summaryrefslogtreecommitdiff
path: root/frontend/beta
authorGiulio Cesare Solaroli <giulio.cesare@clipperz.com>2011-10-02 23:56:18 (UTC)
committer Giulio Cesare Solaroli <giulio.cesare@clipperz.com>2011-10-02 23:56:18 (UTC)
commitef68436ac04da078ffdcacd7e1f785473a303d45 (patch) (unidiff)
treec403752d66a2c4775f00affd4fa8431b29c5b68c /frontend/beta
parent597ecfbc0249d83e1b856cbd558340c01237a360 (diff)
downloadclipperz-ef68436ac04da078ffdcacd7e1f785473a303d45.zip
clipperz-ef68436ac04da078ffdcacd7e1f785473a303d45.tar.gz
clipperz-ef68436ac04da078ffdcacd7e1f785473a303d45.tar.bz2
First version of the newly restructured repository
Diffstat (limited to 'frontend/beta') (more/less context) (ignore whitespace changes)
-rw-r--r--frontend/beta/css/clipperz/clipperz.css3238
-rw-r--r--frontend/beta/css/clipperz/compact.css162
-rw-r--r--frontend/beta/css/clipperz/ie.css351
-rw-r--r--frontend/beta/css/clipperz/ytheme-clipperz.css141
-rw-r--r--frontend/beta/css/yui-extensions/basic-dialog.css250
-rw-r--r--frontend/beta/css/yui-extensions/button.css86
-rw-r--r--frontend/beta/css/yui-extensions/core.css53
-rw-r--r--frontend/beta/css/yui-extensions/dd.css81
-rw-r--r--frontend/beta/css/yui-extensions/grid.css584
-rw-r--r--frontend/beta/css/yui-extensions/inline-editor.css60
-rw-r--r--frontend/beta/css/yui-extensions/layout.css228
-rw-r--r--frontend/beta/css/yui-extensions/qtips.css70
-rw-r--r--frontend/beta/css/yui-extensions/reset-min.css29
-rw-r--r--frontend/beta/css/yui-extensions/resizable.css160
-rw-r--r--frontend/beta/css/yui-extensions/tabs.css152
-rw-r--r--frontend/beta/css/yui-extensions/toolbar.css115
-rw-r--r--frontend/beta/css/yui-extensions/tree.css193
-rw-r--r--frontend/beta/css/yui-extensions/ytheme-aero.css361
-rw-r--r--frontend/beta/css/yui-extensions/ytheme-gray.css300
-rw-r--r--frontend/beta/css/yui-extensions/ytheme-vista.css403
-rw-r--r--frontend/beta/css/yui/calendar.css189
-rw-r--r--frontend/beta/css/yui/container.css240
-rw-r--r--frontend/beta/css/yui/fonts.css62
-rw-r--r--frontend/beta/css/yui/grids.css116
-rw-r--r--frontend/beta/css/yui/logger.css49
-rw-r--r--frontend/beta/css/yui/menu.css328
-rw-r--r--frontend/beta/css/yui/reset.css43
-rw-r--r--frontend/beta/css/yui/tree.css132
-rw-r--r--frontend/beta/html/index_template.html100
-rw-r--r--frontend/beta/images/cardBlockLowerBorder.gif0
-rw-r--r--frontend/beta/images/cardBlockLowerRoundedCorner.gif0
-rw-r--r--frontend/beta/images/cardFiltersSprite.gif0
-rw-r--r--frontend/beta/images/cardsBlockRoundCorners.gif0
-rw-r--r--frontend/beta/images/clipperz/basic-dialog/btn-sprite.gif0
-rw-r--r--frontend/beta/images/clipperz/basic-dialog/close.gif0
-rw-r--r--frontend/beta/images/clipperz/basic-dialog/close.png0
-rw-r--r--frontend/beta/images/clipperz/basic-dialog/close_over.gif0
-rw-r--r--frontend/beta/images/clipperz/basic-dialog/e-handle.gif0
-rw-r--r--frontend/beta/images/clipperz/basic-dialog/hd-sprite.gif0
-rw-r--r--frontend/beta/images/clipperz/basic-dialog/progress.gif0
-rw-r--r--frontend/beta/images/clipperz/basic-dialog/progress2.gif0
-rw-r--r--frontend/beta/images/clipperz/basic-dialog/s-handle.gif0
-rw-r--r--frontend/beta/images/clipperz/basic-dialog/se-handle.gif0
-rw-r--r--frontend/beta/images/default/basic-dialog/btn-sprite.gif0
-rw-r--r--frontend/beta/images/default/basic-dialog/close.gif0
-rw-r--r--frontend/beta/images/default/basic-dialog/e-handle.gif0
-rw-r--r--frontend/beta/images/default/basic-dialog/hd-sprite.gif0
-rw-r--r--frontend/beta/images/default/basic-dialog/progress.gif0
-rw-r--r--frontend/beta/images/default/basic-dialog/progress2.gif0
-rw-r--r--frontend/beta/images/default/basic-dialog/s-handle.gif0
-rw-r--r--frontend/beta/images/default/basic-dialog/se-handle.gif0
-rw-r--r--frontend/beta/images/directLogin/toggle.png0
-rw-r--r--frontend/beta/images/directLoginBox.png0
-rw-r--r--frontend/beta/images/entropyBackground.gif0
-rw-r--r--frontend/beta/images/exportLogo.png0
-rw-r--r--frontend/beta/images/favicon.ico0
-rw-r--r--frontend/beta/images/flags/br.png0
-rw-r--r--frontend/beta/images/flags/cn.png0
-rw-r--r--frontend/beta/images/flags/de.png0
-rw-r--r--frontend/beta/images/flags/en.png0
-rw-r--r--frontend/beta/images/flags/es.png0
-rw-r--r--frontend/beta/images/flags/it.png0
-rw-r--r--frontend/beta/images/flags/jp.png0
-rw-r--r--frontend/beta/images/flags/ru.png0
-rw-r--r--frontend/beta/images/grippie.png0
-rw-r--r--frontend/beta/images/importActiveStepsSeparator.png0
-rw-r--r--frontend/beta/images/importStepsBackground.png0
-rw-r--r--frontend/beta/images/importStepsLabelsBackground.png0
-rw-r--r--frontend/beta/images/importStepsLeftLabelsBackground.png0
-rw-r--r--frontend/beta/images/importStepsSeparator.png0
-rw-r--r--frontend/beta/images/languageBox.png0
-rw-r--r--frontend/beta/images/loginFormBox.png0
-rw-r--r--frontend/beta/images/loginInfoBackground.png0
-rw-r--r--frontend/beta/images/loginInfoInnerBackground.png0
-rw-r--r--frontend/beta/images/logo.gif0
-rw-r--r--frontend/beta/images/menubarSprite.gif0
-rw-r--r--frontend/beta/images/newRecordPanelBackground.gif0
-rw-r--r--frontend/beta/images/newRecordPanelBackground.png0
-rw-r--r--frontend/beta/images/passwordAssistant.png0
-rw-r--r--frontend/beta/images/read-only.gif0
-rw-r--r--frontend/beta/images/read-only.png0
-rw-r--r--frontend/beta/images/read-only_background.png0
-rw-r--r--frontend/beta/images/recordFilterBackground.png0
-rw-r--r--frontend/beta/images/rss.gif0
-rw-r--r--frontend/beta/images/scrambledValue.gif0
-rw-r--r--frontend/beta/images/scrambledValue.png0
-rw-r--r--frontend/beta/images/smiles.gif0
-rw-r--r--frontend/beta/images/smiles_big.gif0
-rw-r--r--frontend/beta/images/smiles_small.gif0
-rw-r--r--frontend/beta/images/test-database.png0
-rw-r--r--frontend/beta/js/Bookmarklet.js400
-rw-r--r--frontend/beta/js/BookmarkletHash.js47
-rw-r--r--frontend/beta/js/Bookmarklet_IE.js23
-rw-r--r--frontend/beta/js/Clipperz/Base.js308
-rw-r--r--frontend/beta/js/Clipperz/ByteArray.js1426
-rw-r--r--frontend/beta/js/Clipperz/CSVProcessor.js348
-rw-r--r--frontend/beta/js/Clipperz/Crypto/AES.js836
-rw-r--r--frontend/beta/js/Clipperz/Crypto/Base.js1852
-rw-r--r--frontend/beta/js/Clipperz/Crypto/BigInt.js1760
-rw-r--r--frontend/beta/js/Clipperz/Crypto/BigInt_scoped.js1649
-rw-r--r--frontend/beta/js/Clipperz/Crypto/ECC.js960
-rw-r--r--frontend/beta/js/Clipperz/Crypto/ECC/BinaryField/Curve.js461
-rw-r--r--frontend/beta/js/Clipperz/Crypto/ECC/BinaryField/FiniteField.js526
-rw-r--r--frontend/beta/js/Clipperz/Crypto/ECC/BinaryField/Point.js67
-rw-r--r--frontend/beta/js/Clipperz/Crypto/ECC/BinaryField/Value.js377
-rw-r--r--frontend/beta/js/Clipperz/Crypto/PRNG.js854
-rw-r--r--frontend/beta/js/Clipperz/Crypto/RSA.js151
-rw-r--r--frontend/beta/js/Clipperz/Crypto/SHA.js296
-rw-r--r--frontend/beta/js/Clipperz/Crypto/SRP.js331
-rw-r--r--frontend/beta/js/Clipperz/DOM.js131
-rw-r--r--frontend/beta/js/Clipperz/Date.js305
-rw-r--r--frontend/beta/js/Clipperz/KeePassExportProcessor.js251
-rw-r--r--frontend/beta/js/Clipperz/NotificationCenter.js325
-rw-r--r--frontend/beta/js/Clipperz/PM/BookmarkletProcessor.js288
-rw-r--r--frontend/beta/js/Clipperz/PM/Components/BaseComponent.js124
-rw-r--r--frontend/beta/js/Clipperz/PM/Components/Compact/CompactHeader.js86
-rw-r--r--frontend/beta/js/Clipperz/PM/Components/Compact/CompactInterface.js312
-rw-r--r--frontend/beta/js/Clipperz/PM/Components/Compact/LoginForm.js189
-rw-r--r--frontend/beta/js/Clipperz/PM/Components/Import/CSVImport/CSVImportColumns.js174
-rw-r--r--frontend/beta/js/Clipperz/PM/Components/Import/CSVImport/CSVImportFields.js247
-rw-r--r--frontend/beta/js/Clipperz/PM/Components/Import/CSVImport/CSVImportHeader.js240
-rw-r--r--frontend/beta/js/Clipperz/PM/Components/Import/CSVImport/CSVImportNotes.js212
-rw-r--r--frontend/beta/js/Clipperz/PM/Components/Import/CSVImport/CSVImportTitle.js189
-rw-r--r--frontend/beta/js/Clipperz/PM/Components/Import/CSVImportComponent.js548
-rw-r--r--frontend/beta/js/Clipperz/PM/Components/Import/ClipperzImportComponent.js212
-rw-r--r--frontend/beta/js/Clipperz/PM/Components/Import/ExcelImportComponent.js134
-rw-r--r--frontend/beta/js/Clipperz/PM/Components/Import/GenericImportComponent.js523
-rw-r--r--frontend/beta/js/Clipperz/PM/Components/Import/KeePassImportComponent.js450
-rw-r--r--frontend/beta/js/Clipperz/PM/Components/Import/MainComponent.js332
-rw-r--r--frontend/beta/js/Clipperz/PM/Components/Import/PasswordPlusImportComponent.js315
-rw-r--r--frontend/beta/js/Clipperz/PM/Components/Import/RoboFormImportComponent.js392
-rw-r--r--frontend/beta/js/Clipperz/PM/Components/MessageBox.js224
-rw-r--r--frontend/beta/js/Clipperz/PM/Components/OTP/MainComponent.js490
-rw-r--r--frontend/beta/js/Clipperz/PM/Components/Panels/AccountPanel.js784
-rw-r--r--frontend/beta/js/Clipperz/PM/Components/Panels/BasePanel.js96
-rw-r--r--frontend/beta/js/Clipperz/PM/Components/Panels/ContactsPanel.js105
-rw-r--r--frontend/beta/js/Clipperz/PM/Components/Panels/DataPanel.js486
-rw-r--r--frontend/beta/js/Clipperz/PM/Components/Panels/LoginPanel.js1114
-rw-r--r--frontend/beta/js/Clipperz/PM/Components/Panels/LogoutPanel.js73
-rw-r--r--frontend/beta/js/Clipperz/PM/Components/Panels/MainPanel.js906
-rw-r--r--frontend/beta/js/Clipperz/PM/Components/Panels/ToolsPanel.js305
-rw-r--r--frontend/beta/js/Clipperz/PM/Components/PasswordEntropyDisplay.js118
-rw-r--r--frontend/beta/js/Clipperz/PM/Components/PasswordGenerator.js285
-rw-r--r--frontend/beta/js/Clipperz/PM/Components/Printing/Footer.js28
-rw-r--r--frontend/beta/js/Clipperz/PM/Components/Printing/Header.js28
-rw-r--r--frontend/beta/js/Clipperz/PM/Components/Printing/Record.js95
-rw-r--r--frontend/beta/js/Clipperz/PM/Components/RecordDetail/AbstractComponent.js105
-rw-r--r--frontend/beta/js/Clipperz/PM/Components/RecordDetail/AbstractFieldSubComponent.js77
-rw-r--r--frontend/beta/js/Clipperz/PM/Components/RecordDetail/CreationWizard.js317
-rw-r--r--frontend/beta/js/Clipperz/PM/Components/RecordDetail/DirectLoginBindingComponent.js174
-rw-r--r--frontend/beta/js/Clipperz/PM/Components/RecordDetail/DirectLoginComponent.js362
-rw-r--r--frontend/beta/js/Clipperz/PM/Components/RecordDetail/DirectLoginValueComponent.js257
-rw-r--r--frontend/beta/js/Clipperz/PM/Components/RecordDetail/DirectLoginsComponent.js199
-rw-r--r--frontend/beta/js/Clipperz/PM/Components/RecordDetail/FieldButtonComponent.js117
-rw-r--r--frontend/beta/js/Clipperz/PM/Components/RecordDetail/FieldComponent.js189
-rw-r--r--frontend/beta/js/Clipperz/PM/Components/RecordDetail/FieldDragHandler.js59
-rw-r--r--frontend/beta/js/Clipperz/PM/Components/RecordDetail/FieldLabelComponent.js141
-rw-r--r--frontend/beta/js/Clipperz/PM/Components/RecordDetail/FieldTypeComponent.js157
-rw-r--r--frontend/beta/js/Clipperz/PM/Components/RecordDetail/FieldValueComponent.js275
-rw-r--r--frontend/beta/js/Clipperz/PM/Components/RecordDetail/HeaderComponent.js165
-rw-r--r--frontend/beta/js/Clipperz/PM/Components/RecordDetail/MainComponent.js758
-rw-r--r--frontend/beta/js/Clipperz/PM/Components/RecordDetail/NotesComponent.js240
-rw-r--r--frontend/beta/js/Clipperz/PM/Components/RecordDetail/TitleComponent.js137
-rw-r--r--frontend/beta/js/Clipperz/PM/Components/TabPanel/TabPanelController.js158
-rw-r--r--frontend/beta/js/Clipperz/PM/Components/TextFormField.js310
-rw-r--r--frontend/beta/js/Clipperz/PM/Connection.js584
-rw-r--r--frontend/beta/js/Clipperz/PM/Crypto.js503
-rw-r--r--frontend/beta/js/Clipperz/PM/DataModel/DirectLogin.js536
-rw-r--r--frontend/beta/js/Clipperz/PM/DataModel/DirectLoginBinding.js113
-rw-r--r--frontend/beta/js/Clipperz/PM/DataModel/DirectLoginInput.js229
-rw-r--r--frontend/beta/js/Clipperz/PM/DataModel/DirectLoginReference.js192
-rw-r--r--frontend/beta/js/Clipperz/PM/DataModel/Header.js751
-rw-r--r--frontend/beta/js/Clipperz/PM/DataModel/OneTimePassword.js333
-rw-r--r--frontend/beta/js/Clipperz/PM/DataModel/OneTimePasswordManager.js280
-rw-r--r--frontend/beta/js/Clipperz/PM/DataModel/Record.js759
-rw-r--r--frontend/beta/js/Clipperz/PM/DataModel/RecordField.js220
-rw-r--r--frontend/beta/js/Clipperz/PM/DataModel/RecordVersion.js535
-rw-r--r--frontend/beta/js/Clipperz/PM/DataModel/Statistics.js133
-rw-r--r--frontend/beta/js/Clipperz/PM/DataModel/User.js904
-rw-r--r--frontend/beta/js/Clipperz/PM/DataModel/UserPreferences.js197
-rw-r--r--frontend/beta/js/Clipperz/PM/Date.js193
-rw-r--r--frontend/beta/js/Clipperz/PM/Main.js588
-rw-r--r--frontend/beta/js/Clipperz/PM/Proxy.js173
-rwxr-xr-xfrontend/beta/js/Clipperz/PM/Proxy/Proxy.JSON.js100
-rw-r--r--frontend/beta/js/Clipperz/PM/Proxy/Proxy.Offline.DataStore.js804
-rw-r--r--frontend/beta/js/Clipperz/PM/Proxy/Proxy.Offline.js73
-rwxr-xr-xfrontend/beta/js/Clipperz/PM/Proxy/Proxy.PHP.js259
-rw-r--r--frontend/beta/js/Clipperz/PM/Proxy/Proxy.Test.js94
-rw-r--r--frontend/beta/js/Clipperz/PM/Strings.js231
-rw-r--r--frontend/beta/js/Clipperz/PM/Strings/MessagePanelConfigurations.js389
-rw-r--r--frontend/beta/js/Clipperz/PM/Strings/Strings_de-DE.js352
-rw-r--r--frontend/beta/js/Clipperz/PM/Strings/Strings_el-GR.js701
-rw-r--r--frontend/beta/js/Clipperz/PM/Strings/Strings_en-CA.js43
-rw-r--r--frontend/beta/js/Clipperz/PM/Strings/Strings_en-GB.js43
-rw-r--r--frontend/beta/js/Clipperz/PM/Strings/Strings_en-US.js1259
-rw-r--r--frontend/beta/js/Clipperz/PM/Strings/Strings_es-ES.js480
-rw-r--r--frontend/beta/js/Clipperz/PM/Strings/Strings_fr-FR.js362
-rw-r--r--frontend/beta/js/Clipperz/PM/Strings/Strings_he-IL.js40
-rw-r--r--frontend/beta/js/Clipperz/PM/Strings/Strings_it-IT.js694
-rw-r--r--frontend/beta/js/Clipperz/PM/Strings/Strings_ja-JP.js808
-rw-r--r--frontend/beta/js/Clipperz/PM/Strings/Strings_pt-BR.js478
-rw-r--r--frontend/beta/js/Clipperz/PM/Strings/Strings_pt-PT.js42
-rw-r--r--frontend/beta/js/Clipperz/PM/Strings/Strings_ru-RU.js440
-rw-r--r--frontend/beta/js/Clipperz/PM/Strings/Strings_zh-CN.js477
-rw-r--r--frontend/beta/js/Clipperz/PM/Toll.js193
-rw-r--r--frontend/beta/js/Clipperz/Profile.js485
-rw-r--r--frontend/beta/js/Clipperz/Set.js167
-rw-r--r--frontend/beta/js/Clipperz/Signal.js71
-rw-r--r--frontend/beta/js/Clipperz/Style.js73
-rw-r--r--frontend/beta/js/Clipperz/YUI/Collapser.js73
-rw-r--r--frontend/beta/js/Clipperz/YUI/DomHelper.js465
-rw-r--r--frontend/beta/js/Clipperz/YUI/DomQuery.js710
-rw-r--r--frontend/beta/js/Clipperz/YUI/Drawer.js238
-rw-r--r--frontend/beta/js/Clipperz/YUI/IBLayoutManager.js114
-rw-r--r--frontend/beta/js/Clipperz/YUI/IBLayoutRegion.js249
-rw-r--r--frontend/beta/js/Clipperz/YUI/MessageBox.js265
-rw-r--r--frontend/beta/js/JSON/json2.js481
-rw-r--r--frontend/beta/js/MochiKit/Async.js683
-rw-r--r--frontend/beta/js/MochiKit/Base.js1403
-rw-r--r--frontend/beta/js/MochiKit/Color.js902
-rw-r--r--frontend/beta/js/MochiKit/Controls.js1388
-rw-r--r--frontend/beta/js/MochiKit/DOM.js1267
-rw-r--r--frontend/beta/js/MochiKit/DateTime.js216
-rw-r--r--frontend/beta/js/MochiKit/DragAndDrop.js824
-rw-r--r--frontend/beta/js/MochiKit/Format.js304
-rw-r--r--frontend/beta/js/MochiKit/Iter.js843
-rw-r--r--frontend/beta/js/MochiKit/Logging.js321
-rw-r--r--frontend/beta/js/MochiKit/LoggingPane.js374
-rw-r--r--frontend/beta/js/MochiKit/MochiKit.js154
-rw-r--r--frontend/beta/js/MochiKit/MockDOM.js115
-rw-r--r--frontend/beta/js/MochiKit/New.js1
-rw-r--r--frontend/beta/js/MochiKit/Position.js246
-rw-r--r--frontend/beta/js/MochiKit/Selector.js431
-rw-r--r--frontend/beta/js/MochiKit/Signal.js864
-rw-r--r--frontend/beta/js/MochiKit/Sortable.js589
-rw-r--r--frontend/beta/js/MochiKit/Style.js444
-rw-r--r--frontend/beta/js/MochiKit/Test.js181
-rw-r--r--frontend/beta/js/MochiKit/Visual.js1976
-rw-r--r--frontend/beta/js/MochiKit/__package__.js18
-rw-r--r--frontend/beta/js/YUI-extensions/Bench.js40
-rw-r--r--frontend/beta/js/YUI-extensions/CSS.js208
-rw-r--r--frontend/beta/js/YUI-extensions/CompositeElement.js140
-rw-r--r--frontend/beta/js/YUI-extensions/CustomTagReader.js40
-rw-r--r--frontend/beta/js/YUI-extensions/Date.js407
-rw-r--r--frontend/beta/js/YUI-extensions/DomHelper.js416
-rw-r--r--frontend/beta/js/YUI-extensions/Element.js2157
-rw-r--r--frontend/beta/js/YUI-extensions/EventManager.js456
-rw-r--r--frontend/beta/js/YUI-extensions/JSON.js132
-rw-r--r--frontend/beta/js/YUI-extensions/KeyMap.js135
-rw-r--r--frontend/beta/js/YUI-extensions/Layer.js246
-rw-r--r--frontend/beta/js/YUI-extensions/MixedCollection.js344
-rw-r--r--frontend/beta/js/YUI-extensions/State.js264
-rw-r--r--frontend/beta/js/YUI-extensions/UpdateManager.js484
-rw-r--r--frontend/beta/js/YUI-extensions/anim/Actor.js759
-rw-r--r--frontend/beta/js/YUI-extensions/anim/Animator.js482
-rw-r--r--frontend/beta/js/YUI-extensions/data/AbstractDataModel.js226
-rw-r--r--frontend/beta/js/YUI-extensions/data/DefaultDataModel.js339
-rw-r--r--frontend/beta/js/YUI-extensions/data/JSONDataModel.js81
-rw-r--r--frontend/beta/js/YUI-extensions/data/LoadableDataModel.js330
-rw-r--r--frontend/beta/js/YUI-extensions/data/Tree.js412
-rw-r--r--frontend/beta/js/YUI-extensions/data/XMLDataModel.js274
-rw-r--r--frontend/beta/js/YUI-extensions/dd/DragSource.js218
-rw-r--r--frontend/beta/js/YUI-extensions/dd/DragZone.js64
-rw-r--r--frontend/beta/js/YUI-extensions/dd/DropTarget.js45
-rw-r--r--frontend/beta/js/YUI-extensions/dd/DropZone.js81
-rw-r--r--frontend/beta/js/YUI-extensions/dd/Registry.js80
-rw-r--r--frontend/beta/js/YUI-extensions/dd/ScrollManager.js171
-rw-r--r--frontend/beta/js/YUI-extensions/dd/StatusProxy.js110
-rw-r--r--frontend/beta/js/YUI-extensions/grid/AbstractColumnModel.js131
-rw-r--r--frontend/beta/js/YUI-extensions/grid/DefaultColumnModel.js325
-rw-r--r--frontend/beta/js/YUI-extensions/grid/EditorGrid.js16
-rw-r--r--frontend/beta/js/YUI-extensions/grid/EditorSelectionModel.js182
-rw-r--r--frontend/beta/js/YUI-extensions/grid/Grid.js965
-rw-r--r--frontend/beta/js/YUI-extensions/grid/GridDD.js101
-rw-r--r--frontend/beta/js/YUI-extensions/grid/GridView.js790
-rw-r--r--frontend/beta/js/YUI-extensions/grid/PagedGridView.js194
-rw-r--r--frontend/beta/js/YUI-extensions/grid/SelectionModel.js445
-rw-r--r--frontend/beta/js/YUI-extensions/grid/editor/CellEditor.js91
-rw-r--r--frontend/beta/js/YUI-extensions/grid/editor/CheckboxEditor.js60
-rw-r--r--frontend/beta/js/YUI-extensions/grid/editor/DateEditor.js268
-rw-r--r--frontend/beta/js/YUI-extensions/grid/editor/NumberEditor.js166
-rw-r--r--frontend/beta/js/YUI-extensions/grid/editor/SelectEditor.js37
-rw-r--r--frontend/beta/js/YUI-extensions/grid/editor/TextEditor.js110
-rw-r--r--frontend/beta/js/YUI-extensions/layout/BasicLayoutRegion.js265
-rw-r--r--frontend/beta/js/YUI-extensions/layout/BorderLayout.js281
-rw-r--r--frontend/beta/js/YUI-extensions/layout/BorderLayoutRegions.js207
-rw-r--r--frontend/beta/js/YUI-extensions/layout/ContentPanels.js325
-rw-r--r--frontend/beta/js/YUI-extensions/layout/LayoutManager.js135
-rw-r--r--frontend/beta/js/YUI-extensions/layout/LayoutRegion.js496
-rw-r--r--frontend/beta/js/YUI-extensions/layout/LayoutStateManager.js68
-rw-r--r--frontend/beta/js/YUI-extensions/layout/SplitLayoutRegion.js282
-rw-r--r--frontend/beta/js/YUI-extensions/tree/AsyncTreeNode.js58
-rw-r--r--frontend/beta/js/YUI-extensions/tree/TreeDragZone.js43
-rw-r--r--frontend/beta/js/YUI-extensions/tree/TreeDropZone.js228
-rw-r--r--frontend/beta/js/YUI-extensions/tree/TreeFilter.js105
-rw-r--r--frontend/beta/js/YUI-extensions/tree/TreeLoader.js107
-rw-r--r--frontend/beta/js/YUI-extensions/tree/TreeNode.js300
-rw-r--r--frontend/beta/js/YUI-extensions/tree/TreeNodeUI.js452
-rw-r--r--frontend/beta/js/YUI-extensions/tree/TreePanel.js213
-rw-r--r--frontend/beta/js/YUI-extensions/tree/TreeSelectionModel.js195
-rw-r--r--frontend/beta/js/YUI-extensions/tree/TreeSorter.js49
-rw-r--r--frontend/beta/js/YUI-extensions/widgets/BasicDialog.js1046
-rw-r--r--frontend/beta/js/YUI-extensions/widgets/Button.js185
-rw-r--r--frontend/beta/js/YUI-extensions/widgets/DatePicker.js344
-rw-r--r--frontend/beta/js/YUI-extensions/widgets/InlineEditor.js216
-rw-r--r--frontend/beta/js/YUI-extensions/widgets/MessageBox.js230
-rw-r--r--frontend/beta/js/YUI-extensions/widgets/QuickTips.js311
-rw-r--r--frontend/beta/js/YUI-extensions/widgets/Resizable.js586
-rw-r--r--frontend/beta/js/YUI-extensions/widgets/SplitBar.js468
-rw-r--r--frontend/beta/js/YUI-extensions/widgets/TabPanel.js756
-rw-r--r--frontend/beta/js/YUI-extensions/widgets/TaskPanel.js0
-rw-r--r--frontend/beta/js/YUI-extensions/widgets/TemplateView.js766
-rw-r--r--frontend/beta/js/YUI-extensions/widgets/Toolbar.js296
-rw-r--r--frontend/beta/js/YUI-extensions/yutil.js637
-rw-r--r--frontend/beta/js/YUI/animation.js1272
-rw-r--r--frontend/beta/js/YUI/autocomplete.js3066
-rw-r--r--frontend/beta/js/YUI/calendar.js4239
-rw-r--r--frontend/beta/js/YUI/connection.js960
-rw-r--r--frontend/beta/js/YUI/container.js4561
-rw-r--r--frontend/beta/js/YUI/dom.js881
-rw-r--r--frontend/beta/js/YUI/dragdrop.js2940
-rw-r--r--frontend/beta/js/YUI/event.js1738
-rw-r--r--frontend/beta/js/YUI/logger.js1559
-rw-r--r--frontend/beta/js/YUI/menu.js6780
-rw-r--r--frontend/beta/js/YUI/slider.js1113
-rw-r--r--frontend/beta/js/YUI/tabview.js1950
-rw-r--r--frontend/beta/js/YUI/treeview.js2182
-rw-r--r--frontend/beta/js/YUI/yahoo.js145
-rw-r--r--frontend/beta/properties/beta.properties.json183
-rw-r--r--frontend/beta/properties/creditsAndCopyrights.txt335
330 files changed, 125357 insertions, 0 deletions
diff --git a/frontend/beta/css/clipperz/clipperz.css b/frontend/beta/css/clipperz/clipperz.css
new file mode 100644
index 0000000..b0601a2
--- a/dev/null
+++ b/frontend/beta/css/clipperz/clipperz.css
@@ -0,0 +1,3238 @@
1/*
2
3Copyright 2008-2011 Clipperz Srl
4
5This file is part of Clipperz's Javascript Crypto Library.
6Javascript Crypto Library provides web developers with an extensive
7and efficient set of cryptographic functions. The library aims to
8obtain maximum execution speed while preserving modularity and
9reusability.
10For further information about its features and functionalities please
11refer to http://www.clipperz.com
12
13* Javascript Crypto Library is free software: you can redistribute
14 it and/or modify it under the terms of the GNU Affero General Public
15 License as published by the Free Software Foundation, either version
16 3 of the License, or (at your option) any later version.
17
18* Javascript Crypto Library is distributed in the hope that it will
19 be useful, but WITHOUT ANY WARRANTY; without even the implied
20 warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
21 See the GNU Affero General Public License for more details.
22
23* You should have received a copy of the GNU Affero General Public
24 License along with Javascript Crypto Library. If not, see
25 <http://www.gnu.org/licenses/>.
26
27*/
28
29/* @override
30 https://www.example.com/css/clipperz.css
31 http://www.example.com/css/clipperz.css
32 https://www.example.com/concurrency/css/clipperz.css
33 https://www.clipperz.com/beta-connection/css/clipperz.css
34 https://www.example.com/import/css/clipperz.css
35*/
36
37body {
38 /*margin-left: 15px; margin-right: 15px;*/
39 background-color: white;
40 color: black;
41 font-family: Helvetica, Arial, Geneva, sans-serif;
42}
43
44table {
45 /* width: 100%;*/
46}
47
48/* @group Header */
49
50div#applicationVersionType {
51 position: fixed;
52 top: 0;
53 left: 0;
54 width: 120px;
55 height: 120px;
56 z-index: 99999;
57}
58
59div#applicationVersionType.readOnly {
60 /* background: url(../images/read-only.png) no-repeat fixed -5px -8px;*/
61 background: url(data:image/png;charset=utf-8;base64,iVBORw0KGgoAAAANSUhEUgAAAI0AAACSCAYAAAB43knrAAAABGdBTUEAANbY1E9YMgAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAABB8SURBVHja7J0LcFTlFcfPbh4bCAnPBCNIGIlOBEYaEWxxEKpFqGklYgWpQkXwAak6Sh07jshYHVumra1ioCLRSEBALQZHbGNAggpiAiIjUOQxJIMBNJFA3tlkc3vO9927e+8mIdm7j+TunjNzyd3Ncu/uvb+c8z/nO9+3NrCe2dUtCrdo3GLVrc+xZfbHrxpqfxTY3Fb+o7Jy5HLXCtxtwq0ZtxbcXLi10aYoiqkbEBbAHF9uX8rAtLfUwbZHCrOjJqvXK0q9fjZ/b0JYeJi0JPvvGZH29u05JXd6juurSISmc2CetT/BHqZjKy1TNqW/4Mr1AkaDxmYWHrvlgUm2P8J4tLed3yofTPyba4N63QIGjBWgYWBM2EeHlKKbV7q26CCxByIsWQEaBsaEFRxUdmX+y/Uh7ipqhqT91PbDFhoGxoS995Wy547XXYVqWq2l1i4dNBo4ij8A2RmY8LDN+5Uv73rDVaTWYvSb07s24y84dgbG+rZpn1Jy95uu7bjbgFu9+rMRZEFPg6ZVB47i701iYKwNTOncPNcO3K1Tt3ovcDRvE3bQMDAmbCN6GC9gaKvVwdPk5W1cgRDFdgbGusD8Ns/1iQpJjW7ToNF7Gm9RDFaGhoEJDjD68KTXNPoU3JLhKbTADBoLkLUh3IHx9jLODvRMm7/vITpSPMz30/Jg6JAxeLY4vIRNDIzFPE2PhKSkrTPk6Sb+gYGxGDRBA4YCtTMLEwm7Tt/FDQGwRckTN1XBuYpPATKewOcUBsYi0ATVwzjT50PssJsAFp8VULSRhlmI+0swFGUsFVglfvgr/JkAMGYBA+OH2cIBGM1aEI6YSX/BvUqA1akAI26FpswCiNNeUDgXnGMXI1zXAOSkhPDj915gzLR72sIFGM3qJyyD+InPSnBWIRgKfsSk8dAyYxPEJI70vHDbbQBlRRHvYXpjj3DIRW986fNQX/Inkr4YmmSogsr9EJN/FUBeKrSRriHLXO3Tcdvw76sy+zwEqLvAciEpVNCEDpjoPgBjHxYepVNwhBs6A/aCW6D2wEv4AMNXfEq3T9E48jY8Guqh9DsjGphgQhM6YBwDAB7CazplJcDsvQDTcjoAp1KCpfqJtuTr5fVHiLrtwcq2QTnt3PKPiAYmWNCENCSdytoOUIHbxgyobr4AcPWDGHryvMDp4069bZiG96csa+NNXUq6Vvo/8Ze7H6dsmYr/4uOUSRELTDCEcMiAoRsajd6lMS0L+qz1ZEI/zDsOySR4yzag2L1PfVf4FtqcXh9b6VLD/JjtJD+Fx9oGsB2PhVCWL6rEwIY+Z+31YQFMTwvhkHqY5uufBhjzAPRxDASI6et+PhkF7w81ZQAj78FQ9bJKgLODUmBXH0aBpPWjoaXqIB4rEwBhgamrIHU/pvSOcQD9r4w4DxNoT9MjQwP1eBPjERxoPoZ/+aMNH6dhzj7oS+Gkpc7HT4Jv+8rb8VMgiCfexdvTKHXTTaiZrr7b87oq9D6bsywPTE/VaUILTH9MnaMcAOe/EW//UuD4bDTsQFVkvW3LkuFJA2r8UwCiDoSWNwLJPWtpD9MT0IQOGLyhTXhD4/TPvfNTUYPxgHMKIPcavBIuU6c4gXoo7dxnADuzAQaOhibMxsT53rkBz/OVR08lpEL0/BMAJUsBSl+xdEgKtaYJGTDN+BcugDmWD7BmoPzrJ6MUG29gfPESqD/8OoaRFHdq7auoJr0yzBEPULRAhiQqCOK5RBPF7PeNZaGhE+RO2ecRoWECBU1IQ5Jz9P34F18tbyhpFAoX69LkL7NyZXqN4MDqwb5rmEuI6ig8VrNI2QcZxPPJ6RsBDv/T4H0iBRiz0IRc9Cox8dCuX6y2HM4f2wSQOFyXJztNHV/Uc8hT0Tnu3mUAxJlMVebzhkg+KicGoPjJiATGDDQ9kiVF1VItNgFTaKN+aBiE+qXmlMlPHiuHHdTinTvEJWYAZKNXS/sNQGYBJFG6vfGXEZdWB0oI92gT+JlFlXA5pb4VxQCfPg6QPk82VOWijmmq8u1g6fMBbsnVxScE742xwlO5RbWWOZX/17SwtgIwwcyeLrkClT8LCtFbtsX061yLkDe48C20tdRDa9Z22WglDCXq+usALh736Xwtw2+GmJmFEoizuwF+9qLQM4glQE6qsf5TcwAgf4LpJNMKHiZY0AQNGDJRlndgYrsmGe9oo/GX1H0394CxkEbZEdVpaJzJhJ3MboFRB54D2POCR7dMWAaxVHspvBPz7g+M4AiYRvgMjlVCUjBS7qACQzb8c2rFRGgerMDMpY/RwxAwNSXGyiulwyaBofGkZCFgkowpdOkL4i5CwlCPOEaNI4T2sQ/DFphgCOGgAyNE7tF1oGydLoWuDpzKicsQjiMYHm4M4IdV4CKNJV2N6XnSdR6YbHYQZ6393ujoilA3FWUzMN0MTyEBxh1uMENpmr5RrfbidV0zTA1VCgRkpCMBtQpqIhLMbXFDwK4NFVAN5uT7UD1rJwx0XMQwlBZxWVKgNE3ogKFsiEaPKzBDKXoIYNxjMiMygOPf8Wvx+AnaY204ACGqnX/C83zVFxgCJ/sFqFU9TCCgCR0waKezdsAVw1INf+Ft6HXsmQUqOCNMVXiF9LFFQeuSJjn0sOcZgL4pYmjA87EVCa2rWeqkCK3D+CuEQwqMACRhRPs3VLZN9sMIjfO16WM3YuYTR/eLhh6orVMFhrIimKCWlEhQRzAw/grhkANDNgBFsGjwzuhgGeAdC9HT/MT0sWO0f7186cW0uwDSZwXk/b9dGnnA6GEJHTBUtqf6C1pi6fMgWrsn/R1gWr7slZm0ApIT+wMQUCZDk/hgdadlKv+LVYbn6Q7CuYMBAeaetyIPGC24R4cKmPNz9sGgIePkgwMvotZYLsaAqu+vwOxlgM7nZ+CLD/l9PvfQAwndoiWeoQc/mqfCDRizQtgRCmC+R2CG0nX9aAFU476A5PBfAYqf9nggxyCA6v/5NdbjXcyrm1MKiRqodN/WX+vz0EM4exiz0MQHGxglaTzYZhdjltRPnPIcZk2XaWNIenCCZX4OPYRzSDKbPQVd9NYOn+red6bcCJcNQYGaE0uzrQHGPAmQtcXPIBvVRf7dyMAEWAgHPUvqV14I8M4UaLVFQ+ws9DhvTBZ1krhdaur7da65A1PPS3aLXE4kG+9byo1BuUgMjJfjDiow5AFQn9hVUds49mFIIP/SpvblTsHQtCparuzgq1sdfjPYqO2SUvO676B2ZiEkEJBr8HgtNgYmmNAEBRjyAHRDhaEX2DJD9K44RLNUEnqFVkFrwq4HTAFDdhYhuXzPoyI1p/EkMSSwfjRqFzy+vdXvcMTAXCI8BVz0ogcAzQNsnY5XNg6APECMArEn3sNU+yUJUuFcgEN5prMiavWGyqNiaosYgNw4TmRFtbSvm3/NwAQnPAXUuvQAe56Sm69GhT+a+XgkF+zoRSrwqVEzP5a/o+MjMDTVRZyPRrQZmKAKYXNGLZokPOlnkD2Ai3p67z0CQEuj0ah4yiS4kibKydxM/nAMgIv3E0onxUwFBiZ4ZlNejVbM3MQofWP2jvvQs8iFnUU7pfa8zgM4FtfLuUombmgtHjOBMq2609CaWSDd49ZbZZmJ+n01q/kGz5lhWidFIjCminu+QuMGpmofwGl1iVW6bq8NFIs6y0LeXnmN19+A8qVSLv/h+BEgJ923d0djVKPuAEge5Vk2BD1YK3otNzjfoV6i0XK1yYo9TC+Dxg3MsTXuNkgnZkqxJHz1U0lIDJvwAK2YkkdfOIYgfCIel6OHEfMDanYD5HsKhAZwKPydP8IaJoTQdFvT0A0VwNB0VF3frHL+qNy56wuAeUdkayXd9JxYGY4IpvzrugRGie4jFimCEZ5Vpq7QqsaJqJ0m6MQzwhmVh+cp28zA9FZNQwL3YrYTBtIDas0s+LX0PCiCGx6sxoyF6iJ1shOOTL88R3eM/h/VVdT5T02TVkDcqa2Yiu0xrkjlNfWE0+pe7Gmoiz9hlZiCDzBsBsCcj0WIEMDQhLKcOIC1SaIuI4zaNdWeme54MJER0eyAFgleHOmkWbvEc3TuwZrHyViOGdRzDIyVsicq/dcuaZIeh6xqJ8DmW40vovDUf5Rbl3Rp9Hpa64VM1/jt/Zzb41S8j55uNgNjBU0jKoGKy+NxOs2Py7sFjPAw2WfE65U8OR0WZn8pPQ4dQ1tKRH1OrIGH52ZgLFjcM4Az5Ocofnf7fFKq24h1f6lzj9xd/ZmuwaFCop/NWQxMD0HTDpzEiahJ9vn0/x0xfWW6nDpL9ATDnHcFON7exQCOI5GBsaKm6VTjbLsds6X/dPl60bN7YjVA8bPGJT1IRGuj0gY9I9fUa78OMANjGU3TkccZQKtCdQMY58hM2eS9+8/icYy+sXv2x0ZN5PY4e+XcbgbG+uHJ4Kq6q2P6XSF3xi6BH9DjxFIL5pqBntWnFh00gkPjVuTB/Jiay8D0wvDkcyhbeE7OQqDVINaOc/+uZlo+JNLCzl7Ps4YJw/Dki0VhKGtxK2H0ImMXuX+XWDQPamgtGHp+EU9kC/vw1HmKNEB+pwBtuE9hLHnvMoDXEmV1dwoK4ozFBnAuiC+u+CMDE4nhqS6zAPoRLHqr+gxg88+FCqI6TcPiellZpi6/A6sDcl4GxqLhiWZSCmDKPpAp846FctXvIZMBsivFt7w5MBvquzpe1nkmvWLwOAxMhIUnZ9J4GEpTYEuewcznTlljOboOYnNioVosH4K+ZebbMnqp4NTS/TyUz8BEaniS020nAqzq165/xtBeoS/msYeJ7PDU3MEiRZ4TKRCtzahMDMwXbG0oYWAsH57kIkVxAGMWdOzWWhvUOFYbEGDuXcfAWB6ahG/ULGjK6x02YTWn/07uNHzHwDA06sGaqqBhj1pnoYWjqWeGlvmI6Qct0/JhMC0vUvKUX0MDDEyY1mmUjKVgo4lt3nb4VYDixxkYiwvh4I09UUX4WhS+w6aKL8SA/Sv8mvnIwEQCNAE0BiaMU24GhoUwA8NmLWgYGIaGgWFoGBiGhoFhsyI0DAxDw8AwNAwMWy+BhoFhaBgYhoaBYesl0DAwDA0Dw9AwMGy9BBoGhqFhYBgaBoatl0DDwDA0DAxb8KBhYBgaBoYteNAwMAwNA8MWPGgYGIbGJ1tfonzJwDA0PgEzb51rJwPD0DAwbIGHhoFhizYJTI0XNAwMexoGhs1PaBgYNp+gYWDYfIKGgWHzCRoGhs2n7EkF5hMdIAwMW+fQbChV9urqMAwM26WhebtU+eJe+V0DderGwLB1Ds2m/crn97zl2qFCUafzMnUMDFs7aP59QNk5901XEe426aDRw8LAsLnN9thU+8qXi9uO4z59L2mzCke9DpZ6BiZ8zdSK5bjRV6MoOmgadeA0MDAMTUfhqVq9+S4VmiYVEu0nA8PWITSKCoMGhwZPMwPD1hE0NTpoWtRNA0V7zMCwGaCpVaFpU+HQthYVFAaGrR009eq+S6dt9FsbA8PmDY323YCKDg5FB4zCwLB5Q+PUQaPfNFAYGLZ20LR6QQOdPGZjc0Pj8gKFje2SZjNTEWSLbLPzJWBjaNgYGjaGho2hYWNo2NgYGjaGho2hYWNo2BgaNjaGhi1A9n8BBgBfmCD4GUFjiQAAAABJRU5ErkJgggo=) no-repeat fixed -5px -8px;
62}
63
64div#applicationVersionType.TEST {
65 /* background: url(../images/test-database.png) no-repeat fixed -5px -8px;*/
66 background: url(data:image/png;charset=utf-8;base64,iVBORw0KGgoAAAANSUhEUgAAAIMAAACGCAYAAAD+UDnVAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAADMlJREFUeNrtnX+MXFUVx99OaaFLwdIfKrTQym81hsQCmiiIYPUP+R0ggXSL0KYgBKMBUUn9QVJMTIx/dDet1EAT21qEQM1iirKEFrKBGlOpbBoK6Lqhu6CLTJ2hdKY7O3s9575777v3zczuzPs19807L/lm29lt3+bd7/vcc8499z3HSc/RBcqBZoNOBM0DnQb6BGj5m+udjWyjw0i1+udPnD64RmeBFoNOEdfvBHFNuxhjDsqRfwgqMoLdeu1B53G4RheBzhbXaz5orriWOcMMRITO1UvfcX4P1+hK0ArQeaAzxLXrrmsGy8mQnBF6uzrKCM992+mHa3QzaCXoUtAFoKWghaCTQXPSRIaEjNDl+5p+7VrrPA/XaJ1mhkuEGZaAFjQ0g6VkoKkhoJ68w9kL1+h+0BrQjWKa+Lw2TSxIExmmNcJbZISG2nm7MwjXaD3oPlAP6BrQ5VoA+UktgLQ+myAjBNSO1c4rcI0eBj0AWiumiK+DvgD6jJZango6STODYyMZyAgBtX218ypcow2gB0F3g24DXQ26TFDhXNDp4nrKKWJWjRksIQMZIZwRHgH9CHQvaBXoWtAVIqW8EHQmaJEoOMkawywbyZCcEXpndVTWsK3H2QfX6OeaETBOuA70VZFB4PSwTFzLj4n6gkEFm8jQJiJ0daIRVoOuB12lGeFTImiU04NRhq4xA8UIHWOEG4QRLp3BCAYVbCBD7EY4PvInxvrmJDdIvSek0gjtJkPsRiiMv8bYZJmxF1bFP0BbFrM80459P0uVEdpJhgSMcMAdlMF7YzdCue9EVsFzDf+BsScuZtXRl9xz7+lJjRHaRYbYjfCfwr9qjbB1GWNPfyUWMxQGvw8n+4f6+1j5CGNDj7gB6lNfToUR2kGGWI0wBRdfEWGgx0B4ZWoSpozhWMxwGM9Z2MsHfwTPPfQL/vk7SIjCQCqMkDQZYidCdcfnvDlbmgGNwD8Yh+BO//lcZGYo7rlHixUeUp+/jYQ41JcKIyRJhuTSR5iz1TH0KCvVMwKaZqrKjRLoHID+ijzHY0tYFYylgseBbzG2qdsNIPF49LRUGCEpMsRvhK3L3QGuZwgcpo0+I/CjyNjmU1oPFnGweTwCccKur3npJPxfRjaBdvnt+W03QiuDGzcZYjfCBzJG4EfJuxN1Q+xZV2uETXNbj0nwjud3uxeLFHEq4JnETvUZN2dKpoakyJBc1rD/l2xCmmL8j/UJceh3Au3BjGBQAb/CFMSPMkxB8vfYutSaYDFI2h8XGZIzwlNfMinBo/oGMUQII0gyVPRpQKSNeaQRjx/OSCUR4iRDcumjHieAxoefdQcJ0Y0FIMMQIYyA/15OPxhn4N/1OgNQh5X/ah0R2k2G9qSP+Hn/NQLbR7S7N69F8wFWKOHflvSYUDPfFAaP6hhLNRHiIEN70kecv+XADH5X/cwE3q31solWpwT8//VUUhoCfwc8B37fUiK0hQxtWYY2YgFfxVEKBypA+oh6F6ec4S1qampEiE4gQpRkaF8/gkGIaBeFeFl5dLtXbu7/hls3kMfum6wnQqJkSC5rKHoFnukMIesJEagqlqCPYiyiZSi8sFR+NzBxbCRCFGSI3Qjvy5KuXlSqN0cbhrgz2PlgGZrtvsUV/lmuQGoLT1N4nvIrqSFCImRIamqYhLuPB26F12GQ7zF9gUbRBk2lj03csRgDMIwJ5GfyPPohSDQiK4zya4rWGpIgQ6Ixgls7gGOTGEQggxHMYUTfYvro9h/gAL/J/z6MS81YTkYjwbTgZQ6f5VkFr24W3uKLUmkiQqxkSKKgxBtDYBBUDyMOAK/9P+4uF8OAlcSdWtKnD50STeioLCdDTFJCoui/hzyn1rDSSVlDFGSInQiTKlofMSN7HkSWOLqL2h0dNn1UhuD4n2d87wj/Xsk6I7SdDElODR/IYtHATfWrjroRIpBHiL8Zn7/H+xjHMkGEVsgQ+9SgI74CvQFFuajU68v78djcHd4EOA1ohSOPEEWXNDJOsaAfodGAJU6GJIygVh8xpZNxglxnECmd8dn+n0bX/7B/Q/0pAzOXFmOQNBOhGTJMa4S3f+z0RtFibmQG5XdUxD4iTSIyBTROPuSi0L/RCOMv8+aTvEwVNcO5hij6eiXtbGdPjAxJGKHmjoeBKqrexU0c0TzFG/+zN4XgHRswWOQFIy0gfE/ubfAZIotEmI4MsRqBxwi+fgC3sDPGB6ICXUta+4h7PLGi9Wri0EY3+BRd0G5twTXDcWxK4ZXEHLbKusdof6ra2WMnQxJEGJN4Hh1Qd6GqJex/SPURHJPTRIB8/7CMCyAz4dPB4F1uRgKmwgCVH32+NnckVEaJUI8MyUwNgH+ji1isNbwvA7gtC72f5X0KRbf1POj2Ol+M4Q7+uJa5lKyOEdpChtiNgF3DAt1cmD3otQOYOnjMUBgMbTiepUgCcUL82otR9POGWdjqICLUM0N8RgDsq/lfW+jhyNZTOnlg70DYcyL24f9X05JmCMbjkpKRzqatnT1uMsRshErjhR6ghhkjjERWUFLrHXx941l30UmscxARGpshOSM0ShF5r2E+cBdzo4KSYQgkQtBtdRa1s8dNhshjhEqdi1+R0XvISmKrBSVpNiJCc2aINGtQC07cDAtNIwz9KlydwkeVpgtKHdTOHjcZIq0sqs0l0hAyUPQZgZeAywebb1Tld33JWLDqlIKSNWSIzAh8SsjVMQSrCdzU4pDctNpMz4Pc78hb3Lq9Je6MFJSSqUCGNYGxJd0MGA1CiPjBM8K21qcKtZupaBAi7QUla8gQWR1Bpoi+DbCGIWS/QAAj8Gok1AdK+mZaYYgsFJTsJgM3wpR7R4q1hiMyDvA9RMOcMrYFOpcbAzznkkctammESHFBKd1k2LKIVarAhKnDZv1fW3l0y80HTUOMPhNogPgDs3wFKbXhNuCTWNLazm4dGfJIgIkP4Slq/1WxgBocnL+BDOrJJgO3ht/yxqegkcbPaghTucwwESKbJop/h0aU43BXVkH7oJCEU0b/N2tb3fd9L/RA/U/usNJ2WyszhOiSTmM7u7XZRPF1WASaOAo+mKx5IutHcsOKthdiOvHCVINGVF5W1jfP4M/xKSlPRLAmm0BDDP3GfU7z1EfqcTYqum+y4liSdYHygWm7mPL68nQEW+TT2M5uBxn6Zjc2xMGtMF1gknnMew5ik1mDMoJv/8KMq5Mhn+JORAhkhube+1h4Y5sbNwQxAlYrNqfrfQ1JP3zbwphhBkMc2tF0+ljy766ueaxvuh7TTzFDQHlTw194LOCliPEaIo7d0BkmQ3Qv7PDHCF4TSjyGICJYZAbej4DpJlYTMcisEwDGZYg4n49AZAiwsln0N782aEEzDBFylxMRIZQZon/FX1U1m+TdtBCrhTNUDPMyhth1lfVPTCEytKAPZVOK1irPt76pVvlKTY8i/37IvkUigoUxg/sklIpHA9Wx5DtCPkCrXc9QIjIE2W3tf0EH7zvIeaudsC+SsoYOJANfdNIwf0xvbvG991Gtbu6+PnXPWSQyNL3o5O98zk2zAYZ6FjuODI2N4OtQwl5ImCaOyTSy1ecwWPKcRSJDC0bghSZtWlBviNWf4xjyvU5EBMvIoHZM4Ta3em1p2oDztBGbU0I+US2r7exWk8F4t+P4i7WFI9/OaFpr6FAyyFY13LiiDAFrDxN13iWlKpERvA4gy+3sVpLB36pmGMIXFFb1/Y/0DKXOIkOjVjXDEGLKMIxgwVpD2gfMKjLM1KpmGuIAm7Bo0YkYEKEZmm1Vq5kyyAidRYZWW9WUIcgIHUiGAK1qYVNJMkLK6gw2t6rRPd+GCiS1qhEZrG1Vo3u9zauW1KpGZKAYgchARiAykBGIDGQEIgMZgchARiAykBGIDGQEIkPiZiAjEBnICEQGMgKRgYxAZCAjEBnICEQGMgKRgYxAZCAjEBnICEQGMgKRgYxAZAhjBjICkYGMQGQgIxAZyAhEBjICkYGMQGQgI5DRmjADGYHIQEYgMnjavtp5lYxAZJBG2AD6IRkhw2TYebszCN97GPQDYYQeMkIGyfDkHc5e+Hw96AHQ3cII15ERMkSGZ9Y4z+9a6wzAZ/eD7gOtBd0GuhZ0JRkhQ2SAYx3oLtAa0CrQzaCrQVeALiYjZIgMYvBRNwoarARdBlpBRsgeGVYK4ZRwOeiLoItAF4CWkxGyRQaMCS4RUwKa4NOgc0FngT5ORsgWGS4UOh90DmgZ6HTQYtB8MkK2yLAUdCZoiZgSFgkanArqBs0hI2SHDAtAC4UB5gsTzAOdREbIHhlO1jRXTAn6tJAjI2SHDHM0zdZMIGlARsgQGWZpymkGIBNkjQxBX/tL6jzRRSCRGUi1+j+w3nFdxUGuNgAAAABJRU5ErkJgggo=) no-repeat fixed -5px -8px;
67}
68
69div#applicationVersionType.LIVE {
70 display: none;
71 visibility: hidden;
72}
73
74div#applicationVersionType.DEBUG {
75 display: none;
76 visibility: hidden;
77}
78
79div#header {
80 background-color: #336;
81 /*border-bottom: 8px solid #ff9400;*/
82}
83
84div#logoFrame {
85 /* float: left;*/
86 /* height: 44px;*/
87 min-height: 44px;
88 background-color: #333366;
89}
90
91div#logoFrame > a {
92 font-size: 12pt;
93}
94
95img#logo {
96 padding-left: 15px;
97}
98
99h5.clipperzPayoff {
100 color: white;
101 font-size: 10pt;
102 font-weight: normal;
103 padding-left: 20px;
104 display: inline;
105 vertical-align: 7px;
106 white-space: nowrap;
107}
108
109/* @group Misc links
110 */
111div#miscLinks {
112 float: right;
113 top: 0;
114 right: 15px;
115}
116
117div#miscLinks ul {
118 padding-top: 5px;
119 padding-right: 3px;
120}
121
122div#miscLinks ul li {
123 display: inline;
124 padding-left: 5px;
125 padding-right: 5px;
126}
127
128div#miscLinks ul li a {
129 color: #ff9404;
130 text-decoration: none;
131 font-size: 10pt;
132}
133
134div#miscLinks ul li a:hover {
135 text-decoration: underline;
136}
137
138/* @end */
139
140/* @end */
141
142/* @group Menu */
143
144div#mainTabs {
145 /* background: #ff9400 url(../images/menubarSprite.gif) repeat-x;*/
146 background: #ff9400 url(data:image/gif;charset=utf-8;base64,R0lGODlhAQCcAOYAANN7AKNfAP2zTf/KgO7QppVXAKJeALFmAOCkTfKtTZhZAPWvTaVgAJ5cAPCsTd2hTdygTaxjAOinTc13APySAOe8gO6rTfSuTZFVAKdhAOqIAN+jTfuyTZJVAO+LAPmxTeuqTbBlAKGDWbFnAOKkTaFdAOmoTfevTeSkTZdXAK9lAPyzTY9TAO+rTeamTfGMALKNWf60TeSmTZ1bAN+BAJpZAP/apvmyTZRWAKliAKpjAJxaAK1lAOiHAPaPANh9APyTANd9APSOANyBAPqQAPiPANF6ANB5AOOEANV9AOaGANV8AOyKANyAAPWPAP6UAPiQANp/AOGDANp+AOaFAOCDAO2KANJ6AP2TAPqRAOOFAM95APSNAP2UAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAAAAAAALAAAAAABAJwAAAeigANdQBRZUD5cLx5MGj1USFU0Q1E/SwBXWxUTNjECKxw3HycLFwkOLRYgJhIuMigkCBsPBBAwIwchKjwROjkZDAEGJQ0zOzUKKQU4HRgiLBVHRgBJQVNNNFJaSj0aVh4vQk5FRBRYTwMTIhgdOAUpCjU7Mw0lBgEMGTk6ETwqIQcjYLAg8GADAhIoZLiQYAKEhRYOElxYcOLDDQ4rBMSwASEQADsK) repeat-x;
147 height: 26px;
148}
149
150/* @group Exit links */
151
152ul#exitLinks {
153 padding-left: 5px;
154 padding-top: 3px;
155}
156
157ul#exitLinks li {
158 display: inline;
159 font-size: 10pt;
160 padding-left: 20px;
161}
162
163ul#exitLinks li a {
164 color: white;
165 text-decoration: none;
166}
167
168ul#exitLinks li a:hover {
169 color: #333366;
170}
171/*
172ul#logoutBlock {
173 padding-top: 3px;
174}
175
176ul#logoutBlock li {
177 line-height: 14px;
178}
179
180td.logoutTD {
181 width: auto;
182}
183*/
184
185/* @end */
186
187/* @group Menus */
188
189div#menus {
190 padding-right: 1px;
191 position: absolute;
192 right: 20;
193 top: 44px;
194 /* background: url(../images/menubarSprite.gif) no-repeat right -26px;*/
195 background: url(data:image/gif;charset=utf-8;base64,R0lGODlhAQCcAOYAANN7AKNfAP2zTf/KgO7QppVXAKJeALFmAOCkTfKtTZhZAPWvTaVgAJ5cAPCsTd2hTdygTaxjAOinTc13APySAOe8gO6rTfSuTZFVAKdhAOqIAN+jTfuyTZJVAO+LAPmxTeuqTbBlAKGDWbFnAOKkTaFdAOmoTfevTeSkTZdXAK9lAPyzTY9TAO+rTeamTfGMALKNWf60TeSmTZ1bAN+BAJpZAP/apvmyTZRWAKliAKpjAJxaAK1lAOiHAPaPANh9APyTANd9APSOANyBAPqQAPiPANF6ANB5AOOEANV9AOaGANV8AOyKANyAAPWPAP6UAPiQANp/AOGDANp+AOaFAOCDAO2KANJ6AP2TAPqRAOOFAM95APSNAP2UAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAAAAAAALAAAAAABAJwAAAeigANdQBRZUD5cLx5MGj1USFU0Q1E/SwBXWxUTNjECKxw3HycLFwkOLRYgJhIuMigkCBsPBBAwIwchKjwROjkZDAEGJQ0zOzUKKQU4HRgiLBVHRgBJQVNNNFJaSj0aVh4vQk5FRBRYTwMTIhgdOAUpCjU7Mw0lBgEMGTk6ETwqIQcjYLAg8GADAhIoZLiQYAKEhRYOElxYcOLDDQ4rBMSwASEQADsK) no-repeat right -26px;
196}
197
198
199div#menus table {
200 padding-left: 1px;
201 /* background: url(../images/menubarSprite.gif) no-repeat 0 -52px;*/
202 background: url(data:image/gif;charset=utf-8;base64,R0lGODlhAQCcAOYAANN7AKNfAP2zTf/KgO7QppVXAKJeALFmAOCkTfKtTZhZAPWvTaVgAJ5cAPCsTd2hTdygTaxjAOinTc13APySAOe8gO6rTfSuTZFVAKdhAOqIAN+jTfuyTZJVAO+LAPmxTeuqTbBlAKGDWbFnAOKkTaFdAOmoTfevTeSkTZdXAK9lAPyzTY9TAO+rTeamTfGMALKNWf60TeSmTZ1bAN+BAJpZAP/apvmyTZRWAKliAKpjAJxaAK1lAOiHAPaPANh9APyTANd9APSOANyBAPqQAPiPANF6ANB5AOOEANV9AOaGANV8AOyKANyAAPWPAP6UAPiQANp/AOGDANp+AOaFAOCDAO2KANJ6AP2TAPqRAOOFAM95APSNAP2UAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAAAAAAALAAAAAABAJwAAAeigANdQBRZUD5cLx5MGj1USFU0Q1E/SwBXWxUTNjECKxw3HycLFwkOLRYgJhIuMigkCBsPBBAwIwchKjwROjkZDAEGJQ0zOzUKKQU4HRgiLBVHRgBJQVNNNFJaSj0aVh4vQk5FRBRYTwMTIhgdOAUpCjU7Mw0lBgEMGTk6ETwqIQcjYLAg8GADAhIoZLiQYAKEhRYOElxYcOLDDQ4rBMSwASEQADsK) no-repeat 0 -52px;
203}
204
205div#menus table tbody tr td {
206 cursor: pointer;
207}
208
209div#menus table tbody tr td div {
210 /* background: url(../images/menubarSprite.gif) no-repeat right -52px;*/
211 background: url(data:image/gif;charset=utf-8;base64,R0lGODlhAQCcAOYAANN7AKNfAP2zTf/KgO7QppVXAKJeALFmAOCkTfKtTZhZAPWvTaVgAJ5cAPCsTd2hTdygTaxjAOinTc13APySAOe8gO6rTfSuTZFVAKdhAOqIAN+jTfuyTZJVAO+LAPmxTeuqTbBlAKGDWbFnAOKkTaFdAOmoTfevTeSkTZdXAK9lAPyzTY9TAO+rTeamTfGMALKNWf60TeSmTZ1bAN+BAJpZAP/apvmyTZRWAKliAKpjAJxaAK1lAOiHAPaPANh9APyTANd9APSOANyBAPqQAPiPANF6ANB5AOOEANV9AOaGANV8AOyKANyAAPWPAP6UAPiQANp/AOGDANp+AOaFAOCDAO2KANJ6AP2TAPqRAOOFAM95APSNAP2UAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAAAAAAALAAAAAABAJwAAAeigANdQBRZUD5cLx5MGj1USFU0Q1E/SwBXWxUTNjECKxw3HycLFwkOLRYgJhIuMigkCBsPBBAwIwchKjwROjkZDAEGJQ0zOzUKKQU4HRgiLBVHRgBJQVNNNFJaSj0aVh4vQk5FRBRYTwMTIhgdOAUpCjU7Mw0lBgEMGTk6ETwqIQcjYLAg8GADAhIoZLiQYAKEhRYOElxYcOLDDQ4rBMSwASEQADsK) no-repeat right -52px;
212}
213
214div#menus table tbody tr td div a {
215 display: block;
216 color: white;
217 font-size: 10pt;
218 text-decoration: none;
219 padding: 0px 15px;
220 /* background: url(../images/menubarSprite.gif) no-repeat left -26px;*/
221 background: url(data:image/gif;charset=utf-8;base64,R0lGODlhAQCcAOYAANN7AKNfAP2zTf/KgO7QppVXAKJeALFmAOCkTfKtTZhZAPWvTaVgAJ5cAPCsTd2hTdygTaxjAOinTc13APySAOe8gO6rTfSuTZFVAKdhAOqIAN+jTfuyTZJVAO+LAPmxTeuqTbBlAKGDWbFnAOKkTaFdAOmoTfevTeSkTZdXAK9lAPyzTY9TAO+rTeamTfGMALKNWf60TeSmTZ1bAN+BAJpZAP/apvmyTZRWAKliAKpjAJxaAK1lAOiHAPaPANh9APyTANd9APSOANyBAPqQAPiPANF6ANB5AOOEANV9AOaGANV8AOyKANyAAPWPAP6UAPiQANp/AOGDANp+AOaFAOCDAO2KANJ6AP2TAPqRAOOFAM95APSNAP2UAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAAAAAAALAAAAAABAJwAAAeigANdQBRZUD5cLx5MGj1USFU0Q1E/SwBXWxUTNjECKxw3HycLFwkOLRYgJhIuMigkCBsPBBAwIwchKjwROjkZDAEGJQ0zOzUKKQU4HRgiLBVHRgBJQVNNNFJaSj0aVh4vQk5FRBRYTwMTIhgdOAUpCjU7Mw0lBgEMGTk6ETwqIQcjYLAg8GADAhIoZLiQYAKEhRYOElxYcOLDDQ4rBMSwASEQADsK) no-repeat left -26px;
222 height: 26px;
223 line-height: 26px;
224}
225
226div#menus table tbody tr td.hover div a {
227 color: #333366;
228}
229
230/* @group .selected */
231div#menus table tbody tr td.selectedTab {
232 /* background: url(../images/menubarSprite.gif) repeat-x right -78px;*/
233 background: url(data:image/gif;charset=utf-8;base64,R0lGODlhAQCcAOYAANN7AKNfAP2zTf/KgO7QppVXAKJeALFmAOCkTfKtTZhZAPWvTaVgAJ5cAPCsTd2hTdygTaxjAOinTc13APySAOe8gO6rTfSuTZFVAKdhAOqIAN+jTfuyTZJVAO+LAPmxTeuqTbBlAKGDWbFnAOKkTaFdAOmoTfevTeSkTZdXAK9lAPyzTY9TAO+rTeamTfGMALKNWf60TeSmTZ1bAN+BAJpZAP/apvmyTZRWAKliAKpjAJxaAK1lAOiHAPaPANh9APyTANd9APSOANyBAPqQAPiPANF6ANB5AOOEANV9AOaGANV8AOyKANyAAPWPAP6UAPiQANp/AOGDANp+AOaFAOCDAO2KANJ6AP2TAPqRAOOFAM95APSNAP2UAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAAAAAAALAAAAAABAJwAAAeigANdQBRZUD5cLx5MGj1USFU0Q1E/SwBXWxUTNjECKxw3HycLFwkOLRYgJhIuMigkCBsPBBAwIwchKjwROjkZDAEGJQ0zOzUKKQU4HRgiLBVHRgBJQVNNNFJaSj0aVh4vQk5FRBRYTwMTIhgdOAUpCjU7Mw0lBgEMGTk6ETwqIQcjYLAg8GADAhIoZLiQYAKEhRYOElxYcOLDDQ4rBMSwASEQADsK) repeat-x right -78px;
234}
235
236div#menus table tbody tr td.selectedTab div {
237 /* background: url(../images/menubarSprite.gif) no-repeat right -130px;*/
238 background: url(data:image/gif;charset=utf-8;base64,R0lGODlhAQCcAOYAANN7AKNfAP2zTf/KgO7QppVXAKJeALFmAOCkTfKtTZhZAPWvTaVgAJ5cAPCsTd2hTdygTaxjAOinTc13APySAOe8gO6rTfSuTZFVAKdhAOqIAN+jTfuyTZJVAO+LAPmxTeuqTbBlAKGDWbFnAOKkTaFdAOmoTfevTeSkTZdXAK9lAPyzTY9TAO+rTeamTfGMALKNWf60TeSmTZ1bAN+BAJpZAP/apvmyTZRWAKliAKpjAJxaAK1lAOiHAPaPANh9APyTANd9APSOANyBAPqQAPiPANF6ANB5AOOEANV9AOaGANV8AOyKANyAAPWPAP6UAPiQANp/AOGDANp+AOaFAOCDAO2KANJ6AP2TAPqRAOOFAM95APSNAP2UAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAAAAAAALAAAAAABAJwAAAeigANdQBRZUD5cLx5MGj1USFU0Q1E/SwBXWxUTNjECKxw3HycLFwkOLRYgJhIuMigkCBsPBBAwIwchKjwROjkZDAEGJQ0zOzUKKQU4HRgiLBVHRgBJQVNNNFJaSj0aVh4vQk5FRBRYTwMTIhgdOAUpCjU7Mw0lBgEMGTk6ETwqIQcjYLAg8GADAhIoZLiQYAKEhRYOElxYcOLDDQ4rBMSwASEQADsK) no-repeat right -130px;
239}
240
241div#menus table tbody tr td.selectedTab div a {
242 color: #333366;
243 /* background: url(../images/menubarSprite.gif) no-repeat left -104px;*/
244 background: url(data:image/gif;charset=utf-8;base64,R0lGODlhAQCcAOYAANN7AKNfAP2zTf/KgO7QppVXAKJeALFmAOCkTfKtTZhZAPWvTaVgAJ5cAPCsTd2hTdygTaxjAOinTc13APySAOe8gO6rTfSuTZFVAKdhAOqIAN+jTfuyTZJVAO+LAPmxTeuqTbBlAKGDWbFnAOKkTaFdAOmoTfevTeSkTZdXAK9lAPyzTY9TAO+rTeamTfGMALKNWf60TeSmTZ1bAN+BAJpZAP/apvmyTZRWAKliAKpjAJxaAK1lAOiHAPaPANh9APyTANd9APSOANyBAPqQAPiPANF6ANB5AOOEANV9AOaGANV8AOyKANyAAPWPAP6UAPiQANp/AOGDANp+AOaFAOCDAO2KANJ6AP2TAPqRAOOFAM95APSNAP2UAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAAAAAAALAAAAAABAJwAAAeigANdQBRZUD5cLx5MGj1USFU0Q1E/SwBXWxUTNjECKxw3HycLFwkOLRYgJhIuMigkCBsPBBAwIwchKjwROjkZDAEGJQ0zOzUKKQU4HRgiLBVHRgBJQVNNNFJaSj0aVh4vQk5FRBRYTwMTIhgdOAUpCjU7Mw0lBgEMGTk6ETwqIQcjYLAg8GADAhIoZLiQYAKEhRYOElxYcOLDDQ4rBMSwASEQADsK) no-repeat left -104px;
245}
246
247/* @end */
248/*
249ul#menus li {
250 display: inline;
251 padding: 4px 15px;
252 margin-right: 2px;
253 color: white;
254 cursor: pointer;
255 line-height: 16px;
256 border: 1px solid white;
257 border-bottom: 0px;
258 position: relative;
259 top: -5px;
260}
261
262ul#menus li:hover {
263 border: 1px solid #ff9400;
264 border-bottom: 0px;
265}
266
267ul#menus li.selectedTab {
268 border: 1px solid #ff9400;
269 background-color: #ff9400;
270 border-bottom: 0px;
271 color: #333366;
272}
273
274ul#menus li.selectedTab:hover {
275 border: 1px solid #ff9400;
276 background-color: #ff9400;
277 border-bottom: 0px;
278 padding: 4px 15px;
279 color: #333366;
280}
281*/
282
283/* @end */
284
285/* @end */
286
287/* @group Content */
288
289div#content {
290 margin-top: 15px;
291}
292
293div#main {
294 padding-top: 15px;
295 /*margin-left: 15px; margin-right: 15px;*/
296}
297
298div#main ul li.selectedPanel {
299 padding: 0px 15px;
300}
301
302div#main ul li#recordsPanel {
303 padding: 0px;
304}
305
306div#main ul li ul li.selectedPanel {
307 padding: 0px;
308}
309
310/* @group Login page */
311
312
313/* @group Service description */
314div.clipperzServiceDescription {
315 color: #666666;
316 padding-left: 10px;
317 margin-right: 20px;
318}
319
320div.clipperzServiceDescription h2 {
321 color: #ff9400;
322 font-size: 20pt;
323 margin-bottom: 15px;
324}
325
326div.clipperzServiceDescription ul li h3 {
327}
328
329div.clipperzServiceDescription ul li ul {
330 list-style-position: outside;
331 list-style-type: disc;
332 color: #ff9400;
333 margin-bottom: 15px;
334 margin-left: 20px;
335}
336
337div.clipperzServiceDescription ul li ul li p {
338 display: inline;
339 color: #999999;
340 font-size: 11pt;
341}
342
343div.clipperzServiceDescription ul li a {
344 color: #333366;
345 font-weight: bold;
346}
347
348/* @end */
349
350/* @group Form */
351
352div.clipperzLoginForm {
353 /* border: 4px solid #ff9400;*/
354 color: #999999;
355 font-size: 11pt;
356 width: 400px;
357 height: 350px;
358}
359
360div.clipperzLoginForm a {
361 margin-left: 10px;
362 color: #333366;
363 text-decoration: none;
364 font-weight: bold;
365}
366
367div.clipperzLoginForm a:hover {
368 text-decoration: underline;
369}
370
371div.clipperzLoginForm div.loginFormHeaderBox {
372 padding: 30px 20px 0px 20px;
373 /* background: url(../images/loginFormBox.png) no-repeat -3px top;*/
374 background: url(data:image/png;charset=utf-8;base64,iVBORw0KGgoAAAANSUhEUgAABMAAAAAvCAIAAACKdSGFAAAABGdBTUEAANbY1E9YMgAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAv4SURBVHja7N3Zj1vlGcfxY3u8e7ZMokCUNCIbVdIAQrlAkZAIoSigFoTaSOWmN73oQiWqUlX9D0oXEL0A2steRSqV2kRViygpaaAsEpCKQNIkbRayTZaZTGbz2B7bfY6f8eM3niU+E0/EnPl+VE09M6aDjtWf3t857xKpVqseACxC27Z998MPfzfHGyqVyuTkZKFQGB8fHx0dHRkZuXbt2uDg4Df6v9V40zMlriSAYF6O28s/rtyzfPny7ppsNpvJZJLJZDwej0QitxhfpVJJ42tsbGx4eHhoaGhgYOCbl54mvgC0K76WLVvW29vb1dWVy+XS6bTGVzQanft/I8plBBBi7j0yfc1dMwDtJWVvxrQBgFCiQAIIf4dkMAdgUQfO3M8zAeBWsiVowlAgAQAAvqBju5vOJQOAdgVOi02SVAIAAPgiDuZu+hMAuP05Q4EEAAAAALSEAgkAAAAAoEACAACESMlLNL4pjnBBAATghMYNYUKBBAAACA3bJlGMVbsbvxi/yMUBEIATGhImukfXPHbqokACAAB8oXuj7Y44HulpvGPkLFcJQABOaGiYNOUMBRIAAGBxt0d3bBeNRkeiKxpvOvsmFwpAAE5oSJhIpDTdomqxQ3Ys0L/ejKfocpY3sKSGPrN9CwAIGqpaIM/Ftt5deXfqp6f2edt/zsUB0KqTe+2lhImmyjwGaW0ukG5FrFQq+pOm3qg/BxDK0mgxZC8kmyQEAt3ZAgBoZkZvdDG+dbIY64iU/V8PHffOveWt3sGFAnBzEhfXT+jLyWqsP3FP143x0vogrT0Fsqk3akW0r1XHbP8UgBC0R2+mRTu2RHsecyQAYCnnqqWoiMVifpzGs6crd2+IHZl607s/83a/75GoAG7W1vy4qDtd+XIllu7o6NBgaRqkLXiBtBIoL7QrVm7k/rzp/RRIIEyjHPvWGqNFUtP9LWuV1EgAmDtdrT3KUC8ej8vXj6KPra9+NpWfVz72Pn3V2/oDrhWAuRx+xY+Legv7KLpL80TjRWvkbXoCqQ1Qq6D0w3K5rKVxcnLS/6/CSOz8/sTF/bHRM7GJS7HCpWg5z8cHhF4lli4nV5ZTK8u5tcU7d06uejiW6tJsspCS0KBDAsAc3HtwmpzaIQcS646M37sl/snU+97+sde72Vv9EFcMwMzOHfDeec6+OzJ573B2/bJagdQOafeqWnwIOf8Cqe1RG6NVx1KpJO0xcvXf2SMvJS+9Fa2W+MiAJTfoKeej46fj46e9wQ+yn/+hEokXVu4Y2/yj6vL7ZOgTq9MOaU8jAQBGslEHWhqYWh1VIpF4b/Tx9ZX/pKLF2oCs7L2+29v1Gh0SwMztUSKiWtbvJiqJ9yqPa5LE6x1SBJrCOs9xmz111PYopbFYLObz+dLAfzP/+l7f/sfS/W/QHgH4KVMtSSBILEg4FK+eKBQKEhelUsluPLGxFgDM2CHdJ5CJmmQymUqliqk7/zy+u1KpLwUqDHn7dvlT1FgcBMApbH4sSDhIRNRIaEh0SIBIjEiYWIfUkFnYAmk74mh1lIGgDAcnJia8M6/3vfnV7Pl9zEkDMH0kJOEgEVE59VfrkBIgdiuKSwQAM3ZIfT6gHVKHffL1Qvyev4/tdAZnZe/gs95rD/gbLQKARIEEgsRC/dmjkNCQ6LD2qGwrnQVcA9nUHrVAynAwdfSV3qO/aP673Ru9dU96ax7xOtd4mVVeIsenCYRfcdQbv+CNnPXPqz251/aMFrHy2IoPvjN4/aeFLT/U7bW82gQt/S1zWQFgeoHUKaz2BDKTyehtuEPFHeWh8q6uAzLwm/oHrnzs7X3U69nk3fUEoy+A0ZeRMdfrww8d7ni4O+NLp9NSI7U9LniBnN4e9dmjtMdlx3/luX90xf3e9uc5mwhYimSwktjkj2DW7PQPuT73lr9zdH3vL0mnvmO/vFqtFjY/M30rZjokAFh7tJ0tdA2kjPZk2CdDLymQpZpDwzv6ry57uu8v6ZizbmjouHfo1/5/AMDz8uX4noGv9Sfv68xksjXSIfU5pG5OYbPlF/AYj6Z1j9Gzb/Qdc9pjJOY9+KL3le9zKhEA3+od/jFln77qbxVYn0choXE+s66wdpc7TuJoHwCY3iFtEx0pkDL60g6p9/FlSHZh5J7f9PftzB3Y1nWCNUQAXDKy+nB44z/GdpTSqzqz2Vwul6k/gXTXQE4dM9uyjkD/BnZch7bHQqEwOfi/L33yXCOvkj3sAwZg+iDIP6asd7O/D1htJbf84M7DP/k8tyGyfKN7x4tNWQGgqUPaQ0gZ8OlhaVPnpdUXAoxGVv9p9Kl/Xj/zSPf7WzrPxaOsKgeWulIl+tnImv3DDwzG1kpj7OrslPbYWZPNZt0prEHnrwYokHZoh22cI/L5fN+xF2LlsXrIxWiPAGYl4SARsW+XPoeU6Og59sJg7qWIQyJMcoYOCQDWHmUMJiO8eDxuu98LW1Vk6yRH8hv2XF9duTyyMXlqc/bM8vhwT3y8JzGeipW5kkDoTZRjQ8XMUClztdR1ZGzticJdkUROimJnOp2tPXu09ug+gXQL5IKsgbQnkFog/W1Xrxzqufy3xlTVB1+kPQK4SYeUoDj4rH4nATJw+duFO7bZMdn6gusEAEbvqckYTDtkKpWyZ486wVXrpQwH8/n8xETyZLHr+PAWGa3ZaUn6ZlsmwHoBIATcymeLGPVMDgmETHdSd2zO1Nc9SofUr9oehe6gE7Q9BiuQmkG2d06hUFh58tXGH1txv7/uEQDmJkFx9Pe6p44ESN/J317qfdkiTOk9dS4VAGgY2tDQPfTIHTLqBq1iYmJCz1drKpCclgSEOCJsBKW3k3TGuxVI7ZD2IlWj2+fMY/5qqwXSpknY40e/QI4Odl9/v/Gm7c+zaw6AVqLOj4u9j+p33dffOzt2raNOgkxyJuidMAAI9wDRJvZLUbSxmZ3woY8fZUSYTqelQNpBu7ZUUtsjHRIIa3t0N9yyTNBYsA6pEaFLH3XyqrxNa+eCFEjNKXcBpGRT+srb0Wp9z+ieTZzYAaBVEhfdG/WEIomR1OWDxfTXdSswuxnGRQIAl87OcDuk+8BBR4rSHvWEj9meQDJ5FQhfMnizPIHUiQk2YdUePNrxj/OYvDqfAqlhJMHkz18dfKfx67ue4PMDEMC6J+2Mss7Bd/rveFSiTRJGcs3dGYLrBABe7TmDbqWj38r4zwaLOl6Un/g392snfOhOh/r4UTukhioFEghlONgRjjqhXedzJer0sEf96p7bIea99f18prAWa5IT5xvvWPMInx+AACQ06gVSwsQmXOnuguyjAwCzdUhbFWn7r0p+6gMHq44WpzZ/dcYCSZ8EFmMUTH9hgWAdUouiLpCO11i3tGeP857wdfMCaYljU1jlq4z2EqWrjTd1ruHjBBCAExoSJm57tJvlPIEEgOkd0masWYHUwaIEqY7TbPKqe9qHxxpIIKRlsqlAWizYdFZbG+lud38ry4VafQJpi7B1CqtIVQYb78is4iMEEIATGhImurja3e+B++IAMNt4UY/MleGgbpshYzMdHepMsYqjafUj0QqELA1U00pIOx1NS6NlhU12vcV79AGO8dCHA3pny58sUS00fpfI8SkCCMAJDQkTm3Ml7GY5AGC2gaP79ED7pO5inUgk3GeP1h7JVSDcNdKaoc1NsHkK7oTVtuxT2FKBdG9i2URWPjAA7WITrjRn2EcHAFoZNepY0IaGNmBzZ65Ob4+USSBM1bFpMaQbC5EbtetPB9iF1S2QTKMH0Ea20wPzVwEg6AhS10Z6Nz6ZnHHnVdIVCF+BNPZ//6a1kW3/08EKpFsj+dgAtL1A2uCGUQ4AzKNJzpGf5CqwRJrkQk/gCrALq1VHm1IPAG3hTrtyjywDANz6aPL2jCkBLBEtLaN0p0C4a7IBoF2aVuxwQQAAABZrgZw+wmN4B6CN3F0fuBoAAADhKZBcMgALipwBAAAISYFkeAdg4Uoj2QIAABDCAgkAAAAAoEACAAAAAHDLBZLZZQAAAABAgQxQHVmqBGAh6OFA09MGAAAAi6xAevUDPLheAG4DAgcAAGBxF0gAAAAAwBL3fwEGAGLpZ+CuDirCAAAAAElFTkSuQmCCCg==) no-repeat -3px top;
375}
376
377div.clipperzLoginForm h3 {
378 color: #666666;
379 font-size: 14pt;
380 padding: 0px 15px 8px 15px;
381 border-bottom: 1px dotted #ff9400;
382}
383
384div.clipperzLoginForm form table.formLayout {
385 color: #999999;
386 font-size: 10pt;
387 padding: 0px 25px;
388}
389
390div.clipperzLoginForm form table tbody tr.formFieldTR td {
391 height: 22px;
392}
393
394input.loginFormField {
395 font-size: 10pt;
396 height: 20px;
397 width: 251px;
398 /* width: 330px;*/
399 }
400
401div.passwordTypeChooser {
402 padding-top: 2px;
403 width: 250px;
404 padding-bottom: 8px;
405}
406
407/* @group Login form */
408
409input.passwordTypeCheckbox {
410 margin-top: 2px;
411 margin-right: 5px;
412}
413
414div.oneTimePassword input {
415 width: 59px;
416 height: 20px;
417 font-size: 8pt;
418}
419
420div.oneTimePassword span {
421 font-size: 7px;
422 padding: 0px 1px;
423 color: #666666;
424}
425
426div.clipperzLoginForm div.loginForm {
427 text-align: left;
428 /* background: url(../images/loginFormBox.png) repeat-y -408px;*/
429 background: url(data:image/png;charset=utf-8;base64,iVBORw0KGgoAAAANSUhEUgAABMAAAAAvCAIAAACKdSGFAAAABGdBTUEAANbY1E9YMgAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAv4SURBVHja7N3Zj1vlGcfxY3u8e7ZMokCUNCIbVdIAQrlAkZAIoSigFoTaSOWmN73oQiWqUlX9D0oXEL0A2steRSqV2kRViygpaaAsEpCKQNIkbRayTZaZTGbz2B7bfY6f8eM3niU+E0/EnPl+VE09M6aDjtWf3t857xKpVqseACxC27Z998MPfzfHGyqVyuTkZKFQGB8fHx0dHRkZuXbt2uDg4Df6v9V40zMlriSAYF6O28s/rtyzfPny7ppsNpvJZJLJZDwej0QitxhfpVJJ42tsbGx4eHhoaGhgYOCbl54mvgC0K76WLVvW29vb1dWVy+XS6bTGVzQanft/I8plBBBi7j0yfc1dMwDtJWVvxrQBgFCiQAIIf4dkMAdgUQfO3M8zAeBWsiVowlAgAQAAvqBju5vOJQOAdgVOi02SVAIAAPgiDuZu+hMAuP05Q4EEAAAAALSEAgkAAAAAoEACAACESMlLNL4pjnBBAATghMYNYUKBBAAACA3bJlGMVbsbvxi/yMUBEIATGhImukfXPHbqokACAAB8oXuj7Y44HulpvGPkLFcJQABOaGiYNOUMBRIAAGBxt0d3bBeNRkeiKxpvOvsmFwpAAE5oSJhIpDTdomqxQ3Ys0L/ejKfocpY3sKSGPrN9CwAIGqpaIM/Ftt5deXfqp6f2edt/zsUB0KqTe+2lhImmyjwGaW0ukG5FrFQq+pOm3qg/BxDK0mgxZC8kmyQEAt3ZAgBoZkZvdDG+dbIY64iU/V8PHffOveWt3sGFAnBzEhfXT+jLyWqsP3FP143x0vogrT0Fsqk3akW0r1XHbP8UgBC0R2+mRTu2RHsecyQAYCnnqqWoiMVifpzGs6crd2+IHZl607s/83a/75GoAG7W1vy4qDtd+XIllu7o6NBgaRqkLXiBtBIoL7QrVm7k/rzp/RRIIEyjHPvWGqNFUtP9LWuV1EgAmDtdrT3KUC8ej8vXj6KPra9+NpWfVz72Pn3V2/oDrhWAuRx+xY+Legv7KLpL80TjRWvkbXoCqQ1Qq6D0w3K5rKVxcnLS/6/CSOz8/sTF/bHRM7GJS7HCpWg5z8cHhF4lli4nV5ZTK8u5tcU7d06uejiW6tJsspCS0KBDAsAc3HtwmpzaIQcS646M37sl/snU+97+sde72Vv9EFcMwMzOHfDeec6+OzJ573B2/bJagdQOafeqWnwIOf8Cqe1RG6NVx1KpJO0xcvXf2SMvJS+9Fa2W+MiAJTfoKeej46fj46e9wQ+yn/+hEokXVu4Y2/yj6vL7ZOgTq9MOaU8jAQBGslEHWhqYWh1VIpF4b/Tx9ZX/pKLF2oCs7L2+29v1Gh0SwMztUSKiWtbvJiqJ9yqPa5LE6x1SBJrCOs9xmz111PYopbFYLObz+dLAfzP/+l7f/sfS/W/QHgH4KVMtSSBILEg4FK+eKBQKEhelUsluPLGxFgDM2CHdJ5CJmmQymUqliqk7/zy+u1KpLwUqDHn7dvlT1FgcBMApbH4sSDhIRNRIaEh0SIBIjEiYWIfUkFnYAmk74mh1lIGgDAcnJia8M6/3vfnV7Pl9zEkDMH0kJOEgEVE59VfrkBIgdiuKSwQAM3ZIfT6gHVKHffL1Qvyev4/tdAZnZe/gs95rD/gbLQKARIEEgsRC/dmjkNCQ6LD2qGwrnQVcA9nUHrVAynAwdfSV3qO/aP673Ru9dU96ax7xOtd4mVVeIsenCYRfcdQbv+CNnPXPqz251/aMFrHy2IoPvjN4/aeFLT/U7bW82gQt/S1zWQFgeoHUKaz2BDKTyehtuEPFHeWh8q6uAzLwm/oHrnzs7X3U69nk3fUEoy+A0ZeRMdfrww8d7ni4O+NLp9NSI7U9LniBnN4e9dmjtMdlx3/luX90xf3e9uc5mwhYimSwktjkj2DW7PQPuT73lr9zdH3vL0mnvmO/vFqtFjY/M30rZjokAFh7tJ0tdA2kjPZk2CdDLymQpZpDwzv6ry57uu8v6ZizbmjouHfo1/5/AMDz8uX4noGv9Sfv68xksjXSIfU5pG5OYbPlF/AYj6Z1j9Gzb/Qdc9pjJOY9+KL3le9zKhEA3+od/jFln77qbxVYn0choXE+s66wdpc7TuJoHwCY3iFtEx0pkDL60g6p9/FlSHZh5J7f9PftzB3Y1nWCNUQAXDKy+nB44z/GdpTSqzqz2Vwul6k/gXTXQE4dM9uyjkD/BnZch7bHQqEwOfi/L33yXCOvkj3sAwZg+iDIP6asd7O/D1htJbf84M7DP/k8tyGyfKN7x4tNWQGgqUPaQ0gZ8OlhaVPnpdUXAoxGVv9p9Kl/Xj/zSPf7WzrPxaOsKgeWulIl+tnImv3DDwzG1kpj7OrslPbYWZPNZt0prEHnrwYokHZoh22cI/L5fN+xF2LlsXrIxWiPAGYl4SARsW+XPoeU6Og59sJg7qWIQyJMcoYOCQDWHmUMJiO8eDxuu98LW1Vk6yRH8hv2XF9duTyyMXlqc/bM8vhwT3y8JzGeipW5kkDoTZRjQ8XMUClztdR1ZGzticJdkUROimJnOp2tPXu09ug+gXQL5IKsgbQnkFog/W1Xrxzqufy3xlTVB1+kPQK4SYeUoDj4rH4nATJw+duFO7bZMdn6gusEAEbvqckYTDtkKpWyZ486wVXrpQwH8/n8xETyZLHr+PAWGa3ZaUn6ZlsmwHoBIATcymeLGPVMDgmETHdSd2zO1Nc9SofUr9oehe6gE7Q9BiuQmkG2d06hUFh58tXGH1txv7/uEQDmJkFx9Pe6p44ESN/J317qfdkiTOk9dS4VAGgY2tDQPfTIHTLqBq1iYmJCz1drKpCclgSEOCJsBKW3k3TGuxVI7ZD2IlWj2+fMY/5qqwXSpknY40e/QI4Odl9/v/Gm7c+zaw6AVqLOj4u9j+p33dffOzt2raNOgkxyJuidMAAI9wDRJvZLUbSxmZ3woY8fZUSYTqelQNpBu7ZUUtsjHRIIa3t0N9yyTNBYsA6pEaFLH3XyqrxNa+eCFEjNKXcBpGRT+srb0Wp9z+ieTZzYAaBVEhfdG/WEIomR1OWDxfTXdSswuxnGRQIAl87OcDuk+8BBR4rSHvWEj9meQDJ5FQhfMnizPIHUiQk2YdUePNrxj/OYvDqfAqlhJMHkz18dfKfx67ue4PMDEMC6J+2Mss7Bd/rveFSiTRJGcs3dGYLrBABe7TmDbqWj38r4zwaLOl6Un/g392snfOhOh/r4UTukhioFEghlONgRjjqhXedzJer0sEf96p7bIea99f18prAWa5IT5xvvWPMInx+AACQ06gVSwsQmXOnuguyjAwCzdUhbFWn7r0p+6gMHq44WpzZ/dcYCSZ8EFmMUTH9hgWAdUouiLpCO11i3tGeP857wdfMCaYljU1jlq4z2EqWrjTd1ruHjBBCAExoSJm57tJvlPIEEgOkd0masWYHUwaIEqY7TbPKqe9qHxxpIIKRlsqlAWizYdFZbG+lud38ry4VafQJpi7B1CqtIVQYb78is4iMEEIATGhImurja3e+B++IAMNt4UY/MleGgbpshYzMdHepMsYqjafUj0QqELA1U00pIOx1NS6NlhU12vcV79AGO8dCHA3pny58sUS00fpfI8SkCCMAJDQkTm3Ml7GY5AGC2gaP79ED7pO5inUgk3GeP1h7JVSDcNdKaoc1NsHkK7oTVtuxT2FKBdG9i2URWPjAA7WITrjRn2EcHAFoZNepY0IaGNmBzZ65Ob4+USSBM1bFpMaQbC5EbtetPB9iF1S2QTKMH0Ea20wPzVwEg6AhS10Z6Nz6ZnHHnVdIVCF+BNPZ//6a1kW3/08EKpFsj+dgAtL1A2uCGUQ4AzKNJzpGf5CqwRJrkQk/gCrALq1VHm1IPAG3hTrtyjywDANz6aPL2jCkBLBEtLaN0p0C4a7IBoF2aVuxwQQAAABZrgZw+wmN4B6CN3F0fuBoAAADhKZBcMgALipwBAAAISYFkeAdg4Uoj2QIAABDCAgkAAAAAoEACAAAAAHDLBZLZZQAAAABAgQxQHVmqBGAh6OFA09MGAAAAi6xAevUDPLheAG4DAgcAAGBxF0gAAAAAwBL3fwEGAGLpZ+CuDirCAAAAAElFTkSuQmCCCg==) repeat-y -408px;
430 margin: 0px;
431}
432
433div.clipperzLoginForm form table.formLayout {
434 margin: 7px 10px 4px;
435}
436
437div.loginForm div.loginFormFooterBox {
438 padding: 0px 20px 30px 20px;
439 /* background: url(../images/loginFormBox.png) no-repeat -813px bottom;*/
440 background: url(data:image/png;charset=utf-8;base64,iVBORw0KGgoAAAANSUhEUgAABMAAAAAvCAIAAACKdSGFAAAABGdBTUEAANbY1E9YMgAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAv4SURBVHja7N3Zj1vlGcfxY3u8e7ZMokCUNCIbVdIAQrlAkZAIoSigFoTaSOWmN73oQiWqUlX9D0oXEL0A2steRSqV2kRViygpaaAsEpCKQNIkbRayTZaZTGbz2B7bfY6f8eM3niU+E0/EnPl+VE09M6aDjtWf3t857xKpVqseACxC27Z998MPfzfHGyqVyuTkZKFQGB8fHx0dHRkZuXbt2uDg4Df6v9V40zMlriSAYF6O28s/rtyzfPny7ppsNpvJZJLJZDwej0QitxhfpVJJ42tsbGx4eHhoaGhgYOCbl54mvgC0K76WLVvW29vb1dWVy+XS6bTGVzQanft/I8plBBBi7j0yfc1dMwDtJWVvxrQBgFCiQAIIf4dkMAdgUQfO3M8zAeBWsiVowlAgAQAAvqBju5vOJQOAdgVOi02SVAIAAPgiDuZu+hMAuP05Q4EEAAAAALSEAgkAAAAAoEACAACESMlLNL4pjnBBAATghMYNYUKBBAAACA3bJlGMVbsbvxi/yMUBEIATGhImukfXPHbqokACAAB8oXuj7Y44HulpvGPkLFcJQABOaGiYNOUMBRIAAGBxt0d3bBeNRkeiKxpvOvsmFwpAAE5oSJhIpDTdomqxQ3Ys0L/ejKfocpY3sKSGPrN9CwAIGqpaIM/Ftt5deXfqp6f2edt/zsUB0KqTe+2lhImmyjwGaW0ukG5FrFQq+pOm3qg/BxDK0mgxZC8kmyQEAt3ZAgBoZkZvdDG+dbIY64iU/V8PHffOveWt3sGFAnBzEhfXT+jLyWqsP3FP143x0vogrT0Fsqk3akW0r1XHbP8UgBC0R2+mRTu2RHsecyQAYCnnqqWoiMVifpzGs6crd2+IHZl607s/83a/75GoAG7W1vy4qDtd+XIllu7o6NBgaRqkLXiBtBIoL7QrVm7k/rzp/RRIIEyjHPvWGqNFUtP9LWuV1EgAmDtdrT3KUC8ej8vXj6KPra9+NpWfVz72Pn3V2/oDrhWAuRx+xY+Legv7KLpL80TjRWvkbXoCqQ1Qq6D0w3K5rKVxcnLS/6/CSOz8/sTF/bHRM7GJS7HCpWg5z8cHhF4lli4nV5ZTK8u5tcU7d06uejiW6tJsspCS0KBDAsAc3HtwmpzaIQcS646M37sl/snU+97+sde72Vv9EFcMwMzOHfDeec6+OzJ573B2/bJagdQOafeqWnwIOf8Cqe1RG6NVx1KpJO0xcvXf2SMvJS+9Fa2W+MiAJTfoKeej46fj46e9wQ+yn/+hEokXVu4Y2/yj6vL7ZOgTq9MOaU8jAQBGslEHWhqYWh1VIpF4b/Tx9ZX/pKLF2oCs7L2+29v1Gh0SwMztUSKiWtbvJiqJ9yqPa5LE6x1SBJrCOs9xmz111PYopbFYLObz+dLAfzP/+l7f/sfS/W/QHgH4KVMtSSBILEg4FK+eKBQKEhelUsluPLGxFgDM2CHdJ5CJmmQymUqliqk7/zy+u1KpLwUqDHn7dvlT1FgcBMApbH4sSDhIRNRIaEh0SIBIjEiYWIfUkFnYAmk74mh1lIGgDAcnJia8M6/3vfnV7Pl9zEkDMH0kJOEgEVE59VfrkBIgdiuKSwQAM3ZIfT6gHVKHffL1Qvyev4/tdAZnZe/gs95rD/gbLQKARIEEgsRC/dmjkNCQ6LD2qGwrnQVcA9nUHrVAynAwdfSV3qO/aP673Ru9dU96ax7xOtd4mVVeIsenCYRfcdQbv+CNnPXPqz251/aMFrHy2IoPvjN4/aeFLT/U7bW82gQt/S1zWQFgeoHUKaz2BDKTyehtuEPFHeWh8q6uAzLwm/oHrnzs7X3U69nk3fUEoy+A0ZeRMdfrww8d7ni4O+NLp9NSI7U9LniBnN4e9dmjtMdlx3/luX90xf3e9uc5mwhYimSwktjkj2DW7PQPuT73lr9zdH3vL0mnvmO/vFqtFjY/M30rZjokAFh7tJ0tdA2kjPZk2CdDLymQpZpDwzv6ry57uu8v6ZizbmjouHfo1/5/AMDz8uX4noGv9Sfv68xksjXSIfU5pG5OYbPlF/AYj6Z1j9Gzb/Qdc9pjJOY9+KL3le9zKhEA3+od/jFln77qbxVYn0choXE+s66wdpc7TuJoHwCY3iFtEx0pkDL60g6p9/FlSHZh5J7f9PftzB3Y1nWCNUQAXDKy+nB44z/GdpTSqzqz2Vwul6k/gXTXQE4dM9uyjkD/BnZch7bHQqEwOfi/L33yXCOvkj3sAwZg+iDIP6asd7O/D1htJbf84M7DP/k8tyGyfKN7x4tNWQGgqUPaQ0gZ8OlhaVPnpdUXAoxGVv9p9Kl/Xj/zSPf7WzrPxaOsKgeWulIl+tnImv3DDwzG1kpj7OrslPbYWZPNZt0prEHnrwYokHZoh22cI/L5fN+xF2LlsXrIxWiPAGYl4SARsW+XPoeU6Og59sJg7qWIQyJMcoYOCQDWHmUMJiO8eDxuu98LW1Vk6yRH8hv2XF9duTyyMXlqc/bM8vhwT3y8JzGeipW5kkDoTZRjQ8XMUClztdR1ZGzticJdkUROimJnOp2tPXu09ug+gXQL5IKsgbQnkFog/W1Xrxzqufy3xlTVB1+kPQK4SYeUoDj4rH4nATJw+duFO7bZMdn6gusEAEbvqckYTDtkKpWyZ486wVXrpQwH8/n8xETyZLHr+PAWGa3ZaUn6ZlsmwHoBIATcymeLGPVMDgmETHdSd2zO1Nc9SofUr9oehe6gE7Q9BiuQmkG2d06hUFh58tXGH1txv7/uEQDmJkFx9Pe6p44ESN/J317qfdkiTOk9dS4VAGgY2tDQPfTIHTLqBq1iYmJCz1drKpCclgSEOCJsBKW3k3TGuxVI7ZD2IlWj2+fMY/5qqwXSpknY40e/QI4Odl9/v/Gm7c+zaw6AVqLOj4u9j+p33dffOzt2raNOgkxyJuidMAAI9wDRJvZLUbSxmZ3woY8fZUSYTqelQNpBu7ZUUtsjHRIIa3t0N9yyTNBYsA6pEaFLH3XyqrxNa+eCFEjNKXcBpGRT+srb0Wp9z+ieTZzYAaBVEhfdG/WEIomR1OWDxfTXdSswuxnGRQIAl87OcDuk+8BBR4rSHvWEj9meQDJ5FQhfMnizPIHUiQk2YdUePNrxj/OYvDqfAqlhJMHkz18dfKfx67ue4PMDEMC6J+2Mss7Bd/rveFSiTRJGcs3dGYLrBABe7TmDbqWj38r4zwaLOl6Un/g392snfOhOh/r4UTukhioFEghlONgRjjqhXedzJer0sEf96p7bIea99f18prAWa5IT5xvvWPMInx+AACQ06gVSwsQmXOnuguyjAwCzdUhbFWn7r0p+6gMHq44WpzZ/dcYCSZ8EFmMUTH9hgWAdUouiLpCO11i3tGeP857wdfMCaYljU1jlq4z2EqWrjTd1ruHjBBCAExoSJm57tJvlPIEEgOkd0masWYHUwaIEqY7TbPKqe9qHxxpIIKRlsqlAWizYdFZbG+lud38ry4VafQJpi7B1CqtIVQYb78is4iMEEIATGhImurja3e+B++IAMNt4UY/MleGgbpshYzMdHepMsYqjafUj0QqELA1U00pIOx1NS6NlhU12vcV79AGO8dCHA3pny58sUS00fpfI8SkCCMAJDQkTm3Ml7GY5AGC2gaP79ED7pO5inUgk3GeP1h7JVSDcNdKaoc1NsHkK7oTVtuxT2FKBdG9i2URWPjAA7WITrjRn2EcHAFoZNepY0IaGNmBzZ65Ob4+USSBM1bFpMaQbC5EbtetPB9iF1S2QTKMH0Ea20wPzVwEg6AhS10Z6Nz6ZnHHnVdIVCF+BNPZ//6a1kW3/08EKpFsj+dgAtL1A2uCGUQ4AzKNJzpGf5CqwRJrkQk/gCrALq1VHm1IPAG3hTrtyjywDANz6aPL2jCkBLBEtLaN0p0C4a7IBoF2aVuxwQQAAABZrgZw+wmN4B6CN3F0fuBoAAADhKZBcMgALipwBAAAISYFkeAdg4Uoj2QIAABDCAgkAAAAAoEACAAAAAHDLBZLZZQAAAABAgQxQHVmqBGAh6OFA09MGAAAAi6xAevUDPLheAG4DAgcAAGBxF0gAAAAAwBL3fwEGAGLpZ+CuDirCAAAAAElFTkSuQmCCCg==) no-repeat -813px bottom;
441}
442
443div.loginForm ul {
444 padding: 8px 15px 8px 15px;
445 border-top: 1px dotted #ff9400;
446}
447
448div.loginFormButtonFooter {
449 padding: 0px 40px 10px;
450}
451
452/* @end */
453
454/* @group Registration form */
455
456div.clipperzLoginForm div.registrationForm {
457 text-align: left;
458 /* background: url(../images/loginFormBox.png) repeat-y -408px;*/
459 background: url(data:image/png;charset=utf-8;base64,iVBORw0KGgoAAAANSUhEUgAABMAAAAAvCAIAAACKdSGFAAAABGdBTUEAANbY1E9YMgAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAv4SURBVHja7N3Zj1vlGcfxY3u8e7ZMokCUNCIbVdIAQrlAkZAIoSigFoTaSOWmN73oQiWqUlX9D0oXEL0A2steRSqV2kRViygpaaAsEpCKQNIkbRayTZaZTGbz2B7bfY6f8eM3niU+E0/EnPl+VE09M6aDjtWf3t857xKpVqseACxC27Z998MPfzfHGyqVyuTkZKFQGB8fHx0dHRkZuXbt2uDg4Df6v9V40zMlriSAYF6O28s/rtyzfPny7ppsNpvJZJLJZDwej0QitxhfpVJJ42tsbGx4eHhoaGhgYOCbl54mvgC0K76WLVvW29vb1dWVy+XS6bTGVzQanft/I8plBBBi7j0yfc1dMwDtJWVvxrQBgFCiQAIIf4dkMAdgUQfO3M8zAeBWsiVowlAgAQAAvqBju5vOJQOAdgVOi02SVAIAAPgiDuZu+hMAuP05Q4EEAAAAALSEAgkAAAAAoEACAACESMlLNL4pjnBBAATghMYNYUKBBAAACA3bJlGMVbsbvxi/yMUBEIATGhImukfXPHbqokACAAB8oXuj7Y44HulpvGPkLFcJQABOaGiYNOUMBRIAAGBxt0d3bBeNRkeiKxpvOvsmFwpAAE5oSJhIpDTdomqxQ3Ys0L/ejKfocpY3sKSGPrN9CwAIGqpaIM/Ftt5deXfqp6f2edt/zsUB0KqTe+2lhImmyjwGaW0ukG5FrFQq+pOm3qg/BxDK0mgxZC8kmyQEAt3ZAgBoZkZvdDG+dbIY64iU/V8PHffOveWt3sGFAnBzEhfXT+jLyWqsP3FP143x0vogrT0Fsqk3akW0r1XHbP8UgBC0R2+mRTu2RHsecyQAYCnnqqWoiMVifpzGs6crd2+IHZl607s/83a/75GoAG7W1vy4qDtd+XIllu7o6NBgaRqkLXiBtBIoL7QrVm7k/rzp/RRIIEyjHPvWGqNFUtP9LWuV1EgAmDtdrT3KUC8ej8vXj6KPra9+NpWfVz72Pn3V2/oDrhWAuRx+xY+Legv7KLpL80TjRWvkbXoCqQ1Qq6D0w3K5rKVxcnLS/6/CSOz8/sTF/bHRM7GJS7HCpWg5z8cHhF4lli4nV5ZTK8u5tcU7d06uejiW6tJsspCS0KBDAsAc3HtwmpzaIQcS646M37sl/snU+97+sde72Vv9EFcMwMzOHfDeec6+OzJ573B2/bJagdQOafeqWnwIOf8Cqe1RG6NVx1KpJO0xcvXf2SMvJS+9Fa2W+MiAJTfoKeej46fj46e9wQ+yn/+hEokXVu4Y2/yj6vL7ZOgTq9MOaU8jAQBGslEHWhqYWh1VIpF4b/Tx9ZX/pKLF2oCs7L2+29v1Gh0SwMztUSKiWtbvJiqJ9yqPa5LE6x1SBJrCOs9xmz111PYopbFYLObz+dLAfzP/+l7f/sfS/W/QHgH4KVMtSSBILEg4FK+eKBQKEhelUsluPLGxFgDM2CHdJ5CJmmQymUqliqk7/zy+u1KpLwUqDHn7dvlT1FgcBMApbH4sSDhIRNRIaEh0SIBIjEiYWIfUkFnYAmk74mh1lIGgDAcnJia8M6/3vfnV7Pl9zEkDMH0kJOEgEVE59VfrkBIgdiuKSwQAM3ZIfT6gHVKHffL1Qvyev4/tdAZnZe/gs95rD/gbLQKARIEEgsRC/dmjkNCQ6LD2qGwrnQVcA9nUHrVAynAwdfSV3qO/aP673Ru9dU96ax7xOtd4mVVeIsenCYRfcdQbv+CNnPXPqz251/aMFrHy2IoPvjN4/aeFLT/U7bW82gQt/S1zWQFgeoHUKaz2BDKTyehtuEPFHeWh8q6uAzLwm/oHrnzs7X3U69nk3fUEoy+A0ZeRMdfrww8d7ni4O+NLp9NSI7U9LniBnN4e9dmjtMdlx3/luX90xf3e9uc5mwhYimSwktjkj2DW7PQPuT73lr9zdH3vL0mnvmO/vFqtFjY/M30rZjokAFh7tJ0tdA2kjPZk2CdDLymQpZpDwzv6ry57uu8v6ZizbmjouHfo1/5/AMDz8uX4noGv9Sfv68xksjXSIfU5pG5OYbPlF/AYj6Z1j9Gzb/Qdc9pjJOY9+KL3le9zKhEA3+od/jFln77qbxVYn0choXE+s66wdpc7TuJoHwCY3iFtEx0pkDL60g6p9/FlSHZh5J7f9PftzB3Y1nWCNUQAXDKy+nB44z/GdpTSqzqz2Vwul6k/gXTXQE4dM9uyjkD/BnZch7bHQqEwOfi/L33yXCOvkj3sAwZg+iDIP6asd7O/D1htJbf84M7DP/k8tyGyfKN7x4tNWQGgqUPaQ0gZ8OlhaVPnpdUXAoxGVv9p9Kl/Xj/zSPf7WzrPxaOsKgeWulIl+tnImv3DDwzG1kpj7OrslPbYWZPNZt0prEHnrwYokHZoh22cI/L5fN+xF2LlsXrIxWiPAGYl4SARsW+XPoeU6Og59sJg7qWIQyJMcoYOCQDWHmUMJiO8eDxuu98LW1Vk6yRH8hv2XF9duTyyMXlqc/bM8vhwT3y8JzGeipW5kkDoTZRjQ8XMUClztdR1ZGzticJdkUROimJnOp2tPXu09ug+gXQL5IKsgbQnkFog/W1Xrxzqufy3xlTVB1+kPQK4SYeUoDj4rH4nATJw+duFO7bZMdn6gusEAEbvqckYTDtkKpWyZ486wVXrpQwH8/n8xETyZLHr+PAWGa3ZaUn6ZlsmwHoBIATcymeLGPVMDgmETHdSd2zO1Nc9SofUr9oehe6gE7Q9BiuQmkG2d06hUFh58tXGH1txv7/uEQDmJkFx9Pe6p44ESN/J317qfdkiTOk9dS4VAGgY2tDQPfTIHTLqBq1iYmJCz1drKpCclgSEOCJsBKW3k3TGuxVI7ZD2IlWj2+fMY/5qqwXSpknY40e/QI4Odl9/v/Gm7c+zaw6AVqLOj4u9j+p33dffOzt2raNOgkxyJuidMAAI9wDRJvZLUbSxmZ3woY8fZUSYTqelQNpBu7ZUUtsjHRIIa3t0N9yyTNBYsA6pEaFLH3XyqrxNa+eCFEjNKXcBpGRT+srb0Wp9z+ieTZzYAaBVEhfdG/WEIomR1OWDxfTXdSswuxnGRQIAl87OcDuk+8BBR4rSHvWEj9meQDJ5FQhfMnizPIHUiQk2YdUePNrxj/OYvDqfAqlhJMHkz18dfKfx67ue4PMDEMC6J+2Mss7Bd/rveFSiTRJGcs3dGYLrBABe7TmDbqWj38r4zwaLOl6Un/g392snfOhOh/r4UTukhioFEghlONgRjjqhXedzJer0sEf96p7bIea99f18prAWa5IT5xvvWPMInx+AACQ06gVSwsQmXOnuguyjAwCzdUhbFWn7r0p+6gMHq44WpzZ/dcYCSZ8EFmMUTH9hgWAdUouiLpCO11i3tGeP857wdfMCaYljU1jlq4z2EqWrjTd1ruHjBBCAExoSJm57tJvlPIEEgOkd0masWYHUwaIEqY7TbPKqe9qHxxpIIKRlsqlAWizYdFZbG+lud38ry4VafQJpi7B1CqtIVQYb78is4iMEEIATGhImurja3e+B++IAMNt4UY/MleGgbpshYzMdHepMsYqjafUj0QqELA1U00pIOx1NS6NlhU12vcV79AGO8dCHA3pny58sUS00fpfI8SkCCMAJDQkTm3Ml7GY5AGC2gaP79ED7pO5inUgk3GeP1h7JVSDcNdKaoc1NsHkK7oTVtuxT2FKBdG9i2URWPjAA7WITrjRn2EcHAFoZNepY0IaGNmBzZ65Ob4+USSBM1bFpMaQbC5EbtetPB9iF1S2QTKMH0Ea20wPzVwEg6AhS10Z6Nz6ZnHHnVdIVCF+BNPZ//6a1kW3/08EKpFsj+dgAtL1A2uCGUQ4AzKNJzpGf5CqwRJrkQk/gCrALq1VHm1IPAG3hTrtyjywDANz6aPL2jCkBLBEtLaN0p0C4a7IBoF2aVuxwQQAAABZrgZw+wmN4B6CN3F0fuBoAAADhKZBcMgALipwBAAAISYFkeAdg4Uoj2QIAABDCAgkAAAAAoEACAAAAAHDLBZLZZQAAAABAgQxQHVmqBGAh6OFA09MGAAAAi6xAevUDPLheAG4DAgcAAGBxF0gAAAAAwBL3fwEGAGLpZ+CuDirCAAAAAElFTkSuQmCCCg==) repeat-y -408px;
460 margin: 0px;
461}
462
463div.clipperzLoginForm div.registrationForm form a {
464 margin: 0px;
465}
466div.registrationForm form table.formLayout {
467 padding: 10px;
468 /*padding: 4px 10px;*/
469 margin: 0px 20px;
470}
471
472
473/*
474div.clipperzLoginForm form.read-only table.formLayout {
475 background-image: url(../images/read-only_background.png);
476}
477
478div.panelBody form.read-only table.panelBody {
479 background-image: url(../images/read-only_background.png);
480}
481
482*/
483
484div.clipperzLoginForm form.read-only table.formLayout, div.panelBody form.read-only table.panelBody, div.clipperzSubPanel span.read-only, div.read-only {
485 /* background-image: url(../images/read-only_background.png);*/
486 background-image: url(data:image/png;charset=utf-8;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAABGdBTUEAANbY1E9YMgAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAT8SURBVHjaxJppc9NIEIZbshTHxkACNhRHQVGQAwJF8cv5FxRfdosjCVeyG7aA3U3sOM7tIxLdGmFLmkMz40lwpSo+ZtR69HbPdLfkxZsvD6AyW4XkFSd/cP0ZwOW7wL32vwLsfgDwMt9FOKHeBGg+B6jM5McPjwG2/8T/Bzjn1yQyUAG48QKg1uJtdD8D9P7ibTRuow08L8/Pjx/0AP593Q8gqM9CpRowCJw9vwBw6TZv4PA7gvwNENYKEPMI/gTAD/PjRycAnXUcM8I59ZSBIHw2vtbkbfTw+Ic/eBuNGwDXlgUQeIE6H+mdF0AcxWMl5hcR4pYYYu8Lf5VmFRDtNVTiEH/z9CFIcd8rXCgJBKncQRtnp8nBM0ooILpfknMYk1hBoDtdf2wB8TjjllklUoj0t4ApsaBWQgixgt8HehBehZ2QlRIFCDp2AYLE8OKDbwNo3AnV7jQFRKLEsjiwxxAFGwZKJDaiaOjFcTzAj3mQw28IseEIokwJEYQoJvDY7VUewp+h8cNArIQFxEjkTssWECIlyJ0kEBSn1TnweSUs3ckTQbQslDCHYMHu2p1wRbdTQrRPEMR7hOgrIQDSQzKITUfutOQuJjQhmCJk4OCrAGJOAYFSD48slNDd7Ciw9SFo+fWh+0mixFMDCF0lzgGCfsNUKDBzJ5kSSyWBPa0SoRyCFqf9fzLBroQ4ZRAjmRKti1cCUghKMvGcAj2I9xJ3WnajhHJ1wnOqXhUrkUJARNfLNcT+lgTiJlNPuDqt6kMUlJisWhSgSRYrgRjZKCFypyUHSkRsrytA0BwvPhsOECLUV0KSO5ESvS2JEotsrlbuFLIVU6REl1civVCYaxkrYbLE3jRUQgIRi90psUEl+dxDCJwoIQ3sRYOYUCghcqcMBG0fQbkSvkZRZKKEI3fKQEySxotQ4hwhGMjoOM1ibZTwfrsSE5D//8B5ZwYQpkpIylMpBCgg7iDEI378aQe9myuKCOKJZJ/YYi4l3bErU0LErEEnhVgQQHQBtt9Q0iiCaBpAyNzJtRISiM4HHDNIg70UQpU7ySDWHcaEwJ36XWYjHiY2WIMOypQwSQAlSnguYyIPkS6/FXdtTGMlwC4mChAs1zraHkC9FTrpxbZlMbEiqCfcQeAHSYPOQS9WnYpbQFBMtAUQlRp5lKBB56IXm6vsDCAaisAWQtQBmmgjbBSSRmU9cRFKiCD25EqkEPkGnbTv1Dp/JaRL7B6rWeLRxAaND+o5iAmIaS9WGtiyRoEtxFoegmwENQ6CgYwNaPZik8rOBMJysxNBJO6Ey3h4iSuBfehtpgY0e7Ht1XOG2DODiDDh3XmbybW0erEGEBrlqVZMKJVACOqUHv1XaNC57gBOG9hlELsfAY53Ehv+dB3AFUdKdC0gPo0hWLCr7mNfmBImMTFi7pSBYCD0RIGzXuyGhRLrAohZdUwUIFjSGJ0NECLkVyeEiEx6sRvs/qNmjT1tTIwvXgRkA3Mt2eoU9SVZrF4vVglxihC7a24grj4AuHK/kGu56sUqISSpuMqdSiAm9xBLO4Ar1h1AVXmah3hmDTHJtUz7TrGNO5lCROzJn5NyCAYy2PeMGwWmEKTEroUSJ4XVSQLBHnP68QoJ4moyIU5P1JthD5JxSqQb0a/CK8pAXLknhjjpYC70JmnZ5Gz4ipjYeZekHTkbNI+Oz0Pg2O/9nwIMAFYA4szm5y3UAAAAAElFTkSuQmCCCg==);
487}
488
489div.registrationForm div.loginFormFooterBox {
490 padding: 0px 20px 30px 20px;
491 /* background: url(../images/loginFormBox.png) no-repeat -813px bottom;*/
492 background: url(data:image/png;charset=utf-8;base64,iVBORw0KGgoAAAANSUhEUgAABMAAAAAvCAIAAACKdSGFAAAABGdBTUEAANbY1E9YMgAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAv4SURBVHja7N3Zj1vlGcfxY3u8e7ZMokCUNCIbVdIAQrlAkZAIoSigFoTaSOWmN73oQiWqUlX9D0oXEL0A2steRSqV2kRViygpaaAsEpCKQNIkbRayTZaZTGbz2B7bfY6f8eM3niU+E0/EnPl+VE09M6aDjtWf3t857xKpVqseACxC27Z998MPfzfHGyqVyuTkZKFQGB8fHx0dHRkZuXbt2uDg4Df6v9V40zMlriSAYF6O28s/rtyzfPny7ppsNpvJZJLJZDwej0QitxhfpVJJ42tsbGx4eHhoaGhgYOCbl54mvgC0K76WLVvW29vb1dWVy+XS6bTGVzQanft/I8plBBBi7j0yfc1dMwDtJWVvxrQBgFCiQAIIf4dkMAdgUQfO3M8zAeBWsiVowlAgAQAAvqBju5vOJQOAdgVOi02SVAIAAPgiDuZu+hMAuP05Q4EEAAAAALSEAgkAAAAAoEACAACESMlLNL4pjnBBAATghMYNYUKBBAAACA3bJlGMVbsbvxi/yMUBEIATGhImukfXPHbqokACAAB8oXuj7Y44HulpvGPkLFcJQABOaGiYNOUMBRIAAGBxt0d3bBeNRkeiKxpvOvsmFwpAAE5oSJhIpDTdomqxQ3Ys0L/ejKfocpY3sKSGPrN9CwAIGqpaIM/Ftt5deXfqp6f2edt/zsUB0KqTe+2lhImmyjwGaW0ukG5FrFQq+pOm3qg/BxDK0mgxZC8kmyQEAt3ZAgBoZkZvdDG+dbIY64iU/V8PHffOveWt3sGFAnBzEhfXT+jLyWqsP3FP143x0vogrT0Fsqk3akW0r1XHbP8UgBC0R2+mRTu2RHsecyQAYCnnqqWoiMVifpzGs6crd2+IHZl607s/83a/75GoAG7W1vy4qDtd+XIllu7o6NBgaRqkLXiBtBIoL7QrVm7k/rzp/RRIIEyjHPvWGqNFUtP9LWuV1EgAmDtdrT3KUC8ej8vXj6KPra9+NpWfVz72Pn3V2/oDrhWAuRx+xY+Legv7KLpL80TjRWvkbXoCqQ1Qq6D0w3K5rKVxcnLS/6/CSOz8/sTF/bHRM7GJS7HCpWg5z8cHhF4lli4nV5ZTK8u5tcU7d06uejiW6tJsspCS0KBDAsAc3HtwmpzaIQcS646M37sl/snU+97+sde72Vv9EFcMwMzOHfDeec6+OzJ573B2/bJagdQOafeqWnwIOf8Cqe1RG6NVx1KpJO0xcvXf2SMvJS+9Fa2W+MiAJTfoKeej46fj46e9wQ+yn/+hEokXVu4Y2/yj6vL7ZOgTq9MOaU8jAQBGslEHWhqYWh1VIpF4b/Tx9ZX/pKLF2oCs7L2+29v1Gh0SwMztUSKiWtbvJiqJ9yqPa5LE6x1SBJrCOs9xmz111PYopbFYLObz+dLAfzP/+l7f/sfS/W/QHgH4KVMtSSBILEg4FK+eKBQKEhelUsluPLGxFgDM2CHdJ5CJmmQymUqliqk7/zy+u1KpLwUqDHn7dvlT1FgcBMApbH4sSDhIRNRIaEh0SIBIjEiYWIfUkFnYAmk74mh1lIGgDAcnJia8M6/3vfnV7Pl9zEkDMH0kJOEgEVE59VfrkBIgdiuKSwQAM3ZIfT6gHVKHffL1Qvyev4/tdAZnZe/gs95rD/gbLQKARIEEgsRC/dmjkNCQ6LD2qGwrnQVcA9nUHrVAynAwdfSV3qO/aP673Ru9dU96ax7xOtd4mVVeIsenCYRfcdQbv+CNnPXPqz251/aMFrHy2IoPvjN4/aeFLT/U7bW82gQt/S1zWQFgeoHUKaz2BDKTyehtuEPFHeWh8q6uAzLwm/oHrnzs7X3U69nk3fUEoy+A0ZeRMdfrww8d7ni4O+NLp9NSI7U9LniBnN4e9dmjtMdlx3/luX90xf3e9uc5mwhYimSwktjkj2DW7PQPuT73lr9zdH3vL0mnvmO/vFqtFjY/M30rZjokAFh7tJ0tdA2kjPZk2CdDLymQpZpDwzv6ry57uu8v6ZizbmjouHfo1/5/AMDz8uX4noGv9Sfv68xksjXSIfU5pG5OYbPlF/AYj6Z1j9Gzb/Qdc9pjJOY9+KL3le9zKhEA3+od/jFln77qbxVYn0choXE+s66wdpc7TuJoHwCY3iFtEx0pkDL60g6p9/FlSHZh5J7f9PftzB3Y1nWCNUQAXDKy+nB44z/GdpTSqzqz2Vwul6k/gXTXQE4dM9uyjkD/BnZch7bHQqEwOfi/L33yXCOvkj3sAwZg+iDIP6asd7O/D1htJbf84M7DP/k8tyGyfKN7x4tNWQGgqUPaQ0gZ8OlhaVPnpdUXAoxGVv9p9Kl/Xj/zSPf7WzrPxaOsKgeWulIl+tnImv3DDwzG1kpj7OrslPbYWZPNZt0prEHnrwYokHZoh22cI/L5fN+xF2LlsXrIxWiPAGYl4SARsW+XPoeU6Og59sJg7qWIQyJMcoYOCQDWHmUMJiO8eDxuu98LW1Vk6yRH8hv2XF9duTyyMXlqc/bM8vhwT3y8JzGeipW5kkDoTZRjQ8XMUClztdR1ZGzticJdkUROimJnOp2tPXu09ug+gXQL5IKsgbQnkFog/W1Xrxzqufy3xlTVB1+kPQK4SYeUoDj4rH4nATJw+duFO7bZMdn6gusEAEbvqckYTDtkKpWyZ486wVXrpQwH8/n8xETyZLHr+PAWGa3ZaUn6ZlsmwHoBIATcymeLGPVMDgmETHdSd2zO1Nc9SofUr9oehe6gE7Q9BiuQmkG2d06hUFh58tXGH1txv7/uEQDmJkFx9Pe6p44ESN/J317qfdkiTOk9dS4VAGgY2tDQPfTIHTLqBq1iYmJCz1drKpCclgSEOCJsBKW3k3TGuxVI7ZD2IlWj2+fMY/5qqwXSpknY40e/QI4Odl9/v/Gm7c+zaw6AVqLOj4u9j+p33dffOzt2raNOgkxyJuidMAAI9wDRJvZLUbSxmZ3woY8fZUSYTqelQNpBu7ZUUtsjHRIIa3t0N9yyTNBYsA6pEaFLH3XyqrxNa+eCFEjNKXcBpGRT+srb0Wp9z+ieTZzYAaBVEhfdG/WEIomR1OWDxfTXdSswuxnGRQIAl87OcDuk+8BBR4rSHvWEj9meQDJ5FQhfMnizPIHUiQk2YdUePNrxj/OYvDqfAqlhJMHkz18dfKfx67ue4PMDEMC6J+2Mss7Bd/rveFSiTRJGcs3dGYLrBABe7TmDbqWj38r4zwaLOl6Un/g392snfOhOh/r4UTukhioFEghlONgRjjqhXedzJer0sEf96p7bIea99f18prAWa5IT5xvvWPMInx+AACQ06gVSwsQmXOnuguyjAwCzdUhbFWn7r0p+6gMHq44WpzZ/dcYCSZ8EFmMUTH9hgWAdUouiLpCO11i3tGeP857wdfMCaYljU1jlq4z2EqWrjTd1ruHjBBCAExoSJm57tJvlPIEEgOkd0masWYHUwaIEqY7TbPKqe9qHxxpIIKRlsqlAWizYdFZbG+lud38ry4VafQJpi7B1CqtIVQYb78is4iMEEIATGhImurja3e+B++IAMNt4UY/MleGgbpshYzMdHepMsYqjafUj0QqELA1U00pIOx1NS6NlhU12vcV79AGO8dCHA3pny58sUS00fpfI8SkCCMAJDQkTm3Ml7GY5AGC2gaP79ED7pO5inUgk3GeP1h7JVSDcNdKaoc1NsHkK7oTVtuxT2FKBdG9i2URWPjAA7WITrjRn2EcHAFoZNepY0IaGNmBzZ65Ob4+USSBM1bFpMaQbC5EbtetPB9iF1S2QTKMH0Ea20wPzVwEg6AhS10Z6Nz6ZnHHnVdIVCF+BNPZ//6a1kW3/08EKpFsj+dgAtL1A2uCGUQ4AzKNJzpGf5CqwRJrkQk/gCrALq1VHm1IPAG3hTrtyjywDANz6aPL2jCkBLBEtLaN0p0C4a7IBoF2aVuxwQQAAABZrgZw+wmN4B6CN3F0fuBoAAADhKZBcMgALipwBAAAISYFkeAdg4Uoj2QIAABDCAgkAAAAAoEACAAAAAHDLBZLZZQAAAABAgQxQHVmqBGAh6OFA09MGAAAAi6xAevUDPLheAG4DAgcAAGBxF0gAAAAAwBL3fwEGAGLpZ+CuDirCAAAAAElFTkSuQmCCCg==) no-repeat -813px bottom;
493}
494
495div.registrationForm ul {
496 padding: 8px 15px 8px 15px;
497 border-top: 1px dotted #ff9400;
498}
499
500/* @end */
501
502
503/* @end */
504
505/* @group Registration splash */
506
507div#splashMessage table {
508 width: auto;
509 color: #333366;
510 font-size: 10pt;
511 padding: 10px;
512}
513
514div#splashMessage span {
515 color: #666666;
516}
517
518div#splashMessage table span.label {
519 color: #999999;
520 padding-right: 10px;
521}
522
523div#splashMessage table span.value {
524 color: #666666;
525 font-weight: bold;
526}
527
528div#splashMessage input {
529 margin-right: 5px;
530}
531/* @end */
532
533/* @group Browser compatibility box */
534
535div.browserCompatibilityBox {
536 color: #666666;
537 padding: 0px 0px;
538 /*border: 4px solid #ff9400; */
539 font-weight: bold;
540 text-align: center;
541 width: 400px;
542}
543
544div.browserCompatibilityBox p {
545 margin: 0px 50px;
546}
547div.browserCompatibilityBox a {
548 color: #666666;
549}
550
551/* @end */
552
553/* @group Language switch */
554
555li#loginPanel {
556 padding: 0px 15px;
557}
558
559div.loginPanelSwitchLanguageBox {
560 color: #666666;
561 padding: 12px 0px 10px 0px;
562 /*border: 4px solid #ff9400; */
563 font-weight: bold;
564 text-align: center;
565 height: 75px;
566 /* background: url(../images/languageBox.png) no-repeat 19px -15px;*/
567 background: url(data:image/png;charset=utf-8;base64,iVBORw0KGgoAAAANSUhEUgAAAWUAAABpCAIAAABtUqUjAAANIWlDQ1BJQ0MgUHJvZmlsZQAAeJyV13k0lG8bB/BrFsYyZhhjDyO77LKHLJFItmwp2bdhJiZRypIUIkso2iiSFC0kEtWPLCHJkq2oyJI9kmXeP6R6f+f9ve95rz+ecz3385xz389zzud7nxsAr+FKpZKRABAQSAuyNjEgOTg6kTBdgAJewAEzaLi6B1P1LS3N4R9roRMQAADtcq5UKvmf3/uPhQtycHQCQMgCANF7vd8OAES39d4WAIhHaFQaAMIHAIjuPq4eAIhwAJANsrU2BEAUAADOe70vBwCc23pfDwC4EHdvGgCiG4CREOjhGwiAmQBg1PXwDHYHwMkCgIdHsHsAAC4ZACwCAigeALgPACDlTg2iAeCZAEDOwdGJtL7kffEAW/kAmMx+jx1JByjNAZDa/XtM9BEAtytAbuLvsTlrQAAAgrs12EtFGQAAEFgDAIYBOn1OAgCTCrCaQqcv59Lpq9cBUH0ANWT3w0EhP/8XAtEM8L/u17/5Z6EQAEgAhBgiH3kUFY4OZzjBGImJZjrJbMRcy3Ka9Qw2ju0srozdhyOFkMKZSjzPlc6dzpPJW8tPEcjelC14WaiedFgkd/N10VbxYxL5km3SJ2Rub+mUi5a/o9CjdFr5vsp71bNqZeqDmklaFdrDOmm6T/XG9DMMnhtO7sgyrjOZNb26q9FsYXeuRcue15avrdqsV2wL93bYddp3OXQ7offdc+7b339gwOX9wQ9uWPfHHp88P3sNe4/4fPEd9eciPwv4GjhJmaJOH5oJmg2ep80f/haycGQx9HvY0tEfx1bCV46vRkhHdkQjTiJjUKfQsQynGc9g4pjimRNYzrImYpPYzuGS8SnsqRxphPOc6cQMrkzuCzwXebP4svkvCVzedEXwqtA14RxSrsj1zTdE88TyxW9KFkjekiqUvi1ze7yIfEf2rlyxQoniPaX7Sg+UH24tVS1TK1t4FFKu/lijQqtS+8m2qm1PdZ6uVUfU6D3b/lz/hcFfhrXo2pi6HS+N600aTBtNm1iaEl6ZNZu3WLTiWs+9tmyzemPdTmhPfWvTYdu5t4u7K7Pb/p1Dj1Mvf292n3O/88D+90Lvr35wGTw4JDKU+9Htk/tnj2Hx4fwRry/eoz5j0mOF434T/l/Jk3KTd6cCpykz1Fml2ftzQfPB32gLqgtliyHfQ5fCfoQtay1XrhxbDV/TWXtKpwMgRJE45DSqCX2bIY0xHOPNZMtsyLKVVRIrycaL48HzsvNycBEkOKWIGlzm3Ad4gnmT+Ir5mwRGBTmF1IS9SRdEXooixHTED0nck5ySlpIhb6mUQ8nrK6QoDipLq8Ru7VKTUadq1GrxaIdue6XLrUfZ/txAzPCYUZuxkEnozirTJTMlc8/d6RZtljgrE+tQmzzbt3Ys9tsdDjledqrbN7Vf+MAel6MHc11r3UY9uDz1vBy8T/hc863x6/dfCuAM3EIxovocCg9KDs6llR6uD+k9Mha6cBR1jCOcdFz2hGrE9kizqD3R+04ejPE8RY6lnQ46ExkXGX8yIe5samJCUta5i8mZKSmpl9JSz2ekX8goyLx54e7Fgqzb2cWXnlx+cqX26qtrbTntue3X22/05n3KH7k5VPD51lThzO2posk7s3enisdLJu6N3B98MPSwp7StrOFRTfmjx8UVlypTn0RWBTzdV21Ws+2ZzHPC86UXH/5qrH1Yl/YyqN6mQa1RoJHe1PPqYXN8i1OraOvw6wdtx9/saMe197+91uHXqdK52tXcnfZuf490z1xvRV90v9kAcWDg/a0PwYPaQ+ihxo/nPx34LPl5YrhiJOrLrlGu0f6xG+PkCdWJta8Nk6lT+6bFpidmHsyGz5nME+a7v+UtUBY1v6O+v1xK+bFvWXT560rZauSaKZ2bTgeAk4hQ5FGUNqoCfZxBj6GaMQpzismYqZY5luU0azx2F7aJLRGXiE9i38PeypFMSOVMI6Zx2XK95c7gyeC9wJfFny2QvemSoLNgv9BV4WukHJGczTmi18VuiOdJ5EvelCqQviXjKzO2pVC2SO6O/F2FYsUSpXvK91UebH2oWqZWpl6mEarxXbNCq0K7ctsTnSrdE7pretXba/SfGTw3fGEUswO9o9a4zuTlznrThl2NZgnmWPNXu5stWva0WiZbsVu1Wb+xabd9u7fTLsOe277LodvxnVPPvmxnAee+/f0H3rt8OPjBNcdNxG3I/aPHJ8/PXvneEusJ4jfmf5ssS574txSZ+5Ui5WEaYUtHfxxbDl85vnpiLYIeBdHIX0mCOYOJY4priN+VwHoWm4hNYjuHT2ZP4fiVJdyZPBd4f2bJpj+zJHfouvsN0TyxfImbEhtpUiR7R+6u/B9ZolK6tUz1kXq5+mONCs1K7SfaVdue6lbr/pEjO+qMXxrXmzTsbDRtMnsV0rK51eK1ZZvlG6v24x0ynXZd9t3RPQq9Tn2xAyrv4wZVh85+8hjWHkkZ9R33+0qeoszEzzstnFtKWLWm0wHW9z4AAEY1gIwtAHZZADa5ALFbACRdALgLACzZAGw1AckgBEgdKiB26WzsH4AAdhAEeTAARwiGZCiB7wgSwgwRiihAtCBGkHikCTIKWYVcQemgolB1qBW0CNoRnY/+xmDMcIqhmGGK0YQxh3EYw4VxxlQxYZg0mWKYxpm1mCnMNSxyLJEs5aw41ijWd1giNhD7hW0H20m2QZwr7jkehffCT7BbsWewr3LEccwStAh5nOqceZxTRBfiIpcvVxn3Fu6XPF68GN5CPnG+I3zz/JcFTATmNl0TFBMMF0IIlQr7kURIPSLnN2/eHCmKF20VSxHfK8EvMSR5W8pQ6pa0gQyHzOCWB7Kn5ZzlVRSwCiOKfynlKkereGw1UZVV41RbUR/WyNTEadZolWjnbDuvc0Y3Qu/I9kP6ZANfQx8jnx3+xoEmtJ3HTGN2nTPLNr+1u9yiYU+f5Yw1xkbIVmOvjR3VPsnhruNrpzln3v26B7xckg9Wun5x5/Ew8QzzKvLl9bP0jyfXBiIp+tSoQy+CGWlmh1NDxcIoR5+Esxx3OlEUQY+yjUGeco59dIYz7lB8W2J60lKyS0pdmsL5rMzgCx+zbLJrr9y9Jp5z+TpPPvvNpFu4wnN3MosFS27clys1Kmsrd308U8XztKjG4AWtFl9XVL+rKb5ZrqXtdUh7XQe1S6C7vk+iv/t9/KDep6Jhjy/Coz1f7aa4p7tms+ZdFieWSpcj6Lx0OgAggQV4QBr0wAEOQzqUwwACg1BEuCCSENWIOaQM0gWZhXyLwqN2o86imtFs6D3odHQvA4nBl6GE4TujIeM5xncYccxhzAsmApMHUzkzK7Mz810WNMsBloesLKzurNVYLiwV28wmw5bINoEzxxXj2fAUfCf7dvYbHDiOEI5egjHhHieJM5VzjRhM/MrlxzXGTeae5aHxLPAe5UPwneXn5y8U0BSo22S3aVQwUohPqEzYSniMFCsiIVK/OVCUR/SpmLs4VvyZRKCksOQbqThpA+lVmcot4bI6soty1fJnFGwVRRSnlKqVU1T8thqpCqkuq3WoP9a4rBml5a1tv01HR0FXRI+wHa2P0p81mDGcMhrfMWw8ZzK+89supBnRnGe3koXunj2W1lb+1mE22bb3976y67VfcSQ6KeyzcD60/+KBWpcRV2Y3RXcfjyzPaq9pH2lfT79M/44AgcC9lGzqlyCp4BBaQ4jgkeDQxqOix5LCx044RtRHqUXnxRBOJZ0mnMmI503ITlRNakn2TPmRlpiunvH5wpUsv0t7r0hfY8iZuP48r/TmxVuxt93vOBcb39N4sLVU/pHcY6lK8SqpasVnei921lq9JDccakppvtb6pG2gnd4p3K3T49GXMFDxYeIj32eDkcjRgvFPk/zTXrNX5ocXpZYCl8vWEHQ6ADACOwiCAThCMpTAmw37G+7X1aPxaEf0NwZjhqyf3tcwzkzCTDFM48y2zDUsciyXWHGsUayL2EDsFzYPnCvuI94LP8EezL7KEUfgJuRxqnM2El2Ii1zJv0xb8M3/9GwphBAq/WnZal3yT8ch0gZ/Gv4t+KffN5o1WiW/7f6W+89u/5ta70FfXj/Lv6sN6fm72+jCP+WeVf4tN4Nxw+5lzQ29N9I2/BYRNgQ/KN8wXHlyXfGzng3HDaNN8a/+as5oaXsd8kawva6D2lnSFdtd3xPSJ9HvP2D0Pn5Qb+j0R7dPRZ8Xhtu/CI/6j5mOS01gvtpN5k/FTnvP7JyVmWOdm5x//e3BQsai7eLE95glgx+SP4aXI1Z4V66scqzGrC6u3aAn0OkA6+clAABgMaSQKUEkc0Oj//Ow978qgHx4Yw4kAGA9A/faAAABAKR8aaa2AEAEAC0wBAqQgQJBQAJzMASjn1cSuP964guwfpYDAGBkB7hkDwBQ/f1Y5N/npXmG0gAADCnUsCBfbx8aSZ9KJXuSDCkB1MM0zyBZkmmgu7wsSVlRURUA4F93RgACxGzQPQAAAAlwSFlzAAALEwAACxMBAJqcGAAACJRJREFUeJzt3d1rHOcVx/F525md3ZWNY0upW1KoZNktITdpJLBpQ6CF3vnlHwiYBtqLQqHXBhPIfaH0riUN/gdsq71rCZhgmUrtXYpxXTuhpXaC7bZ+ibyzMzvTi1MdP145yZnRaiW538+F2FmtZmYNz2/Pc56ZtV9VlQcABsF2nwCAXYO8AGBFXgCwIi8AWJEXAKzICwBW5AUAK/ICgBV5AcCKvABgFY1lL8+8qJwrzYHt4vv+F2w23+1mRrX7t2VZyjPukyObALaOhoI80M0gCDY+2UzD+kJToCzLyjGy+cw/ATB2G8NCBUGgkaGaHaVJXsjI14AYDofl0+R595UeeQFsJUkE93HwtDAMgyCQ+PCaFhq188ItJTQpiqLoP86WL19dvnz1+l9v/ftfj7KsaHA2AMYiSaJ9L/TmD3/16LFvfue7LyftOFxXVZVbdNRSr3+hYTFcVxRFnucfXPrwvXff//ST/9Q9PICtNvPi3tM//N7rb7wSRVEYhlEURVHULDJq5MVIWBRFMRgMsiz7za//sHRhtf67ADA5x08unH7r++12O4qiVqvVLDKs8xHtQcg0JM/zPM+zLHv3V7//7cU/NTl9ABO0dGG1LMu3fvQD6S36vi9zk7Is7ZFRo3+hxYWERb/f/+DShyNhceLUseMnj87OHex0EvueAYzX2lp288btpQtXLp5f1id/t/Tn+cMHX3/jFXeJJAxD+25N8xG3wTkYDKSyeHD/4c9++t7dOw/lNfsP7Hn7nTcXFo/UeVMAttbqyrWzZ87du/tANg9MT/38F6d7U912ux3HsfQy7LOSGlMXdzLS7/eXL1/VsPA8j7AAdqCFxSNvv/Ombt6983D58tUsywaDgaxv1lrxsOaFrptqm3N15W/62xOnjhEWwM60sHjkxKljurnyx+tZlklXQdYu7Ndhm/LCnY/keS558fFHd/QFx08erfseAEyMO0I//uiO1BdFUeglVMb9fHle6MqIRJHmxYP7j/U1s3MHa54/gMlxR+iD+4/7/b40Ioui0Hs4LPupV19IIMmUJM+fZBKrIcBO5o7QPC9lMiJhofdwWPZTIy80MqTEaHjiALabTkZkPiJPWiLDmhcSQu6VnZs6XwDbR4oLt38xzvrCcyJDV0k2cbYAtpOGxTO/euIL1Oh36pSkVkMVwE7jfgeFDHDjiG5SX7hzHgC7jjsNqXXJlrV/MfKYvAB2tY3faGVR7+73z/uuPQC7yDO/bdeidl54fLMe8FxoMJz5/0eA/zuNP/LJCwBW9e5n37rzALDzNVwfITuAXc1dHxFjux7c438qA55fY74/FQA88gKAHXkBwIq8AGBFXgCwIi8AWJEXAKzICwBW5AUAK/ICgBV5AcCKvABgRV4AsCIvAFiRFwCsyAsAVuQFACvyAoAVeQHAirwAYEVeALAiLwBYkRcArMgLAFbkBQAr8gKAFXkBwIq8AGBVOy9839+K8wAwSTKQ6w5na174vh8EFCPAc8j3fWNwmCJg476oMoBdrdmgpmQAYEVeALCqlxdasfi+H0VPqpe1tWycJwVgrNwRGkV+s2anV7d/IQ+k8Zl2In3BzRu36x4YwMS4IzTtRJoXyrifGusjIggC+Tk909HfLl24Yj5zAJPmjtDpmU4QBDKQa4WFZ8mLkd1pXszO7dMnL55fXl25Zj8qgIlZXbl28fyybs4dekE/+DUvxrme6q1ffyHHiKIoDMND8/u7vSdTkrNnzhEZwE6zunLt7JlzutntRbNz+2QIh2FYt8SIvvwl65MRyQs5TBRFSTt+bXHm0vu35DX37j74yY9/eeLUseMnj87OHex0krpvDMC4rK1lN2/cXrpwxa0sPM97bXEm7bSjKNLhrLWGZbemvPCcyJCwiKIojuNDh/ff+ueD69ce6csunl8eOT8AO8T8kd6hw/tbrVar1ZISQ1LDvgfr+ojsV5Ki1WrFcZwkSZIkry5Mzx5Km54/gAn5xlz724szSZLEcRzHsUaGpMbY6gt3ZSQMQwmnJEna7Xaapr1e79WF6T177139y2dZf9PvCcC4JW3vWy93548c6Ha7aZq2221JDS0x7F2Mev0LSSPNi06nMxgMhsPh3Hw1PdP6x98fffrJ4LNHXj7wqoorR4Ft4/tlK/a6Pe/Fr8Qvfb23Z+9Up9PpdrudTidN09Y6Xe4cf/9COhdufZHn+XA4rKqqqirf91tx9LWXsizLiqIoiqIsy6qqPM9zfwLYCtqG0I92mXSkaZqmabfbnZqa0rxot9tSX0iJMeb1Ec8pMaTTWZalJoKEhTzf7/cHg0Ge5/rbsiybvHsANenl1zoPkD6jVBbdbrfX68mUROYj2rywH8I6HwmCoKoqOQkJAqksJEeiKJL2Z7/fz/Nc6o7hcKiB0vAfAICNhoV+rmtepGmqk5Fut6v9i1arpUskY56PeE6dI5GRpqmen8xQkiTJskzzoixL8gKYmJHrpCQv4jiWpQmZhnQ6HRmqbrPTfoga8xGpW6qqiqJII0D6GtrRkMmIFhfkBTBJwTr3OimJDPenVBZy1db4r+90z8bddJugg8FAO6DSvJAJi7eh00l8AOMycu+4t/7RLlkgF1noGoVUHHoVVd2w8OrOR6qq2tiGDcMwz/M4jouikLBwOxf0O4HJ0BaGBIHeuiHpEK1zK4u6X8pbr75wI0OPJ4eXmHCnIbqe6lFTAFvJrRFGuhjuPV/ubSPehumC6UANRrL8iRsKGhP6pJQVFBfAJLmrJJoa7n1lesNIs6/7b5IXQlNDfuoDbXCOhAUlBrB1RhoZmhfe0/HhNU2K/+18k8NY/1zTQfPC3TNhAWydjT1Lt8/oJshmDzTGkfx5uyIsgMnYmAibz4in9sZgBmDEXaQArMgLAFbkBQAr8gKAFXkBwIq8AGBFXgCwIi8AWJEXAKzICwBW/wV04SbMTUL/WgAAAABJRU5ErkJgggo=) no-repeat 19px -15px;
568 width: 400px;
569 margin: 0px;
570}
571
572option.disabledOption {
573 color: #999999;
574}
575
576/* @end */
577
578/* @end */
579
580/* @group Record page */
581div.mainPanelMinHeightDiv {
582 width: 15px;
583 min-width: 15px;
584 height: 200px;
585}
586
587table#mainPanelTABLE {
588 width: 100%;
589}
590
591/* @group Direct logins */
592
593div#directLoginsBlock {
594 width: 230px;
595 padding: 0px;
596 /*border: 4px solid #ff9400;*/
597 /* background: url(../images/directLoginBox.png) repeat-y -262px bottom;*/
598 background: url(data:image/png;charset=utf-8;base64,iVBORw0KGgoAAAANSUhEUgAAAvIAAAAtCAIAAABDDhjIAAAABGdBTUEAANbY1E9YMgAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAtrSURBVHja7J1tjFxVGcefnZk77y+727VbK9uXLRpNS0X6gpRaMFqoigpIodX4xS8axQ9GEqNBjVFp1QThAxGIgRhNmhQIRWOpDQ1xS6XEVtjSwhbqlr5tbWd3Z99mZ+7Om2fm2Xnu6ey2mTszt7uw/1+am7kzNws597n3/O5zznluU6FQIABAmXw+n8lkTNNMpVJjY2MjIyOJRGJwcPCeC1utg76XQUOBq8Fjhnx8tn3HvHnzmpubo9FoKBQKBoM+n88wDJfLdYU/sHr1tw8deqLKgE8mk8PDw0NDQwMDAwh4MBsCvqWlJRKJhMPhQCBQTcArXGhGAACYyzSV0HfRJmA2hGVFiFYZmdAaMLdQD69oBAAgMeCDCrQGAAAAANAaAAAAH1AKpGVx8jk0CHCcfHb68IPWAAAAqA0ek1LbFEWtb1MX0DLAcZLn5eN4U7NMprE7TgqtAQAA2MwlXYjaqn5F62/60ETAccbOWBFHLXo06s4NrQEAAFCV2fDSWbVVn5NNMeu3/iNoH+A48dctrXG16NFoK3MDrQEAgLkuNFaXUO5L4q5O64jeF9BKwHF6d8nHi65l4jR2/wy0BgAAYDZN8ljsKnHGuMH6+ew+SifQSsBBkn3U1yV7pz2rOA4lIKv3G2gNAADMdafhPoP7D7fbrbZjxjWJwvzJI3ImHd6GhgIO8tovqJDnjxcKHWnjQx6PR6LRVjk+j3P/kxWvZcBbGsCVb6xVfgkAcOIC5P5DN5tjdNN6Kg8/HXmMVnyHYp1oK9B4+rvp7adl72hhnbsEm40tp3FEa1hfeJvP5yucRv8VACqP5U/74ChxAr8BwOmHCs72c19iGIbX633LfeuKbFezqzT8lJ+gF++hu7vIG0aLgUaS6qcX7y2WqikRzy/4r3d9i2GoOGS9VtuZ0RrxFYaFRm0LGlP9BszxO2mFzcjQvtpyCPGzI/wGAEevREnSeEoYJdzewCvpTXd4d0weOvAm7d1Km54hjx/tBhrDxAjt/hqN9MoXXbk7PEWpLsLRKGZT5QybBmiNJGZEaAR9l7TkjQgQzulcvplWVCOQ2WEyR0yHj1cxA7MBwImLUa41ydb4fL6TnjXHJt5c7j06eeipPfTcBvrCMxRdjHYD9ZLoKTrN0DvyxaH0mvO+5a1+vwo/o4w4TZV/tV6tEZXhba4Ef8ibY57zL3v7XnIn33OnL7rTF5qySZxHMH0gGZGcvz3nn5+LLDM/vDG78JYmj5/vsPpgv926TACAarSGLy51lXFHwk7jL/GPxOYoJTq85yaP7n+ddq6mTz1AK+8nI4TWA7WQTlD3I9T9KGUsK3jX7Owq3BXx+Tj2OFvDk2zkydZxrdHzMbkymUzGNXg0eOxh/4WXm/ImTh+o6saaGfWof6MnKP6vYO+fC55gasFtqRU/zMau5TykijTxG6RtAHDCbPha050mEAiYZvS50W9soacWePsnjzaH6OCD9MbvqfMu6vgcta8lb4yMMLncaElwGV3IUmaMzASdf7VYL6B3V3H4SeO0ufCF9JZALKhQgacikA1bzOZqzK2RYSalMtky+eFToaO/CZ3dJdN/AKjlJpsdD57dFTz3t+SSrePLH8iG2iW+SavRBLMBoCFOQ+XpNfoIlOpgJkoMZ9qeGvnWF/3PXx9+V3vgHqC3/lj8B0B9HBxd+ZL5pXCsJVhCyTSbDSdsbKVqatcacRq2mUwJ19l9bYfud2VHcZJAYyjkQif/4u/bM3jjk+n5aznEVdSxvOt3ZABAPfDEfL6ylNZwtkbd1ZXTqC1n4p8f3fyeeeC25oNBN9LwoDGMZAO7E5/poTWRSCQcDodCITYbcRqpO+DsIJTMAuYhJ457X88TrW9vk3I6k8SupaVfoUUbKdxBoYXkjeAsgukxh4tVJkdPFecknvyr/s4zt9nftv++gZW/SnVuUbFufQ+zAaBxyDiUurerh1V1ramtTJfkBR9vjK3/T991N/pf+2xrd9A9gUYD9QjNvsQNh9OrvMFYJBRSWqOchs2mIltjawSqFq2pcBrTNJXW+HqebO156JLj2q6ndduo4/M4eaAqfLHiv9ZP0OJNtOGR4sjrqw/S0PHJG24h09b9ozi50ks3k1YdQEU878JsAKjfaThhw9NrxGaU3PDSEJ5TnPR4Dozf2nV67Udcpz8aOPOx4Llm77jPlfW5MoYrj5YE05LJu828J53zJLKR48mFJ9KLzucXebz+QDjANqOIRqNKbngQiufWyJIRWy9PsK01svSJnUZRHHs6vl27Ptx0829p5fcJPQ2omc47acmX6dCv6d+/tFT5yE/6Ah3pBZ/Wy9jYFXkAwBXkRl1Q6vauehS9VIf8JNKTSvn+ZwbPjC/bO1KaVVlePqI/AKM953gsVWx5wYeEUMjnC5RQHsNJGk7YsNbwAm+7k4Vr0RrJ0/B8momJiWzi5KLuH1hjT94obdpZnBsPQJ243LT2Z9S2kvZ+k3Jpztm0H/7u2Q27iRboFbW5ngHkBoD6EzZUSoLqZVT5KtM7JJ55w6l6mXkjAoSCZKDyXl6uRiaTtziKeLCJVUaZjcwX5lp8rDV2UzX2tEZ8XDmNimYV0+l0urXnYWuOcJMLTgMan7bZ+Cfac99kvGYGIz2PDl33c71qH5Xm2WAoCoD6zUZm2EjFVPmStYadRt38uRfg+TdTEzaQG0Ba2VV5DYKuNVxBQG1ZaGRXqvDJHd7ZbA2LOQd0Id7dcvHv1s83/w5OAxrPsrtpzU9lNKq1b2fimq+b7o9L6UmeEwCnAaBRORt1Qal+haas/S4NP6U4VaPIZDK8GFbP1mD4CejhpGdreP4vW4uvjF9D7XKY6TOFnRqEYnOXgns8sab95ONWfZq2Txbn0wDgBKt+TO/soOETxRAv5Fp6H4+Ht+uvrSdtYRQAoM5+SO9R9FQNP2TL8JNojf7CHORpQEU4yfOnDGVywkbkxltG8jS2XgJVu9ZULoBKDsUSB6wj1m3HHGHgFG6DbnqI9tzLe82D/zyXSk6UX4SmwpIHoQgzbABo3BO27OrDB9wVsdPw8JOkanSn0eUGojOnIudyWqMnbKSeNW/1gsJSf682p7GtNVJQWKl6oP8VV6FctyC2DGu5gbN03lksfZTsK0pObswbP2D6N3rK2C1DCQCo0mwqEjaq+5GBp4pZNaI18BggSBTJe8fkNR0syvJ6hIrl3DXfz6vSGv3V3Ow0itaB/dYRS7+KkwecvtEWw+zoH3gvOrg/3n6L0ny5q+JOCkBjzUafWKMMhnsjvuIueauxtgZq2mwNmMtyLLGk52zcGrIrv1J9eXfb2RoZhPKmrTqwxTrCADjN4ttFa3yp0yoIpRCqmA0SNgA0/FGbuxnWFy5soyPPvRAaUI0i6+tYK76hRkwksJetkUGo4tsSsoPWEeEOnDngOJEl8tGXifN0RY5JwzAk+w2zAcAJuZFifTLkROXCH1OTNJAbqMy0ZqOnbURlGlt7rFqtETFnpym+MSQ7YB0RWoizCJzXGsue/dl4xSoMZGsAuDpyw+9Y0G1m2kXdMBuYzdRdfdKMngts4H/X3gLvbBnVo3gKaetnvMMSXAW8UStwC2nWGk4iYm4NAFetr5JOSC46vbwCrkRwObOp8ifHtUZKaEvukdP+OGFgZhHJ1of5ayhJCQBoYKeFjCmYWartA/RxKDYbtB2YWfSZwihsCgAAoFqt0WeBQWvALEHSh1PfHgwAAABacyWt0astSZUCAGZWa6aWN8W4PgAAQGuqMhvS5tmg4cCMo0cjnAYAAIANranoSJCtATOOJGlgMwAAAGxrDToPMDtBZAIAALCtNXoXgo4EQGgAAAC877UGAAAAAABaAwAAAAAwa7QGOX8AAAAAvI+1ZqrKYBkUmA1MXdoN7QYAgDnO/wUYABme+D8+TaFnAAAAAElFTkSuQmCCCg==) repeat-y -262px bottom;
599}
600
601div#directLoginsBlock div.directLoginsBlockHeaderBox {
602 /* background: url(../images/directLoginBox.png) no-repeat -11px -13px;*/
603 background: url(data:image/png;charset=utf-8;base64,iVBORw0KGgoAAAANSUhEUgAAAvIAAAAtCAIAAABDDhjIAAAABGdBTUEAANbY1E9YMgAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAtrSURBVHja7J1tjFxVGcefnZk77y+727VbK9uXLRpNS0X6gpRaMFqoigpIodX4xS8axQ9GEqNBjVFp1QThAxGIgRhNmhQIRWOpDQ1xS6XEVtjSwhbqlr5tbWd3Z99mZ+7Om2fm2Xnu6ey2mTszt7uw/1+am7kzNws597n3/O5zznluU6FQIABAmXw+n8lkTNNMpVJjY2MjIyOJRGJwcPCeC1utg76XQUOBq8Fjhnx8tn3HvHnzmpubo9FoKBQKBoM+n88wDJfLdYU/sHr1tw8deqLKgE8mk8PDw0NDQwMDAwh4MBsCvqWlJRKJhMPhQCBQTcArXGhGAACYyzSV0HfRJmA2hGVFiFYZmdAaMLdQD69oBAAgMeCDCrQGAAAAANAaAAAAH1AKpGVx8jk0CHCcfHb68IPWAAAAqA0ek1LbFEWtb1MX0DLAcZLn5eN4U7NMprE7TgqtAQAA2MwlXYjaqn5F62/60ETAccbOWBFHLXo06s4NrQEAAFCV2fDSWbVVn5NNMeu3/iNoH+A48dctrXG16NFoK3MDrQEAgLkuNFaXUO5L4q5O64jeF9BKwHF6d8nHi65l4jR2/wy0BgAAYDZN8ljsKnHGuMH6+ew+SifQSsBBkn3U1yV7pz2rOA4lIKv3G2gNAADMdafhPoP7D7fbrbZjxjWJwvzJI3ImHd6GhgIO8tovqJDnjxcKHWnjQx6PR6LRVjk+j3P/kxWvZcBbGsCVb6xVfgkAcOIC5P5DN5tjdNN6Kg8/HXmMVnyHYp1oK9B4+rvp7adl72hhnbsEm40tp3FEa1hfeJvP5yucRv8VACqP5U/74ChxAr8BwOmHCs72c19iGIbX633LfeuKbFezqzT8lJ+gF++hu7vIG0aLgUaS6qcX7y2WqikRzy/4r3d9i2GoOGS9VtuZ0RrxFYaFRm0LGlP9BszxO2mFzcjQvtpyCPGzI/wGAEevREnSeEoYJdzewCvpTXd4d0weOvAm7d1Km54hjx/tBhrDxAjt/hqN9MoXXbk7PEWpLsLRKGZT5QybBmiNJGZEaAR9l7TkjQgQzulcvplWVCOQ2WEyR0yHj1cxA7MBwImLUa41ydb4fL6TnjXHJt5c7j06eeipPfTcBvrCMxRdjHYD9ZLoKTrN0DvyxaH0mvO+5a1+vwo/o4w4TZV/tV6tEZXhba4Ef8ibY57zL3v7XnIn33OnL7rTF5qySZxHMH0gGZGcvz3nn5+LLDM/vDG78JYmj5/vsPpgv926TACAarSGLy51lXFHwk7jL/GPxOYoJTq85yaP7n+ddq6mTz1AK+8nI4TWA7WQTlD3I9T9KGUsK3jX7Owq3BXx+Tj2OFvDk2zkydZxrdHzMbkymUzGNXg0eOxh/4WXm/ImTh+o6saaGfWof6MnKP6vYO+fC55gasFtqRU/zMau5TykijTxG6RtAHDCbPha050mEAiYZvS50W9soacWePsnjzaH6OCD9MbvqfMu6vgcta8lb4yMMLncaElwGV3IUmaMzASdf7VYL6B3V3H4SeO0ufCF9JZALKhQgacikA1bzOZqzK2RYSalMtky+eFToaO/CZ3dJdN/AKjlJpsdD57dFTz3t+SSrePLH8iG2iW+SavRBLMBoCFOQ+XpNfoIlOpgJkoMZ9qeGvnWF/3PXx9+V3vgHqC3/lj8B0B9HBxd+ZL5pXCsJVhCyTSbDSdsbKVqatcacRq2mUwJ19l9bYfud2VHcZJAYyjkQif/4u/bM3jjk+n5aznEVdSxvOt3ZABAPfDEfL6ylNZwtkbd1ZXTqC1n4p8f3fyeeeC25oNBN9LwoDGMZAO7E5/poTWRSCQcDodCITYbcRqpO+DsIJTMAuYhJ457X88TrW9vk3I6k8SupaVfoUUbKdxBoYXkjeAsgukxh4tVJkdPFecknvyr/s4zt9nftv++gZW/SnVuUbFufQ+zAaBxyDiUurerh1V1ramtTJfkBR9vjK3/T991N/pf+2xrd9A9gUYD9QjNvsQNh9OrvMFYJBRSWqOchs2mIltjawSqFq2pcBrTNJXW+HqebO156JLj2q6ndduo4/M4eaAqfLHiv9ZP0OJNtOGR4sjrqw/S0PHJG24h09b9ozi50ks3k1YdQEU878JsAKjfaThhw9NrxGaU3PDSEJ5TnPR4Dozf2nV67Udcpz8aOPOx4Llm77jPlfW5MoYrj5YE05LJu828J53zJLKR48mFJ9KLzucXebz+QDjANqOIRqNKbngQiufWyJIRWy9PsK01svSJnUZRHHs6vl27Ptx0829p5fcJPQ2omc47acmX6dCv6d+/tFT5yE/6Ah3pBZ/Wy9jYFXkAwBXkRl1Q6vauehS9VIf8JNKTSvn+ZwbPjC/bO1KaVVlePqI/AKM953gsVWx5wYeEUMjnC5RQHsNJGk7YsNbwAm+7k4Vr0RrJ0/B8momJiWzi5KLuH1hjT94obdpZnBsPQJ243LT2Z9S2kvZ+k3Jpztm0H/7u2Q27iRboFbW5ngHkBoD6EzZUSoLqZVT5KtM7JJ55w6l6mXkjAoSCZKDyXl6uRiaTtziKeLCJVUaZjcwX5lp8rDV2UzX2tEZ8XDmNimYV0+l0urXnYWuOcJMLTgMan7bZ+Cfac99kvGYGIz2PDl33c71qH5Xm2WAoCoD6zUZm2EjFVPmStYadRt38uRfg+TdTEzaQG0Ba2VV5DYKuNVxBQG1ZaGRXqvDJHd7ZbA2LOQd0Id7dcvHv1s83/w5OAxrPsrtpzU9lNKq1b2fimq+b7o9L6UmeEwCnAaBRORt1Qal+haas/S4NP6U4VaPIZDK8GFbP1mD4CejhpGdreP4vW4uvjF9D7XKY6TOFnRqEYnOXgns8sab95ONWfZq2Txbn0wDgBKt+TO/soOETxRAv5Fp6H4+Ht+uvrSdtYRQAoM5+SO9R9FQNP2TL8JNojf7CHORpQEU4yfOnDGVywkbkxltG8jS2XgJVu9ZULoBKDsUSB6wj1m3HHGHgFG6DbnqI9tzLe82D/zyXSk6UX4SmwpIHoQgzbABo3BO27OrDB9wVsdPw8JOkanSn0eUGojOnIudyWqMnbKSeNW/1gsJSf682p7GtNVJQWKl6oP8VV6FctyC2DGu5gbN03lksfZTsK0pObswbP2D6N3rK2C1DCQCo0mwqEjaq+5GBp4pZNaI18BggSBTJe8fkNR0syvJ6hIrl3DXfz6vSGv3V3Ow0itaB/dYRS7+KkwecvtEWw+zoH3gvOrg/3n6L0ny5q+JOCkBjzUafWKMMhnsjvuIueauxtgZq2mwNmMtyLLGk52zcGrIrv1J9eXfb2RoZhPKmrTqwxTrCADjN4ttFa3yp0yoIpRCqmA0SNgA0/FGbuxnWFy5soyPPvRAaUI0i6+tYK76hRkwksJetkUGo4tsSsoPWEeEOnDngOJEl8tGXifN0RY5JwzAk+w2zAcAJuZFifTLkROXCH1OTNJAbqMy0ZqOnbURlGlt7rFqtETFnpym+MSQ7YB0RWoizCJzXGsue/dl4xSoMZGsAuDpyw+9Y0G1m2kXdMBuYzdRdfdKMngts4H/X3gLvbBnVo3gKaetnvMMSXAW8UStwC2nWGk4iYm4NAFetr5JOSC46vbwCrkRwObOp8ifHtUZKaEvukdP+OGFgZhHJ1of5ayhJCQBoYKeFjCmYWartA/RxKDYbtB2YWfSZwihsCgAAoFqt0WeBQWvALEHSh1PfHgwAAABacyWt0astSZUCAGZWa6aWN8W4PgAAQGuqMhvS5tmg4cCMo0cjnAYAAIANranoSJCtATOOJGlgMwAAAGxrDToPMDtBZAIAALCtNXoXgo4EQGgAAAC877UGAAAAAABaAwAAAAAwa7QGOX8AAAAAvI+1ZqrKYBkUmA1MXdoN7QYAgDnO/wUYABme+D8+TaFnAAAAAElFTkSuQmCCCg==) no-repeat -11px -13px;
604}
605
606div#directLoginsBlock h3 {
607 text-align: center;
608 color: #666666;
609 padding-top: 12px;
610 padding-bottom: 5px;
611 margin: 0px 10px 0px 10px;
612 border-bottom: 1px dotted #ff9400;
613 font-size: 12pt;
614}
615
616ul#directLogins {
617 /* padding: 7px 20px 45px 20px;*/
618 padding: 7px 12px 45px 12px;
619 min-height: 200px;
620 /* background: url(../images/directLoginBox.png) no-repeat -513px bottom; */
621 background: url(data:image/png;charset=utf-8;base64,iVBORw0KGgoAAAANSUhEUgAAAvIAAAAtCAIAAABDDhjIAAAABGdBTUEAANbY1E9YMgAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAtrSURBVHja7J1tjFxVGcefnZk77y+727VbK9uXLRpNS0X6gpRaMFqoigpIodX4xS8axQ9GEqNBjVFp1QThAxGIgRhNmhQIRWOpDQ1xS6XEVtjSwhbqlr5tbWd3Z99mZ+7Om2fm2Xnu6ey2mTszt7uw/1+am7kzNws597n3/O5zznluU6FQIABAmXw+n8lkTNNMpVJjY2MjIyOJRGJwcPCeC1utg76XQUOBq8Fjhnx8tn3HvHnzmpubo9FoKBQKBoM+n88wDJfLdYU/sHr1tw8deqLKgE8mk8PDw0NDQwMDAwh4MBsCvqWlJRKJhMPhQCBQTcArXGhGAACYyzSV0HfRJmA2hGVFiFYZmdAaMLdQD69oBAAgMeCDCrQGAAAAANAaAAAAH1AKpGVx8jk0CHCcfHb68IPWAAAAqA0ek1LbFEWtb1MX0DLAcZLn5eN4U7NMprE7TgqtAQAA2MwlXYjaqn5F62/60ETAccbOWBFHLXo06s4NrQEAAFCV2fDSWbVVn5NNMeu3/iNoH+A48dctrXG16NFoK3MDrQEAgLkuNFaXUO5L4q5O64jeF9BKwHF6d8nHi65l4jR2/wy0BgAAYDZN8ljsKnHGuMH6+ew+SifQSsBBkn3U1yV7pz2rOA4lIKv3G2gNAADMdafhPoP7D7fbrbZjxjWJwvzJI3ImHd6GhgIO8tovqJDnjxcKHWnjQx6PR6LRVjk+j3P/kxWvZcBbGsCVb6xVfgkAcOIC5P5DN5tjdNN6Kg8/HXmMVnyHYp1oK9B4+rvp7adl72hhnbsEm40tp3FEa1hfeJvP5yucRv8VACqP5U/74ChxAr8BwOmHCs72c19iGIbX633LfeuKbFezqzT8lJ+gF++hu7vIG0aLgUaS6qcX7y2WqikRzy/4r3d9i2GoOGS9VtuZ0RrxFYaFRm0LGlP9BszxO2mFzcjQvtpyCPGzI/wGAEevREnSeEoYJdzewCvpTXd4d0weOvAm7d1Km54hjx/tBhrDxAjt/hqN9MoXXbk7PEWpLsLRKGZT5QybBmiNJGZEaAR9l7TkjQgQzulcvplWVCOQ2WEyR0yHj1cxA7MBwImLUa41ydb4fL6TnjXHJt5c7j06eeipPfTcBvrCMxRdjHYD9ZLoKTrN0DvyxaH0mvO+5a1+vwo/o4w4TZV/tV6tEZXhba4Ef8ibY57zL3v7XnIn33OnL7rTF5qySZxHMH0gGZGcvz3nn5+LLDM/vDG78JYmj5/vsPpgv926TACAarSGLy51lXFHwk7jL/GPxOYoJTq85yaP7n+ddq6mTz1AK+8nI4TWA7WQTlD3I9T9KGUsK3jX7Owq3BXx+Tj2OFvDk2zkydZxrdHzMbkymUzGNXg0eOxh/4WXm/ImTh+o6saaGfWof6MnKP6vYO+fC55gasFtqRU/zMau5TykijTxG6RtAHDCbPha050mEAiYZvS50W9soacWePsnjzaH6OCD9MbvqfMu6vgcta8lb4yMMLncaElwGV3IUmaMzASdf7VYL6B3V3H4SeO0ufCF9JZALKhQgacikA1bzOZqzK2RYSalMtky+eFToaO/CZ3dJdN/AKjlJpsdD57dFTz3t+SSrePLH8iG2iW+SavRBLMBoCFOQ+XpNfoIlOpgJkoMZ9qeGvnWF/3PXx9+V3vgHqC3/lj8B0B9HBxd+ZL5pXCsJVhCyTSbDSdsbKVqatcacRq2mUwJ19l9bYfud2VHcZJAYyjkQif/4u/bM3jjk+n5aznEVdSxvOt3ZABAPfDEfL6ylNZwtkbd1ZXTqC1n4p8f3fyeeeC25oNBN9LwoDGMZAO7E5/poTWRSCQcDodCITYbcRqpO+DsIJTMAuYhJ457X88TrW9vk3I6k8SupaVfoUUbKdxBoYXkjeAsgukxh4tVJkdPFecknvyr/s4zt9nftv++gZW/SnVuUbFufQ+zAaBxyDiUurerh1V1ramtTJfkBR9vjK3/T991N/pf+2xrd9A9gUYD9QjNvsQNh9OrvMFYJBRSWqOchs2mIltjawSqFq2pcBrTNJXW+HqebO156JLj2q6ndduo4/M4eaAqfLHiv9ZP0OJNtOGR4sjrqw/S0PHJG24h09b9ozi50ks3k1YdQEU878JsAKjfaThhw9NrxGaU3PDSEJ5TnPR4Dozf2nV67Udcpz8aOPOx4Llm77jPlfW5MoYrj5YE05LJu828J53zJLKR48mFJ9KLzucXebz+QDjANqOIRqNKbngQiufWyJIRWy9PsK01svSJnUZRHHs6vl27Ptx0829p5fcJPQ2omc47acmX6dCv6d+/tFT5yE/6Ah3pBZ/Wy9jYFXkAwBXkRl1Q6vauehS9VIf8JNKTSvn+ZwbPjC/bO1KaVVlePqI/AKM953gsVWx5wYeEUMjnC5RQHsNJGk7YsNbwAm+7k4Vr0RrJ0/B8momJiWzi5KLuH1hjT94obdpZnBsPQJ243LT2Z9S2kvZ+k3Jpztm0H/7u2Q27iRboFbW5ngHkBoD6EzZUSoLqZVT5KtM7JJ55w6l6mXkjAoSCZKDyXl6uRiaTtziKeLCJVUaZjcwX5lp8rDV2UzX2tEZ8XDmNimYV0+l0urXnYWuOcJMLTgMan7bZ+Cfac99kvGYGIz2PDl33c71qH5Xm2WAoCoD6zUZm2EjFVPmStYadRt38uRfg+TdTEzaQG0Ba2VV5DYKuNVxBQG1ZaGRXqvDJHd7ZbA2LOQd0Id7dcvHv1s83/w5OAxrPsrtpzU9lNKq1b2fimq+b7o9L6UmeEwCnAaBRORt1Qal+haas/S4NP6U4VaPIZDK8GFbP1mD4CejhpGdreP4vW4uvjF9D7XKY6TOFnRqEYnOXgns8sab95ONWfZq2Txbn0wDgBKt+TO/soOETxRAv5Fp6H4+Ht+uvrSdtYRQAoM5+SO9R9FQNP2TL8JNojf7CHORpQEU4yfOnDGVywkbkxltG8jS2XgJVu9ZULoBKDsUSB6wj1m3HHGHgFG6DbnqI9tzLe82D/zyXSk6UX4SmwpIHoQgzbABo3BO27OrDB9wVsdPw8JOkanSn0eUGojOnIudyWqMnbKSeNW/1gsJSf682p7GtNVJQWKl6oP8VV6FctyC2DGu5gbN03lksfZTsK0pObswbP2D6N3rK2C1DCQCo0mwqEjaq+5GBp4pZNaI18BggSBTJe8fkNR0syvJ6hIrl3DXfz6vSGv3V3Ow0itaB/dYRS7+KkwecvtEWw+zoH3gvOrg/3n6L0ny5q+JOCkBjzUafWKMMhnsjvuIueauxtgZq2mwNmMtyLLGk52zcGrIrv1J9eXfb2RoZhPKmrTqwxTrCADjN4ttFa3yp0yoIpRCqmA0SNgA0/FGbuxnWFy5soyPPvRAaUI0i6+tYK76hRkwksJetkUGo4tsSsoPWEeEOnDngOJEl8tGXifN0RY5JwzAk+w2zAcAJuZFifTLkROXCH1OTNJAbqMy0ZqOnbURlGlt7rFqtETFnpym+MSQ7YB0RWoizCJzXGsue/dl4xSoMZGsAuDpyw+9Y0G1m2kXdMBuYzdRdfdKMngts4H/X3gLvbBnVo3gKaetnvMMSXAW8UStwC2nWGk4iYm4NAFetr5JOSC46vbwCrkRwObOp8ifHtUZKaEvukdP+OGFgZhHJ1of5ayhJCQBoYKeFjCmYWartA/RxKDYbtB2YWfSZwihsCgAAoFqt0WeBQWvALEHSh1PfHgwAAABacyWt0astSZUCAGZWa6aWN8W4PgAAQGuqMhvS5tmg4cCMo0cjnAYAAIANranoSJCtATOOJGlgMwAAAGxrDToPMDtBZAIAALCtNXoXgo4EQGgAAAC877UGAAAAAABaAwAAAAAwa7QGOX8AAAAAvI+1ZqrKYBkUmA1MXdoN7QYAgDnO/wUYABme+D8+TaFnAAAAAElFTkSuQmCCCg==) no-repeat -513px bottom;
622}
623
624ul#directLogins li {
625 border-top: 1px solid white;
626 border-bottom: 1px solid white;
627 padding: 1px 0px;
628 width: 206px;
629}
630
631ul#directLogins li.hover {
632 border-top: 1px solid #ffc880;
633 border-bottom: 1px solid #ffc880;
634 background-color: #fff9f2;
635 cursor: pointer;
636}
637
638ul#directLogins li img {
639 width: 16px;
640 height: 16px;
641}
642
643ul#directLogins li div {
644}
645
646/* @group Direct logins description */
647
648div#directLoginsDescription {
649 padding: 6px 20px 50px 20px;
650 color: #999999;
651 font-size: 10pt;
652 /* background: url(../images/directLoginBox.png) no-repeat -513px bottom; */
653 background: url(data:image/png;charset=utf-8;base64,iVBORw0KGgoAAAANSUhEUgAAAvIAAAAtCAIAAABDDhjIAAAABGdBTUEAANbY1E9YMgAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAtrSURBVHja7J1tjFxVGcefnZk77y+727VbK9uXLRpNS0X6gpRaMFqoigpIodX4xS8axQ9GEqNBjVFp1QThAxGIgRhNmhQIRWOpDQ1xS6XEVtjSwhbqlr5tbWd3Z99mZ+7Om2fm2Xnu6ey2mTszt7uw/1+am7kzNws597n3/O5zznluU6FQIABAmXw+n8lkTNNMpVJjY2MjIyOJRGJwcPCeC1utg76XQUOBq8Fjhnx8tn3HvHnzmpubo9FoKBQKBoM+n88wDJfLdYU/sHr1tw8deqLKgE8mk8PDw0NDQwMDAwh4MBsCvqWlJRKJhMPhQCBQTcArXGhGAACYyzSV0HfRJmA2hGVFiFYZmdAaMLdQD69oBAAgMeCDCrQGAAAAANAaAAAAH1AKpGVx8jk0CHCcfHb68IPWAAAAqA0ek1LbFEWtb1MX0DLAcZLn5eN4U7NMprE7TgqtAQAA2MwlXYjaqn5F62/60ETAccbOWBFHLXo06s4NrQEAAFCV2fDSWbVVn5NNMeu3/iNoH+A48dctrXG16NFoK3MDrQEAgLkuNFaXUO5L4q5O64jeF9BKwHF6d8nHi65l4jR2/wy0BgAAYDZN8ljsKnHGuMH6+ew+SifQSsBBkn3U1yV7pz2rOA4lIKv3G2gNAADMdafhPoP7D7fbrbZjxjWJwvzJI3ImHd6GhgIO8tovqJDnjxcKHWnjQx6PR6LRVjk+j3P/kxWvZcBbGsCVb6xVfgkAcOIC5P5DN5tjdNN6Kg8/HXmMVnyHYp1oK9B4+rvp7adl72hhnbsEm40tp3FEa1hfeJvP5yucRv8VACqP5U/74ChxAr8BwOmHCs72c19iGIbX633LfeuKbFezqzT8lJ+gF++hu7vIG0aLgUaS6qcX7y2WqikRzy/4r3d9i2GoOGS9VtuZ0RrxFYaFRm0LGlP9BszxO2mFzcjQvtpyCPGzI/wGAEevREnSeEoYJdzewCvpTXd4d0weOvAm7d1Km54hjx/tBhrDxAjt/hqN9MoXXbk7PEWpLsLRKGZT5QybBmiNJGZEaAR9l7TkjQgQzulcvplWVCOQ2WEyR0yHj1cxA7MBwImLUa41ydb4fL6TnjXHJt5c7j06eeipPfTcBvrCMxRdjHYD9ZLoKTrN0DvyxaH0mvO+5a1+vwo/o4w4TZV/tV6tEZXhba4Ef8ibY57zL3v7XnIn33OnL7rTF5qySZxHMH0gGZGcvz3nn5+LLDM/vDG78JYmj5/vsPpgv926TACAarSGLy51lXFHwk7jL/GPxOYoJTq85yaP7n+ddq6mTz1AK+8nI4TWA7WQTlD3I9T9KGUsK3jX7Owq3BXx+Tj2OFvDk2zkydZxrdHzMbkymUzGNXg0eOxh/4WXm/ImTh+o6saaGfWof6MnKP6vYO+fC55gasFtqRU/zMau5TykijTxG6RtAHDCbPha050mEAiYZvS50W9soacWePsnjzaH6OCD9MbvqfMu6vgcta8lb4yMMLncaElwGV3IUmaMzASdf7VYL6B3V3H4SeO0ufCF9JZALKhQgacikA1bzOZqzK2RYSalMtky+eFToaO/CZ3dJdN/AKjlJpsdD57dFTz3t+SSrePLH8iG2iW+SavRBLMBoCFOQ+XpNfoIlOpgJkoMZ9qeGvnWF/3PXx9+V3vgHqC3/lj8B0B9HBxd+ZL5pXCsJVhCyTSbDSdsbKVqatcacRq2mUwJ19l9bYfud2VHcZJAYyjkQif/4u/bM3jjk+n5aznEVdSxvOt3ZABAPfDEfL6ylNZwtkbd1ZXTqC1n4p8f3fyeeeC25oNBN9LwoDGMZAO7E5/poTWRSCQcDodCITYbcRqpO+DsIJTMAuYhJ457X88TrW9vk3I6k8SupaVfoUUbKdxBoYXkjeAsgukxh4tVJkdPFecknvyr/s4zt9nftv++gZW/SnVuUbFufQ+zAaBxyDiUurerh1V1ramtTJfkBR9vjK3/T991N/pf+2xrd9A9gUYD9QjNvsQNh9OrvMFYJBRSWqOchs2mIltjawSqFq2pcBrTNJXW+HqebO156JLj2q6ndduo4/M4eaAqfLHiv9ZP0OJNtOGR4sjrqw/S0PHJG24h09b9ozi50ks3k1YdQEU878JsAKjfaThhw9NrxGaU3PDSEJ5TnPR4Dozf2nV67Udcpz8aOPOx4Llm77jPlfW5MoYrj5YE05LJu828J53zJLKR48mFJ9KLzucXebz+QDjANqOIRqNKbngQiufWyJIRWy9PsK01svSJnUZRHHs6vl27Ptx0829p5fcJPQ2omc47acmX6dCv6d+/tFT5yE/6Ah3pBZ/Wy9jYFXkAwBXkRl1Q6vauehS9VIf8JNKTSvn+ZwbPjC/bO1KaVVlePqI/AKM953gsVWx5wYeEUMjnC5RQHsNJGk7YsNbwAm+7k4Vr0RrJ0/B8momJiWzi5KLuH1hjT94obdpZnBsPQJ243LT2Z9S2kvZ+k3Jpztm0H/7u2Q27iRboFbW5ngHkBoD6EzZUSoLqZVT5KtM7JJ55w6l6mXkjAoSCZKDyXl6uRiaTtziKeLCJVUaZjcwX5lp8rDV2UzX2tEZ8XDmNimYV0+l0urXnYWuOcJMLTgMan7bZ+Cfac99kvGYGIz2PDl33c71qH5Xm2WAoCoD6zUZm2EjFVPmStYadRt38uRfg+TdTEzaQG0Ba2VV5DYKuNVxBQG1ZaGRXqvDJHd7ZbA2LOQd0Id7dcvHv1s83/w5OAxrPsrtpzU9lNKq1b2fimq+b7o9L6UmeEwCnAaBRORt1Qal+haas/S4NP6U4VaPIZDK8GFbP1mD4CejhpGdreP4vW4uvjF9D7XKY6TOFnRqEYnOXgns8sab95ONWfZq2Txbn0wDgBKt+TO/soOETxRAv5Fp6H4+Ht+uvrSdtYRQAoM5+SO9R9FQNP2TL8JNojf7CHORpQEU4yfOnDGVywkbkxltG8jS2XgJVu9ZULoBKDsUSB6wj1m3HHGHgFG6DbnqI9tzLe82D/zyXSk6UX4SmwpIHoQgzbABo3BO27OrDB9wVsdPw8JOkanSn0eUGojOnIudyWqMnbKSeNW/1gsJSf682p7GtNVJQWKl6oP8VV6FctyC2DGu5gbN03lksfZTsK0pObswbP2D6N3rK2C1DCQCo0mwqEjaq+5GBp4pZNaI18BggSBTJe8fkNR0syvJ6hIrl3DXfz6vSGv3V3Ow0itaB/dYRS7+KkwecvtEWw+zoH3gvOrg/3n6L0ny5q+JOCkBjzUafWKMMhnsjvuIueauxtgZq2mwNmMtyLLGk52zcGrIrv1J9eXfb2RoZhPKmrTqwxTrCADjN4ttFa3yp0yoIpRCqmA0SNgA0/FGbuxnWFy5soyPPvRAaUI0i6+tYK76hRkwksJetkUGo4tsSsoPWEeEOnDngOJEl8tGXifN0RY5JwzAk+w2zAcAJuZFifTLkROXCH1OTNJAbqMy0ZqOnbURlGlt7rFqtETFnpym+MSQ7YB0RWoizCJzXGsue/dl4xSoMZGsAuDpyw+9Y0G1m2kXdMBuYzdRdfdKMngts4H/X3gLvbBnVo3gKaetnvMMSXAW8UStwC2nWGk4iYm4NAFetr5JOSC46vbwCrkRwObOp8ifHtUZKaEvukdP+OGFgZhHJ1of5ayhJCQBoYKeFjCmYWartA/RxKDYbtB2YWfSZwihsCgAAoFqt0WeBQWvALEHSh1PfHgwAAABacyWt0astSZUCAGZWa6aWN8W4PgAAQGuqMhvS5tmg4cCMo0cjnAYAAIANranoSJCtATOOJGlgMwAAAGxrDToPMDtBZAIAALCtNXoXgo4EQGgAAAC877UGAAAAAABaAwAAAAAwa7QGOX8AAAAAvI+1ZqrKYBkUmA1MXdoN7QYAgDnO/wUYABme+D8+TaFnAAAAAElFTkSuQmCCCg==) no-repeat -513px bottom;
654}
655
656div#directLoginsDescription p {
657 padding-bottom: 8px;
658}
659
660div#directLoginsDescription a {
661 color: #333366;
662}
663
664div#directLoginsDescription ul {
665 padding-left: 20px;
666 list-style-position: outside;
667 list-style-type: circle;
668 color: #ff9400;
669 padding-bottom: 10px;
670}
671
672div#directLoginsDescription ul li {
673 padding-bottom: 3px;
674}
675
676div#directLoginsDescription ul li p {
677 display: inline;
678 color: #999999;
679}
680
681/* @end */
682
683/* @group Direct login [open] */
684
685ul#directLogins li a.directLoginItemTitle {
686 color: #336;
687 font-size: 10pt;
688 line-height: 16px;
689}
690
691ul#directLogins li table {
692 width: 100%;
693}
694
695ul#directLogins li a.directLoginItemTitle:hover {
696 text-decoration: underline;
697}
698
699/* @end */
700
701/* @group Direct login [edit] */
702
703ul#directLogins li a.directLoginItemEditButton {
704 visibility: visible;
705 color: white;
706 font-size: 8pt;
707 /*background-color: #ff9400;*/
708 padding: 0px 5px;
709 line-height: 14px;
710}
711
712ul#directLogins li.hover a.directLoginItemEditButton {
713 visibility: visible;
714 color: #ff9400;
715 /*border-top: 3px solid #fff9f2;*/
716}
717
718ul#directLogins li.hover a.directLoginItemEditButton:hover {
719 color: #35306b;
720}
721
722/* @end */
723
724/* @end */
725
726/* @group Records */
727
728div#recordListBlock {
729 width: 250px;
730 min-height: 200px;
731}
732
733div#recordListFilterHeader {
734 /* background: url(../images/cardFiltersSprite.gif) repeat-x 0 -114px;*/
735 background: url(data:image/gif;charset=utf-8;base64,R0lGODlhAQCFAOYAAISEuaen6ZSU0KCg4IKCt8zM9bOz0qWl552d3JGRzJqb2Gpqlaio7MfH7oeHvcTF6snJ8ZeX1IKCtr+/48HB5cLC6La216Oj5IyLxLy83nd3p3JyoGdnkrm53Li42YCAtMvL9LKy0W5umnl5qo6OyHR1o3BwnY+PqcrK8nt7rrW11X5+sYaFuuDg+WZmj7294Gtrl9HR5MbG7LS01KOjxH5+somJwYaHvH9/so+OyIaGvJKSzamp7IuMxImJwJua2JeX1aKj5AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAAAAAAALAAAAAABAIUAAAd8gAUMAQcXAwgKEQIJJBg2NwAEBjUtICgQDTIPFRQTLxkdHhYqMzEhNA4sABIfKykjGiUbJiIwCxwnLgUEADo+PTk7AkA/CANBBwE8BjgtHAswIiYbJRojKSsfEgAsDqY0MyoWHh0ZLxMUFQ8yDRAoILmChIaIioyOkJI1gQA7Cg==) repeat-x 0 -114px;
736}
737
738/* @group Record filters */
739
740
741div#recordFiltersTableWrapper {
742 /* padding: 0px; border: 0px; margin: 0px;*/
743 margin-left: 15px;
744 padding-left: 1px;
745 /* background: url(../images/cardFiltersSprite.gif) no-repeat left -38px;*/
746 background: url(data:image/gif;charset=utf-8;base64,R0lGODlhAQCFAOYAAISEuaen6ZSU0KCg4IKCt8zM9bOz0qWl552d3JGRzJqb2Gpqlaio7MfH7oeHvcTF6snJ8ZeX1IKCtr+/48HB5cLC6La216Oj5IyLxLy83nd3p3JyoGdnkrm53Li42YCAtMvL9LKy0W5umnl5qo6OyHR1o3BwnY+PqcrK8nt7rrW11X5+sYaFuuDg+WZmj7294Gtrl9HR5MbG7LS01KOjxH5+somJwYaHvH9/so+OyIaGvJKSzamp7IuMxImJwJua2JeX1aKj5AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAAAAAAALAAAAAABAIUAAAd8gAUMAQcXAwgKEQIJJBg2NwAEBjUtICgQDTIPFRQTLxkdHhYqMzEhNA4sABIfKykjGiUbJiIwCxwnLgUEADo+PTk7AkA/CANBBwE8BjgtHAswIiYbJRojKSsfEgAsDqY0MyoWHh0ZLxMUFQ8yDRAoILmChIaIioyOkJI1gQA7Cg==) no-repeat left -38px;
747 height: 19px;
748}
749
750div#recordFiltersDIV table {
751 padding-right: 1px;
752 /* background: url(../images/cardFiltersSprite.gif) no-repeat right -19px;*/
753 background: url(data:image/gif;charset=utf-8;base64,R0lGODlhAQCFAOYAAISEuaen6ZSU0KCg4IKCt8zM9bOz0qWl552d3JGRzJqb2Gpqlaio7MfH7oeHvcTF6snJ8ZeX1IKCtr+/48HB5cLC6La216Oj5IyLxLy83nd3p3JyoGdnkrm53Li42YCAtMvL9LKy0W5umnl5qo6OyHR1o3BwnY+PqcrK8nt7rrW11X5+sYaFuuDg+WZmj7294Gtrl9HR5MbG7LS01KOjxH5+somJwYaHvH9/so+OyIaGvJKSzamp7IuMxImJwJua2JeX1aKj5AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAAAAAAALAAAAAABAIUAAAd8gAUMAQcXAwgKEQIJJBg2NwAEBjUtICgQDTIPFRQTLxkdHhYqMzEhNA4sABIfKykjGiUbJiIwCxwnLgUEADo+PTk7AkA/CANBBwE8BjgtHAswIiYbJRojKSsfEgAsDqY0MyoWHh0ZLxMUFQ8yDRAoILmChIaIioyOkJI1gQA7Cg==) no-repeat right -19px;
754}
755
756div#recordFiltersDIV table tbody tr td {
757 cursor: pointer;
758 height: 19px;
759}
760
761div#recordFiltersDIV table tbody tr td div {
762 /* background: url(../images/cardFiltersSprite.gif) no-repeat right -38px;*/
763 background: url(data:image/gif;charset=utf-8;base64,R0lGODlhAQCFAOYAAISEuaen6ZSU0KCg4IKCt8zM9bOz0qWl552d3JGRzJqb2Gpqlaio7MfH7oeHvcTF6snJ8ZeX1IKCtr+/48HB5cLC6La216Oj5IyLxLy83nd3p3JyoGdnkrm53Li42YCAtMvL9LKy0W5umnl5qo6OyHR1o3BwnY+PqcrK8nt7rrW11X5+sYaFuuDg+WZmj7294Gtrl9HR5MbG7LS01KOjxH5+somJwYaHvH9/so+OyIaGvJKSzamp7IuMxImJwJua2JeX1aKj5AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAAAAAAALAAAAAABAIUAAAd8gAUMAQcXAwgKEQIJJBg2NwAEBjUtICgQDTIPFRQTLxkdHhYqMzEhNA4sABIfKykjGiUbJiIwCxwnLgUEADo+PTk7AkA/CANBBwE8BjgtHAswIiYbJRojKSsfEgAsDqY0MyoWHh0ZLxMUFQ8yDRAoILmChIaIioyOkJI1gQA7Cg==) no-repeat right -38px;
764}
765
766div#recordFiltersDIV table tbody tr td div a {
767 display: block;
768 padding: 0px 10px;
769 font-size: 8pt;
770 color: white;
771 line-height: 19px;
772 height: 19px;
773 /* background: url(../images/cardFiltersSprite.gif) no-repeat left -19px;*/
774 background: url(data:image/gif;charset=utf-8;base64,R0lGODlhAQCFAOYAAISEuaen6ZSU0KCg4IKCt8zM9bOz0qWl552d3JGRzJqb2Gpqlaio7MfH7oeHvcTF6snJ8ZeX1IKCtr+/48HB5cLC6La216Oj5IyLxLy83nd3p3JyoGdnkrm53Li42YCAtMvL9LKy0W5umnl5qo6OyHR1o3BwnY+PqcrK8nt7rrW11X5+sYaFuuDg+WZmj7294Gtrl9HR5MbG7LS01KOjxH5+somJwYaHvH9/so+OyIaGvJKSzamp7IuMxImJwJua2JeX1aKj5AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAAAAAAALAAAAAABAIUAAAd8gAUMAQcXAwgKEQIJJBg2NwAEBjUtICgQDTIPFRQTLxkdHhYqMzEhNA4sABIfKykjGiUbJiIwCxwnLgUEADo+PTk7AkA/CANBBwE8BjgtHAswIiYbJRojKSsfEgAsDqY0MyoWHh0ZLxMUFQ8yDRAoILmChIaIioyOkJI1gQA7Cg==) no-repeat left -19px;
775}
776
777div#recordFiltersDIV table tbody tr td:hover div a {
778 color: #ff9400;
779}
780/* @group selected */
781
782div#recordFiltersDIV table tbody tr td.selectedTab {
783 height: 19px;
784 /* background: url(../images/cardFiltersSprite.gif) repeat-x -57px;*/
785 background: url(data:image/gif;charset=utf-8;base64,R0lGODlhAQCFAOYAAISEuaen6ZSU0KCg4IKCt8zM9bOz0qWl552d3JGRzJqb2Gpqlaio7MfH7oeHvcTF6snJ8ZeX1IKCtr+/48HB5cLC6La216Oj5IyLxLy83nd3p3JyoGdnkrm53Li42YCAtMvL9LKy0W5umnl5qo6OyHR1o3BwnY+PqcrK8nt7rrW11X5+sYaFuuDg+WZmj7294Gtrl9HR5MbG7LS01KOjxH5+somJwYaHvH9/so+OyIaGvJKSzamp7IuMxImJwJua2JeX1aKj5AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAAAAAAALAAAAAABAIUAAAd8gAUMAQcXAwgKEQIJJBg2NwAEBjUtICgQDTIPFRQTLxkdHhYqMzEhNA4sABIfKykjGiUbJiIwCxwnLgUEADo+PTk7AkA/CANBBwE8BjgtHAswIiYbJRojKSsfEgAsDqY0MyoWHh0ZLxMUFQ8yDRAoILmChIaIioyOkJI1gQA7Cg==) repeat-x -57px;
786}
787
788div#recordFiltersDIV table tbody tr td.selectedTab div {
789 /* background: url(../images/cardFiltersSprite.gif) no-repeat right -95px;*/
790 background: url(data:image/gif;charset=utf-8;base64,R0lGODlhAQCFAOYAAISEuaen6ZSU0KCg4IKCt8zM9bOz0qWl552d3JGRzJqb2Gpqlaio7MfH7oeHvcTF6snJ8ZeX1IKCtr+/48HB5cLC6La216Oj5IyLxLy83nd3p3JyoGdnkrm53Li42YCAtMvL9LKy0W5umnl5qo6OyHR1o3BwnY+PqcrK8nt7rrW11X5+sYaFuuDg+WZmj7294Gtrl9HR5MbG7LS01KOjxH5+somJwYaHvH9/so+OyIaGvJKSzamp7IuMxImJwJua2JeX1aKj5AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAAAAAAALAAAAAABAIUAAAd8gAUMAQcXAwgKEQIJJBg2NwAEBjUtICgQDTIPFRQTLxkdHhYqMzEhNA4sABIfKykjGiUbJiIwCxwnLgUEADo+PTk7AkA/CANBBwE8BjgtHAswIiYbJRojKSsfEgAsDqY0MyoWHh0ZLxMUFQ8yDRAoILmChIaIioyOkJI1gQA7Cg==) no-repeat right -95px;
791}
792
793div#recordFiltersDIV table tbody tr td.selectedTab div a {
794 /* background: url(../images/cardFiltersSprite.gif) no-repeat left -76px;*/
795 background: url(data:image/gif;charset=utf-8;base64,R0lGODlhAQCFAOYAAISEuaen6ZSU0KCg4IKCt8zM9bOz0qWl552d3JGRzJqb2Gpqlaio7MfH7oeHvcTF6snJ8ZeX1IKCtr+/48HB5cLC6La216Oj5IyLxLy83nd3p3JyoGdnkrm53Li42YCAtMvL9LKy0W5umnl5qo6OyHR1o3BwnY+PqcrK8nt7rrW11X5+sYaFuuDg+WZmj7294Gtrl9HR5MbG7LS01KOjxH5+somJwYaHvH9/so+OyIaGvJKSzamp7IuMxImJwJua2JeX1aKj5AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAAAAAAALAAAAAABAIUAAAd8gAUMAQcXAwgKEQIJJBg2NwAEBjUtICgQDTIPFRQTLxkdHhYqMzEhNA4sABIfKykjGiUbJiIwCxwnLgUEADo+PTk7AkA/CANBBwE8BjgtHAswIiYbJRojKSsfEgAsDqY0MyoWHh0ZLxMUFQ8yDRAoILmChIaIioyOkJI1gQA7Cg==) no-repeat left -76px;
796}
797
798div#recordFiltersDIV table tbody tr td.selectedTab:hover div a {
799 color: white;
800}
801
802
803
804/* @end */
805
806/* @group record filter - SEARCH */
807
808div#recordFiltersSearchPanel {
809 position: absolute;
810}
811
812div#recordFiltersSearchInnerPanel {
813 padding: 10px 24px 25px 24px;
814 /* background: url(../images/recordFilterBackground.png) no-repeat -10px -138px;*/
815 background: url(data:image/png;charset=utf-8;base64,iVBORw0KGgoAAAANSUhEUgAAAQ4AAADMCAYAAACC5k2uAAANIWlDQ1BJQ0MgUHJvZmlsZQAAeJyV13k0lG8bB/BrFsYyZhhjDyO77LKHLJFItmwp2bdhJiZRypIUIkso2iiSFC0kEtWPLCHJkq2oyJI9kmXeP6R6f+f9ve95rz+ecz3385xz389zzud7nxsAr+FKpZKRABAQSAuyNjEgOTg6kTBdgAJewAEzaLi6B1P1LS3N4R9roRMQAADtcq5UKvmf3/uPhQtycHQCQMgCANF7vd8OAES39d4WAIhHaFQaAMIHAIjuPq4eAIhwAJANsrU2BEAUAADOe70vBwCc23pfDwC4EHdvGgCiG4CREOjhGwiAmQBg1PXwDHYHwMkCgIdHsHsAAC4ZACwCAigeALgPACDlTg2iAeCZAEDOwdGJtL7kffEAW/kAmMx+jx1JByjNAZDa/XtM9BEAtytAbuLvsTlrQAAAgrs12EtFGQAAEFgDAIYBOn1OAgCTCrCaQqcv59Lpq9cBUH0ANWT3w0EhP/8XAtEM8L/u17/5Z6EQAEgAhBgiH3kUFY4OZzjBGImJZjrJbMRcy3Ka9Qw2ju0srozdhyOFkMKZSjzPlc6dzpPJW8tPEcjelC14WaiedFgkd/N10VbxYxL5km3SJ2Rub+mUi5a/o9CjdFr5vsp71bNqZeqDmklaFdrDOmm6T/XG9DMMnhtO7sgyrjOZNb26q9FsYXeuRcue15avrdqsV2wL93bYddp3OXQ7offdc+7b339gwOX9wQ9uWPfHHp88P3sNe4/4fPEd9eciPwv4GjhJmaJOH5oJmg2ep80f/haycGQx9HvY0tEfx1bCV46vRkhHdkQjTiJjUKfQsQynGc9g4pjimRNYzrImYpPYzuGS8SnsqRxphPOc6cQMrkzuCzwXebP4svkvCVzedEXwqtA14RxSrsj1zTdE88TyxW9KFkjekiqUvi1ze7yIfEf2rlyxQoniPaX7Sg+UH24tVS1TK1t4FFKu/lijQqtS+8m2qm1PdZ6uVUfU6D3b/lz/hcFfhrXo2pi6HS+N600aTBtNm1iaEl6ZNZu3WLTiWs+9tmyzemPdTmhPfWvTYdu5t4u7K7Pb/p1Dj1Mvf292n3O/88D+90Lvr35wGTw4JDKU+9Htk/tnj2Hx4fwRry/eoz5j0mOF434T/l/Jk3KTd6cCpykz1Fml2ftzQfPB32gLqgtliyHfQ5fCfoQtay1XrhxbDV/TWXtKpwMgRJE45DSqCX2bIY0xHOPNZMtsyLKVVRIrycaL48HzsvNycBEkOKWIGlzm3Ad4gnmT+Ir5mwRGBTmF1IS9SRdEXooixHTED0nck5ySlpIhb6mUQ8nrK6QoDipLq8Ru7VKTUadq1GrxaIdue6XLrUfZ/txAzPCYUZuxkEnozirTJTMlc8/d6RZtljgrE+tQmzzbt3Ys9tsdDjledqrbN7Vf+MAel6MHc11r3UY9uDz1vBy8T/hc863x6/dfCuAM3EIxovocCg9KDs6llR6uD+k9Mha6cBR1jCOcdFz2hGrE9kizqD3R+04ejPE8RY6lnQ46ExkXGX8yIe5samJCUta5i8mZKSmpl9JSz2ekX8goyLx54e7Fgqzb2cWXnlx+cqX26qtrbTntue3X22/05n3KH7k5VPD51lThzO2posk7s3enisdLJu6N3B98MPSwp7StrOFRTfmjx8UVlypTn0RWBTzdV21Ws+2ZzHPC86UXH/5qrH1Yl/YyqN6mQa1RoJHe1PPqYXN8i1OraOvw6wdtx9/saMe197+91uHXqdK52tXcnfZuf490z1xvRV90v9kAcWDg/a0PwYPaQ+ihxo/nPx34LPl5YrhiJOrLrlGu0f6xG+PkCdWJta8Nk6lT+6bFpidmHsyGz5nME+a7v+UtUBY1v6O+v1xK+bFvWXT560rZauSaKZ2bTgeAk4hQ5FGUNqoCfZxBj6GaMQpzismYqZY5luU0azx2F7aJLRGXiE9i38PeypFMSOVMI6Zx2XK95c7gyeC9wJfFny2QvemSoLNgv9BV4WukHJGczTmi18VuiOdJ5EvelCqQviXjKzO2pVC2SO6O/F2FYsUSpXvK91UebH2oWqZWpl6mEarxXbNCq0K7ctsTnSrdE7pretXba/SfGTw3fGEUswO9o9a4zuTlznrThl2NZgnmWPNXu5stWva0WiZbsVu1Wb+xabd9u7fTLsOe277LodvxnVPPvmxnAee+/f0H3rt8OPjBNcdNxG3I/aPHJ8/PXvneEusJ4jfmf5ssS574txSZ+5Ui5WEaYUtHfxxbDl85vnpiLYIeBdHIX0mCOYOJY4priN+VwHoWm4hNYjuHT2ZP4fiVJdyZPBd4f2bJpj+zJHfouvsN0TyxfImbEhtpUiR7R+6u/B9ZolK6tUz1kXq5+mONCs1K7SfaVdue6lbr/pEjO+qMXxrXmzTsbDRtMnsV0rK51eK1ZZvlG6v24x0ynXZd9t3RPQq9Tn2xAyrv4wZVh85+8hjWHkkZ9R33+0qeoszEzzstnFtKWLWm0wHW9z4AAEY1gIwtAHZZADa5ALFbACRdALgLACzZAGw1AckgBEgdKiB26WzsH4AAdhAEeTAARwiGZCiB7wgSwgwRiihAtCBGkHikCTIKWYVcQemgolB1qBW0CNoRnY/+xmDMcIqhmGGK0YQxh3EYw4VxxlQxYZg0mWKYxpm1mCnMNSxyLJEs5aw41ijWd1giNhD7hW0H20m2QZwr7jkehffCT7BbsWewr3LEccwStAh5nOqceZxTRBfiIpcvVxn3Fu6XPF68GN5CPnG+I3zz/JcFTATmNl0TFBMMF0IIlQr7kURIPSLnN2/eHCmKF20VSxHfK8EvMSR5W8pQ6pa0gQyHzOCWB7Kn5ZzlVRSwCiOKfynlKkereGw1UZVV41RbUR/WyNTEadZolWjnbDuvc0Y3Qu/I9kP6ZANfQx8jnx3+xoEmtJ3HTGN2nTPLNr+1u9yiYU+f5Yw1xkbIVmOvjR3VPsnhruNrpzln3v26B7xckg9Wun5x5/Ew8QzzKvLl9bP0jyfXBiIp+tSoQy+CGWlmh1NDxcIoR5+Esxx3OlEUQY+yjUGeco59dIYz7lB8W2J60lKyS0pdmsL5rMzgCx+zbLJrr9y9Jp5z+TpPPvvNpFu4wnN3MosFS27clys1Kmsrd308U8XztKjG4AWtFl9XVL+rKb5ZrqXtdUh7XQe1S6C7vk+iv/t9/KDep6Jhjy/Coz1f7aa4p7tms+ZdFieWSpcj6Lx0OgAggQV4QBr0wAEOQzqUwwACg1BEuCCSENWIOaQM0gWZhXyLwqN2o86imtFs6D3odHQvA4nBl6GE4TujIeM5xncYccxhzAsmApMHUzkzK7Mz810WNMsBloesLKzurNVYLiwV28wmw5bINoEzxxXj2fAUfCf7dvYbHDiOEI5egjHhHieJM5VzjRhM/MrlxzXGTeae5aHxLPAe5UPwneXn5y8U0BSo22S3aVQwUohPqEzYSniMFCsiIVK/OVCUR/SpmLs4VvyZRKCksOQbqThpA+lVmcot4bI6soty1fJnFGwVRRSnlKqVU1T8thqpCqkuq3WoP9a4rBml5a1tv01HR0FXRI+wHa2P0p81mDGcMhrfMWw8ZzK+89supBnRnGe3koXunj2W1lb+1mE22bb3976y67VfcSQ6KeyzcD60/+KBWpcRV2Y3RXcfjyzPaq9pH2lfT79M/44AgcC9lGzqlyCp4BBaQ4jgkeDQxqOix5LCx044RtRHqUXnxRBOJZ0mnMmI503ITlRNakn2TPmRlpiunvH5wpUsv0t7r0hfY8iZuP48r/TmxVuxt93vOBcb39N4sLVU/pHcY6lK8SqpasVnei921lq9JDccakppvtb6pG2gnd4p3K3T49GXMFDxYeIj32eDkcjRgvFPk/zTXrNX5ocXpZYCl8vWEHQ6ADACOwiCAThCMpTAmw37G+7X1aPxaEf0NwZjhqyf3tcwzkzCTDFM48y2zDUsciyXWHGsUayL2EDsFzYPnCvuI94LP8EezL7KEUfgJuRxqnM2El2Ii1zJv0xb8M3/9GwphBAq/WnZal3yT8ch0gZ/Gv4t+KffN5o1WiW/7f6W+89u/5ta70FfXj/Lv6sN6fm72+jCP+WeVf4tN4Nxw+5lzQ29N9I2/BYRNgQ/KN8wXHlyXfGzng3HDaNN8a/+as5oaXsd8kawva6D2lnSFdtd3xPSJ9HvP2D0Pn5Qb+j0R7dPRZ8Xhtu/CI/6j5mOS01gvtpN5k/FTnvP7JyVmWOdm5x//e3BQsai7eLE95glgx+SP4aXI1Z4V66scqzGrC6u3aAn0OkA6+clAABgMaSQKUEkc0Oj//Ow978qgHx4Yw4kAGA9A/faAAABAKR8aaa2AEAEAC0wBAqQgQJBQAJzMASjn1cSuP964guwfpYDAGBkB7hkDwBQ/f1Y5N/npXmG0gAADCnUsCBfbx8aSZ9KJXuSDCkB1MM0zyBZkmmgu7wsSVlRURUA4F93RgACxGzQPQAAAAlwSFlzAAALEwAACxMBAJqcGAAAC39JREFUeJzt3W+MHHUdx/HP7Ozu7e1dDyjXq+215dBWSkhMbbWIEQ2JQhB5YuIjHxvQiCZijCFaCPGJJBgTYjD+4ZmAhCeikQQTkX+BAsWqTajU0BZ7Lb0eB1zvbu92dnZ8MPvr/m671/Y7O72e7fuV/LJ3u3e70wfz3t/8Zm4rAQAAAAAAAAAAAAAAAAAAAADQVXABn/98vzZwqUjO8b7cnI+dt/M5C979nY91uw/AmSVdvvbva57hsVzkudP6z1VQOwpudLvvfG4PcDFaKhr+aGpxPPyRi2JOzxN4ty4SYeu2c7jHO3/PvwXQXXOJ75tdRty6TXT6LKQneYSjc1bhB6M4NnZd5e7vPH7bFVes/XK51LctKBTXFoJgIIfXBSCpmSSzSbNxvB4t7H3vvWNP//wXX//jwYP7FpSGw41Ap89GMuv1Hd6PRuiNoqTSgw+8dvvG0Wt+/JF15bENm0INrymovz9QscTEAshLI0pUqyWaPNHUkXdivXt04fB/j751/90/+PRTkhpKw9FojVzi0cse3C0aRUnlarVafuhnb+4aHR25c/vOktaMhL1sIwCDExOx3ng10vj4xC/v+t6198/NzS0ojUaknOKRNRzu904dkkgqtUbfbx4+uGvzlnV33HBjWeVyoChKdGB/Q8fGY83MJIobWTcXQKewKA0OBlo3GmrL1qJKpUD1eqKXX6jrwFtHf/WNb330PqXRqLdGt7UPk17C4dY0ipLKSqNR+cn9z97+qU9+5uGbbu5TuRxo4nisPbsjVasFrR4uqtIfKAw5VAHyEseJ5muJpiYbmptrasf1JY2sDVWvJ3r2mQW9/vdXvvmjXTc9JWlBaTgitdc+MoWjcPYfOU3nQmhJrXgMD68f3Dy27Z7tO0unovHKi3Wt31DSxrGyBgYLRAPIWRgGGhgsaONYWes3lPTKi3VNHI9VLgfavrOkzWPb7hkeHh2U1Kf2/uqfxDDL9EstnfGofPuO3962fkP/xjUjoaIo0Z7dka66uqxVQ6xxAMth1VCoq64ua8/uSFGUaM1IqPUb+jfedecjtykNR1ntaGR+F88aDn9twx2q9I2OXvOlDZvSSBzY31C1WiAawDJbNRSqWi3owP50MXHDplDr12+5We0ZR0ntExqZrt7O61ClLKlvoDp03fCa9CmPjcdaPZzX9WUALFYPF3VsPJYkDa8paKA6dJ3aM45lP1Txr/B0xToVjmKpb7i/P/2RmZlElX7WM4ALodIfaGYmvUg0vXaqb1hSRe0TGUUt/jMQk15nHK5cRUnlsBD2u4u74oZYCAUukDAMTl32UCwFCgthv9qHKS4a/p+BmPQSDj8ebtYBYOXyD1PcoYpjikfWcLhSLbpiNMNzAVg+brbRucaxLDMOaXE8/LMrAFYuPxpn+niLs+plcdQ/XMm8Ogtg2XR+1IX/pyMmec04Oo+XAKw8nYcnmS8Cy7rG0e17wgGsfEt9iFamJ8nqbB8FCGDlONPn/2Z6oqz4yD/g/0/P+y2HF8ClI7c3eMIBwKzXP6sHcAnK86wKIQFWvs6zKlri+3N6EivOogAXh2X761gAlzjCAcCMcAAwIxwAzAgHADPCAcCMcAAwIxwAzAgHADPCAcCMcAAwIxwAzAgHADPCAcCMcAAwIxwAzAgHADPCAcCMcAAwIxwAzAgHADPCAcCMcAAwIxwAzAgHADPCAcCMcAAwIxwAzAgHADPCAcCMcAAwIxwAzAgHADPCAcCMcAAwIxwAzAgHADPCAcCMcAAwIxwAzAgHADPCAcCMcAAwIxwAzAgHADPCAcCMcAAwIxwAzAgHADPCAcCMcAAwIxwAzAgHADPCAcCMcAAwIxwAzAgHADPCAcCMcAAwIxwAzAgHADPCAcCMcAAwIxwAzAgHADPCAcCMcAAwIxwAzAgHADPCAcCMcAAwIxwAzAgHADPCAcCMcAAwIxwAzAgHADPCAcCMcAAwIxwAzAgHADPCAcCMcAAwIxwAzAgHADPCAcCMcAAwIxwAzAgHADPCAcCMcAAwIxwAzAgHADPCAcCMcAAwIxwAzAgHADPCAcCMcAAwIxwAzAgHADPCAcCMcAAwIxwAzAgHADPCAcCMcAAwIxwAzAgHADPCAcCMcAAwIxwAzAgHADPCAcCMcAAwIxwAzAgHADPCAcCMcAAwIxwAzAgHADPCAcCMcAAwIxwAzAgHADPCAcCMcAAwyyMcSQ7PAWB5JB23mWQNRyKp2csLA1gREmWISJZwLPUizDyAlS+X/Zc1DgBmhAOAWa/h8Kc3SSNuzDei9K6wKMUxRy/AhRDHicJi+nUjStSIG/PKaWFU6n2Nw33dlKSF+ZkPa7X0rsHBQPM1wgFcCPO1RIODgSSpVku0MD/zoRaHwx9mvZxVcaPpbienxg9NnkhPtqwbDTU12cj49AB6MTXZ0LrRUJI0eaKpyanxQ0r3Vbe/Zo6GZA9Htxc6FY5/7fvbG0feiSVJW7YWNTfX1MnpOOu2Acjg5HSsubmmtmxNj1WOvBNr377n9mjxG70fjmU5HeteyK9XQ1L82BP3vXbo7anJExOxSqVAO64v6fDBOvEAlsnJ6ViHD9a14/qSSqVAJyZiHXp7avLRJ3btUWs/bY2eZh2h8eeD1ghbo9QaZUl9jUZUrlSH5tdeecOOTWOhhi4r6IorC3rrzUi12aaKxUBhKBUKQZZtBdBFHCeqzSU6fjTS1Huxdn62rJG1oer1RC8/X9eTf3jod3v3/uWApFlJNUnzrRG1hgvJOStm3FZ/fSNWWrKGpPpjj9/7+sfGtn280n/LF264Mf0HfPHWgg7sb+jYeF0zM4lilj6A3ITF9GTEutFQW7b2qVQK0mi8UNeLLz3z3GOP3/u62pFwsw53xJCJ9a0/UHp4U5TUJ6kiaUDSoKTLW2N1oVBY/cPvP/nVz9946+e27yxpzYh1YgMgqxMTsd54NdJzz//5pZ8++LUnm83m+5LelzQlaVrSSbVnH3WlMXHLDuckyx7t4uGPoj+SJAlfeOn3h2dr0fuF5rWjJ6crlWZTKhalsCAVQg5VgLw0okSzs4mOHom17x+Rdr/87gePPvHAU79+5Lt/TZJkRpI/apIWlAbDHaaYoiHZZxzud4pqr230S6oqnXUMSbpM6cxjlaRV5XJl6Cu33vWJbdtuvmZ03eaRavXygXKpr5ThdQF0UY8Worm5D2bHj/1nYu/eZ/79p6cf+me9Pj+tNBQfeuOk2rONBbUDYl7jyBoOf3G0ojQcVbVi0RpDrduB1mN9reFmJgXv9TtvAXTnr0v464xuBlFrjVm1QzHdGjNqH6K4aJgPU6R8FkcbrQ1whywuCIHap2rrSgNTVhob/+f4exnAxr9i251ejZTuZwuS5pQGYlbdY+F+J/PiaJZwuGAE3ga7CIRqB8NFw02JKmqfvnUzFj8yAM7Oj4b/5u2Ho6Z2PNztvLqvbZhnG1L2GYf7B7jiuXjUWo+5jYnUDkefFofDLawSDsDGn/H7+2C9NebVPmSZVxoPtx/6p2MzX3Ley6GKm+YErY0JOh53/5gFpRvvDlP82QbhALJpanE4Tl1LpXY8Om8j72f9S8/NeplxSN2PkVw03PSprHSjXTTc+oY7rJG6h4OYAKluf5HuvnaHKk21L/ByF3stqD0TaXiP9RQNqfdDlUBLr/LGSmNRb71O6N36Mw0WRwEbf53DRcDtc34gGt7onGn09JnBebyru+fwF0j9UVT3wxP/dGxe2wJczDpnCN3WOvw3bhcN/3Ephw8az2tn7YyHHxH/ClP/qlOJ2QaQVefZFT8gLhKd90k5REPK/13eD4i79b8OuvzM+dwe4GLTbb3DD4d0ekyknILhnK8d1X/eQsf9Sy2IEg3gzJZazOxcZ+wMSu6Wa2c92+sQDcCG/98IAAAAAAAAAAAAAAAAAAAAALAS/Q8LAUdRAb/LqgAAAABJRU5ErkJgggo=) no-repeat -10px -138px;
816}
817
818form#recordFilterSearchForm {
819}
820
821input#recordFilterSearchValue {
822 width: 200px;
823}
824
825/* @end */
826
827/* @end */
828/*
829div#mainContent {
830 padding-left: 15px;
831}
832*/
833div#recordListAndDetailBlock {
834}
835
836table#recordListAndDetailBlockTABLE {
837 width: 100%;
838 /* background: url(../images/cardBlockLowerBorder.gif) repeat-x 0 bottom;*/
839 background: url(data:image/gif;charset=utf-8;base64,R0lGODlhBwAZANUAAP///6qq7tzc+OLi+eXl+vz8/v7+/9/f+dnZ9/b2/fr7/vT0/fv7/vLy/Ojo+vj5/vT1/dnZ+Ovq++3t+/n5/e3t/Orq+/n5/u7t/Orr+/Dv/PPy/PLy/e/v/OXk+tna9/38/uvq+ufn++Df+P7+/vX1/fj5/fz9/+jo+9/f+Ojn++/w/P79//v6/vb3/efo+u3u/Pf3/ejn+vDw/PDw+/X0/e/w+/f2/QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAAAAAAALAAAAAAHABkAAAZoQIBwSCwaj8ikEkAyOFnOAqhALZwYCkZLkaVQHpfLw+SKJRK3M2RRKy0WkA2H06hvNDMbbdXRVCYYMBUYExYSIRkSGRYiMi8qDg4oBJSVHgOYmQMpIweengKhogIIEREIHwgIAaytAUEAOwo=) repeat-x 0 bottom;
840}
841
842td#recordDetailSeparatorTD {
843 border-bottom: 1px solid #aaaaee;
844}
845
846table#recordListAndDetailBlockTABLE tbody tr td {
847}
848
849div#recordListBlockHeader {
850 background-color: #333366;
851 /* border-bottom: 2px solid #aaaaee;*/
852}
853
854div#recordListBlockHeader table.recordListBlockHeaderTABLE {
855 width: 100%;
856 height: 30px;
857 color: white;
858 /* background: url(../images/cardsBlockRoundCorners.gif) no-repeat right -51px;*/
859 background: url(data:image/gif;charset=utf-8;base64,R0lGODlhCQBkALMMAP///z8/b7e3yaKiufX19zQ0Zzw8bVxchaSkuz4+bltbhDk5av///wAAAAAAAAAAACH5BAEAAAwALAAAAAAJAGQAAARTEEhAhgplimCYl8jijYAwnkRwjkO3MsfrJTJT1Hiu73zv/8CgcEgsGo/IpHJZKyQOA8IEMDIEBJMXQvJaYGUBgswwqClqKtmNyW673/C4fE4/RgAAOwo=) no-repeat right -51px;
860}
861
862div#recordListBlockHeader table.recordListBlockHeaderTABLE tbody tr td.recordBlockTitleTD {
863 /* background: url(../images/cardsBlockRoundCorners.gif) no-repeat left 0px;*/
864 background: url(data:image/gif;charset=utf-8;base64,R0lGODlhCQBkALMMAP///z8/b7e3yaKiufX19zQ0Zzw8bVxchaSkuz4+bltbhDk5av///wAAAAAAAAAAACH5BAEAAAwALAAAAAAJAGQAAARTEEhAhgplimCYl8jijYAwnkRwjkO3MsfrJTJT1Hiu73zv/8CgcEgsGo/IpHJZKyQOA8IEMDIEBJMXQvJaYGUBgswwqClqKtmNyW673/C4fE4/RgAAOwo=) no-repeat left 0px;
865}
866
867/*
868table#recordListButtonsTABLE {
869 width: auto;
870 margin-right: 10px;
871 position: static;
872 float: right;
873}
874*/
875div#recordListBlockHeader table.recordListBlockHeaderTABLE h3 {
876 color: white;
877 padding-left: 10px;
878 padding-top: 3px;
879}
880
881div#recordListBlock h3 {
882 padding: 8px 0px 2px 10px;
883 /* margin-right: 8px;*/
884 color: #666666;
885}
886
887div#recordListBlockHeaderButtons {
888 padding-top: 5px;
889 padding-right: 0px;
890}
891
892div.recordButton {
893 padding: 2px;
894}
895
896td#recordDetailSeparatorTD {
897 width: 1px;
898}
899
900ul#records {
901 margin-top: 6px;
902 list-style-type: none;
903 padding-bottom: 15px;
904}
905
906ul#records li {
907 list-style-position: inside;
908 padding: 1px 5px 1px 8px;
909 border: 1px solid white;
910 color: #35306b;
911}
912
913ul#records li.hover {
914 color: #ff9400;
915 border: 1px solid #f5f5ff;
916 border-top: 1px solid #aaaaee;
917 border-bottom: 1px solid #aaaaee;
918 background-color: #f5f5ff;
919}
920
921ul#records li.selected {
922 background-color: #ddddff;
923 color: #ff9400;
924 border: 1px solid #ddddff;
925 /* border: 2px solid #35306b;*/
926 /* border-right: 1px dotted #333366;*/
927 padding: 1px 6px 1px 8px;
928 /*background-color: #35306b; */
929}
930
931ul#records li span {
932 color: #35306b;
933 text-decoration: none;
934 line-height: 16px;
935 font-size: 10pt;
936 cursor: pointer;
937}
938
939ul#records li.selected span {
940 /* color: white;*/
941 color: #333366;
942}
943
944/* @group Bottom rounded corners */
945
946td#cardBoxLowerLeftTD {
947 /* background: url(../images/cardBlockLowerRoundedCorner.gif) no-repeat left -32px;*/
948 background: url(data:image/gif;charset=utf-8;base64,R0lGODlhCQBkANUyAP////Ly/PDw/O3t/OLi+ejo+vz8//n5/urq++Xl+tzc+Ovr+/z8/t/f+Pv6/vb3/fT0/f7+//v7/vT1/efo+/79/8vL9fr6/uXl+e3t+/3+/9jY9/b2/vX1/d/f+ff2/fb2/fj5/uHh+dnZ+OLi+rOz8NnZ99vb+LKy7/r7/6ur7sDA8vLy/f7+/vn4/u/w/Pj4/vX0/P///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAADIALAAAAAAJAGQAAAb3QJlwSCwaj8ikcslsOp/QqHRKfQKu2Kx2y+16v+BtRFNpjSuRisHAYKzdDMfFIZE7UpfQYa8/wFwfDyAcgSAPHB0QExCJExMxAZGSkSwClpeWLwObnAMZGQsLCAiipAgUFAUFqaoFGwkJGLCyGBIEBCS3uQQAIhYNwA0eHlcnFgrIyFgiJRYmIyNZEhsrKCpV2Nna29zd3t9h4eLj5FdoFRoRLegRcG9uBhcpdnVzLjB8ewchHIIPHxwMfYjhiJEiRiwmTXqBCdOnTpxMSQzVapUqVLRmwdqgqyMBCcOCNbAgAkAyZBZOXIFmwkKJkldUoFixQUKWIAA7Cg==) no-repeat left -32px;
949}
950
951td#cardBoxLowerRightTD {
952 /* background: url(../images/cardBlockLowerRoundedCorner.gif) no-repeat right -82px;*/
953 background: url(data:image/gif;charset=utf-8;base64,R0lGODlhCQBkANUyAP////Ly/PDw/O3t/OLi+ejo+vz8//n5/urq++Xl+tzc+Ovr+/z8/t/f+Pv6/vb3/fT0/f7+//v7/vT1/efo+/79/8vL9fr6/uXl+e3t+/3+/9jY9/b2/vX1/d/f+ff2/fb2/fj5/uHh+dnZ+OLi+rOz8NnZ99vb+LKy7/r7/6ur7sDA8vLy/f7+/vn4/u/w/Pj4/vX0/P///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAADIALAAAAAAJAGQAAAb3QJlwSCwaj8ikcslsOp/QqHRKfQKu2Kx2y+16v+BtRFNpjSuRisHAYKzdDMfFIZE7UpfQYa8/wFwfDyAcgSAPHB0QExCJExMxAZGSkSwClpeWLwObnAMZGQsLCAiipAgUFAUFqaoFGwkJGLCyGBIEBCS3uQQAIhYNwA0eHlcnFgrIyFgiJRYmIyNZEhsrKCpV2Nna29zd3t9h4eLj5FdoFRoRLegRcG9uBhcpdnVzLjB8ewchHIIPHxwMfYjhiJEiRiwmTXqBCdOnTpxMSQzVapUqVLRmwdqgqyMBCcOCNbAgAkAyZBZOXIFmwkKJkldUoFixQUKWIAA7Cg==) no-repeat right -82px;
954}
955
956/* @end */
957
958/* @group New record panel */
959
960div#newRecordPanel {
961 position: absolute;
962 margin-left: 20px;
963 width: 400px;
964 height: 160px;
965}
966
967div#newRecordInnerPanel {
968 width: 400px;
969 height: 160px;
970 /* background: url(../images/newRecordPanelBackground.png) no-repeat 0 -165px;*/
971 background: url(data:image/png;charset=utf-8;base64,iVBORw0KGgoAAAANSUhEUgAAAY4AAAFQCAYAAACoMJkjAAANIWlDQ1BJQ0MgUHJvZmlsZQAAeJyV13k0lG8bB/BrFsYyZhhjDyO7iLITskQi2feS7AwzMQkpS1KILKFoQWihKJGoqH5kSUghoajIkj1Llnn/kOr9nff3vue9/njO9dzPc859P885n+99bgC8miuVSkYCgH8ALdDSSI9k7+BIwnQCBnDAA1gQdnULouqam5vCP9Z8JyAAADrkXKlU8j+/9x8LF2jv4AiAkAUAotd6vxMAiIfWe2sAIB6lUWkACG8AILp5u7oDIMIBQDbQ2lIfAHEDAHBe630lAOAOrfcNAIALdvOiASC6ARgJAe4+AQCYcQBGbXePIDcAnCwAuLsHufkD4JIBwMzfn+IOgPsIAFJu1EAaAJ4JAOTsHRxJ60t2igdQ4gNgMvk9djQdoDwXQGrv7zHRBwDcrgB5ib/HZi0BAQAI7tYgT8XtAACAwOoBMPTT6bMSAJhUgNUUOn05j05fvQaA6gWoJbsdCQz++b8QiBaA/3W//s0/C4UAQAIgxBCFyDBUODqc4QRjJCaa6SSzAXMdy2nWM9g4trO4CnZvjhRCCmcq8TxXOnc6TyZvHT9FIHtTtuBloQbSEZG8zddEW8WPSRRKtkufkCna0ikXvfW2fM+209vvKX5QPqtSoTqgnqRRpTmklab9RGdUN0Pvmf7ErizDeqMZ46t7mkzm9+aZvdrXZt5m0W65Yn3L5q1tp12Xfbcj2umuc+/+vgP9Lh8OfjyEdXvo/tnji+eQ17D3V58RPy7yU/9vAROUSerU4enAmaA52tyR78HzRxdCFkOXwn4cWwlfOb4aIR35NhpxEhmDOoWOZTjNeAYTxxTPnMByljURm8R2DpeMT2FP5UgjnOdMJ2ZwZXJf4LnIm8WXzX9J4PKmK4JXhXKEc0l5Itc254sWiBWKX5e8IXlT6pZ0kUzRWDH5tuwduRL5UoW72+5tK9t+X6lcuUKlYv5BcKXqQ7UqjWrNRzse73ii9WStJqJW5+nOZ7rP9f7Sr0PXxdTvemHYYNRo3GTczNKc8NKkxfSVWSuu9VybebvFa8sOQkfqG6u31p02Xdxdmd127+x7HN/zv8/ude5z7t//QejD1Y8uAwcHRQbzPh367PbFfUh8qHDY86vXiPeo9OitMd9xv2/kCbmJO5MBU5Rp6sy2mXuzgXNB32nzyvMVC8GLIUuhP0KXNZarV46thq9prT2h0wEQokgccgrVjC5iSGMMx3gxWTPrsyixSmIl2XhxPHhedl4OLoIEpxRRjcuU+wBPEG8SXwl/s8CIIKeQirAX6YLIC1GEmJb4YYm7kpPSUjLkLdVyqK268ikKA9ulFWOVulRkVKlqdRo8miE7Xmpz61B2PtMT0z9m0G4oZBSy+7Hxksk2U4+96Wbt5jgLI8sQqwLrN7YsdjvtDztcdqx3mtwvfGCfS9jBPNe6QyPuXB46nvZeJ7xzfGp9+/yW/DkDtlAMqN6HwwOTg/Jo5Ucagt8fHQ2ZD0Md4wgnHZc9oRyxM9Ikal+008mDMR6nyLG004FnIuMi408mxJ1NTUxIyjp3MTkzJSX1Ulrq+Yz0Cxk3Mq9fuHPxRlZRdsmlR5cfXam7+jKnPbcjr+NaR/77gs+Fw9cHb3y5OXlrumiyeOL2zJ3JkrHS8bvD9wbKBu/3lLdXND6orXzwsKTqUnXqo8jH/k+cakxqdzyVeUZ4tvT8419Ndffr014ENlg1qjQJNNGbe17eb4l/5dgq2jrUVtZ+/PWuDlxH35uct76dip2rXS3dae/290j3zL6v6o3uM+kn9vd/uPkxaEBzED3Y9On85wNfJL+MD1UNR33dM8I10jeaP0YeVx5f+9Y4kTrpNCU2NT5dNhM+azRHmOv+XjBPWVBfRC2+WEr54bQsuvxtpWI1cs2Yzk2nA8BJRAgyDKWJqkIfZ9BhqGGMwpxiMmSqY45lOc0aj92DbWZLxCXik9j3sbdyJBNSOdOIaVzWXG+4M3gyeC/wZfFnC2RvuiToLNgndFU4h5Qrkrs5V/SaWL54gUSh5HWpG9I3ZXxkRrfcki2Wu731jnyJQum2u9vvKZYp3VeuUKlQrVALUVtUr9Ko0qze8UjrsfYJ7TWdmp21uk/1nuk/N4jZhd5VZ1hv9GJ3g3HjniaTBFOs6cu9LWav9rWaJ1uwW7RbvrbqsH5j02mbYcdt12Xf7fDOsccp21nAuXd/34EPLh8PfnTNPSRyaNDtk/tnjy+ehV4S6wniO+pXRJYlj/9bisz+SpHKULXQpbAfx5bDV46vnliLoEdBNPJXkmDOYOKY4hrj9ySwnsUmYpPYzuGT2VM4fmUJdybPBd6fWbLpzyzJG7zmli9aIFYocV1iI02KZW/L3dn6R5YolitVKD9QrVR9qFalXq35SPPxjifaNdp/5MiuesMXhg1GjbubjJtNXga/2txq1mbebv7aouP4W5lO2y677uge+feOvbH9ih/iBpQHz352H9IcThnxGfP9Rp6kTMfPOc6fW0pYtaTTAdb3PgAARhWAjC0AtlkAVnkAsVsAJF0AuG8AmLMBWKsDkkEIkFpUQOzR2tg/AAHsIAhbQQ8cIAiSoRQWESSECSIEcQPxCjGMxCONkFHIx8gVlBYqClWPWkGLoB3QhejvDIYMpxhKGCYZjRhzGYcwXBhnzGMmDJM6UwzTGLMGM4W5lkWOJZKlkhXHGsX6DkvEBmC/su1iO8k2gHPFPcOj8J74cXYL9gz2VY44jhmCBqGAU5WzgHOS6EJc4PLhquDewv2Cx5MXw3uLT5zvKN8c/2UBI4HZTTmCYoLhQgihcmFfkgipR+T85s2bI0Xxoq1iKeI2EvwSg5JFUvpSN6X1ZDhkBraUyZ6Wc96qKI+VH1b4a1ve9mhFdyUjZVkVTpUV1SG1THWceq1GqWbujvNaZ7QjdI7uPKxL1vPR9zbw3uVnGGBE233MOGbPOZNs05t7K80a9/WaT1tirISs1WysbKl2SfZ3HNocZ51592sf8HRJPljt+tWNx93II9Sz2IfX19wvnlwXgKToUqMOPw9ipJkcSQ0RC6WEPQpnOe54ojiCHmUdgzzlHPvgDGfc4fj2xPSkpWSXlPo0+fNZmUEXPmVZZddduZMjnnv5Gk8h+/Wkm7hb525nlgiW5t+TKzeoaK90fTj9mOdJca3ec1odvr64YU9zfIvcq/a24I76t9Quge6GXom+7g/xAzqfi4fcvwqP9HyzneSe6prJmnNZGF8qX46g89LpAIAEFuABadABezgC6VAJ/QgMQgHhgkhC1CBmkTJIF2QW8g0Kj9qLOotqQbOh96HT0e8ZSAw+DKUMi4z6jOcY32HEMUcwz5kITO5MlcyszM7Md1jQLAdY7rOysLqx1mC5sFRsC5sMWyLbOM4UV4Jnw1Pwnew72fM5cBzBHO8JhoS7nCTOVM41YhDxG5cv1yg3mXuGh8YzzxvGh+A7y8/Pf0tAXaB+k+2mEcFIIT6hCmEL4VFSrIiESMPmAFEe0SdibuJY8acSAZLCkq+l4qT1pFdlqreEy2rJLsjVbD0jb60gojC5rWZ7iqKvkoGykPKyylvVh2qX1aM0vDTtdmhpyWuL6BB2onVRujN60/qTBmO7hgxnjcZ2f9+DNCGa8uzdZqa9b5+5pYWfZahVtvU9m5e27+1WHIiO8k5mzof3XzxQ5zLsynxIwc3bPcujxnPKW9rHwzfT762/QIANJZv6NVAqKJjWGCx4NCikKUz0WFL46AmHiIYoleiCGMKppNOEMxnxvAnZicpJr5I9Un6kJaarZny5cCXL95LNFekchtzxa88Kyq9fvBlb5HbbucTwrlqZUvnWB3IPparFH0vVKDzVeb67zuIFufFwc0pLTuuj9v4Oeqdwt1aPe29Cf9XH8U98X/SGI0dujH2e4J/ynLkyN7QgtRSwXLGGoNMBgBHYQRD0wAGSoRReb9jfcL+uHo1HO6C/MxgyZP30voZxZhJmimEaY7ZmrmWRY7nEimONYl3ABmC/srnjXHGf8J74cfYg9lWOOAI3oYBTlbOJ6EJc4Er+ZdqMb+6nZ3MhhFD5T8sW65J/Og6W1vvT8G/BP/2+Vq/VKP1t97fcf3b739R6Dfjw+pr/XW1wz9/dRt/6U+7Z7b/lZjBu2L2svqE3P23DbzFhQ3BZ5Ybh6pPrip/2bDhuHGmOf/lXS8ar9rbg14Id9W+pnaVdsd0NPcG9En1+/QYf4gd0Bk9/OvS5+Mv8UMdX4RG/UeMxqXHMN9uJwsnYKa/p3TMys6yzE3Nt38vmMxasF8YXY5b0fkj+GFqOWOFdubLKsRqzurCWT0+g0wHWz0sAAMCiTyFTAkmm+gb/52Hvf5U/+cjGHEgAwHoE2FgBAAEApHxoxtYAQAQADdAHCpCBAoFAAlPQB4OfVxK4/XriA7B+lgMAYGQHuGQHAFCzeCzy7/PSPEJoAAD6FGpooI+XN42kS6WSPUj6FH/qEZpHoCzJOMBtqyxpu4KCMgDAvwBJl//fxucdgAAAAAlwSFlzAAALEwAACxMBAJqcGAAADQdJREFUeJzt3U+MnGd9wPHfOzP7x/FuvOAYZAzGRg1pFKDAIVXbiD8Sai2knKJK7QHEAXHoHfXS9MIFDkg9c0BVD1SqUIA2VRuLKhIEOBjhQxDBjo0BJ7gQ4jq769m1d2emh5nH885k7e5vZnbj2p+P9Gr+7LvvO3t5v/u8z/vuRgAAAAAAAAAAAAAAAAAAAAAA95HqLd7vW7V/gHtBb7Dsq70+cFe1Jcae78f+Ae5V48Hojj3fs6Ds1YG7iohGjIZj/PV4VADYvV5tKdHo3uG9mZn1QbseiEZENAfvt2rvNcbW28vPA3Av2WmUUQ9FWTq15/WvzyQgszpQ7xSM5uB56/jxPzt66NDxJ5vNA59sNKr3RjROVlU1P6N9A9zHemu9Xu/Vbnf7JzdurP/bSy9987sRsR39eGzHMCQzi8cswlGPxq1YRETr0KH3v+3EiT/+21Zr8bMR1eIM9gXAHXS7nZfa7d///blz33k+hvGoB2TqeDT/71XuaDwarYiYj4iFEyc+9cFjxz70zWZz/lMRVWvK/QCwC1XVODI3d/AvH3ro0d7vfvfij8vbs9zHtOEocxb1aMy/5z0fe/TIkT94pqoa75r2AwKQU1VV1WzOP3H48CMxiEcZYfRiBhGZZgNllDESjeXld608/PCnT1dV43h95cOHH4zPfObP4/HH/zCOHj0cy8sPTLFrACIi1tbacf78K/HMM9+L5547M/K1Xq/XW1+/8rnz55/9bkRsRsTWYCmnrrpv2uAuTBOOMp8xN1jmI+KBD3zgr/9uYWH58/UVT516PL74xb+KQ4cOTrE7AO7k+efPxpe+9E+xutq+9V63u33h7Nmvn4qIdozGoxPDSfOUSU9VlbmN1mBZiIjFBx88cfTIkUf/oaqqW9v9xCc+HF/+8hdicdFFVAB76eTJo3HixNE4fXo48qiqxtsPHnzn+atXX/5FjF6uW78PJKUx4eerX3Z7Kx7Hjn3kqfpltu94x0o8/fRnJ9wFAFkf//gfxalTj4+8t7i48hcRsRj9X/LLMXune+l2ZZJw1G/kG7mSam5u6Yn6ik8++adOTwHss6ee+tjI67m5xQ9F/zjdiv7UQjOm+Osd04w4SkDK/MZ8szn/aH2lJ5744ISbB2BSDz/87pHXVdV4KPqjjTLiKL/071s4yk7qp6nmImKx0Wiu1Fd87LETE2wegGksLR0YeV1VjYPRj8ZcDMNRfvlPm3TEUa6oKvEoV1aNbrwx6eYBmLFynC7hqP/h2ZRJjuyN2mO5smou+jUD4O40H8N770o4It6COY6Rv0014bYA2HtlpFGO22VJy35TfRa+GaN3j0/750sA2Dvll/z6v7eY6MqqaUYcEaOXdAkHwN1rqktw66YNR9nGxDeSALAv6tML5fW+3QBY/xD1+zlcQgVw96pqj1ONOmYVDgDubtVtnqfNcpQgIAD3AaeXAEgRDoD7w05nhfZlcvxO1/06VQXw/0P9GL5v93GM71w0AO5+MzleO1UFQIpwAJAiHACkCAcAKcIBQIpwAJAiHACkCAcAKcIBQIpwAJAiHACkCAcAKcIBQIpwAJAiHACkCAcAKcIBQIpwAJAiHACkCAcAKcIBQIpwAJAiHACkCAcAKcIBQIpwAJAiHACkCAcAKcIBQIpwAJAiHACkCAcAKcIBQIpwAJAiHACkCAcAKcIBQIpwAJAiHACkCAcAKcIBQIpwAJAiHACkCAcAKcIBQIpwAJAiHACkCAcAKcIBQIpwAJAiHACkCAcAKcIBQIpwAJAiHACkCAcAKcIBQIpwAJAiHACkCAcAKcIBQIpwAJAiHACkCAcAKcIBQIpwAJAiHACkCAcAKcIBQIpwAJAiHACkCAcAKcIBQIpwAJAiHACkCAcAKcIBQIpwAJAiHACkCAcAKcIBQIpwAJAiHACkCAcAKcIBQIpwAJAiHACkCAcAKcIBQIpwAJAiHACkCAcAKcIBQIpwAJAiHACkCAcAKcIBQIpwAJAiHACkCAcAKcIBQIpwAJAiHACkCAcAKcIBQIpwAJAiHACkCAcAKcIBQIpwAJAiHACkCAcAKcIBQIpwAJAiHACkCAcAKcIBQIpwAJAiHACkCAcAKcIBQIpwAJAiHACkCAcAKcIBQIpwAJAiHACkCAcAKcIBQIpwAJAiHACkCAcAKcIBQIpwAJAiHACkCAcAKcIBQIpwAJAiHACkCAcAKcIBQIpwAJAiHACkCAcAKcIBQIpwAJAiHACkCAcAKcIBQIpwAJAiHACkCAcAKcIBQIpwAJAiHACkCAcAKcIBQIpwAJAiHACkCAcAKcIBQIpwAJAiHACkCAcAKcIBQIpwAJAiHACkCAcAKcIBQIpwAJAiHACkCAcAKcIBQIpwAJAiHACkCAcAKcIBQIpwAJAiHACkCAcAKcIBQIpwAJAiHACkCAcAKcIBQIpwAJAiHACkCAcAKcIBQIpwAJAiHACkCAcAKcIBQIpwAJAiHACkCAcAKcIBQIpwAJAiHACkCAcAKcIBQIpwAJAiHACkCAcAKcIBQIpwAJAiHACkCAcAKcIBQIpwAJAiHACkCAcAKcIBQIpwAJAiHACkCAcAKcIBQIpwAJAiHACkCAcAKcIBQIpwAJAiHACkCAcAKcIBQIpwAJAiHACkCAcAKcIBQIpwAJAiHACkCAcAKcIBQIpwAJAiHACkCAcAKcIBQIpwAJAiHACkCAcAKcIBQIpwAJAiHACkCAcAKcIBQIpwAJAiHACkCAcAKcIBQIpwAJAiHACkCAcAKcIBQIpwAJAiHACkCAcAKcIBQIpwAJAiHACkzDIcvRluC4DZmtkxOhuO3tjz+gLA3W0mx+1JRhxCAXBvmCgi5jgASJlFOG5bql7PwATgXjNpOHo7PPa63e3r9ZXOnbs86ecCYELXr2+OvO71OpsxwznpaUYc4x+gu7W18av6Ci+88OIUmwdgEpcuXRl53elsvzG2ylQRmUU4uhHRiYheu/36z+orPPvsj6Ld3tzpewHYI9/+9gsjr7e2rv8yBsfpGB63JzarcPQionPlytnvR/Q6ZYVXXnktvvKVf57m8wGQcObMz98UjrW1V88OnpZf9MvziTQn+J5q8H2twTIXEfMRsbi93W4sLx9758LC8vGy8ssvvxKrq+346EffH63WJLsDYDfOnPl5PP3016PdvnHrvU7nxu8vXnzuH3u97lpEtCPiRkRsRsTWYOlGMiKTHMkbg6U5WEo4FiJifn39yquHDz/yJ41Gc6F8w09/eilOn/5xLC0diJWVpVhcXIhGo5pg1wDUtdubce7c5fja156Nr371X0aiERHx29+++I3V1csXImI9IjYGy42IuBkR24MlFY5Jjt5ltLEQEQciYikiliPiwYh4KCLetrLyvsdOnvzk39TjAcD+euONy9+7cOE/vhERr0fE1Yi4FhGrMYzIZvTD0bntRnYw6amq8VFHGXnMRcT85ub/bNy8uf6b5eVjj4gHwP67du3XP7h48T+/FRFrEXE9RkccW9EfcXRiOGm+a5OGo8xzjMejjEaaGxtX169d+9W5AwfevjI/v3SkqirnpgD22Pb25rUrV37yr5cvv/B89KNRwnE9+nMcm9GPxlb0o1EucNq1aWerdwpIa/C60elsbr3++vkL6+v/fTEithqNVquqGo2qajSFBGB63W5na3t7Y31j4+qvX3vtpR9euvRf/7629ptfRn+EUR9ttOPN8xslHCmTHrwbMbyiaiEiFiPigejPdSxFxKEYzn0sRcTBwTqLMbwaq5zumvazANxP6qODcvDfjv4IYjOGoVgbPK4Onq9GPx7lyqqtGE6Mp0YcrSk+fHew0zLauBn9mpWRR9EZfMADg6/Px2g4yqmvCPEAuJORP/MUwzmKrRheZrsR/TjURxwlFjdiOMroxoR3j08ajvrt6t3Bh65qS3m/VPDG4IdZjP4opZzSKhPtggGwO/Vjb7mhr0x2b8Zw1NGuPW7E8PRUfW5jItOGoxOjo4V6AEpQbkZ/tLEQ/dHG3GC/zRiGI0I8AHZjp3Bsx3Duoow66ksJSolG/c+PpE1zqqrssFz/Ox6NUrZy3m0+huEoE+r1cIxvA4BR9VNV5VTTdm25GcN4lMf6neL1OY23NBxl5FGed2tL+UHKvEaZUC/zIvXTWxHCAXAn4wf8csqpPkFezvTcrD0v0Zh6tBExXTgi3vwD1N8rP0gr+sUr4RgfbYgFQF59grsEoYw8tmJ0PqN+6e3U/5Nj2nDE4IM0xj5IfXK8xKJ+v0f9aqrxuREAbm+nK6vKYznudnZYejHlKapilgfs8RDUT0eVWOw00nCaCmB3xv/7asTo9MBOIan//42p/g9HsRcH6/pVUuMhGf9afX0Adqc+ahi/PaL+OP71mdjL3/J3mvS+3aW7AOSNj0B2epxZMIr9PHg7JQWwd3Y6jQUAAAAAAAAAAAAAAAAAAAAAMK3/BX4vwOY3EngcAAAAAElFTkSuQmCCCg==) no-repeat 0 -165px;
972}
973
974div.newRecordInnerInnerPanel {
975 background-color: white;
976 padding: 0px;
977 margin-left: 23px;
978 margin-right: 25px;
979}
980
981div#newRecordPanel h2 {
982 color: #666666;
983 font-size: 12pt;
984 font-weight: bold;
985 padding: 5px 10px;
986}
987
988div#newRecordPanel table#newRecordPanelDataTABLE {
989 width: 340px;
990 color: #999999;
991 padding-bottom: 5px;
992}
993
994div#newRecordPanel table td.newRecordPanelLabelTD {
995 padding-left: 10px;
996 padding-top: 3px;
997 font-size: 9pt;
998 width: 100px;
999}
1000
1001div#newRecordPanel table td.newRecordPanelLabelTD span {
1002 font-size: 8pt;
1003}
1004
1005div#newRecordPanel input {
1006 width: 100%;
1007}
1008
1009/*
1010div#newRecordPanel textarea {
1011 width: 100%;
1012 height: 50px;
1013}
1014*/
1015
1016div#newRecordPanelButtonsBox {
1017 border-top: 1px dotted #333366;
1018 padding-top: 5px;
1019}
1020
1021
1022div#newRecordPanelButtonsBox table#newRecordPanelButtonsBoxTABLE {
1023 width: 100%;
1024}
1025
1026div#newRecordPanelButtonsBox table tbody tr td.newRecordPanelButtonTD {
1027 padding-right: 10;
1028}
1029
1030/* @end */
1031
1032/* @end */
1033
1034/* @group Record detail */
1035
1036div.recordDetailDataBox {
1037 padding: 0px;
1038 padding-top: 5px;
1039 /* padding: 0px 0px 0px 10px;*/
1040}
1041
1042div#recordDetail {
1043 border-top: 4px solid #ddddff;
1044}
1045
1046div#recordDetail table.recordDetailDataBoxTABLE {
1047 width: 100%;
1048}
1049
1050div#recordDetail form table tbody {
1051 color: #35306b;
1052 font-size: 10pt;
1053}
1054
1055div.recordTitleBlock {
1056 color: #666666;
1057 padding: 8px;
1058 font-size: 12pt;
1059}
1060
1061div.recordTitleBlock h2 {
1062 color: #333366;
1063}
1064
1065form.processingRecordFORM div.recordTitleBlock {
1066 color: #444444;
1067 background-color: #ddddff;
1068 padding: 8px;
1069 /* margin-right: 8px;*/
1070 font-size: 12pt;
1071}
1072
1073form.recordDataForm div.recordTitleBlock {
1074 color: #444444;
1075 background-color: #ddddff;
1076 padding: 8px;
1077 font-size: 12pt;
1078
1079 /* margin-right: 8px;*/
1080}
1081
1082div.recordTitleBlock input {
1083 width: 100%;
1084}
1085
1086span.noteFieldLabel {
1087 display: block;
1088 color: #cccccc;
1089 font-size: 8pt;
1090}
1091
1092div.noteFieldContent {
1093 color: #666666;
1094 font-size: 8pt;
1095 padding: 3px 0px 5px 0px;
1096 /* border-bottom: 1px dotted #333366;*/
1097 margin-bottom: 5px;
1098}
1099
1100.resizable-textarea {
1101 /* width: 95%;*/
1102}
1103.resizable-textarea .grippie {
1104 height: 5px;
1105 /* background: #eee url(../images/grippie.png) no-repeat center 1px;*/
1106 background: #eee url(data:image/png;charset=utf-8;base64,iVBORw0KGgoAAAANSUhEUgAAABsAAAAFCAMAAACD1meMAAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAAGUExURbu7u////3iwjPUAAAACdFJOU/8A5bcwSgAAABRJREFUeNpiYMADGHEDBhroAwgwAA9QADeT0qnSAAAAAElFTkSuQmCCCg==) no-repeat center 1px;
1107 border: 1px solid #ddd;
1108 border-top-width: 0;
1109 cursor: s-resize;
1110}
1111
1112div.noteFieldContent textarea {
1113 /*margin-right: 10px;*/
1114 font-size: 8pt;
1115 width: 100%;
1116 height: 50px;
1117 /* color: #666666;*/
1118}
1119
1120div.noteFieldContent div.viewMode {
1121 /* max-height: 100px;*/
1122 overflow: auto;
1123}
1124
1125tr.recordFieldsTR {
1126 background-color: #ff9400; /* #ffc880 */
1127 }
1128
1129tr.recordFieldsTR td {
1130 padding: 2px 0px 1px 0px;
1131 color: white;
1132 font-size: 9pt;
1133 border-bottom: 6px solid white;
1134 /*border-left: 1px solid white; */
1135}
1136
1137 div.Clipperz_recordFieldLabel {
1138 color: #999999;
1139}
1140
1141div.Clipperz_recordFieldLabel input {
1142 font-size: 10pt;
1143 width: 100%;
1144 /* color: #666666;*/
1145}
1146
1147div.Clipperz_recordFieldData {
1148 color: #666666;
1149}
1150
1151div.Clipperz_recordFieldData a {
1152 color: #333366;
1153}
1154
1155div.Clipperz_recordFieldData input {
1156 font-size: 10pt;
1157 width: 100%;
1158 /* color: #666666;*/
1159}
1160
1161/*
1162td.removeFieldButton {
1163 padding-left: 10px;
1164}
1165*/
1166/*
1167div.addFieldButton {
1168 padding-left: 8px;
1169}
1170*/
1171
1172td.fieldTypeTD {
1173 width: 70px;
1174 color: #999999;
1175 white-space: nowrap;
1176 overflow: hidden;
1177 text-align: right;
1178}
1179
1180td.fieldTypeTD select {
1181 min-width: 68px;
1182 width: 68px;
1183 font-size: 10pt;
1184}
1185
1186table.recordDetailButtonsTABLE {
1187 width: 100%;
1188}
1189
1190/* @group Scrambled value */
1191
1192div.Clipperz_recordFieldData a.scrambleLink {
1193 display: block;
1194 text-align: left;
1195 font-size: 8pt;
1196 text-decoration: none;
1197 color: #ff9400;
1198}
1199
1200div.Clipperz_recordFieldData div.passwordBackground, div.passwordEntropy {
1201 /* background: url(../images/entropyBackground.gif) repeat-x 0 0;*/
1202 background: url(data:image/gif;charset=utf-8;base64,R0lGODlhAQCWAOYAABb8Ev9KAP81AP8hABvxAP86AP95AP9qAP8FAP8HAP9QAP9SAP9wAPCGAP8PAP9jAP8XAP9EAP88AP8+AP9UAP9bAP8bAP8JAP8tAP9WAAj6AAv5AP8rAP8fANSUAP8zANGWAMScAP9AAA/3AP8lADvhAF7PAOyIALGmAI23AC/nAJG2ADPlAHXDAOSMAEfbACfrAL2gAKGuAP8RAM2YAIW8AP9YAMiaAIG+AELdAHrBAGbLAP8ZAP99AD7fABfzAKWsAP9mAP9IAP9GAPuBAP8jAMGeAP9rAP9xAP9CAP8TAP8vADfjAP8VABT0AP9OAPiDAP8dAP9gAFbTAKmqAP9oAPSEAP9iANyQAJW0AJ2vAIq6AP8TEh/vALWkAP91AH6/AP9MAP84AP94AE7XAP82AP8LAP8oAP97AGLOANiSAG7HAP8wAFrRAP8DAOCOAP9tAP9zAP9aAP8nAP8NAGrJAOiKAHHGAFLVAJmyAK2nACPtALmiAErZAP9eACvpACH5BAAAAAAALAAAAAABAJYAAAeJgFxuCAkXZnQOM0pNEDwWUR0DRSRzZxwYS2wfAmViBRITIkkRQ0IBYU8KCxQZNnIVflJXD0FVB0dwDEhxX2MGaD1EUFYNJ3Yub1hqHiA0NyFGMXxeKHpUQDJaeVkrKVs1OGA6LXdrdTtpJm1TeGR9Lzk+JUwsKn8we10EP04jGxoAAgocSLBgwEAAOwo=) repeat-x 0 0;
1203}
1204
1205div.Clipperz_recordFieldData input.scrambledField {
1206 font-size: 1pt;
1207
1208 width: 71px;
1209 height: 16px;
1210 color: white;
1211 padding-top: 4px;
1212 border: 0px solid white;
1213 /* background: transparent url(../images/scrambledValue.png) no-repeat 0 0px;*/
1214 background: transparent url(data:image/png;charset=utf-8;base64,iVBORw0KGgoAAAANSUhEUgAAAEcAAAAgCAYAAABAQWX9AAAABGdBTUEAANbY1E9YMgAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAANXSURBVHja7FgxixNBFJ6TEyFXxEBiYWFEuCKHcEJio6RRIZAycF3qjWU67xcEr0par04Q7mA7hSAWErVyC1GTIiAmoMUlcHeFQblC53uZWTbJzmZ3cazmwUBm5+ObN9978zb7Nv5wY8Z87ZKRwIjz78SZTqes2+2ywWAQiqTX6xE+jOnkjoE/5OMgkjiTyYTZts3G43GoHRzHIXwY08kdA3/Mx/5acRDR2WymZBmNRoHz5ezwcunkjoF3AsT6ysepnGzKH1AbqufzeZZOp91N2+02PYc1m033eaPRIBzwcnOkM7BYr1QqrFQqaeeOiMdmBT5u8bHnEeJAZBHWn/LxZEGcbDZLKktnZYrCvBsnEgl6ViwWad17v2U6e0XQzR0DbwkhvLVGXq09IRzZxvL/HCjdarXcCFSrVdpcZYg+iqAUoV6vu4f0uz66uGPga6Igk4Z8vOIjFViQQQ7npdNyrjosIgYHECE5D3qT6OKOiHdE9qREtsi5+m0FMjicy+Uoqrir2ERV/TudDh3OsizCwzFg/QqkTu4Y+JqoN0d8PBMi7S8X65XMwf0EOQxFDIfJZDIr7HAEWImBM3DMD6ubOyL+VNQVFN1HQpgjb61R1hxj5vPBiGPE0WibL/tGBJM5Rpz/IM7P8ykbfuiyyThcz+Xb5x7hw5hO7hj46P2c2fmE9d/Z7OwkXM/lx9AhfBjTyR0Df1zeCdHPQUQvfqt7Lmcno8D5cnZ4uXRyx8BH7+dAbah+fTvPtpJpd9OPr9vs+3DOV37cdJ+/ed4gHPAXv+abI53BgfWd+xW2XShp546Id3imFPgb2refw9ccvrbaz7l6LctTfkqE3hSFuRvzCFy+Mm8B3LxdpIN577dMZ68Iurmj4vnhLSGEW2vk1eJri/2cF18Wv62g9Hu75abi7sMqba4yRB9FUIpwr1J3D+l3fXRxx8DXuCiHQpRw/ZzRpx45L52Wc9VhETE4gAjJubLnopE7Ip76N1yUFLIF12ltPwepDuUzN3IUVdxVbNJ/aysi1aHD3S1b7A7HwzFg/QqkTu4YeGSN28+BSKH6Obifuw/mPRcUMRwmkVzti8CRBMdKDJyBY1tJdT9HF3dEPPVzuCDr+znLNceY+Xww4hhxNNpfAQYAoVB5BoFW//8AAAAASUVORK5CYIIK) no-repeat 0 0px;
1215}
1216
1217div.Clipperz_recordFieldData input.scrambledField:focus {
1218 color: #b5d5ff;
1219 border: 0px solid white;
1220 /* background: transparent url(../images/scrambledValue.png) no-repeat 0 -16px;*/
1221 background: transparent url(data:image/png;charset=utf-8;base64,iVBORw0KGgoAAAANSUhEUgAAAEcAAAAgCAYAAABAQWX9AAAABGdBTUEAANbY1E9YMgAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAANXSURBVHja7FgxixNBFJ6TEyFXxEBiYWFEuCKHcEJio6RRIZAycF3qjWU67xcEr0par04Q7mA7hSAWErVyC1GTIiAmoMUlcHeFQblC53uZWTbJzmZ3cazmwUBm5+ObN9978zb7Nv5wY8Z87ZKRwIjz78SZTqes2+2ywWAQiqTX6xE+jOnkjoE/5OMgkjiTyYTZts3G43GoHRzHIXwY08kdA3/Mx/5acRDR2WymZBmNRoHz5ezwcunkjoF3AsT6ysepnGzKH1AbqufzeZZOp91N2+02PYc1m033eaPRIBzwcnOkM7BYr1QqrFQqaeeOiMdmBT5u8bHnEeJAZBHWn/LxZEGcbDZLKktnZYrCvBsnEgl6ViwWad17v2U6e0XQzR0DbwkhvLVGXq09IRzZxvL/HCjdarXcCFSrVdpcZYg+iqAUoV6vu4f0uz66uGPga6Igk4Z8vOIjFViQQQ7npdNyrjosIgYHECE5D3qT6OKOiHdE9qREtsi5+m0FMjicy+Uoqrir2ERV/TudDh3OsizCwzFg/QqkTu4Y+JqoN0d8PBMi7S8X65XMwf0EOQxFDIfJZDIr7HAEWImBM3DMD6ubOyL+VNQVFN1HQpgjb61R1hxj5vPBiGPE0WibL/tGBJM5Rpz/IM7P8ykbfuiyyThcz+Xb5x7hw5hO7hj46P2c2fmE9d/Z7OwkXM/lx9AhfBjTyR0Df1zeCdHPQUQvfqt7Lmcno8D5cnZ4uXRyx8BH7+dAbah+fTvPtpJpd9OPr9vs+3DOV37cdJ+/ed4gHPAXv+abI53BgfWd+xW2XShp546Id3imFPgb2refw9ccvrbaz7l6LctTfkqE3hSFuRvzCFy+Mm8B3LxdpIN577dMZ68Iurmj4vnhLSGEW2vk1eJri/2cF18Wv62g9Hu75abi7sMqba4yRB9FUIpwr1J3D+l3fXRxx8DXuCiHQpRw/ZzRpx45L52Wc9VhETE4gAjJubLnopE7Ip76N1yUFLIF12ltPwepDuUzN3IUVdxVbNJ/aysi1aHD3S1b7A7HwzFg/QqkTu4YeGSN28+BSKH6Obifuw/mPRcUMRwmkVzti8CRBMdKDJyBY1tJdT9HF3dEPPVzuCDr+znLNceY+Xww4hhxNNpfAQYAoVB5BoFW//8AAAAASUVORK5CYIIK) no-repeat 0 -16px;
1222}
1223
1224div.Clipperz_recordFieldData span.scrambledFieldLabel {
1225 display: block;
1226 color: #999999;
1227 font-size: 11px;
1228 padding-left: 10px;
1229}
1230
1231/*
1232div.passwordTooltip {
1233 position: absolute;
1234 padding: 30px 30px 30px 40px;
1235 font-size: 10pt;
1236 font-weight: bold;
1237 color: black;
1238 background: url(../images/tooltipBackground.png) no-repeat 0 -30px;
1239 width: 335px;
1240 height: 148px;
1241 z-index: 10000;
1242}
1243*/
1244/* @end */
1245
1246/* @group Editing mask */
1247
1248div#recordDetailEditModeHeaderMask {
1249 position: absolute;
1250 top: 0px;
1251 left: 0px;
1252 width: 100%;
1253 height: 119px;
1254 z-index: 20000;
1255 overflow: hidden;
1256/*
1257 border: 10px solid red;
1258*/
1259}
1260
1261div#recordDetailEditModeVerticalMask {
1262 width: 511px;
1263 position: absolute;
1264 top: 119px;
1265 left: 0px;
1266 z-index: 20000;
1267 overflow: hidden;
1268/*
1269 height: 100%;
1270 border: 10px solid red;
1271*/
1272}
1273
1274/* @end */
1275
1276/* @group Direct logins (record detail) */
1277
1278div.directLoginsRecordBox {
1279 margin: 10px 0px 10px 0px;
1280 border-top: 4px solid #ff9400; /* #ffc880 */
1281 border-bottom: 4px solid #ff9400; /* #ffc880 */
1282}
1283
1284div.directLoginsRecordBox textarea {
1285 color: #666666;
1286}
1287
1288div.recordDetailNoDirectLoginDescriptionBox {
1289 padding: 5px 5px 0px 5px;
1290}
1291div.directLoginsRecordBox p {
1292 font-size: 10pt;
1293 color: #999999;
1294 padding-bottom: 5px;
1295}
1296
1297div.directLoginDetailTitle a {
1298 color: #333366;
1299 font-size: 10pt;
1300 font-weight: normal;
1301}
1302
1303div.directLoginDetailTitle input {
1304 width: 100%;
1305}
1306
1307div.recordDetailDescriptionBox {
1308 padding: 10px 10px;
1309 color: #666666;
1310}
1311
1312div.recordDetailDescriptionBox h5 {
1313 padding: 10px 10px;
1314 padding: 5px 0px 10px 0px;
1315}
1316
1317div.recordDetailDescriptionBox p {
1318 color: #999999;
1319 padding-bottom: 10px;
1320}
1321
1322div.recordDetailDescriptionBox a {
1323 color: #333366;
1324}
1325
1326div.directLoginsRecordBox h3 {
1327 color: #666666;
1328 padding: 5px 0px 0px 5px;
1329 margin: 0px 0px 5px 0px;
1330 font-size: 12pt;
1331}
1332
1333div.directLoginsRecordBox span {
1334 color: #999999;
1335}
1336
1337table.directLoginBindings {
1338 width: auto;
1339 padding-top: 10px;
1340 padding-bottom: 5px;
1341}
1342
1343table.directLoginBindings td.directLoginBindingLabelTD {
1344 padding-right: 20px;
1345}
1346
1347table.directLoginBindings td.directLoginBindingLabelTD span {
1348 font-weight: bold;
1349 color: #bbbbbb;
1350}
1351
1352table.directLoginBindings td.directLoginBindingValueTD span{
1353 color: #999999;
1354}
1355
1356table.directLoginBindings td.directLoginDataLabelTD {
1357 padding-right: 20px;
1358}
1359
1360table.directLoginBindings td.directLoginDataLabelTD span {
1361 color: #bbbbbb;
1362}
1363
1364table.directLoginBindings td.directLoginDataValueTD span{
1365 color: #999999;
1366}
1367
1368div.directLoginsRecordBox ul {
1369}
1370
1371div.directLoginsRecordBox ul li {
1372 padding: 5px 0px 5px 0px;
1373 border-top: 1px dotted #ff9400;
1374}
1375
1376div.directLoginsRecordBox ul li span {
1377 font-size: 10pt;
1378 padding-left: 5px;
1379}
1380
1381div.directLoginsRecordBox ul li a.directLoginFavicon {
1382 width: 16px;
1383 height: 16px;
1384}
1385
1386div.directLoginsRecordBox div.addDirectLoginBox {
1387 border-top: 1px dotted #ff9400;
1388 padding: 5px 0px 10px 0px;
1389}
1390
1391div.directLoginsRecordBox div.addDirectLoginBox div.addDirectLoginBoxContent {
1392 padding-left: 35px;
1393}
1394
1395/*
1396div.directLoginsRecordBox div.addDirectLoginBox textarea {
1397 width: 80%;
1398 height: 50px;
1399 margin-left: 30px;
1400 margin-bottom: 10px;
1401}
1402*/
1403
1404div.directLoginsRecordBox div.addDirectLoginBox div {
1405 /* margin-left: 30px;*/
1406}
1407
1408/* @group toogle button */
1409
1410div.directLoginCollapseLink {
1411 display: inline-block;
1412 width: 15px;
1413 height: 15px;
1414 cursor: pointer;
1415 /* background: url(../images/directLogin/toggle.png) no-repeat;*/
1416 background: url(data:image/png;charset=utf-8;base64,iVBORw0KGgoAAAANSUhEUgAAAB4AAAAeCAIAAAC0Ujn1AAANIWlDQ1BJQ0MgUHJvZmlsZQAAeJyV13k0lG8bB/BrFsYyZhhjDyO7iLITskQi2feS7AwzMQkpS1KILKFoQWihKJGoqH5kSUghoajIkj1Llnn/kOr9nff3vue9/njO9dzPc859P885n+99bgC8miuVSkYCgH8ALdDSSI9k7+BIwnQCBnDAA1gQdnULouqam5vCP9Z8JyAAADrkXKlU8j+/9x8LF2jv4AiAkAUAotd6vxMAiIfWe2sAIB6lUWkACG8AILp5u7oDIMIBQDbQ2lIfAHEDAHBe630lAOAOrfcNAIALdvOiASC6ARgJAe4+AQCYcQBGbXePIDcAnCwAuLsHufkD4JIBwMzfn+IOgPsIAFJu1EAaAJ4JAOTsHRxJ60t2igdQ4gNgMvk9djQdoDwXQGrv7zHRBwDcrgB5ib/HZi0BAQAI7tYgT8XtAACAwOoBMPTT6bMSAJhUgNUUOn05j05fvQaA6gWoJbsdCQz++b8QiBaA/3W//s0/C4UAQAIgxBCFyDBUODqc4QRjJCaa6SSzAXMdy2nWM9g4trO4CnZvjhRCCmcq8TxXOnc6TyZvHT9FIHtTtuBloQbSEZG8zddEW8WPSRRKtkufkCna0ikXvfW2fM+209vvKX5QPqtSoTqgnqRRpTmklab9RGdUN0Pvmf7ErizDeqMZ46t7mkzm9+aZvdrXZt5m0W65Yn3L5q1tp12Xfbcj2umuc+/+vgP9Lh8OfjyEdXvo/tnji+eQ17D3V58RPy7yU/9vAROUSerU4enAmaA52tyR78HzRxdCFkOXwn4cWwlfOb4aIR35NhpxEhmDOoWOZTjNeAYTxxTPnMByljURm8R2DpeMT2FP5UgjnOdMJ2ZwZXJf4LnIm8WXzX9J4PKmK4JXhXKEc0l5Itc254sWiBWKX5e8IXlT6pZ0kUzRWDH5tuwduRL5UoW72+5tK9t+X6lcuUKlYv5BcKXqQ7UqjWrNRzse73ii9WStJqJW5+nOZ7rP9f7Sr0PXxdTvemHYYNRo3GTczNKc8NKkxfSVWSuu9VybebvFa8sOQkfqG6u31p02Xdxdmd127+x7HN/zv8/ude5z7t//QejD1Y8uAwcHRQbzPh367PbFfUh8qHDY86vXiPeo9OitMd9xv2/kCbmJO5MBU5Rp6sy2mXuzgXNB32nzyvMVC8GLIUuhP0KXNZarV46thq9prT2h0wEQokgccgrVjC5iSGMMx3gxWTPrsyixSmIl2XhxPHhedl4OLoIEpxRRjcuU+wBPEG8SXwl/s8CIIKeQirAX6YLIC1GEmJb4YYm7kpPSUjLkLdVyqK268ikKA9ulFWOVulRkVKlqdRo8miE7Xmpz61B2PtMT0z9m0G4oZBSy+7Hxksk2U4+96Wbt5jgLI8sQqwLrN7YsdjvtDztcdqx3mtwvfGCfS9jBPNe6QyPuXB46nvZeJ7xzfGp9+/yW/DkDtlAMqN6HwwOTg/Jo5Ucagt8fHQ2ZD0Md4wgnHZc9oRyxM9Ikal+008mDMR6nyLG004FnIuMi408mxJ1NTUxIyjp3MTkzJSX1Ulrq+Yz0Cxk3Mq9fuHPxRlZRdsmlR5cfXam7+jKnPbcjr+NaR/77gs+Fw9cHb3y5OXlrumiyeOL2zJ3JkrHS8bvD9wbKBu/3lLdXND6orXzwsKTqUnXqo8jH/k+cakxqdzyVeUZ4tvT8419Ndffr014ENlg1qjQJNNGbe17eb4l/5dgq2jrUVtZ+/PWuDlxH35uct76dip2rXS3dae/290j3zL6v6o3uM+kn9vd/uPkxaEBzED3Y9On85wNfJL+MD1UNR33dM8I10jeaP0YeVx5f+9Y4kTrpNCU2NT5dNhM+azRHmOv+XjBPWVBfRC2+WEr54bQsuvxtpWI1cs2Yzk2nA8BJRAgyDKWJqkIfZ9BhqGGMwpxiMmSqY45lOc0aj92DbWZLxCXik9j3sbdyJBNSOdOIaVzWXG+4M3gyeC/wZfFnC2RvuiToLNgndFU4h5Qrkrs5V/SaWL54gUSh5HWpG9I3ZXxkRrfcki2Wu731jnyJQum2u9vvKZYp3VeuUKlQrVALUVtUr9Ko0qze8UjrsfYJ7TWdmp21uk/1nuk/N4jZhd5VZ1hv9GJ3g3HjniaTBFOs6cu9LWav9rWaJ1uwW7RbvrbqsH5j02mbYcdt12Xf7fDOsccp21nAuXd/34EPLh8PfnTNPSRyaNDtk/tnjy+ehV4S6wniO+pXRJYlj/9bisz+SpHKULXQpbAfx5bDV46vnliLoEdBNPJXkmDOYOKY4hrj9ySwnsUmYpPYzuGT2VM4fmUJdybPBd6fWbLpzyzJG7zmli9aIFYocV1iI02KZW/L3dn6R5YolitVKD9QrVR9qFalXq35SPPxjifaNdp/5MiuesMXhg1GjbubjJtNXga/2txq1mbebv7aouP4W5lO2y677uge+feOvbH9ih/iBpQHz352H9IcThnxGfP9Rp6kTMfPOc6fW0pYtaTTAdb3PgAARhWAjC0AtlkAVnkAsVsAJF0AuG8AmLMBWKsDkkEIkFpUQOzR2tg/AAHsIAhbQQ8cIAiSoRQWESSECSIEcQPxCjGMxCONkFHIx8gVlBYqClWPWkGLoB3QhejvDIYMpxhKGCYZjRhzGYcwXBhnzGMmDJM6UwzTGLMGM4W5lkWOJZKlkhXHGsX6DkvEBmC/su1iO8k2gHPFPcOj8J74cXYL9gz2VY44jhmCBqGAU5WzgHOS6EJc4PLhquDewv2Cx5MXw3uLT5zvKN8c/2UBI4HZTTmCYoLhQgihcmFfkgipR+T85s2bI0Xxoq1iKeI2EvwSg5JFUvpSN6X1ZDhkBraUyZ6Wc96qKI+VH1b4a1ve9mhFdyUjZVkVTpUV1SG1THWceq1GqWbujvNaZ7QjdI7uPKxL1vPR9zbw3uVnGGBE233MOGbPOZNs05t7K80a9/WaT1tirISs1WysbKl2SfZ3HNocZ51592sf8HRJPljt+tWNx93II9Sz2IfX19wvnlwXgKToUqMOPw9ipJkcSQ0RC6WEPQpnOe54ojiCHmUdgzzlHPvgDGfc4fj2xPSkpWSXlPo0+fNZmUEXPmVZZddduZMjnnv5Gk8h+/Wkm7hb525nlgiW5t+TKzeoaK90fTj9mOdJca3ec1odvr64YU9zfIvcq/a24I76t9Quge6GXom+7g/xAzqfi4fcvwqP9HyzneSe6prJmnNZGF8qX46g89LpAIAEFuABadABezgC6VAJ/QgMQgHhgkhC1CBmkTJIF2QW8g0Kj9qLOotqQbOh96HT0e8ZSAw+DKUMi4z6jOcY32HEMUcwz5kITO5MlcyszM7Md1jQLAdY7rOysLqx1mC5sFRsC5sMWyLbOM4UV4Jnw1Pwnew72fM5cBzBHO8JhoS7nCTOVM41YhDxG5cv1yg3mXuGh8YzzxvGh+A7y8/Pf0tAXaB+k+2mEcFIIT6hCmEL4VFSrIiESMPmAFEe0SdibuJY8acSAZLCkq+l4qT1pFdlqreEy2rJLsjVbD0jb60gojC5rWZ7iqKvkoGykPKyylvVh2qX1aM0vDTtdmhpyWuL6BB2onVRujN60/qTBmO7hgxnjcZ2f9+DNCGa8uzdZqa9b5+5pYWfZahVtvU9m5e27+1WHIiO8k5mzof3XzxQ5zLsynxIwc3bPcujxnPKW9rHwzfT762/QIANJZv6NVAqKJjWGCx4NCikKUz0WFL46AmHiIYoleiCGMKppNOEMxnxvAnZicpJr5I9Un6kJaarZny5cCXL95LNFekchtzxa88Kyq9fvBlb5HbbucTwrlqZUvnWB3IPparFH0vVKDzVeb67zuIFufFwc0pLTuuj9v4Oeqdwt1aPe29Cf9XH8U98X/SGI0dujH2e4J/ynLkyN7QgtRSwXLGGoNMBgBHYQRD0wAGSoRReb9jfcL+uHo1HO6C/MxgyZP30voZxZhJmimEaY7ZmrmWRY7nEimONYl3ABmC/srnjXHGf8J74cfYg9lWOOAI3oYBTlbOJ6EJc4Er+ZdqMb+6nZ3MhhFD5T8sW65J/Og6W1vvT8G/BP/2+Vq/VKP1t97fcf3b739R6Dfjw+pr/XW1wz9/dRt/6U+7Z7b/lZjBu2L2svqE3P23DbzFhQ3BZ5Ybh6pPrip/2bDhuHGmOf/lXS8ar9rbg14Id9W+pnaVdsd0NPcG9En1+/QYf4gd0Bk9/OvS5+Mv8UMdX4RG/UeMxqXHMN9uJwsnYKa/p3TMys6yzE3Nt38vmMxasF8YXY5b0fkj+GFqOWOFdubLKsRqzurCWT0+g0wHWz0sAAMCiTyFTAkmm+gb/52Hvf5U/+cjGHEgAwHoE2FgBAAEApHxoxtYAQAQADdAHCpCBAoFAAlPQB4OfVxK4/XriA7B+lgMAYGQHuGQHAFCzeCzy7/PSPEJoAAD6FGpooI+XN42kS6WSPUj6FH/qEZpHoCzJOMBtqyxpu4KCMgDAvwBJl//fxucdgAAAAAlwSFlzAAALEwAACxMBAJqcGAAAAflJREFUSIlj/P//PwNtABONzB01mjij50gwXJnFQCh6PV2rVq04+PfvP1KM/v6S4Xg1w0oThjeX8Bj97u3n6VO3hAW1nD93B6sCRiyJbzIjAwMDAzM7AyMLg04ag2UbAwsHpk5zo1wIg4ODzcJKs6Q8VESEj5GREa+rIeDvT4Y/XxmuzmaYzonH7QwMDD9+/Dpy6IqPe83r1x+RxVnwa2NgYGAQMyGohI2NRUxcgJ2dlTij2QUZmNkZnOcxKHjiMZSdnZWFhTmvMMAvwJKJCSUMcBjNysOgk8ZgVs/Agi802DlYPb1Ms/P8+fi4sEj/xwQHcv6/uYJFHBV0day8efMxHgXYUgiVwPDJ6CPaaNR0/foiwwoDLKrCTjGIm8J5Hz9+dXeqxExaZZVhwaG2cC6qq0X1GcRNGZjYECJMLAyCWgxixsiq+Pm545NceXlRsgkHB5utvS6yCEaAOM9jYEIqCpjYGVzmMzCiK0tMdmdjQ/iYh4czNcNLTEwAr9HCOgxayQysPAwMDAws3AyqoQwSZuhqGBg4ONiqaiO5uNghXF4+rogoBzQ12KLRshUaJkzMDDa9WBQwMDAwMNjY6ejoKrKwMHNwsNU1RrOwMBNhNBsPg9NsBgYGBtuJDBxCuIxmYGCorov88+evjq6CkbEqpuxoGTIsjAYAPTy7g/tBa3gAAAAASUVORK5CYIIK) no-repeat;
1417 overflow: hidden;
1418}
1419
1420div.directLoginCollapseLink.collapser-collapsed {
1421 background-position: 0px 0px;
1422}
1423
1424/*div.directLoginCollapseLink.collapser-collapsed.hover {*/
1425div.directLoginCollapseLink.hover {
1426 background-position: -13px 0px;
1427}
1428
1429div.directLoginCollapseLink.collapser-expanded {
1430 background-position: 0px -13px;
1431}
1432
1433div.directLoginCollapseLink.collapser-expanded.hover {
1434 background-position: -13px -13px;
1435}
1436
1437/* @end */
1438
1439/* @end */
1440
1441/* @end */
1442
1443/* @group Record creation wizard */
1444
1445div.recordCreationWizard {
1446 padding: 10px;
1447}
1448
1449div.recordCreationWizardTitleBox {
1450 padding-bottom: 5px;
1451 border-bottom: 1px solid #ff9400;
1452 margin-bottom: 10px;
1453}
1454
1455div.recordCreationWizardTitleBox h5 {
1456 padding: 5px;
1457 color: #666666;
1458 font-size: 13pt;
1459}
1460
1461div.recordCreationWizardTitleBox p {
1462 padding: 5px;
1463 font-size: 10pt;
1464 color: #999999;
1465}
1466
1467/*
1468div.recordCreationWizard ul {
1469 padding: 5px;
1470 list-style-type: none;
1471 list-style-position: outside;
1472}
1473
1474div.recordCreationWizard ul li h4 {
1475 font-size: 11pt;
1476 font-weight: bold;
1477 color: #ff9400;
1478 text-decoration: none;
1479 padding-bottom: 2px;
1480 cursor: pointer;
1481}
1482
1483div.recordCreationWizard ul li table tr td {
1484 font-size: 9pt;
1485 color: #999999;
1486 padding-left: 5px;
1487 padding-bottom: 10px;
1488}
1489*/
1490
1491div.newRecordWizardHeader {
1492 margin-top: 10px;
1493 border-top: 3px double #ff9400;
1494 padding-top: 5px;
1495}
1496
1497div.newRecordWizardFooter {
1498 border-top: 1px solid #ff9400;
1499 padding-top: 5px;
1500 padding-bottom: 5px;
1501 border-bottom: 3px double #ff9400;
1502}
1503
1504/*
1505div.recordCreationWizard ul li table input {
1506 margin-top: 3px;
1507}
1508*/
1509
1510/* @end */
1511
1512/* @end */
1513
1514/* @group Account page */
1515
1516div#changePassphraseBlock form table.panelBody tbody tr td {
1517 vertical-align: top;
1518 height: 25px
1519}
1520
1521div#changePassphraseBlock form table.panelBody tbody tr td span.formLabel {
1522 line-height: 20px;
1523}
1524
1525div.panelBody form table.panelBody {
1526 padding: 10px;
1527 color: #999999;
1528 font-size: 10pt;
1529 line-height: 9pt;
1530}
1531
1532div.panelBody form table.panelBody span.formLabel {
1533 padding-right: 5px;
1534}
1535
1536div.panelBody form table.panelBody tbody tr td input[type=text] {
1537 width: 250px;
1538}
1539
1540div.panelBody form table.panelBody tbody tr td input[type=password] {
1541 width: 250px;
1542}
1543
1544div.panelBody form table.panelBody tbody tr td input {
1545 margin-right: 10px;
1546}
1547
1548div#deleteAccountBlock {
1549 height: 200px;
1550 min-height: 200px;
1551}
1552
1553
1554/* @end */
1555
1556/* @group Tools page */
1557
1558/* @group Bookmarklet */
1559
1560a.bookmarkletLink {
1561 display: block;
1562 margin: 0px 0px 0px 35px;
1563 padding: 15px;
1564 color: #333366;
1565 font-weight: bold;
1566 border: 1px dotted #6666aa;
1567 width: 200px;
1568 text-align: center;
1569}
1570
1571div.bookmarkletConfiguration {
1572 padding-bottom: 10px;
1573}
1574
1575div.bookmarkletConfiguration p {
1576 color: #666666;
1577 display: block;
1578 padding-top: 5px;
1579 font-weight: bold;
1580}
1581
1582div.bookmarkletConfiguration textarea {
1583 color: #666666;
1584 font-size: 8pt;
1585 width: 300px;
1586 height: 100px;
1587}
1588
1589
1590
1591/* @end */
1592
1593/* @group Compact link */
1594
1595div#compactLinkBox a {
1596 display: block;
1597 margin: 10px 0px 10px 0px;
1598 padding: 15px;
1599 color: #333366;
1600 font-weight: bold;
1601 border: 1px dotted #6666aa;
1602 width: 200px;
1603 text-align: center;
1604 font-size: 12pt;
1605}
1606
1607
1608
1609/* @end */
1610
1611/* @end */
1612
1613/* @group Exit */
1614/*
1615div#exitBlock {
1616 padding: 10px 30px;
1617 width: 60%;
1618 color: #999999;
1619}
1620
1621div#exitBlock h2 {
1622 padding-bottom: 5px;
1623}
1624
1625div#exitBlock h3 {
1626 padding-top: 20px;
1627 padding-bottom: 5px;
1628}
1629
1630div#exitBlock ul li ul {
1631 padding-left: 20px;
1632 list-style-type: disc;
1633}
1634
1635div#exitBlock ul li ul li {
1636 color: #ff9400;
1637 padding-bottom: 5px;
1638}
1639
1640div#exitBlock ul li ul li span {
1641 color: #999999;
1642}
1643*/
1644/* @end */
1645
1646/* @end */
1647
1648/* @group Yui-Ext customization */
1649
1650div.ydlg-dlg-body {
1651 background-color: white;
1652}
1653
1654/* @group Splash dialog */
1655div#alert div.ydlg-dlg-body {
1656 background-color: white;
1657}
1658
1659div#splashMessage {
1660 /*border: 4px solid #ff9400;*/
1661 /*border-bottom: 1px solid #ff9400; */
1662 padding: 10px;
1663 color: #666666;
1664 background-color: white;
1665}
1666
1667div#splashMessage p {
1668 margin-bottom: 0px;
1669 font-weight: normal;
1670}
1671
1672div#splashMessage p a {
1673 color: #333366;
1674}
1675
1676div#splashMessage ul {
1677 list-style-type: disc;
1678 list-style-position: outside;
1679 padding-bottom: 10px;
1680}
1681
1682div#splashMessage ul li {
1683 margin-left: 20px;
1684 padding-bottom: 5px;
1685 color: #ff9400;
1686}
1687
1688div#splashMessage ul li p {
1689 display: inline;
1690 font-size: 10pt;
1691 color: #999999;
1692}
1693
1694/* @end */
1695
1696/* @end */
1697
1698/* @group subMenu */
1699
1700ul.subMenu {
1701 width: 200px;
1702 min-width: 200px;
1703 max-width: 200px;
1704
1705 color: #35306b;
1706 padding-top: 10px;
1707}
1708
1709ul.subMenu li {
1710 padding: 5px 10px 5px 10px;
1711 cursor: pointer;
1712 border: 1px solid white;
1713 font-size: 10pt;
1714}
1715
1716ul.subMenu li.hover {
1717 border: 1px dotted #ff9400;
1718}
1719
1720ul.subMenu li.selectedTab {
1721 background-color: #ff9400;
1722 border: 1px solid #ff9400;
1723 color: white;
1724}
1725
1726/* @end */
1727
1728/* @group tabPanels */
1729
1730li.hiddenPanel {
1731 display: none;
1732}
1733
1734div.clipperzSubPanel {
1735 color: #35306b;
1736 padding-left: 10px;
1737 border-left: 4px solid #ff9400;
1738 min-height: 200px;
1739}
1740
1741div.clipperzSubPanel span.read-only {
1742 /* background-image: url(../images/read-only_background.png);*/
1743 display: block;
1744 color: #666666;
1745 padding: 10px;
1746 font-weight: bold;
1747}
1748
1749div.clipperzSubPanel h5 {
1750 border-bottom: 1px dotted #ff9400;
1751 padding: 10px;
1752 color: #666666;
1753}
1754
1755div.clipperzLoginForm form h5.errorMessage {
1756 margin: 0px 20px;
1757 padding: 10px 10px;
1758 color: #ff9400;
1759 border-bottom: 1px dotted #ff9400;
1760 font-size: 12pt;
1761}
1762
1763div.panelBody form h5.errorMessage {
1764 color: #ff9400;
1765}
1766
1767div.clipperzSubPanel div.clipperzSubPanelButtonBox {
1768 border-top: 1px dotted #ff9400;
1769 padding: 10px;
1770}
1771
1772a#printingLink, a#offlineCopyLink, a#exportLink {
1773 color: #333366;
1774 font-weight: bold;
1775 padding: 10px 10px 10px 10px;
1776}
1777/*
1778div.clipperzSubPanel a {
1779 color: #333366;
1780 font-weight: bold;
1781 padding: 100px;
1782}
1783*/
1784
1785tr.openPreferenceBlock div.preferenceBlockTitle {
1786 padding: 10px 0px 0px;
1787}
1788
1789tr.openPreferenceBlock div.panelDescription p {
1790 padding-bottom: 0px;
1791}
1792
1793
1794div.preferenceBlockTitle {
1795 padding-bottom: 8px;
1796 font-weight: bold;
1797 color: #999999;
1798}
1799
1800div.panelDescription {
1801 max-width: 450px;
1802 padding: 10px;
1803 font-size: 10pt;
1804 color: #999999;
1805}
1806
1807div.panelDescription h3 {
1808 font-size: 12pt;
1809 color: #666666;
1810 padding-top: 20px;
1811 padding-bottom: 4px;
1812}
1813
1814div.panelDescription h5 {
1815 padding-left: 0px;
1816 border-bottom: 0px;
1817}
1818
1819div.panelDescription h5 a {
1820 color: #333366;
1821 text-decoration: none;
1822}
1823
1824div.panelDescription h5 a:hover {
1825 text-decoration: underline;
1826}
1827
1828div.panelDescription ol {
1829 padding-left: 25px;
1830 list-style-position: outside;
1831 list-style-type: decimal;
1832 color: #ff9400;
1833}
1834
1835div.panelDescription ol li {
1836 padding-bottom: 4px;
1837}
1838
1839div.panelDescription ol li p {
1840 display: inline;
1841 color: #999999;
1842}
1843
1844
1845div.panelDescription p {
1846 padding-bottom: 10px;
1847}
1848
1849div.panelDescription p a {
1850 color: #333366;
1851 text-decoration: none;
1852}
1853
1854div.panelDescription p a:hover {
1855 text-decoration: underline;
1856}
1857
1858/* @group SubSubTabs */
1859ul.subSubMenu {
1860 padding-left: 10px;
1861 padding-bottom: 3px;
1862}
1863
1864ul.subSubMenu li {
1865 font-size: 10pt;
1866 color: #666666;
1867 display: inline;
1868 padding: 3px 10px;
1869 cursor: pointer;
1870}
1871
1872ul.subSubMenu li.selectedTab {
1873 color: white;
1874 background-color: #333366;
1875 cursor: default;
1876}
1877
1878
1879
1880/* @end */
1881
1882/* @end */
1883
1884/* @group Footer */
1885
1886div#footer {
1887 margin-top: 20px;
1888 border-top: 1px solid #999999;
1889 padding: 5px;
1890 color: #666666;
1891 text-align: center;
1892 font-size: 8pt;
1893}
1894
1895div#footer a {
1896 color: #333366;
1897}
1898
1899div#rss {
1900 display: inline;
1901 float: right;
1902}
1903
1904div#rss a {
1905 vertical-align: middle;
1906}
1907
1908/* @end */
1909
1910/* @group Main */
1911
1912div#main h3.loading {
1913 padding: 20px;
1914 color: #666666;
1915}
1916
1917div#javaScriptAlert {
1918 margin: 20px;
1919 border: 4px solid #ff9403;
1920 padding: 15px;
1921 /* width: 70%;*/
1922 max-width: 400px;
1923 color: #999999;
1924 font-size: 12pt;
1925}
1926
1927div#javaScriptAlert h1 {
1928 color: #ff9403;
1929 font-size: 28pt;
1930 padding-bottom: 10px;
1931}
1932
1933div#javaScriptAlert h3 {
1934 color: #333366;
1935 padding-top: 10px;
1936 padding-bottom: 10px;
1937 font-size: 16pt;
1938}
1939
1940div#javaScriptAlert h5 {
1941 color: #666666;
1942 font-size: 12pt;
1943}
1944
1945input:focus {
1946 background-color: #ffeac0;
1947}
1948
1949textarea:focus {
1950 background-color: #ffeac0;
1951}
1952
1953/* @end */
1954
1955/* @group Lock */
1956
1957div#lockMessage {
1958 color: #666666;
1959 font-size: 10pt;
1960}
1961
1962div#lockMessage p {
1963 padding-bottom: 15px;
1964}
1965
1966div#lockMessage form input {
1967 width: 100%;
1968}
1969/* @end */
1970
1971/* @group Password entropy display */
1972
1973div.passwordEntropy {
1974 margin-top: 0px;
1975 margin-bottom: 4px;
1976 height: 3px;
1977 font-size: 1pt;
1978 /* background: url(../images/entropyBackground.gif) repeat-x 0 0;*/
1979 line-height: 3px;
1980}
1981
1982/* @end */
1983
1984
1985div#miscLinks ul li a.highlightedHeader {
1986/*
1987 color: white;
1988 font-size: 12pt;
1989 font-weight: bold;
1990*/
1991}
1992
1993/* @group Donate */
1994
1995a#donateHeaderLink.highlightedHeader {
1996 font-weight: bold;
1997}
1998
1999img#donateHeaderIcon {
2000 padding-top: 5px;
2001 margin-bottom: -5px;
2002}
2003
2004div#miscLinks ul {
2005 display: inline;
2006}
2007
2008/* @group Donate Splash */
2009
2010div#donateMessage {
2011 margin-left: 5px;
2012}
2013
2014div#donateMessage div.donateSplashPanelIcon {
2015 float: left;
2016 text-align: center;
2017 width: 100px;
2018 height: 70px;
2019}
2020
2021div#donateMessage div.donateSplashPanelDescription {
2022 font-size: 11pt;
2023
2024 color: #666666;
2025 line-height: 23px;
2026}
2027
2028div#donateMessage div.donateSplashPanelDescription ul {
2029 color: #aaaaaa;
2030 padding-left: 5;
2031 margin-bottom: 5px;
2032 list-style-type: disc;
2033 list-style-position: inside;
2034}
2035
2036div#donateMessage div.donateSplashPanelDescription ul li p {
2037 display: inline;
2038 color: #666666;
2039}
2040
2041div#donateMessage div.donateSplashPanelDescription a {
2042 text-decoration: none;
2043 color: #333366;
2044}
2045
2046div#donateMessage div a:hover {
2047 text-decoration: underline;
2048}
2049
2050div#donateSplash div.ydlg-dlg-body div.ydlg-ft {
2051 padding-right: 130px;
2052}
2053
2054/* @end */
2055
2056
2057/* @end */
2058
2059/* @group Password Generator */
2060
2061div.Clipperz_PasswordGenerator_button {
2062 /* background: url(../images/passwordAssistant.png) 0 22px;*/
2063 background: url(data:image/png;charset=utf-8;base64,iVBORw0KGgoAAAANSUhEUgAAABsAAAAuCAMAAADuvZJ5AAACZFBMVEX///8APHTHyc4zM2bAwsn+/v/6+vrW2N/z9fjw8vX5/P329/ra3OH92InllwD4sjDd3+T+/v7/8M/3+Pnd3uL80nklV4P3+vwWTX7r7fLj5+v19vng4ujo6u9cXYW7vcuVlq56laiPkKtcXISpqr+EhaP09fnNz9fy9Pd9mar8ymnP0dmNjqmBgqHZ2+FniKDf4en6wVD8znFVfaJFRnR7lan5ukH+3ZX6xFnO0Nnn6e/09PCAgaH7x2H29vNtbpJXWIHw8/Z1dpfz9PjU1uCNnqHf4eiwscX29vTl5+319fF/f5/a3OLy8u5qi6Jmh6D2+fuHiKVsjKT09fji5Ov9/fzX2uLx8ew4OGr3+vv4tTXd3+WtrsP09O9gYIjy8u380nq/wdBmZoxWVoD7ymrz8+5VVoBYWYI7O2y+wM3u3K16fJw5OWo9PW6Ula+oqb/Z2+Dq7PFVVYC8vs4+Pm79249sbpGvsMTw8OtKcZP8znLttUf4szDr6OL6ukH6wFD+35rq6OH29vLs6+bv6NK/x8rs6+T5vUnt6ub5vUjs6+Xg3dTr6OH91YL+/v394Jv7yGCjrrRIbpDo5d+xt7bz8e7Az93x8Or47dPm493V3+i/ztvp5uDq5+Dm49y2vb3l4tvv7ujb1836+vn91YH4+PeEhnH4tDXk4tnk4tr5tzv7z3L6xFjt7OX4+Pb7+/rx8Ov5uDvvtUnw7urw7+n80Xro5d7n5N3u7eb6wFH6vkn5tzr4tzv6vUn19PL29PL19fK/ztzu7ef6w1jw8Orr6uPr6+X5ukLi39aDhG/5tDX6x2HHdGeUAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAeRJREFUOMtjYGPADdgYFMUYMYGEPkhO0bVFCBPMcDUFyollifJiAtEsMaAcY4MoKyYQ7WcEyZmLckGAeCSXuHiAoziILWoOlisV5YYAaTVp52BubjVpIFu0FCzHK8oBAxocHJ5WYJYoL1iuV5QTDly8ixwC3YAM0SVguYQEScnC4vzyGBV3lWRmIJAzkJQU3QqWMzKSlVXNYYYBE5uSvBDZ1VVgOa0UKak0uBSzvVR2WZhUihZYznaCjEyik5Kuqk5cBFAuNylDKVrmtC1Y7rCFABT4ZKaD7bMUEFhjAZarN+SBAj0edQVlZQVtngKenYZgufZd7EhAXh5M7e0Ey9UdZ8EEZmZguY2rmDDBnt1AOQbGU1EimCBqOUhOYhM/FlBTLQGU81/Ghw2c9AOlGE2s6SWIAT8gPw0aT8OiZZYxOA0eFMQC+maD02BoKJY0uH4/OMzYFmNJg/s2g+WWrsOSBqd2gOU8PLCkwQ21YDk7OyxpcHoPWK7pAJY0uGUuWM7LC0saXDgHLGdtjSUNHpoMlouNxZIGd2wDy6WmYkmDa7eD5Xx9saTBrplgufh4LGmwbR5YLjwcSxo8ugAsV3EESxpsXAFOg83HsMit7AanwdYTWOQWzQenwcqJwphgyiTy0yAAb2mGoAo92xQAAAAASUVORK5CYIIK) 0 22px;
2064 width: 27px;
2065 height: 22px;
2066}
2067
2068div.Clipperz_PasswordGenerator_button.hover {
2069 /* background: url(../images/passwordAssistant.png) 0 -1px;*/
2070 background: url(data:image/png;charset=utf-8;base64,iVBORw0KGgoAAAANSUhEUgAAABsAAAAuCAMAAADuvZJ5AAACZFBMVEX///8APHTHyc4zM2bAwsn+/v/6+vrW2N/z9fjw8vX5/P329/ra3OH92InllwD4sjDd3+T+/v7/8M/3+Pnd3uL80nklV4P3+vwWTX7r7fLj5+v19vng4ujo6u9cXYW7vcuVlq56laiPkKtcXISpqr+EhaP09fnNz9fy9Pd9mar8ymnP0dmNjqmBgqHZ2+FniKDf4en6wVD8znFVfaJFRnR7lan5ukH+3ZX6xFnO0Nnn6e/09PCAgaH7x2H29vNtbpJXWIHw8/Z1dpfz9PjU1uCNnqHf4eiwscX29vTl5+319fF/f5/a3OLy8u5qi6Jmh6D2+fuHiKVsjKT09fji5Ov9/fzX2uLx8ew4OGr3+vv4tTXd3+WtrsP09O9gYIjy8u380nq/wdBmZoxWVoD7ymrz8+5VVoBYWYI7O2y+wM3u3K16fJw5OWo9PW6Ula+oqb/Z2+Dq7PFVVYC8vs4+Pm79249sbpGvsMTw8OtKcZP8znLttUf4szDr6OL6ukH6wFD+35rq6OH29vLs6+bv6NK/x8rs6+T5vUnt6ub5vUjs6+Xg3dTr6OH91YL+/v394Jv7yGCjrrRIbpDo5d+xt7bz8e7Az93x8Or47dPm493V3+i/ztvp5uDq5+Dm49y2vb3l4tvv7ujb1836+vn91YH4+PeEhnH4tDXk4tnk4tr5tzv7z3L6xFjt7OX4+Pb7+/rx8Ov5uDvvtUnw7urw7+n80Xro5d7n5N3u7eb6wFH6vkn5tzr4tzv6vUn19PL29PL19fK/ztzu7ef6w1jw8Orr6uPr6+X5ukLi39aDhG/5tDX6x2HHdGeUAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAeRJREFUOMtjYGPADdgYFMUYMYGEPkhO0bVFCBPMcDUFyollifJiAtEsMaAcY4MoKyYQ7WcEyZmLckGAeCSXuHiAoziILWoOlisV5YYAaTVp52BubjVpIFu0FCzHK8oBAxocHJ5WYJYoL1iuV5QTDly8ixwC3YAM0SVguYQEScnC4vzyGBV3lWRmIJAzkJQU3QqWMzKSlVXNYYYBE5uSvBDZ1VVgOa0UKak0uBSzvVR2WZhUihZYznaCjEyik5Kuqk5cBFAuNylDKVrmtC1Y7rCFABT4ZKaD7bMUEFhjAZarN+SBAj0edQVlZQVtngKenYZgufZd7EhAXh5M7e0Ey9UdZ8EEZmZguY2rmDDBnt1AOQbGU1EimCBqOUhOYhM/FlBTLQGU81/Ghw2c9AOlGE2s6SWIAT8gPw0aT8OiZZYxOA0eFMQC+maD02BoKJY0uH4/OMzYFmNJg/s2g+WWrsOSBqd2gOU8PLCkwQ21YDk7OyxpcHoPWK7pAJY0uGUuWM7LC0saXDgHLGdtjSUNHpoMlouNxZIGd2wDy6WmYkmDa7eD5Xx9saTBrplgufh4LGmwbR5YLjwcSxo8ugAsV3EESxpsXAFOg83HsMit7AanwdYTWOQWzQenwcqJwphgyiTy0yAAb2mGoAo92xQAAAAASUVORK5CYIIK) 0 -1px;
2071}
2072
2073table tbody tr td span.passwordGeneratorLength {
2074 padding: 0px;
2075 margin: 0px;
2076}
2077
2078table tbody tr td span.passwordGeneratorLength span {
2079 padding: 0px;
2080 margin: 0px;
2081 color: #bbbbbb;
2082 font-size: 9pt;
2083}
2084
2085span.passwordGeneratorLength span.passwordGeneratorLengthValue {
2086 padding-left: 3px;
2087 font-weight: bold;
2088}
2089
2090div#passwordGenerator div.ydlg-bd {
2091 overflow: hidden;
2092}
2093
2094form.passwordGenerator input.clipperz_passwordGenerator_password {
2095 width: 95%;
2096}
2097
2098form.passwordGenerator table {
2099 width: 95%;
2100}
2101
2102form.passwordGenerator table > tbody > tr > td {
2103 white-space: nowrap;
2104}
2105
2106form.passwordGenerator td span {
2107 padding-left: 3px;
2108 padding-right: 10px;
2109 font-size: 9pt;
2110 color: #666666;
2111}
2112
2113/* @end */
2114
2115/* @group IE Read-only header */
2116
2117div#logoFrame a {
2118 text-decoration: none;
2119}
2120
2121div#logoFrame a span {
2122 font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
2123 font-weight: bold;
2124 font-size: 24pt;
2125 padding-top: 10px;
2126 padding-left: 10px;
2127}
2128span.clipperzLogoSpan {
2129 color: white;
2130}
2131
2132div#logoFrame a span span.clipperzLogoZSpan {
2133 padding-left: 0px;
2134 color: #ff9400;
2135}
2136
2137
2138/* @end */
2139
2140span.activeText {
2141 cursor: pointer;
2142}
2143
2144/* @group LoginInfo */
2145
2146/* @group login panel */
2147
2148div#loginInfoWrapper {
2149 margin-left: 10px;
2150}
2151
2152div#loginInfo {
2153 padding: 0px;
2154 margin: 0px;
2155 border: 0px;
2156 width: 389px;
2157 background: url(../images/loginInfoBackground.png) repeat-y -405px 0;
2158}
2159
2160div#loginInfo div.header {
2161 background: url(../images/loginInfoBackground.png) no-repeat 0 0;
2162 min-height: 20px;
2163 height: 20px;
2164}
2165
2166div#loginInfo div.footer {
2167 background: url(../images/loginInfoBackground.png) 389px -5px;
2168 min-height: 20px;
2169 height: 20px;
2170}
2171
2172div#loginInfo div.content {
2173 padding-left: 20px;
2174 padding-right: 25px;
2175}
2176
2177div#loginInfo div.content div {
2178}
2179
2180div#loginInfo div.content h4 {
2181 font-weight: normal;
2182 color: #666666;
2183 font-size: 18pt;
2184 padding-bottom: 10px;
2185 padding-left: 10px;
2186}
2187
2188
2189/* @group Now
2190 */
2191
2192div#loginInfo div.loginInfo_now {
2193 padding-left: 10px;
2194 padding-right: 0px;
2195}
2196
2197div#loginInfo div.loginInfo_now div.text {
2198 width: 200px;
2199 color: #666666;
2200 line-height: 20px;
2201 float: left;
2202 padding-bottom: 15px;
2203}
2204
2205div#loginInfo div.loginInfo_now div.icons {
2206 text-align: right;
2207 float: right;
2208 width: 110px;
2209}
2210
2211div#loginInfo div.loginInfo_now div.icons img {
2212 margin-left: 4px;
2213}
2214
2215div#loginInfo div.loginInfo_latest div.icons {
2216 text-align: right;
2217 float: right;
2218 width: 110px;
2219}
2220
2221div#loginInfo div.loginInfo_latest div.icons img {
2222 margin-left: 4px;
2223}
2224
2225
2226
2227/* @end */
2228
2229/* @group Latest */
2230div#loginInfo div.content div.loginInfo_latest {
2231 background: url(../images/loginInfoInnerBackground.png) repeat-y -349px 0px;
2232 width: 349px;
2233 min-width: 349px;
2234 clear: both;
2235}
2236
2237div#loginInfo div.loginInfo_latest div.inner_header {
2238 background: url(../images/loginInfoInnerBackground.png) 0px 0px;
2239 min-height: 6px;
2240 height: 6px;
2241 max-height: 6px;
2242 font-size: 1px;
2243}
2244
2245div#loginInfo div.loginInfo_latest div.content {
2246 padding-left: 12px;
2247 padding-right: 5px;
2248}
2249
2250div#loginInfo div.loginInfo_latest div.text {
2251 float: left;
2252 width: 200px;
2253 line-height: 20px;
2254 color: #666666;
2255 padding-bottom: 5px;
2256}
2257
2258div#loginInfo div.loginInfo_latest div.inner_footer {
2259
2260 background: url(../images/loginInfoInnerBackground.png) 349px -9px;
2261 min-height: 6px;
2262 height: 6px;
2263 max-height: 6px;
2264 font-size: 1px;
2265 clear: both;
2266}
2267
2268a#fullLoginHistoryLink {
2269 font-size: 9pt;
2270 color: #666666;
2271 text-align: center;
2272 padding: 5px 10px;
2273 clear: both;
2274 display: block;
2275 text-decoration: none;
2276 border-top: 1px dotted white;
2277}
2278
2279/* @end */
2280
2281/* @group Download offline-copy warning */
2282
2283table#shouldDownloadOfflineCopyWarningBox {
2284 clear: both;
2285 margin-top: 10px;
2286}
2287
2288div#loginInfo table tbody tr td.offlineCopyDownloadWarningIconTD img {
2289}
2290
2291a#offlineCopyDownloadWarningLink {
2292 font-weight: bold;
2293 color: #666666;
2294 text-decoration: none;
2295}
2296
2297div#loginInfo div.content div.offlineCopyDownloadWarning h4 {
2298 padding: 5px 10px 2px;
2299 font-size: 11pt;
2300}
2301
2302div#loginInfo div.content div.offlineCopyDownloadWarning p {
2303 color: #999999;
2304 padding: 0px 10px 10px;
2305}
2306
2307/* @end */
2308
2309
2310
2311/* @end */
2312
2313/* @group history */
2314
2315
2316table#loginHistoryTable {
2317 padding-left: 2px;
2318 padding-bottom: 15px;
2319 padding-right: 50px;
2320 font-size: 9pt;
2321 color: #666666;
2322}
2323
2324
2325table#loginHistoryTable tr.zebra_even {
2326 background-color: #f2f2f2;
2327}
2328
2329table#loginHistoryTable td.loginHistoryValues {
2330 padding: 5px 10px;
2331}
2332
2333table#loginHistoryTable td.loginHistoryValues div.currentSession {
2334 color: green;
2335 font-size: 11pt;
2336}
2337
2338table#loginHistoryTable td.loginHistoryValues div.elapsedTime {
2339 font-size: 11pt;
2340}
2341
2342table#loginHistoryTable td.loginHistoryValues div.fullDate {
2343 font-size: 9pt;
2344 color: #999999;
2345}
2346
2347table#loginHistoryTable td.loginHistoryValues div.loginHistoryIP {
2348 padding-top: 3px;
2349}
2350
2351table#loginHistoryTable td.loginHistoryValues div.loginHistoryIP span.loginHistoryIPLabel {
2352 padding-right: 5px;
2353}
2354
2355table#loginHistoryTable img {
2356 display: block;
2357 margin: 5px;
2358}
2359
2360
2361td.loginHistoryCountry, td.loginHistoryBrowser, td.loginHistoryOperatingSystem {
2362 padding-left: 10px;
2363 padding-right: 10px;
2364 padding-bottom: 5px;
2365}
2366
2367
2368/* @end */
2369
2370/* @end */
2371
2372/* @group OTP */
2373
2374div#oneTimePasswordList {
2375 width: 700px;
2376}
2377
2378div#oneTimePasswords_header {
2379 background-color: #ddddff;
2380 padding: 5px;
2381}
2382
2383div#oneTimePasswords_header div ul {
2384 padding-top: 3px;
2385}
2386
2387div#oneTimePasswords_header div ul li {
2388 font-size: 9pt;
2389 padding: 0px 5px;
2390 display: inline;
2391}
2392
2393div#oneTimePasswords_header div ul li span {
2394 color: #999999;
2395}
2396
2397div#oneTimePasswords_header div ul li a {
2398 color: #333366;
2399 text-decoration: none;
2400}
2401
2402table.oneTimePassword {
2403 width: 100%;
2404 padding: 0px 0px ;
2405}
2406
2407table.oneTimePassword tbody tr td {
2408 border-bottom: 2px solid white;
2409 }
2410
2411table.oneTimePassword tbody tr.oneTimePassword_used {
2412 background-color: #f0f0f0;
2413}
2414
2415table.oneTimePassword tbody tr td input.otpCheckbox {
2416 margin: 5px 10px 5px 10px;
2417 }
2418
2419table.oneTimePassword tbody tr.oneTimePassword_used td span.oneTimePassword_value {
2420 color: #aaaaaa;
2421}
2422
2423span.oneTimePassword_value {
2424 color: #555555;
2425 line-height: 22px;
2426 font-size: 11pt;
2427 font-family: monospace;
2428 white-space: nowrap;
2429}
2430
2431span.disabledOneTimePassword {
2432 font-size: 10pt;
2433 display: block;
2434 color: #999999;
2435 font-style: italic;
2436 padding-top: 5px;
2437 font-weight: bold;
2438}
2439
2440div.oneTimePassword_usageStats {
2441 padding-left: 20px;
2442 padding-bottom: 5px;
2443}
2444
2445div.oneTimePassword_usageStats div.oneTimePassword_usageDateDescription {
2446 line-height: 22px;
2447 font-size: 10pt;
2448 color: #999999;
2449 font-weight: bold;
2450}
2451
2452div.oneTimePassword_usageStats div.oneTimePassword_usageDate {
2453 color: #aaaaaa;
2454 font-size: 9pt;
2455}
2456
2457div.oneTimePassword_usageStats div.oneTimePassword_usageDetails img {
2458 padding: 5px;
2459}
2460
2461div.oneTimePassword_usageStats div.oneTimePassword_IP {
2462 font-size: 9pt;
2463 color: #999999;
2464}
2465
2466div.oneTimePassword_usageStats div.oneTimePassword_IP span.oneTimePassword_IPLabel {
2467 padding-right: 4px;
2468}
2469
2470div.oneTimePassword_noPasswordPresent {
2471 color: #999999;
2472 padding: 10px;
2473}
2474
2475
2476
2477/* @group Calendar
2478 */
2479
2480div.calendarWidget {
2481 text-align: right;
2482}
2483
2484table.calendarWidget {
2485 font-size: 8pt;
2486 color: #666666;
2487}
2488
2489table.calendarWidget td.daysOfWeek {
2490 padding: 0px 3px;
2491 color: white;
2492 background-color: #ff9400;
2493}
2494
2495table.calendarWidget td.day {
2496 text-align: right;
2497}
2498
2499table.calendarWidget td.day span {
2500 padding: 0px 3px;
2501}
2502
2503table.calendarWidget td.day span.saturday {
2504 font-weight: bold;
2505}
2506
2507table.calendarWidget td.day span.sunday {
2508 font-weight: bold;
2509 color: #ff9400;
2510}
2511
2512table.calendarWidget td.day span.today {
2513 border: 1px solid #666666;
2514 font-weight: bold;
2515}
2516
2517/* @end */
2518
2519
2520
2521/* @end */
2522
2523/*
2524
2525div.loadingMessage {
2526
2527}
2528
2529*/
2530
2531/* @group Loading panel */
2532
2533div.loadingMessage {
2534 padding: 10px;
2535 color: #666666;
2536}
2537
2538div.loadingMessage h6 {
2539 font-size: 12pt;
2540}
2541
2542div.loadingMessage p {
2543 font-size: 10pt;
2544 padding: 5px 0px;
2545}
2546
2547
2548/* @end */
2549
2550/* @group Import */
2551
2552/* @group Formats */
2553
2554/*
2555div.importFormats ul li {
2556 width: 400px;
2557 max-width: 400px;
2558 min-width: 400px;
2559 padding: 10px;
2560 border: 1px solid white;
2561}
2562
2563div.importFormats ul li:hover {
2564 border: 1px solid #ff9400;
2565}
2566
2567div.importFormats ul li.disabled:hover {
2568 border: 1px solid white;
2569}
2570
2571div.importFormats ul li h4 {
2572 font-size: 10pt;
2573}
2574
2575div.importFormats ul li:hover h4 {
2576 font-size: 10pt;
2577}
2578
2579div.importFormats ul li.disabled h4 {
2580 color: #888888;
2581}
2582
2583div.importFormats ul li p {
2584 font-size: 9pt;
2585 color: #999999;
2586 padding: 5px 0px 5px 10px;
2587}
2588*/
2589div.importFormats {
2590 border-top: 3px double #ff9400;
2591 padding-top: 10px;
2592 border-bottom: 3px double #ff9400;
2593 padding-bottom: 10px;
2594
2595}
2596
2597div.importFormats a {
2598 color: #333366;
2599 text-decoration: none;
2600}
2601
2602div.importFormats a:hover {
2603 text-decoration: underline;
2604}
2605
2606ul.radioList {
2607 padding: 5px;
2608 list-style-type: none;
2609 list-style-position: outside;
2610}
2611
2612ul.radioList li h4 {
2613 font-size: 11pt;
2614 font-weight: bold;
2615 color: #ff9400;
2616 text-decoration: none;
2617 padding-bottom: 2px;
2618 cursor: pointer;
2619}
2620
2621ul.radioList li.disabled h4 {
2622 color: #666666;
2623 cursor: auto;
2624}
2625
2626ul.radioList li table tr td {
2627 font-size: 9pt;
2628 color: #999999;
2629 padding-left: 5px;
2630 padding-bottom: 10px;
2631}
2632
2633div.templateDescription {
2634 max-width: 420px;
2635 padding: 2px 0px 5px;
2636 font-size: 10pt;
2637 color: #999999;
2638}
2639
2640
2641/*
2642div.importFormats ul {
2643 padding: 5px;
2644 list-style-type: none;
2645 list-style-position: outside;
2646}
2647
2648div.importFormats ul li h4 {
2649 font-size: 11pt;
2650 font-weight: bold;
2651 color: #ff9400;
2652 text-decoration: none;
2653 padding-bottom: 2px;
2654 cursor: pointer;
2655}
2656
2657div.importFormats ul li.disabled h4 {
2658 color: #666666;
2659 cursor: auto;
2660}
2661
2662div.importFormats ul li table tr td {
2663 font-size: 9pt;
2664 color: #999999;
2665 padding-left: 5px;
2666 padding-bottom: 10px;
2667}
2668
2669*/
2670
2671
2672
2673
2674
2675
2676.clickableElement {
2677 cursor: pointer;
2678}
2679
2680
2681
2682
2683/* @end */
2684
2685
2686div.wizardComponent h3 {
2687 color: #666666;
2688 padding: 10px;
2689 margin-bottom: 10px;
2690 border-bottom: 1px dotted #ff9400;
2691}
2692
2693/* @group Steps */
2694
2695/* @group bar */
2696
2697div.importWizardStepsBox {
2698 height: 53px;
2699 min-height: 53px;
2700 max-height: 53px;
2701
2702 padding-left: 18px;
2703 margin-left: -10px;
2704
2705 width:600px;
2706
2707 background: url(../images/importStepsBackground.png) no-repeat;
2708}
2709
2710div.importWizardStepsInnerBox {
2711 float: left;
2712
2713 height: 53px;
2714 min-height: 53px;
2715 max-height: 53px;
2716
2717 background: url(../images/importStepsBackground.png) repeat-x 0 -53px;
2718}
2719
2720div.importWizardStepsBoxFooter {
2721 float: left;
2722
2723 height: 53px;
2724 min-height: 53px;
2725 max-height: 53px;
2726
2727 width: 18px;
2728 min-width: 18px;
2729 max-width: 18px;
2730
2731 background: url(../images/importStepsBackground.png) no-repeat -9px -106px;
2732}
2733
2734div.importWizardStepsBox table.importWizardSteps tbody tr td {
2735 padding-top: 9px;
2736}
2737div.importWizardStepsBox table.importWizardSteps tbody tr td div {
2738 height: 23px;
2739 min-height: 23px;
2740 max-height: 23px;
2741
2742 padding: 0px;
2743 padding-left: 4px;
2744 margin: 0px;
2745}
2746
2747div.importWizardStepsBox table.importWizardSteps tbody tr td div span {
2748 color: #333366;
2749 font-size: 9pt;
2750
2751 height: 23px;
2752 min-height: 23px;
2753 max-height: 23px;
2754
2755 display: block;
2756 padding-right: 4px;
2757 line-height: 22px;
2758}
2759
2760div.importWizardStepsBox table.importWizardSteps tbody tr td.current div {
2761 padding-left: 8px;
2762 background: url(../images/importStepsLabelsBackground.png) repeat-x 0 0px;
2763}
2764
2765div.importWizardStepsBox table.importWizardSteps tbody tr td.current div span {
2766 color: white;
2767 padding-right: 8px;
2768 background: url(../images/importStepsLabelsBackground.png) repeat-x right -23px;
2769}
2770
2771div.importWizardStepsBox table.importWizardSteps tbody tr td.currentProcessing div {
2772 padding-left: 8px;
2773 background: url(../images/importStepsLeftLabelsBackground.png) repeat-x 0 0px;
2774}
2775
2776div.importWizardStepsBox table.importWizardSteps tbody tr td.currentProcessing div span {
2777 padding-right: 8px;
2778 background: url(../images/importStepsLeftLabelsBackground.png) repeat-x right -23px;
2779}
2780
2781/* @group Steps separator */
2782div.importWizardStepsBox table.importWizardSteps tbody tr td.stepSeparator div {
2783 width: 18px;
2784 max-width: 18px;
2785 min-width: 18px;
2786
2787 background: url(../images/importStepsSeparator.png) no-repeat 0 2px;
2788}
2789
2790div.importWizardStepsBox table.importWizardSteps tbody tr td.stepSeparator div span {
2791 display: none;
2792}
2793
2794div.importWizardStepsBox table.importWizardSteps tbody tr td.stepSeparatorProcessing div {
2795 width: 18px;
2796 max-width: 18px;
2797 min-width: 18px;
2798
2799 background: url(../images/importActiveStepsSeparator.png) no-repeat 0 2px;
2800}
2801
2802div.importWizardStepsBox table.importWizardSteps tbody tr td.stepSeparatorProcessing div span {
2803 display: none;
2804}
2805
2806
2807/* @end */
2808
2809/*
2810importStepsSeparator.png
2811importActiveStepsSeparator.png
2812*/
2813
2814/* @end */
2815
2816
2817div.importStepParameters {
2818 padding-bottom: 10px;
2819}
2820/* @group CSV steps */
2821
2822div.importStepBlocks div.step_2 div.importStepParameters span {
2823 padding-left: 5px;
2824 font-size: 9pt;
2825 color: #999999;
2826
2827}
2828
2829div.importStepBlocks div.step_4 div.importStepParameters span {
2830 padding-left: 5px;
2831 font-size: 9pt;
2832 color: #999999;
2833
2834}
2835
2836
2837
2838/* @end */
2839
2840
2841/* @end */
2842
2843div.importPreviewDiv {
2844 height: 250px;
2845 max-height: 250px;
2846 overflow: auto;
2847
2848 border: 1px solid #333366;
2849 margin-bottom: 10px;
2850}
2851
2852textarea.importTextArea {
2853 width: 500px;
2854 height: 200px;
2855}
2856
2857body.masked div.importPreviewDiv {
2858 overflow: hidden;
2859}
2860
2861div.importPreviewCommandsDiv {
2862 width: 500px;
2863}
2864
2865div.importOptions {
2866 color: #666666;
2867 font-size: 10pt;
2868 padding: 3px;
2869}
2870
2871div.importOptions span {
2872 padding-left: 4px;
2873}
2874
2875/* @group Options */
2876
2877div.importOptionsDescription {
2878 padding: 10px 0px;
2879 font-size: 10pt;
2880 color: #666666;
2881}
2882
2883div.importStepDescription {
2884 padding: 10px 0px;
2885 font-size: 10pt;
2886 color: #666666;
2887}
2888
2889div.CSVImportOptionsParameters ul {
2890 padding-bottom: 10px;
2891}
2892
2893div.CSVImportOptionsParameters ul li {
2894 padding-right: 15px;
2895 display: inline;
2896}
2897
2898div.CSVImportOptionsParameters ul li label {
2899 padding-right: 5px;
2900 font-size: 9pt;
2901 color: #999999;
2902
2903}
2904
2905div.importOptionsButtons {
2906 padding: 10px;
2907}
2908
2909/* @end */
2910
2911/* @group PasswordPlus */
2912/* @end */
2913
2914/* @group KeePass */
2915
2916table#KeePassSettings {
2917 margin: 15px 0px;
2918 border-top: 3px double #cccccc;
2919 border-bottom: 3px double #cccccc;
2920 padding: 10px 10px;
2921}
2922
2923table#KeePassSettings td {
2924 padding: 2px 0px;
2925}
2926
2927table#KeePassSettings span.keePassFieldLabel {
2928 font-size: 10pt;
2929 color: #666666;
2930 padding-left: 5px;
2931}
2932
2933table#KeePassSettings span.keePassFieldLabel.disabled {
2934 color: #aaaaaa;
2935}
2936
2937
2938
2939/* @end */
2940
2941/* @group CSV */
2942
2943div.csvImportPreview {
2944 width: 700px;
2945 max-width: 700px;
2946 min-width: 700px;
2947
2948 height: 300px;
2949 max-height: 300px;
2950 min-height: 300px;
2951
2952 overflow: auto;
2953}
2954
2955table.csvImportPreview {
2956/*
2957 border: 1px solid #333366;
2958 margin-bottom: 10px;
2959*/
2960}
2961
2962table.csvImportPreview thead tr th {
2963 font-size: 10pt;
2964 color: white;
2965 background-color: #666666;
2966 padding: 5px;
2967 border-right: 1px solid #dddddd;
2968}
2969
2970table.csvImportPreview thead tr th span {
2971 padding-left: 5px;
2972}
2973
2974table.csvImportPreview.header thead tr th input {
2975 font-size: 9pt;
2976 margin: 3px 0px;
2977}
2978
2979table.csvImportPreview tr.CSV_previewData_header td {
2980 padding: 3px;
2981 color: white;
2982 border-right: 1px solid #dddddd;
2983 background-color: #666666;
2984/*
2985 padding-bottom: 15px;
2986 border-bottom: 1px solid #333366;
2987 border-bottom: 5px solid white;
2988*/
2989}
2990
2991/* @group Columns */
2992
2993table.csvImportPreview.columns th {
2994 padding: 10px;
2995 border-right: 1px solid white;
2996}
2997
2998table.csvImportPreview.columns th.selectedColumn {
2999 background-color: #666666;
3000}
3001
3002table.csvImportPreview.columns th.skippedColumn {
3003 background-color: #bbbbbb;
3004}
3005
3006table.csvImportPreview.columns td.selectedColumn {
3007}
3008
3009table.csvImportPreview.columns td.skippedColumn {
3010 color: #aaaaaa;
3011}
3012
3013/* @end */
3014
3015/* @group titleColumn */
3016
3017table.csvImportPreview tr th.titleColumn {
3018 background-color: #333366;
3019}
3020
3021table.csvImportPreview tbody tr.zebra_even td.titleColumn {
3022 background-color: #e0e0ff;
3023/*
3024 background-color: #ffffcc;
3025*/
3026}
3027
3028table.csvImportPreview tbody td.titleColumn {
3029 background-color: #f0f0ff;
3030/*
3031 background-color: #ffffee;
3032*/
3033}
3034
3035/* @end */
3036
3037/* @group title */
3038
3039table.csvImportPreview tr th.title, table.csvImportPreview tr.CSV_previewData_header td.title {
3040 padding-left: 10px;
3041 background-color: #333366;
3042}
3043
3044table.csvImportPreview tbody tr.zebra_even td.title {
3045}
3046
3047table.csvImportPreview tbody td.title {
3048 font-weight: bold;
3049}
3050
3051/* @end */
3052
3053/* @group notesColumn */
3054
3055table.csvImportPreview tr th.notesColumn {
3056 background-color: #333366;
3057}
3058
3059table.csvImportPreview tbody tr.zebra_even td.notesColumn {
3060 background-color: #e0e0ff;
3061}
3062
3063table.csvImportPreview tbody td.notesColumn {
3064 background-color: #f0f0ff;
3065}
3066
3067/* @end */
3068
3069/* @group notes */
3070
3071table.csvImportPreview tr.CSV_previewData_header td.notes {
3072 padding-left: 10px;
3073 font-style: normal;
3074 background-color: #333366;
3075}
3076
3077table.csvImportPreview tbody tr.zebra_even td.notes {
3078}
3079
3080table.csvImportPreview tbody td.notes {
3081 font-style: italic;
3082}
3083
3084/* @end */
3085
3086/* @group Fields */
3087table.csvImportPreview tr.CSV_previewData_header td span {
3088 padding-left: 5px;
3089 display: block;
3090}
3091
3092table.csvImportPreview tr.CSV_previewData_header td.missingLabelWarning {
3093 background-color: #eeeeee;
3094 border: 2px double red;
3095}
3096
3097table.csvImportPreview tr.CSV_previewData_header td.missingLabelWarning span {
3098 color: red;
3099}
3100
3101table.csvImportPreview tr.CSV_previewData_header td.configuredColumn {
3102 font-style: normal;
3103 background-color: #333366;
3104}
3105
3106table.csvImportPreview td.configuredColumn {
3107}
3108
3109table.csvImportPreview td.unconfiguredColumn {
3110 color: bbbbbb;
3111}
3112
3113/* @end */
3114
3115table.csvImportPreview tr.CSV_previewData_header td:last-child {
3116 border-right: 0px;
3117}
3118
3119table.csvImportPreview thead td {
3120 font-size: 9pt;
3121 padding: 4px 4px 3px;
3122}
3123
3124table.csvImportPreview tbody td {
3125 border-right: 1px solid #dddddd;
3126 color: #666666;
3127 font-size: 9pt;
3128 padding: 4px 4px 3px;
3129}
3130
3131
3132
3133table.csvImportPreview tbody td:last-child {
3134 border-right: 0px;
3135}
3136
3137table.csvImportPreview tbody tr.zebra_even {
3138 background-color: #f2f2f2;
3139}
3140
3141
3142
3143/* @end */
3144
3145/* @group Preview */
3146
3147table#importPreview {
3148 width: 400px;
3149/*
3150 margin: 15px 0px;
3151 border-top: 3px double #cccccc;
3152 border-bottom: 3px double #cccccc;
3153 padding: 10px 0px;
3154*/
3155 }
3156
3157table#importPreview input {
3158 margin: 4px 4px 0px 10px;
3159}
3160
3161table#importPreview tr.zebra_even {
3162 background-color: #f2f2f2;
3163}
3164
3165span.importPreview_title {
3166 font-size: 11pt;
3167
3168 font-weight: bold;
3169 padding: 4px 4px;
3170 color: #333366;
3171}
3172
3173span.importPreview_notes {
3174 display: block;
3175 width: 150px;
3176 padding: 4px;
3177 font-size: 8pt;
3178 color: #999999;
3179}
3180
3181table.importPreview_record {
3182 padding-bottom: 10px;
3183 padding-top: 10px;
3184}
3185
3186table.importPreview_record tbody tr td.importPreview_fieds {
3187 border-left: 1px solid #dddddd;
3188}
3189
3190table.importPreview_fields {
3191/*
3192 border-left: 1px solid #dddddd;
3193*/
3194 padding-left: 5px;
3195}
3196
3197span.importPreview_fields_label {
3198 font-size: 9pt;
3199 color: #666666;
3200 display: block;
3201 width: 150px;
3202}
3203
3204span.importPreview_fields_value {
3205 font-size: 9pt;
3206 color: #333366;
3207}
3208
3209
3210/* @end */
3211
3212
3213
3214/* @end */
3215
3216span.clickableSpan {
3217 cursor: pointer;
3218}
3219
3220
3221
3222/*
3223div.importStepBlocks {
3224 height: 220px;
3225 min-height: 220px;
3226 max-height: 220px;
3227 width: 600px;
3228 min-width: 600px;
3229 max-width: 600px;
3230 overflow: auto;
3231}
3232*/
3233
3234hr {
3235 margin-top: 20px;
3236 border: 0px;
3237 border-top: 1px dotted #aaaaaa;
3238}
diff --git a/frontend/beta/css/clipperz/compact.css b/frontend/beta/css/clipperz/compact.css
new file mode 100644
index 0000000..7c9252a
--- a/dev/null
+++ b/frontend/beta/css/clipperz/compact.css
@@ -0,0 +1,162 @@
1/*
2
3Copyright 2008-2011 Clipperz Srl
4
5This file is part of Clipperz's Javascript Crypto Library.
6Javascript Crypto Library provides web developers with an extensive
7and efficient set of cryptographic functions. The library aims to
8obtain maximum execution speed while preserving modularity and
9reusability.
10For further information about its features and functionalities please
11refer to http://www.clipperz.com
12
13* Javascript Crypto Library is free software: you can redistribute
14 it and/or modify it under the terms of the GNU Affero General Public
15 License as published by the Free Software Foundation, either version
16 3 of the License, or (at your option) any later version.
17
18* Javascript Crypto Library is distributed in the hope that it will
19 be useful, but WITHOUT ANY WARRANTY; without even the implied
20 warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
21 See the GNU Affero General Public License for more details.
22
23* You should have received a copy of the GNU Affero General Public
24 License along with Javascript Crypto Library. If not, see
25 <http://www.gnu.org/licenses/>.
26
27*/
28
29/* @override https://www.example.com/css/compact.css */
30
31body.compact div#mainDiv {
32/*
33 width: 250px;
34 height: 95%;
35 border: 1px solid #333366;
36*/
37 padding: 0px;
38}
39
40body.compact div#compactHeader {
41 background-color: #333366;
42}
43
44body.compact div#compactHeader img {
45 padding: 2px 20px 2px 4px;
46 width: 60;
47}
48
49body.compact div#compactHeader a {
50 color: white;
51 text-decoration: none;
52 font-size: 10pt;
53 /*position: absolute; */
54 right: 10px;
55 top: 6px;
56}
57
58body.compact div#compactHeader a:hover {
59 color: #ff9400;
60}
61
62body.compact h4 {
63 color: #999999;
64 text-align: center;
65 padding: 20px;
66 font-weight: normal;
67 font-size: 12pt;
68 font-style: italic;
69}
70
71body.compact div.loginPanel form {
72 padding: 10px;
73}
74
75body.compact div.loginPanel dt {
76 color: #aaaaaa;
77 font-size: 10pt;
78}
79
80body.compact div.loginPanel input {
81 width: 180px;
82}
83
84body.compact ul#directLogins {
85 background-image: none;
86 padding: 4px 0px;
87}
88
89body.compact ul#directLogins li {
90 width:auto;
91}
92
93body.compact ul#directLogins li.hover {
94 width:auto;
95 padding-right: 0px;
96}
97
98body.compact div.lockPanel {
99 color: #999999;
100 font-size: 10pt;
101 padding: 10px;
102}
103
104div#compactMiscLinks ul {
105 /* text-align: center;*/
106 display: block;
107 padding-left: 22px;
108 background-color: #ff9400;
109}
110
111div#compactMiscLinks ul li {
112 display: inline;
113 padding: 2px 5px;
114}
115
116div#compactHeader div#compactMiscLinks ul li a {
117 font-size: 9pt;
118}
119
120div#compactHeader div#compactMiscLinks ul li a:hover {
121 color: #333366;
122}
123
124div#lockBlock {
125 position: absolute;
126 right: 10px;
127 top: 6px;
128}
129
130div#lockBlock input {
131 width: auto;
132 padding-bottom: 2px;
133}
134
135div#lockBlock span {
136 font-size: 9pt;
137 padding: 0px 5px 0px 4px;
138 color: #aaaaaa;
139}
140
141div#lockBlock a#lock {
142 font-size: 9pt;
143}
144
145/* @group Donate */
146
147a#donateHeaderLink {
148 font-weight: bold;
149}
150
151div#compactMiscLinks a#donateHeaderIconLink img#donateHeaderLinkIcon {
152 display: inline;
153 position: absolute;
154 top: 22px;
155 left: 1px;
156 width: 12px;
157 height: 12px;
158}
159
160
161
162/* @end */ \ No newline at end of file
diff --git a/frontend/beta/css/clipperz/ie.css b/frontend/beta/css/clipperz/ie.css
new file mode 100644
index 0000000..02b09f2
--- a/dev/null
+++ b/frontend/beta/css/clipperz/ie.css
@@ -0,0 +1,351 @@
1/*
2
3Copyright 2008-2011 Clipperz Srl
4
5This file is part of Clipperz's Javascript Crypto Library.
6Javascript Crypto Library provides web developers with an extensive
7and efficient set of cryptographic functions. The library aims to
8obtain maximum execution speed while preserving modularity and
9reusability.
10For further information about its features and functionalities please
11refer to http://www.clipperz.com
12
13* Javascript Crypto Library is free software: you can redistribute
14 it and/or modify it under the terms of the GNU Affero General Public
15 License as published by the Free Software Foundation, either version
16 3 of the License, or (at your option) any later version.
17
18* Javascript Crypto Library is distributed in the hope that it will
19 be useful, but WITHOUT ANY WARRANTY; without even the implied
20 warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
21 See the GNU Affero General Public License for more details.
22
23* You should have received a copy of the GNU Affero General Public
24 License along with Javascript Crypto Library. If not, see
25 <http://www.gnu.org/licenses/>.
26
27*/
28
29<!--[if IE]>
30
31<style>
32
33{
34 background-color: white;
35}
36
37div#logoFrame {
38 height: 44px;
39}
40
41div.clipperzLoginForm div.loginForm form {
42 padding-left: 20px;
43}
44
45div.clipperzLoginForm div.registrationForm form {
46 padding-left: 20px;
47}
48
49div#newRecordInnerPanel {
50 width: 350px;
51 height: 160px;
52 background: url(../images/newRecordPanelBackground.png) no-repeat 0 -165px;
53 /*background: url(data:image/png;charset=utf-8;base64,iVBORw0KGgoAAAANSUhEUgAAAY4AAAFQCAYAAACoMJkjAAANIWlDQ1BJQ0MgUHJvZmlsZQAAeJyV13k0lG8bB/BrFsYyZhhjDyO7iLITskQi2feS7AwzMQkpS1KILKFoQWihKJGoqH5kSUghoajIkj1Llnn/kOr9nff3vue9/njO9dzPc859P885n+99bgC8miuVSkYCgH8ALdDSSI9k7+BIwnQCBnDAA1gQdnULouqam5vCP9Z8JyAAADrkXKlU8j+/9x8LF2jv4AiAkAUAotd6vxMAiIfWe2sAIB6lUWkACG8AILp5u7oDIMIBQDbQ2lIfAHEDAHBe630lAOAOrfcNAIALdvOiASC6ARgJAe4+AQCYcQBGbXePIDcAnCwAuLsHufkD4JIBwMzfn+IOgPsIAFJu1EAaAJ4JAOTsHRxJ60t2igdQ4gNgMvk9djQdoDwXQGrv7zHRBwDcrgB5ib/HZi0BAQAI7tYgT8XtAACAwOoBMPTT6bMSAJhUgNUUOn05j05fvQaA6gWoJbsdCQz++b8QiBaA/3W//s0/C4UAQAIgxBCFyDBUODqc4QRjJCaa6SSzAXMdy2nWM9g4trO4CnZvjhRCCmcq8TxXOnc6TyZvHT9FIHtTtuBloQbSEZG8zddEW8WPSRRKtkufkCna0ikXvfW2fM+209vvKX5QPqtSoTqgnqRRpTmklab9RGdUN0Pvmf7ErizDeqMZ46t7mkzm9+aZvdrXZt5m0W65Yn3L5q1tp12Xfbcj2umuc+/+vgP9Lh8OfjyEdXvo/tnji+eQ17D3V58RPy7yU/9vAROUSerU4enAmaA52tyR78HzRxdCFkOXwn4cWwlfOb4aIR35NhpxEhmDOoWOZTjNeAYTxxTPnMByljURm8R2DpeMT2FP5UgjnOdMJ2ZwZXJf4LnIm8WXzX9J4PKmK4JXhXKEc0l5Itc254sWiBWKX5e8IXlT6pZ0kUzRWDH5tuwduRL5UoW72+5tK9t+X6lcuUKlYv5BcKXqQ7UqjWrNRzse73ii9WStJqJW5+nOZ7rP9f7Sr0PXxdTvemHYYNRo3GTczNKc8NKkxfSVWSuu9VybebvFa8sOQkfqG6u31p02Xdxdmd127+x7HN/zv8/ude5z7t//QejD1Y8uAwcHRQbzPh367PbFfUh8qHDY86vXiPeo9OitMd9xv2/kCbmJO5MBU5Rp6sy2mXuzgXNB32nzyvMVC8GLIUuhP0KXNZarV46thq9prT2h0wEQokgccgrVjC5iSGMMx3gxWTPrsyixSmIl2XhxPHhedl4OLoIEpxRRjcuU+wBPEG8SXwl/s8CIIKeQirAX6YLIC1GEmJb4YYm7kpPSUjLkLdVyqK268ikKA9ulFWOVulRkVKlqdRo8miE7Xmpz61B2PtMT0z9m0G4oZBSy+7Hxksk2U4+96Wbt5jgLI8sQqwLrN7YsdjvtDztcdqx3mtwvfGCfS9jBPNe6QyPuXB46nvZeJ7xzfGp9+/yW/DkDtlAMqN6HwwOTg/Jo5Ucagt8fHQ2ZD0Md4wgnHZc9oRyxM9Ikal+008mDMR6nyLG004FnIuMi408mxJ1NTUxIyjp3MTkzJSX1Ulrq+Yz0Cxk3Mq9fuHPxRlZRdsmlR5cfXam7+jKnPbcjr+NaR/77gs+Fw9cHb3y5OXlrumiyeOL2zJ3JkrHS8bvD9wbKBu/3lLdXND6orXzwsKTqUnXqo8jH/k+cakxqdzyVeUZ4tvT8419Ndffr014ENlg1qjQJNNGbe17eb4l/5dgq2jrUVtZ+/PWuDlxH35uct76dip2rXS3dae/290j3zL6v6o3uM+kn9vd/uPkxaEBzED3Y9On85wNfJL+MD1UNR33dM8I10jeaP0YeVx5f+9Y4kTrpNCU2NT5dNhM+azRHmOv+XjBPWVBfRC2+WEr54bQsuvxtpWI1cs2Yzk2nA8BJRAgyDKWJqkIfZ9BhqGGMwpxiMmSqY45lOc0aj92DbWZLxCXik9j3sbdyJBNSOdOIaVzWXG+4M3gyeC/wZfFnC2RvuiToLNgndFU4h5Qrkrs5V/SaWL54gUSh5HWpG9I3ZXxkRrfcki2Wu731jnyJQum2u9vvKZYp3VeuUKlQrVALUVtUr9Ko0qze8UjrsfYJ7TWdmp21uk/1nuk/N4jZhd5VZ1hv9GJ3g3HjniaTBFOs6cu9LWav9rWaJ1uwW7RbvrbqsH5j02mbYcdt12Xf7fDOsccp21nAuXd/34EPLh8PfnTNPSRyaNDtk/tnjy+ehV4S6wniO+pXRJYlj/9bisz+SpHKULXQpbAfx5bDV46vnliLoEdBNPJXkmDOYOKY4hrj9ySwnsUmYpPYzuGT2VM4fmUJdybPBd6fWbLpzyzJG7zmli9aIFYocV1iI02KZW/L3dn6R5YolitVKD9QrVR9qFalXq35SPPxjifaNdp/5MiuesMXhg1GjbubjJtNXga/2txq1mbebv7aouP4W5lO2y677uge+feOvbH9ih/iBpQHz352H9IcThnxGfP9Rp6kTMfPOc6fW0pYtaTTAdb3PgAARhWAjC0AtlkAVnkAsVsAJF0AuG8AmLMBWKsDkkEIkFpUQOzR2tg/AAHsIAhbQQ8cIAiSoRQWESSECSIEcQPxCjGMxCONkFHIx8gVlBYqClWPWkGLoB3QhejvDIYMpxhKGCYZjRhzGYcwXBhnzGMmDJM6UwzTGLMGM4W5lkWOJZKlkhXHGsX6DkvEBmC/su1iO8k2gHPFPcOj8J74cXYL9gz2VY44jhmCBqGAU5WzgHOS6EJc4PLhquDewv2Cx5MXw3uLT5zvKN8c/2UBI4HZTTmCYoLhQgihcmFfkgipR+T85s2bI0Xxoq1iKeI2EvwSg5JFUvpSN6X1ZDhkBraUyZ6Wc96qKI+VH1b4a1ve9mhFdyUjZVkVTpUV1SG1THWceq1GqWbujvNaZ7QjdI7uPKxL1vPR9zbw3uVnGGBE233MOGbPOZNs05t7K80a9/WaT1tirISs1WysbKl2SfZ3HNocZ51592sf8HRJPljt+tWNx93II9Sz2IfX19wvnlwXgKToUqMOPw9ipJkcSQ0RC6WEPQpnOe54ojiCHmUdgzzlHPvgDGfc4fj2xPSkpWSXlPo0+fNZmUEXPmVZZddduZMjnnv5Gk8h+/Wkm7hb525nlgiW5t+TKzeoaK90fTj9mOdJca3ec1odvr64YU9zfIvcq/a24I76t9Quge6GXom+7g/xAzqfi4fcvwqP9HyzneSe6prJmnNZGF8qX46g89LpAIAEFuABadABezgC6VAJ/QgMQgHhgkhC1CBmkTJIF2QW8g0Kj9qLOotqQbOh96HT0e8ZSAw+DKUMi4z6jOcY32HEMUcwz5kITO5MlcyszM7Md1jQLAdY7rOysLqx1mC5sFRsC5sMWyLbOM4UV4Jnw1Pwnew72fM5cBzBHO8JhoS7nCTOVM41YhDxG5cv1yg3mXuGh8YzzxvGh+A7y8/Pf0tAXaB+k+2mEcFIIT6hCmEL4VFSrIiESMPmAFEe0SdibuJY8acSAZLCkq+l4qT1pFdlqreEy2rJLsjVbD0jb60gojC5rWZ7iqKvkoGykPKyylvVh2qX1aM0vDTtdmhpyWuL6BB2onVRujN60/qTBmO7hgxnjcZ2f9+DNCGa8uzdZqa9b5+5pYWfZahVtvU9m5e27+1WHIiO8k5mzof3XzxQ5zLsynxIwc3bPcujxnPKW9rHwzfT762/QIANJZv6NVAqKJjWGCx4NCikKUz0WFL46AmHiIYoleiCGMKppNOEMxnxvAnZicpJr5I9Un6kJaarZny5cCXL95LNFekchtzxa88Kyq9fvBlb5HbbucTwrlqZUvnWB3IPparFH0vVKDzVeb67zuIFufFwc0pLTuuj9v4Oeqdwt1aPe29Cf9XH8U98X/SGI0dujH2e4J/ynLkyN7QgtRSwXLGGoNMBgBHYQRD0wAGSoRReb9jfcL+uHo1HO6C/MxgyZP30voZxZhJmimEaY7ZmrmWRY7nEimONYl3ABmC/srnjXHGf8J74cfYg9lWOOAI3oYBTlbOJ6EJc4Er+ZdqMb+6nZ3MhhFD5T8sW65J/Og6W1vvT8G/BP/2+Vq/VKP1t97fcf3b739R6Dfjw+pr/XW1wz9/dRt/6U+7Z7b/lZjBu2L2svqE3P23DbzFhQ3BZ5Ybh6pPrip/2bDhuHGmOf/lXS8ar9rbg14Id9W+pnaVdsd0NPcG9En1+/QYf4gd0Bk9/OvS5+Mv8UMdX4RG/UeMxqXHMN9uJwsnYKa/p3TMys6yzE3Nt38vmMxasF8YXY5b0fkj+GFqOWOFdubLKsRqzurCWT0+g0wHWz0sAAMCiTyFTAkmm+gb/52Hvf5U/+cjGHEgAwHoE2FgBAAEApHxoxtYAQAQADdAHCpCBAoFAAlPQB4OfVxK4/XriA7B+lgMAYGQHuGQHAFCzeCzy7/PSPEJoAAD6FGpooI+XN42kS6WSPUj6FH/qEZpHoCzJOMBtqyxpu4KCMgDAvwBJl//fxucdgAAAAAlwSFlzAAALEwAACxMBAJqcGAAADQdJREFUeJzt3U+MnGd9wPHfOzP7x/FuvOAYZAzGRg1pFKDAIVXbiD8Sai2knKJK7QHEAXHoHfXS9MIFDkg9c0BVD1SqUIA2VRuLKhIEOBjhQxDBjo0BJ7gQ4jq769m1d2emh5nH885k7e5vZnbj2p+P9Gr+7LvvO3t5v/u8z/vuRgAAAAAAAAAAAAAAAAAAAAAA95HqLd7vW7V/gHtBb7Dsq70+cFe1Jcae78f+Ae5V48Hojj3fs6Ds1YG7iohGjIZj/PV4VADYvV5tKdHo3uG9mZn1QbseiEZENAfvt2rvNcbW28vPA3Av2WmUUQ9FWTq15/WvzyQgszpQ7xSM5uB56/jxPzt66NDxJ5vNA59sNKr3RjROVlU1P6N9A9zHemu9Xu/Vbnf7JzdurP/bSy9987sRsR39eGzHMCQzi8cswlGPxq1YRETr0KH3v+3EiT/+21Zr8bMR1eIM9gXAHXS7nZfa7d///blz33k+hvGoB2TqeDT/71XuaDwarYiYj4iFEyc+9cFjxz70zWZz/lMRVWvK/QCwC1XVODI3d/AvH3ro0d7vfvfij8vbs9zHtOEocxb1aMy/5z0fe/TIkT94pqoa75r2AwKQU1VV1WzOP3H48CMxiEcZYfRiBhGZZgNllDESjeXld608/PCnT1dV43h95cOHH4zPfObP4/HH/zCOHj0cy8sPTLFrACIi1tbacf78K/HMM9+L5547M/K1Xq/XW1+/8rnz55/9bkRsRsTWYCmnrrpv2uAuTBOOMp8xN1jmI+KBD3zgr/9uYWH58/UVT516PL74xb+KQ4cOTrE7AO7k+efPxpe+9E+xutq+9V63u33h7Nmvn4qIdozGoxPDSfOUSU9VlbmN1mBZiIjFBx88cfTIkUf/oaqqW9v9xCc+HF/+8hdicdFFVAB76eTJo3HixNE4fXo48qiqxtsPHnzn+atXX/5FjF6uW78PJKUx4eerX3Z7Kx7Hjn3kqfpltu94x0o8/fRnJ9wFAFkf//gfxalTj4+8t7i48hcRsRj9X/LLMXune+l2ZZJw1G/kG7mSam5u6Yn6ik8++adOTwHss6ee+tjI67m5xQ9F/zjdiv7UQjOm+Osd04w4SkDK/MZ8szn/aH2lJ5744ISbB2BSDz/87pHXVdV4KPqjjTLiKL/071s4yk7qp6nmImKx0Wiu1Fd87LETE2wegGksLR0YeV1VjYPRj8ZcDMNRfvlPm3TEUa6oKvEoV1aNbrwx6eYBmLFynC7hqP/h2ZRJjuyN2mO5smou+jUD4O40H8N770o4It6COY6Rv0014bYA2HtlpFGO22VJy35TfRa+GaN3j0/750sA2Dvll/z6v7eY6MqqaUYcEaOXdAkHwN1rqktw66YNR9nGxDeSALAv6tML5fW+3QBY/xD1+zlcQgVw96pqj1ONOmYVDgDubtVtnqfNcpQgIAD3AaeXAEgRDoD7w05nhfZlcvxO1/06VQXw/0P9GL5v93GM71w0AO5+MzleO1UFQIpwAJAiHACkCAcAKcIBQIpwAJAiHACkCAcAKcIBQIpwAJAiHACkCAcAKcIBQIpwAJAiHACkCAcAKcIBQIpwAJAiHACkCAcAKcIBQIpwAJAiHACkCAcAKcIBQIpwAJAiHACkCAcAKcIBQIpwAJAiHACkCAcAKcIBQIpwAJAiHACkCAcAKcIBQIpwAJAiHACkCAcAKcIBQIpwAJAiHACkCAcAKcIBQIpwAJAiHACkCAcAKcIBQIpwAJAiHACkCAcAKcIBQIpwAJAiHACkCAcAKcIBQIpwAJAiHACkCAcAKcIBQIpwAJAiHACkCAcAKcIBQIpwAJAiHACkCAcAKcIBQIpwAJAiHACkCAcAKcIBQIpwAJAiHACkCAcAKcIBQIpwAJAiHACkCAcAKcIBQIpwAJAiHACkCAcAKcIBQIpwAJAiHACkCAcAKcIBQIpwAJAiHACkCAcAKcIBQIpwAJAiHACkCAcAKcIBQIpwAJAiHACkCAcAKcIBQIpwAJAiHACkCAcAKcIBQIpwAJAiHACkCAcAKcIBQIpwAJAiHACkCAcAKcIBQIpwAJAiHACkCAcAKcIBQIpwAJAiHACkCAcAKcIBQIpwAJAiHACkCAcAKcIBQIpwAJAiHACkCAcAKcIBQIpwAJAiHACkCAcAKcIBQIpwAJAiHACkCAcAKcIBQIpwAJAiHACkCAcAKcIBQIpwAJAiHACkCAcAKcIBQIpwAJAiHACkCAcAKcIBQIpwAJAiHACkCAcAKcIBQIpwAJAiHACkCAcAKcIBQIpwAJAiHACkCAcAKcIBQIpwAJAiHACkCAcAKcIBQIpwAJAiHACkCAcAKcIBQIpwAJAiHACkCAcAKcIBQIpwAJAiHACkCAcAKcIBQIpwAJAiHACkCAcAKcIBQIpwAJAiHACkCAcAKcIBQIpwAJAiHACkCAcAKcIBQIpwAJAiHACkCAcAKcIBQIpwAJAiHACkCAcAKcIBQIpwAJAiHACkCAcAKcIBQIpwAJAiHACkCAcAKcIBQIpwAJAiHACkCAcAKcIBQIpwAJAiHACkCAcAKcIBQIpwAJAiHACkCAcAKcIBQIpwAJAiHACkCAcAKcIBQIpwAJAiHACkCAcAKcIBQIpwAJAiHACkCAcAKcIBQIpwAJAiHACkCAcAKcIBQIpwAJAiHACkCAcAKcIBQIpwAJAiHACkCAcAKcIBQIpwAJAiHACkCAcAKcIBQIpwAJAiHACkCAcAKcIBQIpwAJAiHACkCAcAKcIBQIpwAJAiHACkCAcAKcIBQIpwAJAiHACkzDIcvRluC4DZmtkxOhuO3tjz+gLA3W0mx+1JRhxCAXBvmCgi5jgASJlFOG5bql7PwATgXjNpOHo7PPa63e3r9ZXOnbs86ecCYELXr2+OvO71OpsxwznpaUYc4x+gu7W18av6Ci+88OIUmwdgEpcuXRl53elsvzG2ylQRmUU4uhHRiYheu/36z+orPPvsj6Ld3tzpewHYI9/+9gsjr7e2rv8yBsfpGB63JzarcPQionPlytnvR/Q6ZYVXXnktvvKVf57m8wGQcObMz98UjrW1V88OnpZf9MvziTQn+J5q8H2twTIXEfMRsbi93W4sLx9758LC8vGy8ssvvxKrq+346EffH63WJLsDYDfOnPl5PP3016PdvnHrvU7nxu8vXnzuH3u97lpEtCPiRkRsRsTWYOlGMiKTHMkbg6U5WEo4FiJifn39yquHDz/yJ41Gc6F8w09/eilOn/5xLC0diJWVpVhcXIhGo5pg1wDUtdubce7c5fja156Nr371X0aiERHx29+++I3V1csXImI9IjYGy42IuBkR24MlFY5Jjt5ltLEQEQciYikiliPiwYh4KCLetrLyvsdOnvzk39TjAcD+euONy9+7cOE/vhERr0fE1Yi4FhGrMYzIZvTD0bntRnYw6amq8VFHGXnMRcT85ub/bNy8uf6b5eVjj4gHwP67du3XP7h48T+/FRFrEXE9RkccW9EfcXRiOGm+a5OGo8xzjMejjEaaGxtX169d+9W5AwfevjI/v3SkqirnpgD22Pb25rUrV37yr5cvv/B89KNRwnE9+nMcm9GPxlb0o1EucNq1aWerdwpIa/C60elsbr3++vkL6+v/fTEithqNVquqGo2qajSFBGB63W5na3t7Y31j4+qvX3vtpR9euvRf/7629ptfRn+EUR9ttOPN8xslHCmTHrwbMbyiaiEiFiPigejPdSxFxKEYzn0sRcTBwTqLMbwaq5zumvazANxP6qODcvDfjv4IYjOGoVgbPK4Onq9GPx7lyqqtGE6Mp0YcrSk+fHew0zLauBn9mpWRR9EZfMADg6/Px2g4yqmvCPEAuJORP/MUwzmKrRheZrsR/TjURxwlFjdiOMroxoR3j08ajvrt6t3Bh65qS3m/VPDG4IdZjP4opZzSKhPtggGwO/Vjb7mhr0x2b8Zw1NGuPW7E8PRUfW5jItOGoxOjo4V6AEpQbkZ/tLEQ/dHG3GC/zRiGI0I8AHZjp3Bsx3Duoow66ksJSolG/c+PpE1zqqrssFz/Ox6NUrZy3m0+huEoE+r1cIxvA4BR9VNV5VTTdm25GcN4lMf6neL1OY23NBxl5FGed2tL+UHKvEaZUC/zIvXTWxHCAXAn4wf8csqpPkFezvTcrD0v0Zh6tBExXTgi3vwD1N8rP0gr+sUr4RgfbYgFQF59grsEoYw8tmJ0PqN+6e3U/5Nj2nDE4IM0xj5IfXK8xKJ+v0f9aqrxuREAbm+nK6vKYznudnZYejHlKapilgfs8RDUT0eVWOw00nCaCmB3xv/7asTo9MBOIan//42p/g9HsRcH6/pVUuMhGf9afX0Adqc+ahi/PaL+OP71mdjL3/J3mvS+3aW7AOSNj0B2epxZMIr9PHg7JQWwd3Y6jQUAAAAAAAAAAAAAAAAAAAAAMK3/BX4vwOY3EngcAAAAAElFTkSuQmCCCg==) no-repeat 0 -165px; */
54}
55
56img#donateHeaderIcon {
57 padding-top: 0px;
58 margin-bottom: 0px;
59}
60
61/* ========================================================== */
62
63div#applicationVersionType {
64 position: absolute;
65}
66
67div#applicationVersionType.readOnly {
68 background: url(../images/read-only.png) no-repeat fixed -5px -8px;
69}
70
71div#applicationVersionType.TEST {
72 background: url(../images/test-database.png) no-repeat fixed -5px -8px;
73}
74
75div#mainTabs {
76 background: #ff9400 url(../images/menubarSprite.gif) repeat-x;
77}
78
79div#menus {
80 background: url(../images/menubarSprite.gif) no-repeat right -26px;
81}
82
83div#menus table {
84 background: url(../images/menubarSprite.gif) no-repeat 0 -52px;
85}
86
87div#menus table tbody tr td div {
88 background: url(../images/menubarSprite.gif) no-repeat right -52px;
89}
90
91div#menus table tbody tr td div a {
92 background: url(../images/menubarSprite.gif) no-repeat left -26px;
93}
94
95div#menus table tbody tr td.selectedTab {
96 background: url(../images/menubarSprite.gif) repeat-x right -78px;
97}
98
99div#menus table tbody tr td.selectedTab div {
100 background: url(../images/menubarSprite.gif) no-repeat right -130px;
101}
102
103div#menus table tbody tr td.selectedTab div a {
104 background: url(../images/menubarSprite.gif) no-repeat left -104px;
105}
106
107div.clipperzLoginForm div.loginFormHeaderBox {
108 background: url(../images/loginFormBox.png) no-repeat -3px top;
109}
110
111div.clipperzLoginForm div.loginForm {
112 background: url(../images/loginFormBox.png) repeat-y -408px;
113}
114
115div.loginForm div.loginFormFooterBox {
116 background: url(../images/loginFormBox.png) no-repeat -813px bottom;
117}
118
119div.clipperzLoginForm div.registrationForm {
120 background: url(../images/loginFormBox.png) repeat-y -408px;
121}
122
123div.clipperzLoginForm form.read-only table.formLayout, div.panelform.read-only table.panelBody, div.clipperzSubPanel span.read-only, div.read-only {
124 background-image: url(../images/read-only_background.png);
125}
126
127div.registrationForm div.loginFormFooterBox {
128 background: url(../images/loginFormBox.png) no-repeat -813px bottom;
129}
130
131div.loginPanelSwitchLanguageBox {
132 background: url(../images/languageBox.png) no-repeat 19px -15px;
133}
134
135div#directLoginsBlock {
136 background: url(../images/directLoginBox.png) repeat-y -262px bottom;
137}
138
139div#directLoginsBlock div.directLoginsBlockHeaderBox {
140 background: url(../images/directLoginBox.png) no-repeat -11px -13px;
141}
142
143ul#directLogins {
144 background: url(../images/directLoginBox.png) no-repeat -513px bottom;
145}
146
147div#directLoginsDescription {
148 background: url(../images/directLoginBox.png) no-repeat -513px bottom;
149}
150
151/*
152div#recordListFilterHeader {
153 background: url(../images/cardFiltersSprite.gif) repeat-x 0 -114px;
154}
155
156div#recordFiltersTableWrapper {
157 background: url(../images/cardFiltersSprite.gif) no-repeat left -38px;
158}
159
160div#recordFiltersDIV table {
161 background: url(../images/cardFiltersSprite.gif) no-repeat right -19px;
162}
163
164div#recordFiltersDIV table tbody tr td div {
165 background: url(../images/cardFiltersSprite.gif) no-repeat right -38px;
166}
167
168div#recordFiltersDIV table tbody tr td div a {
169 background: url(../images/cardFiltersSprite.gif) no-repeat left -19px;
170}
171
172div#recordFiltersDIV table tbody tr td.selectedTab {
173 background: url(../images/cardFiltersSprite.gif) repeat-x -57px;
174}
175
176div#recordFiltersDIV table tbody tr td.selectedTab div {
177 background: url(../images/cardFiltersSprite.gif) no-repeat right -95px;
178}
179
180div#recordFiltersDIV table tbody tr td.selectedTab div a {
181 background: url(../images/cardFiltersSprite.gif) no-repeat left -76px;
182}
183*/
184
185div#recordFiltersSearchInnerPanel {
186 background: url(../images/recordFilterBackground.png) no-repeat -10px -138px;
187}
188
189table#recordListAndDetailBlockTABLE {
190 background: url(../images/cardBlockLowerBorder.gif) repeat-x 0 bottom;
191}
192
193div#recordListBlockHeader table.recordListBlockHeaderTABLE {
194 background: url(../images/cardsBlockRoundCorners.gif) no-repeat right -51px;
195}
196
197div#recordListBlockHeader table.recordListBlockHeaderTABLE tbody tr td.recordBlockTitleTD {
198 background: url(../images/cardsBlockRoundCorners.gif) no-repeat left 0px;
199}
200
201td#cardBoxLowerLeftTD {
202 background: url(../images/cardBlockLowerRoundedCorner.gif) no-repeat left -32px;
203}
204
205td#cardBoxLowerRightTD {
206 background: url(../images/cardBlockLowerRoundedCorner.gif) no-repeat right -82px;
207}
208
209div#newRecordInnerPanel {
210 background: url(../images/newRecordPanelBackground.png) no-repeat 0 -165px;
211}
212
213.resizable-textarea .grippie {
214 background: #eee url(../images/grippie.png) no-repeat center 1px;
215}
216
217div.Clipperz_recordFieldData div.passwordBackground, div.passwordEntropy {
218 background: url(../images/entropyBackground.gif) repeat-x 0 0;
219}
220
221div.Clipperz_recordFieldData input.scrambledField {
222 background: transparent url(../images/scrambledValue.png) no-repeat 0 0px;
223}
224
225div.Clipperz_recordFieldData input.scrambledField:focus {
226 background: transparent url(../images/scrambledValue.png) no-repeat 0 -16px;
227}
228
229div.directLoginCollapseLink {
230 background: url(../images/directLogin/toggle.png) no-repeat;
231}
232
233#mb-dlg .ext-mb-progress {
234 background:transparent url(../images/default/basic-dialog/progress2.gif) repeat-x 1px 1px;
235}
236
237.ydlg .ydlg-hd {
238 background: url(../images/clipperz/basic-dialog/hd-sprite.gif) repeat-x 0 -82px;
239}
240.ydlg .ydlg-hd-left {
241 background: url(../images/clipperz/basic-dialog/hd-sprite.gif) no-repeat 0 -41px;
242}
243.ydlg .ydlg-hd-right {
244 background: url(../images/clipperz/basic-dialog/hd-sprite.gif) no-repeat right 0;
245}
246
247.ydlg .ydlg-close {
248 background-image:url(../images/clipperz/basic-dialog/close.gif);
249}
250
251body .ybtn-left{
252 background:url(../images/default/basic-dialog/btn-sprite.gif) no-repeat 0 0;
253}
254body .ybtn-right{
255 background:url(../images/default/basic-dialog/btn-sprite.gif) no-repeat 0 -21px;
256}
257body .ybtn-center{
258 background:url(../images/default/basic-dialog/btn-sprite.gif) repeat-x 0 -42px;
259}
260
261
262
263
264div.Clipperz_PasswordGenerator_button {
265 background: url(../images/passwordAssistant.png) 0 22px;
266}
267
268div.Clipperz_PasswordGenerator_button.hover {
269 background: url(../images/passwordAssistant.png) 0 -1px;
270}
271
272body ul.radioList li h4 {
273 cursor: auto;
274}
275
276/* ========================================================== */
277
278</style>
279
280<![endif]-->
281
282
283
284<!--[if lt IE 7]>
285
286<style>
287
288div#newRecordPanel {
289 position: absolute;
290 margin-left: 0px;
291 width: 350px;
292 height: 160px;
293}
294
295div#newRecordInnerPanel {
296 width: 350px;
297 height: 160px;
298 background: url(../images/newRecordPanelBackground.gif) no-repeat 0 -165px;
299 /*background: url(data:image/gif;charset=utf-8;base64,R0lGODlhfAE+AeZaAP///zYxbERAdu/u81FNgPX1+Ly6znx5n1NPgUpGevPz9v39/ff2+crJ2NPS34yJq4WCppKPr9LR3jcybezs8fz8/b+90PDw9D86cvv6/ElFejs2cGJfjJOQsMC/0cPC02Nfjezr8d3c5n98oeHh6Y+MrWxok8fG1lVRg+vq8EQ/dunp76GeurSzyKGfuoF+o4mGqW9rlv7+/p6cuJeVs83M2vPy9kdCePDv9MG/0tnZ49nY43VymkhEeZqYtTk0blBMf9fW4khDeV1ZiDgzbeDf6FdThDw3cHVxmkE8dKWivXJvmEA7c0VBd09Kfn16oJyatqakvqqowUM+dc/O3FhUhYB8ouXl7MvK2UtGe////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAFoALAAAAAB8AT4BAAf/gFqCg4SFhoeIiYqLjI2Oj5CRkpOUlZaXmJmam5ydnp+goaKjpKWmp6ipqqusra6vsLGys7S1tre4ubq7vL2+v8DBwsPExcbHyMnKy8zNzs/Q0dLT1NXWyhkGBwgYAd7f4OHi4+Tl5ufo6err7O3u7/Dx8vP09epEGhw+RZ4WBPYAAwocSLCgwYMIE4qbMIKCpgURFEqcSLGixYsYASaQkClixo8gQ4ocSZIdkx2XLISD4KAAgJcwY8qcSbOmzZs4c+rcybOnz59AgwodSrSo0Z0VVrT49y2BjUoZmAbQ0OCo1atYs2rdyrWr168xGTwAB6OSAXBVwapdy7at27dw/4la+fYjBKUD3yDE3cu3r9+/gHUWAPKNBSUE3xwEXsy4sePHRKF8M0GpmzeXkDNr3szZb5BvKiiB60y6tOnTR2WAE/0NtevXsGO/XD1ptOzbuHMvpi3Jtu7fwIN/5R3Jt/DjyJMDJQ7JuPLn0KPP/sbam/Tr2I8zf+Q8u/fvqLc76g6+vHnI4huRP8++fd/0jNa7n09fLfxF8uvr33/1vqL8/AUo4E/+JQLggAgmWFOBiByo4IMKMniIgxBWGKCEhlBo4Yb0YViIhhyGeJ6HhIAo4onekTiIiSi2GJ2KgrDo4ozIwaiFjDTm+JuNOOroo2w8tvbjkC9SV5uQRCZZo/+RvSGp5JM7Mlmck1BWCaSUzVFp5ZbhYcmdllyG2VmQ1olpJmlkBnDmmpulyeabj7kJ55yByUnnnXzZieeebunJ559g+QnooFsJSuihVhmK6KJDKcrooz45CumkOUlK6aU0WYrpptN5U52anIa6oJfjgSlqqJqeOmmqqj7KaquLvgrrobLOOmittv6Ja6577srrnb7+Omewwr5JbLFrHousmcouG2azzm4JbbRVTkvtk9Zem2S22g7Jbbc+fgtujuKOO2O55raIbronrstuiO6+u2G88lZIb70P3otvgvruO2C//l5IqnqmBiztwPEVbHC1COOn8MLYNvzfwxBvK7H/gRRX7O3FDWascbgcT+jxx+SGnOHIJJ9r8ocop6zuyiW27HK7MK8o88zw1hzjzTjPq/ONPPds7889Cp0v0UEbHSHSZSr9I8BOXwd11EV6emTTVNM4ddbKbc31klY3ifXXKHpNdnBmnx1l2FOOrTaHab+NW9xyX8l2lm7XDSHder/Gd99d3v1l3oAj+HfhpR2O+JhMg7r40oKXSvjj+ylOeWaWXx5n45obznnnAmYO+m6fj1556abXJ3rqfq3Oep6ov96e67LDRXvtfcaOe3m3775W774Hqnvw2QFPfFfGH1/o8MpXHcCnzX+XfPT9MU99ctNfb1T22hPFffdCfQ/+/3LWj7/281c7bj7Y6Iut/vrCiQ//TvLPX2n59sdWf/427c9/pvj7X+Da17b3CdBuBMSbAQ8IG/8xsFMJHNwCHzhA6FEQgRa8YAMDqEHNOPCBH2RgCA84QgGW8H8n5F8K87dC+7Vwfi+EXwzXN0Pz1XB8NwRfDru3Q+318Ho/pF4QozfE5hVReUc8XhKJt8TgNdF3T9xdFHE3xdpVUXZXfF0WWbfF1HXRdF8cXRhBN8bOlVFzZ7xcGim3xse1cXFvRFwcCzdHwNWxb3fUWx7rtke59fFtf1RbIM82SLIV8muH5Fois7ZIqjUyao90WiSVNkmjVVJol+xZJnG2yZl10v9ln0xZKEk2yo+VUmOnrFgqIbbKhbXSYK8MWCz9Nct91RJft6xXLuW1y3f1kl2/TFcwzTXMcRUTXMfsVjK1tcxrNZNaz4xWNJ01zWVVE1nXLFY2hbXNX3WTV9/MVThtNc5ZlRNW52xVOlW1zlO1U1TvRBUHO4ieedLTMfHkVD43tU9M9fNS/6RUQFdlz3syZqCQQqirCmrQOjG0oX9RKKMkGquHQvQ9Fr3oXiiKKI7SKqMafcsCbJSEbyggpJuRwDduQAkUfIMKKNUMDb4RA0q84BsHiClkLpCFb0SBEjkAhwd06hgkfGMDOKBEBYzwjSkYgKiBucATwNEBS5wgHDzF+MAVBsDVrnr1q2ANq1jHStaymvWsaE2rWtfK1ra69a1wjatc54pWCuhACT0ABwEYcIkZlOSvgA2sYAdrjyaQIBMumABhF8vYxjp2JAgQwSZqMITHWvaymM2sPI5QAgV4AgsPAIETBEDa0pr2tKhNrWpXy9rWuva1sI2tbGdL29ra9ra4za1udwtbIVRhCVJIwTWGS9ziGve4yE2ucpfL3OY697nQja50p0vd6lr3utjNrna3y93ueve74A2veMdL3vLaIhAAOwo=) no-repeat 0 -165px; */
300}
301
302div.newRecordInnerInnerPanel {
303 background-color: white;
304 padding: 0px;
305 margin-left: 15px;
306 margin-right: 15px;
307}
308
309div#newRecordPanel table td.newRecordPanelLabelTD {
310 padding-left: 0px;
311 padding-top: 3px;
312 font-size: 9pt;
313 width: 100px;
314}
315
316div#readOnlyBanner {
317 background: url(../images/read-only.gif) no-repeat fixed -5px -8px;
318 /*background: url(data:image/gif;charset=utf-8;base64,R0lGODlhjQCSAPe9AP+SAP/////If//Jgv+fIP+ZEf2SAv+lLf+oNP+iJv+XDf/Jgfv///+aFf6SAf+UB/L/////+/+oM//krv+yTf/IgP//6v//9+n47/+rPP+7YP//7v/Tjv/NjP/Kg/+TAP+2Vv6dG/+dG/+WCvuTBOX47/+SAf//5f//8ur///+dGv+vRPiUB/+SAv/Nf/+TBP+/aunx3/+7We7//+3q0Pu/av2aFff///myTf+yS+Pq0P+2UPTTmf+rO/rq0P+/Yv//4P/ep/+7Xf//3P+yR//YmP+lK//Ea//EdfmdG//qtNz//+D47//enures/HYpv/47//es/7EdfXEdeD///ufIP/41fqvRP+iI/+vQ//xxP/ku/SyTf/esP/NhP/Ice/Tmf/eo/yXDfDIgP6rPP/IevmoNO747/+aE/+fHPyiJv/Tmf+/Xf/42f6WCv/xwODx3/+UAP/YlP/Tif6oNP/45v/EZ//Ynf/40P/xzvy7YP+oLvnIgOX///mrPNv47/3kwfjes/+rMv/Thfm2VuvTmf+2S+Lkwf/kt+/es/e/aujq0PeaFf+/Zv/x3/L47//Yj/2lLf/qy//emv/43v/Yof+rNvrYpv/xyf/Ypv22Vv/4y/+7VPPes//Nev/NiPbYpv/IfvDkwf+XAP/44v/xu/Lx3/f/7v/Tkvb47+r/8v+vP//kqfK/avO7YOfkwfHEdf/EcP/qxvWWCvHq0P/EdP/szfXq0P/Idf/YpfilLf2yTfOdG////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAL0ALAAAAACNAJIAAAj/AHsJHEiwoMGDCBMa9ACgocOHECNKnEixokWHAhRq3MixY0KGF0OKHDkyo8eTKFP2AkmypcuWJlXKnLnwpc2bFWPS3CmTJc6fOHXyHOrRJ9CjMIkqLYq0adKlUBUOcEo1pNCoWAVOrcp14tWsUbd2HYsRrNleYsmO/XqWaFq1XNm25fkWLlW5c2nWDWlAld2LePPK3BuSSwBOfykGFpySsEgqJxJLXMz4pOOKJEQ09BOgh+SHlCt3vByxhmcDKQJEKQCACZ7PDUOL3kgaopsAASQASOAD9xokAbB8lj1bqksCuHUDKJAJdwAlkokXR1h7IvLcDh9UwK3ir/TpBqtT/7yuvGGVAF8sgrEE9Dt4guIjJkDCmrxDENgpsmCg5af791rZpIdznl2XQUNLcHDRGAGkcdN/AMYXEQQwUMBAAFkAgFwOISXQEAkQsGIThO9J+NABFYTRUAMXZvhASGAEUAcCALgSAGtPAdjYTVQE0N+KFxohkgId4EYKBTdAkqOOluGEWgBlOBRCECFlAIOHLcBwYQAXxFESkzu+9AACmj3pAkkxOEdlQytAEAAuIpEInokOaeAcJQ886YVIXGzQQAG3BNDEQ31sYhWYKNHZ0BUBUFDAGgFEhtoEIUnhyB4OLRJAdwA0cMOgFsk5naIIntkQHwHsAMALIYWAmwwOJf+RakOKWPBBqIg2aZMBEMjhEK92kHRAABFoBgAdAaDxZa6j/aRDfiQwoOpFDSCgAADDBlABcHvGyWyzP9mAWwUHnAFESDQ4hwq2uFVyrbff0kYSjhBpoKGbAcgS0isbiEDAIwGcOWyx8MZr3EgNBEDpQzwEsEpDBYwQkrjCNYRBl+wG4CGuBh88kgPpLgxAw0e4dF55ugTXEB0WvJhTxx631InCAIBYsktuMGDrZhHcWjDMBi1gEwFF0txCSw8kcO0UAaCwAgXoLQt00AIGoAEBvYkskia4XXArDM7VIvXUBAn9kgMQeOKQKDSLxCgFB1x7dAsFsPoz2QKZ/RKvpgL/MMuFN1+0RN8kzKAsSaIWpzdJIxwIQB8RcMrCKfbyBQGoywUA69h497L4SPhFqiFuV54xCUnPKseCxpzj/blIOFyQQJEWAICAc5HNO+4Bppx7t+t73yCkGbjZ6kACBLxEwA245eEzYJ2XbdN5ghjAwAOFNE2vRSYcHVHErZP9+kgGfAIAHEQAwEgAa14UCG6SvPtS4rONH5LdAIgrpBOGiKQDChnYzhBGFL2B2M8iDZjBuAAgBucMMCSyGgUApnACE1DAJfQTzQErsp8uIAAQAWADADIAhVyMJAQReMEYaseLCCwpejaBxQNLMAgTOI4k4gpAGxqCgw0groAEGQkB/w7gEB28wQRUmAMADlGKkVCgck4IACIUcLsfhK9zIkkXl1jTCtxECQB/8FVI0hSAlgEAFM4JxRWxeJE0daA30DGAAjUwgu1sjyJmuAACirSBF40gARL7HRDb2JmG0OANDVGAAom1MYtIIRWYAkANAtDHFwJRIBVxAC0CQMSGOCECUOjCipJHkRDcoSGu0pxDJunDNRawIpHAjRAasosAQOFCG7ijRJiQu4yRcoIcEuQle2GR21ltBQGIRUMuQcmKXMsAAFCDinyJwWEi5CLGDMAs6yS/iCRMQQAoQQCK0JBsdVKY1gyJMbd5ERMYAAMBUJADxElOdgXzUNa8pjpx0/+Ii7jKQfCUJz0T6cp0isSYVqwIHF5jsXgCYJ4BOGVBDXpQFHRzlygAwQUaKk8MaI1j+UxIS0xAkRrUDqENcUBAHzrRfCJlP8G6DsEeCs/N4TOkCkFKAQKwhQ7YAgG3i1xDDNCBloa0KQ27UUPIQCxOGfWoSEFVAPLgEKYGoAFPhapNXpABEHhoBQpomBUccoWPvgynHbkJ1Jwju4Y8IQBjtSRaRfoSHMhoBRnoTX7eGld0ztUgLwHRDh0iBS75LBH3hN5f0+oSNczqIW8VoVwXq8+WECIA6XtIA6HzQ8oytiWywgRE0GbWs3qWIzYRpxIdYtfM3vS0G7FJwnjagAft4Md3r4WtRm5CgC0Vz2WK1S1qb2IAEEQhChf0q3ALMpzleiQ6zn2ud6IrXbhkcK52uS521aLd7a6FuikhS3f/+l3whjcu5lUJetN7XqeM17N3Ya9M3Cvf+SLlvbC9b31nchT86rY9+6WJfwIs4AcRuMDzOzCCJ6vgz3a2wfZ9MITVK+EJtze3FkZJVjMMWAxz+CQe/nB1FSPiBU+mxCaGiH8JTGIUpzg2Lt7JiWOc4hU3WMU05glocqxjGPNYxgCwsYUrIOQfG/nISE6ykpfM5CY7+clQjrKUp0zlKlv5yljOspa3zOUue/nLBgsIADsK) no-repeat fixed -5px -8px; */
319}
320
321
322
323ul#directLogins {
324 height: 200px;
325}
326
327div#recordListBlock {
328 height: 200px;
329}
330
331div.clipperzSubPanel {
332 height: 200px;
333}
334
335
336
337div.Clipperz_recordFieldData input.scrambledField {
338 background: transparent url(../images/scrambledValue.gif) no-repeat 0 0px;
339 /* background: transparent url(data:image/gif;charset=utf-8;base64,R0lGODlhRwAgANUmAP///7XV/2ZmZqW/4ODg4HBwcGttcJChuLi4uHZ8hYWFhfX19bDO9YCLmZmZmaOjo4aSo6C31tbW1q2trXuEj4uarY+Pj+vr66rG68LCwpWpwnp6eszMzHF1epuwzMTd/7rY/9Pm/8ng/7/b/87j/9jp/////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAACYALAAAAABHACAAAAb/QIBwSCwaj8ikcslsOp/QqHRKRV4QkmQGkbxmkVtlGGkyLSUCLtIiSKLVR7ZSTjYfLwvAW0gY9gF0eEKCewB/hkKBeXyJbQCCRGVIDgIOE5UPBQV8AhsTCmmgapSWmJqcnqKiqJ+haUJlsbFFCKACt50TeQSZuLcOHEK1vrm7vb7AfMe4yQCyskcEBbcZRw+3CotE0tTW2NpE1wLZRtBI19fk25qU1UXo4+CG7ALu6wXt5bNHHAIWAAgEPCgCSsICTYcA9PsXcCCRggcLJAQAEWEkO5KMcNhwIREcAAssCZGgIOHGjoA+hpwwsiSRlS0TZsxYpabNmzhz6tzJs6fP/wBAgwodSrSo0aNIkypdyrSp06dQo0o1iuFAhKMaDhytetVoVqRfjZZJGkGAVqMUBBwte7ZoWqRvxZqgyiAAW6ADguYNEBdD3QB+7ZrFqxdo378B9h4G+gHo2AAjQAhtIKBBhcoQDBjAK6BDhQRmQZ+lbBmzZs6eRYtG/Tn04A/PYpUQegC0L891B2Qm1sAD0NrEcCfe7as3XuK4jMOObYIE0QEGbmkoCuFWAsR6owuYTrS6gOvUrWN3HEty+OrghUI3QJm70Orox69v/1wzfaHLy4Qo6kEAhQAHCADBUKBFwIBmewHV338BDihUgQcakCBQECIoVBkigFBGY0N50DIBBoa1FQADlgEVQQITeggiXyKSWIGJKArlIowJajhXABtOpeOOPPbo449ABinkkAEEAQA7Cg==) no-repeat 0 0px;*/
340}
341
342div.Clipperz_recordFieldData input.scrambledField:focus {
343 background: transparent url(../images/scrambledValue.gif) no-repeat 0 -14px;
344 /* background: transparent url(data:image/gif;charset=utf-8;base64,R0lGODlhRwAgANUmAP///7XV/2ZmZqW/4ODg4HBwcGttcJChuLi4uHZ8hYWFhfX19bDO9YCLmZmZmaOjo4aSo6C31tbW1q2trXuEj4uarY+Pj+vr66rG68LCwpWpwnp6eszMzHF1epuwzMTd/7rY/9Pm/8ng/7/b/87j/9jp/////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAACYALAAAAABHACAAAAb/QIBwSCwaj8ikcslsOp/QqHRKRV4QkmQGkbxmkVtlGGkyLSUCLtIiSKLVR7ZSTjYfLwvAW0gY9gF0eEKCewB/hkKBeXyJbQCCRGVIDgIOE5UPBQV8AhsTCmmgapSWmJqcnqKiqJ+haUJlsbFFCKACt50TeQSZuLcOHEK1vrm7vb7AfMe4yQCyskcEBbcZRw+3CotE0tTW2NpE1wLZRtBI19fk25qU1UXo4+CG7ALu6wXt5bNHHAIWAAgEPCgCSsICTYcA9PsXcCCRggcLJAQAEWEkO5KMcNhwIREcAAssCZGgIOHGjoA+hpwwsiSRlS0TZsxYpabNmzhz6tzJs6fP/wBAgwodSrSo0aNIkypdyrSp06dQo0o1iuFAhKMaDhytetVoVqRfjZZJGkGAVqMUBBwte7ZoWqRvxZqgyiAAW6ADguYNEBdD3QB+7ZrFqxdo378B9h4G+gHo2AAjQAhtIKBBhcoQDBjAK6BDhQRmQZ+lbBmzZs6eRYtG/Tn04A/PYpUQegC0L891B2Qm1sAD0NrEcCfe7as3XuK4jMOObYIE0QEGbmkoCuFWAsR6owuYTrS6gOvUrWN3HEty+OrghUI3QJm70Orox69v/1wzfaHLy4Qo6kEAhQAHCADBUKBFwIBmewHV338BDihUgQcakCBQECIoVBkigFBGY0N50DIBBoa1FQADlgEVQQITeggiXyKSWIGJKArlIowJajhXABtOpeOOPPbo449ABinkkAEEAQA7Cg==) no-repeat 0 -14px;*/
345}
346
347
348
349</style>
350
351<![endif]-->
diff --git a/frontend/beta/css/clipperz/ytheme-clipperz.css b/frontend/beta/css/clipperz/ytheme-clipperz.css
new file mode 100644
index 0000000..71ca4d1
--- a/dev/null
+++ b/frontend/beta/css/clipperz/ytheme-clipperz.css
@@ -0,0 +1,141 @@
1/*
2
3Copyright 2008-2011 Clipperz Srl
4
5This file is part of Clipperz's Javascript Crypto Library.
6Javascript Crypto Library provides web developers with an extensive
7and efficient set of cryptographic functions. The library aims to
8obtain maximum execution speed while preserving modularity and
9reusability.
10For further information about its features and functionalities please
11refer to http://www.clipperz.com
12
13* Javascript Crypto Library is free software: you can redistribute
14 it and/or modify it under the terms of the GNU Affero General Public
15 License as published by the Free Software Foundation, either version
16 3 of the License, or (at your option) any later version.
17
18* Javascript Crypto Library is distributed in the hope that it will
19 be useful, but WITHOUT ANY WARRANTY; without even the implied
20 warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
21 See the GNU Affero General Public License for more details.
22
23* You should have received a copy of the GNU Affero General Public
24 License along with Javascript Crypto Library. If not, see
25 <http://www.gnu.org/licenses/>.
26
27*/
28
29/* @override
30 http://localhost:8080/pm-restyle/css/ytheme-clipperz.css
31 http://proxy/css/ytheme-clipperz.css
32 http://proxy/pm-497/css/ytheme-clipperz.css
33 https://www.example.com/css/ytheme-clipperz.css
34*/
35
36/* @group new Message dialog */
37
38#mb-dlg .ext-mb-progress {
39 height:18px;
40 /* background:transparent url(../images/default/basic-dialog/progress2.gif) repeat-x 1px 1px;*/
41 background:transparent url(data:image/gif;charset=utf-8;base64,R0lGODlhHwEPAPQAAICAgLrW8u70+/X4/Pj6/ff5/PD1+/P3/M3h9dHj9s/i9eDs+Ovy+ufw+uTu+cvg9bzX8t3q+Nvp98rf9MXc88Ha88bd9Nno99bm9tTl9gAAAAAAAAAAAAAAAAAAAAAAACH/C05FVFNDQVBFMi4wAwEAAAAh+QQJCgAAACwAAAAAHwEPAAQF/2CGXaRlVRR1oqY1TZUpzVJk3xMEUW/vvpVY7UaMPB47Xu/1Ew6LttxuuTzJoLcjhPoDorBE5Jbbi1meUG2K6nOBcbpqF5Z6G5HsiQn2tYvzeid1b2pKbXxnIiQXJigqQSp7MDI0UFKGTGVChEhrZJMzb5eAVmecYz5LkHZGcZ+TpmCFpG52UnKqg7J4bHurfq69ghR+nZiBiBIODQwMC0EKCQkZ0tTSCAgUDczN3c0LzwrR1dLl2dre6Q4pR0fk5Qno6d3gFO3u7/Hb893rFOPlrElLwY2fg3X3HsDLQE1bwXn+7sG7RpBfs4MU8gUcuM/iAnbtJiY49zBdPXETGf+Wc2iRgb9xAss9qOit3YgLN28ysrDggM+fPw3Y1LloEc+eQA0Y+GmzqFMTSH0qBeqOYQSnRqNKBXqgKdYS4LgeWOpz6FewYrd2PUL0aVixU6tmuIoValqpQtmeZfQ2KVOFVr/avVtW79mjPmsazmmUJ+G8DzC0LYo4Kdm1kfcOxksV8NzDWsdy9Sq4b9C/kSdnvUuWdF3TQZfKpfvUMWvIqsGGFl142ue6tgm7dqs1SqUIlWb4LsC8ufMFRy4cpyGhmvPrBcA9mE69OkPsz6N3R658Gvjm2sd3N3+eOfTt6stnaJ8devfk3ulnFz8e+fL22pFwXw3W0ffegEP8d17/gNINWGBzeX113ARcEWChhUo9IGAo3e0E1IUXRhgfDRQeACKISk1wFnUvmHhiiC80OAR1JFD4YohCbUgdeRK0eCOGMWJFQwku3pjiijNcUOKPBIg4IHI+/nikjDxKUGOFJxoQ44g9lugTAQVEKGQoEXj5JYo5UtmhCR9myR9+JJ754pRjzhClkVuSSaOSRc6Z5n083jlnkE4NyUifWWqJpJVLSvmmeoImqqKahpqJaJN5wtnlhwX4RpuOZU7gAH3V2FBUd6KO2p6nhdJwxG4HNFfqp909AA6ps546w6u4sqqrBA8cRGpgvwJra1qyVvPbIq6quqo0mjIKm0/JzkWr/6u26lfOjlWmep19Ay6ioHMXOvAojQ+Sa+FBGkqo3HfYlRvdiuk2V665Ou45rr3rzttqddIwSQC7+RpajsDmtntWvczdq/CYASPs71f7NrwuvntdEPGJ4N4nLrzXyashghqzF/LFD/9acQEi7wXwfPGiXHCSGoOs7sATM1teAghjHG7JPDOZcMYMsywzkhv/OPReKzuccck3WuCynXKeWJZkOKlmggECnzukNI2+6NOkhtbGNZNeJwm2UlIqKqNgFpz942KHsW2k2+52KfegEzAm2N6SCrhi2GK/4HdRktn4IgJ5vwBrrJ0moMCiE9z6bAJlUxYcUMlO3rjl55XTeLLluHrubuWwyiqOy473mjlloIO3Lc21LeA67W5pCy3ujUV1HeN1On4Xc9KY/i/qt1sJXOrES0557NiJHjzpzxrfKurIEr/64NSHvrvyr9l++esl8JQ8aLpjznv5vjs3AtZOYSCOgZliVbyBC5C9vuQKGEh3/PIbwAAWBB34taocA1zQ/xAXwARiBxx9e99k5KcABz7QMBSThgAJqD/wiQsbFvzWAhchmQoCqICq2VkImxMCACH5BAkKAAAALAAAAAAfAQ8ABAX/YIZdJClNE1RVlOWiMCtJUW3bKQRb8POkFMptGPHpYBPe5AeBCIm3RxOJUk5YT2gEdbQiV1mt9JjscYPaGpeK8l1Z6do46Y2h00bkyw2Ob6d6VlhxeTs8fCIlJlxgLnUyNFo5Oz1Md2JSVEpMTn5zmnZhRGtlbH2EgKVLZ6JDpFR8cKg6L6aXUIVVhz+naZOBoYSZhku8Dg0MyckLKwoJCRnP0tIUyMrXDAsLFAoK0dMP1A3W2MkOQeHQ088IQeTlDuc+0t/pCdXv2OcU9OvP7uWUaePmjF4Ge/gCmkPnT1q7agqzbes27Zu4fNf22ZOW7iFGZfH4GUwwD0G7cRH3/xVs2C7ZgZcvfTwYcYGmDQwuFsDcCXOeIkU2Huh8acAAzwMyf5KwYUHbgaJHDSRVeiHChZxEj8Z8RpWp06w7pYajWvVqU55Gd6brKucr0bRPp/5kehYtXLlASTQd+hQt3p8SsGp9KpWrUq8u1fqgabMGzrqDfbItwhcqz79La+wlHBXzUrND4V42PFezW9Fxx3YFjXZ0gslC+XIm6pmu7Lc9fay+etqvbrKBIUct/PqwaZ5qasygMSNohgwFoksvALPIg0jLI1mHPr27tgfKs2vHwL079egLfCyPsN6qNPPTvzcXL+dB+e7V1c9vLuc5/JcFyJcde5H4cN90MKV3Xf974/kHH3rpiafdBc8cKF2C+rVnw3vmVVeEhOORFx1MYl0wg4n8lWABTAS0SACART1gAn01mHWAiy6SqNt+IU5gAI4tkigVYM2V4OOPQOooY3j8WYUCkjjCaMAEMzJHg4ovAflidFNSeSKIT2oppIyKtIcBBhOwGCVRKKCoYQRopinmW2QSmCIJR4rZYok8WoVnmgdQR5uMX955lZpBBhpjlRraOGdqKNp5E5pQ5kgnkVfiWdSjJTI5YZhJKjpllQT6eeiNSXLZZqHigbomYWSWYCaaiCb61KoD3oQCqq8uWlWuRm6a5J47WpnpBbsGKp00sjZplgMPRscso9rtFW3/AdO6GckFPshmXrYgngDtf1sVR2pbC5CLlGrNVpvuteBqGNtOFwaaLancPjBuh9I+YyerE7il7HTxtjrBvg9Kg52G1koXz4LLleBnOtNp6UCGEQdlX8WJEvAwpjc5GF2O6P1WpgkcjgzkwxJ+RuGBLkqnYJknkiCNljiyLN5Pz+Ccs8lA1ZByARZfrBR/Bvrs4sWxUjV00U3nNQ+O0ekcscsUS2cxxidqfJ+lHhtNc4NfB1ly1Cai/AzHOV/cclkvdxfz2WOXcLPSVl9tdwJKt8j0ZE+vLDbN9WXQt8dAKxV422h/NnXMJQJmg6aVvigqlZPFySvJBXSprQRVmQpo/6iwkoViAq6KudjOk8pJelETnHmYka5HqSrmpfnpI6dDEimrBcL2igJNQcO565wECCAA7nMZmeXrwxv35+YHYNDN2DX64ABP3d3rpp8WxAMvacULBuCIL52pAMjoqmv9+u3aRi625M8YlMAXtvj+0TW6gHC91bOe6WbQlGsVYH/GiUDD8GOv+klMgQV03/VMt8ARIfBc+doevQhWv/XoRXzR8l5mIOgt9AUQfvFrX4fSN8FzkXB+ImzSvGCSPwJcUFb9C5/7BAicwLwrWjd8oAK1AUMHZiYnD4JJEH9SwQJcTHZHkwDqJnAtBRHvgflKwAAGwMAApQeKRJoiFxl4AEQrmu4ZCtgiA8PGPPsJ7RljhI8D2iS9eagRQS+RAxgVB8domZEsaIwjAPV4xRGS545yXMwZuyHI7sSjjSg63QQQGZ0QAAAh+QQJCgAAACwAAAAAHwEPAAQF/2CFXSQpmdMEWWzqplVFRXRNX7S6us8z+SrKzEZMQVKWlK83iQ2JtgfkiHwZhVCb0ar0TZ9EXES6U5qbWChpLH0xXc6sdsp9ycDQ3rH1NkLweVQTLVZ3cjR6g0lMDyIlJigqLElccVliOpQ/S1eAWipVP5tNMoeIdKEvf541W1xMX3JiZJpAQIZqOIk8QDClpjp1cGlyiXy9Oqw1bUiaw8pse4tLCw0M19jXCzEKCd7f4ELW2dkLCxQK3d4P698UDePk1w5CGeD3COLy2A703vYJ2PVwB2/fvHr3wOV7Z5CBOQrfMmQQyA5BvoIG6aFLGI5hRn//Elp8F0+eRnDsAv96W1iS3MMEEgOmXHmxZTaN6lAmuHagp8+ePR6MEBNBDAYL5n4qNRD0EVFdDxYYMKD0Z9MSeZJW7cm0h9OiN1gs2GrV26OsUsl2TfAVa4+xB6huTXmWSNSxU+eyqxslqs+8Sq+uKSFBAtK0W9c6vSAhLFKycZmaxWqDp16ha27QOKo1seDMYN8Cvsx3WeeqXR+0dQwXMl3KUczJRT2w7Zq3XMm+Bm0a72yre2Ev88v1N1CvWAkblq22ttPGRcVCnrqbKA2yOQpH0G43Q4Hv36uyKcy9qC6J4NP7NPeAfHlED7yrD99zQY/t3InGl5++gE9E7kE3HH/0/WTfA/gJaN7/N+od4F9PADaWH1QEPvjTeDQoiAh6/VkYoYBiXPBPfz99d+B7YI3BYYHr2edeHhb+5RV5mt1wgQU+EdCThVNNYMJ7JeB4AAFEopYCY+WtgUEKBhCp41IG+IhkY4SRIKSTRvpIY4ZB4oilgztSt4Z2WGGwZI46hvddlFoGWMMFTH75U48/QqfkmUMWudSRKN4Qp55zRvmjjTiYOUFPWALK5pTmvTlBjFzNmN+bN+a441+CMkpppXk+OSefSRb6p6eYSkljlZzK+ReoAp5gpZd6PliAmDiQeeehiKbp35qsblnUqKhluuWtuZLKFaiXAAulqXYS22meq7ZJ5VOPgudg/wHf+OpWVB1amO2Ldi3QrbfegIvkBXdday143wZIXgoOkBiYWb6Sd1eDwLGl6XDidutTuwpamZS1O373TZ0pstHvurtiW25hUyKZbof/PuwmfAuTaLDFrZLwQLwWsgfxYJntV4CTcp4IMaUSDHSynij3o9q+SHrzHZY3E+kAcoyZsAx6KMcqM3kkU5gzAQzvrBrRTn0TdNBDj9y0N09DzbN1G3r3dIszI2lXfFV7euBi+gEd9I4yr1bUP0iH7KKrOFBm8tb19UA0yy5/GfPOCN9QmM0v6+qk0qgKOPfZDkbtqnlGB560pHCX4HTYBChO9uSUEy5c1oGnbJ9yX2cQ9v96V8N2OMpo831WiGzzeKTPNpQwwVSxlvrVpsCqOWsKGKzMeASGPltij2Y+4jueW4c3kO+NLnmonF/u1qiftBdZ4KKwmXCUBU0CeukBUp5b9OzdGxvX66Ah6Xz5iIYZZfGDUUq+qrxOMFSIjMepLgbpaBqidOoqkJkUgDDQ3GtcBeAfAbPHGNwQbH/861uKuIWvf/VPW4w5DL7AM0DQEeox6vIJB/sHO/2YY4Mb05fxTqCwcV0rASRMn8dOSDByLXBzb5HX/mLIlwPukIDDYk3BHthBRhmQhuNSIF9M4MACcTCCNENExiB1ABgCMVTLyZgIv1NEr30QLg8c4Q3t1BuKFDpMhcqByhQZZsUlzlCLYOqJN27ImxaaUYmLKWMBBlAAc4QvjZyj2HccgL4QMZEdA+CjrLgGv0FlTZExGmQP7kcZEcEEku1LHCGLl6TCIBKSDzzQ/QglgTlicogya+RiYJhIitUNM2RTUQZOqS4/NpJS32jluJRGSblJBJQFYg8nT8CdHsxSkSEAACH5BAkKAAAALAAAAAAfAQ8ABAX/YFBdJCmZkjRBkDW98PQ8FUVFeH7lLwTPMlillisWV63XQ7Z81W7G4+rlismG0CiPZQU6bdEdrvdTColGUu7BZVpXYC1u5nvDWFk52+LyKmlxelx8dnhyW4RADyIlJigqLFVdgHk4YhFkf0FOaIdIVUt+T4eYUxOSP1ikmG0/TROjaTymm6+qaZdsdX53gVp0dncQlVF7fa9MsYI+hG+GpCuJoRUODNbX1wsLFQoKCd/g3wgIFA0N2OjbFeAP3+0z5OXo2NoU4fcJ4+Xn89YLNhncJZgBLh6/fvXwsdNnrp81BzYSZMjwrp04GwfnJVQ4kGFGdBDtBbwHD6NDBhsH/woUR66hQ4gTB1oMZ/BkPW/h2kVgcKCnz54GCKqxlAMDnwU/kxoI+q2EDh7akiYVOtTIDKRSgTJN4FSMmAlRs/akeknHUbEHllrsqiaFBW0G0JINc3RpVrVNyxZ5ENWu1LklUkQ4KxZvowsSLLkNe3euEZ6N21W9ZPQtWrxcJ0PFKtaxVb6Xt3YliolxVs9mLRcWrcbp4gVxO0uumhp2bKWs9fS9/RMwisGq7zI9nDgCYglvOUsNOlsv2gOlIgguNrGA9azaHqQoblwMBgwZrIsvkHTBjO2/ql+/7jM7euM6voUfT76ndfPapxsBP79+efPvWbLDDP3ZV94M0hXXlv8EEhUoVXY4cFfEd/2Jd6B2T8EXwQPq+XeAeO7JYpx8FmJ3noQReuiTWiaQVtQEPRFg4E/MHVeEGhi8cAABMiZVAIuI6bBDCRYs1eNyM9gYWAk68ijcAy1G6MgFRRrQY3311SiYU5bwYaWM61m31ASPcHfCBTDuKJWYL9jYnQ5NHkmjAWTqVVSOMRaWpIKTeemkkyvS2SJtF6ioFZRBavhinh8qtaeEOMa5JpDctUZClXLS+Gh3iDEJI6C4IWrmlJjOmOWmXBrnJ5jkiTdmmTmcmWamH/7Y5nSTSbqcoHbi8N2sekLJ5yVUFvmnnK8GSeh4tR5AkH6pPuAAfSpaFOD/XtpQ21s77x23wwsL0FereOBsZ+52EzgwLXs/FVCufubOsK6hY31z7RrZimvfu5AOyFeJ4/bEr6Jz5NvqwQe8e9wJgoGr7U/8wiuBtPNaeN3AUg7ILo8OJGnpJTHxKPKRBbh3gpDFtSNyjCMT0HF+laZwATgrWzeyuqJGOQeHLV/ZE35nctrdSCJbTJ7JZzayIc89A7p00ofN/E3TIuOcqg4ht3yhm0I22PNP2UUdq3xfN3oAfqNpGNDGLns8ZFVZj+xTyQCeLGDKCay8Y8svB+gtzU7aXHXHU0pIYNn1Af3x0FPzaPTZdUOtxuFU9/R01CUATrXVtFkSt97tbXrj/8wTlf2zeWJHSLbWZqPdGmlr+0QApSLm+OmMtdJZZ1k44hk4wsl6VRWearYLVJuB2U3CC1/WLCavxL6NppGyA1qjpTpU9mWzge6OMpPUt8smmTK3JjPzoM45wXfECvYro1fyqHvaCaI5wfZzkwekV5x+V+S4BPiOArolICoZjF09wUA30EObq1BrPAJMVZTAArASKXCA0IpQcgD2EwH6rVNHqSB7Lsg1p2yQXeIJoAKjVBYHohCC3WiEzLpzQmaJJ4KTMUEI2aMiEnYOBzXMH3lwqLQ1/AuAHsRVAWuIwANckIEt/NcDrUNElI0hXC+szxMzKJ0gSiWJlQLhW0SoxZ4YQksNXkTiChMVRSz6hz4+RMHbmBimAlSxgMgZIw+TEkctpNFCRLyaAwcAIuTJMQfi0NZ1ssM+PJKgQYTE3c9mgIHkjU0ihPQQiMzDPi6JIQEKGEAki5c4SkJLMBbJJAfn0EhOnUmBonwje/BTScxhohuqRCEja1nEF4RylABs2wNqKaRHjiOX9NHG+ng5FKn9kllgMyXDJDQBXBYgBAAh+QQJCgAAACwAAAAAHwEPAAQF/yBFQRB1XdIprexEUlM8Pc/8VGKkX3ofxSVYTTar4HxI3eNlkw2DSR8QRhy6SlEpxGml3XK7JK0Us8qMlN5JDKERyzRcOhtZbt+225E+dnNtcnR1THhAWHRAbg8iLyoqLCtXVHCAYBE8SFNCb3pzfEx+M5qCU5wyL4I/d01wX56YPmNUZjFoarA9S6FcroJ2hV62fLpmir2fZIWSpC6KCIsUDgzT1NQLCxUKCgnc3d7R0tXVCyIP3OY03dAN4tUODhXe6ubcFA3s7dPwFej0CV4IRITLd42CvH8AA77Lp68cwoMJRODL986gPH807E1s58CiNy80AtpjyIAcBXr+5v+BY1gx3cWQEkl2pLDtX4IMFq4d2Mmzp5cwSDBYyNmz6E56asToNMrzJ52hC5juNGDgJyZYJ3JGlXrAqY8TWYlKpWp1DYusS6WmSwKLxlamZBOk0sq1K7dLj9RA5VrVnIodK8DSHYvUB860TJ3i0iFULNfCl5S+TUxD0N6xfR9E3ox3sNrKSMBeuAw3M14eZ0cjNro2dK4Hk4vGnbu6KFKwK/Q6Nto3wd9LgdHG7ln1bqwMXAsU+DHBVwbkXK9p3rGYRgblBYwqXwA6y4PnB5QzlQ6UMwYM18XvVH+A+/Qs6KEzLUD+lppu67XTB21WQi7w0XEXBVjdYCeVgJtVB+D/euy5l1SC3Mh34Hs9SGBBXVRNABZbWdV1QF8briHaUNrxlKFoPKCQQocYxiDaimeRyJcBGqL2WwTnTUBVduHJ5uKGOkASgwHiGTgVjTf6xxgGOhrQE3s0aohXEkzqOKOUA57QJF81AkndBTFwRQBZXupw4ZVlfnkmXzSEmKJga/LE44dIigbciqN5GOWLj6QgI2Y1RgBjDznumB9xP64RZAs6FgllnUoKSiiTVD05555TBjUkmlmAteVYXSr6ZZhSjVlVmgsYyB4B3Xx5CzcOGMmacUismMA7svbU6p2opQCro6oW0A0kxEowwTsl7rSroMXGMByDwtLqAwsP4Moe/4+sStufscfKeW20ci3Wgk6OyjlsYLm9lip7tiXAQoWRwrZuduwuu6KgqxKgLwEOVOYlgdzsK+e+77x3Yx3f7bSvwPr2a3BghIKn3MI8SXfwpBkI3GNPDrr5X3r0Zkdwvyi+eUE3C+urcMNtlgxwAimnXDBbO0SosaUOfgVLfDdzzJ2X8X6nMbYsa3aVD/kS7K+oL99cwMgGoxBLwgfEXDW/3am4s8RP32yx1FSiN3RRHYvY1nPBXs0vySiehnLKK2P9gMtNxww1zZfYrHJR23VHXcQZ7032z6IGHTgBhyptdHkRzIn4kYECJVqTc0IZAwb2ETpkuSbSeF6ahTp56P/VXZkDsXlDqoydxrelOCpPPX+YqBp4bj4n7Ec9h1cKk34a3sT67ilibp5OgGGdd56mJVWPd23i5bAQr6Xx3hLnOQYmi/b70+vtepWoOeXKYKui6nUNduhjx40Ctyh5AqzeVg7ug3je6kBd57FPXQqBwQ9tURjQxi1MloC0rA47+WMcY2hwP2ixJ4AK0NqUziOvYKEvgV/C02Vupytp+YCCBrxWN8rUv+01z3uuMtO89EO+xVxCK+lL3/raRx3/bc9by8JE/ZDFFQzuTms2FB8EB+i2ED4NgQFUII4YGL8HakOCawDhCmPoQ9zAaSsc5MmygoIBecXPXNwgoa8GECxw90jwKxFKW8W48zlHvOkmAyDjhB6AgXRJijHPGcAXdyKdz0nuZAlQQBybRzYaYC55ttIGGbPYHjZiz415g6MexeeeR7rpZIq8lsLeEarvAVKQkwRexQz5JRS8L5MxVE7B2ljK9cWRke0xpB0/mIEQAAAh+QQJCgAAACwAAAAAHwEPAAQF/yBFPSQEUdclrawURZNJTST92JV4vXw/xbPfj1Q69Y4vYJA2/J0oSJ9JeBPSKrkozymi1rgoLcxUtQ6xqF201B1+JzmoOAaxEs9ZMXtWez/FY3VmNg8ygGAjRWktLEkyNpAkcWpRXGZEhUaHT1RNSpuCTHZoh0peZU+USHRll2gpWnunQnGgdl8PpHqFXX2oIraDRIZzQAiYIg4My8zMCwsUCgoJ1NXWFA7Kzc3QIwkk1tQIydvN2RTW4OEUDQ3lzA6J1UTV49jvy/Ho1Jj14+34GEBTF66aCHf49M0riGBctoTx5vXjdzBgtwcF1wF8dy4cPXEVE4qYhqEkBgvPDv+oXMmSiJiTKFnKVIkxgaojKBfMbEkCkIWYOw8YMNAzAqUUSHMGpVnUKNIVF37qDDqUBCwWsFIoXVqTx00YE6buJIpRS9KUXKmpcPFibVSgQcG1hQrrxdaZVam9MHkSbdymSGCKjatWzN2dLg3DxUu2rVekUf0ibgoZqtSlVR9cpev08Myujo/8GCyTbAKzWiV/VrvCq+XFn8sapUvJ88q8p51Wm1mgwIHeYAHtXvpM89cX1DLw9t17AWAkCTIoD1qguNfAGKb/9i3TOeoLw1lyP2C9rlEeJbWv7L3d+Wbo0peSB4yUR3L51s/3kJBid+/x20VgVWhqgEcNft690Br/CfJVVV9bkEW1VG9k1fdgBBj8sB5jxs3GX4QTyCfUD5VhpZUFDRowwVNHJKUSgCypuCIPjeyl4YsrEaCjgwrS+OEFIb4I44gX9mjUTxPKeFOEQA5FlYrmOYXejSwRcBuJ+wn4QIrGHRUhitQVUGFW5mUY5G8cZkUbUmdSReJTJr6V4oopsPWYhGiOhaWCrdl45ng6EsBjBHbS9ueQUEZJaFtIUqdkiyA6OVaiPZRJZY5XzuhVAtlshylTNnm5RVgTFlDNfnW+8ECnS1UDFaH8sUDCAv+xx55KrjLSwgN+wWgqNbo2QoIDMv233ak+2hmWWNxZCaqUNUYglbFCriRb/7JIcUrsrXn+alOffEowa5jIwposrzpxu56rVyGQQI6BxuvAgBBCFl4B8eqYjXF29pBcvgfouN28mr16RHYZxDtTflqkh+NOzmkm5RHRKcdeoCsVZ2GE1WAccL4EM2kvNfmCPO91TvV3YLH46vvAY3eGx1vENGI3XbMC93ayfi+4C2/JId+Z7cq/AT1vqtBFB3DOBYRscA8IK9xdgg1n9/DCAyoaQcWeekyee2SOnIDHQFslsspjlxzoviiLvdzaL0MYM9EzN9XvXlbnibHOcatCgQEqORtjogXWVdKheL2pCmQ/GKDubZTu9+MEQwFqJYU/mORlCo3/57GYKpakH/8lhwe+nIwYzMVk4zIJXpXmPrJZeW9eK7mWU5NTjhmUrT3I5osCryfmBKL3rgKblD/+21DEMxkBrbRfTY0C9T5GDbEsH6sXpP1lUyu1B5SkANJ18jctt98nII0aP2aQGmkyTV+nW0M7AL7w1Wx8fGTQ40utt4GRzgVm9b2ZYGB9UirJWdJVwN/Ib34RGpd81IedLTwDfOOZnuR20D9nZZCCKbMep5ajvdxUKlve+954xEc+t5xvPOlDIKGQ4j7+TVB981vT9e4npPyF7UM58dz/yoUeARKwVgZEICwU+L7tINGBOIQgZCTYKuodLHVJuCD6VqLB2EVgAMayVXXoJTRl/wzpaw/Q3A5S4D4SKGAAAyAOCbB4NwxJB4zKK45J6oU2OA6Jb2ksHsekEceg6BEDH0qZgRLgR0POUXRMqkYhm/Wffe0xkurzY/BYEjEMPKVMd1RhxpyDxRIZ6I2FZBnBsIiEEAAAIfkECQoAAAAsAAAAAB8BDwAEBf8gRT1kCUGUpK5RtE4oNZHzU1diq+/Rc8q1EunH4w1FttlkubTkijoYirksSSnQKAxJo06c2Gzv5A1OKjhxz1ftKs/PrNRsRoflMJo7ibtDfVNtSVdqE1xCPyssLipbMno2JH1qgEBCJiiUPkhVXmCFP15WRGJLMVaecX9kojR2mhCCTHyqRXOoVq+leZGDtH5FlbNupHIIQgkJDyIODM7PzwsLFArJ1tYPCAgUDs3Q0NMk19jZzN/QDiLKD+PJJNze590U7uLjyxQN58/pIyXkCbTl07dPGr12ypJt47bPWT9299gJbEDwnMFL7fBVtKguo5CBDbtVqAfx2sKN3xz/VMDAEkMElhakHZhJs2YJKBcuYLAQs6ZPAwZIiMkZc4FPnxDF7Ox5lKY4HTmjvtwps+nMElEvqIi61KjVoCRW5IzAlapXq1iLbOV59ijYBDykEq2KNhnUrVHZWj3wFu+FHTDpNmXX0mXgtkdvFsnZdS9QoVnmIkZqN0vjvU9bZP17eO8BrFH9Xm4K9oHYv2WLek7LYy1T0pmhjpW8ujJZvxf0fhXnF7DZ2mNbLMlAs0CBA8aRF1ijJkEG4nulPWjuvPjx5DMXTG/+/Ohx5Nof/MWZLAN2nwWkx519wTl05EfDQ5XdvvrM5Nilq1ic071n+VJpplV5/2nXWmgSuPfd/30Lhjfeg1sRGJ12ikiQmwWePcbYZloR5d2CYGW1Q14YOmbABDphkJVfJTomnlanZcVThiSMR5+FF0wAlGMowijBiDktYQBNBBRJ04kossSIj0HuSNqJjLXwIyON6IjekUs8yGGTQz7ZI1k2wpjjBES6lSUGilyYYVAbboZji9YdWWOAAqppYpIqIpiXZ3y9mOZmM7oo3nod5ugkaT0uUqeQRBo5E5IpLnmajl26BaVOUkr5gpU1gZhlnRxS+tWlYN5l4RJl/nSmjxN0k2pN5Qmow6YOfOiUXThOCWMCru4V61YVSrCEA/gtqJxzwVb4QDfGwjeTe8FSSYJXxl1Xbf8Bzmk6pbTSfEcAetZQOauFyZx1nnHhUomgsL06a2262mqB2LXYIrttsA8Idh9N4VqIQXlFBixwkQ4ItSVjyRQw8LfgGSgGwN8aeZ6DDz/HcFPqPWxfdC9WTFzA8RnIoQ4SLhxwwQeTbLHJBNcIalQSKjdwNx3XqfJ7xZ0cVmQlS3xdxpr96xzLOk93sE4JL3wf0FBAfIDPNFGchXsXh7zd1BtbpV1wTXcHsk/qjdxCzyajvOXNRBNQ8KBgbhazcTObTd/N3hW9bVxkK9fw1WQtVamlPdLZtqhffWpzVIyO+uWSi+4I9aOGt52VkF+DeKJLZNHHZaeeoojjlolX/Sj/lOOGFuRMX9dEak6fb4Uqj4FD+DnhDDqaFOvsjfm3s3xlKZVZDDdbbwJcB3ehudYea9uWCXRbrXX1KiAgbuVCX6w1n2eAIK+1WjW8mHpWj967dpnOGPDPuwsvBs/JGNN5nCczFkscLkts+t8N/3n9+XofvQ5KAuBv9uWTflnoJUUJHrjkF6YH6UZv11seh5q3gGtBLxnSAxP1mmc98iUge9trl3esAT7WkYuD41MeXMyXogTi7z7rax+JKtgsBjFwKvVj1guRg72jTct/GBSgb1RDQFjh6oAKUECx9JYdyEgOTP6Z0AOUlBPtsQ6DAxgAx6aolv4kUYta0w79RESWRvJkkXNRIwGaNgPF54ARY2J0CfOcc0atqXFLLEnAF1GXvgNIJ09zzEAdMTbFNYZJBXpUwAD6mMYp6qksCRikcqpVsADqIAQAIfkECQoAAAAsAAAAAB8BDwAEBf9gQD1kSU5VRUlsFLHwNEGWNZ34o1Ju70cPCM1koqR4Px8JInvInk4UBZl0BWnN0/NY7S21z5ts17UKbbfcDEKtfqPiOLl8jZagXHoQDCepyi5rFndhKH9VIkR3RzAuMCwyNDZqflOAV4OKD0aHXUtNhVFznmdZcIZtSW+FcpZ0pWlOJ0KpP6ugrbVKQnZ8eZ57fVA6uj6ChGG/P5kkCc7PUw0M09TUC1MKz84PzwgIFA3S1dbX2tvczt/g49UOU+bwCeDi7AvXzebo8uvs0+4jz5oJ3BSuHwMHDirkgxfN4MF3AfUl8DbPoL0REs2po8cuocKIJRKQ4NcPYQV88Tb/GsTAEkMElj0m2DtAs6bNEj4uXOiBYcoCm0AN4Pyhs4eFmUBvkkjiMsKFGj+T1myms+rLphFkRpV6AN0FFlWxytiaVCi3omGxHiWbFJ0PsEaPcj1gNoELq0UDIeVa4quEqoChzjX7IK8Lln+f7g3a0iVMvWyBDr2787DPwZN7GF47t+vSH02fyp1LFfDVmIvbOvMbNqZMzGd3pjWaWrKzt3/jRq5Zl7LsyllrKy0MFrBOwVwJG76amLNUA8sDTchQoMCB6tetVwcCKMKzuQUWfO7ijLp26zbtPeieIEOGmujPi19PlCeG90DRH1Dv2ynw+9RJVd18wFnlQnnYYZee/3hEoXXBd3MRqNlXPZTXGX8vVAUWCxAqmB4JlbFWYXvgvQADazV0ZoABExhHoX9Pwacfb4UZpuFfMoBnFmAbJhbjYCy6qNOJKQpYAIstGvcIJCoKtZxhGORIwJRlycBaI4dFuWJyTr7YSFU50jRjdUgKeeKPQE1JwIo1atbCYTIYgNkjKFrQZJI8+manmDPS1GWBQ+I4gY4g3sjacXcK6ddfRSZFppVKLjkokG1OyJOUVAZlZY8S2DfBls912amJnYI56XU2PYonj8XtmeaUbNr45ktxYraoFwgRwFUBzwB3pgQkOCBjUqu9uKhODyAEXq9LJgbsAwt4KOMzzUqqrP+YqiXQyJIXkBDtefHx6syszU6Qa37ZUdsDXNJ9O+x11PpYLkLxZZfubViSKoOw2VUX3zOOLEnbVn0esBpWLGWg5sK60kSgizy5tzC2DjNYRsJUSludA/QlURWErxLAccdVWCjVlAiRXAWADduk5sim5fQMwwynbNyEDzpD88IwK5pzAtXtLDLH/d3FAjrw0TyyxyMqrGuCLxN9AcL3CV3TwzcfJrGaFO9ncRcYPz1mAURX8bEzJ6M8Xskkpp1ydywn9XKh0f0sNMocZw3jzHf3rOgzQe/8NoxuAou2mEqvfVfTGWsX9Xr/1cplkjn59qmcyUHqIGuSO7pii+z+p6X/nBofuapppmJe8I44F3fBqR5y/QBLEMP5qdxUkoCB66OCCWpZQX51o4+d1yT77EbLq9Pl2WVKl6ib65RAmKjSdLxjH9tTsL8sKUDZ4i5AleB5NWGggAJCohatjAWo2f2hmx3l7/j36pTBjeo7yv35rIboDMH62d+QZiM97VHsX84AUMxyFhkFPYN2etNKvfolrgSkr135mV/3HpMlv0Brffrr1UuyB8JUVad733OKbujnIfOhr3bBKaG/3Gc++AFHfPOzV3WKdb9A5S+DJ+Sfoe7yv3f1q4bC0wlMCgjCCVZQgQZioP5o8kAMwFCCB/RXr674GhNyz3wcvIoHDRjCbdWM0BkKoJ+MHKC530QMP0BMWcKG160HKGAAA4iQ7tZlnOlNII9cUY8V8wIYNOLRXmucAAR/c7YEANJleDsdIZ9xyDhKknZHc8YA/MU+IMzOZ4Z8JFAEiRW/vFGUfCKb7lwnugwccn7oIaULQgAAIfkECQoAAAAsAAAAAB8BDwAEBf8gFTxkSU5oRVFSFElwLE0QNJ34M1Wq6/8REsRkopBUFCDwUdOhUM4HL6n0CaGn53FVtdae2ue067recmckOfiFum9jsrkUnlio8vZNq1PLmXRgaXg/IkSBOystLzIwNDZoJ3FdQockRlJceUOCUZNVc1lYfpR6dTs9fzZnOjmkoHpRUJ9KoU57doSwq7hnibpLgKJ8qUAQCCUJyssnDQ0M0NHQCwsVCgrMy8oIK8/S0gsr2MokzCgUzt/RDg4U2u/k3errK/AP5Ajc6fPU7uT35UhwQzdvGo9s2h7kQ+dNXb9rCcoxUyivYDt/8LbpK8iAHUYiy/Q1VHcxY8iN6hD/YFgZgeWFlxYsLDhAs2ZNAyd8vPyxUuZMmzdxKvux08qDn0Br5uTp4oILCtSS0jSAE8VLpyybxkQqtRyMqxiAQOVqk6qTCGDDupCwVapSHT6+AvHp1qyyq2idapXpluaJr1fxRuBbV2gCnhgk7CRBtqZKli5hEpaKE25TvS56RqVsmCjmIEf7HljqQ63esYWd4M2Ktm1fr4pfqvWBmvPZtHFduyUt9wdd23d3Fm09uasOwIH1Fgdq93DpxItDSx2+JEOGAwUKYNeevQDoNSSuS81O7cGaINa3S11AAvwD8dqxqy8P5DN68TTj12T/AC/18OORx55Ow72UQHrZrdfe/2VOvSSBMvglVQB9ly1iRXp98RfbBV99BaF6SVHIoWJAHBhhTdrJMGJLGDwg2gE4JbdIYCiAyBwJ/jkI2ARuaWfWVR2S2BIJBvRVWXIjtrDSA1QBleCPgan4Uo1G4khgXFPSRABnEwAJQ31U1mUlIy0IdwGP8qHoowFdyvjlkEzaRMCcU1nlpWdo1qXil0u+GGOUDJ7JY4JJHWlmklmOB+OfIzaaGZFV9uemki02adOTjOqIXJiUjZkXlmdqyaWXFjbFaaFjxvBpovqpR1WbUb7ZYpw1zbkljHbqiKdoBiTpmwUO9JhdRHEBtshRMxEK1D0JzBhDdI3ldwA5jcR27P9ml8YX0QPVPutaq/kt82UjI9LVXX7aLkimDLpJ290yxdqHrJrSjhZckqrGFKx8CSYIm4WqBkFNd4S+q0y1PzBW77IXzGagdbbaimJ5SCb8nsRp7mceeAi2miB/SuAFIFASs7NxFS9lQEJSdB7ggLohW+ciyXSaLJhOZUAcMcYvS4pZYMvsHLHLLyMp2HsZCB1xzzevOHIBQh9AIc4Jd4zdzkU7fIGJUedHcXIWJ90yuANyfJ2y88HMIGgnHlDyy2SkvDLNNPUct8ws11w0dWjlLHbXTBd4VdBKb2mz0XohXficgf/85dNRT91UdWdzh3V/oE5gKWVWUU2j5kayicH/oZtujuJUPk9OVI1oE0rC6IHlFZvmBoA71Z95NXpVTLXrh3GuTU9pusSvytjUVygUWRfwzzZ45vAtj7aS7hw+ymR20dc5Aey577QkVb5Hvz3sLynsJMEYXFMUZjCYy12rKylQsVFIdYdx+sjJO3C/7x+QvgIZuNNeyEIw/6XPS3pRDjtshL5rbCgybCFMfCZoQAAGUDAK3Be60PW/+aEFBT+ZIPoOCDbfLBBd5/LfNRDjNOmcr4ItCYz5stWdDiawWO6zUQU9CJr6Ya9l+NuQ/hZwLv6pEIACJA4BzxU/BKoOWMFSVgMV8MCwOOhb9dJO/KwTu74N5oQb3I4Nu/jBggmEEIXZaWIJfQBFNaXwfyx8nAuzBUPybUuH3fma83TyofPFhz/ke5YLtjWADLFHLUJ0SngGUEi3HHJ0gTLQNQbQOu0A8lCDiwgj5dSyR3ZxcNZppBtd9rq0NEoZCmCkfs5VnukhCQYJmGSGXne8Ui1SlNuxpCdvNshJEqxVgIxACAAAIfkEAQoAAAAsAAAAAB8BDwAEBf9ghj0PRJ5T+lhWxUpwLEX0BEETmT9pXrm0oDCSMp0elOPDZRkOSziVSvdrOoMkY2/XA16xtx5v2vJ+s7o0j1ShfIM2k3S3arvf6HFu+ru/43o6O3ZvEVlbU3VtQiJ5KCosTDIxcGFqYlWFRUpJR0yFUGKJE5l4JYJTXVZ4YXM7ZatXeVxqi5o3Y7kkLRR+sqeBfLZ/uGK6hKZRWydlvg4RPwoJ09TVCRQNDQzb3NsLCxQKCg/WR73a3d3gFAkk1OTTCAjY6OkMDg7h0tbV5/bc695Ne4ABAzVs/7bh69SOHAmDCeYhTJgvSTlrE/99Y/iOYDx6CRms21fN3bWM9hb/KrEmDyTFXvxKpqi3bUyEghEu6CwYEcGCA0CDCnWn08mFgha+CRVqwAC8nBeEFLzA4ufSoeRoYKARlStVpVeDPsXJdWrVsGLJ7TT61erVpvCObqUxI+dZtAfcwegqRGdSvECfFuXKNanbsER1Kg5C9S9auNNuYpAw2C7YoAxs4lTMU97hq4mNIr28FHICqFIxNP681J1Wwl4NAx47N6dZx2gT12bc9rHTaXKD1F09m9xetrhzR67ctTfexIr5EvdNm7J02UKJFDKUIcOBAgW+gw9KZMKbC9SWjgdK48H2B90BG3Jvyvt38UK/0efLO0H88GEtQAJqQ6A3jVDgAXiA/36LeYVFfHgJ+MBiOtU1n30IBsXgBRb2hyFa83FI2XE5+ffhVfqR2Bd6J4Y3gVwi8kYVYHCtBVVUirFAIwnRUXKjBeoxZcCLFVImYwoG4DUkkSJaqNgETQG1HlBNETnZXtcBqSSPlQ2n0wQ0DlkhWxcgqWQKwRU1CZRBTXlAlTv5KAOUSRJgZ2lowkAmmGG9OJWeXs2opFM2UuiXlo9xWaSXgrYpJJMqPsnmY2guemSU+AUF51ExMKfjlhN2GSifvhHZ4aiThrVkmlGtmaSUCr4pJqeAzhmlnQTg+SKgK5aJVgI+9sWCA+qtR02nHPJmAT6AUdNkZfMRm2FawGJ56v8Dl01p57GTNJmCtNMewG2nkzyAD4BuijvNJGtOIG14CQbFLX9CYLvAeuiCNy4lMZBA7HhuUiNcrTBgG694CRYwrhD9movWUbw9mAGujh5AgAOK/pKAlEvZiQ99eEAIq8UeDxgoY9NgSLGGApLJ04FA3UnyxSb3KtfGMcvMniEF9jcNrjLjijHI0SlGDdB3Co1x0fTCNzHSQA/NGK8GPg10UBdjDJuM6RUANQEQO9hedyvfZ/HQDT5BDsdCeaw1KCLjJ3TNaVeNtc4LtlzgThDhTHLONIMs481350oez335nADSgEsdaHRHM650qNE9QfbXJRNNdcpQY/3x1oF2/TX/X4zSeWaDhpZJqqqVFtncl0FqOiu9N6aAYKyrFjVm7WFCah2OX05a9putMzbqrXhvOhzVZl51p15YHln4o0U7GbzFlDJZ95fIG06lapypdhfCCRdg0NYwgC9bukA5C21hSSU4vPv0qq8UwLE6SzX8ViUsFE8kko5zyCcvcbBqOMNiW/6AMxgBLutf+ZIXA6UDv3f5r30TRM65LijB0/zJSQlsU6ymEr7pkC9h58vJwOz3E/apKwFpY0xV5Ic3+g2BhfgJGHD2ZxfHcPAAADSSCmOTrYOJy4CbSVYP38U2DMKwgcpiFr4UZEPYNMaCRqziih5YvqUI7IMyXNbt/ge+bKPoJD0i9Jrb3MMcrqARYY0zlYraM40BROghRUNZHe0YIAGRsHJnFAcfMwUUCZUxbe4YgB2Hp5+pnOyM3eHjwTJXENVg6SjTUIAi4cgyghxST2es4x0Jwis9atKO8UrQxxzZK4gMwE2qfEAIAAAh/h1CdWlsdCB3aXRoIEdJRiBNb3ZpZSBHZWFyIDQuMAAh/hVNYWRlIGJ5IEFqYXhMb2FkLmluZm8AOwo=) repeat-x 1px 1px;
42}
43
44.ydlg .ydlg-hd {
45 /* background: url(../images/clipperz/basic-dialog/hd-sprite.gif) repeat-x 0 -82px;*/
46 background: url(data:image/gif;charset=utf-8;base64,R0lGODlhAwB7AIABADMzZv///yH5BAEAAAEALAAAAAADAHsAAAITBGKpy+0Po5y0Houz3rz7D4ZUAQA7Cg==) repeat-x 0 -82px;
47 background-color:navy;
48 color:#ffffff;
49 font:bold 12px "sans serif", Helvetica, Arial, Geneva, sans-serif;
50 overflow:hidden;
51 padding:5px;
52}
53.ydlg .ydlg-hd-left {
54 /* background: url(../images/clipperz/basic-dialog/hd-sprite.gif) no-repeat 0 -41px;*/
55 background: url(data:image/gif;charset=utf-8;base64,R0lGODlhAwB7AIABADMzZv///yH5BAEAAAEALAAAAAADAHsAAAITBGKpy+0Po5y0Houz3rz7D4ZUAQA7Cg==) no-repeat 0 -41px;
56 padding-left:3px;
57 margin:0px;
58}
59.ydlg .ydlg-hd-right {
60 /* background: url(../images/clipperz/basic-dialog/hd-sprite.gif) no-repeat right 0;*/
61 background: url(data:image/gif;charset=utf-8;base64,R0lGODlhAwB7AIABADMzZv///yH5BAEAAAEALAAAAAADAHsAAAITBGKpy+0Po5y0Houz3rz7D4ZUAQA7Cg==) no-repeat right 0;
62 padding-right:3px;
63}
64.ydlg .ydlg-dlg-body {
65 /*background:url(../images/clipperz/layout/gradient-bg.gif);*/
66 background-color: white;
67 border:1px solid #333366;
68 border-top:0 none;
69 padding:10px;
70 overflow:hidden;
71}
72
73/*
74.ydlg .ydlg-dlg-body .ydlg-ft{
75 padding-top: 7px;
76 border-top: 1px dotted #333366;
77}
78*/
79
80.ydlg .ydlg-close {
81 position:absolute;
82 top:4px;
83 right:4px;
84 z-index:6;
85 height:15px;
86 width:15px;
87 margin:0;
88 padding:0;
89 line-height:1px;
90 font-size:1px;
91 background-repeat:no-repeat;
92 cursor:pointer;
93 visibility:inherit;
94 /* background-image:url(../images/clipperz/basic-dialog/close.gif);*/
95 background-image:url(data:image/gif;charset=utf-8;base64,R0lGODlhDwAPANUAADk1bpeVs5+dub27z+Df6LGvxo2KqzIyZdfW4jk0brq4zNbU4cTD1ImGqVZSg/f2+Y+MraKgu9/e6NjX4qyqwjIyZtrZ5Pn5+mZij0pGenx4n0A7c7Oxx8C/0XZzm/39/Tw3cLCvxX57obe1yrCuxX16oP///zMzZjYxbAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAAAAAAALAAAAAAPAA8AAAZ9wJNQSAgJKIuh8oTAoJ5PB2M5AEGvKMEQYcVeFUInqmSBoDyTwDNzIEAtJlPnY7oAngMSFBLvF6AGAlcdfRIJUBoUUB50fWpPDQtQE3EScQ93KBwnDk8BFwUJAQ8jTxsVJwxQmSisEUOCXk8iSwoZWBuvSycHAwYaDRyoQ0EAOwo=);
96}
97
98/* @end */
99
100/* @group Message dialog */
101
102div#mb-dlg div div div.ydlg-hd {
103 background-color: #35306b;
104}
105
106div#mb-dlg div.ydlg-dlg-body {
107 border-color: #333366;
108}
109
110div#mb-dlg div.ydlg-dlg-body span.ext-mb-text {
111 font-size: 10pt;
112 color: #999999;
113}
114
115div.ydlg-btns-center table tbody tr td {
116 text-align: center;
117}
118
119/* @end */
120
121body .ybtn-left{
122 /* background:url(../images/default/basic-dialog/btn-sprite.gif) no-repeat 0 0;*/
123 background:url(data:image/gif;charset=utf-8;base64,R0lGODlhAwCTAIcAAAA8dBZNfiVXg0hukEpxk1V9okD/QGaHoGeIoGqLomyMpHqVqHuVqX2ZqoOEb4SGceWXAPiyMPizMPi0Nfi1Nfm0Nfi3O/m3Ovm3O/m4O+21R++1Sfm6Qfm6Qvq6Qfm9SPm9Sfq9Sfq+SfrAUPrAUfrBUPrDWPrEWPrEWfrHYfvHYfvIYPvKavzKafvPcvzOcfzOcvzRevzSefzSeo2eoaOutLG3tra9vb/Hyr/O27/O3P3Vgf3Vgv3Yif3bj/7dlf7fmu7crf3gm8DCycfJzsDP3dvXzdbY39Xf6Nrc4d3e4t3f5ODd1OLf1uTi2eTi2uXi2+bj3Obj3efk3ejl3ujl3+/o0vjt0//wz+Di6OPn6+nm4Orn4Oro4evo4evo4uvq4+vr5ezr5Ozr5ezr5u3q5u3s5e7t5u7t5+jq7+/u6Ovt8vDv6fDu6vDw6vDw6/Hw6vHw6/Hx7PPx7vLy7fLy7vPz7vT07/Dy9fT08PX18fX08vX18vb08vb28vb28/b29PP1+Pb3+vf4+fj49vj49/r6+fr6+vv7+vn8/f39/P7+/f7+/v7+/////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAMAAAYALAAAAAADAJMAAAj/AA0sELCgQBEBOhgBUKQIwCFDAAoRAgAIEIA/fwD44QNAjx4AefIAuHMHgB07AOrUAUCHDgA5cgC8cQOATJgAOJocIFDDQAMBARAYQFKAwaIcAhD1AbCnDYA5ZQDE+QIAjhcAbLgAULMFAJoqAM5QAWBmCoAxUgCIiQIADBQAXZwAeMIEgJEbAWwMSBBAgQEAgB0JZkS4keFEiAUpDsQYj+M1kNNI1kI5i+UlmJNoPsJ5iGcioEOHHkQaMACBBGlYERBEBgAgrn+49uG6h2sermfMAPDiBYAWLACoWAHABAoAI0oAACECgIcOADJgAFCBQoANEQ48gOATqNArNBjIfwgiQIYQADJ+oPeBvgf6HehjAHABAwCLFgBSqABw4jgJ5SF8AAAHHABgwQUAUDABABJoEAAEDvDll2lYVNjDhYY1glgiignCWCCO4QHZGpKlQZkWlmWB2RKaJcHZEZ4NEZoSNEZgIwQ4mkahhRee6OOPQAYp5JAn2hgBjhCYFhAAOwo=) no-repeat 0 0;
124}
125body .ybtn-right{
126 /* background:url(../images/default/basic-dialog/btn-sprite.gif) no-repeat 0 -21px;*/
127 background:url(data:image/gif;charset=utf-8;base64,R0lGODlhAwCTAIcAAAA8dBZNfiVXg0hukEpxk1V9okD/QGaHoGeIoGqLomyMpHqVqHuVqX2ZqoOEb4SGceWXAPiyMPizMPi0Nfi1Nfm0Nfi3O/m3Ovm3O/m4O+21R++1Sfm6Qfm6Qvq6Qfm9SPm9Sfq9Sfq+SfrAUPrAUfrBUPrDWPrEWPrEWfrHYfvHYfvIYPvKavzKafvPcvzOcfzOcvzRevzSefzSeo2eoaOutLG3tra9vb/Hyr/O27/O3P3Vgf3Vgv3Yif3bj/7dlf7fmu7crf3gm8DCycfJzsDP3dvXzdbY39Xf6Nrc4d3e4t3f5ODd1OLf1uTi2eTi2uXi2+bj3Obj3efk3ejl3ujl3+/o0vjt0//wz+Di6OPn6+nm4Orn4Oro4evo4evo4uvq4+vr5ezr5Ozr5ezr5u3q5u3s5e7t5u7t5+jq7+/u6Ovt8vDv6fDu6vDw6vDw6/Hw6vHw6/Hx7PPx7vLy7fLy7vPz7vT07/Dy9fT08PX18fX08vX18vb08vb28vb28/b29PP1+Pb3+vf4+fj49vj49/r6+fr6+vv7+vn8/f39/P7+/f7+/v7+/////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAMAAAYALAAAAAADAJMAAAj/AA0sELCgQBEBOhgBUKQIwCFDAAoRAgAIEIA/fwD44QNAjx4AefIAuHMHgB07AOrUAUCHDgA5cgC8cQOATJgAOJocIFDDQAMBARAYQFKAwaIcAhD1AbCnDYA5ZQDE+QIAjhcAbLgAULMFAJoqAM5QAWBmCoAxUgCIiQIADBQAXZwAeMIEgJEbAWwMSBBAgQEAgB0JZkS4keFEiAUpDsQYj+M1kNNI1kI5i+UlmJNoPsJ5iGcioEOHHkQaMACBBGlYERBEBgAgrn+49uG6h2sermfMAPDiBYAWLACoWAHABAoAI0oAACECgIcOADJgAFCBQoANEQ48gOATqNArNBjIfwgiQIYQADJ+oPeBvgf6HehjAHABAwCLFgBSqABw4jgJ5SF8AAAHHABgwQUAUDABABJoEAAEDvDll2lYVNjDhYY1glgiignCWCCO4QHZGpKlQZkWlmWB2RKaJcHZEZ4NEZoSNEZgIwQ4mkahhRee6OOPQAYp5JAn2hgBjhCYFhAAOwo=) no-repeat 0 -21px;
128}
129body .ybtn-center{
130 /* background:url(../images/default/basic-dialog/btn-sprite.gif) repeat-x 0 -42px;*/
131 background:url(data:image/gif;charset=utf-8;base64,R0lGODlhAwCTAIcAAAA8dBZNfiVXg0hukEpxk1V9okD/QGaHoGeIoGqLomyMpHqVqHuVqX2ZqoOEb4SGceWXAPiyMPizMPi0Nfi1Nfm0Nfi3O/m3Ovm3O/m4O+21R++1Sfm6Qfm6Qvq6Qfm9SPm9Sfq9Sfq+SfrAUPrAUfrBUPrDWPrEWPrEWfrHYfvHYfvIYPvKavzKafvPcvzOcfzOcvzRevzSefzSeo2eoaOutLG3tra9vb/Hyr/O27/O3P3Vgf3Vgv3Yif3bj/7dlf7fmu7crf3gm8DCycfJzsDP3dvXzdbY39Xf6Nrc4d3e4t3f5ODd1OLf1uTi2eTi2uXi2+bj3Obj3efk3ejl3ujl3+/o0vjt0//wz+Di6OPn6+nm4Orn4Oro4evo4evo4uvq4+vr5ezr5Ozr5ezr5u3q5u3s5e7t5u7t5+jq7+/u6Ovt8vDv6fDu6vDw6vDw6/Hw6vHw6/Hx7PPx7vLy7fLy7vPz7vT07/Dy9fT08PX18fX08vX18vb08vb28vb28/b29PP1+Pb3+vf4+fj49vj49/r6+fr6+vv7+vn8/f39/P7+/f7+/v7+/////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAMAAAYALAAAAAADAJMAAAj/AA0sELCgQBEBOhgBUKQIwCFDAAoRAgAIEIA/fwD44QNAjx4AefIAuHMHgB07AOrUAUCHDgA5cgC8cQOATJgAOJocIFDDQAMBARAYQFKAwaIcAhD1AbCnDYA5ZQDE+QIAjhcAbLgAULMFAJoqAM5QAWBmCoAxUgCIiQIADBQAXZwAeMIEgJEbAWwMSBBAgQEAgB0JZkS4keFEiAUpDsQYj+M1kNNI1kI5i+UlmJNoPsJ5iGcioEOHHkQaMACBBGlYERBEBgAgrn+49uG6h2sermfMAPDiBYAWLACoWAHABAoAI0oAACECgIcOADJgAFCBQoANEQ48gOATqNArNBjIfwgiQIYQADJ+oPeBvgf6HehjAHABAwCLFgBSqABw4jgJ5SF8AAAHHABgwQUAUDABABJoEAAEDvDll2lYVNjDhYY1glgiignCWCCO4QHZGpKlQZkWlmWB2RKaJcHZEZ4NEZoSNEZgIwQ4mkahhRee6OOPQAYp5JAn2hgBjhCYFhAAOwo=) repeat-x 0 -42px;
132}
133
134.ext-el-mask {
135 zoom:100%;
136}
137
138
139body.masked textarea {
140 overflow: hidden;
141}
diff --git a/frontend/beta/css/yui-extensions/basic-dialog.css b/frontend/beta/css/yui-extensions/basic-dialog.css
new file mode 100644
index 0000000..f1b6375
--- a/dev/null
+++ b/frontend/beta/css/yui-extensions/basic-dialog.css
@@ -0,0 +1,250 @@
1/*
2
3Copyright 2008-2011 Clipperz Srl
4
5This file is part of Clipperz's Javascript Crypto Library.
6Javascript Crypto Library provides web developers with an extensive
7and efficient set of cryptographic functions. The library aims to
8obtain maximum execution speed while preserving modularity and
9reusability.
10For further information about its features and functionalities please
11refer to http://www.clipperz.com
12
13* Javascript Crypto Library is free software: you can redistribute
14 it and/or modify it under the terms of the GNU Affero General Public
15 License as published by the Free Software Foundation, either version
16 3 of the License, or (at your option) any later version.
17
18* Javascript Crypto Library is distributed in the hope that it will
19 be useful, but WITHOUT ANY WARRANTY; without even the implied
20 warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
21 See the GNU Affero General Public License for more details.
22
23* You should have received a copy of the GNU Affero General Public
24 License along with Javascript Crypto Library. If not, see
25 <http://www.gnu.org/licenses/>.
26
27*/
28
29.ydlg-proxy {
30 background-image: url(../images/default/gradient-bg.gif);
31 background-color:#c3daf9;
32 border:1px solid #6593cf;
33 z-index:10001;
34 overflow:hidden;
35 position:absolute;
36 left:0;top:0;
37}
38.ydlg-shadow{
39 background:#aaaaaa;
40 position:absolute;
41 left:0;top:0;
42}
43.ydlg-focus{
44 -moz-outline:0 none;
45 outline:0 none;
46 width:0;
47 height:0;
48 overflow:hidden;
49 position:absolute;
50 top:0;
51 left:0;
52}
53.ydlg-mask{
54 z-index:10000;
55 display:none;
56 position:absolute;
57 top:0;
58 left:0;
59 -moz-opacity: 0.5;
60 opacity:.50;
61 filter: alpha(opacity=50);
62 background-color:#CCC;
63}
64body.masked{
65}
66body.masked select {
67 visibility:hidden;
68}
69body.masked .ydlg select {
70 visibility:visible;
71}
72.ydlg{
73 z-index:10001;
74 overflow:hidden;
75 position:absolute;
76 left:300;top:0;
77}
78.yresizable-proxy{
79 z-index:10002;
80}
81.ydlg .ydlg-hd {
82 background: url(../images/default/basic-dialog/hd-sprite.gif) repeat-x 0 -82px;
83 background-color:navy;
84 color:#ffffff;
85 font:bold 12px "sans serif", tahoma, verdana, helvetica;
86 overflow:hidden;
87 padding:5px;
88}
89.ydlg .ydlg-hd-left {
90 background: url(../images/default/basic-dialog/hd-sprite.gif) no-repeat 0 -41px;
91 padding-left:3px;
92 margin:0px;
93}
94.ydlg .ydlg-hd-right {
95 background: url(../images/default/basic-dialog/hd-sprite.gif) no-repeat right 0;
96 padding-right:3px;
97}
98.ydlg .ydlg-dlg-body{
99 background:url(../images/default/layout/gradient-bg.gif);
100 border:1px solid #6593cf;
101 border-top:0 none;
102 padding:10px;
103 overflow:hidden;
104}
105.ydlg .ydlg-bd{
106 overflow:hidden;
107}
108.ydlg .ydlg-ft{
109 overflow:hidden;
110 padding:5px;
111 padding-bottom:0;
112}
113.ydlg .yui-ext-tabbody{
114 background:white;
115 overflow:auto;
116}
117.ydlg .ytabs-top .yui-ext-tabbody{
118 border:1px solid #6593cf;
119 border-top:0 none;
120}
121.ydlg .ytabs-bottom .yui-ext-tabbody{
122 border:1px solid #6593cf;
123 border-bottom:0 none;
124}
125.ydlg .ylayout-container .yui-ext-tabbody{
126 border:0 none;
127}
128.ydlg .inner-tab{
129 margin:5px;
130}
131.ydlg .ydlg-ft .ybtn{
132 margin-right:5px;
133 float:right;
134 clear:none;
135}
136.ydlg .ydlg-ft .ydlg-btns td {
137 border:0;
138 padding:0;
139}
140.ydlg .ydlg-ft .ydlg-btns-right table{
141 float:right;
142 clear:none;
143}
144.ydlg .ydlg-ft .ydlg-btns-left table{
145 float:left;
146 clear:none;
147}
148.ydlg .ydlg-ft .ydlg-btns-center{
149 text-align:center; /*ie*/
150}
151.ydlg .ydlg-ft .ydlg-btns-center table{
152 margin:0 auto; /*everyone else*/
153}
154.ydlg-draggable .ydlg-hd{
155 cursor:move;
156}
157.ydlg-closable .ydlg-hd{
158 padding-right:22px;
159}
160.ydlg .ydlg-close {
161 position:absolute;
162 top:4px;
163 right:4px;
164 z-index:6;
165 height:15px;
166 width:15px;
167 margin:0;
168 padding:0;
169 line-height:1px;
170 font-size:1px;
171 background-repeat:no-repeat;
172 cursor:pointer;
173 visibility:inherit;
174 background-image:url(../images/default/basic-dialog/close.gif);
175}
176.ydlg div.yresizable-handle-east{
177 background-image:url(../images/default/sizer/e-handle-dark.gif);
178 border:0;
179 background-position:left;
180 margin-right:0;
181}
182.ydlg div.yresizable-handle-south{
183 background-image:url(../images/default/sizer/s-handle-dark.gif);
184 border:0;
185 height:6px;
186}
187.ydlg div.yresizable-handle-west{
188 background-image:url(../images/default/sizer/e-handle-dark.gif);
189 border:0;
190 background-position:1px;
191}
192.ydlg div.yresizable-handle-north{
193 background-image:url(../images/default/s.gif);
194 border:0;
195}
196.ydlg div.yresizable-handle-northeast, .ytheme-gray .ydlg div.yresizable-handle-northeast{
197 background-image:url(../images/default/s.gif);
198 border:0;
199}
200.ydlg div.yresizable-handle-northwest, .ytheme-gray .ydlg div.yresizable-handle-northwest{
201 background-image:url(../images/default/s.gif);
202 border:0;
203}
204.ydlg div.yresizable-handle-southeast{
205 background-image:url(../images/default/sizer/corners-sprite.gif);
206 background-position: top left;
207 width:8px;
208 height:8px;
209 border:0;
210}
211.ydlg div.yresizable-handle-southwest{
212 background-image:url(../images/default/sizer/corners-sprite.gif);
213 background-position: top right;
214 margin-left:1px;
215 margin-bottom:1px;
216 border:0;
217}
218
219#mb-dlg .ydlg-ft .ybtn{
220 float:none;
221 clear:none;
222 margin:0 3px;
223}
224
225#mb-dlg .ydlg-bd {
226 padding:5px;
227 overflow:hidden !important;
228}
229#mb-dlg .ext-mb-input {
230 margin-top:4px;
231 width:95%;
232}
233#mb-dlg .ext-mb-textarea {
234 margin-top:4px;
235 font:normal 13px verdana,tahoma,sans-serif;
236}
237#mb-dlg .ext-mb-progress-wrap {
238 margin-top:4px;
239 border:1px solid #6593cf;
240}
241#mb-dlg .ext-mb-progress {
242 height:18px;
243 background:transparent url(../images/default/basic-dialog/progress2.gif) repeat-x 1px 1px;
244}
245#mb-dlg .ext-mb-progress-bar {
246 height:18px;
247 overflow:hidden;
248 width:0;
249 background:#8bb8f3;
250}
diff --git a/frontend/beta/css/yui-extensions/button.css b/frontend/beta/css/yui-extensions/button.css
new file mode 100644
index 0000000..ee2d86f
--- a/dev/null
+++ b/frontend/beta/css/yui-extensions/button.css
@@ -0,0 +1,86 @@
1/*
2
3Copyright 2008-2011 Clipperz Srl
4
5This file is part of Clipperz's Javascript Crypto Library.
6Javascript Crypto Library provides web developers with an extensive
7and efficient set of cryptographic functions. The library aims to
8obtain maximum execution speed while preserving modularity and
9reusability.
10For further information about its features and functionalities please
11refer to http://www.clipperz.com
12
13* Javascript Crypto Library is free software: you can redistribute
14 it and/or modify it under the terms of the GNU Affero General Public
15 License as published by the Free Software Foundation, either version
16 3 of the License, or (at your option) any later version.
17
18* Javascript Crypto Library is distributed in the hope that it will
19 be useful, but WITHOUT ANY WARRANTY; without even the implied
20 warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
21 See the GNU Affero General Public License for more details.
22
23* You should have received a copy of the GNU Affero General Public
24 License along with Javascript Crypto Library. If not, see
25 <http://www.gnu.org/licenses/>.
26
27*/
28
29.ybtn{
30 font:normal 11px arial, tahoma, verdana, helvetica;
31 cursor:pointer;
32 white-space: nowrap;
33}
34.ybtn-left, .ybtn-right{
35 font-size:1px;
36 line-height:1px;
37}
38.ybtn-left{
39 width:3px;
40 height:21px;
41 background:url(../images/default/basic-dialog/btn-sprite.gif) no-repeat 0 0;
42}
43.ybtn-right{
44 width:3px;
45 height:21px;
46 background:url(../images/default/basic-dialog/btn-sprite.gif) no-repeat 0 -21px;
47}
48.ybtn-focus{
49 text-decoration:none !important;
50 color:black !important;
51 display: -moz-inline-block;
52 display:inline-block;
53 width:auto;
54 position:relative;
55 white-space: nowrap;
56}
57.ybtn-center{
58 background:url(../images/default/basic-dialog/btn-sprite.gif) repeat-x 0 -42px;
59 font:normal 11px "san serif",tahoma,verdana,helvetica;
60 vertical-align: middle;
61 text-align:center;
62 padding:0 5px;
63 cursor:pointer;
64 white-space:nowrap;
65 -moz-user-select: none;
66 -khtml-user-select: none;
67}
68.ybtn-over .ybtn-left{
69 background-position:0 -63px;
70}
71.ybtn-over .ybtn-right{
72 background-position:0 -84px;
73}
74.ybtn-over .ybtn-center{
75 background-position:0 -105px;
76}
77.ybtn-click .ybtn-center{
78 background-position:0 -126px;
79}
80.ybtn-disabled{
81 cursor:default;
82}
83.ybtn-disabled .ybtn-center{
84 color:gray;
85 cursor:default;
86}
diff --git a/frontend/beta/css/yui-extensions/core.css b/frontend/beta/css/yui-extensions/core.css
new file mode 100644
index 0000000..3cd8b6e
--- a/dev/null
+++ b/frontend/beta/css/yui-extensions/core.css
@@ -0,0 +1,53 @@
1/*
2
3Copyright 2008-2011 Clipperz Srl
4
5This file is part of Clipperz's Javascript Crypto Library.
6Javascript Crypto Library provides web developers with an extensive
7and efficient set of cryptographic functions. The library aims to
8obtain maximum execution speed while preserving modularity and
9reusability.
10For further information about its features and functionalities please
11refer to http://www.clipperz.com
12
13* Javascript Crypto Library is free software: you can redistribute
14 it and/or modify it under the terms of the GNU Affero General Public
15 License as published by the Free Software Foundation, either version
16 3 of the License, or (at your option) any later version.
17
18* Javascript Crypto Library is distributed in the hope that it will
19 be useful, but WITHOUT ANY WARRANTY; without even the implied
20 warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
21 See the GNU Affero General Public License for more details.
22
23* You should have received a copy of the GNU Affero General Public
24 License along with Javascript Crypto Library. If not, see
25 <http://www.gnu.org/licenses/>.
26
27*/
28
29.ext-el-mask {
30 z-index:20000;
31 position:absolute;
32 top:0;
33 left:0;
34 -moz-opacity: 0.5;
35 opacity:.50;
36 filter: alpha(opacity=50);
37 background-color:#CCC;
38 width:100%;
39 height:100%;
40 zoom:1;
41}
42.ext-masked {
43 overflow:hidden !important;
44}
45.ext-masked select,.ext-masked object,.ext-masked embed{
46 visibility:hidden;
47}
48.ylayer-shadow{
49 background:#cccccc;
50 opacity:.3;
51 -moz-opacity:.3;
52 filter: alpha(opacity=30);
53} \ No newline at end of file
diff --git a/frontend/beta/css/yui-extensions/dd.css b/frontend/beta/css/yui-extensions/dd.css
new file mode 100644
index 0000000..ac2ba40
--- a/dev/null
+++ b/frontend/beta/css/yui-extensions/dd.css
@@ -0,0 +1,81 @@
1/*
2
3Copyright 2008-2011 Clipperz Srl
4
5This file is part of Clipperz's Javascript Crypto Library.
6Javascript Crypto Library provides web developers with an extensive
7and efficient set of cryptographic functions. The library aims to
8obtain maximum execution speed while preserving modularity and
9reusability.
10For further information about its features and functionalities please
11refer to http://www.clipperz.com
12
13* Javascript Crypto Library is free software: you can redistribute
14 it and/or modify it under the terms of the GNU Affero General Public
15 License as published by the Free Software Foundation, either version
16 3 of the License, or (at your option) any later version.
17
18* Javascript Crypto Library is distributed in the hope that it will
19 be useful, but WITHOUT ANY WARRANTY; without even the implied
20 warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
21 See the GNU Affero General Public License for more details.
22
23* You should have received a copy of the GNU Affero General Public
24 License along with Javascript Crypto Library. If not, see
25 <http://www.gnu.org/licenses/>.
26
27*/
28
29.ydd-drag-proxy{
30 position:absolute;
31 left:0;top:0;
32 visibility:hidden;
33 z-index:15000;
34}
35.ydd-drag-ghost{
36 color: black;
37 font: normal 11px arial, helvetica, sans-serif;
38 -moz-opacity: 0.85;
39 opacity:.85;
40 filter: alpha(opacity=85);
41 border-top:1px solid #dddddd;
42 border-left:1px solid #dddddd;
43 border-right:1px solid #bbbbbb;
44 border-bottom:1px solid #bbbbbb;
45 padding:3px;
46 padding-left:20px;
47 background-color:white;
48 white-space:nowrap;
49}
50.ydd-drag-repair .ydd-drag-ghost{
51 -moz-opacity: 0.4;
52 opacity:.4;
53 filter: alpha(opacity=40);
54 border:0 none;
55 padding:0;
56 background-color:transparent;
57}
58.ydd-drag-repair .ydd-drop-icon{
59 visibility:hidden;
60}
61.ydd-drop-icon{
62 position:absolute;
63 top:3px;
64 left:3px;
65 display:block;
66 width:16px;
67 height:16px;
68 background-color:transparent;
69 background-position: center;
70 background-repeat: no-repeat;
71 z-index:1;
72}
73.ydd-drop-nodrop .ydd-drop-icon{
74 background-image: url(../images/default/dd/drop-no.gif);
75}
76.ydd-drop-ok .ydd-drop-icon{
77 background-image: url(../images/default/dd/drop-yes.gif);
78}
79.ydd-drop-ok-add .ydd-drop-icon{
80 background-image: url(../images/default/dd/drop-add.gif);
81}
diff --git a/frontend/beta/css/yui-extensions/grid.css b/frontend/beta/css/yui-extensions/grid.css
new file mode 100644
index 0000000..01be8d5
--- a/dev/null
+++ b/frontend/beta/css/yui-extensions/grid.css
@@ -0,0 +1,584 @@
1/*
2
3Copyright 2008-2011 Clipperz Srl
4
5This file is part of Clipperz's Javascript Crypto Library.
6Javascript Crypto Library provides web developers with an extensive
7and efficient set of cryptographic functions. The library aims to
8obtain maximum execution speed while preserving modularity and
9reusability.
10For further information about its features and functionalities please
11refer to http://www.clipperz.com
12
13* Javascript Crypto Library is free software: you can redistribute
14 it and/or modify it under the terms of the GNU Affero General Public
15 License as published by the Free Software Foundation, either version
16 3 of the License, or (at your option) any later version.
17
18* Javascript Crypto Library is distributed in the hope that it will
19 be useful, but WITHOUT ANY WARRANTY; without even the implied
20 warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
21 See the GNU Affero General Public License for more details.
22
23* You should have received a copy of the GNU Affero General Public
24 License along with Javascript Crypto Library. If not, see
25 <http://www.gnu.org/licenses/>.
26
27*/
28
29.ygrid-cell-text {
30 display: block;
31 overflow: hidden;
32 padding: 3px 5px;
33 white-space: nowrap;
34}
35.ygrid-col{
36 cursor: default;
37 height:21px !important;
38 box-sizing: border-box;
39 -moz-box-sizing: border-box;
40 position:absolute;
41 display:block;
42 -moz-outline: none;
43 -moz-user-focus: normal;
44 overflow: hidden;
45 border-left: 1px solid #f1efe2;
46}
47.yeditgrid .ygrid-col{
48 -moz-outline: normal;
49}
50.ygrid-col, .ygrid-hd {
51 -o-text-overflow: ellipsis;
52 text-overflow: ellipsis;
53}
54.ygrid-col-0{
55 border-left: 0;
56}
57.ygrid-col-last{
58 border-right: 1px solid #f1efe2;
59}
60.ygrid-editor{
61 box-sizing: border-box;
62 -moz-box-sizing: border-box;
63 position:absolute;
64 visibility:hidden;
65 font: normal 8pt arial;
66 border: 1px solid #afbdc9;
67 z-index:10;
68}
69.ygrid-editor input{
70 font: normal 8pt arial;
71 border: 0;
72 padding-top:2px;
73 padding-left:3px;
74}
75.ygrid-editor-container{
76 overflow:hidden;
77 display:block;
78 background-color:white;
79}
80.ygrid-editor .pick-button{
81 width:15px;
82 height:20px;
83 position:absolute;
84 display:block;
85 right:0;
86 top:0;
87 z-index:2;
88 background-image: url(../images/default/grid/pick-button.gif);
89 background-repeat: no-repeat;
90}
91.ygrid-editor-invalid{
92 background-image: url(../images/default/grid/invalid_line.gif);
93 background-repeat: repeat-x;
94 background-position: bottom;
95 border: 1px solid #afbdc9;
96}
97.ygrid-checkbox-editor{
98 text-align: center;
99 overflow:hidden;
100 display:block;
101 background-color:white;
102}
103.ygrid-checkbox-editor input{
104 margin-top:3px;
105 height:13px;
106 width:13px;
107}
108select.ygrid-editor{
109 padding: 0;
110 -moz-outline: none;
111 border: 1px solid #afbdc9;
112}
113.ygrid-num-editor{
114 text-align:right;
115 padding-top:2px;
116 padding-left:3px;
117}
118.ygrid-text-editor{
119 padding-top:2px;
120 padding-left:3px;
121}
122.ygrid-hd{
123 font: normal 8pt arial;
124 background-color: #ebeadb;
125 box-sizing: border-box;
126 -moz-box-sizing: border-box;
127 display: block;
128 position: absolute;
129 overflow:hidden;
130}
131.ygrid-column-sizer {
132 width:1px;
133 border-right:1px dashed #6593cf;
134 background:none;
135 cursor: col-resize;
136}
137.ygrid-drag-proxy{
138 width:150px;
139 height:24px;
140 background-color:#3366cc;
141 border: 1px solid #002266;
142 position:absolute;
143 visibility:hidden;
144 z-index:10000;
145}
146.ygrid-drag-text{
147 font: normal 8pt arial;
148 color:white;
149 position:absolute;
150 top:0;
151 left:26px;
152 padding:3px;
153 display:block;
154}
155.ygrid-drop-icon{
156 position:absolute;
157 top:0;
158 left:0;
159 display:block;
160 width:24px;
161 height:100%;
162 background-position: center;
163 background-repeat: no-repeat;
164}
165.ygrid-drop-nodrop{
166 background-image: url(../images/default/grid/drop-no.gif);
167}
168.ygrid-drop-ok{
169 background-image: url(../images/default/grid/drop-yes.gif);
170}
171.ygrid-hd .sort-asc {
172 background-image: url(../images/default/grid/sort_asc.gif);
173 background-position: right;
174 background-repeat: no-repeat;
175 display: none;
176 height: 14px;
177 width: 16px;
178}
179.ygrid-hd .sort-desc {
180 background-image: url(../images/default/grid/sort_desc.gif);
181 background-position: right;
182 background-repeat: no-repeat;
183 display: none;
184 height: 14px;
185 width: 16px;
186}
187.ygrid-hd-body {
188 cursor: default;
189 display: block;
190 font: normal 8pt arial;
191 left: 0;
192 overflow: hidden;
193 padding: 3px 5px;
194 position: relative;
195 top: 0;
196 white-space: nowrap;
197}
198.ygrid-hd-body span {
199 font: normal 8pt arial;
200 white-space: nowrap;
201}
202.ygrid-hd-over{
203 border-bottom: 2px solid #fcc247;
204}
205.ygrid-hd-over .ygrid-hd-body{
206 background-color: #faf9f4;
207 border-bottom: 1px solid #f9a900;
208}
209.ygrid-hd-split {
210 background-image: url(../images/default/grid/grid-split.gif);
211 background-position: center;
212 background-repeat: no-repeat;
213 cursor: e-resize;
214 display: block;
215 font-size: 1px;
216 height: 16px;
217 overflow: hidden;
218 position: absolute;
219 top: 2px;
220 width: 6px;
221 z-index: 3;
222}
223.ygrid-hrow{
224 background: #ebeadb url(../images/default/grid/grid-hrow.gif) repeat-x;
225 display: block;
226 height: 22px;
227 left: 0;
228 position: relative;
229 top: 0;
230 width: 10000px;
231 overflow:hidden;
232 z-index:2;
233}
234.ygrid-hrow-frame{
235 height: 22px;
236 left: 0;
237 display:block;
238 position: absolute;
239 top: 0;
240 width: 10000px;
241 z-index:1;
242}
243.ygrid-footer .ytoolbar{
244 border:0;
245}
246.ygrid-page-number{
247 width:24px;
248 height:14px;
249}
250.ygrid-page-first{
251 background-image: url(../images/default/grid/page-first.gif);
252}
253.ygrid-loading{
254 background-image: url(../images/default/grid/done.gif);
255}
256.ygrid-page-last{
257 background-image: url(../images/default/grid/page-last.gif);
258}
259.ygrid-page-next{
260 background-image: url(../images/default/grid/page-next.gif);
261}
262.ygrid-page-prev{
263 background-image: url(../images/default/grid/page-prev.gif);
264}
265.ytb-button-disabled .ygrid-loading{
266 background-image: url(../images/default/grid/loading.gif);
267}
268.ytb-button-disabled .ygrid-page-first{
269 background-image: url(../images/default/grid/page-first-disabled.gif);
270}
271.ytb-button-disabled .ygrid-page-last{
272 background-image: url(../images/default/grid/page-last-disabled.gif);
273}
274.ytb-button-disabled .ygrid-page-next{
275 background-image: url(../images/default/grid/page-next-disabled.gif);
276}
277.ytb-button-disabled .ygrid-page-prev{
278 background-image: url(../images/default/grid/page-prev-disabled.gif);
279}
280.ygrid-mso{
281}
282.ygrid-mso .ygrid-hd{
283 background:none;
284 border-bottom:0;
285}
286.ygrid-mso .ygrid-footer {
287 border-top: 1px solid #6593cf;
288}
289
290.ygrid-mso .ygrid-footer .ygrid-fbutton{
291 border:0;
292}
293.ygrid-mso .ygrid-hd-body {
294 border-bottom:0;
295}
296.ygrid-mso .ygrid-hd-over{
297 border-bottom:0;
298}
299.ygrid-mso .ygrid-hd-over .ygrid-hd-body{
300 background-color: transparent;
301}
302.ygrid-mso .ygrid-hd-split {
303 background-image: url(../images/default/grid/grid-blue-split.gif);
304}
305.ygrid-mso .ytoolbar .ytb-sep {
306 background-image: url(../images/default/grid/grid-blue-split.gif);
307}
308.ygrid-mso .ygrid-hrow{
309 background: url(../images/default/grid/mso-hd.gif);
310 border-bottom: 1px solid #6593cf;
311 height: 21px;
312}
313.ygrid-mso .ygrid-row{
314 color: black;
315 border-bottom: 1px solid #ddecfe;
316}
317.ygrid-mso .ygrid-row-alt{
318 background-color: #f5f5f5;
319}
320.ygrid-mso .ygrid-row-selected{
321 background-color: #b3c8e8 !important;
322 color: black;
323}
324.ygrid-mso .ygrid-row-selected span{
325 color: black !important;
326}
327.yprops-grid .ygrid-col-1{
328 background-color: #f1efe2;
329}
330.yprops-grid .ygrid-col-1 .ygrid-cell-text{
331 background-color: white;
332}
333.yprops-grid .ygrid-col-0{
334 background-color: #f1efe2;
335}
336.yprops-grid .ygrid-col-0 .ygrid-cell-text{
337 background-color: white;
338 margin-left:10px;
339}
340.yprops-grid .ygrid-prop-edting .ygrid-col-0 .ygrid-cell-text{
341 background-color: #316ac5;
342 color: white;
343}
344.yprops-grid .ygrid-prop-edting .ygrid-col-0{
345 color: white;
346}
347.yprops-grid .ygrid-num-editor{
348 text-align:left;
349}
350.ygrid-row{
351 font: normal 8pt arial;
352 border-bottom: 1px solid #f1efe2;
353 overflow: visible;
354 white-space: nowrap;
355 height:21px;
356 width:10000px;
357 box-sizing: border-box;
358 -moz-box-sizing: border-box;
359 display:block;
360 position:absolute;
361}
362.ygrid-row-alt{
363 background-color: #fcfaf6;
364}
365.ygrid-row-over{
366 background-color: #f1f1f1;
367 color: black;
368}
369.ygrid-row-selected{
370 background-color: #316ac5 !important;
371 color: white;
372}
373.ygrid-row-selected span{
374 color: white !important;
375}
376.ygrid-vista{
377 border:1px solid #535353;
378}
379.ygrid-vista .ygrid-hd{
380 border-bottom:0px;
381 background:none;
382}
383.ygrid-vista .ygrid-hd-body {
384 border-bottom: 1px solid #b3bcc0;
385}
386.ygrid-vista .ygrid-hd-over{
387 border-bottom:0px;
388}
389.ygrid-vista .ygrid-hd-over .ygrid-hd-body{
390 background-color: transparent;
391 border-bottom:0;
392}
393.ygrid-vista .ygrid-hd-split {
394 background-image: url(../images/default/grid/grid-split.gif);
395}
396.ygrid-vista .ygrid-hrow{
397 background: url(../images/default/grid/grid-vista-hd.gif);
398 height: 21px;
399}
400.ygrid-vista .ygrid-row-alt{
401 background-color: #f5f5f5;
402}
403.ygrid-vista .ygrid-row-selected{
404 background-color: #535353 !important;
405 color: white;
406}
407.ygrid-vista .ygrid-row-selected span{
408 color: white !important;
409}
410.ygrid-vista .ygrid-wrap-body {
411}
412.ygrid-vista .ytoolbar{
413 border: 0px none;
414 background: url(../images/default/grid/grid-vista-hd.gif);
415}
416.ygrid-vista .ytoolbar .ytb-sep{
417 background-image: url(../images/default/grid/grid-split.gif);
418}
419/*
420 To have the scrollbars overlap the header, change .ygrid-wrap top style to 0 and
421 and ygrid-wrap-body top to 22px
422 Then grid.getView().scrollbarMode = YAHOO.ext.grid.GridView.SCROLLBARS_OVERLAP;
423 */
424.ygrid-wrap {
425 height: 100%;
426 left: 0;
427 overflow: auto;
428 position: relative;
429 top: 22px;
430 width: 100%;
431}
432.ygrid-footer{
433 display: block;
434 padding:0;
435 border-top: 1px solid #cbc7b8;
436}
437.ygrid-wrap-footer {
438 display: block;
439 overflow: hidden;
440 width:100%;
441 height:25px;
442 box-sizing: border-box;
443 -moz-box-sizing: border-box;
444 background-color: #ebeadb;
445 position:absolute;
446 bottom:0;
447}
448.ygrid-wrap-body {
449 left: 0;
450 overflow: hidden;
451 position: absolute;
452 top: 0;
453 display: block;
454}
455.ygrid-wrap-headers {
456 left: 0;
457 overflow: hidden;
458 position: absolute;
459 top: 0;
460 z-index: 12;
461}
462.ypopcal{
463 background: white;
464 padding:2px;
465 border: 1px solid gray;
466 z-index:12001;
467 -moz-outline:none;
468 position:absolute;
469 display:none;
470 top:0;
471 left:0;
472}
473.ypopcal-shadow {
474 background: #dddddd;
475 filter: progid:DXImageTransform.Microsoft.Blur(MakeShadow=true,pixelradius=1) Alpha(opacity=35,style=1,startX=0,finishX=200,FinishOpacity=35);
476 padding: 0;
477 position:absolute;
478 z-index:12000;
479 display:none;
480 top:0;
481 left:0;
482}
483.ypopcal-head{
484 width:150px;
485 background: #93b5e4;
486}
487.ypopcal-head td{
488 padding:1px;
489}
490.ypopcal-month{
491 color: white;
492 font: bold 7pt verdana;
493 text-decoration: none;
494 text-align:center;
495}
496.ypopcal-head .ypopcal-arrow{
497 width:16px;
498 text-align:center;
499 cursor:pointer;
500 -moz-user-select: none;
501}
502
503.ypopcal-head .next-month{
504 width:16px;
505 background-image: url(../images/default/grid/arrow-right-white.gif);
506 background-position: center;
507 background-repeat: no-repeat;
508 cursor:pointer;
509}
510.ypopcal-head .prev-month{
511 width:16px;
512 background-image: url(../images/default/grid/arrow-left-white.gif);
513 background-position: center;
514 background-repeat: no-repeat;
515 cursor:pointer;
516}
517
518.ypopcal-table {
519 background:white;
520 border-bottom: 1px solid #cccccc;
521}
522.ypopcal-table tr{
523
524}
525.ypopcal-table td{
526 box-sizing: border-box;
527 -moz-box-sizing: border-box;
528 border: 1px solid white;
529 text-align:right;
530 color:#aaaaaa;
531 cursor:pointer;
532 font:normal 8pt arial;
533 background:white;
534 padding:1px 2px;
535 width:12px;
536 height:12px;
537}
538.ypopcal-table td.today{
539 border: 1px solid darkred;
540}
541.ypopcal-table .ypopcal-daynames td{
542 text-align:center !important;
543 border:0;
544 border-bottom: 1px solid #cccccc;
545 font-size: 8pt;
546 font-weight: normal;
547 text-align:right;
548 color:black;
549 cursor:default;
550}
551.ypopcal-table td.active{
552 cursor:pointer;
553 color:black;
554}
555.ypopcal-table td.ypopcal-disabled{
556 cursor:default;
557 background:#eeeeee;
558 border: 1px solid #eeeeee;
559 color:#bbbbbb;
560}
561.ypopcal-table td.selected{
562 background: #ddecfe;
563 border: 1px solid #c3daf9;
564}
565.ypopcal-today{
566 color: black;
567 cursor: hand;
568 display: inline-block;
569 font: normal 8pt arial;
570 margin-left: 2px;
571 text-decoration: none;
572 margin-top:2px;
573}
574
575.ygrid-simple-view .ygrid-col{
576 height:100% !important;
577 position:static;
578 display:table-cell;
579 display:inline-block;
580}
581.ygrid-simple-view .ygrid-row{
582 position:static;
583 display: table-row;
584}
diff --git a/frontend/beta/css/yui-extensions/inline-editor.css b/frontend/beta/css/yui-extensions/inline-editor.css
new file mode 100644
index 0000000..1ef560a
--- a/dev/null
+++ b/frontend/beta/css/yui-extensions/inline-editor.css
@@ -0,0 +1,60 @@
1/*
2
3Copyright 2008-2011 Clipperz Srl
4
5This file is part of Clipperz's Javascript Crypto Library.
6Javascript Crypto Library provides web developers with an extensive
7and efficient set of cryptographic functions. The library aims to
8obtain maximum execution speed while preserving modularity and
9reusability.
10For further information about its features and functionalities please
11refer to http://www.clipperz.com
12
13* Javascript Crypto Library is free software: you can redistribute
14 it and/or modify it under the terms of the GNU Affero General Public
15 License as published by the Free Software Foundation, either version
16 3 of the License, or (at your option) any later version.
17
18* Javascript Crypto Library is distributed in the hope that it will
19 be useful, but WITHOUT ANY WARRANTY; without even the implied
20 warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
21 See the GNU Affero General Public License for more details.
22
23* You should have received a copy of the GNU Affero General Public
24 License along with Javascript Crypto Library. If not, see
25 <http://www.gnu.org/licenses/>.
26
27*/
28
29.yinline-editor {
30 border: 1px solid #a3bac9;
31 font: normal 11px arial,helvetica,sans-serif;
32 left: 0;
33 overflow: hidden;
34 padding: 1px 0 0 1px;
35 position: absolute;
36 top: 0;
37}
38.yinline-editor-multiline {
39 overflow: hidden;
40 padding: 0;
41 white-space: nowrap;
42}
43.yinline-editor-sizer {
44 font: normal 11px arial,helvetica,sans-serif;
45 left: -1000px;
46 padding: 3px;
47 padding-right: 6px;
48 position: absolute;
49 top: -1000px;
50 visibility: hidden;
51 white-space: nowrap;
52}
53.yinline-editor-wrap {
54 color: white;
55 overflow: auto;
56 position: absolute;
57 top: 0;
58 visibility: hidden;
59 z-index: 15002;
60}
diff --git a/frontend/beta/css/yui-extensions/layout.css b/frontend/beta/css/yui-extensions/layout.css
new file mode 100644
index 0000000..58456ac
--- a/dev/null
+++ b/frontend/beta/css/yui-extensions/layout.css
@@ -0,0 +1,228 @@
1/*
2
3Copyright 2008-2011 Clipperz Srl
4
5This file is part of Clipperz's Javascript Crypto Library.
6Javascript Crypto Library provides web developers with an extensive
7and efficient set of cryptographic functions. The library aims to
8obtain maximum execution speed while preserving modularity and
9reusability.
10For further information about its features and functionalities please
11refer to http://www.clipperz.com
12
13* Javascript Crypto Library is free software: you can redistribute
14 it and/or modify it under the terms of the GNU Affero General Public
15 License as published by the Free Software Foundation, either version
16 3 of the License, or (at your option) any later version.
17
18* Javascript Crypto Library is distributed in the hope that it will
19 be useful, but WITHOUT ANY WARRANTY; without even the implied
20 warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
21 See the GNU Affero General Public License for more details.
22
23* You should have received a copy of the GNU Affero General Public
24 License along with Javascript Crypto Library. If not, see
25 <http://www.gnu.org/licenses/>.
26
27*/
28
29.ylayout-container{
30 width:100%;
31 height:100%;
32 overflow:hidden;
33 background-color:#c3daf9;
34}
35.ylayout-collapsed{
36 position:absolute;
37 left:-10000px;
38 top:-10000px;
39 visibility:hidden;
40 background-color:#c3daf9;
41 width:20px;
42 height:20px;
43 overflow:hidden;
44 border:1px solid #98c0f4;
45 z-index:20;
46}
47.ylayout-collapsed-over{
48 cursor:pointer;
49 background-color:#d9e8fb;
50}
51.ylayout-collapsed-west .ylayout-tools-button{
52 float:right;
53}
54.ylayout-collapsed-east .ylayout-tools-button{
55 float:left;
56}
57.ylayout-collapsed-north, .ylayout-collapsed-south{
58 text-align:right;
59}
60.ylayout-collapsed .ylayout-tools-button{
61 margin:2px;
62 width:12px;
63 text-align:center;
64}
65.ylayout-inactive-content{
66 position:absolute;
67 left:-10000px;
68 top:-10000px;
69 visibility:hidden;
70}
71.ylayout-active-content{
72 visibility:visible;
73}
74.ylayout-panel{
75 position:absolute;border:1px solid #98c0f4;overflow:hidden;background-color:white;
76}
77.ylayout-panel-east, .ylayout-panel-west {
78 z-index:10;
79}
80.ylayout-panel-north, .ylayout-panel-south {
81 z-index:11;
82}
83.ylayout-collapsed-north, .ylayout-collapsed-south, .ylayout-collapsed-east, .ylayout-collapsed-west {
84 z-index:12;
85}
86.ylayout-panel-body{
87 overflow:hidden;
88}
89.ylayout-grid-wrapper{
90
91}
92.ylayout-split{
93 position:absolute;
94 height:5px;
95 width:5px;
96 line-height:1px;
97 font-size:1px;
98 z-index:3;
99 background-color:#c3daf9;
100}
101.ylayout-panel-hd{
102 background-image: url(../images/default/layout/panel-title-light-bg.gif);
103 color: black;
104 border-bottom:1px solid #98c0f4;
105 position:relative;
106}
107.ylayout-panel-hd-text{
108 font:normal 11px tahoma, verdana, helvetica;
109 padding: 4px;
110 padding-left: 4px;
111 display:block;
112 white-space:nowrap;
113}
114.ylayout-panel-hd-tools{
115 position:absolute;
116 right:0;
117 top:0;
118 text-align:right;
119 padding-top:2px;
120 padding-right:2px;width:40px;
121}
122.ylayout-tools-button{
123 z-index:6;
124 padding:2px;
125 cursor:pointer;
126}
127.ylayout-tools-button-over{
128 padding:1px;
129 border:1px solid #98c0f4;
130 background-color:white;
131}
132.ylayout-tools-button-inner{
133 height:12px;
134 width:12px;
135 line-height:1px;
136 font-size:1px;
137 background-repeat:no-repeat;
138 background-position:center;
139}
140.ylayout-close{
141 background-image:url(../images/default/layout/layout-sprite.gif);
142 background-repeat: no-repeat;
143 background-position: 50% -48px;
144}
145.ylayout-collapse-west,.ylayout-expand-east{
146 background-image:url(../images/default/layout/layout-sprite.gif);
147 background-repeat: no-repeat;
148 background-position: 50% 0;
149}
150.ylayout-expand-west,.ylayout-collapse-east{
151 background-image:url(../images/default/layout/layout-sprite.gif);
152 background-repeat: no-repeat;
153 background-position: 50% -12px;
154}
155.ylayout-collapse-north,.ylayout-expand-south{
156 background-image:url(../images/default/layout/layout-sprite.gif);
157 background-repeat: no-repeat;
158 background-position: 50% -24px;
159}
160.ylayout-expand-north,.ylayout-collapse-south{
161 background-image:url(../images/default/layout/layout-sprite.gif);
162 background-repeat: no-repeat;
163 background-position: 50% -36px;
164}
165.ylayout-split-h{
166 background-image:url(../images/default/sizer/e-handle.gif);
167 background-position: left;
168}
169.ylayout-split-v{
170 background-image:url(../images/default/sizer/s-handle.gif);
171 background-position: top;
172}
173.ylayout-panel .ytab-wrap{
174 background:url(../images/default/layout/gradient-bg.gif);
175}
176.ylayout-panel .yui-ext-tabbody {
177 background-color:white;
178 overflow:auto;height:100%;
179}
180.ylayout-component-panel, .ylayout-nested-layout {
181 position:relative;
182 padding:0;
183 overflow:hidden;
184 width:200px;
185 height:200px;
186}
187.ylayout-nested-layout .ylayout-panel {
188 border:0 none;
189}
190.ylayout-nested-layout .ylayout-panel-north {
191 border-bottom:1px solid #98c0f4;
192}
193.ylayout-nested-layout .ylayout-panel-south {
194 border-top:1px solid #98c0f4;
195}
196.ylayout-nested-layout .ylayout-panel-east {
197 border-left:1px solid #98c0f4;
198}
199.ylayout-nested-layout .ylayout-panel-west {
200 border-right:1px solid #98c0f4;
201}
202.yui-ext-repaint{
203 zoom:1;
204 background-color: transparent;
205}
206.ylayout-panel-dragover {
207 border: 2px solid #6593cf;
208}
209.ylayout-panel-proxy {
210 background-image: url(../images/default/layout/gradient-bg.gif);
211 background-color:#c3daf9;
212 border:1px dashed #6593cf;
213 z-index:10001;
214 overflow:hidden;
215 position:absolute;
216 left:0;top:0;
217}
218.ylayout-slider {
219 z-index:15;
220 overflow:hidden;
221 position:absolute;
222}
223
224.yunselectable{
225 -moz-user-select: none;
226 -khtml-user-select: none;
227 cursor:default;
228}
diff --git a/frontend/beta/css/yui-extensions/qtips.css b/frontend/beta/css/yui-extensions/qtips.css
new file mode 100644
index 0000000..4165168
--- a/dev/null
+++ b/frontend/beta/css/yui-extensions/qtips.css
@@ -0,0 +1,70 @@
1/*
2
3Copyright 2008-2011 Clipperz Srl
4
5This file is part of Clipperz's Javascript Crypto Library.
6Javascript Crypto Library provides web developers with an extensive
7and efficient set of cryptographic functions. The library aims to
8obtain maximum execution speed while preserving modularity and
9reusability.
10For further information about its features and functionalities please
11refer to http://www.clipperz.com
12
13* Javascript Crypto Library is free software: you can redistribute
14 it and/or modify it under the terms of the GNU Affero General Public
15 License as published by the Free Software Foundation, either version
16 3 of the License, or (at your option) any later version.
17
18* Javascript Crypto Library is distributed in the hope that it will
19 be useful, but WITHOUT ANY WARRANTY; without even the implied
20 warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
21 See the GNU Affero General Public License for more details.
22
23* You should have received a copy of the GNU Affero General Public
24 License along with Javascript Crypto Library. If not, see
25 <http://www.gnu.org/licenses/>.
26
27*/
28
29.ytip{
30 position: absolute;
31 top: 0;
32 visibility: hidden;
33 z-index: 11000;
34}
35.ytip .ytip-bd{
36 background: #e0e8f3 url(../images/default/qtip/bg.gif) repeat-x;
37 border: 1px solid #a3bad9;
38 font: normal 11px arial,helvetica,sans-serif;
39 padding: 5px;
40}
41.ytip .ytip-close{
42 background-image: url(../images/default/basic-dialog/close.gif);
43 height: 15px;
44 position: absolute;
45 right: 3px;
46 top: 3px;
47 width: 15px;
48}
49.ytip .ytip-hd {
50 background: url(../images/default/basic-dialog/hd-sprite.gif) repeat-x 0px -82px;
51 background-color: navy;
52 color: #FFF;
53 display: block;
54 font: bold 11px tahoma, arial, verdana, helvetica;
55 padding: 4px;
56}
57.ytip .ytip-hd-left {
58 background: url(../images/default/basic-dialog/hd-sprite.gif) no-repeat 0px -41px;
59 display: block;
60 margin: 0px;
61 padding-left: 3px;
62}
63.ytip .ytip-hd-right {
64 background: url(../images/default/basic-dialog/hd-sprite.gif) no-repeat right 0px;
65 display: block;
66 padding-right: 3px;
67}
68y\:qtip, qtip{
69 display: none;
70}
diff --git a/frontend/beta/css/yui-extensions/reset-min.css b/frontend/beta/css/yui-extensions/reset-min.css
new file mode 100644
index 0000000..25a5158
--- a/dev/null
+++ b/frontend/beta/css/yui-extensions/reset-min.css
@@ -0,0 +1,29 @@
1/*
2
3Copyright 2008-2011 Clipperz Srl
4
5This file is part of Clipperz's Javascript Crypto Library.
6Javascript Crypto Library provides web developers with an extensive
7and efficient set of cryptographic functions. The library aims to
8obtain maximum execution speed while preserving modularity and
9reusability.
10For further information about its features and functionalities please
11refer to http://www.clipperz.com
12
13* Javascript Crypto Library is free software: you can redistribute
14 it and/or modify it under the terms of the GNU Affero General Public
15 License as published by the Free Software Foundation, either version
16 3 of the License, or (at your option) any later version.
17
18* Javascript Crypto Library is distributed in the hope that it will
19 be useful, but WITHOUT ANY WARRANTY; without even the implied
20 warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
21 See the GNU Affero General Public License for more details.
22
23* You should have received a copy of the GNU Affero General Public
24 License along with Javascript Crypto Library. If not, see
25 <http://www.gnu.org/licenses/>.
26
27*/
28
29body,div,dl,dt,dd,ul,ol,li,h1,h2,h3,h4,h5,h6,pre,form,fieldset,input,p,blockquote,th,td{margin:0;padding:0;}fieldset,img{border:0;}address,caption,cite,code,dfn,em,strong,th,var{font-style:normal;font-weight:normal;}ol,ul {list-style:none;}caption,th {text-align:left;}h1,h2,h3,h4,h5,h6{font-size:100%;}q:before,q:after{content:'';} \ No newline at end of file
diff --git a/frontend/beta/css/yui-extensions/resizable.css b/frontend/beta/css/yui-extensions/resizable.css
new file mode 100644
index 0000000..46fef2a
--- a/dev/null
+++ b/frontend/beta/css/yui-extensions/resizable.css
@@ -0,0 +1,160 @@
1/*
2
3Copyright 2008-2011 Clipperz Srl
4
5This file is part of Clipperz's Javascript Crypto Library.
6Javascript Crypto Library provides web developers with an extensive
7and efficient set of cryptographic functions. The library aims to
8obtain maximum execution speed while preserving modularity and
9reusability.
10For further information about its features and functionalities please
11refer to http://www.clipperz.com
12
13* Javascript Crypto Library is free software: you can redistribute
14 it and/or modify it under the terms of the GNU Affero General Public
15 License as published by the Free Software Foundation, either version
16 3 of the License, or (at your option) any later version.
17
18* Javascript Crypto Library is distributed in the hope that it will
19 be useful, but WITHOUT ANY WARRANTY; without even the implied
20 warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
21 See the GNU Affero General Public License for more details.
22
23* You should have received a copy of the GNU Affero General Public
24 License along with Javascript Crypto Library. If not, see
25 <http://www.gnu.org/licenses/>.
26
27*/
28
29.yresizable-handle {
30 position:absolute;
31 z-index:100;
32 /* ie needs these */
33 font-size:1px;
34 line-height:6px;
35 overflow:hidden;
36 background:white;
37 filter:alpha(opacity=0);
38 opacity:0;
39 zoom:1;
40}
41.yresizable-handle-east{
42 width:6px;
43 cursor:e-resize;
44 right:0px;
45 top:0px;
46 height:100%;
47 margin-right:-1px; /*IE rounding error*/
48}
49.yresizable-handle-south{
50 width:100%;
51 cursor:s-resize;
52 left:0px;
53 bottom:0px;
54 height:6px;
55 margin-bottom:-1px; /*IE rounding error*/
56}
57.yresizable-handle-west{
58 width:6px;
59 cursor:w-resize;
60 left:0px;
61 top:0px;
62 height:100%;
63}
64.yresizable-handle-north{
65 width:100%;
66 cursor:n-resize;
67 left:0px;
68 top:0px;
69 height:6px;
70}
71.yresizable-handle-southeast{
72 width:6px;
73 cursor:se-resize;
74 right:0px;
75 bottom:0px;
76 height:6px;
77 z-index:101;
78}
79.yresizable-handle-northwest{
80 width:6px;
81 cursor:nw-resize;
82 left:0px;
83 top:0px;
84 height:6px;
85 z-index:101;
86}
87.yresizable-handle-northeast{
88 width:6px;
89 cursor:ne-resize;
90 right:0px;
91 top:0px;
92 height:6px;
93 z-index:101;
94}
95.yresizable-handle-southwest{
96 width:6px;
97 cursor:sw-resize;
98 left:0px;
99 bottom:0px;
100 height:6px;
101 z-index:101;
102}
103.yresizable-over .yresizable-handle, .yresizable-pinned .yresizable-handle{
104 filter:alpha(opacity=100);
105 opacity:1;
106}
107.yresizable-over .yresizable-handle-east, .yresizable-pinned .yresizable-handle-east{
108 background:url(../images/default/sizer/e-handle.gif);
109 background-position: left;
110}
111.yresizable-over .yresizable-handle-west, .yresizable-pinned .yresizable-handle-west{
112 background:url(../images/default/sizer/e-handle.gif);
113 background-position: left;
114}
115.yresizable-over .yresizable-handle-south, .yresizable-pinned .yresizable-handle-south{
116 background:url(../images/default/sizer/s-handle.gif);
117 background-position: top;
118}
119.yresizable-over .yresizable-handle-north, .yresizable-pinned .yresizable-handle-north{
120 background:url(../images/default/sizer/s-handle.gif);
121 background-position: top;
122}
123.yresizable-over .yresizable-handle-southeast, .yresizable-pinned .yresizable-handle-southeast{
124 background:url(../images/default/sizer/corners-sprite.gif);
125 background-position: top left;
126}
127.yresizable-over .yresizable-handle-northwest, .yresizable-pinned .yresizable-handle-northwest{
128 background:url(../images/default/sizer/corners-sprite.gif);
129 background-position:bottom right;
130}
131.yresizable-over .yresizable-handle-northeast, .yresizable-pinned .yresizable-handle-northeast{
132 background:url(../images/default/sizer/corners-sprite.gif);
133 background-position: bottom left;
134}
135.yresizable-over .yresizable-handle-southwest, .yresizable-pinned .yresizable-handle-southwest{
136 background:url(../images/default/sizer/corners-sprite.gif);
137 background-position: top right;
138}
139.yresizable-proxy{
140 border: 1px dashed #6593cf;
141 position:absolute;
142 overflow:hidden;
143 visibility:hidden;
144 left:0;top:0;
145 z-index:1001;
146}
147.yresizable-overlay{
148 width:100%;
149 height:100%;
150 display:none;
151 position:absolute;
152 left:0;
153 top:0;
154 background:white;
155 z-index:20000;
156 -moz-opacity: 0;
157 opacity:0;
158 filter: alpha(opacity=0);
159 border:1px solid red;
160}
diff --git a/frontend/beta/css/yui-extensions/tabs.css b/frontend/beta/css/yui-extensions/tabs.css
new file mode 100644
index 0000000..8eb81e0
--- a/dev/null
+++ b/frontend/beta/css/yui-extensions/tabs.css
@@ -0,0 +1,152 @@
1/*
2
3Copyright 2008-2011 Clipperz Srl
4
5This file is part of Clipperz's Javascript Crypto Library.
6Javascript Crypto Library provides web developers with an extensive
7and efficient set of cryptographic functions. The library aims to
8obtain maximum execution speed while preserving modularity and
9reusability.
10For further information about its features and functionalities please
11refer to http://www.clipperz.com
12
13* Javascript Crypto Library is free software: you can redistribute
14 it and/or modify it under the terms of the GNU Affero General Public
15 License as published by the Free Software Foundation, either version
16 3 of the License, or (at your option) any later version.
17
18* Javascript Crypto Library is distributed in the hope that it will
19 be useful, but WITHOUT ANY WARRANTY; without even the implied
20 warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
21 See the GNU Affero General Public License for more details.
22
23* You should have received a copy of the GNU Affero General Public
24 License along with Javascript Crypto Library. If not, see
25 <http://www.gnu.org/licenses/>.
26
27*/
28
29.ytab-wrap {
30 border-bottom:1px solid #6593cf;
31 padding-top:2px;
32}
33.ytab-strip-wrap{
34 width:100%;
35}
36.ytab-wrap table{
37 position:relative;
38 top:0; left:0;
39}
40.ytab-strip td{
41 padding:0;
42 padding-left:2px;
43}
44.ytab-strip a, .ytab-strip span, .ytab-strip em {
45 display:block;
46}
47.ytab-strip a {
48 text-decoration:none !important;
49 -moz-outline: none;
50 outline: none;
51 cursor:pointer;
52}
53.ytab-strip .ytab-text {
54 font:bold 11px tahoma,arial,helvetica;
55 color:#666;
56 overflow:hidden;
57 white-space: nowrap;
58 cursor:pointer;
59 text-overflow: ellipsis;
60}
61.ytab-strip .on .ytab-text {
62 cursor:default;
63 color:#083772;
64}
65.ytab-strip .disabled .ytab-text {
66 cursor:default;
67 color:#aaaaaa;
68}
69.ytab-strip .ytab-inner {
70 padding:4px 10px;
71}
72
73.ytab-strip .on .ytab-right {
74 background: url(../images/default/tabs/tab-sprite.gif) no-repeat right 0;
75}
76.ytab-strip .on .ytab-left {
77 background: url(../images/default/tabs/tab-sprite.gif) no-repeat 0 -100px;
78}
79.ytab-strip .ytab-right {
80 background: url(../images/default/tabs/tab-sprite.gif) no-repeat right -50px;
81}
82.ytab-strip .ytab-left {
83 background: url(../images/default/tabs/tab-sprite.gif) no-repeat 0 -150px;
84}
85
86.ytab-strip a {
87 position:relative;
88 top:1px; left:0;
89}
90.ytab-strip .on a {
91 position:relative;
92}
93.ytab-strip .on .ytab-inner {
94 padding-bottom:5px;
95}
96/** closable tabs */
97.ytab-strip .ytab-closable .ytab-inner{
98 padding-right:22px;
99 position:relative;
100}
101.ytab-strip .ytab-closable .close-icon{
102 line-height: 1px;
103 font-size:1px;
104 background-image:url(../images/default/layout/layout-sprite.gif);
105 background-repeat: no-repeat;
106 background-position: 50% -60px;
107 display:block;
108 position:absolute;
109 right:5px;top:4px;
110 width:12px;height:11px;
111 cursor:pointer;
112}
113.ytab-strip .on .close-icon{
114 background-image:url(../images/default/layout/layout-sprite.gif);
115 background-repeat: no-repeat;
116 background-position: 50% -60px;
117}
118.ytab-strip .ytab-closable .close-over{
119 background-image:url(../images/default/layout/layout-sprite.gif);
120 background-repeat: no-repeat;
121 background-position: 50% -72px;
122}
123
124.ytabs-bottom .ytab-wrap {
125 border-top:1px solid #6593cf;
126 border-bottom:0 none;
127 padding-top:0;
128 padding-bottom:2px;
129}
130.ytabs-bottom .ytab-strip .ytab-right {
131 background: url(../images/default/tabs/tab-btm-inactive-right-bg.gif) no-repeat bottom left;
132}
133.ytabs-bottom .ytab-strip .ytab-left {
134 background: url(../images/default/tabs/tab-btm-inactive-left-bg.gif) no-repeat bottom right;
135}
136.ytabs-bottom .ytab-strip .on .ytab-right {
137 background: url(../images/default/tabs/tab-btm-right-bg.gif) no-repeat bottom left;
138}
139.ytabs-bottom .ytab-strip .on .ytab-left {
140 background: url(../images/default/tabs/tab-btm-left-bg.gif) no-repeat bottom right;
141}
142.ytabs-bottom .ytab-strip a {
143 position:relative;
144 top:0; left:0;
145}
146.ytabs-bottom .ytab-strip .on a {
147 margin-top:-1px;
148}
149.ytabs-bottom .ytab-strip .on .ytab-inner {
150 padding-top:5px;
151}
152
diff --git a/frontend/beta/css/yui-extensions/toolbar.css b/frontend/beta/css/yui-extensions/toolbar.css
new file mode 100644
index 0000000..df91c83
--- a/dev/null
+++ b/frontend/beta/css/yui-extensions/toolbar.css
@@ -0,0 +1,115 @@
1/*
2
3Copyright 2008-2011 Clipperz Srl
4
5This file is part of Clipperz's Javascript Crypto Library.
6Javascript Crypto Library provides web developers with an extensive
7and efficient set of cryptographic functions. The library aims to
8obtain maximum execution speed while preserving modularity and
9reusability.
10For further information about its features and functionalities please
11refer to http://www.clipperz.com
12
13* Javascript Crypto Library is free software: you can redistribute
14 it and/or modify it under the terms of the GNU Affero General Public
15 License as published by the Free Software Foundation, either version
16 3 of the License, or (at your option) any later version.
17
18* Javascript Crypto Library is distributed in the hope that it will
19 be useful, but WITHOUT ANY WARRANTY; without even the implied
20 warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
21 See the GNU Affero General Public License for more details.
22
23* You should have received a copy of the GNU Affero General Public
24 License along with Javascript Crypto Library. If not, see
25 <http://www.gnu.org/licenses/>.
26
27*/
28
29.ytoolbar{
30 background-color: #ebeadb;
31 border: 1px solid #cbc7b8;
32 display: block;
33 padding:2px;
34}
35
36.mso .ytoolbar, .ygrid-mso .ytoolbar{
37 border: 0px none;
38 background: url(../images/default/grid/mso-hd.gif);
39}
40.ytoolbar td,.ytoolbar span,.ytoolbar input,.ytoolbar div{
41 white-space: nowrap;
42 font:normal 8pt arial,helvetica;
43}
44.ytoolbar .ytb-button-disabled .ytb-button-inner{
45 color:gray;
46 cursor:default;
47}
48
49/*
50 Default button class is icon only. Add a class with a background-image property
51 to your toolbar button
52*/
53.ytoolbar .ytb-button-inner{
54 background-position: center;
55 background-repeat: no-repeat;
56 display: block;
57 height: 16px;
58 width: 16px;
59 cursor:pointer;
60 white-space: nowrap;
61}
62
63/*
64 Button class for icon and text. Add this class and a class with a background-image
65 to your toolbar button for both text and icon
66*/
67.ytoolbar .ytb-text-icon{
68 background-position: 0px 0px;
69 background-repeat: no-repeat;
70 padding-left:18px;
71 padding-top:1px;
72 width:auto;
73 display:block;
74}
75
76/*
77 Button class for a button with only text. Add this class
78 to your toolbar button for a just text button
79*/
80.ytoolbar .ytb-text-only{
81 background:none;
82 padding-left:0px;
83 padding-top:1px;
84 width:auto;
85 display:block;
86}
87.ytoolbar .ytb-text{
88 padding:2px;
89}
90.ytoolbar .ytb-button{
91 padding:2px 3px;
92 display:block;
93}
94.ytoolbar .ytb-button-over{
95 background:#c3d3ed url(../images/default/toolbar/btn-over-bg.gif) repeat-x;
96 border:1px solid #6593cf;
97 padding:1px 2px;
98}
99.ytoolbar .ytb-sep {
100 background-image: url(../images/default/grid/grid-split.gif);
101 background-position: center;
102 background-repeat: no-repeat;
103 display: block;
104 font-size: 1px;
105 height: 16px;
106 width:4px;
107 overflow: hidden;
108 cursor:default;
109 margin: 0px 2px 0px;
110 border:0px;
111}
112.mso .ytoolbar .ytb-sep, .ygrid-mso .ytoolbar .ytb-sep{
113 background-image: url(../images/default/grid/grid-blue-split.gif);
114}
115
diff --git a/frontend/beta/css/yui-extensions/tree.css b/frontend/beta/css/yui-extensions/tree.css
new file mode 100644
index 0000000..9667f83
--- a/dev/null
+++ b/frontend/beta/css/yui-extensions/tree.css
@@ -0,0 +1,193 @@
1/*
2
3Copyright 2008-2011 Clipperz Srl
4
5This file is part of Clipperz's Javascript Crypto Library.
6Javascript Crypto Library provides web developers with an extensive
7and efficient set of cryptographic functions. The library aims to
8obtain maximum execution speed while preserving modularity and
9reusability.
10For further information about its features and functionalities please
11refer to http://www.clipperz.com
12
13* Javascript Crypto Library is free software: you can redistribute
14 it and/or modify it under the terms of the GNU Affero General Public
15 License as published by the Free Software Foundation, either version
16 3 of the License, or (at your option) any later version.
17
18* Javascript Crypto Library is distributed in the hope that it will
19 be useful, but WITHOUT ANY WARRANTY; without even the implied
20 warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
21 See the GNU Affero General Public License for more details.
22
23* You should have received a copy of the GNU Affero General Public
24 License along with Javascript Crypto Library. If not, see
25 <http://www.gnu.org/licenses/>.
26
27*/
28
29.ytree-icon, .ytree-ec-icon, .ytree-elbow-line, .ytree-elbow, .ytree-elbow-end, .ytree-elbow-plus, .ytree-elbow-minus, .ytree-elbow-end-plus, .ytree-elbow-end-minus{
30 border: 0 none;
31 height: 18px;
32 margin: 0px;
33 padding: 0px;
34 vertical-align: middle;
35 width: 16px;
36}
37.ytree-node-collapsed .ytree-node-icon, .ytree-node-expanded .ytree-node-icon, .ytree-node-leaf .ytree-node-icon{
38 border: 0 none;
39 height: 16px;
40 margin: 0px;
41 padding: 0px;
42 vertical-align: middle;
43 width: 16px;
44 background-position:center;
45}
46
47/* some default icons for leaf/folder */
48.ytree-node-collapsed .ytree-node-icon{
49 background:transparent url(../images/default/tree/folder.gif);
50}
51.ytree-node-expanded .ytree-node-icon{
52 background:transparent url(../images/default/tree/folder-open.gif);
53}
54.ytree-node-leaf .ytree-node-icon{
55 background:transparent url(../images/default/tree/leaf.gif);
56}
57
58/* loading icon */
59.ytree-node-loading .ytree-node-icon{
60 background:transparent url(../images/default/tree/loading.gif) !important;
61}
62.ytree-node-loading a span{
63 font-style: italic;
64 color:#444444;
65}
66
67/* Line styles */
68.ytree-lines .ytree-elbow{
69 background:transparent url(../images/default/tree/elbow.gif);
70}
71.ytree-lines .ytree-elbow-plus{
72 background:transparent url(../images/default/tree/elbow-plus.gif);
73}
74.ytree-lines .ytree-elbow-minus{
75 background:transparent url(../images/default/tree/elbow-minus.gif);
76}
77.ytree-lines .ytree-elbow-end{
78 background:transparent url(../images/default/tree/elbow-end.gif);
79}
80.ytree-lines .ytree-elbow-end-plus{
81 background:transparent url(../images/default/tree/elbow-end-plus.gif);
82}
83.ytree-lines .ytree-elbow-end-minus{
84 background:transparent url(../images/default/tree/elbow-end-minus.gif);
85}
86.ytree-lines .ytree-elbow-line{
87 background:transparent url(../images/default/tree/elbow-line.gif);
88}
89
90/* No line styles */
91.ytree-no-lines .ytree-elbow{
92 background:transparent;
93}
94.ytree-no-lines .ytree-elbow-plus{
95 background:transparent url(../images/default/tree/elbow-plus-nl.gif);
96}
97.ytree-no-lines .ytree-elbow-minus{
98 background:transparent url(../images/default/tree/elbow-minus-nl.gif);
99}
100.ytree-no-lines .ytree-elbow-end{
101 background:transparent;
102}
103.ytree-no-lines .ytree-elbow-end-plus{
104 background:transparent url(../images/default/tree/elbow-end-plus-nl.gif);
105}
106.ytree-no-lines .ytree-elbow-end-minus{
107 background:transparent url(../images/default/tree/elbow-end-minus-nl.gif);
108}
109.ytree-no-lines .ytree-elbow-line{
110 background:transparent;
111}
112
113.ytree-elbow-plus, .ytree-elbow-minus, .ytree-elbow-end-plus, .ytree-elbow-end-minus{
114 cursor:pointer;
115}
116
117.ytree-node{
118 color: black;
119 font: normal 11px arial, helvetica, sans-serif;
120 white-space: nowrap;
121}
122.ytree-node a, .ydd-drag-ghost a{
123 text-decoration:none;
124 color:black;
125 -khtml-user-select:normal;
126 -moz-user-select:normal;
127}
128.ytree-node a span, .ydd-drag-ghost a span{
129 text-decoration:none;
130 color:black;
131 padding:1px 3px 1px 2px;
132}
133.ytree-node .ytree-node-disabled a span{
134 color:gray !important;
135}
136.ytree-node .ytree-node-disabled .ytree-node-icon{
137 -moz-opacity: 0.5;
138 opacity:.5;
139 filter: alpha(opacity=50);
140}
141.ytree-node .ytree-node-inline-icon{
142 background:transparent;
143}
144.ytree-node a:hover, .ydd-drag-ghost a:hover{
145 text-decoration:none;
146}
147.ytree-node div.ytree-drag-insert-below{
148 border-bottom:1px dotted #3366cc;
149}
150.ytree-node div.ytree-drag-insert-above{
151 border-top:1px dotted #3366cc;
152}
153.ytree-dd-underline .ytree-node div.ytree-drag-insert-below{
154 border-bottom:0px none;
155}
156.ytree-dd-underline .ytree-node div.ytree-drag-insert-above{
157 border-top:0px none;
158}
159.ytree-dd-underline .ytree-node div.ytree-drag-insert-below a{
160 border-bottom:2px solid #3366cc;
161}
162.ytree-dd-underline .ytree-node div.ytree-drag-insert-above a{
163 border-top:2px solid #3366cc;
164}
165.ytree-node .ytree-drag-append a span{
166 background:#dddddd;
167 border:1px dotted gray;
168}
169.ytree-node .ytree-selected a span{
170 background:#3366cc;
171 color:white;
172}
173.ydd-drag-ghost .ytree-node-indent, .ydd-drag-ghost .ytree-ec-icon{
174 display:none !important;
175}
176.ytree-drop-ok-append .ydd-drop-icon{
177 background-image: url(../images/default/tree/drop-add.gif);
178}
179.ytree-drop-ok-above .ydd-drop-icon{
180 background-image: url(../images/default/tree/drop-over.gif);
181}
182.ytree-drop-ok-below .ydd-drop-icon{
183 background-image: url(../images/default/tree/drop-under.gif);
184}
185.ytree-drop-ok-between .ydd-drop-icon{
186 background-image: url(../images/default/tree/drop-between.gif);
187}
188.ylayer-shadow{
189 background:#cccccc;
190 opacity:.3;
191 -moz-opacity:.3;
192 filter: alpha(opacity=30);
193}
diff --git a/frontend/beta/css/yui-extensions/ytheme-aero.css b/frontend/beta/css/yui-extensions/ytheme-aero.css
new file mode 100644
index 0000000..10d8ec0
--- a/dev/null
+++ b/frontend/beta/css/yui-extensions/ytheme-aero.css
@@ -0,0 +1,361 @@
1/*
2
3Copyright 2008-2011 Clipperz Srl
4
5This file is part of Clipperz's Javascript Crypto Library.
6Javascript Crypto Library provides web developers with an extensive
7and efficient set of cryptographic functions. The library aims to
8obtain maximum execution speed while preserving modularity and
9reusability.
10For further information about its features and functionalities please
11refer to http://www.clipperz.com
12
13* Javascript Crypto Library is free software: you can redistribute
14 it and/or modify it under the terms of the GNU Affero General Public
15 License as published by the Free Software Foundation, either version
16 3 of the License, or (at your option) any later version.
17
18* Javascript Crypto Library is distributed in the hope that it will
19 be useful, but WITHOUT ANY WARRANTY; without even the implied
20 warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
21 See the GNU Affero General Public License for more details.
22
23* You should have received a copy of the GNU Affero General Public
24 License along with Javascript Crypto Library. If not, see
25 <http://www.gnu.org/licenses/>.
26
27*/
28
29/**
30* Tabs
31*/
32.ytab-wrap, .ylayout-panel .ytabs-top .ytab-wrap {
33 background:#deecfd;
34 border:1px solid #8db2e3;
35 padding-bottom:2px;
36 padding-top:0px;
37}
38.ytab-strip-wrap{
39 padding-top:1px;
40 background:#cedff5 url(../images/aero/tabs/tab-strip-bg.gif) repeat-x bottom;
41 border-bottom:1px solid #8db2e3;
42}
43.ytab-strip .ytab-text {
44 color:#15428b;
45 font-weight:normal;
46}
47.ytab-strip .on .ytab-text {
48 cursor:default;
49 color:#15428b;
50}
51.ytabs-top .ytab-strip .on .ytab-right {
52 background: url(../images/aero/tabs/tab-sprite.gif) no-repeat right 0px;
53}
54.ytabs-top .ytab-strip .on .ytab-left,.ytabs-top .ytab-strip .on a:hover .ytab-left{
55 background: url(../images/aero/tabs/tab-sprite.gif) no-repeat 0px -100px;
56}
57.ytabs-top .ytab-strip .ytab-right {
58 background:transparent url(../images/aero/tabs/tab-sprite.gif) no-repeat right -50px;
59}
60.ytabs-top .ytab-strip .ytab-left {
61 background:transparent url(../images/aero/tabs/tab-sprite.gif) no-repeat 0px -150px;
62}
63.ytabs-top .yui-ext-tabbody {
64 border:1px solid #8db2e3;
65 border-top:0px none;
66}
67.ytabs-bottom .ytab-wrap, .ylayout-panel .ytabs-bottom .ytab-wrap {
68 background:#deecfd;
69 border:1px solid #8db2e3;
70 padding-top:2px;
71 padding-bottom:0px;
72}
73.ytabs-bottom .ytab-strip-wrap{
74 padding-top:0px;
75 padding-bottom:1px;
76 background:#cedff5 url(../images/aero/tabs/tab-strip-btm-bg.gif) repeat-x top;
77 border-top:1px solid #8db2e3;
78 border-bottom:0px none;
79}
80.ytabs-bottom .ytab-strip .ytab-right {
81 background:transparent url(../images/aero/tabs/tab-btm-inactive-right-bg.gif) no-repeat bottom right;
82}
83.ytabs-bottom .ytab-strip .ytab-left {
84 background:transparent url(../images/aero/tabs/tab-btm-inactive-left-bg.gif) no-repeat bottom left;
85}
86.ytabs-bottom .ytab-strip .on .ytab-right,.ytabs-bottom .ytab-strip .on a:hover {
87 background: url(../images/aero/tabs/tab-btm-right-bg.gif) no-repeat bottom left;
88}
89.ytabs-bottom .ytab-strip .on .ytab-left,.ytabs-bottom .ytab-strip .on a:hover .ytab-left {
90 background: url(../images/aero/tabs/tab-btm-left-bg.gif) no-repeat bottom right;
91}
92.ytabs-bottom .yui-ext-tabbody {
93 border:1px solid #8db2e3;
94 border-bottom:0px none;
95}
96/**
97* Basic-Dialog
98*/
99.ydlg-proxy {
100 background:#C7DFFC;
101 border:1px solid #A5CCF9;
102}
103.ydlg-shadow{
104 background:#cccccc;
105 opacity:.3;
106 -moz-opacity:.3;
107 filter: alpha(opacity=30);
108}
109.ydlg {
110 background:transparent;
111}
112.ydlg .ydlg-hd {
113 background: url(../images/aero/basic-dialog/hd-sprite.gif) repeat-x 0px -82px;
114 background-color:#aabaca;
115 color:#15428b;
116 zoom:1;
117 padding-top:7px;
118}
119.ydlg .ydlg-hd-left {
120 opacity:.85;-moz-opacity:.85;filter:alpha(opacity=80);
121 background: url(../images/aero/basic-dialog/hd-sprite.gif) no-repeat 0px -41px;
122 zoom:1;
123}
124.ydlg-modal .ydlg-hd-left {
125 opacity:.75;-moz-opacity:.75;filter:alpha(opacity=70);
126}
127
128.ydlg .ydlg-hd-right {
129 background: url(../images/aero/basic-dialog/hd-sprite.gif) no-repeat right 0px;
130 zoom:1;
131}
132.ydlg .ydlg-dlg-body{
133 padding:0px 0px 0px;
134 position:absolute;
135 top:24px;left:0px;
136 z-index:1;
137 border:0px none;
138 background:transparent;
139}
140.ydlg .ydlg-bd{
141 background:#fff;
142 border:1px solid #96b9e6;
143}
144.ydlg .ydlg-ft{
145 border:0px none;
146 background:transparent;
147 padding-bottom:8px;
148}
149.ydlg .ydlg-bg{
150 filter:alpha(opacity=80);
151 opacity:.85;
152 -moz-opacity:.85;
153 zoom:1;
154}
155.ydlg-modal .ydlg-bg {
156 opacity:.75;-moz-opacity:.75;filter:alpha(opacity=70);
157}
158.ydlg .ydlg-bg-center {
159 padding: 2px 7px 7px 7px;
160 background:transparent url(../images/aero/basic-dialog/bg-center.gif) repeat-x bottom;
161 zoom:1;
162}
163.ydlg .ydlg-bg-left{
164 padding-left:7px;
165 background:transparent url(../images/aero/basic-dialog/bg-left.gif) no-repeat bottom left;
166 zoom:1;
167}
168.ydlg .ydlg-bg-right{
169 padding-right:7px;
170 background:transparent url(../images/aero/basic-dialog/bg-right.gif) no-repeat bottom right;
171 zoom:1;
172}
173.ydlg-auto-tabs .ydlg-dlg-body, .ydlg-auto-layout .ydlg-dlg-body{
174 background:transparent;
175 border:0px none;
176}
177.ydlg-auto-tabs .ydlg-bd, .ydlg-auto-layout .ydlg-bd{
178 background:#fff;
179 border:1px solid #e9f3f5;
180}
181.ydlg-auto-tabs .ytabs-top .yui-ext-tabbody,.ydlg-auto-tabs .ytabs-bottom .yui-ext-tabbody{
182 border-color:#8db2e3;
183}
184.ydlg-auto-tabs .ytabs-top .ytab-wrap,.ydlg-auto-tabs .ytabs-bottom .ytab-wrap{
185 border-color:#8db2e3;
186}
187.ydlg .ydlg-close {
188 width:21px;
189 height:20px;
190 top:5px;
191 right:5px;
192 opacity:.85;-moz-opacity:.85;filter:alpha(opacity=80);
193 background-image:url(../images/aero/basic-dialog/aero-close.gif);
194 zoom:1;
195}
196.ydlg .ydlg-close-over {
197 background-image:url(../images/aero/basic-dialog/aero-close-over.gif);
198}
199.ydlg div.yresizable-handle-east{
200 background-image:url(../images/aero/s.gif);
201 border:0px none;
202}
203.ydlg div.yresizable-handle-south{
204 background-image:url(../images/aero/s.gif);
205 border:0px none;
206}
207.ydlg div.yresizable-handle-west{
208 background-image:url(../images/aero/s.gif);
209 border:0px none;
210}
211.ydlg div.yresizable-handle-southeast{
212 background-image:url(../images/aero/basic-dialog/se-handle.gif);
213 background-position: bottom right;
214 width:9px;
215 height:9px;
216 border:0px;
217 right:2px;
218 bottom:2px;
219}
220.ydlg div.yresizable-handle-southwest{
221 background-image:url(../images/aero/s.gif);
222 background-position: top right;
223 margin-left:1px;
224 margin-bottom:1px;
225 border:0px;
226}
227.ydlg div.yresizable-handle-north{
228 background-image:url(../images/aero/s.gif);
229 border:0px none;
230}
231
232#mb-dlg .ydlg-bd{
233 background:#CFE0F5;
234 border:0px none;
235}
236
237/* BorderLayout */
238.ylayout-container{
239 background:#deecfd;
240}
241.ylayout-collapsed{
242 background-color:#deecfd;
243 border:1px solid #99bbe8;
244}
245.ylayout-collapsed-over{
246 background-color:#F5F9FE;
247}
248.ylayout-panel{
249 border:1px solid #99bbe8;
250}
251.ylayout-nested-layout .ylayout-panel {
252 border:0px none;
253}
254.ylayout-split{
255 background-color:#deecfd;
256}
257.ylayout-panel-hd{
258 background-image: url(../images/aero/layout/panel-title-light-bg.gif);
259 border-bottom:1px solid #c0d7f4;
260}
261.ylayout-panel-hd-text {
262 color:#15428b;
263}
264
265.ylayout-split-h{
266 background:#deecfd;
267}
268.ylayout-split-v{
269 background:#deecfd;
270}
271.ylayout-panel .ytabs-top .ytab-wrap{
272 border:0px none;
273 border-bottom:1px solid #8db2e3;
274}
275.ylayout-panel .ytabs-bottom .ytab-wrap{
276 border:0px none;
277 border-top:1px solid #8db2e3;
278}
279.ylayout-container .yui-ext-tabbody{
280 border:0px none;
281}
282
283.ylayout-nested-layout .ylayout-panel-north {
284 border-bottom:1px solid #99bbe8;
285}
286.ylayout-nested-layout .ylayout-panel-south {
287 border-top:1px solid #99bbe8;
288}
289.ylayout-nested-layout .ylayout-panel-east {
290 border-left:1px solid #99bbe8;
291}
292.ylayout-nested-layout .ylayout-panel-west {
293 border-right:1px solid #99bbe8;
294}
295.ylayout-panel-dragover {
296 border: 2px solid #99bbe8;
297}
298.ylayout-panel-proxy {
299 background-image: url(../images/aero/layout/gradient-bg.gif);
300 background-color:#f3f2e7;
301 border:1px dashed #99bbe8;
302}
303/** Resizable */
304
305.yresizable-proxy{
306 border: 1px dashed #3b5a82;
307}
308
309/* grid */
310.ygrid-hd{
311 border-bottom:0px;
312 background:none;
313}
314.ygrid-hd-body {
315 border-bottom:0px none;
316}
317.ygrid-hd-over {
318 border-bottom:0px none;
319}
320.ygrid-hd-over .ygrid-hd-body{
321 background:none;
322 border-bottom:0px none;
323}
324.ygrid-hd-over .ygrid-hd-body{
325 background-color: transparent;
326 border-bottom:0px;
327}
328.ygrid-hd-split {
329 background-image: url(../images/aero/grid/grid-split.gif);
330}
331.ygrid-hrow{
332 background: url(../images/aero/grid/grid-hrow.gif);
333 height: 22px;
334 border:0px none;
335}
336.ygrid-row-alt{
337 background-color: #f5f5f5;
338}
339.ygrid-row{
340 border-bottom: 1px solid #eeeeee;
341}
342.ygrid-col{
343 border-right:1px solid #eeeeee;
344}
345.ygrid-sort-col .ygrid-hd-body {
346 padding-bottom:4px;
347}
348
349/** Toolbar */
350.ytoolbar{
351 border:0px none;
352 background: #E2ECF8;
353 padding:1px 3px;
354 border-bottom:1px solid #c0d7f4;
355}
356.ytoolbar .ytb-button-over{
357 border:1px solid #8db2e3;
358}
359.ytoolbar .ytb-sep{
360 background-image: url(../images/aero/grid/grid-blue-split.gif);
361}
diff --git a/frontend/beta/css/yui-extensions/ytheme-gray.css b/frontend/beta/css/yui-extensions/ytheme-gray.css
new file mode 100644
index 0000000..675fed1
--- a/dev/null
+++ b/frontend/beta/css/yui-extensions/ytheme-gray.css
@@ -0,0 +1,300 @@
1/*
2
3Copyright 2008-2011 Clipperz Srl
4
5This file is part of Clipperz's Javascript Crypto Library.
6Javascript Crypto Library provides web developers with an extensive
7and efficient set of cryptographic functions. The library aims to
8obtain maximum execution speed while preserving modularity and
9reusability.
10For further information about its features and functionalities please
11refer to http://www.clipperz.com
12
13* Javascript Crypto Library is free software: you can redistribute
14 it and/or modify it under the terms of the GNU Affero General Public
15 License as published by the Free Software Foundation, either version
16 3 of the License, or (at your option) any later version.
17
18* Javascript Crypto Library is distributed in the hope that it will
19 be useful, but WITHOUT ANY WARRANTY; without even the implied
20 warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
21 See the GNU Affero General Public License for more details.
22
23* You should have received a copy of the GNU Affero General Public
24 License along with Javascript Crypto Library. If not, see
25 <http://www.gnu.org/licenses/>.
26
27*/
28
29/**
30* Basic-Dialog
31*/
32.ydlg-proxy {
33 background-image: url(../images/gray/layout/gradient-bg.gif);
34 background-color:#EAE8D5;
35 border:1px solid #b3b6b0;
36}
37.ydlg-shadow{
38 background:#aaaaaa;
39}
40.ydlg-proxy .tabset{
41 background:url(../images/gray/layout/gradient-bg.gif);
42}
43.ydlg .ydlg-hd {
44 background: url(../images/gray/basic-dialog/hd-sprite.gif) repeat-x 0px -82px;
45 background-color:#333333;
46}
47.ydlg .ydlg-hd-left {
48 background: url(../images/gray/basic-dialog/hd-sprite.gif) no-repeat 0px -41px;
49}
50.ydlg .ydlg-hd-right {
51 background: url(../images/gray/basic-dialog/hd-sprite.gif) no-repeat right 0px;
52}
53.ydlg .ydlg-dlg-body{
54 background:#efefec;
55 border:1px solid #b3b6b0;
56 border-top:0px none;
57}
58.ydlg .ytabs-top .yui-ext-tabbody{
59 border:1px solid #b3b6b0;
60 border-top:0px none;
61}
62.ydlg .ytabs-bottom .yui-ext-tabbody{
63 border:1px solid #b3b6b0;
64 border-bottom:0px none;
65}
66.ydlg .ylayout-container .yui-ext-tabbody{
67 border:0px none;
68}
69.ydlg .ydlg-close {
70 background-image:url(../images/gray/basic-dialog/close.gif);
71}
72.ydlg div.yresizable-handle-east{
73 background-image:url(../images/gray/basic-dialog/e-handle.gif);
74 border:0px none;
75}
76.ydlg div.yresizable-handle-south{
77 background-image:url(../images/gray/basic-dialog/s-handle.gif);
78 border:0px none;
79}
80.ydlg div.yresizable-handle-west{
81 background-image:url(../images/gray/basic-dialog/e-handle.gif);
82 border:0px none;
83}
84.ydlg div.yresizable-handle-southeast{
85 background-image:url(../images/gray/basic-dialog/se-handle.gif);
86 background-position: bottom right;
87 width:8px;
88 height:8px;
89 border:0px;
90}
91.ydlg div.yresizable-handle-southwest{
92 background-image:url(../images/gray/sizer/sw-handle-dark.gif);
93 background-position: top right;
94 margin-left:1px;
95 margin-bottom:1px;
96 border:0px;
97}
98.ydlg div.yresizable-handle-north{
99 background-image:url(../images/gray/s.gif);
100 border:0px none;
101}
102
103/**
104* Tabs
105*/
106.ytab-wrap {
107 border-bottom:1px solid #aca899;
108}
109.ytab-strip .on .ytab-text {
110 cursor:default;
111 color:#333333;
112}
113.ytabs-top .ytab-strip .on .ytab-right {
114 background: url(../images/gray/tabs/tab-sprite.gif) no-repeat right 0px;
115}
116.ytabs-top .ytab-strip .on .ytab-left {
117 background: url(../images/gray/tabs/tab-sprite.gif) no-repeat 0px -100px;
118}
119.ytabs-top .ytab-strip .ytab-right {
120 background: url(../images/gray/tabs/tab-sprite.gif) no-repeat right -50px;
121}
122.ytabs-top .ytab-strip .ytab-left {
123 background: url(../images/gray/tabs/tab-sprite.gif) no-repeat 0px -150px;
124}
125.ytab-strip .ytab-closable .close-icon{
126 background-image:url(../images/gray/layout/layout-sprite.gif);
127 background-position: 50% -60px;
128}
129.ytab-strip .on .close-icon{
130 background-image:url(../images/gray/layout/layout-sprite.gif);
131 background-position: 50% -60px;
132}
133.ytab-strip .ytab-closable .close-over{
134 background-image:url(../images/gray/layout/layout-sprite.gif);
135 background-position: 50% -72px;
136}
137
138.ytabs-bottom .ytab-wrap {
139 border-bottom:0px none;
140 padding-top:0px;
141 border-top:1px solid #aca899;
142}
143.ytabs-bottom .ytab-strip .ytab-right {
144 background: url(../images/gray/tabs/tab-btm-inactive-right-bg.gif) no-repeat bottom left;
145}
146.ytabs-bottom .ytab-strip .ytab-left {
147 background: url(../images/gray/tabs/tab-btm-inactive-left-bg.gif) no-repeat bottom right;
148}
149.ytabs-bottom .ytab-strip .on .ytab-right {
150 background: url(../images/gray/tabs/tab-btm-right-bg.gif) no-repeat bottom left;
151}
152.ytabs-bottom .ytab-strip .on .ytab-left {
153 background: url(../images/gray/tabs/tab-btm-left-bg.gif) no-repeat bottom right;
154}
155
156/* QuickTips */
157
158.ytip .ytip-hd-right{
159 background: url(../images/gray/basic-dialog/hd-sprite.gif) no-repeat right 0px;
160}
161.ytip .ytip-hd-left{
162 background: url(../images/gray/basic-dialog/hd-sprite.gif) no-repeat 0px -41px;
163}
164.ytip .ytip-hd{
165 background: url(../images/gray/basic-dialog/hd-sprite.gif) repeat-x 0px -82px;
166}
167.ytip .ytip-close{
168 background-image: url(../images/gray/basic-dialog/close.gif);
169}
170.ytip .ytip-bd{
171 background: #e7e7e7 url(../images/gray/qtip/bg.gif);
172 border: 1px solid #ababab;
173}
174
175/* BorderLayout */
176
177.ylayout-container{
178 background-color:#f3f2e7;
179}
180.ylayout-collapsed{
181 background-color:#f3f2e7;
182 border:1px solid #aca899;
183}
184.ylayout-collapsed-over{
185 background-color:#fbfbef;
186}
187.ylayout-panel{
188 border:1px solid #aca899;
189}
190.ylayout-nested-layout .ylayout-panel {
191 border:0px none;
192}
193.ylayout-split{
194 background-color:#f3f2e7;
195}
196.ylayout-panel-hd{
197 background-image: url(../images/gray/layout/panel-title-light-bg.gif);
198 border-bottom:1px solid #aca899;
199}
200.ylayout-tools-button-over{
201 border:1px solid #aca899;
202}
203.ylayout-close{
204 background-image:url(../images/gray/layout/layout-sprite.gif);
205 background-repeat: no-repeat;
206 background-position: 50% -48px;
207}
208.ylayout-collapse-west,.ylayout-expand-east{
209 background-image:url(../images/gray/layout/layout-sprite.gif);
210 background-repeat: no-repeat;
211 background-position: 50% 0;
212}
213.ylayout-expand-west,.ylayout-collapse-east{
214 background-image:url(../images/gray/layout/layout-sprite.gif);
215 background-repeat: no-repeat;
216 background-position: 50% -12px;
217}
218.ylayout-collapse-north,.ylayout-expand-south{
219 background-image:url(../images/gray/layout/layout-sprite.gif);
220 background-repeat: no-repeat;
221 background-position: 50% -24px;
222}
223.ylayout-expand-north,.ylayout-collapse-south{
224 background-image:url(../images/gray/layout/layout-sprite.gif);
225 background-repeat: no-repeat;
226 background-position: 50% -36px;
227}
228.ylayout-split-h{
229 background-image:url(../images/gray/sizer/e-handle-dark.gif);
230}
231.ylayout-split-v{
232 background-image:url(../images/gray/sizer/s-handle-dark.gif);
233}
234.ylayout-panel .ytab-wrap{
235 background:url(../images/gray/layout/gradient-bg.gif);
236}
237.ylayout-nested-layout .ylayout-panel-north {
238 border-bottom:1px solid #aca899;
239}
240.ylayout-nested-layout .ylayout-panel-south {
241 border-top:1px solid #aca899;
242}
243.ylayout-nested-layout .ylayout-panel-east {
244 border-left:1px solid #aca899;
245}
246.ylayout-nested-layout .ylayout-panel-west {
247 border-right:1px solid #aca899;
248}
249.ylayout-panel-dragover {
250 border: 2px solid #aca899;
251}
252.ylayout-panel-proxy {
253 background-image: url(../images/gray/layout/gradient-bg.gif);
254 background-color:#f3f2e7;
255 border:1px dashed #aca899;
256}
257/** Resizable */
258
259.yresizable-over .yresizable-handle-east, .yresizable-pinned .yresizable-handle-east{
260 background:url(../images/gray/sizer/e-handle.gif);
261 background-position: left;
262}
263.yresizable-over .yresizable-handle-east, .yresizable-pinned .yresizable-handle-west{
264 background:url(../images/gray/sizer/e-handle.gif);
265 background-position: left;
266}
267.yresizable-over .yresizable-handle-south, .yresizable-pinned .yresizable-handle-south{
268 background:url(../images/gray/sizer/s-handle.gif);
269 background-position: top;
270}
271.yresizable-over .yresizable-handle-south, .yresizable-pinned .yresizable-handle-north{
272 background:url(../images/gray/sizer/s-handle.gif);
273 background-position: top;
274}
275.yresizable-over .yresizable-handle-southeast, .yresizable-pinned .yresizable-handle-southeast{
276 background:url(../images/gray/sizer/se-handle.gif);
277 background-position: top left;
278}
279.yresizable-over .yresizable-handle-northwest,.yresizable-pinned .yresizable-handle-northwest{
280 background:url(../images/gray/sizer/nw-handle.gif);
281 background-position:bottom right;
282}
283.yresizable-over .yresizable-handle-northeast,.yresizable-pinned .yresizable-handle-northeast{
284 background:url(../images/gray/sizer/ne-handle.gif);
285 background-position: bottom left;
286}
287.yresizable-over .yresizable-handle-southwest,.yresizable-pinned .yresizable-handle-southwest{
288 background:url(../images/gray/sizer/sw-handle.gif);
289 background-position: top right;
290}
291.yresizable-proxy{
292 border: 1px dashed #615e55;
293}
294
295/** Toolbar */
296.ytoolbar{
297 border:0px none;
298 background: #efefe3 url(../images/gray/toolbar/gray-bg.gif) repeat-x;
299 padding:3px;
300}
diff --git a/frontend/beta/css/yui-extensions/ytheme-vista.css b/frontend/beta/css/yui-extensions/ytheme-vista.css
new file mode 100644
index 0000000..2770566
--- a/dev/null
+++ b/frontend/beta/css/yui-extensions/ytheme-vista.css
@@ -0,0 +1,403 @@
1/*
2
3Copyright 2008-2011 Clipperz Srl
4
5This file is part of Clipperz's Javascript Crypto Library.
6Javascript Crypto Library provides web developers with an extensive
7and efficient set of cryptographic functions. The library aims to
8obtain maximum execution speed while preserving modularity and
9reusability.
10For further information about its features and functionalities please
11refer to http://www.clipperz.com
12
13* Javascript Crypto Library is free software: you can redistribute
14 it and/or modify it under the terms of the GNU Affero General Public
15 License as published by the Free Software Foundation, either version
16 3 of the License, or (at your option) any later version.
17
18* Javascript Crypto Library is distributed in the hope that it will
19 be useful, but WITHOUT ANY WARRANTY; without even the implied
20 warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
21 See the GNU Affero General Public License for more details.
22
23* You should have received a copy of the GNU Affero General Public
24 License along with Javascript Crypto Library. If not, see
25 <http://www.gnu.org/licenses/>.
26
27*/
28
29/**
30* Tabs
31*/
32.ytab-wrap {
33 background:#4f4f4f;
34 border-bottom:1px solid #b3b6b0;
35}
36.ytab-strip .ytab-text {
37 color:white;
38 font-weight:normal;
39}
40.ytab-strip .on .ytab-text {
41 cursor:default;
42 color:#333333;
43}
44.ytabs-top .ytab-strip a:hover {
45 background:transparent url(../images/vista/tabs/tab-sprite.gif) no-repeat right -50px;
46}
47.ytabs-top .ytab-strip a:hover .ytab-left {
48 background:transparent url(../images/vista/tabs/tab-sprite.gif) no-repeat 0 -150px;
49}
50.ytabs-top .ytab-strip .on .ytab-right, .ytabs-top .ytab-strip .on a:hover {
51 background: url(../images/vista/tabs/tab-sprite.gif) no-repeat right 0;
52}
53.ytabs-top .ytab-strip .on .ytab-left, .ytabs-top .ytab-strip .on a:hover .ytab-left {
54 background: url(../images/vista/tabs/tab-sprite.gif) no-repeat 0 -100px;
55}
56.ytabs-top .ytab-strip .ytab-right {
57 background:transparent;
58}
59.ytabs-top .ytab-strip .ytab-left {
60 background:transparent;
61}
62.ytab-strip .ytab-closable .close-icon{
63 background-image:url(../images/vista/layout/layout-sprite.gif);
64 background-position: 50% -60px;
65}
66.ytab-strip .on .close-icon{
67 background-image:url(../images/vista/layout/layout-sprite.gif);
68 background-position: 50% -72px;
69}
70.ytab-strip .ytab-closable .close-over{
71 background-image:url(../images/vista/layout/layout-sprite.gif);
72 background-position: 50% -72px;
73}
74
75.ytabs-bottom .ytab-strip {
76 background:#4f4f4f;
77}
78.ytabs-bottom .ytab-strip a:hover {
79 background:transparent url(../images/vista/tabs/tab-btm-inactive-right-bg.gif) no-repeat bottom right;
80}
81.ytabs-bottom .ytab-strip a:hover .ytab-left{
82 background:transparent url(../images/vista/tabs/tab-btm-inactive-left-bg.gif) no-repeat bottom left;
83}
84.ytabs-bottom .ytab-wrap {
85 border-bottom:0px none;
86 padding-top:0px;
87 border-top:1px solid #b3b6b0;
88}
89.ytabs-bottom .ytab-strip .ytab-right {
90 background:transparent;
91}
92.ytabs-bottom .ytab-strip .ytab-left {
93 background:transparent;
94}
95.ytabs-bottom .ytab-strip .on .ytab-right,.ytabs-bottom .ytab-strip .on a:hover {
96 background: url(../images/vista/tabs/tab-btm-right-bg.gif) no-repeat bottom left;
97}
98.ytabs-bottom .ytab-strip .on .ytab-left,.ytabs-bottom .ytab-strip .on a:hover .ytab-left {
99 background: url(../images/vista/tabs/tab-btm-left-bg.gif) no-repeat bottom right;
100}
101/**
102* Basic-Dialog
103*/
104.ydlg-proxy {
105 background:#d3d6d0;
106 border:2px solid #b3b6b0;
107}
108.ydlg-shadow{
109 background:#cccccc;
110 opacity:.3;
111 -moz-opacity:.3;
112 filter: alpha(opacity=30);
113}
114.ydlg .ydlg-hd {
115 background: url(../images/vista/basic-dialog/hd-sprite.gif) repeat-x 0px -82px;
116 background-color:#333333;
117 zoom:1;
118}
119.ydlg .ydlg-hd-left {
120 opacity:.95;-moz-opacity:.95;filter:alpha(opacity=90);
121 background: url(../images/vista/basic-dialog/hd-sprite.gif) no-repeat 0px -41px;
122 zoom:1;
123}
124.ydlg .ydlg-hd-right {
125 background: url(../images/vista/basic-dialog/hd-sprite.gif) no-repeat right 0px;
126 zoom:1;
127}
128.ydlg .ydlg-dlg-body{
129 background:#fff;
130 border:0 none;
131 border-top:0px none;
132 padding:0px 0px 0px;
133 position:absolute;
134 top:24px;left:0px;
135 z-index:1;
136}
137.ydlg-auto-tabs .ydlg-dlg-body{
138 background:transparent;
139}
140.ydlg-auto-tabs .ytabs-top .ytab-wrap{
141 background:transparent;
142}
143.ydlg .ydlg-ft{
144 border-top:1px solid #b3b6b0;
145 background:#F0F0F0;
146 padding-bottom:8px;
147}
148.ydlg .ydlg-bg{
149 opacity:.90;-moz-opacity:.90;filter:alpha(opacity=85);
150 zoom:1;
151}
152.ydlg .ydlg-bg-left,.ydlg .ydlg-bg-center,.ydlg .ydlg-bg-right{
153}
154.ydlg .ydlg-bg-center {
155 padding: 0px 4px 4px 4px;
156 background:transparent url(../images/vista/basic-dialog/bg-center.gif) repeat-x bottom;
157 zoom:1;
158}
159.ydlg .ydlg-bg-left{
160 padding-left:4px;
161 background:transparent url(../images/vista/basic-dialog/bg-left.gif) no-repeat bottom left;
162 zoom:1;
163}
164.ydlg .ydlg-bg-right{
165 padding-right:4px;
166 background:transparent url(../images/vista/basic-dialog/bg-right.gif) no-repeat bottom right;
167 zoom:1;
168}
169.ydlg .ytabs-top .yui-ext-tabbody{
170 border:0px none;
171}
172.ydlg .ytabs-bottom .yui-ext-tabbody{
173 border:1px solid #b3b6b0;
174 border-bottom:0px none;
175}
176.ydlg .ylayout-container .yui-ext-tabbody{
177 border:0px none;
178}
179.ydlg .ydlg-close {
180 background-image:url(../images/vista/basic-dialog/close.gif);
181}
182.ydlg div.yresizable-handle-east{
183 background-image:url(../images/vista/s.gif);
184 border:0px none;
185}
186.ydlg div.yresizable-handle-south{
187 background-image:url(../images/vista/s.gif);
188 border:0px none;
189}
190.ydlg div.yresizable-handle-west{
191 background-image:url(../images/vista/s.gif);
192 border:0px none;
193}
194.ydlg div.yresizable-handle-southeast{
195 background-image:url(../images/vista/s.gif);
196 background-position: bottom right;
197 width:8px;
198 height:8px;
199 border:0px;
200}
201.ydlg div.yresizable-handle-southwest{
202 background-image:url(../images/vista/s.gif);
203 background-position: top right;
204 margin-left:1px;
205 margin-bottom:1px;
206 border:0px;
207}
208.ydlg div.yresizable-handle-north{
209 background-image:url(../images/vista/s.gif);
210 border:0px none;
211}
212
213/* QuickTips */
214
215.ytip .ytip-hd-right{
216 background: url(../images/vista/basic-dialog/hd-sprite.gif) no-repeat right 0px;
217}
218.ytip .ytip-hd-left{
219 background: url(../images/vista/basic-dialog/hd-sprite.gif) no-repeat 0px -41px;
220}
221.ytip .ytip-hd{
222 background: url(../images/vista/basic-dialog/hd-sprite.gif) repeat-x 0px -82px;
223}
224.ytip .ytip-close{
225 background-image: url(../images/vista/basic-dialog/close.gif);
226}
227.ytip .ytip-bd{
228 background: #e7e7e7 url(../images/vista/qtip/bg.gif);
229 border: 1px solid #ababab;
230}
231
232/* BorderLayout */
233.ylayout-container{
234 background:#4f4f4f;
235}
236.ylayout-collapsed{
237 background-color:#9f9f9f;
238 border:1px solid #4c535c;
239}
240.ylayout-collapsed-over{
241 background-color:#bfbfbf;
242}
243.ylayout-panel{
244 border:1px solid #4c535c;
245}
246.ylayout-nested-layout .ylayout-panel {
247 border:0px none;
248}
249.ylayout-split{
250 background-color:#f3f2e7;
251}
252.ylayout-panel-hd{
253 background-image: url(../images/vista/layout/panel-title-bg.gif);
254 border-bottom:1px solid #b5bac1;
255}
256.ylayout-panel-hd-text{
257 color:white;
258}
259.ylayout-tools-button-over{
260 border:1px solid #4c535c;
261 background:#9f9f9f url(../images/vista/layout/panel-title-bg.gif) repeat-x;
262}
263.ylayout-close{
264 background-image:url(../images/vista/layout/layout-sprite.gif);
265 background-repeat: no-repeat;
266 background-position: 50% -60px;
267}
268.ylayout-collapse-west,.ylayout-expand-east{
269 background-image:url(../images/vista/layout/layout-sprite.gif);
270 background-repeat: no-repeat;
271 background-position: 50% 0;
272}
273.ylayout-expand-west,.ylayout-collapse-east{
274 background-image:url(../images/vista/layout/layout-sprite.gif);
275 background-repeat: no-repeat;
276 background-position: 50% -12px;
277}
278.ylayout-collapse-north,.ylayout-expand-south{
279 background-image:url(../images/vista/layout/layout-sprite.gif);
280 background-repeat: no-repeat;
281 background-position: 50% -24px;
282}
283.ylayout-expand-north,.ylayout-collapse-south{
284 background-image:url(../images/vista/layout/layout-sprite.gif);
285 background-repeat: no-repeat;
286 background-position: 50% -36px;
287}
288.ylayout-split-h{
289 background:#9f9f9f;
290}
291.ylayout-split-v{
292 background:#9f9f9f;
293}
294.ylayout-panel .ytab-wrap{
295 background:#4f4f4f;
296}
297.ylayout-nested-layout .ylayout-panel-north {
298 border-bottom:1px solid #4c535c;
299}
300.ylayout-nested-layout .ylayout-panel-south {
301 border-top:1px solid #4c535c;
302}
303.ylayout-nested-layout .ylayout-panel-east {
304 border-left:1px solid #4c535c;
305}
306.ylayout-nested-layout .ylayout-panel-west {
307 border-right:1px solid #4c535c;
308}
309.ylayout-panel-dragover {
310 border: 2px solid #4c535c;
311}
312.ylayout-panel-proxy {
313 background-image: url(../images/vista/layout/gradient-bg.gif);
314 background-color:#f3f2e7;
315 border:1px dashed #4c535c;
316}
317/** Resizable */
318
319.yresizable-over .yresizable-handle-east, .yresizable-pinned .yresizable-handle-east{
320 background:url(../images/vista/sizer/e-handle.gif);
321 background-position: left;
322}
323.yresizable-over .yresizable-handle-east, .yresizable-pinned .yresizable-handle-west{
324 background:url(../images/vista/sizer/e-handle.gif);
325 background-position: left;
326}
327.yresizable-over .yresizable-handle-south, .yresizable-pinned .yresizable-handle-south{
328 background:url(../images/vista/sizer/s-handle.gif);
329 background-position: top;
330}
331.yresizable-over .yresizable-handle-south, .yresizable-pinned .yresizable-handle-north{
332 background:url(../images/vista/sizer/s-handle.gif);
333 background-position: top;
334}
335.yresizable-over .yresizable-handle-southeast, .yresizable-pinned .yresizable-handle-southeast{
336 background:url(../images/vista/sizer/se-handle.gif);
337 background-position: top left;
338}
339.yresizable-over .yresizable-handle-northwest,.yresizable-pinned .yresizable-handle-northwest{
340 background:url(../images/vista/sizer/nw-handle.gif);
341 background-position:bottom right;
342}
343.yresizable-over .yresizable-handle-northeast,.yresizable-pinned .yresizable-handle-northeast{
344 background:url(../images/vista/sizer/ne-handle.gif);
345 background-position: bottom left;
346}
347.yresizable-over .yresizable-handle-southwest,.yresizable-pinned .yresizable-handle-southwest{
348 background:url(../images/vista/sizer/sw-handle.gif);
349 background-position: top right;
350}
351.yresizable-proxy{
352 border: 1px dashed #615e55;
353}
354
355/** Toolbar */
356.ytoolbar{
357 border:0px none;
358 background: #efefe3 url(../images/vista/toolbar/gray-bg.gif) repeat-x;
359 padding:3px;
360}
361.ytoolbar .ytb-button-over{
362 border:1px solid transparent;
363 border-bottom:1px solid #bbbbbb;
364 border-top:1px solid #eeeeee;
365 background:#9f9f9f url(../images/vista/grid/grid-vista-hd.gif) repeat-x;
366}
367/* grid */
368.ygrid-hd{
369 border-bottom:0px;
370 background:none;
371}
372.ygrid-hd-body {
373 border-bottom: 1px solid #b3bcc0;
374}
375.ygrid-hd-over{
376 border-bottom:0px;
377}
378.ygrid-hd-over .ygrid-hd-body{
379 background-color: transparent;
380 border-bottom:0px;
381}
382.ygrid-hd-split {
383 background-image: url(../images/vista/grid/grid-split.gif);
384}
385.ygrid-hrow{
386 background: url(../images/vista/grid/grid-vista-hd.gif);
387 height: 21px;
388}
389.ygrid-row-alt{
390 background-color: #f5f5f5;
391}
392.ygrid-row-selected{
393 background-color: #535353 !important;
394 color: white;
395}
396.ygrid-row-selected span{
397 color: white !important;
398}
399.ygrid-wrap-body {
400}
401.ytoolbar .ytb-sep{
402 background-image: url(../images/vista/grid/grid-split.gif);
403}
diff --git a/frontend/beta/css/yui/calendar.css b/frontend/beta/css/yui/calendar.css
new file mode 100644
index 0000000..a634e50
--- a/dev/null
+++ b/frontend/beta/css/yui/calendar.css
@@ -0,0 +1,189 @@
1/*
2
3Copyright 2008-2011 Clipperz Srl
4
5This file is part of Clipperz's Javascript Crypto Library.
6Javascript Crypto Library provides web developers with an extensive
7and efficient set of cryptographic functions. The library aims to
8obtain maximum execution speed while preserving modularity and
9reusability.
10For further information about its features and functionalities please
11refer to http://www.clipperz.com
12
13* Javascript Crypto Library is free software: you can redistribute
14 it and/or modify it under the terms of the GNU Affero General Public
15 License as published by the Free Software Foundation, either version
16 3 of the License, or (at your option) any later version.
17
18* Javascript Crypto Library is distributed in the hope that it will
19 be useful, but WITHOUT ANY WARRANTY; without even the implied
20 warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
21 See the GNU Affero General Public License for more details.
22
23* You should have received a copy of the GNU Affero General Public
24 License along with Javascript Crypto Library. If not, see
25 <http://www.gnu.org/licenses/>.
26
27*/
28
29/*
30Copyright (c) 2006, Yahoo! Inc. All rights reserved.
31Code licensed under the BSD License:
32http://developer.yahoo.net/yui/license.txt
33Version 0.11.3
34*/
35
36.yui-cal2upwrapper {*height:1%;} /* IE */
37.yui-cal2upwrapper:after {content:'.';clear:both;display:block;visibility:hidden;height:0;} /* others */
38
39.yui-calcontainer {
40 float:left;
41 padding:5px;
42 background-color:#F7F9FB;
43 border:1px solid #7B9EBD;
44}
45
46.yui-calcontainer .title {
47 font:100% sans-serif;
48 color:#000;
49 font-weight:bold;
50 margin-bottom:5px;
51 height:auto;
52 position:relative;
53}
54
55.yui-calcontainer .title .close-icon {
56 position:absolute;
57 right:0;
58 top:0;
59 border:none;
60}
61
62.yui-calcontainer .cal2up {
63 float:left;
64}
65
66.yui-calendar .calnavleft {
67 position:absolute;
68 background-repeat:no-repeat;
69 cursor:pointer;
70 top:2px;
71 bottom:0;
72 width:9px;
73 height:12px;
74 left:2px;
75}
76
77.yui-calendar .calnavright {
78 position:absolute;
79 background-repeat:no-repeat;
80 cursor:pointer;
81 top:2px;
82 bottom:0;
83 width:9px;
84 height:12px;
85 right:2px;
86}
87
88/* Calendar element styles */
89
90.yui-calendar {
91 font:100% sans-serif;
92 text-align:center;
93 border-spacing:0;
94 border-collapse:separate;
95}
96
97.yui-calendar td.calcell {
98 padding:.1em .2em;
99 border:1px solid #E0E0E0;
100 background-color:#FFF;
101}
102
103.yui-calendar td.calcell a {
104 color:#003DB8;
105 text-decoration:none;
106}
107
108.yui-calendar td.calcell.today {
109 border:1px solid #000;
110}
111
112.yui-calendar td.calcell.oom {
113 cursor:default;
114 color:#999;
115 background-color:#EEE;
116 border:1px solid #E0E0E0;
117}
118
119.yui-calendar td.calcell.selected {
120 color:#003DB8;
121 background-color:#FFF19F;
122 border:1px solid #FF9900;
123}
124
125.yui-calendar td.calcell.calcellhover {
126 cursor:pointer;
127 color:#FFF;
128 background-color:#FF9900;
129 border:1px solid #FF9900;
130}
131
132.yui-calendar td.calcell.calcellhover a {
133 color:#FFF;
134}
135
136.yui-calendar td.calcell.restricted {
137 text-decoration:line-through;
138}
139
140.yui-calendar td.calcell.previous {
141 color:#CCC;
142}
143
144.yui-calendar td.calcell.highlight1 { background-color:#CCFF99; }
145.yui-calendar td.calcell.highlight2 { background-color:#99CCFF; }
146.yui-calendar td.calcell.highlight3 { background-color:#FFCCCC; }
147.yui-calendar td.calcell.highlight4 { background-color:#CCFF99; }
148
149
150.yui-calendar .calhead {
151 border:1px solid #E0E0E0;
152 vertical-align:middle;
153 background-color:#FFF;
154}
155
156.yui-calendar .calheader {
157 position:relative;
158 width:100%;
159 text-align:center;
160}
161
162.yui-calendar .calheader img {
163 border:none;
164}
165
166.yui-calendar .calweekdaycell {
167 color:#666;
168 font-weight:normal;
169}
170
171.yui-calendar .calfoot {
172 background-color:#EEE;
173}
174
175.yui-calendar .calrowhead, .yui-calendar .calrowfoot {
176 color:#666;
177 font-size:9px;
178 font-style:italic;
179 font-weight:normal;
180 width:15px;
181}
182
183.yui-calendar .calrowhead {
184 border-right-width:2px;
185}
186
187/*Specific changes for calendar running under fonts/reset */
188.yui-calendar a:hover {background:inherit;}
189p#clear {clear:left; padding-top:10px;}
diff --git a/frontend/beta/css/yui/container.css b/frontend/beta/css/yui/container.css
new file mode 100644
index 0000000..1d7154c
--- a/dev/null
+++ b/frontend/beta/css/yui/container.css
@@ -0,0 +1,240 @@
1/*
2
3Copyright 2008-2011 Clipperz Srl
4
5This file is part of Clipperz's Javascript Crypto Library.
6Javascript Crypto Library provides web developers with an extensive
7and efficient set of cryptographic functions. The library aims to
8obtain maximum execution speed while preserving modularity and
9reusability.
10For further information about its features and functionalities please
11refer to http://www.clipperz.com
12
13* Javascript Crypto Library is free software: you can redistribute
14 it and/or modify it under the terms of the GNU Affero General Public
15 License as published by the Free Software Foundation, either version
16 3 of the License, or (at your option) any later version.
17
18* Javascript Crypto Library is distributed in the hope that it will
19 be useful, but WITHOUT ANY WARRANTY; without even the implied
20 warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
21 See the GNU Affero General Public License for more details.
22
23* You should have received a copy of the GNU Affero General Public
24 License along with Javascript Crypto Library. If not, see
25 <http://www.gnu.org/licenses/>.
26
27*/
28
29/*
30Copyright (c) 2006, Yahoo! Inc. All rights reserved.
31Code licensed under the BSD License:
32http://developer.yahoo.net/yui/license.txt
33Version 0.11.4
34*/
35
36.overlay {
37 position:absolute;
38 display:block;
39}
40
41.tt {
42 visibility:hidden;
43 position:absolute;
44 color:#333;
45 background-color:#FDFFB4;
46 font-family:arial,helvetica,verdana,sans-serif;
47 padding:2px;
48 border:1px solid #FCC90D;
49 font:100% sans-serif;
50 width:auto;
51}
52
53* html body.masked select {
54 visibility:hidden;
55}
56
57* html div.panel-container select {
58 visibility:inherit;
59}
60
61* html div.drag select {
62 visibility:hidden;
63}
64
65* html div.hide-select select {
66 visibility:hidden;
67}
68
69.mask {
70 z-index:0;
71 display:none;
72 position:absolute;
73 top:0;
74 left:0;
75 -moz-opacity: 0.5;
76 opacity:.50;
77 filter: alpha(opacity=50);
78 background-color:#CCC;
79}
80
81.hide-scrollbars * {
82 overflow:hidden;
83}
84
85.hide-scrollbars textarea, .hide-scrollbars select {
86 overflow:hidden;
87 display:none;
88}
89
90.show-scrollbars textarea, .show-scrollbars select {
91 overflow:visible;
92}
93
94.panel-container {
95 position:absolute;
96 background-color:transparent;
97 z-index:6;
98 visibility:hidden;
99 overflow:visible;
100 width:auto;
101}
102
103.panel-container.matte {
104 padding:3px;
105 background-color:#FFF;
106}
107
108.panel-container.matte .underlay {
109 display:none;
110}
111
112.panel-container.shadow {
113 padding:0px;
114 background-color:transparent;
115}
116
117.panel-container.shadow .underlay {
118 visibility:inherit;
119 position:absolute;
120 background-color:#CCC;
121 top:3px;left:3px;
122 z-index:0;
123 width:100%;
124 height:100%;
125 -moz-opacity: 0.7;
126 opacity:.70;
127 filter:alpha(opacity=70);
128 zoom:1;
129}
130
131.panel {
132 visibility:hidden;
133 border-collapse:separate;
134 position:relative;
135 left:0px;top:0px;
136 font:1em Arial;
137 background-color:#FFF;
138 border:1px solid #000;
139 z-index:1;
140 overflow:hidden;
141}
142
143.panel .hd {
144 background-color:#3d77cb;
145 color:#FFF;
146 font-size:100%;
147 line-height:100%;
148 border:1px solid #FFF;
149 border-bottom:1px solid #000;
150 font-weight:bold;
151 overflow:hidden;
152 padding:4px;
153}
154
155.panel .bd {
156 overflow:hidden;
157 padding:4px;
158}
159
160.panel .bd p {
161 margin:0 0 1em;
162}
163
164.panel .close {
165 position:absolute;
166 top:5px;
167 right:4px;
168 z-index:6;
169 height:12px;
170 width:12px;
171 margin:0px;
172 padding:0px;
173 background-repeat:no-repeat;
174 cursor:pointer;
175 visibility:inherit;
176}
177
178.panel .close.nonsecure {
179 background-image:url(../../images/yui/container/close12_1.gif);
180}
181
182.panel .close.secure {
183 background-image:url(../../images/yui/container/close12_1.gif);
184}
185
186.panel .ft {
187 padding:4px;
188 overflow:hidden;
189}
190
191.simple-dialog .bd .icon {
192 background-repeat:no-repeat;
193 width:16px;
194 height:16px;
195 margin-right:10px;
196 float:left;
197}
198
199.dialog .ft, .simple-dialog .ft {
200 padding-bottom:5px;
201 padding-right:5px;
202 text-align:right;
203}
204
205.dialog form, .simple-dialog form {
206 margin:0;
207}
208
209.button-group button {
210 font:100 76% verdana;
211 text-decoration:none;
212 background-color: #E4E4E4;
213 color: #333;
214 cursor: hand;
215 vertical-align: middle;
216 border: 2px solid #797979;
217 border-top-color:#FFF;
218 border-left-color:#FFF;
219 margin:2px;
220 padding:2px;
221}
222
223.button-group button.default {
224 font-weight:bold;
225}
226
227.button-group button:hover, .button-group button.hover {
228 border:2px solid #90A029;
229 background-color:#EBF09E;
230 border-top-color:#FFF;
231 border-left-color:#FFF;
232}
233
234.button-group button:active {
235 border:2px solid #E4E4E4;
236 background-color:#BBB;
237 border-top-color:#333;
238 border-left-color:#333;
239}
240
diff --git a/frontend/beta/css/yui/fonts.css b/frontend/beta/css/yui/fonts.css
new file mode 100644
index 0000000..ea8dd16
--- a/dev/null
+++ b/frontend/beta/css/yui/fonts.css
@@ -0,0 +1,62 @@
1/*
2
3Copyright 2008-2011 Clipperz Srl
4
5This file is part of Clipperz's Javascript Crypto Library.
6Javascript Crypto Library provides web developers with an extensive
7and efficient set of cryptographic functions. The library aims to
8obtain maximum execution speed while preserving modularity and
9reusability.
10For further information about its features and functionalities please
11refer to http://www.clipperz.com
12
13* Javascript Crypto Library is free software: you can redistribute
14 it and/or modify it under the terms of the GNU Affero General Public
15 License as published by the Free Software Foundation, either version
16 3 of the License, or (at your option) any later version.
17
18* Javascript Crypto Library is distributed in the hope that it will
19 be useful, but WITHOUT ANY WARRANTY; without even the implied
20 warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
21 See the GNU Affero General Public License for more details.
22
23* You should have received a copy of the GNU Affero General Public
24 License along with Javascript Crypto Library. If not, see
25 <http://www.gnu.org/licenses/>.
26
27*/
28
29/*
30Copyright (c) 2006, Yahoo! Inc. All rights reserved.
31Code licensed under the BSD License:
32http://developer.yahoo.net/yui/license.txt
33version: 0.11.3
34*/
35
36/**
37 * 84.5% for !IE, keywords for IE
38 * Percents could work for IE, but for backCompat purposes, we are using
39 keywords.
40 * x-small is for IE < 6 and IE6 quirks mode.
41 *
42 */
43body {font:13px arial,helvetica,clean,sans-serif;*font-size:small;*font:x-
44small;}
45table {font-size:inherit;font:100%;}
46
47/**
48 * 99% for safari; 100% is too large
49 */
50select, input, textarea {font:99% arial,helvetica,clean,sans-serif;}
51
52/**
53 * Bump up !IE to get to 13px equivalent
54 */
55pre, code {font:115% monospace;*font-size:100%;}
56
57/**
58 * Default line-height based on font-size rather than "computed-value"
59 * see: http://www.w3.org/TR/CSS21/visudet.html#line-height
60 */
61body * {line-height:1.22em;}
62
diff --git a/frontend/beta/css/yui/grids.css b/frontend/beta/css/yui/grids.css
new file mode 100644
index 0000000..8b64f89
--- a/dev/null
+++ b/frontend/beta/css/yui/grids.css
@@ -0,0 +1,116 @@
1/*
2
3Copyright 2008-2011 Clipperz Srl
4
5This file is part of Clipperz's Javascript Crypto Library.
6Javascript Crypto Library provides web developers with an extensive
7and efficient set of cryptographic functions. The library aims to
8obtain maximum execution speed while preserving modularity and
9reusability.
10For further information about its features and functionalities please
11refer to http://www.clipperz.com
12
13* Javascript Crypto Library is free software: you can redistribute
14 it and/or modify it under the terms of the GNU Affero General Public
15 License as published by the Free Software Foundation, either version
16 3 of the License, or (at your option) any later version.
17
18* Javascript Crypto Library is distributed in the hope that it will
19 be useful, but WITHOUT ANY WARRANTY; without even the implied
20 warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
21 See the GNU Affero General Public License for more details.
22
23* You should have received a copy of the GNU Affero General Public
24 License along with Javascript Crypto Library. If not, see
25 <http://www.gnu.org/licenses/>.
26
27*/
28
29/*
30Copyright (c) 2006, Yahoo! Inc. All rights reserved.
31Code licensed under the BSD License:
32http://developer.yahoo.net/yui/license.txt
33version: 0.11.3
34*/
35body {
36 text-align:center;
37}
38
39#doc {
40 width:57.69em;
41 *width:56.3em; /* IE */
42 min-width:750px;
43 margin:auto;
44 text-align:left;
45}
46
47#hd,#bd {margin-bottom:1em;text-align:left;}
48#ft {font-size:77%;font-family:verdana;clear:both;}
49
50/* rules for main templates */
51.yui-t1 #yui-main .yui-b, .yui-t2 #yui-main .yui-b, .yui-t3 #yui-main .yui-b,
52.yui-t4 .yui-b, .yui-t5 .yui-b, .yui-t6 .yui-b {float:right;}
53.yui-t1 .yui-b, .yui-t2 .yui-b, .yui-t3 .yui-b, .yui-t4 #yui-main .yui-b, .yui-
54t5 #yui-main .yui-b, .yui-t6 #yui-main .yui-b {float:left;}
55
56/* t1: L160 */
57.yui-t1 #yui-main .yui-b {width:76%;min-width:570px;}
58.yui-t1 .yui-b {width:21.33%;min-width:160px;}
59
60/* t2 & t4: L180 & R180 */
61.yui-t2 #yui-main .yui-b, .yui-t4 #yui-main .yui-b {width:73.4%;min-
62width:550px;}
63.yui-t2 .yui-b, .yui-t4 .yui-b {width:24%;min-width:180px;}
64
65/* t3 & t6: L300 & R300 */
66.yui-t3 #yui-main .yui-b, .yui-t6 #yui-main .yui-b {width:57.6%;min-
67width:430px;}
68.yui-t3 .yui-b, .yui-t6 .yui-b {width:40%;min-width:300px;}
69
70/* t5: R240 */
71.yui-t5 #yui-main .yui-b {width:65.4%;min-width:490px;}
72.yui-t5 .yui-b {width:32%;min-width:240px;}
73
74/* t7: 750 */
75
76
77
78 /*grid-generic rules for all templates */
79
80/* all modules and grids nested in a grid get floated */
81.yui-g .yui-u, .yui-g .yui-g, .yui-ge .yui-u, .yui-gf .yui-u {
82 float:right;
83 display:inline; /* IE */
84}
85
86/* float left and kill margin on first for added flex */
87.yui-g .first, .yui-gd .first, .yui-ge .first, .yui-gf .first {float:left; }
88
89/* 2 col */
90.yui-g .yui-u, .yui-g .yui-g {width:49.1%;}
91.yui-g .yui-g .yui-u {width:48.1%;} /* smaller for nested to preserve margins */
92
93/* 3 col */
94.yui-gb .yui-u, .yui-gc .yui-u, .yui-gd .yui-u {
95 float:left; /* need to reverse the order for 3 */
96 margin-left:2%; *margin-left:1.895%;
97 width:32%;
98}
99
100.yui-gb .first, .yui-gc .first, .yui-gd .first {margin-left:0;}
101
102/* colspan 2 */
103.yui-gc .first, .yui-gd .yui-u {width:66%;}
104.yui-gd .first {width:32%;}
105
106/* colspan 3 */
107.yui-ge .yui-u {width:24%;}
108.yui-ge .first, .yui-gf .yui-u {width:74.2%;}
109.yui-gf .first {width:24%;}
110.yui-ge .first {width:74.2%;}
111
112/* self clear floated parent containers */
113#bd:after, .yui-g:after, .yui-gb:after, .yui-gc:after, .yui-gd:after, .yui-
114ge:after, .yui-gf:after
115{content:".";display:block;height:0;clear:both;visibility:hidden;}
116#bd, .yui-g, .yui-gb, .yui-gc, .yui-gd, .yui-ge, .yui-gf {zoom:1;} /* IE */
diff --git a/frontend/beta/css/yui/logger.css b/frontend/beta/css/yui/logger.css
new file mode 100644
index 0000000..1a00f44
--- a/dev/null
+++ b/frontend/beta/css/yui/logger.css
@@ -0,0 +1,49 @@
1/*
2
3Copyright 2008-2011 Clipperz Srl
4
5This file is part of Clipperz's Javascript Crypto Library.
6Javascript Crypto Library provides web developers with an extensive
7and efficient set of cryptographic functions. The library aims to
8obtain maximum execution speed while preserving modularity and
9reusability.
10For further information about its features and functionalities please
11refer to http://www.clipperz.com
12
13* Javascript Crypto Library is free software: you can redistribute
14 it and/or modify it under the terms of the GNU Affero General Public
15 License as published by the Free Software Foundation, either version
16 3 of the License, or (at your option) any later version.
17
18* Javascript Crypto Library is distributed in the hope that it will
19 be useful, but WITHOUT ANY WARRANTY; without even the implied
20 warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
21 See the GNU Affero General Public License for more details.
22
23* You should have received a copy of the GNU Affero General Public
24 License along with Javascript Crypto Library. If not, see
25 <http://www.gnu.org/licenses/>.
26
27*/
28
29/* Copyright (c) 2006, Yahoo! Inc. All rights reserved. Code licensed under the BSD License: http://developer.yahoo.net/yui/license.txt Version: 0.11.3 */
30/* logger default styles */
31/* font size is controlled here: default 77% */
32#yui-log {position:absolute;top:1em;right:1em;font-size:77%;text-align:left;}
33/* width is controlled here: default 31em */
34.yui-log {padding:1em;width:31em;background-color:#AAA;border:1px solid black;font-family:monospace;z-index:9000;}
35.yui-log p {margin:1px;padding:.1em;}
36.yui-log button {font-family:monospace;}
37.yui-log .yui-log-hd {margin-top:1em;padding:.5em;background-color:#575757;color:#FFF;}
38/* height is controlled here: default 20em*/
39.yui-log .yui-log-bd {width:100%;height:20em;background-color:#FFF;border:1px solid gray;overflow:auto;}
40.yui-log .yui-log-ft {margin-top:.5em;margin-bottom:1em;}
41.yui-log .yui-log-ft .yui-log-categoryfilters {}
42.yui-log .yui-log-ft .yui-log-sourcefilters {width:100%;border-top:1px solid #575757;margin-top:.75em;padding-top:.75em;}
43.yui-log .yui-log-btns {position:relative;float:right;bottom:.25em;}
44.yui-log .yui-log-filtergrp {margin-right:.5em;}
45.yui-log .info {background-color:#A7CC25;} /* A7CC25 green */
46.yui-log .warn {background-color:#F58516;} /* F58516 orange */
47.yui-log .error {background-color:#E32F0B;} /* E32F0B red */
48.yui-log .time {background-color:#A6C9D7;} /* A6C9D7 blue */
49.yui-log .window {background-color:#F2E886;} /* F2E886 tan */
diff --git a/frontend/beta/css/yui/menu.css b/frontend/beta/css/yui/menu.css
new file mode 100644
index 0000000..ab3daea
--- a/dev/null
+++ b/frontend/beta/css/yui/menu.css
@@ -0,0 +1,328 @@
1/*
2
3Copyright 2008-2011 Clipperz Srl
4
5This file is part of Clipperz's Javascript Crypto Library.
6Javascript Crypto Library provides web developers with an extensive
7and efficient set of cryptographic functions. The library aims to
8obtain maximum execution speed while preserving modularity and
9reusability.
10For further information about its features and functionalities please
11refer to http://www.clipperz.com
12
13* Javascript Crypto Library is free software: you can redistribute
14 it and/or modify it under the terms of the GNU Affero General Public
15 License as published by the Free Software Foundation, either version
16 3 of the License, or (at your option) any later version.
17
18* Javascript Crypto Library is distributed in the hope that it will
19 be useful, but WITHOUT ANY WARRANTY; without even the implied
20 warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
21 See the GNU Affero General Public License for more details.
22
23* You should have received a copy of the GNU Affero General Public
24 License along with Javascript Crypto Library. If not, see
25 <http://www.gnu.org/licenses/>.
26
27*/
28
29/*
30Copyright (c) 2006, Yahoo! Inc. All rights reserved.
31Code licensed under the BSD License:
32http://developer.yahoo.com/yui/license.txt
33Version: 0.11.3
34*/
35
36
37
38/* Menu styles */
39
40div.yuimenu {
41
42 z-index:1;
43 visibility:hidden;
44 background-color:#f6f7ee;
45 border:solid 1px #c4c4be;
46 padding:1px;
47
48}
49
50
51/* MenuBar Styles */
52
53div.yuimenubar {
54
55 background-color:#f6f7ee;
56
57}
58
59/*
60 Application of "zoom:1" triggers "haslayout" in IE so that the module's
61 body clears its floated elements
62*/
63div.yuimenubar div.bd {
64
65 zoom:1;
66
67}
68
69/*
70 Clear the module body for other browsers
71*/
72div.yuimenubar div.bd:after {
73
74 content:'.';
75 display:block;
76 clear:both;
77 visibility:hidden;
78 height:0;
79
80}
81
82
83/* Matches the group title (H6) inside a Menu or MenuBar instance */
84
85div.yuimenu h6,
86div.yuimenubar h6 {
87
88 font-size:100%;
89 font-weight:normal;
90 margin:0;
91 border:solid 1px #c4c4be;
92 color:#b9b9b9;
93
94}
95
96div.yuimenubar h6 {
97
98 float:left;
99 display:inline; /* Prevent margin doubling in IE */
100 padding:4px 12px;
101 border-width:0 1px 0 0;
102
103}
104
105div.yuimenu h6 {
106
107 float:none;
108 display:block;
109 border-width:1px 0 0 0;
110 padding:5px 10px 0 10px;
111
112}
113
114
115/* Matches the UL inside a Menu or MenuBar instance */
116
117div.yuimenubar ul {
118
119 list-style-type:none;
120 margin:0;
121 padding:0;
122
123}
124
125div.yuimenu ul {
126
127 list-style-type:none;
128 border:solid 1px #c4c4be;
129 border-width:1px 0 0 0;
130 margin:0;
131 padding:10px 0;
132
133}
134
135
136div.yuimenu ul.first-of-type,
137div.yuimenu ul.hastitle,
138div.yuimenu h6.first-of-type {
139
140 border-width:0;
141
142}
143
144
145/* MenuItem and MenuBarItem styles */
146
147div.yuimenu li,
148div.yuimenubar li {
149
150 font-size:85%;
151 cursor:pointer;
152 cursor:hand;
153 white-space:nowrap;
154 text-align:left;
155
156}
157
158div.yuimenu li.yuimenuitem {
159
160 padding:2px 24px;
161
162}
163
164div.yuimenu li li,
165div.yuimenubar li li {
166
167 font-size:100%;
168
169}
170
171
172/* Matches the help text for a menu item */
173
174div.yuimenu li em {
175
176 font-style:normal;
177 margin:0 0 0 40px;
178
179}
180
181div.yuimenu li a em {
182
183 margin:0;
184
185}
186
187div.yuimenu li a,
188div.yuimenubar li a {
189
190 /*
191 "zoom:1" triggers "haslayout" in IE to ensure that the mouseover and
192 mouseout events bubble to the parent LI in IE.
193 */
194 zoom:1;
195 color:#000;
196 text-decoration:none;
197
198}
199
200div.yuimenu li.hassubmenu,
201div.yuimenu li.hashelptext {
202
203 text-align:right;
204
205}
206
207div.yuimenu li.hassubmenu a.hassubmenu,
208div.yuimenu li.hashelptext a.hashelptext {
209
210 float:left;
211 display:inline; /* Prevent margin doubling in IE */
212 text-align:left;
213
214}
215
216
217/* Matches focused and selected menu items */
218
219div.yuimenu li.selected,
220div.yuimenubar li.selected {
221
222 background-color:#8c8ad0;
223
224}
225
226div.yuimenu li.selected a.selected,
227div.yuimenubar li.selected a.selected {
228
229 text-decoration:underline;
230
231}
232
233div.yuimenu li.selected a.selected,
234div.yuimenu li.selected em.selected,
235div.yuimenubar li.selected a.selected {
236
237 color:#fff;
238
239}
240
241
242/* Matches disabled menu items */
243
244div.yuimenu li.disabled,
245div.yuimenubar li.disabled {
246
247 cursor:default;
248
249}
250
251div.yuimenu li.disabled a.disabled,
252div.yuimenu li.disabled em.disabled,
253div.yuimenubar li.disabled a.disabled {
254
255 color:#b9b9b9;
256 cursor:default;
257
258}
259
260div.yuimenubar li.yuimenubaritem {
261
262 float:left;
263 display:inline; /* Prevent margin doubling in IE */
264 border-width:0 0 0 1px;
265 border-style:solid;
266 border-color:#c4c4be;
267 padding:4px 24px;
268 margin:0;
269
270}
271
272div.yuimenubar li.yuimenubaritem.first-of-type {
273
274 border-width:0;
275
276}
277
278
279/* Matches the submenu indicator for menu items */
280
281div.yuimenubar li.yuimenubaritem img {
282
283 height:8px;
284 width:8px;
285 margin:0 0 0 10px;
286 vertical-align:middle;
287
288}
289
290div.yuimenu li.yuimenuitem img {
291
292 height:8px;
293 width:8px;
294 margin:0 -16px 0 10px;
295 border:0;
296
297 *margin-left:0;
298 *border-left-width:10px;
299 *border-style:solid;
300 *border-color:#f6f7ee;
301
302}
303
304div.yuimenu li.yuimenuitem.selected img.selected {
305
306 *border-color:#8c8ad0;
307
308}
309
310div.yuimenu li.checked {
311
312 position:relative;
313
314}
315
316div.yuimenu li.checked img.checked {
317
318 height:8px;
319 width:8px;
320 margin:0;
321 border:0;
322 position:absolute;
323 left:6px;
324 _left:-16px; /* Underscore hack b/c this is for IE 5.5 and IE 6 only */
325 top:.5em;
326
327}
328
diff --git a/frontend/beta/css/yui/reset.css b/frontend/beta/css/yui/reset.css
new file mode 100644
index 0000000..c72ae7b
--- a/dev/null
+++ b/frontend/beta/css/yui/reset.css
@@ -0,0 +1,43 @@
1/*
2
3Copyright 2008-2011 Clipperz Srl
4
5This file is part of Clipperz's Javascript Crypto Library.
6Javascript Crypto Library provides web developers with an extensive
7and efficient set of cryptographic functions. The library aims to
8obtain maximum execution speed while preserving modularity and
9reusability.
10For further information about its features and functionalities please
11refer to http://www.clipperz.com
12
13* Javascript Crypto Library is free software: you can redistribute
14 it and/or modify it under the terms of the GNU Affero General Public
15 License as published by the Free Software Foundation, either version
16 3 of the License, or (at your option) any later version.
17
18* Javascript Crypto Library is distributed in the hope that it will
19 be useful, but WITHOUT ANY WARRANTY; without even the implied
20 warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
21 See the GNU Affero General Public License for more details.
22
23* You should have received a copy of the GNU Affero General Public
24 License along with Javascript Crypto Library. If not, see
25 <http://www.gnu.org/licenses/>.
26
27*/
28
29/*
30Copyright (c) 2006, Yahoo! Inc. All rights reserved.
31Code licensed under the BSD License:
32http://developer.yahoo.net/yui/license.txt
33version: 0.11.3
34*/
35body,div,dl,dt,dd,ul,ol,li,h1,h2,h3,h4,h5,h6,pre,form,fieldset,input,p,blockquote,th,td{margin:0;padding:0;}
36table{border-collapse:collapse;border-spacing:0;}
37fieldset,img{border:0;}
38address,caption,cite,code,dfn,em,strong,th,var{font-style:normal;font-weight:normal;}
39ol,ul {list-style:none;}
40caption,th {text-align:left;}
41h1,h2,h3,h4,h5,h6{font-size:100%;}
42q:before,q:after{content:'';}
43
diff --git a/frontend/beta/css/yui/tree.css b/frontend/beta/css/yui/tree.css
new file mode 100644
index 0000000..8f537ac
--- a/dev/null
+++ b/frontend/beta/css/yui/tree.css
@@ -0,0 +1,132 @@
1/*
2
3Copyright 2008-2011 Clipperz Srl
4
5This file is part of Clipperz's Javascript Crypto Library.
6Javascript Crypto Library provides web developers with an extensive
7and efficient set of cryptographic functions. The library aims to
8obtain maximum execution speed while preserving modularity and
9reusability.
10For further information about its features and functionalities please
11refer to http://www.clipperz.com
12
13* Javascript Crypto Library is free software: you can redistribute
14 it and/or modify it under the terms of the GNU Affero General Public
15 License as published by the Free Software Foundation, either version
16 3 of the License, or (at your option) any later version.
17
18* Javascript Crypto Library is distributed in the hope that it will
19 be useful, but WITHOUT ANY WARRANTY; without even the implied
20 warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
21 See the GNU Affero General Public License for more details.
22
23* You should have received a copy of the GNU Affero General Public
24 License along with Javascript Crypto Library. If not, see
25 <http://www.gnu.org/licenses/>.
26
27*/
28
29/*
30Copyright (c) 2006, Yahoo! Inc. All rights reserved.
31Code licensed under the BSD License:
32http://developer.yahoo.com/yui/license.txt
33Version: 0.11.3
34*/
35
36/* first or middle sibling, no children */
37.ygtvtn {
38 width:16px; height:22px;
39 background: url(../../images/yui/treeview/tn.gif) 0 0 no-repeat;
40}
41
42/* first or middle sibling, collapsable */
43.ygtvtm {
44 width:16px; height:22px;
45 cursor:pointer ;
46 background: url(../../images/yui/treeview/tm.gif) 0 0 no-repeat;
47}
48
49/* first or middle sibling, collapsable, hover */
50.ygtvtmh {
51 width:16px; height:22px;
52 cursor:pointer ;
53 background: url(../../images/yui/treeview/tmh.gif) 0 0 no-repeat;
54}
55
56/* first or middle sibling, expandable */
57.ygtvtp {
58 width:16px; height:22px;
59 cursor:pointer ;
60 background: url(../../images/yui/treeview/tp.gif) 0 0 no-repeat;
61}
62
63/* first or middle sibling, expandable, hover */
64.ygtvtph {
65 width:16px; height:22px;
66 cursor:pointer ;
67 background: url(../../images/yui/treeview/tph.gif) 0 0 no-repeat;
68}
69
70/* last sibling, no children */
71.ygtvln {
72 width:16px; height:22px;
73 background: url(../../images/yui/treeview/ln.gif) 0 0 no-repeat;
74}
75
76/* Last sibling, collapsable */
77.ygtvlm {
78 width:16px; height:22px;
79 cursor:pointer ;
80 background: url(../../images/yui/treeview/lm.gif) 0 0 no-repeat;
81}
82
83/* Last sibling, collapsable, hover */
84.ygtvlmh {
85 width:16px; height:22px;
86 cursor:pointer ;
87 background: url(../../images/yui/treeview/lmh.gif) 0 0 no-repeat;
88}
89
90/* Last sibling, expandable */
91.ygtvlp {
92 width:16px; height:22px;
93 cursor:pointer ;
94 background: url(../../images/yui/treeview/lp.gif) 0 0 no-repeat;
95}
96
97/* Last sibling, expandable, hover */
98.ygtvlph {
99 width:16px; height:22px; cursor:pointer ;
100 background: url(../../images/yui/treeview/lph.gif) 0 0 no-repeat;
101}
102
103/* Loading icon */
104.ygtvloading {
105 width:16px; height:22px;
106 background: url(../../images/yui/treeview/loading.gif) 0 0 no-repeat;
107}
108
109/* the style for the empty cells that are used for rendering the depth
110 * of the node */
111.ygtvdepthcell {
112 width:16px; height:22px;
113 background: url(../../images/yui/treeview/vline.gif) 0 0 no-repeat;
114}
115
116.ygtvblankdepthcell { width:16px; height:22px; }
117
118/* the style of the div around each node */
119.ygtvitem { }
120
121/* the style of the div around each node's collection of children */
122.ygtvchildren { }
123* html .ygtvchildren { height:2%; }
124
125/* the style of the text label in ygTextNode */
126.ygtvlabel, .ygtvlabel:link, .ygtvlabel:visited, .ygtvlabel:hover {
127 margin-left:2px;
128 text-decoration: none;
129}
130
131.ygtvspacer { height: 10px; width: 10px; margin: 2px; }
132
diff --git a/frontend/beta/html/index_template.html b/frontend/beta/html/index_template.html
new file mode 100644
index 0000000..9862518
--- a/dev/null
+++ b/frontend/beta/html/index_template.html
@@ -0,0 +1,100 @@
1<html>
2<head>
3 <title>@page.title@</title>
4 <META http-equiv="Content-Type" content="text/html; charset=utf-8" />
5<!--
6@copyright@
7-->
8
9@css@
10
11 <link rel="shortcut icon" href="./clipperz.ico" />
12
13 <meta name="description" content="Login to your web accounts with just one click. Never type a password again! Use multiple complex passwords and forget them. A password manager that enhances your online security." />
14 <meta name="keywords" content="password manager,gestor de contraseñas,gerenciador de senhas,Kennwortmanager,passwords,security,privacy,cryptography" />
15<script>
16 Clipperz_IEisBroken = false;
17 Clipperz_normalizedNewLine = '\n';
18 Clipperz_dumpUrl = "/dump/";
19</script>
20
21<!--[if IE]><script>
22Clipperz_IEisBroken = true;
23Clipperz_normalizedNewLine = '\x0d\x0a';
24</script><![endif]-->
25
26@js_DEBUG@
27
28</head>
29<body>
30<div id="mainDiv">
31 <div id="header">
32 <div id="miscLinks">
33 <a id="donateHeaderIconLink" href="http://www.clipperz.com/donations" target="_blank"><img id='donateHeaderIcon' src=""></a>
34 <ul>
35 <li><a href="http://www.clipperz.com/donations" id='donateHeaderLink' class='highlightedHeader' target="_blank">donate</a></li>
36 <li><a href="http://www.clipperz.com/credits" id='creditsHeaderLink' target="_blank">credits</a></li>
37 <li><a href="http://www.clipperz.com/contact" id='feedbackHeaderLink' target="_blank">feedback</a></li>
38 <li><a href="http://www.clipperz.com/support/user_guide" target="_blank" id='helpHeaderLink'>help</a></li>
39 <li><a href="http://www.clipperz.com/forum" target="_blank" id='forumHeaderLink'>forum</a></li>
40 </ul>
41 </div>
42 <div id="logoFrame">
43 <a href="http://www.clipperz.com" target="_blank"><img id="logo" src="" /></a>
44 <h5 class="clipperzPayoff">keep it to yourself</h5>
45 </div>
46 <div id="mainTabs">
47 <ul id="exitLinks">
48 <li id="logoutLI"><!--<a href="#">logout</a>--></li>
49 <li id="lockLI"><!--<a href="#">lock</a>--></li>
50 </ul>
51 <div id="menus">
52 <table cellpadding="0" cellspacing="0" border="0">
53 <tbody>
54 <tr id="menusTR">
55<!--
56 <td class="selected"><div><a href="#">records</a></div></td>
57 <td><div><a href="./Account.html">account</a></div></td>
58 <td><div><a href="#">data</a></div></td>
59 <td><div><a href="#">bookmarklet</a></div></td>
60-->
61 </tr>
62 </tbody>
63 </table>
64 </div>
65 </div>
66 </div>
67
68 <div id="main">
69 <h3 class="loading">loading ...</h3>
70
71@js_INSTALL@
72
73<script>
74 Clipperz.PM.Proxy.defaultProxy = new Clipperz.PM.Proxy.JSON({'url':'@request.path@', 'shouldPayTolls':@should.pay.toll@});
75 /*offline_data_placeholder*/
76</script>
77
78 <div id="javaScriptAlert">
79 <h1>Attention!</h1>
80 <p>If you can read this message, the chances are that your browser does not properly support JavaScript? or you have disabled this functionality yourself.</p>
81 <h3>Javascript is required to access Clipperz.</h3>
82 <h5>Please enable scripting or upgrade your browser.</h5>
83 </div>
84 </div>
85 <div id="footer">
86 Copyright &copy; 2008 Clipperz Srl -
87 <a href="http://www.clipperz.com/terms_of_service" target="black">Terms of service</a> -
88 <a href="http://www.clipperz.com/privacy_policy" target="black">Privacy policy</a>
89 &nbsp;-&nbsp;
90 Application version: @application.version@
91 </div>
92
93 <div id="recordDetailEditModeHeaderMask"></div>
94 <div id="recordDetailEditModeVerticalMask"></div>
95</div>
96
97<div id="applicationVersionType" class="@application.version.type@" />
98
99</body>
100</html>
diff --git a/frontend/beta/images/cardBlockLowerBorder.gif b/frontend/beta/images/cardBlockLowerBorder.gif
new file mode 100644
index 0000000..e69de29
--- a/dev/null
+++ b/frontend/beta/images/cardBlockLowerBorder.gif
diff --git a/frontend/beta/images/cardBlockLowerRoundedCorner.gif b/frontend/beta/images/cardBlockLowerRoundedCorner.gif
new file mode 100644
index 0000000..e69de29
--- a/dev/null
+++ b/frontend/beta/images/cardBlockLowerRoundedCorner.gif
diff --git a/frontend/beta/images/cardFiltersSprite.gif b/frontend/beta/images/cardFiltersSprite.gif
new file mode 100644
index 0000000..e69de29
--- a/dev/null
+++ b/frontend/beta/images/cardFiltersSprite.gif
diff --git a/frontend/beta/images/cardsBlockRoundCorners.gif b/frontend/beta/images/cardsBlockRoundCorners.gif
new file mode 100644
index 0000000..e69de29
--- a/dev/null
+++ b/frontend/beta/images/cardsBlockRoundCorners.gif
diff --git a/frontend/beta/images/clipperz/basic-dialog/btn-sprite.gif b/frontend/beta/images/clipperz/basic-dialog/btn-sprite.gif
new file mode 100644
index 0000000..e69de29
--- a/dev/null
+++ b/frontend/beta/images/clipperz/basic-dialog/btn-sprite.gif
diff --git a/frontend/beta/images/clipperz/basic-dialog/close.gif b/frontend/beta/images/clipperz/basic-dialog/close.gif
new file mode 100644
index 0000000..e69de29
--- a/dev/null
+++ b/frontend/beta/images/clipperz/basic-dialog/close.gif
diff --git a/frontend/beta/images/clipperz/basic-dialog/close.png b/frontend/beta/images/clipperz/basic-dialog/close.png
new file mode 100644
index 0000000..e69de29
--- a/dev/null
+++ b/frontend/beta/images/clipperz/basic-dialog/close.png
diff --git a/frontend/beta/images/clipperz/basic-dialog/close_over.gif b/frontend/beta/images/clipperz/basic-dialog/close_over.gif
new file mode 100644
index 0000000..e69de29
--- a/dev/null
+++ b/frontend/beta/images/clipperz/basic-dialog/close_over.gif
diff --git a/frontend/beta/images/clipperz/basic-dialog/e-handle.gif b/frontend/beta/images/clipperz/basic-dialog/e-handle.gif
new file mode 100644
index 0000000..e69de29
--- a/dev/null
+++ b/frontend/beta/images/clipperz/basic-dialog/e-handle.gif
diff --git a/frontend/beta/images/clipperz/basic-dialog/hd-sprite.gif b/frontend/beta/images/clipperz/basic-dialog/hd-sprite.gif
new file mode 100644
index 0000000..e69de29
--- a/dev/null
+++ b/frontend/beta/images/clipperz/basic-dialog/hd-sprite.gif
diff --git a/frontend/beta/images/clipperz/basic-dialog/progress.gif b/frontend/beta/images/clipperz/basic-dialog/progress.gif
new file mode 100644
index 0000000..e69de29
--- a/dev/null
+++ b/frontend/beta/images/clipperz/basic-dialog/progress.gif
diff --git a/frontend/beta/images/clipperz/basic-dialog/progress2.gif b/frontend/beta/images/clipperz/basic-dialog/progress2.gif
new file mode 100644
index 0000000..e69de29
--- a/dev/null
+++ b/frontend/beta/images/clipperz/basic-dialog/progress2.gif
diff --git a/frontend/beta/images/clipperz/basic-dialog/s-handle.gif b/frontend/beta/images/clipperz/basic-dialog/s-handle.gif
new file mode 100644
index 0000000..e69de29
--- a/dev/null
+++ b/frontend/beta/images/clipperz/basic-dialog/s-handle.gif
diff --git a/frontend/beta/images/clipperz/basic-dialog/se-handle.gif b/frontend/beta/images/clipperz/basic-dialog/se-handle.gif
new file mode 100644
index 0000000..e69de29
--- a/dev/null
+++ b/frontend/beta/images/clipperz/basic-dialog/se-handle.gif
diff --git a/frontend/beta/images/default/basic-dialog/btn-sprite.gif b/frontend/beta/images/default/basic-dialog/btn-sprite.gif
new file mode 100644
index 0000000..e69de29
--- a/dev/null
+++ b/frontend/beta/images/default/basic-dialog/btn-sprite.gif
diff --git a/frontend/beta/images/default/basic-dialog/close.gif b/frontend/beta/images/default/basic-dialog/close.gif
new file mode 100644
index 0000000..e69de29
--- a/dev/null
+++ b/frontend/beta/images/default/basic-dialog/close.gif
diff --git a/frontend/beta/images/default/basic-dialog/e-handle.gif b/frontend/beta/images/default/basic-dialog/e-handle.gif
new file mode 100644
index 0000000..e69de29
--- a/dev/null
+++ b/frontend/beta/images/default/basic-dialog/e-handle.gif
diff --git a/frontend/beta/images/default/basic-dialog/hd-sprite.gif b/frontend/beta/images/default/basic-dialog/hd-sprite.gif
new file mode 100644
index 0000000..e69de29
--- a/dev/null
+++ b/frontend/beta/images/default/basic-dialog/hd-sprite.gif
diff --git a/frontend/beta/images/default/basic-dialog/progress.gif b/frontend/beta/images/default/basic-dialog/progress.gif
new file mode 100644
index 0000000..e69de29
--- a/dev/null
+++ b/frontend/beta/images/default/basic-dialog/progress.gif
diff --git a/frontend/beta/images/default/basic-dialog/progress2.gif b/frontend/beta/images/default/basic-dialog/progress2.gif
new file mode 100644
index 0000000..e69de29
--- a/dev/null
+++ b/frontend/beta/images/default/basic-dialog/progress2.gif
diff --git a/frontend/beta/images/default/basic-dialog/s-handle.gif b/frontend/beta/images/default/basic-dialog/s-handle.gif
new file mode 100644
index 0000000..e69de29
--- a/dev/null
+++ b/frontend/beta/images/default/basic-dialog/s-handle.gif
diff --git a/frontend/beta/images/default/basic-dialog/se-handle.gif b/frontend/beta/images/default/basic-dialog/se-handle.gif
new file mode 100644
index 0000000..e69de29
--- a/dev/null
+++ b/frontend/beta/images/default/basic-dialog/se-handle.gif
diff --git a/frontend/beta/images/directLogin/toggle.png b/frontend/beta/images/directLogin/toggle.png
new file mode 100644
index 0000000..e69de29
--- a/dev/null
+++ b/frontend/beta/images/directLogin/toggle.png
diff --git a/frontend/beta/images/directLoginBox.png b/frontend/beta/images/directLoginBox.png
new file mode 100644
index 0000000..e69de29
--- a/dev/null
+++ b/frontend/beta/images/directLoginBox.png
diff --git a/frontend/beta/images/entropyBackground.gif b/frontend/beta/images/entropyBackground.gif
new file mode 100644
index 0000000..e69de29
--- a/dev/null
+++ b/frontend/beta/images/entropyBackground.gif
diff --git a/frontend/beta/images/exportLogo.png b/frontend/beta/images/exportLogo.png
new file mode 100644
index 0000000..e69de29
--- a/dev/null
+++ b/frontend/beta/images/exportLogo.png
diff --git a/frontend/beta/images/favicon.ico b/frontend/beta/images/favicon.ico
new file mode 100644
index 0000000..e69de29
--- a/dev/null
+++ b/frontend/beta/images/favicon.ico
diff --git a/frontend/beta/images/flags/br.png b/frontend/beta/images/flags/br.png
new file mode 100644
index 0000000..e69de29
--- a/dev/null
+++ b/frontend/beta/images/flags/br.png
diff --git a/frontend/beta/images/flags/cn.png b/frontend/beta/images/flags/cn.png
new file mode 100644
index 0000000..e69de29
--- a/dev/null
+++ b/frontend/beta/images/flags/cn.png
diff --git a/frontend/beta/images/flags/de.png b/frontend/beta/images/flags/de.png
new file mode 100644
index 0000000..e69de29
--- a/dev/null
+++ b/frontend/beta/images/flags/de.png
diff --git a/frontend/beta/images/flags/en.png b/frontend/beta/images/flags/en.png
new file mode 100644
index 0000000..e69de29
--- a/dev/null
+++ b/frontend/beta/images/flags/en.png
diff --git a/frontend/beta/images/flags/es.png b/frontend/beta/images/flags/es.png
new file mode 100644
index 0000000..e69de29
--- a/dev/null
+++ b/frontend/beta/images/flags/es.png
diff --git a/frontend/beta/images/flags/it.png b/frontend/beta/images/flags/it.png
new file mode 100644
index 0000000..e69de29
--- a/dev/null
+++ b/frontend/beta/images/flags/it.png
diff --git a/frontend/beta/images/flags/jp.png b/frontend/beta/images/flags/jp.png
new file mode 100644
index 0000000..e69de29
--- a/dev/null
+++ b/frontend/beta/images/flags/jp.png
diff --git a/frontend/beta/images/flags/ru.png b/frontend/beta/images/flags/ru.png
new file mode 100644
index 0000000..e69de29
--- a/dev/null
+++ b/frontend/beta/images/flags/ru.png
diff --git a/frontend/beta/images/grippie.png b/frontend/beta/images/grippie.png
new file mode 100644
index 0000000..e69de29
--- a/dev/null
+++ b/frontend/beta/images/grippie.png
diff --git a/frontend/beta/images/importActiveStepsSeparator.png b/frontend/beta/images/importActiveStepsSeparator.png
new file mode 100644
index 0000000..e69de29
--- a/dev/null
+++ b/frontend/beta/images/importActiveStepsSeparator.png
diff --git a/frontend/beta/images/importStepsBackground.png b/frontend/beta/images/importStepsBackground.png
new file mode 100644
index 0000000..e69de29
--- a/dev/null
+++ b/frontend/beta/images/importStepsBackground.png
diff --git a/frontend/beta/images/importStepsLabelsBackground.png b/frontend/beta/images/importStepsLabelsBackground.png
new file mode 100644
index 0000000..e69de29
--- a/dev/null
+++ b/frontend/beta/images/importStepsLabelsBackground.png
diff --git a/frontend/beta/images/importStepsLeftLabelsBackground.png b/frontend/beta/images/importStepsLeftLabelsBackground.png
new file mode 100644
index 0000000..e69de29
--- a/dev/null
+++ b/frontend/beta/images/importStepsLeftLabelsBackground.png
diff --git a/frontend/beta/images/importStepsSeparator.png b/frontend/beta/images/importStepsSeparator.png
new file mode 100644
index 0000000..e69de29
--- a/dev/null
+++ b/frontend/beta/images/importStepsSeparator.png
diff --git a/frontend/beta/images/languageBox.png b/frontend/beta/images/languageBox.png
new file mode 100644
index 0000000..e69de29
--- a/dev/null
+++ b/frontend/beta/images/languageBox.png
diff --git a/frontend/beta/images/loginFormBox.png b/frontend/beta/images/loginFormBox.png
new file mode 100644
index 0000000..e69de29
--- a/dev/null
+++ b/frontend/beta/images/loginFormBox.png
diff --git a/frontend/beta/images/loginInfoBackground.png b/frontend/beta/images/loginInfoBackground.png
new file mode 100644
index 0000000..e69de29
--- a/dev/null
+++ b/frontend/beta/images/loginInfoBackground.png
diff --git a/frontend/beta/images/loginInfoInnerBackground.png b/frontend/beta/images/loginInfoInnerBackground.png
new file mode 100644
index 0000000..e69de29
--- a/dev/null
+++ b/frontend/beta/images/loginInfoInnerBackground.png
diff --git a/frontend/beta/images/logo.gif b/frontend/beta/images/logo.gif
new file mode 100644
index 0000000..e69de29
--- a/dev/null
+++ b/frontend/beta/images/logo.gif
diff --git a/frontend/beta/images/menubarSprite.gif b/frontend/beta/images/menubarSprite.gif
new file mode 100644
index 0000000..e69de29
--- a/dev/null
+++ b/frontend/beta/images/menubarSprite.gif
diff --git a/frontend/beta/images/newRecordPanelBackground.gif b/frontend/beta/images/newRecordPanelBackground.gif
new file mode 100644
index 0000000..e69de29
--- a/dev/null
+++ b/frontend/beta/images/newRecordPanelBackground.gif
diff --git a/frontend/beta/images/newRecordPanelBackground.png b/frontend/beta/images/newRecordPanelBackground.png
new file mode 100644
index 0000000..e69de29
--- a/dev/null
+++ b/frontend/beta/images/newRecordPanelBackground.png
diff --git a/frontend/beta/images/passwordAssistant.png b/frontend/beta/images/passwordAssistant.png
new file mode 100644
index 0000000..e69de29
--- a/dev/null
+++ b/frontend/beta/images/passwordAssistant.png
diff --git a/frontend/beta/images/read-only.gif b/frontend/beta/images/read-only.gif
new file mode 100644
index 0000000..e69de29
--- a/dev/null
+++ b/frontend/beta/images/read-only.gif
diff --git a/frontend/beta/images/read-only.png b/frontend/beta/images/read-only.png
new file mode 100644
index 0000000..e69de29
--- a/dev/null
+++ b/frontend/beta/images/read-only.png
diff --git a/frontend/beta/images/read-only_background.png b/frontend/beta/images/read-only_background.png
new file mode 100644
index 0000000..e69de29
--- a/dev/null
+++ b/frontend/beta/images/read-only_background.png
diff --git a/frontend/beta/images/recordFilterBackground.png b/frontend/beta/images/recordFilterBackground.png
new file mode 100644
index 0000000..e69de29
--- a/dev/null
+++ b/frontend/beta/images/recordFilterBackground.png
diff --git a/frontend/beta/images/rss.gif b/frontend/beta/images/rss.gif
new file mode 100644
index 0000000..e69de29
--- a/dev/null
+++ b/frontend/beta/images/rss.gif
diff --git a/frontend/beta/images/scrambledValue.gif b/frontend/beta/images/scrambledValue.gif
new file mode 100644
index 0000000..e69de29
--- a/dev/null
+++ b/frontend/beta/images/scrambledValue.gif
diff --git a/frontend/beta/images/scrambledValue.png b/frontend/beta/images/scrambledValue.png
new file mode 100644
index 0000000..e69de29
--- a/dev/null
+++ b/frontend/beta/images/scrambledValue.png
diff --git a/frontend/beta/images/smiles.gif b/frontend/beta/images/smiles.gif
new file mode 100644
index 0000000..e69de29
--- a/dev/null
+++ b/frontend/beta/images/smiles.gif
diff --git a/frontend/beta/images/smiles_big.gif b/frontend/beta/images/smiles_big.gif
new file mode 100644
index 0000000..e69de29
--- a/dev/null
+++ b/frontend/beta/images/smiles_big.gif
diff --git a/frontend/beta/images/smiles_small.gif b/frontend/beta/images/smiles_small.gif
new file mode 100644
index 0000000..e69de29
--- a/dev/null
+++ b/frontend/beta/images/smiles_small.gif
diff --git a/frontend/beta/images/test-database.png b/frontend/beta/images/test-database.png
new file mode 100644
index 0000000..e69de29
--- a/dev/null
+++ b/frontend/beta/images/test-database.png
diff --git a/frontend/beta/js/Bookmarklet.js b/frontend/beta/js/Bookmarklet.js
new file mode 100644
index 0000000..b8a0c0e
--- a/dev/null
+++ b/frontend/beta/js/Bookmarklet.js
@@ -0,0 +1,400 @@
1/*
2
3Copyright 2008-2011 Clipperz Srl
4
5This file is part of Clipperz's Javascript Crypto Library.
6Javascript Crypto Library provides web developers with an extensive
7and efficient set of cryptographic functions. The library aims to
8obtain maximum execution speed while preserving modularity and
9reusability.
10For further information about its features and functionalities please
11refer to http://www.clipperz.com
12
13* Javascript Crypto Library is free software: you can redistribute
14 it and/or modify it under the terms of the GNU Affero General Public
15 License as published by the Free Software Foundation, either version
16 3 of the License, or (at your option) any later version.
17
18* Javascript Crypto Library is distributed in the hope that it will
19 be useful, but WITHOUT ANY WARRANTY; without even the implied
20 warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
21 See the GNU Affero General Public License for more details.
22
23* You should have received a copy of the GNU Affero General Public
24 License along with Javascript Crypto Library. If not, see
25 <http://www.gnu.org/licenses/>.
26
27*/
28
29_cble = null;
30
31//-----------------------------------------------------------------------------
32
33isLoginForm = function(aForm) {
34 var inputFields;
35 var passwordFieldsFound;
36 var i,c;
37
38//console.log('is login form: ' + aForm.name + ' (' + aForm.id + ')');
39 passwordFieldsFound = 0;
40 inputFields = aForm.elements;
41 c = inputFields.length;
42 for (i=0; i<c; i++) {
43 if (inputFields[i].type == 'password') {
44 passwordFieldsFound ++;
45 }
46 }
47//console.log('number of password fields found: ' + passwordFieldsFound);
48 return (passwordFieldsFound == 1);
49};
50
51//-----------------------------------------------------------------------------
52
53findLoginForm = function(aDocument, aLevel) {
54 varresult;
55 vardocumentForms;
56 var i,c;
57
58 result = null;
59
60 try {
61 documentForms = aDocument.getElementsByTagName('form');
62
63 c = documentForms.length;
64 for (i=0; (i<c) && (result == null); i++) {
65 if (isLoginForm(documentForms[i])) {
66 result = documentForms[i];
67 }
68 }
69
70 if ((result == null) && (aLevel == 0)) {
71 var iFrames;
72
73 iFrames = aDocument.getElementsByTagName('iframe');
74 c = iFrames.length;
75 for (i=0; (i<c) && (result == null); i++) {
76 result = findLoginForm(iFrames[i].contentDocument, (aLevel + 1));
77 }
78 }
79 } catch (e) {
80 _cble = e;
81 }
82
83 return result;
84};
85
86//-----------------------------------------------------------------------------
87
88inputElementValues = function(anInputElement) {
89 varresult;
90
91 //if ((anInputElement instanceof HTMLInputElement) && (anInputElement.getAttribute('name') != null)) {
92 if ((anInputElement.tagName.toLowerCase() == 'input') && (anInputElement.getAttribute('name') != null)) {
93 result = {};
94 result.type = anInputElement.getAttribute('type') || 'text';
95 result.name = anInputElement.getAttribute('name');
96 // result.value = anInputElement.getAttribute('value');
97 result.value = anInputElement.value;
98 if (anInputElement.type.toLowerCase() == 'radio') {
99 result.checked = anInputElement.checked;
100 }
101 //} else if ((anInputElement instanceof HTMLSelectElement) && (anInputElement.getAttribute('name') != null)) {
102 } else if ((anInputElement.tagName.toLowerCase() == 'select') && (anInputElement.getAttribute('name') != null)) {
103 varoptions;
104 var c,i;
105
106//console.log('input element values: %o', anInputElement);
107 result = {};
108 result.type = 'select';
109 result.name = anInputElement.getAttribute('name');
110
111 result.options = [];
112 options = anInputElement.options;
113 c = options.length;
114 for (i=0; i<c; i++) {
115 varoption;
116
117 option = {};
118 option.selected = options[i].selected;
119 option.label = options[i].label || options[i].innerHTML;
120 option.value = options[i].value;
121 result.options.push(option);
122 }
123 } else {
124 result = null;
125 }
126
127 return result;
128};
129
130//-----------------------------------------------------------------------------
131
132formParameters = function(aLoginForm) {
133 varresult;
134 vari, c;
135 varaction;
136
137 if (aLoginForm == null) {
138 result = null;
139 } else {
140 varradioValues;
141 varradioValueName;
142
143 result = {};
144 radioValues = {};
145
146 action = aLoginForm.action;
147 if (action.constructor != String) {
148 action = aLoginForm.getAttribute('action');
149 }
150
151 if (/^https?\:\/\/.*/.test(action)) {
152 action = action;
153 } else if (/^\/.*/.test(action)) {
154 action = window.location.protocol + '/' + '/' + window.location.hostname + action;
155 } else {
156 action = window.location.href.replace(/\/[^\/]*$/, '/' + action);
157 }
158
159 result.attributes = {};
160 result.attributes.action = action;
161 result.attributes.method = aLoginForm.getAttribute('method');
162
163 result.inputs = [];
164 c = aLoginForm.elements.length;
165 for (i=0; i<c; i++) {
166 varinputElement;
167 varelementValues;
168
169 inputElement = aLoginForm.elements[i];
170 elementValues = inputElementValues(inputElement);
171 if (elementValues != null) {
172 if (elementValues.type != 'radio') {
173 result.inputs.push(elementValues);
174 } else {
175 varradioValue;
176 varvalues;
177
178 radioValue = radioValues[elementValues.name];
179 if (radioValue == null) {
180 radioValue = {};
181 radioValue.name = elementValues.name;
182 radioValue.type = 'radio';
183 radioValue.options = [];
184
185 radioValues[elementValues.name] = radioValue;
186 }
187
188 values = {};
189 values.value = elementValues.value;
190 values.checked = elementValues.checked;
191
192 radioValue.options.push(values);
193 }
194 }
195 }
196
197 for (radioValueName in radioValues) {
198 if (typeof(radioValues[radioValueName]) != 'function') {
199 result.inputs.push(radioValues[radioValueName]);
200 }
201 }
202 }
203
204 return result;
205};
206
207//-----------------------------------------------------------------------------
208
209pageParameters = function() {
210 var result;
211
212 result = {};
213 result['title'] = document.title;
214//<link rel='icon' href='http://example.com/favicon.ico' type='image/x-icon'>
215
216 return result;
217};
218
219//-----------------------------------------------------------------------------
220
221reprString = function (o) {
222 return ('\'' +o.replace(/(["\\])/g, '\\$1') + '\''
223 ).replace(/[\f]/g, '\\f'
224 ).replace(/[\b]/g, '\\b'
225 ).replace(/[\n]/g, '\\n'
226 ).replace(/[\t]/g, '\\t'
227 ).replace(/[\r]/g, '\\r');
228};
229
230//-----------------------------------------------------------------------------
231
232serializeJSON = function (o) {
233 var objtype = typeof(o);
234 if (objtype == 'number' || objtype == 'boolean') {
235 return o + '';
236 } else if (o === null) {
237 return 'null';
238 }
239
240 //var m = MochiKit.Base;
241 //var reprString = m.reprString;
242 if (objtype == 'string') {
243 return reprString(o);
244 }
245
246 //recurse
247 var me = arguments.callee;
248 //array
249 if (objtype != 'function' && typeof(o.length) == 'number') {
250 var res = [];
251 for (var i = 0; i < o.length; i++) {
252 var val = me(o[i]);
253 if (typeof(val) != 'string') {
254 val = 'undefined';
255 }
256 res.push(val);
257 }
258 return '[' + res.join(',\n') + ']';
259 }
260
261 //undefined is outside of the spec
262 if (objtype == 'undefined') {
263 // throw new TypeError('undefined can not be serialized as JSON');
264 throw new TypeError('error');
265 }
266
267 //generic object code path
268 res = [];
269 for (var k in o) {
270 if (typeof(o[k]) != 'function') {
271 var useKey;
272 if (typeof(k) == 'number') {
273 useKey = '\'' + k + '\'';
274 } else if (typeof(k) == 'string') {
275 useKey = reprString(k);
276 } else {
277 //skip non-string or number keys
278 continue;
279 }
280
281 val = me(o[k]);
282 if (typeof(val) != 'string') {
283 //skip non-serializable values
284 continue;
285 }
286 res.push(useKey + ':' + ' ' + val);
287 }
288 }
289
290 return '{' + res.join(',\n') + '}';
291};
292
293//-----------------------------------------------------------------------------
294
295closeBookmarklet = function() {
296 varbookmarkletDiv;
297
298 bookmarkletDiv = document.getElementById('clipperz_bookmarklet');
299 bookmarkletDiv.parentNode.removeChild(bookmarkletDiv);
300};
301
302//-----------------------------------------------------------------------------
303
304logFormParameters = function(someParameters, anException) {
305 varnewDiv;
306 var base_url;
307 varhelp_url;
308 // varbase_image_url;
309 varlogo_image_url;
310 varbackground_image_url;
311 varclose_image_url;
312 varbookmarklet_textarea;
313 var innerHTML;
314
315//
316 //Obsolete: image -> base64 encoding done here: http://www.motobit.com/util/base64-decoder-encoder.asp
317 //conversion done using the Filemark Maker application: http://www.insanelygreattees.com/news/?p=51
318//
319
320 base_url = 'http://www.clipperz.com/';
321 help_url = base_url + 'help/bookmarklet';
322 //base_image_url = base_url + 'files/clipperz.com/bookmarklet/';
323 //logo_image_url = base_image_url + 'logo.png';
324 logo_image_url = 'data:image/png;charset=utf-8;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAAAXCAYAAABOMABkAAAACXBIWXMAAAsTAAALEwEAmpwYAAANJ2lDQ1BQaG90b3Nob3AgSUNDIHByb2ZpbGUAAHjardd5NJRv2AfwaxbGMmbGGHsY2Xcle/YtkWzZUpKdYSYmScqSlDVLKNoo2oQWEonqR5YkyZKtyJKlFLJkmfcPqd7feZfznvNefzzneu7nj/t+7nM+3/vcAHgNdxqNggSAwCB6sK2ZIdnJ2YWM6QQM4IAXsCDi7hFCM7C2toT/uhAA852AAABoV3Cn0SjwfytcsJOzCwBCHgBIPuu9PgCQDq739gBAOkKn0QEQvgBA8vB19wRARACAfLC9rREA4iYA4HzW+woAwB1c7xsAABfq4UMHQHQDMBODPP2CADBTAMy6nl4hHgA4eQDw9AzxCATApQKAVWAg1RMA9xEApD1owXQAPAsAKDg5u5DXl7w3AWAbPwCLxZ+xI5kAZXkA0rv+jIk9AuBxB8hP/jM2awsIAEDwtIZ4q2xd30GsIQDTAIMxKwmASQdYTWMwlvMZjNVrAKg+gFqKx+Hg0I39RrQA/G/v6//8q1AIACQAQhxRiAxHRaAjmE4wR2FiWE6yGrPWsZ1mP4ON50jClRN8OdOIaVzppHPcmTyZvNl8dQJUwdxNuUKXhBvIh0XzN18Ta5U4Jlko1SZzQvaOXKdCjOJdpZ4tp7feV/mgmqRWrj6omaJVqT2qk6H7VG/CIMvwudFXkxzTerMZ8ys7myzmd+Vbvd79xvqNTZvtiv3tPR0OnY5dTt0u6L33XPv29e8fcPtw4ONBrMdjz2GvEe9RnzHfz37jAdyUZ4Ffgr5Sp2nfDn0PngmZo88d/hE6f2QhbPHoUvjPYysRK8dXI2WiOmIQJ5GxqFPoOKbTzGcw8SwJrIlsSezJ2BSOs7hUfBohnTODeI4rk5TFnc1znvcCXw5/rsBFwUubLgtdEb4qkkfOF722+bpYgXihxA2pm1K3pG/L3JG9M1lEuStfrFCiVKp8b8v9LQ+2PtxWplquVj7/KLRC/bFGpVaV9pPt1duf6jxdq4ms1Xum/9zgheE/RnXouth6k5emDWaN5k3mzWzNia8sWixfW7XiWs++sW6zeWvbTmxPf2fXYd+5p4unK7vb8b1Tj0uvQG9un2u/68C+D8Ifrnx0GzwwJDqU/+ngsMeI56jEaOGY92efcd8JmYnbk/5TAV8oXxW+Fk8HfaN+p81smbk/GzwX8oM+rzpfvhC6GLZ09OfRZa3lqpVjqxFrOmtPGQwAhBgSh/yGakbfYcpgjsD4sNizGrFtY5fCSnHw4XjxfAQ+Tm6iJJc0SYPbkmc/bwhfCn+JQLPguBCXsJqID/m86EsxhLiOxCHJe1LTMtKyFLkqBZSigVKa8uBWGZW4bV1qsuo0jTotXu2w7a90efSo+s8NxY2OGbeZCpuF7ag2X7LYYum1K9OqzRpnY2YbZldg/86BzVHf6ZDzJZf6vdP7RPbvdgs/kO9ed3Dck9tLz9vJ54TvVb9a//6ApUCuIDmqMc33UERwakg+vexwQ2jvkYmw+XDUMc4I8nH5E6qR+lEW0btj9p48EOt1ihJHPx18Jio+KuFkYnxSenJiSs7ZC6nZaWnpFzPSz2Vlns+6mX3jfPGFmzl3cksuPrn05HLdlVdX2/La89uvtV/vLRguHLsxdHPk1vTt73emi77enSmeLpksnbo3dn/wwdDDnrK28sZHtRWPHpdUXqxKfxJVHfh0b41F7fZnss+Jz5defPynqe5hfcbL4Aa7RrUmwSZGc8+rhy0Jr11axVpH3zxoO/7WpB3X3v/uaod/p0rnaldLd8b7fT0yPbO9lX0x/RYDpIGBD7c+hgxqD6GHmj6dG94/IjUyNVo5Fv155zj3eP/E9UnKlOrU2pfGr+nTe7+Jf5v6/mAmYtZsjjjX/aNgnrqguYhafLmU9nPvstjyl5Xy1ag1cwYPgwEAJxFhyHCUNqoSfZxJj6mGORpzisWUpY41ju00ewJ2J7aZIxmXjE8h7Ca0cqYS07kySBnc9tzveLJ4s/jO8+cI5Armbroo5CrUL3xF5Co5TzRvc57YNfHrEgWShVI3pG/K3JL1k52Quy1fpHBXsVipRLl0y72t91UebHuoWq5Wrl6uEaaxqFmpValdtf2JTrXuCd01vRr9WoNnhs+NXhjHmqBN6kzrzV7uaDBv3NlkkWiJtXy1q8Xq9e5W61Qbgk2b7Vu7dvt3ezodshx5HLucup3fu/TszXUVdO3b17//g9vHAx/d8w6KHhzy+OQ57DXiXegjuZ4g/hMBdyjylKn/lCKzv1Ok4qjG0aXwn8eWI1aOr55Yi2REQwzyd5JgzmDiWeIbE3Ymsidhk7EpHGfxqYQ0zt9ZwpPNe57vV5Zs+jtL8oeueVwXKxAvlLwhuZEmRfJ3FYoV/8oSlbJt5aqP1CvUH2tUalZpP9Gu3v5Ut0b3rxwxqTd9adpg1rijybzZ4lXo682tVm+s26zf2rQf75DtdOhy7I7pUep16YsbUPkQP6g6lDTsOao9ljbuN+n/hTJN/Z4w5zJ/dilx1ZbBAFg/+wAAmNUAsuQAHHIA7PIB4uQApNwAeG4CWHMA2GsCkkkYkDo0QOzU2Tg/AAEEEAJFMARnCIFUKIVFBBlhgQhD3ES8Rowh8UgzZDSyGrmC0kFFo+pRK2hRtDO6EP2DyZTpFFMJ0zSzGXMe8yiGG+OKqWbBsGiyxLJMsmqxUllr2RTYotgq2HHs0ezvsSRsEPYzhwnHSY5BnDvuOR6F98ZPEWwIWYRVznjOGaIWsYBLnauAa5rkRlrg9uMu55HjecnrzYfhu80vwX+Ef07gkqCZ4Oymq0LiQhHCCOEyEX+yKLlH9NzmzZujxPBireJpEnskBSSHpO5IG0nfkjGU5ZQdlHsgf1rBVVFFCas0pvzPlvytMSqe28xU5dW41FbURzWyNXGatVql2nnbz+mc0Y3UO6J/yIBi6Gfka+xrEmAaZEbfccw8dudZi1zLW7sqrBp391l/t8XYCdtr7LFzoDmmOBU7v3GZdeXbp7vf2y31QJX7Zw9eTzOvo95Ffnz+1gEJlLogJNWAFn3oRQgz3eJwepj4UWr4kwi24y4niiIZ0faxyFOucY/OcMUfSmhLzkxZSnVLq89QOpeTHXL+U45dbt3l4qsSeZeu8RYSbqTcwt0+eze7RKj0+n2FMuPytgr3x9+reZ8W1Rq+oNfh64sadjYntCi8bnsT2l7fQesS7G7ok+zv/pAwqDdcNOr5WWS854vDNM+3rpmcObeFqaWy5UgGH4MBAEhgA16QAT1wgsOQCRUwgMAglBFuiBREDWIWKYt0Q+Yg36HwqF2oJFQLmgO9G52J7mUiM/kxlTItMhsxn2V+j5HAHMa8YCGyeLJUsLKzurIWs6HZ9rM9ZGdj92CvwXJjadgWDlmOZI4pnCWuBM+Bp+I7CfqE65w4zlDOXqIp8R4XmSuda40UQvrC7c89wUPhmeGl887zhfMj+JMEBARuC2oK1m9y2DQuFCXML1wuYiMyQY4TlRRt2Bwkxiv2VNxDAivxTDJISkTqrXS8jKHMqmyVXIS8jvyCQo3iGSV7ZVHl6S01W9NU/LcZqwqrLqt1qD/WuKQZreWj7bhdR0dJV1SPqI82QBnMGH43mjaeNBk1nTWb3PFjJ9KCZMm7a4uV7u7d1rY2AbZH7XLt7+955dDruOJMclHaa+V6aN+F/XVuY+6sB5U9fD1zvGq8v/nK+Hn5Zwd0BAoG7aHm0j4HS4eE0htDhY6EhDWFix1LiZg44RzZEK0WUxBLPJVymngmK4EvMTdZNeV1qlfaz4zkTPWskfOXc/wv7rksc5Upb+ra84KyGxduxd3xuOtaYnpP48G2MsVHCo+lqySqpWuUn+m92FFn85LSeKg5reVq65O2gXZGp0i3To9nX+JA5cepT/wjhmNR4zcnh78KfPOeuTw3uiC9FLRcvoZgMACAGQggBIbgDKlQCm837G+4X1ePxqOd0T+YTJlyfnlfw7iyiLDEskyy2rPWsimwXWTHsUezL2CDsJ85PHHuuE94b/wUIYSwyhlP5CEWcKlzNZHcSAvcqb9NW/HP/fJsLYwQLvtl2WZd8i/HoTKGfxv+I/iX37eatVqlf+z+kfvfu/2f1PoM+vH5W/9bbWjPv93G3P5bbtLWP3KzmDfsXtLc0Hs9Y8NvEXFD8IOKDcNVJ9cVP+vZcNw43pzw6p+WrNdtb0LfCrXXd9A6S7viuht6Qvsk+wMGjD8kDOoNnf50cLhoZH60/bPIeMCE+aT0FOaLw9fC6bhvPt93zMjOss9+nXvz48F81oL9wtRi7JLhT6mfo8uRK3wrl1c5V2NXF9auMxIZDID1+xIAALAZUSnUYLKlkTH8/1Yg5fDGHEgAwHoF7bEDACIASPvRze0BgAQAWmAEVKAAFYKBDJZgBMa/nmTw+P3FD2D9LgcAwEwAuOgIAFCzeCzq3/PSvcLoAABGVNrRYD8fXzrZgEajeJGNqIG0w3SvYHmyeZCHojx5q7KyKgDAfwBYjP/gNJJdnQAAAARnQU1BAADY6/UcFKoAAAAgY0hSTQAAbZgAAHOOAADeVAAAgmQAAHjTAADDvAAAMucAABx04zkiNwAACnFJREFUeNrsnHts1FUWxz+/32/enemL0sLQ0kIfUh5ioQiCQGtFRNmCWElFWFwDEohgQNmwJVAx+pcEWERJLFZFDQ93eSgiAtsl8iyV1LYLpaWtpVBK2Q6lj5npvH6zf7QMjFOUxXUTy++bTGZy55x7z9w53zn3nHMzgtfr9aJAgYJuofo1yuXldaxZ8zEej0zv3qGsXbsQg0HL9u0F7NjxTwDS01NYsmSGstMK7j+CtLfbKSmpRpZloqN74/HIANTXN3Hy5FkkSSQmJkrZZQX3J0FEUUCrVSPLXtTqW1PFxvYhLe0hRFEiObm/sssK7k+C3AlZWRPIypqg7K6CnkmQ8vI6jhz5gZqaBjwemX79evHww4MYM2YIarX0i5NWV1+hqqoeALM5gmHDBgBQUlJNWVkNXi+MHp1MbGwUu3cfpbi4GpfLTXx8X6ZMGc3AgX395jt1qpyqqssApKWlEBxsYM+eo5SV1QKQmNiPp54aQ3R0RLf2uFweTp06y4kTZ6mvtxAcbGDo0DgefzyViIhgP9mqqnqf7QMHmklKiubs2Vr27j1Oc3M7K/+STWhHIdhugCB2vwFeGdRGiJkEolrxsp5CEJfLw7p1O9m27R+0t9vxeGQ8HhmNRkV+/n5GjnyAN998ibi47vMKQeh8/vLL46xduwNJkpg+fTwbN74CwOHDZ1i//gtEUWT+/KnU1l7l0KHvAdBoVEiSyNat37J8eTZZWRN98+7efYzPPz+IWq1iyZIZFBaWc+LE2QC93Ny5TJqU6mdTXd01cnM/5tSpszidLlwuD5IkIkkieXn7eOONFxk//kGf/J49x9iw4W8AvPbaTMrLzeTmfkR7ux2tXseSRZMJPf4qNJyH238rhK4HgAcINcPsMtCGK17WUwjyzjvbyc/fT1CQjtBQI6mpgzAYdBQXV2CxtFFYeI6lSzexdWsOJpP+jpNqNGqCgw2AgF6vvW1chcmkJyhIz969x7Ba7aSlPURUVDjl5bVcvHiVjg4na9Z8TEREKGlpwwHQ6dSYTAaMRh2ffnoQh8PFpEmphIQYKSur5upVC62tNlas+ICIiFBSUhIAaGpqZdGi9Vy4cBmNRsWgQfEkJfWnoaGJ0tJqrl69ztKl7/Hhh39m+PB4n+0mkx6tVsOZMxfYvr2gkxxaNSqpixHGEDAZQKXrSsYk8AKO64AIHhdIkuJdPYkgJSXV7NhRgNGoRxQF3n57HpMnjwKgtraR+fPfoa6ukaKi8+za9R1z507+VQvb7U4WL36WRYumAWCzOVi27H2OHy9Flr1s2fK1jyA3Icte3G6ZlSvnMGtWBgDXr7fxyisbKSurwmZz8dFHB0hJ6YxYmzfv9ZFjxoyJrF79RySp81i0adNuNm/ei9XawaZNe8jLe81vLbVaorS0Go1GxUsvPcUjjwxGlr2E946EJ/eBx9EZMgSh8xh1+EX48evOqOIGBk5TokcPgO8QfeDAaTo6nLhcbjIyUn3kAIiLi2LhwmlkZIwkM3OcX8XqXuB0uhk8OJZ58572jRkMWl599VkMBh1qtYqKiotUV1/5iZ6LUaMG+cgBEB5uYvHiZxBFEa1Www8/VHL9ehs2m4MjR4rRaFSEhZlYsOAPPnIAzJ07mZiYSFQqkeLiSl/ecTsZvV6ZnJzZ5OS8QHp6ChkZIwgyGkAXAUH9IMgMhr5QtrmLHBI4PDDoGZiwQfGunhRBzp+/hEolIcteRo16IEBwxozxzJgx/n+yqMvlZtiwAWg0/kRLSOiH2RxBVdVlXC43dXWNxMebfe+73R5GjEgMmG/w4FgiI8O4dq2ZlhYrjY3NSJKAxdKKWq3C7fbw1lufBujZbB1IkoTV2kFFxSUSEvr55WOxsX2YMuXhn/8wJX+FE6tBJYLTA3ETYdJW/BMUBb9rgng8MnZ7B6IoIIoCvXoF/8bLejGZDAGjarVEUJDeR4bWVluATHBwUMBYUJAOrVbti052uwNBEHA4XBiNOhwOFwcPFvHTWzU6nRZRhI4OJ42NzX7veTweoqMj/XKoAFTthGPLOsnhliFqKEzeBiqj4lk9iSCSJKLRqJFlkGUZi6U1QLClxUp9fVNnjmrU079/5K9YVuDGDWu35Vir1d5pmErCYAh0zhs32gLGrNYOHA5XF8lUaLVq37PT6SYiIoS1axd2fUbZp6fValCpJJxON9HRvbstNtwRlwvg8J/g5nwhMTDli84jl4Ked8RKSDBTWHgOlUqiqKiCmTPT/ATz8/fzwQf7AC+zZk1i1ao597yoWq2itLQam83hR4Iff2zgypUmJElCq5WIje3jb2yXbV6vF+FmTRmoqLiExdKCIAiYTHqiosLR6dT06hXMtWvN2O0OBgwwB5Sna2oasFhakSQxoB/ys7CUwLfZ4LJ1lnZ14fD0bggdpHhUT03Sp04di0ajQq1WUVBwhq++OukTKiqqYPfuo77k/Pa+wb1Ao1FRWXmJd9/dhdvt8VWj1q37AputA5fLTVJSf5KSov30tFoNxcWV5OV97Ru7csXChg1/x+Vy43A4efDBeCIigjEa9UycOByn001bm42NG3fR1mb36R05UsLs2W8xc+Yb5OTkIct3eanZWg/7n4P2f3cm5YIIo9+EsEFgvXLbox7cVsXDekoEGTEikdmznyAvbx8Gg47c3Hy2bStApRKpqKjDbndis3WQmfloQPn1XmA06snP38/Ro6VERYVTW9vAtWvNiKIIyLz88tRu9QwGHevX7+SbbwoJDw/mwoVLNDe3IQgiBoOa+fNv6S1YkElhYTlVVfUcOnSasrJq+vePwmq1U1l5CbvdiU6nYdmy57o9znV/tPoOLBdAowZkECT4/m0oXP2TUl0bpL0Pg+cpXtYTCAKwfHk2JpOBzz47iMXSysmT/+JmjmI06snOzmDFiudvS2RlX8fdZgvyJcFOp4vWVhuSJGG3OwIWdTicTJ06DoNByyefHKC0tMbXEe/VK5jXX8/uloQOh5Pnn3+clhYbO3cW4PHI6PUaAMzmXqxcOcfXJASIigrjvfeWsmbNJ5w+fY6amltXYDQaFVFRYSxZ8ixTpoy+5ddOF21tdkRR9OVD/umTt7NT7nTd3AXoaAiUcwIuJYL0KIKIosCiRdPIzBzHsWOlXLzYCECfPuGkpj7AkCFxfsqJidFs3ry0qyKk8VV8MjPHkZwciyAImM2B96Pcbhm9Xs2qVXPIyBhBYeE57HYnMTGRpKen3PFOldvtISQkiJycF3jyyVTOnKnE6XQzcGBfHntsBJGRoQE6cXFRbNnyOkVFFZSWVtPU1IJGoyIxMZqxY4fSu3eIn/z06Y8ydOgABEEgMjIs0AjzeJi24873sHy/Hk7oM1rxsJ5EkJuIjo4gO/uxX1QOCzMG3H0CiI83+/UvuvUfT2e0GTt2CGPHDrlrg29WodLTU0hPT7krHUkSGTMmmTFjkn9RNiGhn18/JPBsGAMJMYrn3G9JugIFCu4ygvxWcDrdWK0O3+v/Tq/jv9ZToOB3RZAnnhhFTEwkoigwYMDdN9SysiYwcmQisuwlOTlW+dYU/N8gKP9qokDBnfGfAQA9nOAwz2UemwAAAABJRU5ErkJgggo=';
325 //background_image_url = base_image_url + 'background.png';
326 background_image_url = 'data:image/png;charset=utf-8;base64,iVBORw0KGgoAAAANSUhEUgAAASwAAAGlCAYAAABAwstlAAANMWlDQ1BJQ0MgUHJvZmlsZQAAeJyV13k0lG0fB/DfLIxlzDDGHkb2XWQPWSJL9mwpMXbDTAyplCUpRJZQtKBoU5RIJKqHLAnJklBUZCmFSJZ5/5Dqfc553ue81x/3+d2/+9znuu77nM/3OhcAXsuTRqMgASA4hB5qb2ZEcnF1I2F6AAM44AMsiHqSw2iGtrZW8I9jvgcQAABdip40GiUc3ZFJftCtapBvLz7n36D0z+8BAAAu1MXVDQChAABEv7V6KwAQvdZqRwAg7qfT6AAIfwAgkv09vQEQUQCgEOpobwyAuAoAOL+1ugoAcF5rdRMA4CLIfnQARB8AMyHEOyAEADMFwKzv7RNGBsApAIC3dxg5GACXBgDWwcFUbwDcWwCQIdNC6QB4FgBQdHF1I60teVcSwGYBABbL3739WQAVBQAyO373xO8B8HoCFKb87s3aAwIAELztYb5qqgAAgMAaATANMRizUgCYDICVdAZjqZDBWLkEgBoAqKeQw0Mjfv4vBKIN4N/u177550AhAJAACAlEMfIgKgodxXSEOQYTx3KU1YS1ge04+wlsIsdJXCWnP1c6IZ07g3iaJ4s3iy+Hv0GQKpS3IU/4vEgTKVyscOMl8XbJQ1LF0p2yR+RuyPcoxindVO7fdFz1jtob9ZMalZrD2qk61bqjepn6Dw0mDLONHht/3pZr2mg2Y37RosVyfkeh9XObDtsOu077ZcfrO7udepx7Xfrc0Ltuuw/sHtwz5PFm71svLPm+93ufD76jfmP+HwPGg3goj4I/hXymTtO+7PsaOhM2R58L/xYxv38h8vuBxYM/Di1HLR9eiZaN6Y5DHEXGo46hE5iOM5/AJLIksSaznWRPwaZynMKl4dM5M7gyCae5s4jZPDm8Z/jO8ucK5AmeEzq/4YLwRZF80QJSodiljZfFiySKJa9IX5W+JnNd9obcjckSyk2FW4qlymUqtzfd2VSuendzhXqlRuX8vYgqzfta1To1ug+21G55qPdwtS663uDR1seGT4z+Mm5AN8Q3bntq2mTWbN5i3srWmvzMss3quXU7rv1Uh22n3Qv7LkJXxkuHbseenb28vTl9zq9c+t1eC77OG3AfdB/a/UbkzcW3HsN7R8RGCt95vSd/8B6VHC0e8/3oN+4/ITtxfTJwKugT5bPi51vTIV+oX2kzm2buzIbOhX2jz6vPVy5EfI9cPPDjwJLOUs3yoZWoVb3VhwwGAEIciUN+QbWibzBlMkdh/FgcWY3ZNrNLY6U5+HF8eH5Ofi4eghS3DFGLx4p3D18Yf6pAqWCr0Lgwt4iGqB/pjNhTcYSEnuQ+qdvS07IychT5GkWUkqFyusqwqqxawuZeDTlNmlaDDp9u5JZn+rwG1K2PjSSMD5l0moqYRW6vNV+03GTlsyPLutMWZ2dmH+lQ5PjSic15q8s+1/Nujbumd4vusfE4uLfQs8Fr3JvHx8DXxe+If35AfeBg0GIwd4g81YTmvy8qNC2skF4R3hTxev9E5PxB1CGuKNJhhSPq0VtjLGNt4nYd3Rvvc4ySQD8eeiImMSbpaHLiyYyU5NTcU2fTctLTM85lZpzOzjqTfTXnyplbZ6/m3sgrPffg/IMLDRef5XcWdBV2Xeq6/LroffHYlZGrH65NX/96Y7rk882ZW9Olk2VTt8fuDJeP3O2v6Kxsvldfde9+afW5mowHMbXBD3fVWdZveST3mPB48cnbv1oa7jZmPg1tcmjWaBFqYbT2P7vblvTcrV28fbSjvPPwi21duK7Bl/ndgT1qPSu9bX2Zr3b3y/bPvq4eiBu0HCIODb259jZsWHcEPdLy7vT7PR+kP0yNVo/FfrQY5xkfnLg8SZlSn1r91Pw5Y3rXF4kvU1/LZ6JmzeYIc33fiuapC9rfUd+fLqb/2LUkvvRpuXIlZtWcwctgAMBRRCTyIEoXVY0+zGTAVMcciznGYsrSwJrAdpw9CWuBbeVIwaXgUzltONu50ggZ3JnETB5Hnpe82XzZ/GcEcgXzhPI2nBN2Fx4UuSiaTyoQK9hYIH5J4rJkkVSx9BWZq7LX5ALkJuSvK5Qo3lS6pVyqUrbptuodtfLNd9UrNSo1K7Uitb5rV+tU69ZseaBXq39Ef9Wgbmu94SOjx8ZPTOK3obc1mDaaPd3eZN5s0WKZbIW1erajzfq5Tbttmh2nXaf9C4cux5c7e5yynXmde136XF+59e/KcxdyH9g9uOeNx9u9bz0LvMS8RsjvvN/7fPAt9pNaS5DAiaAbFAXK1H+lyOyvFKk6oHVg8eCPQ0tRy4dXjqxGM2IhDvkrSTAnMIksic1JFsnsJ7Ep2FSOU/g0znSuX1nCm8N3hv9nlmz4M0sKRy6RL4sXSRRLXZFaT5MShZuKt5T+yBK1is2V6vc0qzTva1Vr1+g+0K3d8lC/Tv+PHNnWaPrUtMmseXuLeavls4jnG9utO2w7bV/YdR3ulutx6nXui+tXfu02kDCk9iZxWH3k5HvvUd2x9PGAycBPlGnq16Q5t/lTi8kr9gwGwNreBwDArAGQLQ/glAvgUAiQIA8g7QHAexXAlgPAURuQTCKA1KMBwkJvff8ABHCCMCiBEbhCGKRBGXxHkBCWiEjEVcRzxBgSjzRDxiJrkcsoPVQsqhG1jBZDu6KL0d+YTJmOMZUyTTObMRcwj2J4MO6YWhYMizZLPMskqw4rlbWeTZEthq2KHccey/4KS8SGYD9ybOM4yjGM88Q9xqPwvvgpTjvObM4VrkSuGYIOoYhbk7uIe5roQVzgCeCp5JXnfcrny4/hvy4gKbBfYE7wvJCZ0OyGfGEJ4SgRhEiFaCBJjNQvdnrjxo0x4njxdol0yZ1SglIj0jdkjGWuyRrJcckNy5crHFd0V1JTxiqPqfy1qVA1Ts17s5m6gga3xrLmqFaONk67XqdMt2DLab0T+tEG+7fuM6QYBRj7m/hvCzINMaNvP2Qeb3HKMs/q2o4q62abAduv9hgHEUetnQ5ONOdUl1uuHW6z7vy79ff4eqTtrfH8SObzNvM54FsSwB9oG5REaQhBUg1psfuehDHTLcMzIiUOUA8+iGI77HakJJoR6xiPPOaecO8Ed+K+pM6UrNTFNI/0xkzl07k5YWfe5TrkNVy4lS9ZcP4SXzHnldRruOunbuaUCpddvqNYYVLZWeV5/2st38OSeqMn9AZ8Y0mTRWtSm+Lzzo6IrsZuWq9QX9OA1GDfm6Rhg/clo94fRcf7PzlN837pncmd81iYWqxYimbwMxgAgAQ24ANZMAAXCIcsqIIhBAahgvBApCLqELNIOaQHMhf5EoVH7UCdRLWhOdA26Cz0ayYSUwBTGdN3ZmPmU8yvMJKYcMwTFgKLN0sVKzurO+stNjTbHra77GzsZPY6LA+Whm3jkONI4ZjCWeFK8Rx4Kr6HcyvnZS4cVwTXa4Ip4TY3iTuDe5UYRvzEE8gzwUvhneGj883zHxRACJwUFBS8LqQt1LjBacO4cIyIgEilqJ3oBClBTEqsaWOIOJ/4QwmyJFbykVSItKj0C5lEWSPZFbka+SgFPYUFxTqlE8qOKmIq05vqVNPVAjebqIuoL2l0a97XOq8dq+On67xFT09ZX8yAsBVtiDKcMfpqPG0yuW3UdNZscvs3C6Ql0YpvxyZrfRsbW3u7IPsDDnmOd3Y+c3rtvOxKdFPeZe2+b/fZPQ0eY56sXipkf+9cnzrfL/6yAT6BOUHdwUIhO6l5tI+hMmER9OYI4f1hkS0HxQ+lRk0ccY1uitWIK4onHEs9TjiRncSfnJeinvo8zSf9R2ZKlmb2hzMXcgPP7bwgm89UMHXpcVHFlbPXEm6Qb7qXmt7WKt9coXRP8b5MjWStTJ3KI4Mn2xvsnlKa97Wmt+W3P+gc6mL0iPbp9XsPJA9Vv516J/DBaCxm/Ork+8+CX3xnLsyNLsgshixVriIYDABgBk4QBiNwhTQogxfr9tfdr6lH49Gu6G9Mpky5P72vYtxZRFniWSZZHVnr2RTZzrHj2GPZF7Ah2I8c3jhP3Du8L36KM4xzhSuRwEso4tbkbiF6EBd40n6ZthaY++nZVgQhUvHTst2a5J+OI2SN/jT8W/BPvy+063XKftv9Lfef3f4vtX7DAfyBtn9XG9H/d7dx1/+Ue1L1t9xs5nW757XX9V7OXPdbQlgXXF61brjm6JriR/3rjpvHW5Oe/dWW/byzI+KFcFdjN62nrDehr6k/YkBqMGjI5E3SsMHI8Xde70s+zI92fRQdD5own5SZwnxy+lw8nfDF7+v2GblZ9tnPcx3fyuezFxwXpr7HLxr9kP4xuhS9zL98YYVrJX5lYfUyI5nBAFg7LwEAAJsxlUINJVkZm/zL4e7/HcGU8PU5kACA9QnZ6QAABACQCaCbOwIAEQB0wBioQAEqhAIJrMAYTH5eSUD+9SQAYO0sBwDAzAlwzhkAoO77oZi/z0v3iaQDABhTaQdCA/z86SRDGo3iQzKmBtPC6T6hCiTzELKSAklVRUUdAOA/67wHk5DqTvYAAA7ISURBVHic7d1NjNz3Xcfx78w+2Y7tJo5rjEOVh6YoNaWAcqgSIiFURYVWEEJIT9wRF4SK4AZCQoJLIwWJCxcuHCo1TaJIqE3CgyrIg+K2qKVpm0DzUMWpHSdO4ti7ftjdGQ6zf+9//95N7Zm1vZ/k9ZL+mp3Z2ZnxYd/6/n7z33EVAAAAAAAAAAAAAABsJb0P2fMCm2d4pZ/wSoSj+xy9DW7f6P7A1deN00bXL2vELlccuo/bX7mtHavu9cv5eoDJDda5Pqy1sepe31SbHYj247Uj1V/nst/6md4GjwFsDetFqTkGrWO9729auKY364HqwumpX1VTtRqnqc71dtDWm7aAq2/Y+bq53o7Ucufr5noTs+7jjG2zgtVEph2n5uuZqpo6cOCOj+39yK2fn5nZ8dler39Tr9ff1+v1rtmk5weukOFwOD8cDo4NB4OfnFta+Pe33n3x8SNHDh2uUagWazVayzVqQzdeY9uMaaY9ITWxml45Zm644c4b9u05+Bcz03NfrOpNbcLzAVvKcHlx8czXjh7//pePHDn0eo2itdQ6lmvt0nFskwarvYxrh2q6quYO3vrFz+/c+dG/r15v54TPA2xxw+Fw/uTJo1964aWHH6+qszUKV3O0l41jLw8nmXg2itVMVW3/9ME//KPt26//cq/Xm5vgOYAQvV5vdnZ21xf2XPfx08feev75zrc3ZQ9rkgmrvQxsQjVTVdtu+/h9X9i1a/8/9nq9NY9/8y37655776zP3HFb7d+/p3bs0DJIs7Bwto4efbuee/aFeuzRZ+qVl4+u+f5wWIMTJ177k/995bFvVNWZGk1bZ2t1edhMW5ds3GB196xmaxSruX37fu2mGw/c+a/tDfXp6an60z/7/brv/ruq3++v/4hAnMFgUA8/9FQ9+MAjtbS0fP724XA4//Jr3/zd48d/8GqNonWmqs7V6r7WWPtZ4y4Jm2A1pyrM1Cha2z9x02//1fT07K82d5yenqoH/+GP6+7P3V6dgQsI1+v16pc+dWN9+lduricf/04NBsPm9tkd266/9o03v/eftbpv1d58rxpjmThJsJpTF2aqaq6q5vbu/eWb9u659e+qeufHqC/9+R/U3Z+7fcynARLccMPe2r17Rz3z9A/P3zY9PfuJhbMnvnHmzPH3au27hGOf4jDO+qx7GkOz2T67b89tv9U+deHmW/bXffffNc7rAsLcd/9ddfMt+1u39Kb2XX/w7qraXqvbRu1zNC95yTXJhlL77PWZqpqdm939G+073HPvnfas4EOi3+/XPffeuea27XPX/XqNVmCztTrcTNWFf5J3cc8x5mtb7x3CuX5/+hfad/rMHbeN+fBAou7vfH9q5kBVbatRsGZr7YR1ycYNVvtPcM4vCfv9qb3tO+3fv2fMhwcSdX/np3pT19dowmpOe2omrO4nuFyUcfewmssmXNNVNdPr9be37+g8K/hw6f7O9/pTzXTV7F+NHauqyZaE7T2sZsoC6Gomq+a4Ypvu3Y+D6XcOgK7uR0t1+3HRJt10735CA0BX+93Bsaerqsmmom4lncYOrGe9yeqKB6vqwkkLoGviUDUmnbAAfpaN3hG8ome6t1+ICQvYyHr/W9ZVWRIC/CybthoTLCDGJKc1AIzrii4Ju2tRAQPez0a9uGJ/Swhwsd6vGxfdFHtYQAzBAmIIFhBDsIAYggXEECwghmABMQQLiCFYQAzBAmIIFhBDsIAYggXEECwghmABMQQLiCFYQAzBAmIIFhBDsIAYggXEECwghmABMQQLiCFYQAzBAmIIFhBDsIAYggXEECwghmABMQQLiCFYQAzBAmIIFhBDsIAYggXEECwghmABMQQLiCFYQAzBAmIIFhBDsIAYggXEECwghmABMQQLiCFYQAzBAmIIFhBDsIAYggXEECwghmABMQQLiCFYQAzBAmIIFhBDsIAYggXEECwghmABMQQLiCFYQAzBAmIIFhBDsIAYggXEECwghmABMQQLiCFYQAzBAmIIFhBDsIAYggXEECwghmABMQQLiCFYQAzBAmIIFhBDsIAYggXEECwghmABMQQLiCFYQAzBAmIIFhBDsIAYggXEECwghmABMQQLiCFYQAzBAmIIFhBDsIAYggXEECwghmABMQQLiCFYQAzBAmIIFhBDsIAYggXEECwghmABMQQLiCFYQAzBAmIIFhBDsIAYggXEECwghmABMQQLiCFYQAzBAmIIFhBDsIAYggXEECwghmABMQQLiCFYQAzBAmIIFhBDsIAYggXEECwghmABMQQLiCFYQAzBAmIIFhBDsIAYggXEECwghmABMQQLiCFYQAzBAmIIFhBDsIAYggXEECwghmABMQQLiCFYQAzBAmIIFhBDsIAYggXEECwghmABMQQLiCFYQAzBAmIIFhBDsIAYggXEECwghmABMQQLiCFYQAzBAmIIFhBDsIAYggXEECwghmABMQQLiCFYQAzBAmIIFhBDsIAYggXEECwghmABMQQLiCFYQAzBAmIIFhBDsIAYggXEECwghmABMQQLiCFYQAzBAmIIFhBDsIAYggXEECwghmABMQQLiCFYQAzBAmIIFhBDsIAYggXEECwghmABMQQLiCFYQAzBAmIIFhBDsIAYggXEECwghmABMQQLiCFYQAzBAmIIFhBDsIAYggXEECwghmABMQQLiCFYQAzBAmIIFhBDsIAYggXEECwghmABMQQLiCFYQAzBAmIIFhBDsIAYggXEECwghmABMQQLiCFYQAzBAmIIFhBDsIAYggXEECwghmABMQQLiCFYQAzBAmIIFhBDsIAYggXEECwghmABMQQLiCFYQAzBAmIIFhBDsIAYggXEECwghmABMQQLiCFYQAzBAmIIFhBDsIAYggXEECwghmABMQQLiCFYQAzBAmIIFhBDsIAYggXEECwghmABMQQLiCFYQAzBAmIIFhBDsIAYggXEECwghmABMQQLiCFYQAzBAmIIFhBDsIAYggXEECwghmABMQQLiCFYQAzBAmIIFhBDsIAYggXEECwghmABMQQLiCFYQAzBAmIIFhBDsIAYggXEECwghmABMQQLiCFYQAzBAmIIFhBDsIAYggXEECwghmABMQQLiCFYQAzBAmIIFhBDsIAYggXEECwghmABMQQLiCFYQAzBAmIIFhBDsIAYggXEECwghmABMQQLiCFYQAzBAmIIFhBDsIAYggXEmCRYw84BsJFN6cU4wRIo4FJ1mzF8n+9taNwJS7CAzXBJLbGHBcTYzGCZuoD1bFobNnXCGg6Wz7SvLyyc3cyHB7a47u/8YLB8trZQsAY1ejGDqhouD5beaX/z6NG3J3x4IEn3d355sHhi5cvmzbpBTfDG3STBGrReSFXVcHn53BvtOzz37AsTPDyQpvs7v7R05q26MFLdy4u2GUvCwcqxPL9w7L/b33js0WdqMBis/1PAB8pgMKjHHn1mzW2n5o8+X1XLreOKnofVPflr0D6OvvU/h4bD4flCvfLy0Xr4oafGfW1AkIcfeqpeefno+evD4XBw7Pj3v1udTrSOS47XJOdhtZ94qaqWTp16/Y35hWNPt+/44AOP1LcOvTjm0wAJvnXoxXrwgUfW3HZq/si35+ffOFYrfajVKasdrEsyNebr61fV9MrPz6wcs1U1d/rsu0f2XveLv9nr9aerqgaDYT35+Hdq9+4d9cmDH6terzfmUwJbzWAwqK999b/qr//yn2tpabl1+/LZH7/6xD8tLs6/XVWnqmqhqs5U1dmqOldVi7Uar4s2TrB6K0d/5ZiqUbxmq2rm3LmTg15v+p1dOw/c3utVb/Tih/XM0z+s//i379bi4nJds3Nbzc3N1szM9BhPD1xNCwtn67XX3qzHv/7t+tu/+Up9/V8O1WCwOiwNh8Ph60cOfeWdd//vxaqabx1nVo52sC5pyhpn3OnV6mQ1W1XbqmpnVe2qqo9U1bVVteeWGz/7O9dfd9vv9YxU8KExHA6Hbx7/wROvvvbNJ6vqnap6d+XyRFW9V6NJ63SNJq1mmXjR0Rp3wqoaTVdNvJpjujneOfHK4RrU8Z07f/6TzfIQ+OAaDJbOHf7pcw8fPvLsszVaBp6q1emqvSRcrFGsmr2sizbuHlbV6rKwuZyq1YD1q6p/cv6nx989+ZPnt81du3N2dtfPmbbgg2c4HA7eO3n4+R+/+sRX3z3x0ks1CtXJ1uXCytGOVROsSzJuQJowNRPVtqrasXLsWjl2ty6v2b597/6P7jn4qd07D9w6PbP9uumpuWv6/emZMZ8fuEoGg6XFpeWz84uLp0+cPHX45Tff/tGPTp8+/maNlnpNqN5rHfMrtzVLwXO19rysizZJsLob7ttWjmtqtKe1s1ZitfL19pVjbuX+zbuMzZRW5dMjYCtqn5nenNK0XKNpabFGETpTq0u/9nTVLAtP1yhUzZQ11qkN4+4tNS+613rh7eVhr/WPa8a/syvHbK0Ga7rzc1XjRxS4fAaty2Y6WqrR736zN7VQq9NU83V7qmqfyjDWeViTboZ3a9trHe1gnavRP+p0rR+s9pQlWLD1dKerQY1+55upqZmymv2qM63Lc7X6juBYoWpMEqzmxW/0vabCzT/qdI2WjLM1OiWiWU62gyVWsDW1/ySv2TBvJqxmgmomrTO19iTRJljt0xjGitZmTVhVo9gsdm5vV3i2RtGaqbXTVfPuYjtW9rLg6lvv0xWaCamJTxOi9v5Uc9nEqrnfRB8tUzV5sKounLQWa+3oOFOre1hNrJrztjaarkxacPWtF5b23xA3IWoum32q9qkL7VhNtBys2pxgNdqbcu1gNWNjO1TN0d5sb09VggVbR3sqan7P25vn3T9ubp9n1XSgasJYVW1+GLonk645kbTWn6zaobIUhK2ne1pD1doYtb9u9qgm+hiZjVyOSaZ7TlW/Llz6rffOoKkKtrbup4a2V1ODdW6rWrtdNLHLGYn1YtTdrxIqyNKelNofk77esemuVCy6z7NRqMQLtq71/vfmsf4H53FttUBstdcD+D9HAQAAAAAAAAAAAAAAIN3/A/PNWgCA/F3MAAAAAElFTkSuQmCCCg==';
327 //close_image_url = base_image_url + 'close.png';
328 close_image_url = 'data:image/png;charset=utf-8;base64,iVBORw0KGgoAAAANSUhEUgAAABEAAAARCAIAAAC0D9CtAAAABGdBTUEAANbY1E9YMgAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAGiSURBVHjaYvz//z8DiYAFU+jhg5cXLtx9/+4LLy+nlpa8hpYsIyMjTj03rj/u71l74fxdZEEFRfG8wkBrG224CCPcbfv2XKivWfjr1x+s7snM8U1IcoOwmeA24NEABNOnbN698yyKHqCTIBrcPU2WrKiIjHYEsh2c9BctK0tMcYeomdC37sePXyAW0G0P7r8wM8yBoFs3n/wHgwP7L/79+xfI+Pnzl6VpHkR27+7zQBGQPcie3rr5JIRh76DHxASS3bHtzN8//yCCF87fgbrt/fsvcD3Ll+4/eOASnPvg/suO1hVwLjACoHqA8QAXBfrB1k4HOaDjEl3hXF4+LqgeYMTBRZNS3CFOAtoAEUlIdGNmgQaVlrYcVA8wpoHmQUT377v469fvTRuOR4W1zZi25cf3X6DAAPuHi4vd1l4XEadHj1wtypsB0QY0Fe5pZHZOvn9svAsifoBJAxjTEDZcETLbw8s0Js4ZPe0AATCmgRH35vUn5BQAdFJSqgdQAzylMqLlBWBMHztyDRgPoHTNxwX0NNAP/PzcyGoYycg/AAEGABYVzxqE3YcJAAAAAElFTkSuQmCCCg==';
329
330 //newDiv.parentNode.removeChild(newDiv);
331 newDiv = document.createElement('div');
332 newDiv.setAttribute('id', 'clipperz_bookmarklet');
333 //newDiv.setAttribute('style', 'width:270px; height:400px; padding:20px 0px 0px 20px; margin:0px; border:0px; background-color:transparent; background-repeat:no-repeat; position:absolute; z-index:20000; top:40px; left:40px; background-image:url(' + background_image_url + ');');
334
335 innerHTML = '';
336 innerHTML +='<style>div#ClipperzBackgroundDIV { width:290px; height:420px; padding:20px 0px 0px 20px; margin:0px; border:0px; background-color:transparent; background-repeat:no-repeat; position:absolute; z-index:20000; top:40px; left:40px; background-image:url(' + background_image_url + ') }</style>';
337 innerHTML +='<div style="border:0px; margin:0px; padding:0px; padding-left:10px;">' +
338 '<img style="padding-top:5px;" src="' + logo_image_url + '">' +
339 '<a href="javascript:closeBookmarklet();">' +
340 '<img style="padding-left:28px; padding-bottom:10px;" border=0 src="' + close_image_url + '">' +
341 '</a>' +
342 '</div>';
343
344 if ((someParameters != null) && (anException == null)) {
345 innerHTML +='<div style="width:255px; border-top:1px dotted #336;">' +
346 '<div style="line-height:10pt; margin-right:10px; margin-top:5px; padding:5px 10px; color:#666; text-align:left; font-family:sans-serif;">' +
347 '<p style="margin:0px; font-weight:bold; font-size:10pt; font-family:sans-serif;">How to add a new card or a direct login to an existing card for this website:</p>' +
348 '<ol style="padding:0px 0px 0px 20px; font-size:9pt; font-family:sans-serif;">' +
349 '<li>Copy the content of the text area below (Ctrl-C)</li>' +
350 '<li>Go to your Clipperz account</li>' +
351 '<li>Click "Add new card" or select the related card</li>' +
352 '<li>Paste the direct login configuration (Ctrl-V)</li>' +
353 '<li>Complete and review the details, then click "Save"</li>' +
354 '</ol>' +
355 '</div>' +
356 '</div>';
357 innerHTML +='<textarea id="bookmarklet_textarea" style="border:2px solid #333366; font-family:sans-serif; font-size:8pt; color:#336; width:240px; height:135px; padding:4px; background-color:white; margin:0px 10px;">' +
358 serializeJSON(someParameters) +
359 '</textarea>';
360 } else if ((someParameters == null) && (anException == null)) {
361 innerHTML += '<div>No login form has been found on the page</div><div>Get some help <a href="#">here</a></div>';
362 } else {
363 innerHTML += '<div>An error happened while processing the page</div><div>Get some help <a href="#">here</a></div><div>' + anException.name + ' - ' + anException.message + '</div>';
364 }
365
366 //newDiv.innerHTML = '<div style="width:290px; height:420px; padding:20px 0px 0px 20px; margin:0px; border:0px; background-color:transparent; background-repeat:no-repeat; position:absolute; z-index:20000; top:40px; left:40px; background-image:url(' + background_image_url + ')">' + innerHTML + '</div>';
367 newDiv.innerHTML = '<div id="ClipperzBackgroundDIV">' + innerHTML + '</div>';
368
369 document.body.appendChild(newDiv);
370
371 if ((someParameters != null) && (anException == null)) {
372 bookmarklet_textarea = document.getElementById('bookmarklet_textarea');
373 bookmarklet_textarea.focus();
374 bookmarklet_textarea.select();
375 }
376};
377
378//-----------------------------------------------------------------------------
379
380getLoginFormConfiguration = function() {
381 varparameters;
382
383 try {
384 parameters = {};
385 parameters.page = pageParameters();
386 parameters.form = formParameters(findLoginForm(document, 0));
387 parameters.version = '0.2.3';
388 logFormParameters(parameters, _cble);
389 } catch (e) {
390 //parameters = 'No login form has been found'
391 logFormParameters(parameters, e);
392 }
393};
394
395//-----------------------------------------------------------------------------
396
397getLoginFormConfiguration();
398
399
400
diff --git a/frontend/beta/js/BookmarkletHash.js b/frontend/beta/js/BookmarkletHash.js
new file mode 100644
index 0000000..19e49b7
--- a/dev/null
+++ b/frontend/beta/js/BookmarkletHash.js
@@ -0,0 +1,47 @@
1/*
2
3Copyright 2008-2011 Clipperz Srl
4
5This file is part of Clipperz's Javascript Crypto Library.
6Javascript Crypto Library provides web developers with an extensive
7and efficient set of cryptographic functions. The library aims to
8obtain maximum execution speed while preserving modularity and
9reusability.
10For further information about its features and functionalities please
11refer to http://www.clipperz.com
12
13* Javascript Crypto Library is free software: you can redistribute
14 it and/or modify it under the terms of the GNU Affero General Public
15 License as published by the Free Software Foundation, either version
16 3 of the License, or (at your option) any later version.
17
18* Javascript Crypto Library is distributed in the hope that it will
19 be useful, but WITHOUT ANY WARRANTY; without even the implied
20 warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
21 See the GNU Affero General Public License for more details.
22
23* You should have received a copy of the GNU Affero General Public
24 License along with Javascript Crypto Library. If not, see
25 <http://www.gnu.org/licenses/>.
26
27*/
28
29 //18f820faffcdb5e847d4c5d5c4a1de6743baa1a0
30 //9b30434c73fb009b15fecaa904b44f9ced807577
31 //9b30434c73fb009b15fecaa904b44f9ced807577
32 varxh;
33 vardocumentText;
34
35try {
36 xh=new XMLHttpRequest();
37} catch(e) {
38 xh=new ActiveXObject("Msxml2.XMLHTTP");
39}
40
41xh.open("GET", window.location, false);
42xh.send(null);
43
44documentText = "#####" + xh.responseText + "####";
45//documentText = document.body.innerHTML;
46
47console.log(documentText); \ No newline at end of file
diff --git a/frontend/beta/js/Bookmarklet_IE.js b/frontend/beta/js/Bookmarklet_IE.js
new file mode 100644
index 0000000..f372d14
--- a/dev/null
+++ b/frontend/beta/js/Bookmarklet_IE.js
@@ -0,0 +1,23 @@
1//
2 //IE limit: 508 characters!!!!!
3//
4
5loadClipperzBookmarklet = function() {
6 varheadNode;
7 var clipperzScriptNode;
8
9 clipperzScriptNode = document.getElementById('clipperzScript');
10 headNode = document.getElementsByTagName('head').item(0);
11
12 if (clipperzScriptNode) {
13 headNode.removeChild(clipperzScriptNode);
14 }
15
16 clipperzScriptNode = document.createElement('script');
17 clipperzScriptNode.setAttribute('src', 'http%3a%2f%2fclipperz.com%2ffiles%2fclipperz.com%2fbookmarklet%2fBookmarklet.js');
18 clipperzScriptNode.setAttribute('type', 'text/javascript');
19 clipperzScriptNode.setAttribute('defer', true);
20 headNode.appendChild(clipperzScriptNode);
21};
22
23loadClipperzBookmarklet();
diff --git a/frontend/beta/js/Clipperz/Base.js b/frontend/beta/js/Clipperz/Base.js
new file mode 100644
index 0000000..5bd972b
--- a/dev/null
+++ b/frontend/beta/js/Clipperz/Base.js
@@ -0,0 +1,308 @@
1/*
2
3Copyright 2008-2011 Clipperz Srl
4
5This file is part of Clipperz's Javascript Crypto Library.
6Javascript Crypto Library provides web developers with an extensive
7and efficient set of cryptographic functions. The library aims to
8obtain maximum execution speed while preserving modularity and
9reusability.
10For further information about its features and functionalities please
11refer to http://www.clipperz.com
12
13* Javascript Crypto Library is free software: you can redistribute
14 it and/or modify it under the terms of the GNU Affero General Public
15 License as published by the Free Software Foundation, either version
16 3 of the License, or (at your option) any later version.
17
18* Javascript Crypto Library is distributed in the hope that it will
19 be useful, but WITHOUT ANY WARRANTY; without even the implied
20 warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
21 See the GNU Affero General Public License for more details.
22
23* You should have received a copy of the GNU Affero General Public
24 License along with Javascript Crypto Library. If not, see
25 <http://www.gnu.org/licenses/>.
26
27*/
28
29if (typeof(Clipperz) == 'undefined') { Clipperz = {}; }
30if (typeof(Clipperz.Base) == 'undefined') { Clipperz.Base = {}; }
31
32Clipperz.Base.VERSION = "0.1";
33Clipperz.Base.NAME = "Clipperz.Base";
34
35MochiKit.Base.update(Clipperz.Base, {
36
37 //-------------------------------------------------------------------------
38
39 '__repr__': function () {
40 return "[" + this.NAME + " " + this.VERSION + "]";
41 },
42
43 //-------------------------------------------------------------------------
44
45 'toString': function () {
46 return this.__repr__();
47 },
48
49 //-------------------------------------------------------------------------
50
51 'trim': function (aValue) {
52 return aValue.replace(/^\s+|\s+$/g, "");
53 },
54
55 //-------------------------------------------------------------------------
56
57 'stringToByteArray': function (aValue) {
58 varresult;
59 var i, c;
60
61 result = [];
62
63 c = aValue.length;
64 for (i=0; i<c; i++) {
65 result[i] = aValue.charCodeAt(i);
66 }
67
68 return result;
69 },
70
71 //.........................................................................
72
73 'byteArrayToString': function (anArrayOfBytes) {
74 varresult;
75 var i, c;
76
77 result = "";
78
79 c = anArrayOfBytes.length;
80 for (i=0; i<c; i++) {
81 result += String.fromCharCode(anArrayOfBytes[i]);
82 }
83
84 return result;
85 },
86
87 //-------------------------------------------------------------------------
88
89 'getValueForKeyInFormContent': function (aFormContent, aKey) {
90 return aFormContent[1][MochiKit.Base.find(aFormContent[0], aKey)];
91 },
92
93 //-------------------------------------------------------------------------
94
95 'indexOfObjectInArray': function(anObject, anArray) {
96 varresult;
97 vari, c;
98
99 result = -1;
100
101 c = anArray.length;
102 for (i=0; ((i<c) && (result < 0)); i++) {
103 if (anArray[i] === anObject) {
104 result = i;
105 }
106 }
107
108 return result;
109 },
110
111 'removeObjectAtIndexFromArray': function(anIndex, anArray) {
112 anArray.splice(anIndex, 1);
113 },
114
115 'removeObjectFromArray': function(anObject, anArray) {
116 varobjectIndex;
117
118 objectIndex = Clipperz.Base.indexOfObjectInArray(anObject, anArray);
119 if (objectIndex > -1) {
120 Clipperz.Base.removeObjectAtIndexFromArray(objectIndex, anArray);
121 } else {
122 // jslog.error("Trying to remove an object not present in the array");
123 //TODO: raise an exception
124 }
125 },
126
127 'removeFromArray': function(anArray, anObject) {
128 return Clipperz.Base.removeObjectFromArray(anObject, anArray);
129 },
130
131 //-------------------------------------------------------------------------
132
133 'splitStringAtFixedTokenSize': function(aString, aTokenSize) {
134 var result;
135 varstringToProcess;
136
137 stringToProcess = aString;
138 result = [];
139 if (stringToProcess != null) {
140 while (stringToProcess.length > aTokenSize) {
141 result.push(stringToProcess.substring(0, aTokenSize));
142 stringToProcess = stringToProcess.substring(aTokenSize);
143 }
144
145 result.push(stringToProcess);
146 }
147
148 return result;
149 },
150
151 //-------------------------------------------------------------------------
152
153 'objectType': function(anObject) {
154 var result;
155
156 if (anObject == null) {
157 result = null;
158 } else {
159 result = typeof(anObject);
160
161 if (result == "object") {
162 if (anObject instanceof Array) {
163 result = 'array'
164 } else if (anObject.constructor == Boolean) {
165 result = 'boolean'
166 } else if (anObject instanceof Date) {
167 result = 'date'
168 } else if (anObject instanceof Error) {
169 result = 'error'
170 } else if (anObject instanceof Function) {
171 result = 'function'
172 } else if (anObject.constructor == Number) {
173 result = 'number'
174 } else if (anObject.constructor == String) {
175 result = 'string'
176 } else if (anObject instanceof Object) {
177 result = 'object'
178 } else {
179 throw Clipperz.Base.exception.UnknownType;
180 }
181 }
182 }
183
184 return result;
185 },
186
187 //-------------------------------------------------------------------------
188
189 'escapeHTML': function(aValue) {
190 var result;
191
192 result = aValue;
193 result = result.replace(/</g, "&lt;");
194 result = result.replace(/>/g, "&gt;");
195
196 return result;
197 },
198
199 //-------------------------------------------------------------------------
200
201 'deepClone': function(anObject) {
202 var result;
203
204 result = Clipperz.Base.evalJSON(Clipperz.Base.serializeJSON(anObject));
205
206 return result;
207 },
208
209 //-------------------------------------------------------------------------
210
211 'evalJSON': function(aString) {
212/*
213 var result;
214
215 //check for XSS injection
216 if (/<script>/.test(aString)) {
217 throw "error";
218 }
219
220 if (/<iframe>/.test(aString)) {
221 throw "error";
222 }
223
224 result = MochiKit.Base.evalJSON(aString);
225
226 return result;
227*/
228
229 // return MochiKit.Base.evalJSON(aString);
230 return JSON2.parse(aString);
231 },
232
233 'serializeJSON': function(anObject) {
234 // return MochiKit.Base.serializeJSON(anObject);
235 return JSON2.stringify(anObject);
236 },
237
238 //-------------------------------------------------------------------------
239
240 'sanitizeString': function(aValue) {
241 var result;
242
243 if (Clipperz.Base.objectType(aValue) == 'string') {
244 result = aValue;
245 result = result.replace(/</img,"&lt;");
246 result = result.replace(/>/img,"&gt;");
247 } else {
248 result = aValue;
249 }
250
251 return result;
252 },
253
254 //-------------------------------------------------------------------------
255
256 'exception': {
257 'AbstractMethod': new MochiKit.Base.NamedError("Clipperz.Base.exception.AbstractMethod"),
258 'UnknownType': new MochiKit.Base.NamedError("Clipperz.Base.exception.UnknownType"),
259 'VulnerabilityIssue':new MochiKit.Base.NamedError("Clipperz.Base.exception.VulnerabilityIssue")
260 },
261
262 //-------------------------------------------------------------------------
263 __syntaxFix__: "syntax fix"
264
265});
266
267
268
269MochiKit.Base.registerComparator('Object dummy comparator',
270 function(a, b) {
271 return ((a.constructor == Object) && (b.constructor == Object));
272 },
273 function(a, b) {
274 var result;
275 var aKeys;
276 var bKeys;
277
278//MochiKit.Logging.logDebug(">>> comparator");
279//MochiKit.Logging.logDebug("- a: " + Clipperz.Base.serializeJSON(a));
280//MochiKit.Logging.logDebug("- b: " + Clipperz.Base.serializeJSON(a));
281 aKeys = MochiKit.Base.keys(a).sort();
282 bKeys = MochiKit.Base.keys(b).sort();
283
284 result = MochiKit.Base.compare(aKeys, bKeys);
285//if (result != 0) {
286 //MochiKit.Logging.logDebug("- comparator 'keys':");
287 //MochiKit.Logging.logDebug("- comparator aKeys: " + Clipperz.Base.serializeJSON(aKeys));
288 //MochiKit.Logging.logDebug("- comparator bKeys: " + Clipperz.Base.serializeJSON(bKeys));
289//}
290 if (result == 0) {
291 vari, c;
292
293 c = aKeys.length;
294 for (i=0; (i<c) && (result == 0); i++) {
295 result = MochiKit.Base.compare(a[aKeys[i]], b[bKeys[i]]);
296//if (result != 0) {
297 //MochiKit.Logging.logDebug("- comparator 'values':");
298 //MochiKit.Logging.logDebug("- comparator a[aKeys[i]]: " + Clipperz.Base.serializeJSON(a[aKeys[i]]));
299 //MochiKit.Logging.logDebug("- comparator b[bKeys[i]]: " + Clipperz.Base.serializeJSON(b[bKeys[i]]));
300//}
301 }
302 }
303
304//MochiKit.Logging.logDebug("<<< comparator - result: " + result);
305 return result;
306 },
307 true
308);
diff --git a/frontend/beta/js/Clipperz/ByteArray.js b/frontend/beta/js/Clipperz/ByteArray.js
new file mode 100644
index 0000000..2275087
--- a/dev/null
+++ b/frontend/beta/js/Clipperz/ByteArray.js
@@ -0,0 +1,1426 @@
1/*
2
3Copyright 2008-2011 Clipperz Srl
4
5This file is part of Clipperz's Javascript Crypto Library.
6Javascript Crypto Library provides web developers with an extensive
7and efficient set of cryptographic functions. The library aims to
8obtain maximum execution speed while preserving modularity and
9reusability.
10For further information about its features and functionalities please
11refer to http://www.clipperz.com
12
13* Javascript Crypto Library is free software: you can redistribute
14 it and/or modify it under the terms of the GNU Affero General Public
15 License as published by the Free Software Foundation, either version
16 3 of the License, or (at your option) any later version.
17
18* Javascript Crypto Library is distributed in the hope that it will
19 be useful, but WITHOUT ANY WARRANTY; without even the implied
20 warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
21 See the GNU Affero General Public License for more details.
22
23* You should have received a copy of the GNU Affero General Public
24 License along with Javascript Crypto Library. If not, see
25 <http://www.gnu.org/licenses/>.
26
27*/
28
29if (typeof(Clipperz) == 'undefined') { Clipperz = {}; }
30
31//=============================================================================
32
33Clipperz.ByteArray_abstract = function(args) {
34 return this;
35}
36
37Clipperz.ByteArray_abstract.prototype = MochiKit.Base.update(null, {
38
39 //-------------------------------------------------------------------------
40
41 'toString': function() {
42 return "Clipperz.ByteArray_abstract";
43 },
44
45 //-------------------------------------------------------------------------
46
47 'equals': function(aValue) {
48 return (this.compare(aValue) == 0);
49 },
50
51 //-------------------------------------------------------------------------
52
53 'compare': function(aValue) {
54 var result;
55 var i;
56
57 result = MochiKit.Base.compare(this.length(), aValue.length());
58 i = this.length();
59
60 while ((result == 0) && (i>0)) {
61 i--;
62 result = MochiKit.Base.compare(this.byteAtIndex(i), aValue.byteAtIndex(i));
63 }
64
65 return result;
66 },
67
68 //-------------------------------------------------------------------------
69
70 'clone': function() {
71 throw Clipperz.Base.exception.AbstractMethod;
72 },
73
74 //-------------------------------------------------------------------------
75
76 'newInstance': function() {
77 throw Clipperz.Base.exception.AbstractMethod;
78 },
79
80 //-------------------------------------------------------------------------
81
82 'reset': function() {
83 throw Clipperz.Base.exception.AbstractMethod;
84 },
85
86 //-------------------------------------------------------------------------
87
88 'length': function() {
89 throw Clipperz.Base.exception.AbstractMethod;
90 },
91
92 //-------------------------------------------------------------------------
93
94 'checkValue': function(aValue) {
95 if ((aValue & 0xff) != aValue) {
96 MochiKit.Logging.logError("Clipperz.ByteArray.appendByte: the provided value (0x" + aValue.toString(16) + ") is not a byte value.");
97 throw Clipperz.ByteArray.exception.InvalidValue;
98 }
99 },
100
101 //-------------------------------------------------------------------------
102
103 'xorMergeWithBlock': function(aBlock, anAllignment, paddingMode) {
104 var result;
105 var a, b;
106 var aLength;
107 var bLength;
108 var i, c;
109
110 if (this.length() > aBlock.length()) {
111 a = this;
112 b = aBlock;
113 } else {
114 a = aBlock;
115 b = this;
116 }
117
118 aLength = a.length();
119 bLength = b.length();
120
121 if (aLength != bLength) {
122 if (paddingMode == 'truncate') {
123 if (anAllignment == 'left') {
124 a = a.split(0, bLength);
125 } else {
126 a = a.split(aLength - bLength);
127 }
128 } else {
129 var ii, cc;
130 var padding;
131
132 // padding = new Clipperz.ByteArray();
133 padding = this.newInstance();
134 cc = aLength - bLength;
135 for (ii=0; ii<cc; ii++) {
136 padding.appendByte(0);
137 }
138
139 if (anAllignment == 'left') {
140 b = b.appendBlock(padding);
141 } else {
142 b = padding.appendBlock(b);
143 }
144 }
145 }
146
147
148 // result = new Clipperz.ByteArray();
149 result = this.newInstance();
150 c = a.length();
151 for (i=0; i<c; i++) {
152 result.appendByte(a.byteAtIndex(i) ^ b.byteAtIndex(i));
153 }
154
155 return result;
156 },
157
158 //-------------------------------------------------------------------------
159/*
160 'shiftLeft': function(aNumberOfBitsToShift) {
161 var result;
162
163 result = this.clone(); //???????????
164
165 return result;
166 },
167 */
168 //-------------------------------------------------------------------------
169
170 'appendBlock': function(aBlock) {
171 throw Clipperz.Base.exception.AbstractMethod;
172 },
173
174 //-------------------------------------------------------------------------
175
176 'appendByte': function(aValue) {
177 throw Clipperz.Base.exception.AbstractMethod;
178 },
179
180 'appendBytes': function(args) {
181 varvalues;
182 vari,c;
183
184 if (args.constructor == Array) {
185 values = args;
186 } else {
187 values = arguments;
188 }
189
190 c = values.length;
191 for (i=0; i<c; i++) {
192 this.appendByte(values[i]);
193 }
194
195 return this;
196 },
197
198 //-------------------------------------------------------------------------
199
200 'appendWord': function(aValue, isLittleEndian) {
201 var result;
202 var processAsLittleEndian;
203
204 processAsLittleEndian = isLittleEndian === true ? true : false;
205
206 if (processAsLittleEndian) {
207 result = this.appendBytes( (aValue) & 0xff, (aValue >> 8) & 0xff, (aValue >> 16) & 0xff, (aValue >> 24) & 0xff ); //little endian
208 } else {
209 result = this.appendBytes( (aValue >> 24) & 0xff, (aValue >> 16) & 0xff, (aValue >> 8) & 0xff, (aValue) & 0xff ); //big endian - DEFAULT
210 }
211
212 return result;
213 },
214
215 'appendWords': function(args) {
216 varvalues;
217 vari,c;
218
219 if (args.constructor == Array) {
220 values = args;
221 } else {
222 values = arguments;
223 }
224
225 c = values.length;
226 for (i=0; i<c; i++) {
227 this.appendWord(values[i], false);
228 }
229
230 return this;
231 },
232
233 //-------------------------------------------------------------------------
234
235 'appendBigEndianWords': function(args) {
236 varvalues;
237 vari,c;
238
239 if (args.constructor == Array) {
240 values = args;
241 } else {
242 values = arguments;
243 }
244
245 c = values.length;
246 for (i=0; i<c; i++) {
247 this.appendWord(values[i], true);
248 }
249
250 return this;
251 },
252
253 //-------------------------------------------------------------------------
254
255 'byteAtIndex': function(anIndex) {
256 throw Clipperz.Base.exception.AbstractMethod;
257 },
258
259 'setByteAtIndex': function(aValue, anIndex) {
260 throw Clipperz.Base.exception.AbstractMethod;
261 },
262
263 //-------------------------------------------------------------------------
264
265 'bitAtIndex': function(aBitPosition) {
266 var result;
267 varbytePosition;
268 var bitPositionInSelectedByte;
269 var selectedByte;
270 var selectedByteMask;
271
272 bytePosition = this.length() - Math.ceil((aBitPosition + 1)/ 8);
273 bitPositionInSelectedByte = aBitPosition % 8;
274 selectedByte = this.byteAtIndex(bytePosition);
275
276 if (bitPositionInSelectedByte > 0) {
277 selectedByteMask = (1 << bitPositionInSelectedByte);
278 } else {
279 selectedByteMask = 1;
280 }
281 result = selectedByte & selectedByteMask ? 1 : 0;
282//console.log("aBitPosition: " + aBitPosition + ", length: " + this.length() + ", bytePosition: " + bytePosition + ", bitPositionInSelectedByte: " + bitPositionInSelectedByte + ", selectedByteMask: " + selectedByteMask);
283
284 return result;
285 },
286
287 //-------------------------------------------------------------------------
288
289 'bitBlockAtIndexWithSize': function(aBitPosition, aSize) {
290 var result;
291 var bitValue;
292 var i,c;
293
294 result = 0;
295 c = aSize;
296 for (i=0; i<c; i++) {
297 bitValue = this.bitAtIndex(aBitPosition + i);
298 result = result | bitValue << i;
299 }
300
301 return result;
302 },
303
304 //-------------------------------------------------------------------------
305
306 'asString': function() {
307 varresult;
308 varlength;
309 vari;
310
311//var startTime = new Date();
312
313 //# result = "";
314 result = [];
315
316 i = 0;
317 length = this.length();
318
319 while (i < length) {
320 varcurrentCharacter;
321 varcurrentByte;
322 varunicode;
323
324 currentByte = this.byteAtIndex(i);
325
326 if ((currentByte & 0x80) == 0x00 ) { //0xxxxxxx
327 unicode = currentByte;
328 currentCharacter = String.fromCharCode(unicode);
329 } else if ((currentByte & 0xe0) == 0xc0 ) { //110xxxxx 10xxxxxx
330 unicode = (currentByte & 0x1f) << 6;
331 i++; currentByte = this.byteAtIndex(i);
332 unicode = unicode | (currentByte & 0x3f);
333
334 currentCharacter = String.fromCharCode(unicode);
335 } else if ((currentByte & 0xf0) == 0xe0 ) { //1110xxxx 10xxxxxx 10xxxxxx
336 unicode = (currentByte & 0x0f) << (6+6);
337 i++; currentByte = this.byteAtIndex(i);
338 unicode = unicode | ((currentByte & 0x3f) << 6);
339 i++; currentByte = this.byteAtIndex(i);
340 unicode = unicode | (currentByte & 0x3f);
341
342 currentCharacter = String.fromCharCode(unicode);
343 } else { //11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
344 unicode = (currentByte & 0x07) << (6+6+6);
345 i++; currentByte = this.byteAtIndex(i);
346 unicode = unicode | ((currentByte & 0x3f) << (6+6));
347 i++; currentByte = this.byteAtIndex(i);
348 unicode = unicode | ((currentByte & 0x3f) << 6);
349 i++; currentByte = this.byteAtIndex(i);
350 unicode = unicode | (currentByte & 0x3f);
351
352 currentCharacter = String.fromCharCode(unicode);
353 }
354
355 // result += currentCharacter;
356 result.push(currentCharacter);
357 i++;
358 }
359
360//MochiKit.Logging.logDebug("[" + (new Date() - startTime) + "] ByteArray.asString");
361
362 // return result;
363 return result.join("");
364 },
365
366 //-------------------------------------------------------------------------
367
368 'toHexString': function() {
369 throw Clipperz.Base.exception.AbstractMethod;
370 },
371
372 //-------------------------------------------------------------------------
373
374 'base64map': "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",
375 'base64mapIndex': "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".split(''),
376 //'base64mapInvertedIndex': {
377 // 'A': 0, 'B': 1, 'C': 2, 'D': 3, 'E': 4, 'F': 5, 'G': 6, 'H': 7, 'I': 8, 'J': 9,
378 // 'K': 10, 'L': 11, 'M': 12, 'N': 13, 'O': 14, 'P': 15, 'Q': 16, 'R': 17, 'S': 18, 'T': 19,
379 // 'U': 20, 'V': 21, 'W': 22, 'X': 23, 'Y': 24, 'Z': 25, 'a': 26, 'b': 27, 'c': 28, 'd': 29,
380 // 'e': 30, 'f': 31, 'g': 32, 'h': 33, 'i': 34, 'j': 35, 'k': 36, 'l': 37, 'm': 38, 'n': 39,
381 // 'o': 40, 'p': 41, 'q': 42, 'r': 43, 's': 44, 't': 45, 'u': 46, 'v': 47, 'w': 48, 'x': 49,
382 // 'y': 50, 'z': 51, '0': 52, '1': 53, '2': 54, '3': 55, '4': 56, '5': 57, '6': 58, '7': 59,
383 // '8': 60, '9': 61, '+': 62, '/': 63,
384 // "=": -1},
385
386 //-------------------------------------------------------------------------
387
388 'appendBase64String': function(aValue) {
389 var i;
390 var length;
391
392 length = aValue.length;
393
394 if ((length % 4) != 0) {
395 MochiKit.Logging.logError("the value passed to the 'ByteArray.setBase64Value' is not correct");
396 throw Clipperz.ByteArray.exception.InvalidValue;
397 }
398
399 i = 0;
400 while (i<length) {
401 var value1, value2, value3, value4;
402 var byte1, byte2, byte3;
403
404 value1 = this.base64map.indexOf(aValue.charAt(i));
405 value2 = this.base64map.indexOf(aValue.charAt(i+1));
406 value3 = this.base64map.indexOf(aValue.charAt(i+2));
407 value4 = this.base64map.indexOf(aValue.charAt(i+3));
408
409 // value1 = this.base64mapInvertedIndex[aValue.charAt(i)];
410 // value2 = this.base64mapInvertedIndex[aValue.charAt(i+1)];
411 // value3 = this.base64mapInvertedIndex[aValue.charAt(i+2)];
412 // value4 = this.base64mapInvertedIndex[aValue.charAt(i+3)];
413
414 byte1 = (value1 << 2) | ((value2 & 0x30) >> 4);
415 if (value3 != -1) {
416 byte2 = ((value2 & 0x0f) << 4) | ((value3 & 0x3c) >> 2);
417
418 if (value4 != -1) {
419 byte3 = ((value3 & 0x03) << 6) | (value4);
420 } else {
421 byte3 = null;
422 }
423 } else {
424 byte2 = null;
425 byte3 = null;
426 }
427
428 this.appendByte(byte1);
429 this.appendByte(byte2);
430 this.appendByte(byte3);
431
432 i += 4;
433 }
434
435 return this;
436 },
437
438 //-------------------------------------------------------------------------
439
440 'toBase64String': function() {
441 var result;
442 var length;
443 var i;
444 var byte1, byte2, byte3;
445 var char1, char2, char3, char4;
446
447 i = 0;
448 length = this.length();
449 result = new Array(Math.ceil(length/3));
450
451 while (i < length) {
452 byte1 = this.byteAtIndex(i);
453 if ((i+2) < length) {
454 byte2 = this.byteAtIndex(i+1);
455 byte3 = this.byteAtIndex(i+2);
456 } else if ((i+2) == length) {
457 byte2 = this.byteAtIndex(i+1);
458 byte3 = null;
459 } else {
460 byte2 = null;
461 byte3 = null;
462 }
463
464 char1 = this.base64mapIndex[byte1 >> 2];
465 if (byte2 != null) {
466 char2 = this.base64mapIndex[((byte1 & 0x03) << 4) | ((byte2 & 0xf0) >> 4)];
467 if (byte3 != null) {
468 char3 = this.base64mapIndex[((byte2 & 0x0f) << 2) | ((byte3 & 0xc0) >> 6)];
469 char4 = this.base64mapIndex[(byte3 & 0x3f)];
470 } else {
471 char3 = this.base64mapIndex[(byte2 & 0x0f) << 2];
472 char4 = "=";
473 }
474 } else {
475 char2 = this.base64mapIndex[(byte1 & 0x03) << 4];
476 char3 = "=";
477 char4 = "=";
478 }
479
480 result.push(char1 + char2 + char3 + char4);
481
482 i += 3;
483 }
484
485 return result.join("");
486 },
487
488 //-------------------------------------------------------------------------
489
490 'base32map': "0123456789abcdefghjkmnpqrstvwxyz",
491 'base32mapIndex': "0123456789abcdefghjkmnpqrstvwxyz".split(''),
492
493 //-------------------------------------------------------------------------
494
495 'appendBase32String': function(aValue) {
496 var value;
497 var i;
498 var length;
499 var value1, value2, value3, value4, value5, value6, value7, value8;
500 var byte1, byte2, byte3, byte4, byte5;
501
502 value = aValue.toLowerCase();
503 value = value.replace(/[\s\-]/g, '');
504 value = value.replace(/[0o]/g, '0');
505 value = value.replace(/[1il]/g, '1');
506
507 length = value.length;
508
509 if ((length % 8) != 0) {
510 MochiKit.Logging.logError("the value passed to the 'ByteArray.setBase32Value' is not correct");
511 throw Clipperz.ByteArray.exception.InvalidValue;
512 }
513
514 i = 0;
515 while (i<length) {
516 value1 = this.base32map.indexOf(value.charAt(i));
517 value2 = this.base32map.indexOf(value.charAt(i+1));
518 value3 = this.base32map.indexOf(value.charAt(i+2));
519 value4 = this.base32map.indexOf(value.charAt(i+3));
520 value5 = this.base32map.indexOf(value.charAt(i+4));
521 value6 = this.base32map.indexOf(value.charAt(i+5));
522 value7 = this.base32map.indexOf(value.charAt(i+6));
523 value8 = this.base32map.indexOf(value.charAt(i+7));
524
525 byte1 = byte2 = byte3 = byte4 = byte5 = null;
526
527 byte1 = (value1 << 3) | ((value2 & 0x1c) >> 2);
528 if (value3 != -1) {
529 byte2 = ((value2 & 0x03) << 6) | (value3 << 1) | ((value4 & 0x10) >> 4);
530 if (value5 != -1) {
531 byte3 = ((value4 & 0x0f) << 4) | ((value5 & 0x1e) >> 1);
532 if (value6 != -1) {
533 byte4 = ((value5 & 0x01) << 7) | (value6 << 2) | ((value7 & 0x18) >> 3);
534 if (value8 != -1) {
535 byte5 = ((value7 & 0x07) << 5) | (value8);
536 }
537 }
538 }
539 }
540
541 this.appendByte(byte1);
542 this.appendByte(byte2);
543 this.appendByte(byte3);
544 this.appendByte(byte4);
545 this.appendByte(byte5);
546
547 i += 8;
548 }
549
550 return this;
551 },
552
553 //-------------------------------------------------------------------------
554
555 'toBase32String': function() {
556 var result;
557 var length;
558 var i;
559 var byte1, byte2, byte3, byte4, byte5;
560 var char1, char2, char3, char4, char5, char6, char7, char8;
561
562 i = 0;
563 length = this.length();
564 result = new Array(Math.ceil(length/5));
565
566 while (i < length) {
567 byte1 = this.byteAtIndex(i);
568
569 if ((i+4) < length) {
570 byte2 = this.byteAtIndex(i+1);
571 byte3 = this.byteAtIndex(i+2);
572 byte4 = this.byteAtIndex(i+3);
573 byte5 = this.byteAtIndex(i+4);
574 } else if ((i+4) == length) {
575 byte2 = this.byteAtIndex(i+1);
576 byte3 = this.byteAtIndex(i+2);
577 byte4 = this.byteAtIndex(i+3);
578 byte5 = null;
579 } else if ((i+3) == length) {
580 byte2 = this.byteAtIndex(i+1);
581 byte3 = this.byteAtIndex(i+2);
582 byte4 = null;
583 byte5 = null;
584 } else if ((i+2) == length) {
585 byte2 = this.byteAtIndex(i+1);
586 byte3 = null;
587 byte4 = null;
588 byte5 = null;
589 } else {
590 byte2 = null;
591 byte3 = null;
592 byte4 = null;
593 byte5 = null;
594 }
595
596
597 char1 = this.base32mapIndex[byte1 >> 3];
598 char2 = char3 = char4 = char5 = char6 = char7 = char8 = "=";
599
600 if (byte2 != null) {
601 char2 = this.base32mapIndex[((byte1 & 0x07) << 2) | ((byte2 & 0xc0) >> 6)];
602 char3 = this.base32mapIndex[((byte2 & 0x3e) >> 1)];
603 if (byte3 != null) {
604 char4 = this.base32mapIndex[((byte2 & 0x01) << 4) | ((byte3 & 0xf0) >> 4)];
605 if (byte4 != null) {
606 char5 = this.base32mapIndex[((byte3 & 0x0f) << 1) | ((byte4 & 0x80) >> 7)];
607 char6 = this.base32mapIndex[(byte4 & 0x7c) >> 2];
608 if (byte5 != null) {
609 char7 = this.base32mapIndex[((byte4 & 0x03) << 3) | ((byte5 & 0xe0) >> 5)];
610 char8 = this.base32mapIndex[(byte5 & 0x1f)];
611 } else {
612 char7 = this.base32mapIndex[(byte4 & 0x03) << 3];
613 }
614 } else {
615 char5 = this.base32mapIndex[(byte3 & 0x0f) << 1];
616 }
617
618 } else {
619 char4 = this.base32mapIndex[(byte2 & 0x01) << 4];
620 }
621 } else {
622 char2 = this.base32mapIndex[(byte1 & 0x07) << 2];
623 }
624
625 result.push(char1 + char2 + char3 + char4 + char5 + char6 + char7 + char8);
626 i += 5;
627 }
628
629 return result.join("");
630 },
631
632 //-------------------------------------------------------------------------
633
634 'split': function(aStartingIndex, anEndingIndex) {
635 throw Clipperz.Base.exception.AbstractMethod;
636 },
637
638 //-------------------------------------------------------------------------
639
640 'increment': function() {
641 var i;
642 var done;
643
644 done = false;
645 i = this.length() - 1;
646
647 while ((i>=0) && (done == false)) {
648 var currentByteValue;
649
650 currentByteValue = this.byteAtIndex(i);
651
652 if (currentByteValue == 0xff) {
653 this.setByteAtIndex(0, i);
654 if (i>= 0) {
655 i --;
656 } else {
657 done = true;
658 }
659 } else {
660 this.setByteAtIndex(currentByteValue + 1, i);
661 done = true;
662 }
663 }
664 },
665
666 //-------------------------------------------------------------------------
667
668 'arrayValues': function() {
669 throw Clipperz.Base.exception.AbstractMethod;
670 },
671
672 //-------------------------------------------------------------------------
673 __syntaxFix__: "syntax fix"
674
675});
676
677//=============================================================================
678//
679 //Clipperz.ByteArray_hex
680//
681//=============================================================================
682Clipperz.ByteArray_hex = function (args) {
683 this._value = "";
684
685 if (typeof(args) != 'undefined') {
686 if (args.constructor == Array) {
687 this.appendBytes(args);
688 } else if (args.constructor == String) {
689 if (args.indexOf("0x") == 0) {
690 varvalue;
691
692 value = args.substring(2).toLowerCase();
693 if (/[0123456789abcdef]*/.test(value)) {
694 if ((value.length % 2) == 0) {
695 this._value = value;
696 } else {
697 this._value = "0" + value;
698 }
699 } else {
700MochiKit.Logging.logError("Clipperz.ByteArray should be inizialized with an hex string.");
701 throw Clipperz.ByteArray.exception.InvalidValue;
702 }
703 } else {
704 varvalue;
705 vari,c;
706
707 c = args.length;
708 value = new Array(c);
709 for (i=0; i<c; i++) {
710 value.push(Clipperz.ByteArray.unicodeToUtf8HexString(args.charCodeAt(i)));
711 }
712
713 this._value = value.join("");
714 }
715 } else {
716 this.appendBytes(MochiKit.Base.extend(null, arguments));
717 }
718 }
719 return this;
720}
721
722Clipperz.ByteArray_hex.prototype = MochiKit.Base.update(new Clipperz.ByteArray_abstract(), {
723
724 //-------------------------------------------------------------------------
725
726 'toString': function() {
727 return "Clipperz.ByteArray_hex";
728 },
729
730 //-------------------------------------------------------------------------
731
732 'clone': function() {
733 var result;
734
735 result = this.newInstance();
736 result._value = this._value;
737
738 return result;
739 },
740
741 //-------------------------------------------------------------------------
742
743 'newInstance': function() {
744 return new Clipperz.ByteArray_hex();
745 },
746
747 //-------------------------------------------------------------------------
748
749 'reset': function() {
750 this._value = "";
751 },
752
753 //-------------------------------------------------------------------------
754
755 'length': function() {
756 return (this._value.length / 2);
757 },
758
759 //-------------------------------------------------------------------------
760
761 'appendBlock': function(aBlock) {
762 this._value = this._value += aBlock.toHexString().substring(2);
763
764 return this;
765 },
766
767 //-------------------------------------------------------------------------
768
769 'appendByte': function(aValue) {
770 if (aValue != null) {
771 this.checkValue(aValue);
772 this._value += Clipperz.ByteArray.byteToHex(aValue);
773 }
774
775 return this;
776 },
777
778 //-------------------------------------------------------------------------
779
780 'byteAtIndex': function(anIndex) {
781 return parseInt(this._value.substr(anIndex*2, 2), 16);
782 },
783
784 'setByteAtIndex': function(aValue, anIndex) {
785 varmissingBytes;
786
787 this.checkValue(aValue);
788
789 missingBytes = anIndex - this.length();
790
791 if (missingBytes < 0) {
792 varcurrentValue;
793 varfirstCutIndex;
794 var secondCutIndex;
795
796 firstCutIndex = anIndex * 2;
797 secondCutIndex = firstCutIndex + 2;
798 currentValue = this._value;
799 this._value =currentValue.substring(0, firstCutIndex) +
800 Clipperz.ByteArray.byteToHex(aValue) +
801 currentValue.substring(secondCutIndex);
802 } else if (missingBytes == 0) {
803 this.appendByte(aValue);
804 } else {
805 var i,c;
806
807 c = missingBytes;
808 for (i=0; i<c; i++) {
809 this.appendByte(0);
810 }
811
812 this.appendByte(aValue);
813 }
814 },
815
816 //-------------------------------------------------------------------------
817
818 'toHexString': function() {
819 return "0x" + this._value;
820 },
821
822 //-------------------------------------------------------------------------
823
824 'split': function(aStartingIndex, anEndingIndex) {
825 var result;
826 varstartingIndex;
827 var endingIndex;
828
829 result = this.newInstance();
830
831 startingIndex = aStartingIndex * 2;
832 if (typeof(anEndingIndex) != 'undefined') {
833 endingIndex = anEndingIndex * 2;
834 result._value = this._value.substring(startingIndex, endingIndex);
835 } else {
836 result._value = this._value.substring(startingIndex);
837 }
838
839 return result;
840 },
841
842 //-------------------------------------------------------------------------
843
844 'arrayValues': function() {
845 var result;
846 var i,c;
847
848 c = this.length();
849
850 result = new Array(c);
851 for (i=0; i<c; i++) {
852 result[i] = this.byteAtIndex(i);
853 }
854
855 return result;
856 },
857
858 //-------------------------------------------------------------------------
859 __syntaxFix__: "syntax fix"
860});
861
862//=============================================================================
863//
864 //Clipperz.ByteArray_array
865//
866//=============================================================================
867
868Clipperz.ByteArray_array = function (args) {
869 if (typeof(args) != 'undefined') {
870 if (args.constructor == Array) {
871 this._value = args.slice(0);
872 } else if (args.constructor == String) {
873 var result;
874 varvalue;
875 var i, c;
876
877 if (args.indexOf("0x") == 0) {
878
879 value = args.substring(2).toLowerCase();
880 if (/[0123456789abcdef]*/.test(value)) {
881 if ((value.length % 2) != 0) {
882 value = "0" + value;
883 }
884 } else {
885MochiKit.Logging.logError("Clipperz.ByteArray should be inizialized with an hex string.");
886 throw Clipperz.ByteArray.exception.InvalidValue;
887 }
888
889 c = value.length / 2
890 result = new Array(c);
891 for (i=0; i<c; i++) {
892 result[i] = parseInt(value.substr(i*2, 2), 16);
893 }
894
895 } else {
896 var unicode;
897 result = [];
898 c = args.length;
899 for (i=0; i<c; i++) {
900 // Clipperz.ByteArray.pushUtf8BytesOfUnicodeChar(result, args.charCodeAt(i));
901
902 unicode = args.charCodeAt(i);
903 if (unicode <= 0x7f) { //0x00000000 - 0x0000007f -> 0xxxxxxx
904 result.push(unicode);
905 // } else if ((unicode >= 0x80) && (unicode <= 0x7ff)) { //0x00000080 - 0x000007ff -> 110xxxxx 10xxxxxx
906 } else if (unicode <= 0x7ff) { //0x00000080 - 0x000007ff -> 110xxxxx 10xxxxxx
907 result.push((unicode >> 6) | 0xc0);
908 result.push((unicode & 0x3F) | 0x80);
909 // } else if ((unicode >= 0x0800) && (unicode <= 0xffff)) { //0x00000800 - 0x0000ffff -> 1110xxxx 10xxxxxx 10xxxxxx
910 } else if (unicode <= 0xffff) { //0x00000800 - 0x0000ffff -> 1110xxxx 10xxxxxx 10xxxxxx
911 result.push((unicode >> 12) | 0xe0);
912 result.push(((unicode >> 6) & 0x3f) | 0x80);
913 result.push((unicode & 0x3f) | 0x80);
914 } else { //0x00010000 - 0x001fffff -> 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
915 result.push((unicode >> 18) | 0xf0);
916 result.push(((unicode >> 12) & 0x3f) | 0x80);
917 result.push(((unicode >> 6) & 0x3f) | 0x80);
918 result.push((unicode & 0x3f) | 0x80);
919 }
920 }
921 }
922
923
924 this._value = result;
925 } else {
926 this._value = [];
927 this.appendBytes(MochiKit.Base.extend(null, arguments));
928 }
929 } else {
930 this._value = [];
931 }
932
933 return this;
934}
935
936Clipperz.ByteArray_array.prototype = MochiKit.Base.update(new Clipperz.ByteArray_abstract(), {
937
938 //-------------------------------------------------------------------------
939
940 'toString': function() {
941 return "Clipperz.ByteArray_array";
942 },
943
944 //-------------------------------------------------------------------------
945
946 'clone': function() {
947 var result;
948
949 result = this.newInstance();
950 result.appendBytes(this._value);
951
952 return result;
953 },
954
955 //-------------------------------------------------------------------------
956
957 'newInstance': function() {
958 return new Clipperz.ByteArray_array();
959 },
960
961 //-------------------------------------------------------------------------
962
963 'reset': function() {
964 this._value = [];
965 },
966
967 //-------------------------------------------------------------------------
968
969 'length': function() {
970 return (this._value.length);
971 },
972
973 //-------------------------------------------------------------------------
974
975 'appendBlock': function(aBlock) {
976 MochiKit.Base.extend(this._value, aBlock._value);
977
978 return this;
979 },
980
981 //-------------------------------------------------------------------------
982
983 'appendByte': function(aValue) {
984 if (aValue != null) {
985 this.checkValue(aValue);
986 this._value.push(aValue);
987 }
988
989 return this;
990 },
991
992 //-------------------------------------------------------------------------
993
994 'byteAtIndex': function(anIndex) {
995 return this._value[anIndex];
996 },
997
998 'setByteAtIndex': function(aValue, anIndex) {
999 varmissingBytes;
1000
1001 this.checkValue(aValue);
1002
1003 missingBytes = anIndex - this.length();
1004
1005 if (missingBytes < 0) {
1006 this._value[anIndex] = aValue;
1007 } else if (missingBytes == 0) {
1008 this._value.push(aValue);
1009 } else {
1010 var i,c;
1011
1012 c = missingBytes;
1013 for (i=0; i<c; i++) {
1014 this._value.push(0);
1015 }
1016
1017 this._value.push(aValue);
1018 }
1019 },
1020
1021 //-------------------------------------------------------------------------
1022
1023 'toHexString': function() {
1024 var result;
1025 var i, c;
1026
1027 result = "0x";
1028 c = this.length();
1029 for (i=0; i<c; i++) {
1030 result += Clipperz.ByteArray.byteToHex(this._value[i]);
1031 }
1032
1033 return result;
1034 },
1035
1036 //-------------------------------------------------------------------------
1037
1038 'split': function(aStartingIndex, anEndingIndex) {
1039 var result;
1040
1041 result = this.newInstance();
1042 result._value = this._value.slice(aStartingIndex, anEndingIndex ? anEndingIndex : this.length());
1043
1044 return result;
1045 },
1046
1047 //-------------------------------------------------------------------------
1048
1049 'arrayValues': function() {
1050 return this._value.slice(0);
1051 },
1052
1053 //-------------------------------------------------------------------------
1054 __syntaxFix__: "syntax fix"
1055});
1056
1057
1058
1059
1060
1061//=============================================================================
1062//
1063 //Clipperz.ByteArray_string
1064//
1065//=============================================================================
1066
1067Clipperz.ByteArray_string = function (args) {
1068 this._value = "";
1069
1070 if (typeof(args) != 'undefined') {
1071 if (args.constructor == Array) {
1072 this.appendBytes(args);
1073 } else if (args.constructor == String) {
1074 var result;
1075 varvalue;
1076 var i, c;
1077
1078 if (args.indexOf("0x") == 0) {
1079
1080 value = args.substring(2).toLowerCase();
1081 if (/[0123456789abcdef]*/.test(value)) {
1082 if ((value.length % 2) != 0) {
1083 value = "0" + value;
1084 }
1085 } else {
1086MochiKit.Logging.logError("Clipperz.ByteArray should be inizialized with an hex string.");
1087 throw Clipperz.ByteArray.exception.InvalidValue;
1088 }
1089 } else {
1090 value = "";
1091 c = args.length;
1092 for (i=0; i<c; i++) {
1093 value += Clipperz.ByteArray.unicodeToUtf8HexString(args.charCodeAt(i));
1094 }
1095 }
1096
1097 c = value.length / 2
1098 for (i=0; i<c; i++) {
1099 this.appendByte(parseInt(value.substr(i*2, 2), 16));
1100 }
1101 } else {
1102 this.appendBytes(MochiKit.Base.extend(null, arguments));
1103 }
1104 }
1105
1106 return this;
1107}
1108
1109Clipperz.ByteArray_string.prototype = MochiKit.Base.update(new Clipperz.ByteArray_abstract(), {
1110
1111 //-------------------------------------------------------------------------
1112
1113 'toString': function() {
1114 return "Clipperz.ByteArray_string";
1115 },
1116
1117 //-------------------------------------------------------------------------
1118
1119 'clone': function() {
1120 var result;
1121
1122 result = this.newInstance();
1123 result._value = this._value;
1124
1125 return result;
1126 },
1127
1128 //-------------------------------------------------------------------------
1129
1130 'newInstance': function() {
1131 return new Clipperz.ByteArray_string();
1132 },
1133
1134 //-------------------------------------------------------------------------
1135
1136 'reset': function() {
1137 this._value = "";
1138 },
1139
1140 //-------------------------------------------------------------------------
1141
1142 'length': function() {
1143 return (this._value.length);
1144 },
1145
1146 //-------------------------------------------------------------------------
1147
1148 'appendBlock': function(aBlock) {
1149 this._value += aBlock._value;
1150
1151 return this;
1152 },
1153
1154 //-------------------------------------------------------------------------
1155
1156 'appendByte': function(aValue) {
1157 if (aValue != null) {
1158 this.checkValue(aValue);
1159 this._value += String.fromCharCode(aValue);
1160 }
1161
1162 return this;
1163 },
1164
1165 //-------------------------------------------------------------------------
1166
1167 'byteAtIndex': function(anIndex) {
1168 return this._value.charCodeAt(anIndex);
1169 },
1170
1171 'setByteAtIndex': function(aValue, anIndex) {
1172 varmissingBytes;
1173
1174 this.checkValue(aValue);
1175
1176 missingBytes = anIndex - this.length();
1177
1178 if (missingBytes < 0) {
1179 this._value = this._value.substring(0, anIndex) + String.fromCharCode(aValue) + this._value.substring(anIndex + 1);
1180 } else if (missingBytes == 0) {
1181 this.appendByte(aValue);
1182 } else {
1183 var i,c;
1184
1185 c = missingBytes;
1186 for (i=0; i<c; i++) {
1187 this.appendByte(0);
1188 }
1189
1190 this.appendByte(aValue);
1191 }
1192 },
1193
1194 //-------------------------------------------------------------------------
1195
1196 'toHexString': function() {
1197 var result;
1198 var i, c;
1199
1200 result = "0x";
1201 c = this.length();
1202 for (i=0; i<c; i++) {
1203 result += Clipperz.ByteArray.byteToHex(this.byteAtIndex(i));
1204 }
1205
1206 return result;
1207 },
1208
1209 //-------------------------------------------------------------------------
1210
1211 'split': function(aStartingIndex, anEndingIndex) {
1212 var result;
1213 result = this.newInstance();
1214 result._value = this._value.substring(aStartingIndex, anEndingIndex ? anEndingIndex : this.length());
1215
1216 return result;
1217 },
1218
1219 //-------------------------------------------------------------------------
1220
1221 'arrayValues': function() {
1222 var result;
1223 var i,c;
1224
1225 c = this.length();
1226
1227 result = new Array(c);
1228 for (i=0; i<c; i++) {
1229 result[i] = this.byteAtIndex(i);
1230 }
1231
1232 return result;
1233 },
1234
1235 //-------------------------------------------------------------------------
1236 __syntaxFix__: "syntax fix"
1237});
1238
1239
1240//=============================================================================
1241//
1242 //Clipperz.ByteArray
1243//
1244//=============================================================================
1245
1246Clipperz.ByteArray = Clipperz.ByteArray_array;
1247//Clipperz.ByteArray = Clipperz.ByteArray_string;
1248//Clipperz.ByteArray = Clipperz.ByteArray_hex;
1249
1250//#############################################################################
1251
1252Clipperz.ByteArray.byteToHex = function(aByte) {
1253 return ((aByte < 16) ? "0" : "") + aByte.toString(16);
1254}
1255
1256
1257Clipperz.ByteArray.unicodeToUtf8HexString = function(aUnicode) {
1258 var result;
1259 varself;
1260
1261 self = Clipperz.ByteArray;
1262
1263 if (aUnicode <= 0x7f) { //0x00000000 - 0x0000007f -> 0xxxxxxx
1264 result = self.byteToHex(aUnicode);
1265 // } else if ((aUnicode >= 0x80) && (aUnicode <= 0x7ff)) { //0x00000080 - 0x000007ff -> 110xxxxx 10xxxxxx
1266 } else if (aUnicode <= 0x7ff) { //0x00000080 - 0x000007ff -> 110xxxxx 10xxxxxx
1267 result = self.byteToHex((aUnicode >> 6) | 0xc0);
1268 result += self.byteToHex((aUnicode & 0x3F) | 0x80);
1269 // } else if ((aUnicode >= 0x0800) && (aUnicode <= 0xffff)) { //0x00000800 - 0x0000ffff -> 1110xxxx 10xxxxxx 10xxxxxx
1270 } else if (aUnicode <= 0xffff) { //0x00000800 - 0x0000ffff -> 1110xxxx 10xxxxxx 10xxxxxx
1271 result = self.byteToHex((aUnicode >> 12) | 0xe0);
1272 result += self.byteToHex(((aUnicode >> 6) & 0x3f) | 0x80);
1273 result += self.byteToHex((aUnicode & 0x3f) | 0x80);
1274 } else { //0x00010000 - 0x001fffff -> 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
1275 result = self.byteToHex((aUnicode >> 18) | 0xf0);
1276 result += self.byteToHex(((aUnicode >> 12) & 0x3f) | 0x80);
1277 result += self.byteToHex(((aUnicode >> 6) & 0x3f) | 0x80);
1278 result += self.byteToHex((aUnicode & 0x3f) | 0x80);
1279 }
1280
1281 return result;
1282}
1283
1284Clipperz.ByteArray.pushUtf8BytesOfUnicodeChar = function(anArray, aUnicode) {
1285 varself;
1286
1287 self = Clipperz.ByteArray;
1288
1289 if (aUnicode <= 0x7f) { //0x00000000 - 0x0000007f -> 0xxxxxxx
1290 anArray.push(aUnicode);
1291 // } else if ((aUnicode >= 0x80) && (aUnicode <= 0x7ff)) { //0x00000080 - 0x000007ff -> 110xxxxx 10xxxxxx
1292 } else if (aUnicode <= 0x7ff) { //0x00000080 - 0x000007ff -> 110xxxxx 10xxxxxx
1293 anArray.push((aUnicode >> 6) | 0xc0);
1294 anArray.push((aUnicode & 0x3F) | 0x80);
1295 // } else if ((aUnicode >= 0x0800) && (aUnicode <= 0xffff)) { //0x00000800 - 0x0000ffff -> 1110xxxx 10xxxxxx 10xxxxxx
1296 } else if (aUnicode <= 0xffff) { //0x00000800 - 0x0000ffff -> 1110xxxx 10xxxxxx 10xxxxxx
1297 anArray.push((aUnicode >> 12) | 0xe0);
1298 anArray.push(((aUnicode >> 6) & 0x3f) | 0x80);
1299 anArray.push((aUnicode & 0x3f) | 0x80);
1300 } else { //0x00010000 - 0x001fffff -> 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
1301 anArray.push((aUnicode >> 18) | 0xf0);
1302 anArray.push(((aUnicode >> 12) & 0x3f) | 0x80);
1303 anArray.push(((aUnicode >> 6) & 0x3f) | 0x80);
1304 anArray.push((aUnicode & 0x3f) | 0x80);
1305 }
1306}
1307
1308Clipperz.ByteArray.exception = {
1309 InvalidValue: new MochiKit.Base.NamedError("Clipperz.ByteArray.exception.InvalidValue")
1310};
1311
1312//#############################################################################
1313
1314Clipperz.ByteArrayIterator = function(args) {
1315 args = args || {};
1316
1317 this._byteArray = args.byteArray;
1318 this._blockSize = args.blockSize;
1319 this._finalPadding = args.finalPadding || false;
1320
1321 this._currentPosition = 0;
1322
1323 return this;
1324}
1325
1326Clipperz.ByteArrayIterator.prototype = MochiKit.Base.update(null, {
1327
1328 //-------------------------------------------------------------------------
1329
1330 'toString': function() {
1331 return "Clipperz.ByteArrayIterator";
1332 },
1333
1334 //-------------------------------------------------------------------------
1335
1336 'blockSize': function() {
1337 var result;
1338
1339 result = this._blockSize;
1340
1341 return result;
1342 },
1343
1344 //-------------------------------------------------------------------------
1345
1346 'currentPosition': function() {
1347 var result;
1348
1349 result = this._currentPosition;
1350
1351 return result;
1352 },
1353
1354 //-------------------------------------------------------------------------
1355
1356 'byteArray': function() {
1357 var result;
1358
1359 result = this._byteArray;
1360
1361 return result;
1362 },
1363
1364 //-------------------------------------------------------------------------
1365
1366 'finalPadding': function() {
1367 var result;
1368
1369 result = this._finalPadding;
1370
1371 return result;
1372 },
1373
1374 //-------------------------------------------------------------------------
1375
1376 'nextBlock': function() {
1377 var result;
1378 var currentPosition;
1379 varbyteArrayLength;
1380
1381 currentPosition = this._currentPosition;
1382 byteArrayLength = this.byteArray().length();
1383
1384 if (currentPosition < byteArrayLength) {
1385 var i,c;
1386
1387 c = this.blockSize();
1388 result = new Array(c);
1389 for (i=0; i<c; i++) {
1390 if (currentPosition < byteArrayLength) {
1391 result[i] = this.byteArray().byteAtIndex(currentPosition);
1392 currentPosition++;
1393 } else if (this.finalPadding() == true) {
1394 result[i] = 0;
1395 }
1396 }
1397
1398 this._currentPosition = currentPosition;
1399 } else {
1400 result = null;
1401 }
1402
1403 return result;
1404 },
1405
1406 //-------------------------------------------------------------------------
1407
1408 'nextBlockArray': function() {
1409 var result;
1410 var nextBlock;
1411
1412 nextBlock = this.nextBlock();
1413
1414 if (nextBlock != null) {
1415 result = new Clipperz.ByteArray(nextBlock);
1416 } else {
1417 result = null;
1418 }
1419
1420 return result;
1421 },
1422
1423 //-----------------------------------------------------------------------------
1424 __syntaxFix__: "syntax fix"
1425
1426});
diff --git a/frontend/beta/js/Clipperz/CSVProcessor.js b/frontend/beta/js/Clipperz/CSVProcessor.js
new file mode 100644
index 0000000..164b02e
--- a/dev/null
+++ b/frontend/beta/js/Clipperz/CSVProcessor.js
@@ -0,0 +1,348 @@
1/*
2
3Copyright 2008-2011 Clipperz Srl
4
5This file is part of Clipperz's Javascript Crypto Library.
6Javascript Crypto Library provides web developers with an extensive
7and efficient set of cryptographic functions. The library aims to
8obtain maximum execution speed while preserving modularity and
9reusability.
10For further information about its features and functionalities please
11refer to http://www.clipperz.com
12
13* Javascript Crypto Library is free software: you can redistribute
14 it and/or modify it under the terms of the GNU Affero General Public
15 License as published by the Free Software Foundation, either version
16 3 of the License, or (at your option) any later version.
17
18* Javascript Crypto Library is distributed in the hope that it will
19 be useful, but WITHOUT ANY WARRANTY; without even the implied
20 warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
21 See the GNU Affero General Public License for more details.
22
23* You should have received a copy of the GNU Affero General Public
24 License along with Javascript Crypto Library. If not, see
25 <http://www.gnu.org/licenses/>.
26
27*/
28
29if (typeof(Clipperz) == 'undefined') { Clipperz = {}; }
30
31
32Clipperz.CSVProcessor = function(args) {
33 args = args || {};
34
35 // this._status = undefined;
36 // this._error_input= undefined;
37 // this._string = undefined;
38 // this._fields = undefined;
39
40 this._quoteChar = args['quoteChar'] ||"\042";
41 this._eol = args['eol'] ||"";
42 this._escapeChar = args['escapeChar'] ||"\042";
43 this._separatorChar = args['separatorChar'] ||",";
44 this._binary = args['binary'] ||false;
45 this._alwaysQuote = args['alwaysQuote'] ||false;
46
47 return this;
48}
49
50//=============================================================================
51
52Clipperz.CSVProcessor.prototype = MochiKit.Base.update(null, {
53
54 //-------------------------------------------------------------------------
55
56 'quoteChar': function() {
57 return this._quoteChar;
58 },
59
60 //-------------------------------------------------------------------------
61
62 'eol': function() {
63 return this._eol;
64 },
65
66 //-------------------------------------------------------------------------
67
68 'escapeChar': function() {
69 return this._escapeChar;
70 },
71
72 //-------------------------------------------------------------------------
73
74 'separatorChar': function() {
75 return this._separatorChar;
76 },
77
78 'setSeparatorChar': function(aValue) {
79 this._separatorChar = aValue;
80 },
81
82 //-------------------------------------------------------------------------
83
84 'binary': function() {
85 return this._binary;
86 },
87
88 //-------------------------------------------------------------------------
89
90 'alwaysQuote': function() {
91 return this._alwaysQuote;
92 },
93
94 //-------------------------------------------------------------------------
95/*
96 'parse': function(aValue) {
97 var result;
98 var lines;
99 var parameter;
100
101//MochiKit.Logging.logDebug(">>> CSVProcessor.parse");
102 result = [];
103
104 lines = aValue.replace(/\r?\n/g, "\n").replace(/^\n* /g, "").replace(/\n$/g, "");;
105 parameter = {
106 line: lines
107 }
108
109 do {
110 var fields;
111
112 fields = this.parseLine(parameter);
113
114 if (fields != null) {
115 result.push(fields);
116 }
117
118 parameter.line = parameter.line.replace(/^\n* /g, "").replace(/\n$/g, "");
119
120//MochiKit.Logging.logDebug("line: '" + parameter.line + "'");
121 } while (parameter.line != "");
122//MochiKit.Logging.logDebug("--- CSVProcessor.parse - result: " + Clipperz.Base.serializeJSON(result));
123//MochiKit.Logging.logDebug("<<< CSVProcessor.parse");
124
125 return result;
126 },
127*/
128 //-------------------------------------------------------------------------
129
130 'deferredParse_core': function(aContext) {
131 var deferredResult;
132
133 if (aContext.line == "") {
134 deferredResult = MochiKit.Async.succeed(aContext.result);
135 } else {
136 var fields;
137
138 fields = this.parseLine(aContext);
139 if (fields != null) {
140 aContext.result.push(fields);
141 }
142
143 aContext.line = aContext.line.replace(/^\n*/g, "").replace(/\n$/g, "");
144
145 deferredResult = new MochiKit.Async.Deferred();
146 deferredResult.addCallback(Clipperz.NotificationCenter.deferredNotification, this, 'importProcessorProgressUpdate', {status:'processing', size:aContext.size, progress:(aContext.size - aContext.line.length)});
147 deferredResult.addCallback(MochiKit.Async.wait, 0.2);
148 deferredResult.addCallback(MochiKit.Base.method(this, 'deferredParse_core'))
149 deferredResult.callback(aContext);
150 }
151
152 return deferredResult;
153 },
154
155 //.........................................................................
156
157 'deferredParse': function(aValue) {
158 var deferredResult;
159 var lines;
160 var context;
161
162 lines = aValue.replace(/\r?\n/g, "\n").replace(/^\n*/g, "").replace(/\n$/g, "");
163
164 context = {
165 line: lines,
166 size: lines.length,
167 result: []
168 }
169
170 deferredResult = new MochiKit.Async.Deferred();
171 deferredResult.addCallback(MochiKit.Base.method(this, 'deferredParse_core'));
172 deferredResult.callback(context);
173
174 return deferredResult;
175 },
176
177 //-------------------------------------------------------------------------
178
179 'parseLine': function(aParameter) {
180 var result;
181 var palatable;
182 var line;
183 var processedField;
184
185 result = [];
186
187 do {
188 processedField = this.parseField(aParameter);
189 if (processedField != null) {
190 result.push(processedField)
191 };
192 } while (processedField != null);
193
194 return result;
195 },
196
197 //-------------------------------------------------------------------------
198
199 'parseField': function(aParameter) {
200 var result;
201
202 var inQuotes;
203 var validRegExp;
204 var singleQuoteBeginRegexp;
205 var escapedQuoteBeginRegexp;
206 var singleQuoteCommaEndRegexp;
207 var singleQuoteNewLineEndRegexp;
208 var commaBeginRegexp;
209 var newlineRegexp;
210
211
212 singleQuoteBeginRegexp = new RegExp("^" + '\\' + this.quoteChar());
213 escapedQuoteBeginRegexp = new RegExp("^" + '\\' + this.escapeChar() + '\\' + this.quoteChar());
214 singleQuoteCommaEndRegexp= new RegExp("^" + '\\' + this.quoteChar() + '\\' + this.separatorChar());
215 singleQuoteNewLineEndRegexp= new RegExp("^" + '\\' + this.quoteChar() + "\n");
216 commaBeginRegexp = new RegExp("^" + '\\' + this.separatorChar());
217 newlineRegexp = new RegExp("^\n");
218
219 inQuotes = false;
220
221//MochiKit.Logging.logDebug("#################################### '" + aParameter.line + "'");
222 if (aParameter.line == "") {
223 if (aParameter.isThereAnEmptyFinalField == true) {
224 aParameter.isThereAnEmptyFinalField = false;
225 result = "";
226 } else {
227 result = null;
228 }
229 } else {
230 if (this.binary()) {
231 validRegexp = /^./;
232 // validRegexp = /^[^\\]/;
233 } else {
234 validRegexp = /^[\t\040-\176]/;
235 }
236
237 try {
238 var done;
239
240 done = false;
241 result = "";
242
243 while (!done) {
244 if (aParameter.line.length < 1) {
245//MochiKit.Logging.logDebug("---> 1: '" + aParameter.line.replace(/\n/g, "\\n") + "'");
246 if (inQuotes == true) {
247//MochiKit.Logging.logDebug("---> 1.1: '" + aParameter.line.replace(/\n/g, "\\n") + "'");
248 throw new Error("CSV Parsing error; end of string, missing closing double-quote...");
249 } else {
250//MochiKit.Logging.logDebug("---> 1.2: '" + aParameter.line.replace(/\n/g, "\\n") + "'");
251 done = true;
252 }
253 } else if (escapedQuoteBeginRegexp.test(aParameter.line)) {
254//MochiKit.Logging.logDebug("---> 2.1: '" + aParameter.line.replace(/\n/g, "\\n") + "'");
255 result += this.quoteChar();
256 aParameter.line = aParameter.line.substr(2, aParameter.line.length - 1);
257//MochiKit.Logging.logDebug("<--- 2.2: '" + aParameter.line.replace(/\n/g, "\\n") + "'");
258 } else if (singleQuoteBeginRegexp.test(aParameter.line)) {
259//MochiKit.Logging.logDebug("---> 3: '" + aParameter.line.replace(/\n/g, "\\n") + "'");
260 if (inQuotes == true) {
261 if (aParameter.line.length == 1) {
262//MochiKit.Logging.logDebug("---> 3.1: '" + aParameter.line.replace(/\n/g, "\\n") + "'");
263 aParameter.line = '';
264 done = true;
265 } else if (singleQuoteCommaEndRegexp.test(aParameter.line)) {
266//MochiKit.Logging.logDebug("---> 3.3: '" + aParameter.line.replace(/\n/g, "\\n") + "'");
267 aParameter.line = aParameter.line.substr(2, aParameter.line.length - 1);
268 done = true;
269//MochiKit.Logging.logDebug("<--- 3.3: '" + aParameter.line.replace(/\n/g, "\\n") + "'");
270 } else if (singleQuoteNewLineEndRegexp.test(aParameter.line)) {
271 aParameter.line = aParameter.line.substr(1, aParameter.line.length - 1);
272 done = true;
273 } else {
274 throw new Error("CSV Parsing error; double-quote, followed by undesirable character (bad character sequence)... " + aParameter.line);
275 }
276 } else {
277//MochiKit.Logging.logDebug("---> 4: '" + aParameter.line.replace(/\n/g, "\\n") + "'");
278 if (result == "") {
279//MochiKit.Logging.logDebug("---> 4.1: '" + aParameter.line.replace(/\n/g, "\\n") + "'");
280 inQuotes = true;
281 aParameter.line = aParameter.line.substr(1, aParameter.line.length - 1);
282//MochiKit.Logging.logDebug("<--- 4.1: '" + aParameter.line.replace(/\n/g, "\\n") + "'");
283 } else {
284 throw new Error("CSV Parsing error; double-quote, outside of double-quotes (bad character sequence)...");
285 }
286 }
287 } else if (commaBeginRegexp.test(aParameter.line)) {
288//MochiKit.Logging.logDebug("---> 5: '" + aParameter.line.replace(/\n/g, "\\n") + "'");
289 if (inQuotes) {
290//MochiKit.Logging.logDebug("---> 5.1: '" + aParameter.line.replace(/\n/g, "\\n") + "'");
291 result += aParameter.line.substr(0 ,1);
292 aParameter.line = aParameter.line.substr(1, aParameter.line.length - 1);
293//MochiKit.Logging.logDebug("<--- 5.1: '" + aParameter.line.replace(/\n/g, "\\n") + "'");
294 } else {
295//MochiKit.Logging.logDebug("---> 5.2: '" + aParameter.line.replace(/\n/g, "\\n") + "'");
296 aParameter.line = aParameter.line.substr(1, aParameter.line.length - 1);
297 if (newlineRegexp.test(aParameter.line) || aParameter.line == "") {
298//MochiKit.Logging.logDebug("######");
299 aParameter.isThereAnEmptyFinalField = true;
300 };
301 done = true;
302//MochiKit.Logging.logDebug("<--- 5.2: '" + aParameter.line.replace(/\n/g, "\\n") + "'");
303 }
304 } else if (validRegexp.test(aParameter.line)) {
305//MochiKit.Logging.logDebug("---> 6: '" + aParameter.line.replace(/\n/g, "\\n") + "'");
306 result += aParameter.line.substr(0, 1);
307 aParameter.line = aParameter.line.substr(1, aParameter.line.length - 1);
308//MochiKit.Logging.logDebug("<--- 6: '" + aParameter.line.replace(/\n/g, "\\n") + "'");
309 } else if (newlineRegexp.test(aParameter.line)) {
310 if (inQuotes == true) {
311 result += aParameter.line.substr(0 ,1);
312 aParameter.line = aParameter.line.substr(1, aParameter.line.length - 1);
313 } else {
314 if (result == "") {
315 if (aParameter.isThereAnEmptyFinalField == true) {
316 aParameter.isThereAnEmptyFinalField = false;
317 } else {
318 result = null;
319 }
320 }
321
322 done = true;
323 }
324 } else {
325 throw new Error("CSV Parsing error; an undesirable character... '" + aParameter.line.substr(0,1) + "'");
326 }
327 }
328 } catch(exception) {
329 MochiKit.Logging.logError(exception.message);
330 // result = null;
331 throw exception;
332 }
333 }
334
335//if (result != null) {
336 //MochiKit.Logging.logDebug("<=== result: '" + result.replace(/\n/g, "\\n") + "'");
337//} else {
338 //MochiKit.Logging.logDebug("<=== result: NULL");
339//}
340
341 return result;
342 },
343
344 //-------------------------------------------------------------------------
345 __syntaxFix__: "syntax fix"
346});
347
348
diff --git a/frontend/beta/js/Clipperz/Crypto/AES.js b/frontend/beta/js/Clipperz/Crypto/AES.js
new file mode 100644
index 0000000..a60df5c
--- a/dev/null
+++ b/frontend/beta/js/Clipperz/Crypto/AES.js
@@ -0,0 +1,836 @@
1/*
2
3Copyright 2008-2011 Clipperz Srl
4
5This file is part of Clipperz's Javascript Crypto Library.
6Javascript Crypto Library provides web developers with an extensive
7and efficient set of cryptographic functions. The library aims to
8obtain maximum execution speed while preserving modularity and
9reusability.
10For further information about its features and functionalities please
11refer to http://www.clipperz.com
12
13* Javascript Crypto Library is free software: you can redistribute
14 it and/or modify it under the terms of the GNU Affero General Public
15 License as published by the Free Software Foundation, either version
16 3 of the License, or (at your option) any later version.
17
18* Javascript Crypto Library is distributed in the hope that it will
19 be useful, but WITHOUT ANY WARRANTY; without even the implied
20 warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
21 See the GNU Affero General Public License for more details.
22
23* You should have received a copy of the GNU Affero General Public
24 License along with Javascript Crypto Library. If not, see
25 <http://www.gnu.org/licenses/>.
26
27*/
28
29try { if (typeof(Clipperz.ByteArray) == 'undefined') { throw ""; }} catch (e) {
30 throw "Clipperz.Crypto.AES depends on Clipperz.ByteArray!";
31}
32
33 //Dependency commented to avoid a circular reference
34//try { if (typeof(Clipperz.Crypto.PRNG) == 'undefined') { throw ""; }} catch (e) {
35 //throw "Clipperz.Crypto.AES depends on Clipperz.Crypto.PRNG!";
36//}
37
38if (typeof(Clipperz.Crypto.AES) == 'undefined') { Clipperz.Crypto.AES = {}; }
39
40//#############################################################################
41
42Clipperz.Crypto.AES.DeferredExecutionContext = function(args) {
43 args = args || {};
44
45 this._key = args.key;
46 this._message = args.message;
47 this._result = args.message.clone();
48 this._nonce = args.nonce;
49 this._messageLength = this._message.length();
50
51 this._messageArray = this._message.arrayValues();
52 this._resultArray = this._result.arrayValues();
53 this._nonceArray = this._nonce.arrayValues();
54
55 this._executionStep = 0;
56
57 return this;
58}
59
60Clipperz.Crypto.AES.DeferredExecutionContext.prototype = MochiKit.Base.update(null, {
61
62 'key': function() {
63 return this._key;
64 },
65
66 'message': function() {
67 return this._message;
68 },
69
70 'messageLength': function() {
71 return this._messageLength;
72 },
73
74 'result': function() {
75 return new Clipperz.ByteArray(this.resultArray());
76 },
77
78 'nonce': function() {
79 return this._nonce;
80 },
81
82 'messageArray': function() {
83 return this._messageArray;
84 },
85
86 'resultArray': function() {
87 return this._resultArray;
88 },
89
90 'nonceArray': function() {
91 return this._nonceArray;
92 },
93
94 'elaborationChunkSize': function() {
95 return Clipperz.Crypto.AES.DeferredExecution.chunkSize;
96 },
97
98 'executionStep': function() {
99 return this._executionStep;
100 },
101
102 'setExecutionStep': function(aValue) {
103 this._executionStep = aValue;
104 },
105
106 'pause': function(aValue) {
107 return MochiKit.Async.wait(Clipperz.Crypto.AES.DeferredExecution.pauseTime, aValue);
108 },
109
110 //-----------------------------------------------------------------------------
111 __syntaxFix__: "syntax fix"
112
113});
114
115//#############################################################################
116
117Clipperz.Crypto.AES.Key = function(args) {
118 args = args || {};
119
120 this._key = args.key;
121 this._keySize = args.keySize || this.key().length();
122
123 if (this.keySize() == 128/8) {
124 this._b = 176;
125 this._numberOfRounds = 10;
126 } else if (this.keySize() == 256/8) {
127 this._b = 240;
128 this._numberOfRounds = 14;
129 } else {
130 MochiKit.Logging.logError("AES unsupported key size: " + (this.keySize() * 8) + " bits");
131 throw Clipperz.Crypto.AES.exception.UnsupportedKeySize;
132 }
133
134 this._stretchedKey = null;
135
136 return this;
137}
138
139Clipperz.Crypto.AES.Key.prototype = MochiKit.Base.update(null, {
140
141 'asString': function() {
142 return "Clipperz.Crypto.AES.Key (" + this.key().toHexString() + ")";
143 },
144
145 //-----------------------------------------------------------------------------
146
147 'key': function() {
148 return this._key;
149 },
150
151 'keySize': function() {
152 return this._keySize;
153 },
154
155 'b': function() {
156 return this._b;
157 },
158
159 'numberOfRounds': function() {
160 return this._numberOfRounds;
161 },
162 //=========================================================================
163
164 'keyScheduleCore': function(aWord, aRoundConstantsIndex) {
165 varresult;
166 var sbox;
167
168 sbox = Clipperz.Crypto.AES.sbox();
169
170 result = [sbox[aWord[1]] ^ Clipperz.Crypto.AES.roundConstants()[aRoundConstantsIndex],
171 sbox[aWord[2]],
172 sbox[aWord[3]],
173 sbox[aWord[0]]];
174
175 return result;
176 },
177
178 //-----------------------------------------------------------------------------
179
180 'xorWithPreviousStretchValues': function(aKey, aWord, aPreviousWordIndex) {
181 varresult;
182 var i,c;
183
184 result = [];
185 c = 4;
186 for (i=0; i<c; i++) {
187 result[i] = aWord[i] ^ aKey.byteAtIndex(aPreviousWordIndex + i);
188 }
189
190 return result;
191 },
192
193 //-----------------------------------------------------------------------------
194
195 'sboxShakeup': function(aWord) {
196 var result;
197 var sbox;
198 var i,c;
199
200 result = [];
201 sbox = Clipperz.Crypto.AES.sbox();
202 c =4;
203 for (i=0; i<c; i++) {
204 result[i] = sbox[aWord[i]];
205 }
206
207 return result;
208 },
209
210 //-----------------------------------------------------------------------------
211
212 'stretchKey': function(aKey) {
213 varcurrentWord;
214 varkeyLength;
215 varpreviousStretchIndex;
216 var i,c;
217
218 keyLength = aKey.length();
219 previousStretchIndex = keyLength - this.keySize();
220
221 currentWord = [aKey.byteAtIndex(keyLength - 4),
222 aKey.byteAtIndex(keyLength - 3),
223 aKey.byteAtIndex(keyLength - 2),
224 aKey.byteAtIndex(keyLength - 1)];
225 currentWord = this.keyScheduleCore(currentWord, keyLength / this.keySize());
226
227 if (this.keySize() == 256/8) {
228 c = 8;
229 } else if (this.keySize() == 128/8){
230 c = 4;
231 }
232
233 for (i=0; i<c; i++) {
234 if (i == 4) {
235 //fifth streatch word
236 currentWord = this.sboxShakeup(currentWord);
237 }
238
239 currentWord = this.xorWithPreviousStretchValues(aKey, currentWord, previousStretchIndex + (i*4));
240 aKey.appendBytes(currentWord);
241 }
242
243 return aKey;
244 },
245
246 //-----------------------------------------------------------------------------
247
248 'stretchedKey': function() {
249 if (this._stretchedKey == null) {
250 var stretchedKey;
251
252 stretchedKey = this.key().clone();
253
254 while (stretchedKey.length() < this.keySize()) {
255 stretchedKey.appendByte(0);
256 }
257
258 while (stretchedKey.length() < this.b()) {
259 stretchedKey = this.stretchKey(stretchedKey);
260 }
261
262 this._stretchedKey = stretchedKey.split(0, this.b());
263 }
264
265 return this._stretchedKey;
266 },
267
268 //=========================================================================
269 __syntaxFix__: "syntax fix"
270});
271
272//#############################################################################
273
274Clipperz.Crypto.AES.State = function(args) {
275 args = args || {};
276
277 this._data = args.block;
278 this._key = args.key;
279
280 return this;
281}
282
283Clipperz.Crypto.AES.State.prototype = MochiKit.Base.update(null, {
284
285 'key': function() {
286 return this._key;
287 },
288
289 //-----------------------------------------------------------------------------
290
291 'data': function() {
292 return this._data;
293 },
294
295 'setData': function(aValue) {
296 this._data = aValue;
297 },
298
299 //=========================================================================
300
301 'addRoundKey': function(aRoundNumber) {
302 //each byte of the state is combined with the round key; each round key is derived from the cipher key using a key schedule.
303 vardata;
304 varstretchedKey;
305 varfirstStretchedKeyIndex;
306 var i,c;
307
308 data = this.data();
309 stretchedKey = this.key().stretchedKey();
310 firstStretchedKeyIndex = aRoundNumber * (128/8);
311 c = 128/8;
312 for (i=0; i<c; i++) {
313 data[i] = data[i] ^ stretchedKey.byteAtIndex(firstStretchedKeyIndex + i);
314 }
315 },
316
317 //-----------------------------------------------------------------------------
318
319 'subBytes': function() {
320 // a non-linear substitution step where each byte is replaced with another according to a lookup table.
321 var i,c;
322 vardata;
323 var sbox;
324
325 data = this.data();
326 sbox = Clipperz.Crypto.AES.sbox();
327
328 c = 16;
329 for (i=0; i<c; i++) {
330 data[i] = sbox[data[i]];
331 }
332 },
333
334 //-----------------------------------------------------------------------------
335
336 'shiftRows': function() {
337 //a transposition step where each row of the state is shifted cyclically a certain number of steps.
338 varnewValue;
339 vardata;
340 varshiftMapping;
341 vari,c;
342
343 newValue = new Array(16);
344 data = this.data();
345 shiftMapping = Clipperz.Crypto.AES.shiftRowMapping();
346 // [0, 5, 10, 15, 4, 9, 14, 3, 8, 13, 2, 7, 12, 1, 6, 11];
347 c = 16;
348 for (i=0; i<c; i++) {
349 newValue[i] = data[shiftMapping[i]];
350 }
351 for (i=0; i<c; i++) {
352 data[i] = newValue[i];
353 }
354 },
355
356 //-----------------------------------------------------------------------------
357/*
358 'mixColumnsWithValues': function(someValues) {
359 varresult;
360 vara;
361 var i,c;
362
363 c = 4;
364 result = [];
365 a = [];
366 for (i=0; i<c; i++) {
367 a[i] = [];
368 a[i][1] = someValues[i]
369 if ((a[i][1] & 0x80) == 0x80) {
370 a[i][2] = (a[i][1] << 1) ^ 0x11b;
371 } else {
372 a[i][2] = a[i][1] << 1;
373 }
374
375 a[i][3] = a[i][2] ^ a[i][1];
376 }
377
378 for (i=0; i<c; i++) {
379 varx;
380
381 x = Clipperz.Crypto.AES.mixColumnsMatrix()[i];
382 result[i] = a[0][x[0]] ^ a[1][x[1]] ^ a[2][x[2]] ^ a[3][x[3]];
383 }
384
385 return result;
386 },
387
388 'mixColumns': function() {
389 //a mixing operation which operates on the columns of the state, combining the four bytes in each column using a linear transformation.
390 var data;
391 var i, c;
392
393 data = this.data();
394 c = 4;
395 for(i=0; i<c; i++) {
396 varblockIndex;
397 var mixedValues;
398
399 blockIndex = i * 4;
400 mixedValues = this.mixColumnsWithValues([data[blockIndex + 0],
401 data[blockIndex + 1],
402 data[blockIndex + 2],
403 data[blockIndex + 3]]);
404 data[blockIndex + 0] = mixedValues[0];
405 data[blockIndex + 1] = mixedValues[1];
406 data[blockIndex + 2] = mixedValues[2];
407 data[blockIndex + 3] = mixedValues[3];
408 }
409 },
410*/
411
412 'mixColumns': function() {
413 //a mixing operation which operates on the columns of the state, combining the four bytes in each column using a linear transformation.
414 var data;
415 var i, c;
416 var a_1;
417 var a_2;
418
419 a_1 = new Array(4);
420 a_2 = new Array(4);
421
422 data = this.data();
423 c = 4;
424 for(i=0; i<c; i++) {
425 varblockIndex;
426 var ii, cc;
427
428 blockIndex = i * 4;
429
430 cc = 4;
431 for (ii=0; ii<cc; ii++) {
432 var value;
433
434 value = data[blockIndex + ii];
435 a_1[ii] = value;
436 a_2[ii] = (value & 0x80) ? ((value << 1) ^ 0x011b) : (value << 1);
437 }
438
439 data[blockIndex + 0] = a_2[0] ^ a_1[1] ^ a_2[1] ^ a_1[2] ^ a_1[3];
440 data[blockIndex + 1] = a_1[0] ^ a_2[1] ^ a_1[2] ^ a_2[2] ^ a_1[3];
441 data[blockIndex + 2] = a_1[0] ^ a_1[1] ^ a_2[2] ^ a_1[3] ^ a_2[3];
442 data[blockIndex + 3] = a_1[0] ^ a_2[0] ^ a_1[1] ^ a_1[2] ^ a_2[3];
443 }
444 },
445
446 //=========================================================================
447
448 'spinRound': function(aRoundNumber) {
449 this.addRoundKey(aRoundNumber);
450 this.subBytes();
451 this.shiftRows();
452 this.mixColumns();
453 },
454
455 'spinLastRound': function() {
456 this.addRoundKey(this.key().numberOfRounds() - 1);
457 this.subBytes();
458 this.shiftRows();
459 this.addRoundKey(this.key().numberOfRounds());
460 },
461
462 //=========================================================================
463
464 'encrypt': function() {
465 vari,c;
466
467 c = this.key().numberOfRounds() - 1;
468 for (i=0; i<c; i++) {
469 this.spinRound(i);
470 }
471
472 this.spinLastRound();
473 },
474
475 //=========================================================================
476 __syntaxFix__: "syntax fix"
477});
478
479//#############################################################################
480
481Clipperz.Crypto.AES.VERSION = "0.1";
482Clipperz.Crypto.AES.NAME = "Clipperz.Crypto.AES";
483
484MochiKit.Base.update(Clipperz.Crypto.AES, {
485
486 //http://www.cs.eku.edu/faculty/styer/460/Encrypt/JS-AES.html
487 //http://en.wikipedia.org/wiki/Advanced_Encryption_Standard
488 //http://en.wikipedia.org/wiki/Rijndael_key_schedule
489 //http://en.wikipedia.org/wiki/Rijndael_S-box
490
491 '__repr__': function () {
492 return "[" + this.NAME + " " + this.VERSION + "]";
493 },
494
495 'toString': function () {
496 return this.__repr__();
497 },
498
499 //=============================================================================
500
501 '_sbox': null,
502 'sbox': function() {
503 if (Clipperz.Crypto.AES._sbox == null) {
504 Clipperz.Crypto.AES._sbox = [
5050x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76,
5060xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0,
5070xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15,
5080x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75,
5090x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84,
5100x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf,
5110xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8,
5120x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2,
5130xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73,
5140x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb,
5150xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79,
5160xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08,
5170xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a,
5180x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e,
5190xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf,
5200x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16
521 ];
522 }
523
524 return Clipperz.Crypto.AES._sbox;
525 },
526
527 //-----------------------------------------------------------------------------
528 //
529 // 0 4 8 12 0 4 812
530 // 1 5 9 13 => 5 9 131
531 // 2 6 10 14 10 14 26
532 // 3 7 11 15 15 3 711
533 //
534 '_shiftRowMapping': null,
535 'shiftRowMapping': function() {
536 if (Clipperz.Crypto.AES._shiftRowMapping == null) {
537 Clipperz.Crypto.AES._shiftRowMapping = [0, 5, 10, 15, 4, 9, 14, 3, 8, 13, 2, 7, 12, 1, 6, 11];
538 }
539
540 return Clipperz.Crypto.AES._shiftRowMapping;
541 },
542
543 //-----------------------------------------------------------------------------
544
545 '_mixColumnsMatrix': null,
546 'mixColumnsMatrix': function() {
547 if (Clipperz.Crypto.AES._mixColumnsMatrix == null) {
548 Clipperz.Crypto.AES._mixColumnsMatrix = [[2, 3, 1 ,1],
549 [1, 2, 3, 1],
550 [1, 1, 2, 3],
551 [3, 1, 1, 2] ];
552 }
553
554 return Clipperz.Crypto.AES._mixColumnsMatrix;
555 },
556
557 '_roundConstants': null,
558 'roundConstants': function() {
559 if (Clipperz.Crypto.AES._roundConstants == null) {
560 Clipperz.Crypto.AES._roundConstants = [ , 1, 2, 4, 8, 16, 32, 64, 128, 27, 54, 108, 216, 171, 77, 154];
561 // Clipperz.Crypto.AES._roundConstants = [ , 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a];
562 }
563
564 return Clipperz.Crypto.AES._roundConstants;
565 },
566
567 //=============================================================================
568
569 'incrementNonce': function(aNonce) {
570//Clipperz.Profile.start("Clipperz.Crypto.AES.incrementNonce");
571 var i;
572 var done;
573
574 done = false;
575 i = aNonce.length - 1;
576
577 while ((i>=0) && (done == false)) {
578 var currentByteValue;
579
580 currentByteValue = aNonce[i];
581
582 if (currentByteValue == 0xff) {
583 aNonce[i] = 0;
584 if (i>= 0) {
585 i --;
586 } else {
587 done = true;
588 }
589 } else {
590 aNonce[i] = currentByteValue + 1;
591 done = true;
592 }
593 }
594//Clipperz.Profile.stop("Clipperz.Crypto.AES.incrementNonce");
595 },
596
597 //-----------------------------------------------------------------------------
598
599 'encryptBlock': function(aKey, aBlock) {
600 varresult;
601 varstate;
602
603 state = new Clipperz.Crypto.AES.State({block:aBlock, key:aKey});
604//is(state.data(), 'before');
605 state.encrypt();
606 result = state.data();
607
608 return result;
609 },
610
611 //-----------------------------------------------------------------------------
612
613 'encryptBlocks': function(aKey, aMessage, aNonce) {
614 varresult;
615 var nonce;
616 var self;
617 varmessageIndex;
618 varmessageLength;
619 var blockSize;
620
621 self = Clipperz.Crypto.AES;
622 blockSize = 128/8;
623 messageLength = aMessage.length;
624 nonce = aNonce;
625
626 result = aMessage;
627 messageIndex = 0;
628 while (messageIndex < messageLength) {
629 var encryptedBlock;
630 var i,c;
631
632 self.incrementNonce(nonce);
633 encryptedBlock = self.encryptBlock(aKey, nonce);
634
635 if ((messageLength - messageIndex) > blockSize) {
636 c = blockSize;
637 } else {
638 c = messageLength - messageIndex;
639 }
640
641 for (i=0; i<c; i++) {
642 result[messageIndex + i] = result[messageIndex + i] ^ encryptedBlock[i];
643 }
644
645 messageIndex += blockSize;
646 }
647
648 return result;
649 },
650
651 //-----------------------------------------------------------------------------
652
653 'encrypt': function(aKey, someData, aNonce) {
654 var result;
655 var nonce;
656 varencryptedData;
657 var key;
658
659 key = new Clipperz.Crypto.AES.Key({key:aKey});
660 nonce = aNonce ? aNonce.clone() : Clipperz.Crypto.PRNG.defaultRandomGenerator().getRandomBytes(128/8);
661
662 encryptedData = Clipperz.Crypto.AES.encryptBlocks(key, someData.arrayValues(), nonce.arrayValues());
663
664 result = nonce.appendBytes(encryptedData);
665
666 return result;
667 },
668
669 //-----------------------------------------------------------------------------
670
671 'decrypt': function(aKey, someData) {
672 var result;
673 var nonce;
674 var encryptedData;
675 var decryptedData;
676 vardataIterator;
677 var key;
678
679 key = new Clipperz.Crypto.AES.Key({key:aKey});
680
681 encryptedData = someData.arrayValues();
682 nonce = encryptedData.slice(0, (128/8));
683 encryptedData = encryptedData.slice(128/8);
684 decryptedData = Clipperz.Crypto.AES.encryptBlocks(key, encryptedData, nonce);
685
686 result = new Clipperz.ByteArray(decryptedData);
687
688 return result;
689 },
690
691 //=============================================================================
692
693 'deferredEncryptExecutionChunk': function(anExecutionContext) {
694 varresult;
695 var nonce;
696 var self;
697 varmessageIndex;
698 varmessageLength;
699 var blockSize;
700 var executionLimit;
701
702 self = Clipperz.Crypto.AES;
703 blockSize = 128/8;
704 messageLength = anExecutionContext.messageArray().length;
705 nonce = anExecutionContext.nonceArray();
706 result = anExecutionContext.resultArray();
707
708 messageIndex = anExecutionContext.executionStep();
709 executionLimit = messageIndex + anExecutionContext.elaborationChunkSize();
710 executionLimit = Math.min(executionLimit, messageLength);
711
712 while (messageIndex < executionLimit) {
713 var encryptedBlock;
714 var i,c;
715
716 self.incrementNonce(nonce);
717 encryptedBlock = self.encryptBlock(anExecutionContext.key(), nonce);
718
719 if ((executionLimit - messageIndex) > blockSize) {
720 c = blockSize;
721 } else {
722 c = executionLimit - messageIndex;
723 }
724
725 for (i=0; i<c; i++) {
726 result[messageIndex + i] = result[messageIndex + i] ^ encryptedBlock[i];
727 }
728
729 messageIndex += blockSize;
730 }
731 anExecutionContext.setExecutionStep(messageIndex);
732
733 return anExecutionContext;
734 },
735
736 //-----------------------------------------------------------------------------
737
738 'deferredEncryptBlocks': function(anExecutionContext) {
739 vardeferredResult;
740 varmessageSize;
741 var i,c;
742 var now;
743
744 messageSize = anExecutionContext.messageLength();
745
746 deferredResult = new MochiKit.Async.Deferred();
747//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("Clipperz.Crypto.AES.deferredEncryptBlocks - START: " + res); return res;});
748 // deferredResult.addCallback(MochiKit.Base.method(anExecutionContext, 'pause'));
749
750 c = Math.ceil(messageSize / anExecutionContext.elaborationChunkSize());
751 for (i=0; i<c; i++) {
752//deferredResult.addBoth(function(res) {now = new Date(); return res;});
753//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("Clipperz.Crypto.AES.deferredEncryptBlocks - : (" + i + ") - " + res); return res;});
754 deferredResult.addCallback(Clipperz.Crypto.AES.deferredEncryptExecutionChunk);
755//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("[" + (new Date() - now) + "]Clipperz.Crypto.AES.deferredEncryptBlocks"); return res;});
756//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("Clipperz.Crypto.AES.deferredEncryptBlocks - : (" + i + ") -- " + res); return res;});
757 deferredResult.addCallback(MochiKit.Base.method(anExecutionContext, 'pause'));
758//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("Clipperz.Crypto.AES.deferredEncryptBlocks - : (" + i + ") --- " + res); return res;});
759 }
760//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("Clipperz.Crypto.AES.deferredEncryptBlocks - END: " + res); return res;});
761
762 deferredResult.callback(anExecutionContext);
763
764 return deferredResult;
765 },
766
767 //-----------------------------------------------------------------------------
768
769 'deferredEncrypt': function(aKey, someData, aNonce) {
770 var deferredResult;
771 varexecutionContext;
772 var result;
773 var nonce;
774 var key;
775
776 key = new Clipperz.Crypto.AES.Key({key:aKey});
777 nonce = aNonce ? aNonce.clone() : Clipperz.Crypto.PRNG.defaultRandomGenerator().getRandomBytes(128/8);
778
779 executionContext = new Clipperz.Crypto.AES.DeferredExecutionContext({key:key, message:someData, nonce:nonce});
780
781 deferredResult = new MochiKit.Async.Deferred();
782//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("Clipperz.Crypto.AES.deferredEncrypt - 1: " + res); return res;});
783 deferredResult.addCallback(Clipperz.Crypto.AES.deferredEncryptBlocks);
784//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("Clipperz.Crypto.AES.deferredEncrypt - 2: " + res); return res;});
785 deferredResult.addCallback(function(anExecutionContext) {
786 var result;
787
788 result = anExecutionContext.nonce().clone();
789 result.appendBytes(anExecutionContext.resultArray());
790
791 return result;
792 });
793//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("Clipperz.Crypto.AES.deferredEncrypt - 3: " + res); return res;});
794 deferredResult.callback(executionContext)
795
796 return deferredResult;
797 },
798
799 //-----------------------------------------------------------------------------
800
801 'deferredDecrypt': function(aKey, someData) {
802 var deferredResult
803 var nonce;
804 var message;
805 var key;
806
807 key = new Clipperz.Crypto.AES.Key({key:aKey});
808 nonce = someData.split(0, (128/8));
809 message = someData.split(128/8);
810 executionContext = new Clipperz.Crypto.AES.DeferredExecutionContext({key:key, message:message, nonce:nonce});
811
812 deferredResult = new MochiKit.Async.Deferred();
813 deferredResult.addCallback(Clipperz.Crypto.AES.deferredEncryptBlocks);
814 deferredResult.addCallback(function(anExecutionContext) {
815 return anExecutionContext.result();
816 });
817 deferredResult.callback(executionContext);
818
819 return deferredResult;
820 },
821
822 //-----------------------------------------------------------------------------
823 __syntaxFix__: "syntax fix"
824
825});
826
827//#############################################################################
828
829Clipperz.Crypto.AES.DeferredExecution = {
830 'chunkSize': 4096, // 1024 4096 8192 1638432768;
831 'pauseTime': 0.2
832}
833
834Clipperz.Crypto.AES.exception = {
835 'UnsupportedKeySize': new MochiKit.Base.NamedError("Clipperz.Crypto.AES.exception.UnsupportedKeySize")
836};
diff --git a/frontend/beta/js/Clipperz/Crypto/Base.js b/frontend/beta/js/Clipperz/Crypto/Base.js
new file mode 100644
index 0000000..b69dcc8
--- a/dev/null
+++ b/frontend/beta/js/Clipperz/Crypto/Base.js
@@ -0,0 +1,1852 @@
1/*
2
3Copyright 2008-2011 Clipperz Srl
4
5This file is part of Clipperz's Javascript Crypto Library.
6Javascript Crypto Library provides web developers with an extensive
7and efficient set of cryptographic functions. The library aims to
8obtain maximum execution speed while preserving modularity and
9reusability.
10For further information about its features and functionalities please
11refer to http://www.clipperz.com
12
13* Javascript Crypto Library is free software: you can redistribute
14 it and/or modify it under the terms of the GNU Affero General Public
15 License as published by the Free Software Foundation, either version
16 3 of the License, or (at your option) any later version.
17
18* Javascript Crypto Library is distributed in the hope that it will
19 be useful, but WITHOUT ANY WARRANTY; without even the implied
20 warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
21 See the GNU Affero General Public License for more details.
22
23* You should have received a copy of the GNU Affero General Public
24 License along with Javascript Crypto Library. If not, see
25 <http://www.gnu.org/licenses/>.
26
27*/
28
29try { if (typeof(Clipperz.Base) == 'undefined') { throw ""; }} catch (e) {
30 throw "Clipperz.Crypto.Base depends on Clipperz.Base!";
31}
32
33if (typeof(Clipperz.Crypto) == 'undefined') { Clipperz.Crypto = {}; }
34if (typeof(Clipperz.Crypto.Base) == 'undefined') { Clipperz.Crypto.Base = {}; }
35
36Clipperz.Crypto.Base.VERSION = "0.1";
37Clipperz.Crypto.Base.NAME = "Clipperz.Crypto.Base";
38
39//#############################################################################
40 //Downloaded on March 30, 2006 from http://anmar.eu.org/projects/jssha2/files/jssha2-0.3.zip (jsSha2/sha256.js)
41//#############################################################################
42
43/* A JavaScript implementation of the Secure Hash Algorithm, SHA-256
44 * Version 0.3 Copyright Angel Marin 2003-2004 - http://anmar.eu.org/
45 * Distributed under the BSD License
46 * Some bits taken from Paul Johnston's SHA-1 implementation
47 */
48var chrsz = 8; /* bits per input character. 8 - ASCII; 16 - Unicode */
49function safe_add (x, y) {
50 var lsw = (x & 0xFFFF) + (y & 0xFFFF);
51 var msw = (x >> 16) + (y >> 16) + (lsw >> 16);
52 return (msw << 16) | (lsw & 0xFFFF);
53}
54function S (X, n) {return ( X >>> n ) | (X << (32 - n));}
55function R (X, n) {return ( X >>> n );}
56function Ch(x, y, z) {return ((x & y) ^ ((~x) & z));}
57function Maj(x, y, z) {return ((x & y) ^ (x & z) ^ (y & z));}
58function Sigma0256(x) {return (S(x, 2) ^ S(x, 13) ^ S(x, 22));}
59function Sigma1256(x) {return (S(x, 6) ^ S(x, 11) ^ S(x, 25));}
60function Gamma0256(x) {return (S(x, 7) ^ S(x, 18) ^ R(x, 3));}
61function Gamma1256(x) {return (S(x, 17) ^ S(x, 19) ^ R(x, 10));}
62function core_sha256 (m, l) {
63 var K = new Array(0x428A2F98,0x71374491,0xB5C0FBCF,0xE9B5DBA5,0x3956C25B,0x59F111F1,0x923F82A4,0xAB1C5ED5,0xD807AA98,0x12835B01,0x243185BE,0x550C7DC3,0x72BE5D74,0x80DEB1FE,0x9BDC06A7,0xC19BF174,0xE49B69C1,0xEFBE4786,0xFC19DC6,0x240CA1CC,0x2DE92C6F,0x4A7484AA,0x5CB0A9DC,0x76F988DA,0x983E5152,0xA831C66D,0xB00327C8,0xBF597FC7,0xC6E00BF3,0xD5A79147,0x6CA6351,0x14292967,0x27B70A85,0x2E1B2138,0x4D2C6DFC,0x53380D13,0x650A7354,0x766A0ABB,0x81C2C92E,0x92722C85,0xA2BFE8A1,0xA81A664B,0xC24B8B70,0xC76C51A3,0xD192E819,0xD6990624,0xF40E3585,0x106AA070,0x19A4C116,0x1E376C08,0x2748774C,0x34B0BCB5,0x391C0CB3,0x4ED8AA4A,0x5B9CCA4F,0x682E6FF3,0x748F82EE,0x78A5636F,0x84C87814,0x8CC70208,0x90BEFFFA,0xA4506CEB,0xBEF9A3F7,0xC67178F2);
64 var HASH = new Array(0x6A09E667, 0xBB67AE85, 0x3C6EF372, 0xA54FF53A, 0x510E527F, 0x9B05688C, 0x1F83D9AB, 0x5BE0CD19);
65 var W = new Array(64);
66 var a, b, c, d, e, f, g, h, i, j;
67 var T1, T2;
68 /* append padding */
69 m[l >> 5] |= 0x80 << (24 - l % 32);
70 m[((l + 64 >> 9) << 4) + 15] = l;
71 for ( var i = 0; i<m.length; i+=16 ) {
72 a = HASH[0]; b = HASH[1]; c = HASH[2]; d = HASH[3]; e = HASH[4]; f = HASH[5]; g = HASH[6]; h = HASH[7];
73 for ( var j = 0; j<64; j++) {
74 if (j < 16) W[j] = m[j + i];
75 else W[j] = safe_add(safe_add(safe_add(Gamma1256(W[j - 2]), W[j - 7]), Gamma0256(W[j - 15])), W[j - 16]);
76 T1 = safe_add(safe_add(safe_add(safe_add(h, Sigma1256(e)), Ch(e, f, g)), K[j]), W[j]);
77 T2 = safe_add(Sigma0256(a), Maj(a, b, c));
78 h = g; g = f; f = e; e = safe_add(d, T1); d = c; c = b; b = a; a = safe_add(T1, T2);
79 }
80 HASH[0] = safe_add(a, HASH[0]); HASH[1] = safe_add(b, HASH[1]); HASH[2] = safe_add(c, HASH[2]); HASH[3] = safe_add(d, HASH[3]); HASH[4] = safe_add(e, HASH[4]); HASH[5] = safe_add(f, HASH[5]); HASH[6] = safe_add(g, HASH[6]); HASH[7] = safe_add(h, HASH[7]);
81 }
82 return HASH;
83}
84function str2binb (str) {
85 var bin = Array();
86 var mask = (1 << chrsz) - 1;
87 for(var i = 0; i < str.length * chrsz; i += chrsz)
88 bin[i>>5] |= (str.charCodeAt(i / chrsz) & mask) << (24 - i%32);
89 return bin;
90}
91function binb2hex (binarray) {
92 var hexcase = 0; /* hex output format. 0 - lowercase; 1 - uppercase */
93 var hex_tab = hexcase ? "0123456789ABCDEF" : "0123456789abcdef";
94 var str = "";
95 for (var i = 0; i < binarray.length * 4; i++) {
96 str += hex_tab.charAt((binarray[i>>2] >> ((3 - i%4)*8+4)) & 0xF) + hex_tab.charAt((binarray[i>>2] >> ((3 - i%4)*8 )) & 0xF);
97 }
98 return str;
99}
100function hex_sha256(s){return binb2hex(core_sha256(str2binb(s),s.length * chrsz));}
101
102
103
104//#############################################################################
105 //Downloaded on March 30, 2006 from http://www.fourmilab.ch/javascrypt/javascrypt.zip (entropy.js)
106//#############################################################################
107
108 // Entropy collection utilities
109
110 /*Start by declaring static storage and initialise
111 the entropy vector from the time we come through
112 here. */
113
114 var entropyData = new Array(); // Collected entropy data
115 var edlen = 0; // Keyboard array data length
116
117 addEntropyTime(); // Start entropy collection with page load time
118 ce(); // Roll milliseconds into initial entropy
119
120 //Add a byte to the entropy vector
121
122 function addEntropyByte(b) {
123 entropyData[edlen++] = b;
124 }
125
126 /*Capture entropy. When the user presses a key or performs
127 various other events for which we can request
128 notification, add the time in 255ths of a second to the
129 entropyData array. The name of the function is short
130 so it doesn't bloat the form object declarations in
131 which it appears in various "onXXX" events. */
132
133 function ce() {
134 addEntropyByte(Math.floor((((new Date).getMilliseconds()) * 255) / 999));
135 }
136
137 //Add a 32 bit quantity to the entropy vector
138
139 function addEntropy32(w) {
140 var i;
141
142 for (i = 0; i < 4; i++) {
143 addEntropyByte(w & 0xFF);
144 w >>= 8;
145 }
146 }
147
148 /*Add the current time and date (milliseconds since the epoch,
149 truncated to 32 bits) to the entropy vector. */
150
151 function addEntropyTime() {
152 addEntropy32((new Date()).getTime());
153 }
154
155 /* Start collection of entropy from mouse movements. The
156 argument specifies the number of entropy items to be
157 obtained from mouse motion, after which mouse motion
158 will be ignored. Note that you can re-enable mouse
159 motion collection at any time if not already underway. */
160
161 var mouseMotionCollect = 0;
162 var oldMoveHandler; // For saving and restoring mouse move handler in IE4
163
164 function mouseMotionEntropy(maxsamp) {
165 if (mouseMotionCollect <= 0) {
166 mouseMotionCollect = maxsamp;
167 if ((document.implementation.hasFeature("Events", "2.0")) &&
168 document.addEventListener) {
169 // Browser supports Document Object Model (DOM) 2 events
170 document.addEventListener("mousemove", mouseMoveEntropy, false);
171 } else {
172 if (document.attachEvent) {
173 // Internet Explorer 5 and above event model
174 document.attachEvent("onmousemove", mouseMoveEntropy);
175 } else {
176 //Internet Explorer 4 event model
177 oldMoveHandler = document.onmousemove;
178 document.onmousemove = mouseMoveEntropy;
179 }
180 }
181//dump("Mouse enable", mouseMotionCollect);
182 }
183 }
184
185 /*Collect entropy from mouse motion events. Note that
186 this is craftily coded to work with either DOM2 or Internet
187 Explorer style events. Note that we don't use every successive
188 mouse movement event. Instead, we XOR the three bytes collected
189 from the mouse and use that to determine how many subsequent
190 mouse movements we ignore before capturing the next one. */
191
192 var mouseEntropyTime = 0; // Delay counter for mouse entropy collection
193
194 function mouseMoveEntropy(e) {
195 if (!e) {
196 e = window.event; // Internet Explorer event model
197 }
198 if (mouseMotionCollect > 0) {
199 if (mouseEntropyTime-- <= 0) {
200 addEntropyByte(e.screenX & 0xFF);
201 addEntropyByte(e.screenY & 0xFF);
202 ce();
203 mouseMotionCollect--;
204 mouseEntropyTime = (entropyData[edlen - 3] ^ entropyData[edlen - 2] ^
205 entropyData[edlen - 1]) % 19;
206//dump("Mouse Move", byteArrayToHex(entropyData.slice(-3)));
207 }
208 if (mouseMotionCollect <= 0) {
209 if (document.removeEventListener) {
210 document.removeEventListener("mousemove", mouseMoveEntropy, false);
211 } else if (document.detachEvent) {
212 document.detachEvent("onmousemove", mouseMoveEntropy);
213 } else {
214 document.onmousemove = oldMoveHandler;
215 }
216//dump("Spung!", 0);
217 }
218 }
219 }
220
221 /*Compute a 32 byte key value from the entropy vector.
222 We compute the value by taking the MD5 sum of the even
223 and odd bytes respectively of the entropy vector, then
224 concatenating the two MD5 sums. */
225
226 function keyFromEntropy() {
227 var i, k = new Array(32);
228
229 if (edlen == 0) {
230 alert("Blooie! Entropy vector void at call to keyFromEntropy.");
231 }
232//dump("Entropy bytes", edlen);
233
234 md5_init();
235 for (i = 0; i < edlen; i += 2) {
236 md5_update(entropyData[i]);
237 }
238 md5_finish();
239 for (i = 0; i < 16; i++) {
240 k[i] = digestBits[i];
241 }
242
243 md5_init();
244 for (i = 1; i < edlen; i += 2) {
245 md5_update(entropyData[i]);
246 }
247 md5_finish();
248 for (i = 0; i < 16; i++) {
249 k[i + 16] = digestBits[i];
250 }
251
252//dump("keyFromEntropy", byteArrayToHex(k));
253 return k;
254 }
255
256//#############################################################################
257 //Downloaded on March 30, 2006 from http://www.fourmilab.ch/javascrypt/javascrypt.zip (aesprng.js)
258//#############################################################################
259
260
261 // AES based pseudorandom number generator
262
263 /* Constructor. Called with an array of 32 byte (0-255) values
264 containing the initial seed. */
265
266 function AESprng(seed) {
267 this.key = new Array();
268 this.key = seed;
269 this.itext = hexToByteArray("9F489613248148F9C27945C6AE62EECA3E3367BB14064E4E6DC67A9F28AB3BD1");
270 this.nbytes = 0; // Bytes left in buffer
271
272 this.next = AESprng_next;
273 this.nextbits = AESprng_nextbits;
274 this.nextInt = AESprng_nextInt;
275 this.round = AESprng_round;
276
277 /* Encrypt the initial text with the seed key
278 three times, feeding the output of the encryption
279 back into the key for the next round. */
280
281 bsb = blockSizeInBits;
282 blockSizeInBits = 256;
283 var i, ct;
284 for (i = 0; i < 3; i++) {
285 this.key = rijndaelEncrypt(this.itext, this.key, "ECB");
286 }
287
288 /* Now make between one and four additional
289 key-feedback rounds, with the number determined
290 by bits from the result of the first three
291 rounds. */
292
293 var n = 1 + (this.key[3] & 2) + (this.key[9] & 1);
294 for (i = 0; i < n; i++) {
295 this.key = rijndaelEncrypt(this.itext, this.key, "ECB");
296 }
297 blockSizeInBits = bsb;
298 }
299
300 function AESprng_round() {
301 bsb = blockSizeInBits;
302 blockSizeInBits = 256;
303 this.key = rijndaelEncrypt(this.itext, this.key, "ECB");
304 this.nbytes = 32;
305 blockSizeInBits = bsb;
306 }
307
308 //Return next byte from the generator
309
310 function AESprng_next() {
311 if (this.nbytes <= 0) {
312 this.round();
313 }
314 return(this.key[--this.nbytes]);
315 }
316
317 //Return n bit integer value (up to maximum integer size)
318
319 function AESprng_nextbits(n) {
320 var i, w = 0, nbytes = Math.floor((n + 7) / 8);
321
322 for (i = 0; i < nbytes; i++) {
323 w = (w << 8) | this.next();
324 }
325 return w & ((1 << n) - 1);
326 }
327
328 // Return integer between 0 and n inclusive
329
330 function AESprng_nextInt(n) {
331 var p = 1, nb = 0;
332
333 // Determine smallest p, 2^p > n
334 // nb = log_2 p
335
336 while (n >= p) {
337 p <<= 1;
338 nb++;
339 }
340 p--;
341
342 /* Generate values from 0 through n by first generating
343 values v from 0 to (2^p)-1, then discarding any results v > n.
344 For the rationale behind this (and why taking
345 values mod (n + 1) is biased toward smaller values, see
346 Ferguson and Schneier, "Practical Cryptography",
347 ISBN 0-471-22357-3, section 10.8). */
348
349 while (true) {
350 var v = this.nextbits(nb) & p;
351
352 if (v <= n) {
353 return v;
354 }
355 }
356 }
357
358//#############################################################################
359 //Downloaded on March 30, 2006 from http://www.fourmilab.ch/javascrypt/javascrypt.zip (md5.js)
360//#############################################################################
361
362/*
363 * md5.jvs 1.0b 27/06/96
364 *
365 * Javascript implementation of the RSA Data Security, Inc. MD5
366 * Message-Digest Algorithm.
367 *
368 * Copyright (c) 1996 Henri Torgemane. All Rights Reserved.
369 *
370 * Permission to use, copy, modify, and distribute this software
371 * and its documentation for any purposes and without
372 * fee is hereby granted provided that this copyright notice
373 * appears in all copies.
374 *
375 * Of course, this soft is provided "as is" without express or implied
376 * warranty of any kind.
377
378 This version contains some trivial reformatting modifications
379 by John Walker.
380
381 */
382
383function array(n) {
384 for (i = 0; i < n; i++) {
385 this[i] = 0;
386 }
387 this.length = n;
388}
389
390/* Some basic logical functions had to be rewritten because of a bug in
391 * Javascript.. Just try to compute 0xffffffff >> 4 with it..
392 * Of course, these functions are slower than the original would be, but
393 * at least, they work!
394 */
395
396function integer(n) {
397 return n % (0xffffffff + 1);
398}
399
400function shr(a, b) {
401 a = integer(a);
402 b = integer(b);
403 if (a - 0x80000000 >= 0) {
404 a = a % 0x80000000;
405 a >>= b;
406 a += 0x40000000 >> (b - 1);
407 } else {
408 a >>= b;
409 }
410 return a;
411}
412
413function shl1(a) {
414 a = a % 0x80000000;
415 if (a & 0x40000000 == 0x40000000) {
416 a -= 0x40000000;
417 a *= 2;
418 a += 0x80000000;
419 } else {
420 a *= 2;
421 }
422 return a;
423}
424
425function shl(a, b) {
426 a = integer(a);
427 b = integer(b);
428 for (var i = 0; i < b; i++) {
429 a = shl1(a);
430 }
431 return a;
432}
433
434function and(a, b) {
435 a = integer(a);
436 b = integer(b);
437 var t1 = a - 0x80000000;
438 var t2 = b - 0x80000000;
439 if (t1 >= 0) {
440 if (t2 >= 0) {
441 return ((t1 & t2) + 0x80000000);
442 } else {
443 return (t1 & b);
444 }
445 } else {
446 if (t2 >= 0) {
447 return (a & t2);
448 } else {
449 return (a & b);
450 }
451 }
452}
453
454function or(a, b) {
455 a = integer(a);
456 b = integer(b);
457 var t1 = a - 0x80000000;
458 var t2 = b - 0x80000000;
459 if (t1 >= 0) {
460 if (t2 >= 0) {
461 return ((t1 | t2) + 0x80000000);
462 } else {
463 return ((t1 | b) + 0x80000000);
464 }
465 } else {
466 if (t2 >= 0) {
467 return ((a | t2) + 0x80000000);
468 } else {
469 return (a | b);
470 }
471 }
472}
473
474function xor(a, b) {
475 a = integer(a);
476 b = integer(b);
477 var t1 = a - 0x80000000;
478 var t2 = b - 0x80000000;
479 if (t1 >= 0) {
480 if (t2 >= 0) {
481 return (t1 ^ t2);
482 } else {
483 return ((t1 ^ b) + 0x80000000);
484 }
485 } else {
486 if (t2 >= 0) {
487 return ((a ^ t2) + 0x80000000);
488 } else {
489 return (a ^ b);
490 }
491 }
492}
493
494function not(a) {
495 a = integer(a);
496 return 0xffffffff - a;
497}
498
499/* Here begin the real algorithm */
500
501var state = new array(4);
502var count = new array(2);
503 count[0] = 0;
504 count[1] = 0;
505var buffer = new array(64);
506var transformBuffer = new array(16);
507var digestBits = new array(16);
508
509var S11 = 7;
510var S12 = 12;
511var S13 = 17;
512var S14 = 22;
513var S21 = 5;
514var S22 = 9;
515var S23 = 14;
516var S24 = 20;
517var S31 = 4;
518var S32 = 11;
519var S33 = 16;
520var S34 = 23;
521var S41 = 6;
522var S42 = 10;
523var S43 = 15;
524var S44 = 21;
525
526function F(x, y, z) {
527 return or(and(x, y), and(not(x), z));
528}
529
530function G(x, y, z) {
531 return or(and(x, z), and(y, not(z)));
532}
533
534function H(x, y, z) {
535 return xor(xor(x, y), z);
536}
537
538function I(x, y, z) {
539 return xor(y ,or(x , not(z)));
540}
541
542function rotateLeft(a, n) {
543 return or(shl(a, n), (shr(a, (32 - n))));
544}
545
546function FF(a, b, c, d, x, s, ac) {
547 a = a + F(b, c, d) + x + ac;
548 a = rotateLeft(a, s);
549 a = a + b;
550 return a;
551}
552
553function GG(a, b, c, d, x, s, ac) {
554 a = a + G(b, c, d) + x + ac;
555 a = rotateLeft(a, s);
556 a = a + b;
557 return a;
558}
559
560function HH(a, b, c, d, x, s, ac) {
561 a = a + H(b, c, d) + x + ac;
562 a = rotateLeft(a, s);
563 a = a + b;
564 return a;
565}
566
567function II(a, b, c, d, x, s, ac) {
568 a = a + I(b, c, d) + x + ac;
569 a = rotateLeft(a, s);
570 a = a + b;
571 return a;
572}
573
574function transform(buf, offset) {
575 var a = 0, b = 0, c = 0, d = 0;
576 var x = transformBuffer;
577
578 a = state[0];
579 b = state[1];
580 c = state[2];
581 d = state[3];
582
583 for (i = 0; i < 16; i++) {
584 x[i] = and(buf[i * 4 + offset], 0xFF);
585 for (j = 1; j < 4; j++) {
586 x[i] += shl(and(buf[i * 4 + j + offset] ,0xFF), j * 8);
587 }
588 }
589
590 /* Round 1 */
591 a = FF( a, b, c, d, x[ 0], S11, 0xd76aa478); /* 1 */
592 d = FF( d, a, b, c, x[ 1], S12, 0xe8c7b756); /* 2 */
593 c = FF( c, d, a, b, x[ 2], S13, 0x242070db); /* 3 */
594 b = FF( b, c, d, a, x[ 3], S14, 0xc1bdceee); /* 4 */
595 a = FF( a, b, c, d, x[ 4], S11, 0xf57c0faf); /* 5 */
596 d = FF( d, a, b, c, x[ 5], S12, 0x4787c62a); /* 6 */
597 c = FF( c, d, a, b, x[ 6], S13, 0xa8304613); /* 7 */
598 b = FF( b, c, d, a, x[ 7], S14, 0xfd469501); /* 8 */
599 a = FF( a, b, c, d, x[ 8], S11, 0x698098d8); /* 9 */
600 d = FF( d, a, b, c, x[ 9], S12, 0x8b44f7af); /* 10 */
601 c = FF( c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */
602 b = FF( b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */
603 a = FF( a, b, c, d, x[12], S11, 0x6b901122); /* 13 */
604 d = FF( d, a, b, c, x[13], S12, 0xfd987193); /* 14 */
605 c = FF( c, d, a, b, x[14], S13, 0xa679438e); /* 15 */
606 b = FF( b, c, d, a, x[15], S14, 0x49b40821); /* 16 */
607
608 /* Round 2 */
609 a = GG( a, b, c, d, x[ 1], S21, 0xf61e2562); /* 17 */
610 d = GG( d, a, b, c, x[ 6], S22, 0xc040b340); /* 18 */
611 c = GG( c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */
612 b = GG( b, c, d, a, x[ 0], S24, 0xe9b6c7aa); /* 20 */
613 a = GG( a, b, c, d, x[ 5], S21, 0xd62f105d); /* 21 */
614 d = GG( d, a, b, c, x[10], S22, 0x2441453); /* 22 */
615 c = GG( c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */
616 b = GG( b, c, d, a, x[ 4], S24, 0xe7d3fbc8); /* 24 */
617 a = GG( a, b, c, d, x[ 9], S21, 0x21e1cde6); /* 25 */
618 d = GG( d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */
619 c = GG( c, d, a, b, x[ 3], S23, 0xf4d50d87); /* 27 */
620 b = GG( b, c, d, a, x[ 8], S24, 0x455a14ed); /* 28 */
621 a = GG( a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */
622 d = GG( d, a, b, c, x[ 2], S22, 0xfcefa3f8); /* 30 */
623 c = GG( c, d, a, b, x[ 7], S23, 0x676f02d9); /* 31 */
624 b = GG( b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */
625
626 /* Round 3 */
627 a = HH( a, b, c, d, x[ 5], S31, 0xfffa3942); /* 33 */
628 d = HH( d, a, b, c, x[ 8], S32, 0x8771f681); /* 34 */
629 c = HH( c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */
630 b = HH( b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */
631 a = HH( a, b, c, d, x[ 1], S31, 0xa4beea44); /* 37 */
632 d = HH( d, a, b, c, x[ 4], S32, 0x4bdecfa9); /* 38 */
633 c = HH( c, d, a, b, x[ 7], S33, 0xf6bb4b60); /* 39 */
634 b = HH( b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */
635 a = HH( a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */
636 d = HH( d, a, b, c, x[ 0], S32, 0xeaa127fa); /* 42 */
637 c = HH( c, d, a, b, x[ 3], S33, 0xd4ef3085); /* 43 */
638 b = HH( b, c, d, a, x[ 6], S34, 0x4881d05); /* 44 */
639 a = HH( a, b, c, d, x[ 9], S31, 0xd9d4d039); /* 45 */
640 d = HH( d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */
641 c = HH( c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */
642 b = HH( b, c, d, a, x[ 2], S34, 0xc4ac5665); /* 48 */
643
644 /* Round 4 */
645 a = II( a, b, c, d, x[ 0], S41, 0xf4292244); /* 49 */
646 d = II( d, a, b, c, x[ 7], S42, 0x432aff97); /* 50 */
647 c = II( c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */
648 b = II( b, c, d, a, x[ 5], S44, 0xfc93a039); /* 52 */
649 a = II( a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */
650 d = II( d, a, b, c, x[ 3], S42, 0x8f0ccc92); /* 54 */
651 c = II( c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */
652 b = II( b, c, d, a, x[ 1], S44, 0x85845dd1); /* 56 */
653 a = II( a, b, c, d, x[ 8], S41, 0x6fa87e4f); /* 57 */
654 d = II( d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */
655 c = II( c, d, a, b, x[ 6], S43, 0xa3014314); /* 59 */
656 b = II( b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */
657 a = II( a, b, c, d, x[ 4], S41, 0xf7537e82); /* 61 */
658 d = II( d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */
659 c = II( c, d, a, b, x[ 2], S43, 0x2ad7d2bb); /* 63 */
660 b = II( b, c, d, a, x[ 9], S44, 0xeb86d391); /* 64 */
661
662 state[0] += a;
663 state[1] += b;
664 state[2] += c;
665 state[3] += d;
666
667}
668
669function md5_init() {
670 count[0] = count[1] = 0;
671 state[0] = 0x67452301;
672 state[1] = 0xefcdab89;
673 state[2] = 0x98badcfe;
674 state[3] = 0x10325476;
675 for (i = 0; i < digestBits.length; i++) {
676 digestBits[i] = 0;
677 }
678}
679
680function md5_update(b) {
681 var index, i;
682
683 index = and(shr(count[0],3) , 0x3F);
684 if (count[0] < 0xFFFFFFFF - 7) {
685 count[0] += 8;
686 } else {
687 count[1]++;
688 count[0] -= 0xFFFFFFFF + 1;
689 count[0] += 8;
690 }
691 buffer[index] = and(b, 0xff);
692 if (index >= 63) {
693 transform(buffer, 0);
694 }
695}
696
697function md5_finish() {
698 var bits = new array(8);
699 var padding;
700 var i = 0, index = 0, padLen = 0;
701
702 for (i = 0; i < 4; i++) {
703 bits[i] = and(shr(count[0], (i * 8)), 0xFF);
704 }
705 for (i = 0; i < 4; i++) {
706 bits[i + 4] = and(shr(count[1], (i * 8)), 0xFF);
707 }
708 index = and(shr(count[0], 3), 0x3F);
709 padLen = (index < 56) ? (56 - index) : (120 - index);
710 padding = new array(64);
711 padding[0] = 0x80;
712 for (i = 0; i < padLen; i++) {
713 md5_update(padding[i]);
714 }
715 for (i = 0; i < 8; i++) {
716 md5_update(bits[i]);
717 }
718
719 for (i = 0; i < 4; i++) {
720 for (j = 0; j < 4; j++) {
721 digestBits[i * 4 + j] = and(shr(state[i], (j * 8)) , 0xFF);
722 }
723 }
724}
725
726/* End of the MD5 algorithm */
727
728//#############################################################################
729 //Downloaded on March 30, 2006 from http://www.fourmilab.ch/javascrypt/javascrypt.zip (aes.js)
730//#############################################################################
731
732
733/* rijndael.js Rijndael Reference Implementation
734
735 This is a modified version of the software described below,
736 produced in September 2003 by John Walker for use in the
737 JavsScrypt browser-based encryption package. The principal
738 changes are replacing the original getRandomBytes function with
739 one which calls our pseudorandom generator (which must
740 be instantiated and seeded before the first call on getRandomBytes),
741 and changing keySizeInBits to 256. Some code not required by the
742 JavsScrypt application has been commented out. Please see
743 http://www.fourmilab.ch/javascrypt/ for further information on
744 JavaScrypt.
745
746 The following is the original copyright and application
747 information.
748
749 Copyright (c) 2001 Fritz Schneider
750
751 This software is provided as-is, without express or implied warranty.
752 Permission to use, copy, modify, distribute or sell this software, with or
753 without fee, for any purpose and by any individual or organization, is hereby
754 granted, provided that the above copyright notice and this paragraph appear
755 in all copies. Distribution as a part of an application or binary must
756 include the above copyright notice in the documentation and/or other materials
757 provided with the application or distribution.
758
759 As the above disclaimer notes, you are free to use this code however you
760 want. However, I would request that you send me an email
761 (fritz /at/ cs /dot/ ucsd /dot/ edu) to say hi if you find this code useful
762 or instructional. Seeing that people are using the code acts as
763 encouragement for me to continue development. If you *really* want to thank
764 me you can buy the book I wrote with Thomas Powell, _JavaScript:
765 _The_Complete_Reference_ :)
766
767 This code is an UNOPTIMIZED REFERENCE implementation of Rijndael.
768 If there is sufficient interest I can write an optimized (word-based,
769 table-driven) version, although you might want to consider using a
770 compiled language if speed is critical to your application. As it stands,
771 one run of the monte carlo test (10,000 encryptions) can take up to
772 several minutes, depending upon your processor. You shouldn't expect more
773 than a few kilobytes per second in throughput.
774
775 Also note that there is very little error checking in these functions.
776 Doing proper error checking is always a good idea, but the ideal
777 implementation (using the instanceof operator and exceptions) requires
778 IE5+/NS6+, and I've chosen to implement this code so that it is compatible
779 with IE4/NS4.
780
781 And finally, because JavaScript doesn't have an explicit byte/char data
782 type (although JavaScript 2.0 most likely will), when I refer to "byte"
783 in this code I generally mean "32 bit integer with value in the interval
784 [0,255]" which I treat as a byte.
785
786 See http://www-cse.ucsd.edu/~fritz/rijndael.html for more documentation
787 of the (very simple) API provided by this code.
788
789 Fritz Schneider
790 fritz at cs.ucsd.edu
791
792*/
793
794
795// Rijndael parameters -- Valid values are 128, 192, or 256
796
797var keySizeInBits = 256;
798var blockSizeInBits = 128;
799
800//
801// Note: in the following code the two dimensional arrays are indexed as
802// you would probably expect, as array[row][column]. The state arrays
803// are 2d arrays of the form state[4][Nb].
804
805
806// The number of rounds for the cipher, indexed by [Nk][Nb]
807var roundsArray = [ ,,,,[,,,,10,, 12,, 14],,
808 [,,,,12,, 12,, 14],,
809 [,,,,14,, 14,, 14] ];
810
811// The number of bytes to shift by in shiftRow, indexed by [Nb][row]
812var shiftOffsets = [ ,,,,[,1, 2, 3],,[,1, 2, 3],,[,1, 3, 4] ];
813
814// The round constants used in subkey expansion
815var Rcon = [
8160x01, 0x02, 0x04, 0x08, 0x10, 0x20,
8170x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8,
8180xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc,
8190x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4,
8200xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91 ];
821
822// Precomputed lookup table for the SBox
823var SBox = [
824 99, 124, 119, 123, 242, 107, 111, 197, 48, 1, 103, 43, 254, 215, 171,
825118, 202, 130, 201, 125, 250, 89, 71, 240, 173, 212, 162, 175, 156, 164,
826114, 192, 183, 253, 147, 38, 54, 63, 247, 204, 52, 165, 229, 241, 113,
827216, 49, 21, 4, 199, 35, 195, 24, 150, 5, 154, 7, 18, 128, 226,
828235, 39, 178, 117, 9, 131, 44, 26, 27, 110, 90, 160, 82, 59, 214,
829179, 41, 227, 47, 132, 83, 209, 0, 237, 32, 252, 177, 91, 106, 203,
830190, 57, 74, 76, 88, 207, 208, 239, 170, 251, 67, 77, 51, 133, 69,
831249, 2, 127, 80, 60, 159, 168, 81, 163, 64, 143, 146, 157, 56, 245,
832188, 182, 218, 33, 16, 255, 243, 210, 205, 12, 19, 236, 95, 151, 68,
83323, 196, 167, 126, 61, 100, 93, 25, 115, 96, 129, 79, 220, 34, 42,
834144, 136, 70, 238, 184, 20, 222, 94, 11, 219, 224, 50, 58, 10, 73,
835 6, 36, 92, 194, 211, 172, 98, 145, 149, 228, 121, 231, 200, 55, 109,
836141, 213, 78, 169, 108, 86, 244, 234, 101, 122, 174, 8, 186, 120, 37,
837 46, 28, 166, 180, 198, 232, 221, 116, 31, 75, 189, 139, 138, 112, 62,
838181, 102, 72, 3, 246, 14, 97, 53, 87, 185, 134, 193, 29, 158, 225,
839248, 152, 17, 105, 217, 142, 148, 155, 30, 135, 233, 206, 85, 40, 223,
840140, 161, 137, 13, 191, 230, 66, 104, 65, 153, 45, 15, 176, 84, 187,
841 22 ];
842
843// Precomputed lookup table for the inverse SBox
844var SBoxInverse = [
845 82, 9, 106, 213, 48, 54, 165, 56, 191, 64, 163, 158, 129, 243, 215,
846251, 124, 227, 57, 130, 155, 47, 255, 135, 52, 142, 67, 68, 196, 222,
847233, 203, 84, 123, 148, 50, 166, 194, 35, 61, 238, 76, 149, 11, 66,
848250, 195, 78, 8, 46, 161, 102, 40, 217, 36, 178, 118, 91, 162, 73,
849109, 139, 209, 37, 114, 248, 246, 100, 134, 104, 152, 22, 212, 164, 92,
850204, 93, 101, 182, 146, 108, 112, 72, 80, 253, 237, 185, 218, 94, 21,
851 70, 87, 167, 141, 157, 132, 144, 216, 171, 0, 140, 188, 211, 10, 247,
852228, 88, 5, 184, 179, 69, 6, 208, 44, 30, 143, 202, 63, 15, 2,
853193, 175, 189, 3, 1, 19, 138, 107, 58, 145, 17, 65, 79, 103, 220,
854234, 151, 242, 207, 206, 240, 180, 230, 115, 150, 172, 116, 34, 231, 173,
855 53, 133, 226, 249, 55, 232, 28, 117, 223, 110, 71, 241, 26, 113, 29,
856 41, 197, 137, 111, 183, 98, 14, 170, 24, 190, 27, 252, 86, 62, 75,
857198, 210, 121, 32, 154, 219, 192, 254, 120, 205, 90, 244, 31, 221, 168,
858 51, 136, 7, 199, 49, 177, 18, 16, 89, 39, 128, 236, 95, 96, 81,
859127, 169, 25, 181, 74, 13, 45, 229, 122, 159, 147, 201, 156, 239, 160,
860224, 59, 77, 174, 42, 245, 176, 200, 235, 187, 60, 131, 83, 153, 97,
861 23, 43, 4, 126, 186, 119, 214, 38, 225, 105, 20, 99, 85, 33, 12,
862125 ];
863
864// This method circularly shifts the array left by the number of elements
865// given in its parameter. It returns the resulting array and is used for
866// the ShiftRow step. Note that shift() and push() could be used for a more
867// elegant solution, but they require IE5.5+, so I chose to do it manually.
868
869function cyclicShiftLeft(theArray, positions) {
870 var temp = theArray.slice(0, positions);
871 theArray = theArray.slice(positions).concat(temp);
872 return theArray;
873}
874
875// Cipher parameters ... do not change these
876var Nk = keySizeInBits / 32;
877var Nb = blockSizeInBits / 32;
878var Nr = roundsArray[Nk][Nb];
879
880// Multiplies the element "poly" of GF(2^8) by x. See the Rijndael spec.
881
882function xtime(poly) {
883 poly <<= 1;
884 return ((poly & 0x100) ? (poly ^ 0x11B) : (poly));
885}
886
887// Multiplies the two elements of GF(2^8) together and returns the result.
888// See the Rijndael spec, but should be straightforward: for each power of
889// the indeterminant that has a 1 coefficient in x, add y times that power
890// to the result. x and y should be bytes representing elements of GF(2^8)
891
892function mult_GF256(x, y) {
893 var bit, result = 0;
894
895 for (bit = 1; bit < 256; bit *= 2, y = xtime(y)) {
896 if (x & bit)
897 result ^= y;
898 }
899 return result;
900}
901
902// Performs the substitution step of the cipher. State is the 2d array of
903// state information (see spec) and direction is string indicating whether
904// we are performing the forward substitution ("encrypt") or inverse
905// substitution (anything else)
906
907function byteSub(state, direction) {
908 var S;
909 if (direction == "encrypt") // Point S to the SBox we're using
910 S = SBox;
911 else
912 S = SBoxInverse;
913 for (var i = 0; i < 4; i++) // Substitute for every byte in state
914 for (var j = 0; j < Nb; j++)
915 state[i][j] = S[state[i][j]];
916}
917
918// Performs the row shifting step of the cipher.
919
920function shiftRow(state, direction) {
921 for (var i=1; i<4; i++) // Row 0 never shifts
922 if (direction == "encrypt")
923 state[i] = cyclicShiftLeft(state[i], shiftOffsets[Nb][i]);
924 else
925 state[i] = cyclicShiftLeft(state[i], Nb - shiftOffsets[Nb][i]);
926
927}
928
929// Performs the column mixing step of the cipher. Most of these steps can
930// be combined into table lookups on 32bit values (at least for encryption)
931// to greatly increase the speed.
932
933function mixColumn(state, direction) {
934 var b = []; // Result of matrix multiplications
935 for (var j = 0; j < Nb; j++) { // Go through each column...
936 for (var i = 0; i < 4; i++) { // and for each row in the column...
937 if (direction == "encrypt")
938 b[i] = mult_GF256(state[i][j], 2) ^ // perform mixing
939 mult_GF256(state[(i+1)%4][j], 3) ^
940 state[(i+2)%4][j] ^
941 state[(i+3)%4][j];
942 else
943 b[i] = mult_GF256(state[i][j], 0xE) ^
944 mult_GF256(state[(i+1)%4][j], 0xB) ^
945 mult_GF256(state[(i+2)%4][j], 0xD) ^
946 mult_GF256(state[(i+3)%4][j], 9);
947 }
948 for (var i = 0; i < 4; i++) // Place result back into column
949 state[i][j] = b[i];
950 }
951}
952
953// Adds the current round key to the state information. Straightforward.
954
955function addRoundKey(state, roundKey) {
956 for (var j = 0; j < Nb; j++) { // Step through columns...
957 state[0][j] ^= (roundKey[j] & 0xFF); // and XOR
958 state[1][j] ^= ((roundKey[j]>>8) & 0xFF);
959 state[2][j] ^= ((roundKey[j]>>16) & 0xFF);
960 state[3][j] ^= ((roundKey[j]>>24) & 0xFF);
961 }
962}
963
964// This function creates the expanded key from the input (128/192/256-bit)
965// key. The parameter key is an array of bytes holding the value of the key.
966// The returned value is an array whose elements are the 32-bit words that
967// make up the expanded key.
968
969function keyExpansion(key) {
970 var expandedKey = new Array();
971 var temp;
972
973 // in case the key size or parameters were changed...
974 Nk = keySizeInBits / 32;
975 Nb = blockSizeInBits / 32;
976 Nr = roundsArray[Nk][Nb];
977
978 for (var j=0; j < Nk; j++) // Fill in input key first
979 expandedKey[j] =
980 (key[4*j]) | (key[4*j+1]<<8) | (key[4*j+2]<<16) | (key[4*j+3]<<24);
981
982 // Now walk down the rest of the array filling in expanded key bytes as
983 // per Rijndael's spec
984 for (j = Nk; j < Nb * (Nr + 1); j++) { // For each word of expanded key
985 temp = expandedKey[j - 1];
986 if (j % Nk == 0)
987 temp = ( (SBox[(temp>>8) & 0xFF]) |
988 (SBox[(temp>>16) & 0xFF]<<8) |
989 (SBox[(temp>>24) & 0xFF]<<16) |
990 (SBox[temp & 0xFF]<<24) ) ^ Rcon[Math.floor(j / Nk) - 1];
991 else if (Nk > 6 && j % Nk == 4)
992 temp = (SBox[(temp>>24) & 0xFF]<<24) |
993 (SBox[(temp>>16) & 0xFF]<<16) |
994 (SBox[(temp>>8) & 0xFF]<<8) |
995 (SBox[temp & 0xFF]);
996 expandedKey[j] = expandedKey[j-Nk] ^ temp;
997 }
998 return expandedKey;
999}
1000
1001// Rijndael's round functions...
1002
1003function Round(state, roundKey) {
1004 byteSub(state, "encrypt");
1005 shiftRow(state, "encrypt");
1006 mixColumn(state, "encrypt");
1007 addRoundKey(state, roundKey);
1008}
1009
1010function InverseRound(state, roundKey) {
1011 addRoundKey(state, roundKey);
1012 mixColumn(state, "decrypt");
1013 shiftRow(state, "decrypt");
1014 byteSub(state, "decrypt");
1015}
1016
1017function FinalRound(state, roundKey) {
1018 byteSub(state, "encrypt");
1019 shiftRow(state, "encrypt");
1020 addRoundKey(state, roundKey);
1021}
1022
1023function InverseFinalRound(state, roundKey){
1024 addRoundKey(state, roundKey);
1025 shiftRow(state, "decrypt");
1026 byteSub(state, "decrypt");
1027}
1028
1029// encrypt is the basic encryption function. It takes parameters
1030// block, an array of bytes representing a plaintext block, and expandedKey,
1031// an array of words representing the expanded key previously returned by
1032// keyExpansion(). The ciphertext block is returned as an array of bytes.
1033
1034function encrypt(block, expandedKey) {
1035 var i;
1036 if (!block || block.length*8 != blockSizeInBits)
1037 return;
1038 if (!expandedKey)
1039 return;
1040
1041 block = packBytes(block);
1042 addRoundKey(block, expandedKey);
1043 for (i=1; i<Nr; i++)
1044 Round(block, expandedKey.slice(Nb*i, Nb*(i+1)));
1045 FinalRound(block, expandedKey.slice(Nb*Nr));
1046 return unpackBytes(block);
1047}
1048
1049// decrypt is the basic decryption function. It takes parameters
1050// block, an array of bytes representing a ciphertext block, and expandedKey,
1051// an array of words representing the expanded key previously returned by
1052// keyExpansion(). The decrypted block is returned as an array of bytes.
1053
1054function decrypt(block, expandedKey) {
1055 var i;
1056 if (!block || block.length*8 != blockSizeInBits)
1057 return;
1058 if (!expandedKey)
1059 return;
1060
1061 block = packBytes(block);
1062 InverseFinalRound(block, expandedKey.slice(Nb*Nr));
1063 for (i = Nr - 1; i>0; i--)
1064 InverseRound(block, expandedKey.slice(Nb*i, Nb*(i+1)));
1065 addRoundKey(block, expandedKey);
1066 return unpackBytes(block);
1067}
1068
1069/* !NEEDED
1070// This method takes a byte array (byteArray) and converts it to a string by
1071// applying String.fromCharCode() to each value and concatenating the result.
1072// The resulting string is returned. Note that this function SKIPS zero bytes
1073// under the assumption that they are padding added in formatPlaintext().
1074// Obviously, do not invoke this method on raw data that can contain zero
1075// bytes. It is really only appropriate for printable ASCII/Latin-1
1076// values. Roll your own function for more robust functionality :)
1077
1078function byteArrayToString(byteArray) {
1079 var result = "";
1080 for(var i=0; i<byteArray.length; i++)
1081 if (byteArray[i] != 0)
1082 result += String.fromCharCode(byteArray[i]);
1083 return result;
1084}
1085*/
1086
1087// This function takes an array of bytes (byteArray) and converts them
1088// to a hexadecimal string. Array element 0 is found at the beginning of
1089// the resulting string, high nibble first. Consecutive elements follow
1090// similarly, for example [16, 255] --> "10ff". The function returns a
1091// string.
1092
1093function byteArrayToHex(byteArray) {
1094 var result = "";
1095 if (!byteArray)
1096 return;
1097 for (var i=0; i<byteArray.length; i++)
1098 result += ((byteArray[i]<16) ? "0" : "") + byteArray[i].toString(16);
1099
1100 return result;
1101}
1102
1103// This function converts a string containing hexadecimal digits to an
1104// array of bytes. The resulting byte array is filled in the order the
1105// values occur in the string, for example "10FF" --> [16, 255]. This
1106// function returns an array.
1107
1108function hexToByteArray(hexString) {
1109 var byteArray = [];
1110 if (hexString.length % 2) // must have even length
1111 return;
1112 if (hexString.indexOf("0x") == 0 || hexString.indexOf("0X") == 0)
1113 hexString = hexString.substring(2);
1114 for (var i = 0; i<hexString.length; i += 2)
1115 byteArray[Math.floor(i/2)] = parseInt(hexString.slice(i, i+2), 16);
1116 return byteArray;
1117}
1118
1119// This function packs an array of bytes into the four row form defined by
1120// Rijndael. It assumes the length of the array of bytes is divisible by
1121// four. Bytes are filled in according to the Rijndael spec (starting with
1122// column 0, row 0 to 3). This function returns a 2d array.
1123
1124function packBytes(octets) {
1125 var state = new Array();
1126 if (!octets || octets.length % 4)
1127 return;
1128
1129 state[0] = new Array(); state[1] = new Array();
1130 state[2] = new Array(); state[3] = new Array();
1131 for (var j=0; j<octets.length; j+= 4) {
1132 state[0][j/4] = octets[j];
1133 state[1][j/4] = octets[j+1];
1134 state[2][j/4] = octets[j+2];
1135 state[3][j/4] = octets[j+3];
1136 }
1137 return state;
1138}
1139
1140// This function unpacks an array of bytes from the four row format preferred
1141// by Rijndael into a single 1d array of bytes. It assumes the input "packed"
1142// is a packed array. Bytes are filled in according to the Rijndael spec.
1143// This function returns a 1d array of bytes.
1144
1145function unpackBytes(packed) {
1146 var result = new Array();
1147 for (var j=0; j<packed[0].length; j++) {
1148 result[result.length] = packed[0][j];
1149 result[result.length] = packed[1][j];
1150 result[result.length] = packed[2][j];
1151 result[result.length] = packed[3][j];
1152 }
1153 return result;
1154}
1155
1156// This function takes a prospective plaintext (string or array of bytes)
1157// and pads it with pseudorandom bytes if its length is not a multiple of the block
1158// size. If plaintext is a string, it is converted to an array of bytes
1159// in the process. The type checking can be made much nicer using the
1160// instanceof operator, but this operator is not available until IE5.0 so I
1161// chose to use the heuristic below.
1162
1163function formatPlaintext(plaintext) {
1164 var bpb = blockSizeInBits / 8; // bytes per block
1165 var fillWithRandomBits;
1166 var i;
1167
1168 // if primitive string or String instance
1169 if ((!((typeof plaintext == "object") &&
1170 ((typeof (plaintext[0])) == "number"))) &&
1171 ((typeof plaintext == "string") || plaintext.indexOf))
1172 {
1173 plaintext = plaintext.split("");
1174 // Unicode issues here (ignoring high byte)
1175 for (i=0; i<plaintext.length; i++) {
1176 plaintext[i] = plaintext[i].charCodeAt(0) & 0xFF;
1177 }
1178 }
1179
1180 i = plaintext.length % bpb;
1181 if (i > 0) {
1182//alert("adding " + (bpb - 1) + " bytes");
1183 // plaintext = plaintext.concat(getRandomBytes(bpb - i));
1184 {
1185 varpaddingBytes;
1186 var ii,cc;
1187
1188 paddingBytes = new Array();
1189 cc = bpb - i;
1190 for (ii=0; ii<cc; ii++) {
1191 paddingBytes[ii] = cc;
1192 }
1193
1194//is("cc", cc);
1195//is(getRandomBytes(bpb - i) + "", paddingBytes + "");
1196 plaintext = plaintext.concat(paddingBytes);
1197 }
1198 }
1199
1200 return plaintext;
1201}
1202
1203// Returns an array containing "howMany" random bytes.
1204
1205function getRandomBytes(howMany) {
1206 var i, bytes = new Array();
1207
1208//alert("getting some random bytes");
1209 for (i = 0; i < howMany; i++) {
1210 bytes[i] = prng.nextInt(255);
1211 }
1212 return bytes;
1213}
1214
1215// rijndaelEncrypt(plaintext, key, mode)
1216// Encrypts the plaintext using the given key and in the given mode.
1217// The parameter "plaintext" can either be a string or an array of bytes.
1218// The parameter "key" must be an array of key bytes. If you have a hex
1219// string representing the key, invoke hexToByteArray() on it to convert it
1220// to an array of bytes. The third parameter "mode" is a string indicating
1221// the encryption mode to use, either "ECB" or "CBC". If the parameter is
1222// omitted, ECB is assumed.
1223//
1224// An array of bytes representing the cihpertext is returned. To convert
1225// this array to hex, invoke byteArrayToHex() on it.
1226
1227function rijndaelEncrypt(plaintext, key, mode) {
1228 var expandedKey, i, aBlock;
1229 var bpb = blockSizeInBits / 8; // bytes per block
1230 var ct; // ciphertext
1231
1232 if (!plaintext || !key)
1233 return;
1234 if (key.length*8 != keySizeInBits)
1235 return;
1236 if (mode == "CBC") {
1237 ct = getRandomBytes(bpb); // get IV
1238//dump("IV", byteArrayToHex(ct));
1239 } else {
1240 mode = "ECB";
1241 ct = new Array();
1242 }
1243
1244 // convert plaintext to byte array and pad with zeros if necessary.
1245 plaintext = formatPlaintext(plaintext);
1246
1247 expandedKey = keyExpansion(key);
1248
1249 for (var block = 0; block < plaintext.length / bpb; block++) {
1250 aBlock = plaintext.slice(block * bpb, (block + 1) * bpb);
1251 if (mode == "CBC") {
1252 for (var i = 0; i < bpb; i++) {
1253 aBlock[i] ^= ct[(block * bpb) + i];
1254 }
1255 }
1256 ct = ct.concat(encrypt(aBlock, expandedKey));
1257 }
1258
1259 return ct;
1260}
1261
1262// rijndaelDecrypt(ciphertext, key, mode)
1263// Decrypts the using the given key and mode. The parameter "ciphertext"
1264// must be an array of bytes. The parameter "key" must be an array of key
1265// bytes. If you have a hex string representing the ciphertext or key,
1266// invoke hexToByteArray() on it to convert it to an array of bytes. The
1267// parameter "mode" is a string, either "CBC" or "ECB".
1268//
1269// An array of bytes representing the plaintext is returned. To convert
1270// this array to a hex string, invoke byteArrayToHex() on it. To convert it
1271// to a string of characters, you can use byteArrayToString().
1272
1273function rijndaelDecrypt(ciphertext, key, mode) {
1274 var expandedKey;
1275 var bpb = blockSizeInBits / 8; // bytes per block
1276 var pt = new Array(); // plaintext array
1277 var aBlock; // a decrypted block
1278 var block; // current block number
1279
1280 if (!ciphertext || !key || typeof ciphertext == "string")
1281 return;
1282 if (key.length*8 != keySizeInBits)
1283 return;
1284 if (!mode) {
1285 mode = "ECB"; // assume ECB if mode omitted
1286 }
1287
1288 expandedKey = keyExpansion(key);
1289
1290 // work backwards to accomodate CBC mode
1291 for (block=(ciphertext.length / bpb)-1; block>0; block--) {
1292 aBlock =
1293 decrypt(ciphertext.slice(block*bpb,(block+1)*bpb), expandedKey);
1294 if (mode == "CBC")
1295 for (var i=0; i<bpb; i++)
1296 pt[(block-1)*bpb + i] = aBlock[i] ^ ciphertext[(block-1)*bpb + i];
1297 else
1298 pt = aBlock.concat(pt);
1299 }
1300
1301 // do last block if ECB (skips the IV in CBC)
1302 if (mode == "ECB")
1303 pt = decrypt(ciphertext.slice(0, bpb), expandedKey).concat(pt);
1304
1305 return pt;
1306}
1307
1308//#############################################################################
1309 //Downloaded on March 30, 2006 from http://www.fourmilab.ch/javascrypt/javascrypt.zip (utf-8.js)
1310//#############################################################################
1311
1312
1313 /*Encoding and decoding of Unicode character strings as
1314 UTF-8 byte streams. */
1315
1316 //UNICODE_TO_UTF8 -- Encode Unicode argument string as UTF-8 return value
1317
1318 function unicode_to_utf8(s) {
1319 var utf8 = "";
1320
1321 for (var n = 0; n < s.length; n++) {
1322 var c = s.charCodeAt(n);
1323
1324 if (c <= 0x7F) {
1325 // 0x00 - 0x7F: Emit as single byte, unchanged
1326 utf8 += String.fromCharCode(c);
1327 } else if ((c >= 0x80) && (c <= 0x7FF)) {
1328 // 0x80 - 0x7FF: Output as two byte code, 0xC0 in first byte
1329 // 0x80 in second byte
1330 utf8 += String.fromCharCode((c >> 6) | 0xC0);
1331 utf8 += String.fromCharCode((c & 0x3F) | 0x80);
1332 } else {
1333 // 0x800 - 0xFFFF: Output as three bytes, 0xE0 in first byte
1334 // 0x80 in second byte
1335 // 0x80 in third byte
1336 utf8 += String.fromCharCode((c >> 12) | 0xE0);
1337 utf8 += String.fromCharCode(((c >> 6) & 0x3F) | 0x80);
1338 utf8 += String.fromCharCode((c & 0x3F) | 0x80);
1339 }
1340 }
1341 return utf8;
1342 }
1343
1344 //UTF8_TO_UNICODE -- Decode UTF-8 argument into Unicode string return value
1345
1346 function utf8_to_unicode(utf8) {
1347 var s = "", i = 0, b1, b2, b2;
1348
1349 while (i < utf8.length) {
1350 b1 = utf8.charCodeAt(i);
1351 if (b1 < 0x80) { // One byte code: 0x00 0x7F
1352 s += String.fromCharCode(b1);
1353 i++;
1354 } else if((b1 >= 0xC0) && (b1 < 0xE0)) {// Two byte code: 0x80 - 0x7FF
1355 b2 = utf8.charCodeAt(i + 1);
1356 s += String.fromCharCode(((b1 & 0x1F) << 6) | (b2 & 0x3F));
1357 i += 2;
1358 } else { // Three byte code: 0x800 - 0xFFFF
1359 b2 = utf8.charCodeAt(i + 1);
1360 b3 = utf8.charCodeAt(i + 2);
1361 s += String.fromCharCode(((b1 & 0xF) << 12) |
1362 ((b2 & 0x3F) << 6) |
1363 (b3 & 0x3F));
1364 i += 3;
1365 }
1366 }
1367 return s;
1368 }
1369
1370 /*ENCODE_UTF8 -- Encode string as UTF8 only if it contains
1371 a character of 0x9D (Unicode OPERATING
1372 SYSTEM COMMAND) or a character greater
1373 than 0xFF. This permits all strings
1374 consisting exclusively of 8 bit
1375 graphic characters to be encoded as
1376 themselves. We choose 0x9D as the sentinel
1377 character as opposed to one of the more
1378 logical PRIVATE USE characters because 0x9D
1379 is not overloaded by the regrettable
1380 "Windows-1252" character set. Now such characters
1381 don't belong in JavaScript strings, but you never
1382 know what somebody is going to paste into a
1383 text box, so this choice keeps Windows-encoded
1384 strings from bloating to UTF-8 encoding. */
1385
1386 function encode_utf8(s) {
1387 var i, necessary = false;
1388
1389 for (i = 0; i < s.length; i++) {
1390 if ((s.charCodeAt(i) == 0x9D) ||
1391 (s.charCodeAt(i) > 0xFF)) {
1392 necessary = true;
1393 break;
1394 }
1395 }
1396 if (!necessary) {
1397 return s;
1398 }
1399 return String.fromCharCode(0x9D) + unicode_to_utf8(s);
1400 }
1401
1402 /* DECODE_UTF8 -- Decode a string encoded with encode_utf8
1403 above. If the string begins with the
1404 sentinel character 0x9D (OPERATING
1405 SYSTEM COMMAND), then we decode the
1406 balance as a UTF-8 stream. Otherwise,
1407 the string is output unchanged, as
1408 it's guaranteed to contain only 8 bit
1409 characters excluding 0x9D. */
1410
1411 function decode_utf8(s) {
1412 if ((s.length > 0) && (s.charCodeAt(0) == 0x9D)) {
1413 return utf8_to_unicode(s.substring(1));
1414 }
1415 return s;
1416 }
1417
1418
1419//#############################################################################
1420 //Downloaded on April 26, 2006 from http://pajhome.org.uk/crypt/md5/md5.js
1421//#############################################################################
1422
1423/*
1424 * A JavaScript implementation of the RSA Data Security, Inc. MD5 Message
1425 * Digest Algorithm, as defined in RFC 1321.
1426 * Version 2.1 Copyright (C) Paul Johnston 1999 - 2002.
1427 * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
1428 * Distributed under the BSD License
1429 * See http://pajhome.org.uk/crypt/md5 for more info.
1430 */
1431
1432/*
1433 * Configurable variables. You may need to tweak these to be compatible with
1434 * the server-side, but the defaults work in most cases.
1435 */
1436var hexcase = 0; /* hex output format. 0 - lowercase; 1 - uppercase */
1437var b64pad = ""; /* base-64 pad character. "=" for strict RFC compliance */
1438var chrsz = 8; /* bits per input character. 8 - ASCII; 16 - Unicode */
1439
1440/*
1441 * These are the functions you'll usually want to call
1442 * They take string arguments and return either hex or base-64 encoded strings
1443 */
1444function hex_md5(s){ return binl2hex(core_md5(str2binl(s), s.length * chrsz));}
1445function b64_md5(s){ return binl2b64(core_md5(str2binl(s), s.length * chrsz));}
1446function str_md5(s){ return binl2str(core_md5(str2binl(s), s.length * chrsz));}
1447function hex_hmac_md5(key, data) { return binl2hex(core_hmac_md5(key, data)); }
1448function b64_hmac_md5(key, data) { return binl2b64(core_hmac_md5(key, data)); }
1449function str_hmac_md5(key, data) { return binl2str(core_hmac_md5(key, data)); }
1450
1451/*
1452 * Perform a simple self-test to see if the VM is working
1453 */
1454function md5_vm_test()
1455{
1456 return hex_md5("abc") == "900150983cd24fb0d6963f7d28e17f72";
1457}
1458
1459/*
1460 * Calculate the MD5 of an array of little-endian words, and a bit length
1461 */
1462function core_md5(x, len)
1463{
1464 /* append padding */
1465 x[len >> 5] |= 0x80 << ((len) % 32);
1466 x[(((len + 64) >>> 9) << 4) + 14] = len;
1467
1468 var a = 1732584193;
1469 var b = -271733879;
1470 var c = -1732584194;
1471 var d = 271733878;
1472
1473 for(var i = 0; i < x.length; i += 16)
1474 {
1475 var olda = a;
1476 var oldb = b;
1477 var oldc = c;
1478 var oldd = d;
1479
1480 a = md5_ff(a, b, c, d, x[i+ 0], 7 , -680876936);
1481 d = md5_ff(d, a, b, c, x[i+ 1], 12, -389564586);
1482 c = md5_ff(c, d, a, b, x[i+ 2], 17, 606105819);
1483 b = md5_ff(b, c, d, a, x[i+ 3], 22, -1044525330);
1484 a = md5_ff(a, b, c, d, x[i+ 4], 7 , -176418897);
1485 d = md5_ff(d, a, b, c, x[i+ 5], 12, 1200080426);
1486 c = md5_ff(c, d, a, b, x[i+ 6], 17, -1473231341);
1487 b = md5_ff(b, c, d, a, x[i+ 7], 22, -45705983);
1488 a = md5_ff(a, b, c, d, x[i+ 8], 7 , 1770035416);
1489 d = md5_ff(d, a, b, c, x[i+ 9], 12, -1958414417);
1490 c = md5_ff(c, d, a, b, x[i+10], 17, -42063);
1491 b = md5_ff(b, c, d, a, x[i+11], 22, -1990404162);
1492 a = md5_ff(a, b, c, d, x[i+12], 7 , 1804603682);
1493 d = md5_ff(d, a, b, c, x[i+13], 12, -40341101);
1494 c = md5_ff(c, d, a, b, x[i+14], 17, -1502002290);
1495 b = md5_ff(b, c, d, a, x[i+15], 22, 1236535329);
1496
1497 a = md5_gg(a, b, c, d, x[i+ 1], 5 , -165796510);
1498 d = md5_gg(d, a, b, c, x[i+ 6], 9 , -1069501632);
1499 c = md5_gg(c, d, a, b, x[i+11], 14, 643717713);
1500 b = md5_gg(b, c, d, a, x[i+ 0], 20, -373897302);
1501 a = md5_gg(a, b, c, d, x[i+ 5], 5 , -701558691);
1502 d = md5_gg(d, a, b, c, x[i+10], 9 , 38016083);
1503 c = md5_gg(c, d, a, b, x[i+15], 14, -660478335);
1504 b = md5_gg(b, c, d, a, x[i+ 4], 20, -405537848);
1505 a = md5_gg(a, b, c, d, x[i+ 9], 5 , 568446438);
1506 d = md5_gg(d, a, b, c, x[i+14], 9 , -1019803690);
1507 c = md5_gg(c, d, a, b, x[i+ 3], 14, -187363961);
1508 b = md5_gg(b, c, d, a, x[i+ 8], 20, 1163531501);
1509 a = md5_gg(a, b, c, d, x[i+13], 5 , -1444681467);
1510 d = md5_gg(d, a, b, c, x[i+ 2], 9 , -51403784);
1511 c = md5_gg(c, d, a, b, x[i+ 7], 14, 1735328473);
1512 b = md5_gg(b, c, d, a, x[i+12], 20, -1926607734);
1513
1514 a = md5_hh(a, b, c, d, x[i+ 5], 4 , -378558);
1515 d = md5_hh(d, a, b, c, x[i+ 8], 11, -2022574463);
1516 c = md5_hh(c, d, a, b, x[i+11], 16, 1839030562);
1517 b = md5_hh(b, c, d, a, x[i+14], 23, -35309556);
1518 a = md5_hh(a, b, c, d, x[i+ 1], 4 , -1530992060);
1519 d = md5_hh(d, a, b, c, x[i+ 4], 11, 1272893353);
1520 c = md5_hh(c, d, a, b, x[i+ 7], 16, -155497632);
1521 b = md5_hh(b, c, d, a, x[i+10], 23, -1094730640);
1522 a = md5_hh(a, b, c, d, x[i+13], 4 , 681279174);
1523 d = md5_hh(d, a, b, c, x[i+ 0], 11, -358537222);
1524 c = md5_hh(c, d, a, b, x[i+ 3], 16, -722521979);
1525 b = md5_hh(b, c, d, a, x[i+ 6], 23, 76029189);
1526 a = md5_hh(a, b, c, d, x[i+ 9], 4 , -640364487);
1527 d = md5_hh(d, a, b, c, x[i+12], 11, -421815835);
1528 c = md5_hh(c, d, a, b, x[i+15], 16, 530742520);
1529 b = md5_hh(b, c, d, a, x[i+ 2], 23, -995338651);
1530
1531 a = md5_ii(a, b, c, d, x[i+ 0], 6 , -198630844);
1532 d = md5_ii(d, a, b, c, x[i+ 7], 10, 1126891415);
1533 c = md5_ii(c, d, a, b, x[i+14], 15, -1416354905);
1534 b = md5_ii(b, c, d, a, x[i+ 5], 21, -57434055);
1535 a = md5_ii(a, b, c, d, x[i+12], 6 , 1700485571);
1536 d = md5_ii(d, a, b, c, x[i+ 3], 10, -1894986606);
1537 c = md5_ii(c, d, a, b, x[i+10], 15, -1051523);
1538 b = md5_ii(b, c, d, a, x[i+ 1], 21, -2054922799);
1539 a = md5_ii(a, b, c, d, x[i+ 8], 6 , 1873313359);
1540 d = md5_ii(d, a, b, c, x[i+15], 10, -30611744);
1541 c = md5_ii(c, d, a, b, x[i+ 6], 15, -1560198380);
1542 b = md5_ii(b, c, d, a, x[i+13], 21, 1309151649);
1543 a = md5_ii(a, b, c, d, x[i+ 4], 6 , -145523070);
1544 d = md5_ii(d, a, b, c, x[i+11], 10, -1120210379);
1545 c = md5_ii(c, d, a, b, x[i+ 2], 15, 718787259);
1546 b = md5_ii(b, c, d, a, x[i+ 9], 21, -343485551);
1547
1548 a = safe_add(a, olda);
1549 b = safe_add(b, oldb);
1550 c = safe_add(c, oldc);
1551 d = safe_add(d, oldd);
1552 }
1553 return Array(a, b, c, d);
1554
1555}
1556
1557/*
1558 * These functions implement the four basic operations the algorithm uses.
1559 */
1560function md5_cmn(q, a, b, x, s, t)
1561{
1562 return safe_add(bit_rol(safe_add(safe_add(a, q), safe_add(x, t)), s),b);
1563}
1564function md5_ff(a, b, c, d, x, s, t)
1565{
1566 return md5_cmn((b & c) | ((~b) & d), a, b, x, s, t);
1567}
1568function md5_gg(a, b, c, d, x, s, t)
1569{
1570 return md5_cmn((b & d) | (c & (~d)), a, b, x, s, t);
1571}
1572function md5_hh(a, b, c, d, x, s, t)
1573{
1574 return md5_cmn(b ^ c ^ d, a, b, x, s, t);
1575}
1576function md5_ii(a, b, c, d, x, s, t)
1577{
1578 return md5_cmn(c ^ (b | (~d)), a, b, x, s, t);
1579}
1580
1581/*
1582 * Calculate the HMAC-MD5, of a key and some data
1583 */
1584function core_hmac_md5(key, data)
1585{
1586 var bkey = str2binl(key);
1587 if(bkey.length > 16) bkey = core_md5(bkey, key.length * chrsz);
1588
1589 var ipad = Array(16), opad = Array(16);
1590 for(var i = 0; i < 16; i++)
1591 {
1592 ipad[i] = bkey[i] ^ 0x36363636;
1593 opad[i] = bkey[i] ^ 0x5C5C5C5C;
1594 }
1595
1596 var hash = core_md5(ipad.concat(str2binl(data)), 512 + data.length * chrsz);
1597 return core_md5(opad.concat(hash), 512 + 128);
1598}
1599
1600/*
1601 * Add integers, wrapping at 2^32. This uses 16-bit operations internally
1602 * to work around bugs in some JS interpreters.
1603 */
1604function safe_add(x, y)
1605{
1606 var lsw = (x & 0xFFFF) + (y & 0xFFFF);
1607 var msw = (x >> 16) + (y >> 16) + (lsw >> 16);
1608 return (msw << 16) | (lsw & 0xFFFF);
1609}
1610
1611/*
1612 * Bitwise rotate a 32-bit number to the left.
1613 */
1614function bit_rol(num, cnt)
1615{
1616 return (num << cnt) | (num >>> (32 - cnt));
1617}
1618
1619/*
1620 * Convert a string to an array of little-endian words
1621 * If chrsz is ASCII, characters >255 have their hi-byte silently ignored.
1622 */
1623function str2binl(str)
1624{
1625 var bin = Array();
1626 var mask = (1 << chrsz) - 1;
1627 for(var i = 0; i < str.length * chrsz; i += chrsz)
1628 bin[i>>5] |= (str.charCodeAt(i / chrsz) & mask) << (i%32);
1629 return bin;
1630}
1631
1632/*
1633 * Convert an array of little-endian words to a string
1634 */
1635function binl2str(bin)
1636{
1637 var str = "";
1638 var mask = (1 << chrsz) - 1;
1639 for(var i = 0; i < bin.length * 32; i += chrsz)
1640 str += String.fromCharCode((bin[i>>5] >>> (i % 32)) & mask);
1641 return str;
1642}
1643
1644/*
1645 * Convert an array of little-endian words to a hex string.
1646 */
1647function binl2hex(binarray)
1648{
1649 var hex_tab = hexcase ? "0123456789ABCDEF" : "0123456789abcdef";
1650 var str = "";
1651 for(var i = 0; i < binarray.length * 4; i++)
1652 {
1653 str += hex_tab.charAt((binarray[i>>2] >> ((i%4)*8+4)) & 0xF) +
1654 hex_tab.charAt((binarray[i>>2] >> ((i%4)*8 )) & 0xF);
1655 }
1656 return str;
1657}
1658
1659/*
1660 * Convert an array of little-endian words to a base-64 string
1661 */
1662function binl2b64(binarray)
1663{
1664 var tab = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
1665 var str = "";
1666 for(var i = 0; i < binarray.length * 4; i += 3)
1667 {
1668 var triplet = (((binarray[i >> 2] >> 8 * ( i %4)) & 0xFF) << 16)
1669 | (((binarray[i+1 >> 2] >> 8 * ((i+1)%4)) & 0xFF) << 8 )
1670 | ((binarray[i+2 >> 2] >> 8 * ((i+2)%4)) & 0xFF);
1671 for(var j = 0; j < 4; j++)
1672 {
1673 if(i * 8 + j * 6 > binarray.length * 32) str += b64pad;
1674 else str += tab.charAt((triplet >> 6*(3-j)) & 0x3F);
1675 }
1676 }
1677 return str;
1678}
1679
1680
1681//#############################################################################
1682//#############################################################################
1683//#############################################################################
1684
1685
1686
1687MochiKit.Base.update(Clipperz.Crypto.Base, {
1688
1689 '__repr__': function () {
1690 return "[" + this.NAME + " " + this.VERSION + "]";
1691 },
1692
1693 'toString': function () {
1694 return this.__repr__();
1695 },
1696
1697 //-----------------------------------------------------------------------------
1698
1699 'encryptUsingSecretKey': function (aKey, aMessage) {
1700//Clipperz.Profile.start("Clipperz.Crypto.Base.encryptUsingSecretKey");
1701 var result;
1702 var plaintext;
1703 varheader;
1704 varkey;
1705
1706 key = hexToByteArray(Clipperz.Crypto.Base.computeHashValue(aKey));
1707
1708 addEntropyTime();
1709 prng = new AESprng(keyFromEntropy());
1710
1711 plaintext = encode_utf8(aMessage);
1712
1713 header = Clipperz.Base.byteArrayToString(hexToByteArray(Clipperz.Crypto.Base.computeMD5HashValue(plaintext)));
1714
1715 // Add message length in bytes to header
1716 i = plaintext.length;
1717 header += String.fromCharCode(i >>> 24);
1718 header += String.fromCharCode(i >>> 16);
1719 header += String.fromCharCode(i >>> 8);
1720 header += String.fromCharCode(i & 0xFF);
1721
1722 //The format of the actual message passed to rijndaelEncrypt
1723 //is:
1724 //
1725 // Bytes Content
1726 // 0-15 MD5 signature of plaintext
1727 // 16-19 Length of plaintext, big-endian order
1728 // 20-end Plaintext
1729 //
1730 //Note that this message will be padded with zero bytes
1731 //to an integral number of AES blocks (blockSizeInBits / 8).
1732 //This does not include the initial vector for CBC
1733 //encryption, which is added internally by rijndaelEncrypt.
1734 result = byteArrayToHex(rijndaelEncrypt(header + plaintext, key, "CBC"));
1735
1736 delete prng;
1737
1738//Clipperz.Profile.stop("Clipperz.Crypto.Base.encryptUsingSecretKey");
1739 return result;
1740 },
1741
1742 //.............................................................................
1743
1744 'decryptUsingSecretKey': function (aKey, aMessage) {
1745//Clipperz.Profile.start("Clipperz.Crypto.Base.decryptUsingSecretKey");
1746 varkey;
1747 var decryptedText;
1748 vartextLength;
1749 varheader;
1750 varheaderDigest;
1751 var plaintext;
1752 var i;
1753
1754 key = hexToByteArray(Clipperz.Crypto.Base.computeHashValue(aKey));
1755
1756 decryptedText = rijndaelDecrypt(hexToByteArray(aMessage), key, "CBC");
1757
1758 header = decryptedText.slice(0, 20);
1759 decryptedText = decryptedText.slice(20);
1760
1761 headerDigest = byteArrayToHex(header.slice(0,16));
1762 textLength = (header[16] << 24) | (header[17] << 16) | (header[18] << 8) | header[19];
1763
1764 if ((textLength < 0) || (textLength > decryptedText.length)) {
1765 // jslog.warning("Message (length " + decryptedText.length + ") truncated. " + textLength + " characters expected.");
1766 //Try to sauve qui peut by setting length to entire message
1767 textLength = decryptedText.length;
1768 }
1769
1770 plainText = "";
1771
1772 for (i=0; i<textLength; i++) {
1773 plainText += String.fromCharCode(decryptedText[i]);
1774 }
1775
1776 if (Clipperz.Crypto.Base.computeMD5HashValue(plainText) != headerDigest) {
1777 // jslog.warning("Message corrupted. Checksum of decrypted message does not match.");
1778 throw Clipperz.Crypto.Base.exception.CorruptedMessage;
1779 // throw new Error("Message corrupted. Checksum of decrypted message does not match. Parsed result: " + decode_utf8(plainText));
1780 }
1781
1782 // That's it; plug plaintext into the result field
1783
1784 result = decode_utf8(plainText);
1785
1786//Clipperz.Profile.stop("Clipperz.Crypto.Base.decryptUsingSecretKey");
1787 return result;
1788 },
1789
1790 //-----------------------------------------------------------------------------
1791
1792 'computeHashValue': function (aMessage) {
1793//Clipperz.Profile.start("Clipperz.Crypto.Base.computeHashValue");
1794 varresult;
1795
1796 result = hex_sha256(aMessage);
1797//Clipperz.Profile.stop("Clipperz.Crypto.Base.computeHashValue");
1798
1799 return result;
1800 },
1801
1802 //.........................................................................
1803
1804 'computeMD5HashValue': function (aMessage) {
1805 varresult;
1806//Clipperz.Profile.start("Clipperz.Crypto.Base.computeMD5HashValue");
1807 result = hex_md5(aMessage);
1808//Clipperz.Profile.stop("Clipperz.Crypto.Base.computeMD5HashValue");
1809
1810 return result;
1811 },
1812
1813 //-----------------------------------------------------------------------------
1814
1815 'generateRandomSeed': function () {
1816//Clipperz.Profile.start("Clipperz.Crypto.Base.generateRandomSeed");
1817 varresult;
1818 var seed;
1819 var prng;
1820 var charA;
1821 var i;
1822
1823 addEntropyTime();
1824
1825 seed = keyFromEntropy();
1826 prng = new AESprng(seed);
1827
1828 result = "";
1829 charA = ("A").charCodeAt(0);
1830
1831 for (i = 0; i < 64; i++) {
1832 result += String.fromCharCode(charA + prng.nextInt(25));
1833 }
1834
1835 delete prng;
1836
1837 result = Clipperz.Crypto.Base.computeHashValue(result);
1838
1839//Clipperz.Profile.stop("Clipperz.Crypto.Base.generateRandomSeed");
1840 return result;
1841 },
1842
1843 //-----------------------------------------------------------------------------
1844
1845 'exception': {
1846 'CorruptedMessage': new MochiKit.Base.NamedError("Clipperz.Crypto.Base.exception.CorruptedMessage")
1847 },
1848
1849 //.........................................................................
1850 __syntaxFix__: "syntax fix"
1851});
1852
diff --git a/frontend/beta/js/Clipperz/Crypto/BigInt.js b/frontend/beta/js/Clipperz/Crypto/BigInt.js
new file mode 100644
index 0000000..d4d05d2
--- a/dev/null
+++ b/frontend/beta/js/Clipperz/Crypto/BigInt.js
@@ -0,0 +1,1760 @@
1/*
2
3Copyright 2008-2011 Clipperz Srl
4
5This file is part of Clipperz's Javascript Crypto Library.
6Javascript Crypto Library provides web developers with an extensive
7and efficient set of cryptographic functions. The library aims to
8obtain maximum execution speed while preserving modularity and
9reusability.
10For further information about its features and functionalities please
11refer to http://www.clipperz.com
12
13* Javascript Crypto Library is free software: you can redistribute
14 it and/or modify it under the terms of the GNU Affero General Public
15 License as published by the Free Software Foundation, either version
16 3 of the License, or (at your option) any later version.
17
18* Javascript Crypto Library is distributed in the hope that it will
19 be useful, but WITHOUT ANY WARRANTY; without even the implied
20 warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
21 See the GNU Affero General Public License for more details.
22
23* You should have received a copy of the GNU Affero General Public
24 License along with Javascript Crypto Library. If not, see
25 <http://www.gnu.org/licenses/>.
26
27*/
28
29if (typeof(Clipperz) == 'undefined') { Clipperz = {}; }
30if (typeof(Clipperz.Crypto) == 'undefined') { Clipperz.Crypto = {}; }
31
32//#############################################################################
33 //Downloaded on March 05, 2007 from http://www.leemon.com/crypto/BigInt.js
34//#############################################################################
35
36
37////////////////////////////////////////////////////////////////////////////////////////
38// Big Integer Library v. 5.0
39// Created 2000, last modified 2006
40// Leemon Baird
41// www.leemon.com
42//
43// This file is public domain. You can use it for any purpose without restriction.
44// I do not guarantee that it is correct, so use it at your own risk. If you use
45// it for something interesting, I'd appreciate hearing about it. If you find
46// any bugs or make any improvements, I'd appreciate hearing about those too.
47// It would also be nice if my name and address were left in the comments.
48// But none of that is required.
49//
50// This code defines a bigInt library for arbitrary-precision integers.
51// A bigInt is an array of integers storing the value in chunks of bpe bits,
52// little endian (buff[0] is the least significant word).
53// Negative bigInts are stored two's complement.
54// Some functions assume their parameters have at least one leading zero element.
55// Functions with an underscore at the end of the name have unpredictable behavior in case of overflow,
56// so the caller must make sure overflow won't happen.
57// For each function where a parameter is modified, that same
58// variable must not be used as another argument too.
59// So, you cannot square x by doing multMod_(x,x,n).
60// You must use squareMod_(x,n) instead, or do y=dup(x); multMod_(x,y,n).
61//
62// These functions are designed to avoid frequent dynamic memory allocation in the inner loop.
63// For most functions, if it needs a BigInt as a local variable it will actually use
64// a global, and will only allocate to it when it's not the right size. This ensures
65// that when a function is called repeatedly with same-sized parameters, it only allocates
66// memory on the first call.
67//
68// Note that for cryptographic purposes, the calls to Math.random() must
69// be replaced with calls to a better pseudorandom number generator.
70//
71// In the following, "bigInt" means a bigInt with at least one leading zero element,
72// and "integer" means a nonnegative integer less than radix. In some cases, integer
73// can be negative. Negative bigInts are 2s complement.
74//
75// The following functions do not modify their inputs, but dynamically allocate memory every time they are called:
76//
77// function bigInt2str(x,base) //convert a bigInt into a string in a given base, from base 2 up to base 95
78// function dup(x) //returns a copy of bigInt x
79// function findPrimes(n) //return array of all primes less than integer n
80// function int2bigInt(t,n,m) //convert integer t to a bigInt with at least n bits and m array elements
81// function int2bigInt(s,b,n,m) //convert string s in base b to a bigInt with at least n bits and m array elements
82// function trim(x,k) //return a copy of x with exactly k leading zero elements
83//
84// The following functions do not modify their inputs, so there is never a problem with the result being too big:
85//
86// function bitSize(x) //returns how many bits long the bigInt x is, not counting leading zeros
87// function equals(x,y) //is the bigInt x equal to the bigint y?
88// function equalsInt(x,y) //is bigint x equal to integer y?
89// function greater(x,y) //is x>y? (x and y are nonnegative bigInts)
90// function greaterShift(x,y,shift)//is (x <<(shift*bpe)) > y?
91// function isZero(x) //is the bigInt x equal to zero?
92// function millerRabin(x,b) //does one round of Miller-Rabin base integer b say that bigInt x is possibly prime (as opposed to definitely composite)?
93// function modInt(x,n) //return x mod n for bigInt x and integer n.
94// function negative(x) //is bigInt x negative?
95//
96// The following functions do not modify their inputs, but allocate memory and call functions with underscores
97//
98// function add(x,y) //return (x+y) for bigInts x and y.
99// function addInt(x,n) //return (x+n) where x is a bigInt and n is an integer.
100// function expand(x,n) //return a copy of x with at least n elements, adding leading zeros if needed
101// function inverseMod(x,n) //return (x**(-1) mod n) for bigInts x and n. If no inverse exists, it returns null
102// function mod(x,n) //return a new bigInt equal to (x mod n) for bigInts x and n.
103// function mult(x,y) //return x*y for bigInts x and y. This is faster when y<x.
104// function multMod(x,y,n) //return (x*y mod n) for bigInts x,y,n. For greater speed, let y<x.
105// function powMod(x,y,n) //return (x**y mod n) where x,y,n are bigInts and ** is exponentiation. 0**0=1. Faster for odd n.
106// function randTruePrime(k) //return a new, random, k-bit, true prime using Maurer's algorithm.
107// function sub(x,y) //return (x-y) for bigInts x and y. Negative answers will be 2s complement
108//
109// The following functions write a bigInt result to one of the parameters, but
110// the result is never bigger than the original, so there can't be overflow problems:
111//
112// function divInt_(x,n) //do x=floor(x/n) for bigInt x and integer n, and return the remainder
113// function GCD_(x,y) //set x to the greatest common divisor of bigInts x and y, (y is destroyed).
114// function halve_(x) //do x=floor(|x|/2)*sgn(x) for bigInt x in 2's complement
115// function mod_(x,n) //do x=x mod n for bigInts x and n.
116// function rightShift_(x,n) //right shift bigInt x by n bits. 0 <= n < bpe.
117//
118// The following functions write a bigInt result to one of the parameters. The caller is responsible for
119// ensuring it is large enough to hold the result.
120//
121// function addInt_(x,n) //do x=x+n where x is a bigInt and n is an integer
122// function add_(x,y) //do x=x+y for bigInts x and y
123// function addShift_(x,y,ys) //do x=x+(y<<(ys*bpe))
124// function copy_(x,y) //do x=y on bigInts x and y
125// function copyInt_(x,n) //do x=n on bigInt x and integer n
126// function carry_(x) //do carries and borrows so each element of the bigInt x fits in bpe bits.
127// function divide_(x,y,q,r) //divide_ x by y giving quotient q and remainder r
128// function eGCD_(x,y,d,a,b) //sets a,b,d to positive big integers such that d = GCD_(x,y) = a*x-b*y
129// function inverseMod_(x,n) //do x=x**(-1) mod n, for bigInts x and n. Returns 1 (0) if inverse does (doesn't) exist
130// function inverseModInt_(x,n) //return x**(-1) mod n, for integers x and n. Return 0 if there is no inverse
131// function leftShift_(x,n) //left shift bigInt x by n bits. n<bpe.
132// function linComb_(x,y,a,b) //do x=a*x+b*y for bigInts x and y and integers a and b
133// function linCombShift_(x,y,b,ys) //do x=x+b*(y<<(ys*bpe)) for bigInts x and y, and integers b and ys
134// function mont_(x,y,n,np) //Montgomery multiplication (see comments where the function is defined)
135// function mult_(x,y) //do x=x*y for bigInts x and y.
136// function multInt_(x,n) //do x=x*n where x is a bigInt and n is an integer.
137// function multMod_(x,y,n) //do x=x*y mod n for bigInts x,y,n.
138// function powMod_(x,y,n) //do x=x**y mod n, where x,y,n are bigInts (n is odd) and ** is exponentiation. 0**0=1.
139// function randBigInt_(b,n,s) //do b = an n-bit random BigInt. if s=1, then nth bit (most significant bit) is set to 1. n>=1.
140// function randTruePrime_(ans,k) //do ans = a random k-bit true random prime (not just probable prime) with 1 in the msb.
141// function squareMod_(x,n) //do x=x*x mod n for bigInts x,n
142// function sub_(x,y) //do x=x-y for bigInts x and y. Negative answers will be 2s complement.
143// function subShift_(x,y,ys) //do x=x-(y<<(ys*bpe)). Negative answers will be 2s complement.
144//
145// The following functions are based on algorithms from the _Handbook of Applied Cryptography_
146// powMod_() = algorithm 14.94, Montgomery exponentiation
147// eGCD_,inverseMod_() = algorithm 14.61, Binary extended GCD_
148// GCD_() = algorothm 14.57, Lehmer's algorithm
149// mont_() = algorithm 14.36, Montgomery multiplication
150// divide_() = algorithm 14.20 Multiple-precision division
151// squareMod_() = algorithm 14.16 Multiple-precision squaring
152// randTruePrime_() = algorithm 4.62, Maurer's algorithm
153// millerRabin() = algorithm 4.24, Miller-Rabin algorithm
154//
155// Profiling shows:
156// randTruePrime_() spends:
157// 10% of its time in calls to powMod_()
158// 85% of its time in calls to millerRabin()
159// millerRabin() spends:
160// 99% of its time in calls to powMod_() (always with a base of 2)
161// powMod_() spends:
162// 94% of its time in calls to mont_() (almost always with x==y)
163//
164// This suggests there are several ways to speed up this library slightly:
165// - convert powMod_ to use a Montgomery form of k-ary window (or maybe a Montgomery form of sliding window)
166// -- this should especially focus on being fast when raising 2 to a power mod n
167// - convert randTruePrime_() to use a minimum r of 1/3 instead of 1/2 with the appropriate change to the test
168// - tune the parameters in randTruePrime_(), including c, m, and recLimit
169// - speed up the single loop in mont_() that takes 95% of the runtime, perhaps by reducing checking
170// within the loop when all the parameters are the same length.
171//
172// There are several ideas that look like they wouldn't help much at all:
173// - replacing trial division in randTruePrime_() with a sieve (that speeds up something taking almost no time anyway)
174// - increase bpe from 15 to 30 (that would help if we had a 32*32->64 multiplier, but not with JavaScript's 32*32->32)
175// - speeding up mont_(x,y,n,np) when x==y by doing a non-modular, non-Montgomery square
176// followed by a Montgomery reduction. The intermediate answer will be twice as long as x, so that
177// method would be slower. This is unfortunate because the code currently spends almost all of its time
178// doing mont_(x,x,...), both for randTruePrime_() and powMod_(). A faster method for Montgomery squaring
179// would have a large impact on the speed of randTruePrime_() and powMod_(). HAC has a couple of poorly-worded
180// sentences that seem to imply it's faster to do a non-modular square followed by a single
181// Montgomery reduction, but that's obviously wrong.
182////////////////////////////////////////////////////////////////////////////////////////
183
184//globals
185bpe=0; //bits stored per array element
186mask=0; //AND this with an array element to chop it down to bpe bits
187radix=mask+1; //equals 2^bpe. A single 1 bit to the left of the last bit of mask.
188
189//the digits for converting to different bases
190digitsStr='0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_=!@#$%^&*()[]{}|;:,.<>/?`~ \\\'\"+-';
191
192//initialize the global variables
193for (bpe=0; (1<<(bpe+1)) > (1<<bpe); bpe++); //bpe=number of bits in the mantissa on this platform
194bpe>>=1; //bpe=number of bits in one element of the array representing the bigInt
195mask=(1<<bpe)-1; //AND the mask with an integer to get its bpe least significant bits
196radix=mask+1; //2^bpe. a single 1 bit to the left of the first bit of mask
197one=int2bigInt(1,1,1); //constant used in powMod_()
198
199//the following global variables are scratchpad memory to
200//reduce dynamic memory allocation in the inner loop
201t=new Array(0);
202ss=t; //used in mult_()
203s0=t; //used in multMod_(), squareMod_()
204s1=t; //used in powMod_(), multMod_(), squareMod_()
205s2=t; //used in powMod_(), multMod_()
206s3=t; //used in powMod_()
207s4=t; s5=t; //used in mod_()
208s6=t; //used in bigInt2str()
209s7=t; //used in powMod_()
210T=t; //used in GCD_()
211sa=t; //used in mont_()
212mr_x1=t; mr_r=t; mr_a=t; //used in millerRabin()
213eg_v=t; eg_u=t; eg_A=t; eg_B=t; eg_C=t; eg_D=t; //used in eGCD_(), inverseMod_()
214md_q1=t; md_q2=t; md_q3=t; md_r=t; md_r1=t; md_r2=t; md_tt=t; //used in mod_()
215
216primes=t; pows=t; s_i=t; s_i2=t; s_R=t; s_rm=t; s_q=t; s_n1=t;
217 s_a=t; s_r2=t; s_n=t; s_b=t; s_d=t; s_x1=t; s_x2=t, s_aa=t; //used in randTruePrime_()
218
219////////////////////////////////////////////////////////////////////////////////////////
220
221//return array of all primes less than integer n
222function findPrimes(n) {
223 var i,s,p,ans;
224 s=new Array(n);
225 for (i=0;i<n;i++)
226 s[i]=0;
227 s[0]=2;
228 p=0; //first p elements of s are primes, the rest are a sieve
229 for(;s[p]<n;) { //s[p] is the pth prime
230 for(i=s[p]*s[p]; i<n; i+=s[p]) //mark multiples of s[p]
231 s[i]=1;
232 p++;
233 s[p]=s[p-1]+1;
234 for(; s[p]<n && s[s[p]]; s[p]++); //find next prime (where s[p]==0)
235 }
236 ans=new Array(p);
237 for(i=0;i<p;i++)
238 ans[i]=s[i];
239 return ans;
240}
241
242//does a single round of Miller-Rabin base b consider x to be a possible prime?
243//x is a bigInt, and b is an integer
244function millerRabin(x,b) {
245 var i,j,k,s;
246
247 if (mr_x1.length!=x.length) {
248 mr_x1=dup(x);
249 mr_r=dup(x);
250 mr_a=dup(x);
251 }
252
253 copyInt_(mr_a,b);
254 copy_(mr_r,x);
255 copy_(mr_x1,x);
256
257 addInt_(mr_r,-1);
258 addInt_(mr_x1,-1);
259
260 //s=the highest power of two that divides mr_r
261 k=0;
262 for (i=0;i<mr_r.length;i++)
263 for (j=1;j<mask;j<<=1)
264 if (x[i] & j) {
265 s=(k<mr_r.length+bpe ? k : 0);
266 i=mr_r.length;
267 j=mask;
268 } else
269 k++;
270
271 if (s)
272 rightShift_(mr_r,s);
273
274 powMod_(mr_a,mr_r,x);
275
276 if (!equalsInt(mr_a,1) && !equals(mr_a,mr_x1)) {
277 j=1;
278 while (j<=s-1 && !equals(mr_a,mr_x1)) {
279 squareMod_(mr_a,x);
280 if (equalsInt(mr_a,1)) {
281 return 0;
282 }
283 j++;
284 }
285 if (!equals(mr_a,mr_x1)) {
286 return 0;
287 }
288 }
289 return 1;
290}
291
292//returns how many bits long the bigInt is, not counting leading zeros.
293function bitSize(x) {
294 var j,z,w;
295 for (j=x.length-1; (x[j]==0) && (j>0); j--);
296 for (z=0,w=x[j]; w; (w>>=1),z++);
297 z+=bpe*j;
298 return z;
299}
300
301//return a copy of x with at least n elements, adding leading zeros if needed
302function expand(x,n) {
303 var ans=int2bigInt(0,(x.length>n ? x.length : n)*bpe,0);
304 copy_(ans,x);
305 return ans;
306}
307
308//return a k-bit true random prime using Maurer's algorithm.
309function randTruePrime(k) {
310 var ans=int2bigInt(0,k,0);
311 randTruePrime_(ans,k);
312 return trim(ans,1);
313}
314
315//return a new bigInt equal to (x mod n) for bigInts x and n.
316function mod(x,n) {
317 var ans=dup(x);
318 mod_(ans,n);
319 return trim(ans,1);
320}
321
322//return (x+n) where x is a bigInt and n is an integer.
323function addInt(x,n) {
324 var ans=expand(x,x.length+1);
325 addInt_(ans,n);
326 return trim(ans,1);
327}
328
329//return x*y for bigInts x and y. This is faster when y<x.
330function mult(x,y) {
331 var ans=expand(x,x.length+y.length);
332 mult_(ans,y);
333 return trim(ans,1);
334}
335
336//return (x**y mod n) where x,y,n are bigInts and ** is exponentiation. 0**0=1. Faster for odd n.
337function powMod(x,y,n) {
338 var ans=expand(x,n.length);
339 powMod_(ans,trim(y,2),trim(n,2),0); //this should work without the trim, but doesn't
340 return trim(ans,1);
341}
342
343//return (x-y) for bigInts x and y. Negative answers will be 2s complement
344function sub(x,y) {
345 var ans=expand(x,(x.length>y.length ? x.length+1 : y.length+1));
346 sub_(ans,y);
347 return trim(ans,1);
348}
349
350//return (x+y) for bigInts x and y.
351function add(x,y) {
352 var ans=expand(x,(x.length>y.length ? x.length+1 : y.length+1));
353 add_(ans,y);
354 return trim(ans,1);
355}
356
357//return (x**(-1) mod n) for bigInts x and n. If no inverse exists, it returns null
358function inverseMod(x,n) {
359 var ans=expand(x,n.length);
360 var s;
361 s=inverseMod_(ans,n);
362 return s ? trim(ans,1) : null;
363}
364
365//return (x*y mod n) for bigInts x,y,n. For greater speed, let y<x.
366function multMod(x,y,n) {
367 var ans=expand(x,n.length);
368 multMod_(ans,y,n);
369 return trim(ans,1);
370}
371
372//generate a k-bit true random prime using Maurer's algorithm,
373//and put it into ans. The bigInt ans must be large enough to hold it.
374function randTruePrime_(ans,k) {
375 var c,m,pm,dd,j,r,B,divisible,z,zz,recSize;
376
377 if (primes.length==0)
378 primes=findPrimes(30000); //check for divisibility by primes <=30000
379
380 if (pows.length==0) {
381 pows=new Array(512);
382 for (j=0;j<512;j++) {
383 pows[j]=Math.pow(2,j/511.-1.);
384 }
385 }
386
387 //c and m should be tuned for a particular machine and value of k, to maximize speed
388 //this was: c=primes[primes.length-1]/k/k; //check using all the small primes. (c=0.1 in HAC)
389 c=0.1;
390 m=20; //generate this k-bit number by first recursively generating a number that has between k/2 and k-m bits
391 recLimit=20; /*must be at least 2 (was 29)*/ //stop recursion when k <=recLimit
392
393 if (s_i2.length!=ans.length) {
394 s_i2=dup(ans);
395 s_R =dup(ans);
396 s_n1=dup(ans);
397 s_r2=dup(ans);
398 s_d =dup(ans);
399 s_x1=dup(ans);
400 s_x2=dup(ans);
401 s_b =dup(ans);
402 s_n =dup(ans);
403 s_i =dup(ans);
404 s_rm=dup(ans);
405 s_q =dup(ans);
406 s_a =dup(ans);
407 s_aa=dup(ans);
408 }
409
410 if (k <= recLimit) { //generate small random primes by trial division up to its square root
411 pm=(1<<((k+2)>>1))-1; //pm is binary number with all ones, just over sqrt(2^k)
412 copyInt_(ans,0);
413 for (dd=1;dd;) {
414 dd=0;
415 ans[0]= 1 | (1<<(k-1)) | Math.floor(Math.random()*(1<<k)); //random, k-bit, odd integer, with msb 1
416 for (j=1;(j<primes.length) && ((primes[j]&pm)==primes[j]);j++) { //trial division by all primes 3...sqrt(2^k)
417 if (0==(ans[0]%primes[j])) {
418 dd=1;
419 break;
420 }
421 }
422 }
423 carry_(ans);
424 return;
425 }
426
427 B=c*k*k; //try small primes up to B (or all the primes[] array if the largest is less than B).
428 if (k>2*m) //generate this k-bit number by first recursively generating a number that has between k/2 and k-m bits
429 for (r=1; k-k*r<=m; )
430 r=pows[Math.floor(Math.random()*512)]; //r=Math.pow(2,Math.random()-1);
431 else
432 r=.5;
433
434 //simulation suggests the more complex algorithm using r=.333 is only slightly faster.
435
436 recSize=Math.floor(r*k)+1;
437
438 randTruePrime_(s_q,recSize);
439 copyInt_(s_i2,0);
440 s_i2[Math.floor((k-2)/bpe)] |= (1<<((k-2)%bpe)); //s_i2=2^(k-2)
441 divide_(s_i2,s_q,s_i,s_rm); //s_i=floor((2^(k-1))/(2q))
442
443 z=bitSize(s_i);
444
445 for (;;) {
446 for (;;) { //generate z-bit numbers until one falls in the range [0,s_i-1]
447 randBigInt_(s_R,z,0);
448 if (greater(s_i,s_R))
449 break;
450 } //now s_R is in the range [0,s_i-1]
451 addInt_(s_R,1); //now s_R is in the range [1,s_i]
452 add_(s_R,s_i); //now s_R is in the range [s_i+1,2*s_i]
453
454 copy_(s_n,s_q);
455 mult_(s_n,s_R);
456 multInt_(s_n,2);
457 addInt_(s_n,1); //s_n=2*s_R*s_q+1
458
459 copy_(s_r2,s_R);
460 multInt_(s_r2,2); //s_r2=2*s_R
461
462 //check s_n for divisibility by small primes up to B
463 for (divisible=0,j=0; (j<primes.length) && (primes[j]<B); j++)
464 if (modInt(s_n,primes[j])==0) {
465 divisible=1;
466 break;
467 }
468
469 if (!divisible) //if it passes small primes check, then try a single Miller-Rabin base 2
470 if (!millerRabin(s_n,2)) //this line represents 75% of the total runtime for randTruePrime_
471 divisible=1;
472
473 if (!divisible) { //if it passes that test, continue checking s_n
474 addInt_(s_n,-3);
475 for (j=s_n.length-1;(s_n[j]==0) && (j>0); j--); //strip leading zeros
476 for (zz=0,w=s_n[j]; w; (w>>=1),zz++);
477 zz+=bpe*j; //zz=number of bits in s_n, ignoring leading zeros
478 for (;;) { //generate z-bit numbers until one falls in the range [0,s_n-1]
479 randBigInt_(s_a,zz,0);
480 if (greater(s_n,s_a))
481 break;
482 } //now s_a is in the range [0,s_n-1]
483 addInt_(s_n,3); //now s_a is in the range [0,s_n-4]
484 addInt_(s_a,2); //now s_a is in the range [2,s_n-2]
485 copy_(s_b,s_a);
486 copy_(s_n1,s_n);
487 addInt_(s_n1,-1);
488 powMod_(s_b,s_n1,s_n); //s_b=s_a^(s_n-1) modulo s_n
489 addInt_(s_b,-1);
490 if (isZero(s_b)) {
491 copy_(s_b,s_a);
492 powMod_(s_b,s_r2,s_n);
493 addInt_(s_b,-1);
494 copy_(s_aa,s_n);
495 copy_(s_d,s_b);
496 GCD_(s_d,s_n); //if s_b and s_n are relatively prime, then s_n is a prime
497 if (equalsInt(s_d,1)) {
498 copy_(ans,s_aa);
499 return; //if we've made it this far, then s_n is absolutely guaranteed to be prime
500 }
501 }
502 }
503 }
504}
505
506//set b to an n-bit random BigInt. If s=1, then nth bit (most significant bit) is set to 1.
507//array b must be big enough to hold the result. Must have n>=1
508function randBigInt_(b,n,s) {
509 var i,a;
510 for (i=0;i<b.length;i++)
511 b[i]=0;
512 a=Math.floor((n-1)/bpe)+1; //# array elements to hold the BigInt
513 for (i=0;i<a;i++) {
514 b[i]=Math.floor(Math.random()*(1<<(bpe-1)));
515 }
516 b[a-1] &= (2<<((n-1)%bpe))-1;
517 if (s)
518 b[a-1] |= (1<<((n-1)%bpe));
519}
520
521//set x to the greatest common divisor of x and y.
522//x,y are bigInts with the same number of elements. y is destroyed.
523function GCD_(x,y) {
524 var i,xp,yp,A,B,C,D,q,sing;
525 if (T.length!=x.length)
526 T=dup(x);
527
528 sing=1;
529 while (sing) { //while y has nonzero elements other than y[0]
530 sing=0;
531 for (i=1;i<y.length;i++) //check if y has nonzero elements other than 0
532 if (y[i]) {
533 sing=1;
534 break;
535 }
536 if (!sing) break; //quit when y all zero elements except possibly y[0]
537
538 for (i=x.length;!x[i] && i>=0;i--); //find most significant element of x
539 xp=x[i];
540 yp=y[i];
541 A=1; B=0; C=0; D=1;
542 while ((yp+C) && (yp+D)) {
543 q =Math.floor((xp+A)/(yp+C));
544 qp=Math.floor((xp+B)/(yp+D));
545 if (q!=qp)
546 break;
547 t= A-q*C; A=C; C=t; // do (A,B,xp, C,D,yp) = (C,D,yp, A,B,xp) - q*(0,0,0, C,D,yp)
548 t= B-q*D; B=D; D=t;
549 t=xp-q*yp; xp=yp; yp=t;
550 }
551 if (B) {
552 copy_(T,x);
553 linComb_(x,y,A,B); //x=A*x+B*y
554 linComb_(y,T,D,C); //y=D*y+C*T
555 } else {
556 mod_(x,y);
557 copy_(T,x);
558 copy_(x,y);
559 copy_(y,T);
560 }
561 }
562 if (y[0]==0)
563 return;
564 t=modInt(x,y[0]);
565 copyInt_(x,y[0]);
566 y[0]=t;
567 while (y[0]) {
568 x[0]%=y[0];
569 t=x[0]; x[0]=y[0]; y[0]=t;
570 }
571}
572
573//do x=x**(-1) mod n, for bigInts x and n.
574//If no inverse exists, it sets x to zero and returns 0, else it returns 1.
575//The x array must be at least as large as the n array.
576function inverseMod_(x,n) {
577 var k=1+2*Math.max(x.length,n.length);
578
579 if(!(x[0]&1) && !(n[0]&1)) { //if both inputs are even, then inverse doesn't exist
580 copyInt_(x,0);
581 return 0;
582 }
583
584 if (eg_u.length!=k) {
585 eg_u=new Array(k);
586 eg_v=new Array(k);
587 eg_A=new Array(k);
588 eg_B=new Array(k);
589 eg_C=new Array(k);
590 eg_D=new Array(k);
591 }
592
593 copy_(eg_u,x);
594 copy_(eg_v,n);
595 copyInt_(eg_A,1);
596 copyInt_(eg_B,0);
597 copyInt_(eg_C,0);
598 copyInt_(eg_D,1);
599 for (;;) {
600 while(!(eg_u[0]&1)) { //while eg_u is even
601 halve_(eg_u);
602 if (!(eg_A[0]&1) && !(eg_B[0]&1)) { //if eg_A==eg_B==0 mod 2
603 halve_(eg_A);
604 halve_(eg_B);
605 } else {
606 add_(eg_A,n); halve_(eg_A);
607 sub_(eg_B,x); halve_(eg_B);
608 }
609 }
610
611 while (!(eg_v[0]&1)) { //while eg_v is even
612 halve_(eg_v);
613 if (!(eg_C[0]&1) && !(eg_D[0]&1)) { //if eg_C==eg_D==0 mod 2
614 halve_(eg_C);
615 halve_(eg_D);
616 } else {
617 add_(eg_C,n); halve_(eg_C);
618 sub_(eg_D,x); halve_(eg_D);
619 }
620 }
621
622 if (!greater(eg_v,eg_u)) { //eg_v <= eg_u
623 sub_(eg_u,eg_v);
624 sub_(eg_A,eg_C);
625 sub_(eg_B,eg_D);
626 } else { //eg_v > eg_u
627 sub_(eg_v,eg_u);
628 sub_(eg_C,eg_A);
629 sub_(eg_D,eg_B);
630 }
631
632 if (equalsInt(eg_u,0)) {
633 if (negative(eg_C)) //make sure answer is nonnegative
634 add_(eg_C,n);
635 copy_(x,eg_C);
636
637 if (!equalsInt(eg_v,1)) { //if GCD_(x,n)!=1, then there is no inverse
638 copyInt_(x,0);
639 return 0;
640 }
641 return 1;
642 }
643 }
644}
645
646//return x**(-1) mod n, for integers x and n. Return 0 if there is no inverse
647function inverseModInt_(x,n) {
648 var a=1,b=0,t;
649 for (;;) {
650 if (x==1) return a;
651 if (x==0) return 0;
652 b-=a*Math.floor(n/x);
653 n%=x;
654
655 if (n==1) return b; //to avoid negatives, change this b to n-b, and each -= to +=
656 if (n==0) return 0;
657 a-=b*Math.floor(x/n);
658 x%=n;
659 }
660}
661
662//Given positive bigInts x and y, change the bigints v, a, and b to positive bigInts such that:
663// v = GCD_(x,y) = a*x-b*y
664//The bigInts v, a, b, must have exactly as many elements as the larger of x and y.
665function eGCD_(x,y,v,a,b) {
666 var g=0;
667 var k=Math.max(x.length,y.length);
668 if (eg_u.length!=k) {
669 eg_u=new Array(k);
670 eg_A=new Array(k);
671 eg_B=new Array(k);
672 eg_C=new Array(k);
673 eg_D=new Array(k);
674 }
675 while(!(x[0]&1) && !(y[0]&1)) { //while x and y both even
676 halve_(x);
677 halve_(y);
678 g++;
679 }
680 copy_(eg_u,x);
681 copy_(v,y);
682 copyInt_(eg_A,1);
683 copyInt_(eg_B,0);
684 copyInt_(eg_C,0);
685 copyInt_(eg_D,1);
686 for (;;) {
687 while(!(eg_u[0]&1)) { //while u is even
688 halve_(eg_u);
689 if (!(eg_A[0]&1) && !(eg_B[0]&1)) { //if A==B==0 mod 2
690 halve_(eg_A);
691 halve_(eg_B);
692 } else {
693 add_(eg_A,y); halve_(eg_A);
694 sub_(eg_B,x); halve_(eg_B);
695 }
696 }
697
698 while (!(v[0]&1)) { //while v is even
699 halve_(v);
700 if (!(eg_C[0]&1) && !(eg_D[0]&1)) { //if C==D==0 mod 2
701 halve_(eg_C);
702 halve_(eg_D);
703 } else {
704 add_(eg_C,y); halve_(eg_C);
705 sub_(eg_D,x); halve_(eg_D);
706 }
707 }
708
709 if (!greater(v,eg_u)) { //v<=u
710 sub_(eg_u,v);
711 sub_(eg_A,eg_C);
712 sub_(eg_B,eg_D);
713 } else { //v>u
714 sub_(v,eg_u);
715 sub_(eg_C,eg_A);
716 sub_(eg_D,eg_B);
717 }
718 if (equalsInt(eg_u,0)) {
719 if (negative(eg_C)) { //make sure a (C)is nonnegative
720 add_(eg_C,y);
721 sub_(eg_D,x);
722 }
723 multInt_(eg_D,-1); ///make sure b (D) is nonnegative
724 copy_(a,eg_C);
725 copy_(b,eg_D);
726 leftShift_(v,g);
727 return;
728 }
729 }
730}
731
732
733//is bigInt x negative?
734function negative(x) {
735 return ((x[x.length-1]>>(bpe-1))&1);
736}
737
738
739//is (x << (shift*bpe)) > y?
740//x and y are nonnegative bigInts
741//shift is a nonnegative integer
742function greaterShift(x,y,shift) {
743 var kx=x.length, ky=y.length;
744 k=((kx+shift)<ky) ? (kx+shift) : ky;
745 for (i=ky-1-shift; i<kx && i>=0; i++)
746 if (x[i]>0)
747 return 1; //if there are nonzeros in x to the left of the first column of y, then x is bigger
748 for (i=kx-1+shift; i<ky; i++)
749 if (y[i]>0)
750 return 0; //if there are nonzeros in y to the left of the first column of x, then x is not bigger
751 for (i=k-1; i>=shift; i--)
752 if (x[i-shift]>y[i]) return 1;
753 else if (x[i-shift]<y[i]) return 0;
754 return 0;
755}
756
757//is x > y? (x and y both nonnegative)
758function greater(x,y) {
759 var i;
760 var k=(x.length<y.length) ? x.length : y.length;
761
762 for (i=x.length;i<y.length;i++)
763 if (y[i])
764 return 0; //y has more digits
765
766 for (i=y.length;i<x.length;i++)
767 if (x[i])
768 return 1; //x has more digits
769
770 for (i=k-1;i>=0;i--)
771 if (x[i]>y[i])
772 return 1;
773 else if (x[i]<y[i])
774 return 0;
775 return 0;
776}
777
778//divide_ x by y giving quotient q and remainder r. (q=floor(x/y), r=x mod y). All 4 are bigints.
779//x must have at least one leading zero element.
780//y must be nonzero.
781//q and r must be arrays that are exactly the same length as x.
782//the x array must have at least as many elements as y.
783function divide_(x,y,q,r) {
784 var kx, ky;
785 var i,j,y1,y2,c,a,b;
786 copy_(r,x);
787 for (ky=y.length;y[ky-1]==0;ky--); //kx,ky is number of elements in x,y, not including leading zeros
788 for (kx=r.length;r[kx-1]==0 && kx>ky;kx--);
789
790 //normalize: ensure the most significant element of y has its highest bit set
791 b=y[ky-1];
792 for (a=0; b; a++)
793 b>>=1;
794 a=bpe-a; //a is how many bits to shift so that the high order bit of y is leftmost in its array element
795 leftShift_(y,a); //multiply both by 1<<a now, then divide_ both by that at the end
796 leftShift_(r,a);
797
798 copyInt_(q,0); // q=0
799 while (!greaterShift(y,r,kx-ky)) { // while (leftShift_(y,kx-ky) <= r) {
800 subShift_(r,y,kx-ky); // r=r-leftShift_(y,kx-ky)
801 q[kx-ky]++; // q[kx-ky]++;
802 } // }
803
804 for (i=kx-1; i>=ky; i--) {
805 if (r[i]==y[ky-1])
806 q[i-ky]=mask;
807 else
808 q[i-ky]=Math.floor((r[i]*radix+r[i-1])/y[ky-1]);
809
810 //The following for(;;) loop is equivalent to the commented while loop,
811 //except that the uncommented version avoids overflow.
812 //The commented loop comes from HAC, which assumes r[-1]==y[-1]==0
813 // while (q[i-ky]*(y[ky-1]*radix+y[ky-2]) > r[i]*radix*radix+r[i-1]*radix+r[i-2])
814 // q[i-ky]--;
815 for (;;) {
816 y2=(ky>1 ? y[ky-2] : 0)*q[i-ky];
817 c=y2>>bpe;
818 y2=y2 & mask;
819 y1=c+q[i-ky]*y[ky-1];
820 c=y1>>bpe;
821 y1=y1 & mask;
822
823 if (c==r[i] ? y1==r[i-1] ? y2>(i>1 ? r[i-2] : 0) : y1>r[i-1] : c>r[i])
824 q[i-ky]--;
825 else
826 break;
827 }
828
829 linCombShift_(r,y,-q[i-ky],i-ky); //r=r-q[i-ky]*leftShift_(y,i-ky)
830 if (negative(r)) {
831 addShift_(r,y,i-ky); //r=r+leftShift_(y,i-ky)
832 q[i-ky]--;
833 }
834 }
835
836 rightShift_(y,a); //undo the normalization step
837 rightShift_(r,a); //undo the normalization step
838}
839
840//do carries and borrows so each element of the bigInt x fits in bpe bits.
841function carry_(x) {
842 var i,k,c,b;
843 k=x.length;
844 c=0;
845 for (i=0;i<k;i++) {
846 c+=x[i];
847 b=0;
848 if (c<0) {
849 b=-(c>>bpe);
850 c+=b*radix;
851 }
852 x[i]=c & mask;
853 c=(c>>bpe)-b;
854 }
855}
856
857//return x mod n for bigInt x and integer n.
858function modInt(x,n) {
859 var i,c=0;
860 for (i=x.length-1; i>=0; i--)
861 c=(c*radix+x[i])%n;
862 return c;
863}
864
865//convert the integer t into a bigInt with at least the given number of bits.
866//the returned array stores the bigInt in bpe-bit chunks, little endian (buff[0] is least significant word)
867//Pad the array with leading zeros so that it has at least minSize elements.
868//There will always be at least one leading 0 element.
869function int2bigInt(t,bits,minSize) {
870 var i,k;
871 k=Math.ceil(bits/bpe)+1;
872 k=minSize>k ? minSize : k;
873 buff=new Array(k);
874 copyInt_(buff,t);
875 return buff;
876}
877
878//return the bigInt given a string representation in a given base.
879//Pad the array with leading zeros so that it has at least minSize elements.
880//If base=-1, then it reads in a space-separated list of array elements in decimal.
881//The array will always have at least one leading zero, unless base=-1.
882function str2bigInt(s,base,minSize) {
883 var d, i, j, x, y, kk;
884 var k=s.length;
885 if (base==-1) { //comma-separated list of array elements in decimal
886 x=new Array(0);
887 for (;;) {
888 y=new Array(x.length+1);
889 for (i=0;i<x.length;i++)
890 y[i+1]=x[i];
891 y[0]=parseInt(s,10);
892 x=y;
893 d=s.indexOf(',',0);
894 if (d<1)
895 break;
896 s=s.substring(d+1);
897 if (s.length==0)
898 break;
899 }
900 if (x.length<minSize) {
901 y=new Array(minSize);
902 copy_(y,x);
903 return y;
904 }
905 return x;
906 }
907
908 x=int2bigInt(0,base*k,0);
909 for (i=0;i<k;i++) {
910 d=digitsStr.indexOf(s.substring(i,i+1),0);
911 if (base<=36 && d>=36) //convert lowercase to uppercase if base<=36
912 d-=26;
913 if (d<base && d>=0) { //ignore illegal characters
914 multInt_(x,base);
915 addInt_(x,d);
916 }
917 }
918
919 for (k=x.length;k>0 && !x[k-1];k--); //strip off leading zeros
920 k=minSize>k+1 ? minSize : k+1;
921 y=new Array(k);
922 kk=k<x.length ? k : x.length;
923 for (i=0;i<kk;i++)
924 y[i]=x[i];
925 for (;i<k;i++)
926 y[i]=0;
927 return y;
928}
929
930//is bigint x equal to integer y?
931//y must have less than bpe bits
932function equalsInt(x,y) {
933 var i;
934 if (x[0]!=y)
935 return 0;
936 for (i=1;i<x.length;i++)
937 if (x[i])
938 return 0;
939 return 1;
940}
941
942//are bigints x and y equal?
943//this works even if x and y are different lengths and have arbitrarily many leading zeros
944function equals(x,y) {
945 var i;
946 var k=x.length<y.length ? x.length : y.length;
947 for (i=0;i<k;i++)
948 if (x[i]!=y[i])
949 return 0;
950 if (x.length>y.length) {
951 for (;i<x.length;i++)
952 if (x[i])
953 return 0;
954 } else {
955 for (;i<y.length;i++)
956 if (y[i])
957 return 0;
958 }
959 return 1;
960}
961
962//is the bigInt x equal to zero?
963function isZero(x) {
964 var i;
965 for (i=0;i<x.length;i++)
966 if (x[i])
967 return 0;
968 return 1;
969}
970
971//convert a bigInt into a string in a given base, from base 2 up to base 95.
972//Base -1 prints the contents of the array representing the number.
973function bigInt2str(x,base) {
974 var i,t,s="";
975
976 if (s6.length!=x.length)
977 s6=dup(x);
978 else
979 copy_(s6,x);
980
981 if (base==-1) { //return the list of array contents
982 for (i=x.length-1;i>0;i--)
983 s+=x[i]+',';
984 s+=x[0];
985 }
986 else { //return it in the given base
987 while (!isZero(s6)) {
988 t=divInt_(s6,base); //t=s6 % base; s6=floor(s6/base);
989 s=digitsStr.substring(t,t+1)+s;
990 }
991 }
992 if (s.length==0)
993 s="0";
994 return s;
995}
996
997//returns a duplicate of bigInt x
998function dup(x) {
999 var i;
1000 buff=new Array(x.length);
1001 copy_(buff,x);
1002 return buff;
1003}
1004
1005//do x=y on bigInts x and y. x must be an array at least as big as y (not counting the leading zeros in y).
1006function copy_(x,y) {
1007 var i;
1008 var k=x.length<y.length ? x.length : y.length;
1009 for (i=0;i<k;i++)
1010 x[i]=y[i];
1011 for (i=k;i<x.length;i++)
1012 x[i]=0;
1013}
1014
1015//do x=y on bigInt x and integer y.
1016function copyInt_(x,n) {
1017 var i,c;
1018 for (c=n,i=0;i<x.length;i++) {
1019 x[i]=c & mask;
1020 c>>=bpe;
1021 }
1022}
1023
1024//do x=x+n where x is a bigInt and n is an integer.
1025//x must be large enough to hold the result.
1026function addInt_(x,n) {
1027 var i,k,c,b;
1028 x[0]+=n;
1029 k=x.length;
1030 c=0;
1031 for (i=0;i<k;i++) {
1032 c+=x[i];
1033 b=0;
1034 if (c<0) {
1035 b=-(c>>bpe);
1036 c+=b*radix;
1037 }
1038 x[i]=c & mask;
1039 c=(c>>bpe)-b;
1040 if (!c) return; //stop carrying as soon as the carry_ is zero
1041 }
1042}
1043
1044//right shift bigInt x by n bits. 0 <= n < bpe.
1045function rightShift_(x,n) {
1046 var i;
1047 var k=Math.floor(n/bpe);
1048 if (k) {
1049 for (i=0;i<x.length-k;i++) //right shift x by k elements
1050 x[i]=x[i+k];
1051 for (;i<x.length;i++)
1052 x[i]=0;
1053 n%=bpe;
1054 }
1055 for (i=0;i<x.length-1;i++) {
1056 x[i]=mask & ((x[i+1]<<(bpe-n)) | (x[i]>>n));
1057 }
1058 x[i]>>=n;
1059}
1060
1061//do x=floor(|x|/2)*sgn(x) for bigInt x in 2's complement
1062function halve_(x) {
1063 var i;
1064 for (i=0;i<x.length-1;i++) {
1065 x[i]=mask & ((x[i+1]<<(bpe-1)) | (x[i]>>1));
1066 }
1067 x[i]=(x[i]>>1) | (x[i] & (radix>>1)); //most significant bit stays the same
1068}
1069
1070//left shift bigInt x by n bits.
1071function leftShift_(x,n) {
1072 var i;
1073 var k=Math.floor(n/bpe);
1074 if (k) {
1075 for (i=x.length; i>=k; i--) //left shift x by k elements
1076 x[i]=x[i-k];
1077 for (;i>=0;i--)
1078 x[i]=0;
1079 n%=bpe;
1080 }
1081 if (!n)
1082 return;
1083 for (i=x.length-1;i>0;i--) {
1084 x[i]=mask & ((x[i]<<n) | (x[i-1]>>(bpe-n)));
1085 }
1086 x[i]=mask & (x[i]<<n);
1087}
1088
1089//do x=x*n where x is a bigInt and n is an integer.
1090//x must be large enough to hold the result.
1091function multInt_(x,n) {
1092 var i,k,c,b;
1093 if (!n)
1094 return;
1095 k=x.length;
1096 c=0;
1097 for (i=0;i<k;i++) {
1098 c+=x[i]*n;
1099 b=0;
1100 if (c<0) {
1101 b=-(c>>bpe);
1102 c+=b*radix;
1103 }
1104 x[i]=c & mask;
1105 c=(c>>bpe)-b;
1106 }
1107}
1108
1109//do x=floor(x/n) for bigInt x and integer n, and return the remainder
1110function divInt_(x,n) {
1111 var i,r=0,s;
1112 for (i=x.length-1;i>=0;i--) {
1113 s=r*radix+x[i];
1114 x[i]=Math.floor(s/n);
1115 r=s%n;
1116 }
1117 return r;
1118}
1119
1120//do the linear combination x=a*x+b*y for bigInts x and y, and integers a and b.
1121//x must be large enough to hold the answer.
1122function linComb_(x,y,a,b) {
1123 var i,c,k,kk;
1124 k=x.length<y.length ? x.length : y.length;
1125 kk=x.length;
1126 for (c=0,i=0;i<k;i++) {
1127 c+=a*x[i]+b*y[i];
1128 x[i]=c & mask;
1129 c>>=bpe;
1130 }
1131 for (i=k;i<kk;i++) {
1132 c+=a*x[i];
1133 x[i]=c & mask;
1134 c>>=bpe;
1135 }
1136}
1137
1138//do the linear combination x=a*x+b*(y<<(ys*bpe)) for bigInts x and y, and integers a, b and ys.
1139//x must be large enough to hold the answer.
1140function linCombShift_(x,y,b,ys) {
1141 var i,c,k,kk;
1142 k=x.length<ys+y.length ? x.length : ys+y.length;
1143 kk=x.length;
1144 for (c=0,i=ys;i<k;i++) {
1145 c+=x[i]+b*y[i-ys];
1146 x[i]=c & mask;
1147 c>>=bpe;
1148 }
1149 for (i=k;c && i<kk;i++) {
1150 c+=x[i];
1151 x[i]=c & mask;
1152 c>>=bpe;
1153 }
1154}
1155
1156//do x=x+(y<<(ys*bpe)) for bigInts x and y, and integers a,b and ys.
1157//x must be large enough to hold the answer.
1158function addShift_(x,y,ys) {
1159 var i,c,k,kk;
1160 k=x.length<ys+y.length ? x.length : ys+y.length;
1161 kk=x.length;
1162 for (c=0,i=ys;i<k;i++) {
1163 c+=x[i]+y[i-ys];
1164 x[i]=c & mask;
1165 c>>=bpe;
1166 }
1167 for (i=k;c && i<kk;i++) {
1168 c+=x[i];
1169 x[i]=c & mask;
1170 c>>=bpe;
1171 }
1172}
1173
1174//do x=x-(y<<(ys*bpe)) for bigInts x and y, and integers a,b and ys.
1175//x must be large enough to hold the answer.
1176function subShift_(x,y,ys) {
1177 var i,c,k,kk;
1178 k=x.length<ys+y.length ? x.length : ys+y.length;
1179 kk=x.length;
1180 for (c=0,i=ys;i<k;i++) {
1181 c+=x[i]-y[i-ys];
1182 x[i]=c & mask;
1183 c>>=bpe;
1184 }
1185 for (i=k;c && i<kk;i++) {
1186 c+=x[i];
1187 x[i]=c & mask;
1188 c>>=bpe;
1189 }
1190}
1191
1192//do x=x-y for bigInts x and y.
1193//x must be large enough to hold the answer.
1194//negative answers will be 2s complement
1195function sub_(x,y) {
1196 var i,c,k,kk;
1197 k=x.length<y.length ? x.length : y.length;
1198 for (c=0,i=0;i<k;i++) {
1199 c+=x[i]-y[i];
1200 x[i]=c & mask;
1201 c>>=bpe;
1202 }
1203 for (i=k;c && i<x.length;i++) {
1204 c+=x[i];
1205 x[i]=c & mask;
1206 c>>=bpe;
1207 }
1208}
1209
1210//do x=x+y for bigInts x and y.
1211//x must be large enough to hold the answer.
1212function add_(x,y) {
1213 var i,c,k,kk;
1214 k=x.length<y.length ? x.length : y.length;
1215 for (c=0,i=0;i<k;i++) {
1216 c+=x[i]+y[i];
1217 x[i]=c & mask;
1218 c>>=bpe;
1219 }
1220 for (i=k;c && i<x.length;i++) {
1221 c+=x[i];
1222 x[i]=c & mask;
1223 c>>=bpe;
1224 }
1225}
1226
1227//do x=x*y for bigInts x and y. This is faster when y<x.
1228function mult_(x,y) {
1229 var i;
1230 if (ss.length!=2*x.length)
1231 ss=new Array(2*x.length);
1232 copyInt_(ss,0);
1233 for (i=0;i<y.length;i++)
1234 if (y[i])
1235 linCombShift_(ss,x,y[i],i); //ss=1*ss+y[i]*(x<<(i*bpe))
1236 copy_(x,ss);
1237}
1238
1239//do x=x mod n for bigInts x and n.
1240function mod_(x,n) {
1241 if (s4.length!=x.length)
1242 s4=dup(x);
1243 else
1244 copy_(s4,x);
1245 if (s5.length!=x.length)
1246 s5=dup(x);
1247 divide_(s4,n,s5,x); //x = remainder of s4 / n
1248}
1249
1250//do x=x*y mod n for bigInts x,y,n.
1251//for greater speed, let y<x.
1252function multMod_(x,y,n) {
1253 var i;
1254 if (s0.length!=2*x.length)
1255 s0=new Array(2*x.length);
1256 copyInt_(s0,0);
1257 for (i=0;i<y.length;i++)
1258 if (y[i])
1259 linCombShift_(s0,x,y[i],i); //s0=1*s0+y[i]*(x<<(i*bpe))
1260 mod_(s0,n);
1261 copy_(x,s0);
1262}
1263
1264//do x=x*x mod n for bigInts x,n.
1265function squareMod_(x,n) {
1266 var i,j,d,c,kx,kn,k;
1267 for (kx=x.length; kx>0 && !x[kx-1]; kx--); //ignore leading zeros in x
1268 k=kx>n.length ? 2*kx : 2*n.length; //k=# elements in the product, which is twice the elements in the larger of x and n
1269 if (s0.length!=k)
1270 s0=new Array(k);
1271 copyInt_(s0,0);
1272 for (i=0;i<kx;i++) {
1273 c=s0[2*i]+x[i]*x[i];
1274 s0[2*i]=c & mask;
1275 c>>=bpe;
1276 for (j=i+1;j<kx;j++) {
1277 c=s0[i+j]+2*x[i]*x[j]+c;
1278 s0[i+j]=(c & mask);
1279 c>>=bpe;
1280 }
1281 s0[i+kx]=c;
1282 }
1283 mod_(s0,n);
1284 copy_(x,s0);
1285}
1286
1287//return x with exactly k leading zero elements
1288function trim(x,k) {
1289 var i,y;
1290 for (i=x.length; i>0 && !x[i-1]; i--);
1291 y=new Array(i+k);
1292 copy_(y,x);
1293 return y;
1294}
1295
1296//do x=x**y mod n, where x,y,n are bigInts and ** is exponentiation. 0**0=1.
1297//this is faster when n is odd. x usually needs to have as many elements as n.
1298function powMod_(x,y,n) {
1299 var k1,k2,kn,np;
1300 if(s7.length!=n.length)
1301 s7=dup(n);
1302
1303 //for even modulus, use a simple square-and-multiply algorithm,
1304 //rather than using the more complex Montgomery algorithm.
1305 if ((n[0]&1)==0) {
1306 copy_(s7,x);
1307 copyInt_(x,1);
1308 while(!equalsInt(y,0)) {
1309 if (y[0]&1)
1310 multMod_(x,s7,n);
1311 divInt_(y,2);
1312 squareMod_(s7,n);
1313 }
1314 return;
1315 }
1316
1317 //calculate np from n for the Montgomery multiplications
1318 copyInt_(s7,0);
1319 for (kn=n.length;kn>0 && !n[kn-1];kn--);
1320 np=radix-inverseModInt_(modInt(n,radix),radix);
1321 s7[kn]=1;
1322 multMod_(x ,s7,n); // x = x * 2**(kn*bp) mod n
1323
1324 if (s3.length!=x.length)
1325 s3=dup(x);
1326 else
1327 copy_(s3,x);
1328
1329 for (k1=y.length-1;k1>0 & !y[k1]; k1--); //k1=first nonzero element of y
1330 if (y[k1]==0) { //anything to the 0th power is 1
1331 copyInt_(x,1);
1332 return;
1333 }
1334 for (k2=1<<(bpe-1);k2 && !(y[k1] & k2); k2>>=1); //k2=position of first 1 bit in y[k1]
1335 for (;;) {
1336 if (!(k2>>=1)) { //look at next bit of y
1337 k1--;
1338 if (k1<0) {
1339 mont_(x,one,n,np);
1340 return;
1341 }
1342 k2=1<<(bpe-1);
1343 }
1344 mont_(x,x,n,np);
1345
1346 if (k2 & y[k1]) //if next bit is a 1
1347 mont_(x,s3,n,np);
1348 }
1349}
1350
1351//do x=x*y*Ri mod n for bigInts x,y,n,
1352// where Ri = 2**(-kn*bpe) mod n, and kn is the
1353// number of elements in the n array, not
1354// counting leading zeros.
1355//x must be large enough to hold the answer.
1356//It's OK if x and y are the same variable.
1357//must have:
1358// x,y < n
1359// n is odd
1360// np = -(n^(-1)) mod radix
1361function mont_(x,y,n,np) {
1362 var i,j,c,ui,t;
1363 var kn=n.length;
1364 var ky=y.length;
1365
1366 if (sa.length!=kn)
1367 sa=new Array(kn);
1368
1369 for (;kn>0 && n[kn-1]==0;kn--); //ignore leading zeros of n
1370 //this function sometimes gives wrong answers when the next line is uncommented
1371 //for (;ky>0 && y[ky-1]==0;ky--); //ignore leading zeros of y
1372
1373 copyInt_(sa,0);
1374
1375 //the following loop consumes 95% of the runtime for randTruePrime_() and powMod_() for large keys
1376 for (i=0; i<kn; i++) {
1377 t=sa[0]+x[i]*y[0];
1378 ui=((t & mask) * np) & mask; //the inner "& mask" is needed on Macintosh MSIE, but not windows MSIE
1379 c=(t+ui*n[0]) >> bpe;
1380 t=x[i];
1381
1382 //do sa=(sa+x[i]*y+ui*n)/b where b=2**bpe
1383 for (j=1;j<ky;j++) {
1384 c+=sa[j]+t*y[j]+ui*n[j];
1385 sa[j-1]=c & mask;
1386 c>>=bpe;
1387 }
1388 for (;j<kn;j++) {
1389 c+=sa[j]+ui*n[j];
1390 sa[j-1]=c & mask;
1391 c>>=bpe;
1392 }
1393 sa[j-1]=c & mask;
1394 }
1395
1396 if (!greater(n,sa))
1397 sub_(sa,n);
1398 copy_(x,sa);
1399}
1400
1401
1402
1403
1404//#############################################################################
1405//#############################################################################
1406//#############################################################################
1407//#############################################################################
1408//#############################################################################
1409//#############################################################################
1410//#############################################################################
1411
1412
1413
1414
1415
1416//#############################################################################
1417
1418Clipperz.Crypto.BigInt = function (aValue, aBase) {
1419 varbase;
1420 varvalue;
1421
1422 if (typeof(aValue) == 'object') {
1423 this._internalValue = aValue;
1424 } else {
1425 if (typeof(aValue) == 'undefined') {
1426 value = "0";
1427 } else {
1428 value = aValue + "";
1429 }
1430
1431 if (typeof(aBase) == 'undefined') {
1432 base = 10;
1433 } else {
1434 base = aBase;
1435 }
1436
1437 this._internalValue = str2bigInt(value, base, 1, 1);
1438 }
1439
1440 return this;
1441}
1442
1443//=============================================================================
1444
1445MochiKit.Base.update(Clipperz.Crypto.BigInt.prototype, {
1446
1447 'clone': function() {
1448 return new Clipperz.Crypto.BigInt(this.internalValue());
1449 },
1450
1451 //-------------------------------------------------------------------------
1452
1453 'internalValue': function () {
1454 return this._internalValue;
1455 },
1456
1457 //-------------------------------------------------------------------------
1458
1459 'isBigInt': true,
1460
1461 //-------------------------------------------------------------------------
1462
1463 'toString': function(aBase) {
1464 return this.asString(aBase);
1465 },
1466
1467 //-------------------------------------------------------------------------
1468
1469 'asString': function (aBase, minimumLength) {
1470 varresult;
1471 varbase;
1472
1473 if (typeof(aBase) == 'undefined') {
1474 base = 10;
1475 } else {
1476 base = aBase;
1477 }
1478
1479 result = bigInt2str(this.internalValue(), base).toLowerCase();
1480
1481 if ((typeof(minimumLength) != 'undefined') && (result.length < minimumLength)) {
1482 var i, c;
1483 //MochiKit.Logging.logDebug(">>> FIXING BigInt.asString length issue")
1484 c = (minimumLength - result.length);
1485 for (i=0; i<c; i++) {
1486 result = '0' + result;
1487 }
1488 }
1489
1490 return result;
1491 },
1492
1493 //-------------------------------------------------------------------------
1494
1495 'asByteArray': function() {
1496 return new Clipperz.ByteArray("0x" + this.asString(16), 16);
1497 },
1498
1499 //-------------------------------------------------------------------------
1500
1501 'equals': function (aValue) {
1502 var result;
1503
1504 if (aValue.isBigInt) {
1505 result = equals(this.internalValue(), aValue.internalValue());
1506 } else if (typeof(aValue) == "number") {
1507 result = equalsInt(this.internalValue(), aValue);
1508 } else {
1509 throw Clipperz.Crypt.BigInt.exception.UnknownType;
1510 }
1511
1512 return result;
1513 },
1514
1515 //-------------------------------------------------------------------------
1516
1517 'compare': function(aValue) {
1518/*
1519 var result;
1520 var thisAsString;
1521 var aValueAsString;
1522
1523 thisAsString = this.asString(10);
1524 aValueAsString = aValue.asString(10);
1525
1526 result = MochiKit.Base.compare(thisAsString.length, aValueAsString.length);
1527 if (result == 0) {
1528 result = MochiKit.Base.compare(thisAsString, aValueAsString);
1529 }
1530
1531 return result;
1532*/
1533 var result;
1534
1535 if (equals(this.internalValue(), aValue.internalValue())) {
1536 result = 0;
1537 } else if (greater(this.internalValue(), aValue.internalValue())) {
1538 result = 1;
1539 } else {
1540 result = -1;
1541 }
1542
1543 return result;
1544 },
1545
1546 //-------------------------------------------------------------------------
1547
1548 'add': function (aValue) {
1549 var result;
1550
1551 if (aValue.isBigInt) {
1552 result = add(this.internalValue(), aValue.internalValue());
1553 } else {
1554 result = addInt(this.internalValue(), aValue);
1555 }
1556
1557 return new Clipperz.Crypto.BigInt(result);
1558 },
1559
1560 //-------------------------------------------------------------------------
1561
1562 'subtract': function (aValue) {
1563 var result;
1564 var value;
1565
1566 if (aValue.isBigInt) {
1567 value = aValue;
1568 } else {
1569 value = new Clipperz.Crypto.BigInt(aValue);
1570 }
1571
1572 result = sub(this.internalValue(), value.internalValue());
1573
1574 return new Clipperz.Crypto.BigInt(result);
1575 },
1576
1577 //-------------------------------------------------------------------------
1578
1579 'multiply': function (aValue, aModule) {
1580 var result;
1581 var value;
1582
1583 if (aValue.isBigInt) {
1584 value = aValue;
1585 } else {
1586 value = new Clipperz.Crypto.BigInt(aValue);
1587 }
1588
1589 if (typeof(aModule) == 'undefined') {
1590 result = mult(this.internalValue(), value.internalValue());
1591 } else {
1592 if (greater(this.internalValue(), value.internalValue())) {
1593 result = multMod(this.internalValue(), value.internalValue(), aModule);
1594 } else {
1595 result = multMod(value.internalValue(), this.internalValue(), aModule);
1596 }
1597 }
1598
1599 return new Clipperz.Crypto.BigInt(result);
1600 },
1601
1602 //-------------------------------------------------------------------------
1603
1604 'module': function (aModule) {
1605 varresult;
1606 var module;
1607
1608 if (aModule.isBigInt) {
1609 module = aModule;
1610 } else {
1611 module = new Clipperz.Crypto.BigInt(aModule);
1612 }
1613
1614 result = mod(this.internalValue(), module.internalValue());
1615
1616 return new Clipperz.Crypto.BigInt(result);
1617 },
1618
1619 //-------------------------------------------------------------------------
1620
1621 'powerModule': function(aValue, aModule) {
1622 varresult;
1623 varvalue;
1624 var module;
1625
1626 if (aValue.isBigInt) {
1627 value = aValue;
1628 } else {
1629 value = new Clipperz.Crypto.BigInt(aValue);
1630 }
1631
1632 if (aModule.isBigInt) {
1633 module = aModule;
1634 } else {
1635 module = new Clipperz.Crypto.BigInt(aModule);
1636 }
1637
1638 if (aValue == -1) {
1639 result = inverseMod(this.internalValue(), module.internalValue());
1640 } else {
1641 result = powMod(this.internalValue(), value.internalValue(), module.internalValue());
1642 }
1643
1644 return new Clipperz.Crypto.BigInt(result);
1645 },
1646
1647 //-------------------------------------------------------------------------
1648
1649 'xor': function(aValue) {
1650 var result;
1651 varthisByteArray;
1652 var aValueByteArray;
1653 var xorArray;
1654
1655 thisByteArray = new Clipperz.ByteArray("0x" + this.asString(16), 16);
1656 aValueByteArray = new Clipperz.ByteArray("0x" + aValue.asString(16), 16);
1657 xorArray = thisByteArray.xorMergeWithBlock(aValueByteArray, 'right');
1658 result = new Clipperz.Crypto.BigInt(xorArray.toHexString(), 16);
1659
1660 return result;
1661 },
1662
1663 //-------------------------------------------------------------------------
1664
1665 'shiftLeft': function(aNumberOfBitsToShift) {
1666 var result;
1667 var internalResult;
1668 var wholeByteToShift;
1669 var bitsLeftToShift;
1670
1671 wholeByteToShift = Math.floor(aNumberOfBitsToShift / 8);
1672 bitsLeftToShift = aNumberOfBitsToShift % 8;
1673
1674 if (wholeByteToShift == 0) {
1675 internalResult = this.internalValue();
1676 } else {
1677 var hexValue;
1678 var i,c;
1679
1680 hexValue = this.asString(16);
1681 c = wholeByteToShift;
1682 for (i=0; i<c; i++) {
1683 hexValue += "00";
1684 }
1685 internalResult = str2bigInt(hexValue, 16, 1, 1);
1686 }
1687
1688 if (bitsLeftToShift > 0) {
1689 leftShift_(internalResult, bitsLeftToShift);
1690 }
1691 result = new Clipperz.Crypto.BigInt(internalResult);
1692
1693 return result;
1694 },
1695
1696 //-------------------------------------------------------------------------
1697
1698 'bitSize': function() {
1699 return bitSize(this.internalValue());
1700 },
1701
1702 //-------------------------------------------------------------------------
1703
1704 'isBitSet': function(aBitPosition) {
1705 var result;
1706
1707 if (this.asByteArray().bitAtIndex(aBitPosition) == 0) {
1708 result = false;
1709 } else {
1710 result = true;
1711 };
1712
1713 return result;
1714 },
1715
1716 //-------------------------------------------------------------------------
1717 __syntaxFix__: "syntax fix"
1718
1719});
1720
1721//#############################################################################
1722
1723Clipperz.Crypto.BigInt.randomPrime = function(aBitSize) {
1724 return new Clipperz.Crypto.BigInt(randTruePrime(aBitSize));
1725}
1726
1727//#############################################################################
1728//#############################################################################
1729
1730Clipperz.Crypto.BigInt.ZERO = new Clipperz.Crypto.BigInt(0);
1731
1732//#############################################################################
1733
1734Clipperz.Crypto.BigInt.equals = function(a, b) {
1735 return a.equals(b);
1736}
1737
1738Clipperz.Crypto.BigInt.add = function(a, b) {
1739 return a.add(b);
1740}
1741
1742Clipperz.Crypto.BigInt.subtract = function(a, b) {
1743 return a.subtract(b);
1744}
1745
1746Clipperz.Crypto.BigInt.multiply = function(a, b, module) {
1747 return a.multiply(b, module);
1748}
1749
1750Clipperz.Crypto.BigInt.module = function(a, module) {
1751 return a.module(module);
1752}
1753
1754Clipperz.Crypto.BigInt.powerModule = function(a, b, module) {
1755 return a.powerModule(b, module);
1756}
1757
1758Clipperz.Crypto.BigInt.exception = {
1759 UnknownType: new MochiKit.Base.NamedError("Clipperz.Crypto.BigInt.exception.UnknownType")
1760}
diff --git a/frontend/beta/js/Clipperz/Crypto/BigInt_scoped.js b/frontend/beta/js/Clipperz/Crypto/BigInt_scoped.js
new file mode 100644
index 0000000..e91e823
--- a/dev/null
+++ b/frontend/beta/js/Clipperz/Crypto/BigInt_scoped.js
@@ -0,0 +1,1649 @@
1/*
2
3Copyright 2008-2011 Clipperz Srl
4
5This file is part of Clipperz's Javascript Crypto Library.
6Javascript Crypto Library provides web developers with an extensive
7and efficient set of cryptographic functions. The library aims to
8obtain maximum execution speed while preserving modularity and
9reusability.
10For further information about its features and functionalities please
11refer to http://www.clipperz.com
12
13* Javascript Crypto Library is free software: you can redistribute
14 it and/or modify it under the terms of the GNU Affero General Public
15 License as published by the Free Software Foundation, either version
16 3 of the License, or (at your option) any later version.
17
18* Javascript Crypto Library is distributed in the hope that it will
19 be useful, but WITHOUT ANY WARRANTY; without even the implied
20 warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
21 See the GNU Affero General Public License for more details.
22
23* You should have received a copy of the GNU Affero General Public
24 License along with Javascript Crypto Library. If not, see
25 <http://www.gnu.org/licenses/>.
26
27*/
28
29if (typeof(Clipperz) == 'undefined') { Clipperz = {}; }
30if (typeof(Clipperz.Crypto) == 'undefined') { Clipperz.Crypto = {}; }
31
32if (typeof(Leemon) == 'undefined') { Leemon = {}; }
33if (typeof(Baird.Crypto) == 'undefined') { Baird.Crypto = {}; }
34if (typeof(Baird.Crypto.BigInt) == 'undefined') { Baird.Crypto.BigInt = {}; }
35
36
37//#############################################################################
38 //Downloaded on March 05, 2007 from http://www.leemon.com/crypto/BigInt.js
39//#############################################################################
40
41////////////////////////////////////////////////////////////////////////////////////////
42// Big Integer Library v. 5.0
43// Created 2000, last modified 2006
44// Leemon Baird
45// www.leemon.com
46//
47// This file is public domain. You can use it for any purpose without restriction.
48// I do not guarantee that it is correct, so use it at your own risk. If you use
49// it for something interesting, I'd appreciate hearing about it. If you find
50// any bugs or make any improvements, I'd appreciate hearing about those too.
51// It would also be nice if my name and address were left in the comments.
52// But none of that is required.
53//
54// This code defines a bigInt library for arbitrary-precision integers.
55// A bigInt is an array of integers storing the value in chunks of bpe bits,
56// little endian (buff[0] is the least significant word).
57// Negative bigInts are stored two's complement.
58// Some functions assume their parameters have at least one leading zero element.
59// Functions with an underscore at the end of the name have unpredictable behavior in case of overflow,
60// so the caller must make sure overflow won't happen.
61// For each function where a parameter is modified, that same
62// variable must not be used as another argument too.
63// So, you cannot square x by doing multMod_(x,x,n).
64// You must use squareMod_(x,n) instead, or do y=dup(x); multMod_(x,y,n).
65//
66// These functions are designed to avoid frequent dynamic memory allocation in the inner loop.
67// For most functions, if it needs a BigInt as a local variable it will actually use
68// a global, and will only allocate to it when it's not the right size. This ensures
69// that when a function is called repeatedly with same-sized parameters, it only allocates
70// memory on the first call.
71//
72// Note that for cryptographic purposes, the calls to Math.random() must
73// be replaced with calls to a better pseudorandom number generator.
74//
75// In the following, "bigInt" means a bigInt with at least one leading zero element,
76// and "integer" means a nonnegative integer less than radix. In some cases, integer
77// can be negative. Negative bigInts are 2s complement.
78//
79// The following functions do not modify their inputs, but dynamically allocate memory every time they are called:
80//
81// function bigInt2str(x,base) //convert a bigInt into a string in a given base, from base 2 up to base 95
82// function dup(x) //returns a copy of bigInt x
83// function findPrimes(n) //return array of all primes less than integer n
84// function int2bigInt(t,n,m) //convert integer t to a bigInt with at least n bits and m array elements
85// function str2bigInt(s,b,n,m) //convert string s in base b to a bigInt with at least n bits and m array elements
86// function trim(x,k) //return a copy of x with exactly k leading zero elements
87//
88// The following functions do not modify their inputs, so there is never a problem with the result being too big:
89//
90// function bitSize(x) //returns how many bits long the bigInt x is, not counting leading zeros
91// function equals(x,y) //is the bigInt x equal to the bigint y?
92// function equalsInt(x,y) //is bigint x equal to integer y?
93// function greater(x,y) //is x>y? (x and y are nonnegative bigInts)
94// function greaterShift(x,y,shift)//is (x <<(shift*bpe)) > y?
95// function isZero(x) //is the bigInt x equal to zero?
96// function millerRabin(x,b) //does one round of Miller-Rabin base integer b say that bigInt x is possibly prime (as opposed to definitely composite)?
97// function modInt(x,n) //return x mod n for bigInt x and integer n.
98// function negative(x) //is bigInt x negative?
99//
100// The following functions do not modify their inputs, but allocate memory and call functions with underscores
101//
102// function add(x,y) //return (x+y) for bigInts x and y.
103// function addInt(x,n) //return (x+n) where x is a bigInt and n is an integer.
104// function expand(x,n) //return a copy of x with at least n elements, adding leading zeros if needed
105// function inverseMod(x,n) //return (x**(-1) mod n) for bigInts x and n. If no inverse exists, it returns null
106// function mod(x,n) //return a new bigInt equal to (x mod n) for bigInts x and n.
107// function mult(x,y) //return x*y for bigInts x and y. This is faster when y<x.
108// function multMod(x,y,n) //return (x*y mod n) for bigInts x,y,n. For greater speed, let y<x.
109// function powMod(x,y,n) //return (x**y mod n) where x,y,n are bigInts and ** is exponentiation. 0**0=1. Faster for odd n.
110// function randTruePrime(k) //return a new, random, k-bit, true prime using Maurer's algorithm.
111// function sub(x,y) //return (x-y) for bigInts x and y. Negative answers will be 2s complement
112//
113// The following functions write a bigInt result to one of the parameters, but
114// the result is never bigger than the original, so there can't be overflow problems:
115//
116// function divInt_(x,n) //do x=floor(x/n) for bigInt x and integer n, and return the remainder
117// function GCD_(x,y) //set x to the greatest common divisor of bigInts x and y, (y is destroyed).
118// function halve_(x) //do x=floor(|x|/2)*sgn(x) for bigInt x in 2's complement
119// function mod_(x,n) //do x=x mod n for bigInts x and n.
120// function rightShift_(x,n) //right shift bigInt x by n bits. 0 <= n < bpe.
121//
122// The following functions write a bigInt result to one of the parameters. The caller is responsible for
123// ensuring it is large enough to hold the result.
124//
125// function addInt_(x,n) //do x=x+n where x is a bigInt and n is an integer
126// function add_(x,y) //do x=x+y for bigInts x and y
127// function addShift_(x,y,ys) //do x=x+(y<<(ys*bpe))
128// function copy_(x,y) //do x=y on bigInts x and y
129// function copyInt_(x,n) //do x=n on bigInt x and integer n
130// function carry_(x) //do carries and borrows so each element of the bigInt x fits in bpe bits.
131// function divide_(x,y,q,r) //divide_ x by y giving quotient q and remainder r
132// function eGCD_(x,y,d,a,b) //sets a,b,d to positive big integers such that d = GCD_(x,y) = a*x-b*y
133// function inverseMod_(x,n) //do x=x**(-1) mod n, for bigInts x and n. Returns 1 (0) if inverse does (doesn't) exist
134// function inverseModInt_(x,n) //return x**(-1) mod n, for integers x and n. Return 0 if there is no inverse
135// function leftShift_(x,n) //left shift bigInt x by n bits. n<bpe.
136// function linComb_(x,y,a,b) //do x=a*x+b*y for bigInts x and y and integers a and b
137// function linCombShift_(x,y,b,ys) //do x=x+b*(y<<(ys*bpe)) for bigInts x and y, and integers b and ys
138// function mont_(x,y,n,np) //Montgomery multiplication (see comments where the function is defined)
139// function mult_(x,y) //do x=x*y for bigInts x and y.
140// function multInt_(x,n) //do x=x*n where x is a bigInt and n is an integer.
141// function multMod_(x,y,n) //do x=x*y mod n for bigInts x,y,n.
142// function powMod_(x,y,n) //do x=x**y mod n, where x,y,n are bigInts (n is odd) and ** is exponentiation. 0**0=1.
143// function randBigInt_(b,n,s) //do b = an n-bit random BigInt. if s=1, then nth bit (most significant bit) is set to 1. n>=1.
144// function randTruePrime_(ans,k) //do ans = a random k-bit true random prime (not just probable prime) with 1 in the msb.
145// function squareMod_(x,n) //do x=x*x mod n for bigInts x,n
146// function sub_(x,y) //do x=x-y for bigInts x and y. Negative answers will be 2s complement.
147// function subShift_(x,y,ys) //do x=x-(y<<(ys*bpe)). Negative answers will be 2s complement.
148//
149// The following functions are based on algorithms from the _Handbook of Applied Cryptography_
150// powMod_() = algorithm 14.94, Montgomery exponentiation
151// eGCD_,inverseMod_() = algorithm 14.61, Binary extended GCD_
152// GCD_() = algorothm 14.57, Lehmer's algorithm
153// mont_() = algorithm 14.36, Montgomery multiplication
154// divide_() = algorithm 14.20 Multiple-precision division
155// squareMod_() = algorithm 14.16 Multiple-precision squaring
156// randTruePrime_() = algorithm 4.62, Maurer's algorithm
157// millerRabin() = algorithm 4.24, Miller-Rabin algorithm
158//
159// Profiling shows:
160// randTruePrime_() spends:
161// 10% of its time in calls to powMod_()
162// 85% of its time in calls to millerRabin()
163// millerRabin() spends:
164// 99% of its time in calls to powMod_() (always with a base of 2)
165// powMod_() spends:
166// 94% of its time in calls to mont_() (almost always with x==y)
167//
168// This suggests there are several ways to speed up this library slightly:
169// - convert powMod_ to use a Montgomery form of k-ary window (or maybe a Montgomery form of sliding window)
170// -- this should especially focus on being fast when raising 2 to a power mod n
171// - convert randTruePrime_() to use a minimum r of 1/3 instead of 1/2 with the appropriate change to the test
172// - tune the parameters in randTruePrime_(), including c, m, and recLimit
173// - speed up the single loop in mont_() that takes 95% of the runtime, perhaps by reducing checking
174// within the loop when all the parameters are the same length.
175//
176// There are several ideas that look like they wouldn't help much at all:
177// - replacing trial division in randTruePrime_() with a sieve (that speeds up something taking almost no time anyway)
178// - increase bpe from 15 to 30 (that would help if we had a 32*32->64 multiplier, but not with JavaScript's 32*32->32)
179// - speeding up mont_(x,y,n,np) when x==y by doing a non-modular, non-Montgomery square
180// followed by a Montgomery reduction. The intermediate answer will be twice as long as x, so that
181// method would be slower. This is unfortunate because the code currently spends almost all of its time
182// doing mont_(x,x,...), both for randTruePrime_() and powMod_(). A faster method for Montgomery squaring
183// would have a large impact on the speed of randTruePrime_() and powMod_(). HAC has a couple of poorly-worded
184// sentences that seem to imply it's faster to do a non-modular square followed by a single
185// Montgomery reduction, but that's obviously wrong.
186////////////////////////////////////////////////////////////////////////////////////////
187
188//
189 //The whole library has been moved into the Baird.Crypto.BigInt scope by Giulio Cesare Solaroli <giulio.cesare@clipperz.com>
190//
191Baird.Crypto.BigInt.VERSION = "5.0";
192Baird.Crypto.BigInt.NAME = "Baird.Crypto.BigInt";
193
194MochiKit.Base.update(Baird.Crypto.BigInt, {
195 //globals
196 'bpe': 0, //bits stored per array element
197 'mask': 0, //AND this with an array element to chop it down to bpe bits
198 'radix': Baird.Crypto.BigInt.mask + 1,//equals 2^bpe. A single 1 bit to the left of the last bit of mask.
199
200 //the digits for converting to different bases
201 'digitsStr': '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_=!@#$%^&*()[]{}|;:,.<>/?`~ \\\'\"+-',
202
203//initialize the global variables
204for (bpe=0; (1<<(bpe+1)) > (1<<bpe); bpe++); //bpe=number of bits in the mantissa on this platform
205bpe>>=1; //bpe=number of bits in one element of the array representing the bigInt
206mask=(1<<bpe)-1; //AND the mask with an integer to get its bpe least significant bits
207radix=mask+1; //2^bpe. a single 1 bit to the left of the first bit of mask
208one=int2bigInt(1,1,1); //constant used in powMod_()
209
210//the following global variables are scratchpad memory to
211//reduce dynamic memory allocation in the inner loop
212t=new Array(0);
213ss=t; //used in mult_()
214s0=t; //used in multMod_(), squareMod_()
215s1=t; //used in powMod_(), multMod_(), squareMod_()
216s2=t; //used in powMod_(), multMod_()
217s3=t; //used in powMod_()
218s4=t; s5=t; //used in mod_()
219s6=t; //used in bigInt2str()
220s7=t; //used in powMod_()
221T=t; //used in GCD_()
222sa=t; //used in mont_()
223mr_x1=t; mr_r=t; mr_a=t; //used in millerRabin()
224eg_v=t; eg_u=t; eg_A=t; eg_B=t; eg_C=t; eg_D=t; //used in eGCD_(), inverseMod_()
225md_q1=t; md_q2=t; md_q3=t; md_r=t; md_r1=t; md_r2=t; md_tt=t; //used in mod_()
226
227primes=t; pows=t; s_i=t; s_i2=t; s_R=t; s_rm=t; s_q=t; s_n1=t;
228 s_a=t; s_r2=t; s_n=t; s_b=t; s_d=t; s_x1=t; s_x2=t, s_aa=t; //used in randTruePrime_()
229
230////////////////////////////////////////////////////////////////////////////////////////
231
232 //return array of all primes less than integer n
233 'findPrimes': function(n) {
234 var i,s,p,ans;
235 s=new Array(n);
236 for (i=0;i<n;i++)
237 s[i]=0;
238 s[0]=2;
239 p=0; //first p elements of s are primes, the rest are a sieve
240 for(;s[p]<n;) { //s[p] is the pth prime
241 for(i=s[p]*s[p]; i<n; i+=s[p]) //mark multiples of s[p]
242 s[i]=1;
243 p++;
244 s[p]=s[p-1]+1;
245 for(; s[p]<n && s[s[p]]; s[p]++); //find next prime (where s[p]==0)
246 }
247 ans=new Array(p);
248 for(i=0;i<p;i++)
249 ans[i]=s[i];
250 return ans;
251 },
252
253 //does a single round of Miller-Rabin base b consider x to be a possible prime?
254 //x is a bigInt, and b is an integer
255 'millerRabin': function(x,b) {
256 var i,j,k,s;
257
258 if (mr_x1.length!=x.length) {
259 mr_x1=dup(x);
260 mr_r=dup(x);
261 mr_a=dup(x);
262 }
263
264 copyInt_(mr_a,b);
265 copy_(mr_r,x);
266 copy_(mr_x1,x);
267
268 addInt_(mr_r,-1);
269 addInt_(mr_x1,-1);
270
271 //s=the highest power of two that divides mr_r
272 k=0;
273 for (i=0;i<mr_r.length;i++)
274 for (j=1;j<mask;j<<=1)
275 if (x[i] & j) {
276 s=(k<mr_r.length+bpe ? k : 0);
277 i=mr_r.length;
278 j=mask;
279 } else
280 k++;
281
282 if (s)
283 rightShift_(mr_r,s);
284
285 powMod_(mr_a,mr_r,x);
286
287 if (!equalsInt(mr_a,1) && !equals(mr_a,mr_x1)) {
288 j=1;
289 while (j<=s-1 && !equals(mr_a,mr_x1)) {
290 squareMod_(mr_a,x);
291 if (equalsInt(mr_a,1)) {
292 return 0;
293 }
294 j++;
295 }
296 if (!equals(mr_a,mr_x1)) {
297 return 0;
298 }
299 }
300
301 return 1;
302 },
303
304 //returns how many bits long the bigInt is, not counting leading zeros.
305 'bitSize': function(x) {
306 var j,z,w;
307 for (j=x.length-1; (x[j]==0) && (j>0); j--);
308 for (z=0,w=x[j]; w; (w>>=1),z++);
309 z+=bpe*j;
310 return z;
311 },
312
313 //return a copy of x with at least n elements, adding leading zeros if needed
314 'expand': function(x,n) {
315 var ans=int2bigInt(0,(x.length>n ? x.length : n)*bpe,0);
316 copy_(ans,x);
317 return ans;
318 },
319
320 //return a k-bit true random prime using Maurer's algorithm.
321 'randTruePrime': function(k) {
322 var ans=int2bigInt(0,k,0);
323 randTruePrime_(ans,k);
324 return trim(ans,1);
325 },
326
327 //return a new bigInt equal to (x mod n) for bigInts x and n.
328 'mod': function(x,n) {
329 var ans=dup(x);
330 mod_(ans,n);
331 return trim(ans,1);
332 },
333
334 //return (x+n) where x is a bigInt and n is an integer.
335 'addInt': function(x,n) {
336 var ans=expand(x,x.length+1);
337 addInt_(ans,n);
338 return trim(ans,1);
339 },
340
341 //return x*y for bigInts x and y. This is faster when y<x.
342 'mult': function(x,y) {
343 var ans=expand(x,x.length+y.length);
344 mult_(ans,y);
345 return trim(ans,1);
346 },
347
348 //return (x**y mod n) where x,y,n are bigInts and ** is exponentiation. 0**0=1. Faster for odd n.
349 'powMod': function(x,y,n) {
350 var ans=expand(x,n.length);
351 powMod_(ans,trim(y,2),trim(n,2),0); //this should work without the trim, but doesn't
352 return trim(ans,1);
353 },
354
355 //return (x-y) for bigInts x and y. Negative answers will be 2s complement
356 'sub': function(x,y) {
357 var ans=expand(x,(x.length>y.length ? x.length+1 : y.length+1));
358 sub_(ans,y);
359 return trim(ans,1);
360 },
361
362 //return (x+y) for bigInts x and y.
363 'add': function(x,y) {
364 var ans=expand(x,(x.length>y.length ? x.length+1 : y.length+1));
365 add_(ans,y);
366 return trim(ans,1);
367 },
368
369 //return (x**(-1) mod n) for bigInts x and n. If no inverse exists, it returns null
370 'inverseMod': function(x,n) {
371 var ans=expand(x,n.length);
372 var s;
373 s=inverseMod_(ans,n);
374 return s ? trim(ans,1) : null;
375 },
376
377 //return (x*y mod n) for bigInts x,y,n. For greater speed, let y<x.
378 'multMod': function(x,y,n) {
379 var ans=expand(x,n.length);
380 multMod_(ans,y,n);
381 return trim(ans,1);
382 },
383
384 //generate a k-bit true random prime using Maurer's algorithm,
385 //and put it into ans. The bigInt ans must be large enough to hold it.
386 'randTruePrime_': function(ans,k) {
387 var c,m,pm,dd,j,r,B,divisible,z,zz,recSize;
388
389 if (primes.length==0)
390 primes=findPrimes(30000); //check for divisibility by primes <=30000
391
392 if (pows.length==0) {
393 pows=new Array(512);
394 for (j=0;j<512;j++) {
395 pows[j]=Math.pow(2,j/511.-1.);
396 }
397 }
398
399 //c and m should be tuned for a particular machine and value of k, to maximize speed
400 //this was: c=primes[primes.length-1]/k/k; //check using all the small primes. (c=0.1 in HAC)
401 c=0.1;
402 m=20; //generate this k-bit number by first recursively generating a number that has between k/2 and k-m bits
403 recLimit=20; /*must be at least 2 (was 29)*/ //stop recursion when k <=recLimit
404
405 if (s_i2.length!=ans.length) {
406 s_i2=dup(ans);
407 s_R =dup(ans);
408 s_n1=dup(ans);
409 s_r2=dup(ans);
410 s_d =dup(ans);
411 s_x1=dup(ans);
412 s_x2=dup(ans);
413 s_b =dup(ans);
414 s_n =dup(ans);
415 s_i =dup(ans);
416 s_rm=dup(ans);
417 s_q =dup(ans);
418 s_a =dup(ans);
419 s_aa=dup(ans);
420 }
421
422 if (k <= recLimit) { //generate small random primes by trial division up to its square root
423 pm=(1<<((k+2)>>1))-1; //pm is binary number with all ones, just over sqrt(2^k)
424 copyInt_(ans,0);
425 for (dd=1;dd;) {
426 dd=0;
427 ans[0]= 1 | (1<<(k-1)) | Math.floor(Math.random()*(1<<k)); //random, k-bit, odd integer, with msb 1
428 for (j=1;(j<primes.length) && ((primes[j]&pm)==primes[j]);j++) { //trial division by all primes 3...sqrt(2^k)
429 if (0==(ans[0]%primes[j])) {
430 dd=1;
431 break;
432 }
433 }
434 }
435 carry_(ans);
436 return;
437 }
438
439 B=c*k*k; //try small primes up to B (or all the primes[] array if the largest is less than B).
440 if (k>2*m) //generate this k-bit number by first recursively generating a number that has between k/2 and k-m bits
441 for (r=1; k-k*r<=m; )
442 r=pows[Math.floor(Math.random()*512)]; //r=Math.pow(2,Math.random()-1);
443 else
444 r=.5;
445
446 //simulation suggests the more complex algorithm using r=.333 is only slightly faster.
447
448 recSize=Math.floor(r*k)+1;
449
450 randTruePrime_(s_q,recSize);
451 copyInt_(s_i2,0);
452 s_i2[Math.floor((k-2)/bpe)] |= (1<<((k-2)%bpe)); //s_i2=2^(k-2)
453 divide_(s_i2,s_q,s_i,s_rm); //s_i=floor((2^(k-1))/(2q))
454
455 z=bitSize(s_i);
456
457 for (;;) {
458 for (;;) { //generate z-bit numbers until one falls in the range [0,s_i-1]
459 randBigInt_(s_R,z,0);
460 if (greater(s_i,s_R))
461 break;
462 } //now s_R is in the range [0,s_i-1]
463 addInt_(s_R,1); //now s_R is in the range [1,s_i]
464 add_(s_R,s_i); //now s_R is in the range [s_i+1,2*s_i]
465
466 copy_(s_n,s_q);
467 mult_(s_n,s_R);
468 multInt_(s_n,2);
469 addInt_(s_n,1); //s_n=2*s_R*s_q+1
470
471 copy_(s_r2,s_R);
472 multInt_(s_r2,2); //s_r2=2*s_R
473
474 //check s_n for divisibility by small primes up to B
475 for (divisible=0,j=0; (j<primes.length) && (primes[j]<B); j++)
476 if (modInt(s_n,primes[j])==0) {
477 divisible=1;
478 break;
479 }
480
481 if (!divisible) //if it passes small primes check, then try a single Miller-Rabin base 2
482 if (!millerRabin(s_n,2)) //this line represents 75% of the total runtime for randTruePrime_
483 divisible=1;
484
485 if (!divisible) { //if it passes that test, continue checking s_n
486 addInt_(s_n,-3);
487 for (j=s_n.length-1;(s_n[j]==0) && (j>0); j--); //strip leading zeros
488 for (zz=0,w=s_n[j]; w; (w>>=1),zz++);
489 zz+=bpe*j; //zz=number of bits in s_n, ignoring leading zeros
490 for (;;) { //generate z-bit numbers until one falls in the range [0,s_n-1]
491 randBigInt_(s_a,zz,0);
492 if (greater(s_n,s_a))
493 break;
494 } //now s_a is in the range [0,s_n-1]
495 addInt_(s_n,3); //now s_a is in the range [0,s_n-4]
496 addInt_(s_a,2); //now s_a is in the range [2,s_n-2]
497 copy_(s_b,s_a);
498 copy_(s_n1,s_n);
499 addInt_(s_n1,-1);
500 powMod_(s_b,s_n1,s_n); //s_b=s_a^(s_n-1) modulo s_n
501 addInt_(s_b,-1);
502 if (isZero(s_b)) {
503 copy_(s_b,s_a);
504 powMod_(s_b,s_r2,s_n);
505 addInt_(s_b,-1);
506 copy_(s_aa,s_n);
507 copy_(s_d,s_b);
508 GCD_(s_d,s_n); //if s_b and s_n are relatively prime, then s_n is a prime
509 if (equalsInt(s_d,1)) {
510 copy_(ans,s_aa);
511 return; //if we've made it this far, then s_n is absolutely guaranteed to be prime
512 }
513 }
514 }
515 }
516 },
517
518 //set b to an n-bit random BigInt. If s=1, then nth bit (most significant bit) is set to 1.
519 //array b must be big enough to hold the result. Must have n>=1
520 'randBigInt_': function(b,n,s) {
521 var i,a;
522 for (i=0;i<b.length;i++)
523 b[i]=0;
524 a=Math.floor((n-1)/bpe)+1; //# array elements to hold the BigInt
525 for (i=0;i<a;i++) {
526 b[i]=Math.floor(Math.random()*(1<<(bpe-1)));
527 }
528 b[a-1] &= (2<<((n-1)%bpe))-1;
529 if (s)
530 b[a-1] |= (1<<((n-1)%bpe));
531 },
532
533 //set x to the greatest common divisor of x and y.
534 //x,y are bigInts with the same number of elements. y is destroyed.
535 'GCD_': function(x,y) {
536 var i,xp,yp,A,B,C,D,q,sing;
537 if (T.length!=x.length)
538 T=dup(x);
539
540 sing=1;
541 while (sing) { //while y has nonzero elements other than y[0]
542 sing=0;
543 for (i=1;i<y.length;i++) //check if y has nonzero elements other than 0
544 if (y[i]) {
545 sing=1;
546 break;
547 }
548 if (!sing) break; //quit when y all zero elements except possibly y[0]
549
550 for (i=x.length;!x[i] && i>=0;i--); //find most significant element of x
551 xp=x[i];
552 yp=y[i];
553 A=1; B=0; C=0; D=1;
554 while ((yp+C) && (yp+D)) {
555 q =Math.floor((xp+A)/(yp+C));
556 qp=Math.floor((xp+B)/(yp+D));
557 if (q!=qp)
558 break;
559 t= A-q*C; A=C; C=t; // do (A,B,xp, C,D,yp) = (C,D,yp, A,B,xp) - q*(0,0,0, C,D,yp)
560 t= B-q*D; B=D; D=t;
561 t=xp-q*yp; xp=yp; yp=t;
562 }
563 if (B) {
564 copy_(T,x);
565 linComb_(x,y,A,B); //x=A*x+B*y
566 linComb_(y,T,D,C); //y=D*y+C*T
567 } else {
568 mod_(x,y);
569 copy_(T,x);
570 copy_(x,y);
571 copy_(y,T);
572 }
573 }
574 if (y[0]==0)
575 return;
576 t=modInt(x,y[0]);
577 copyInt_(x,y[0]);
578 y[0]=t;
579 while (y[0]) {
580 x[0]%=y[0];
581 t=x[0]; x[0]=y[0]; y[0]=t;
582 }
583 },
584
585//do x=x**(-1) mod n, for bigInts x and n.
586//If no inverse exists, it sets x to zero and returns 0, else it returns 1.
587//The x array must be at least as large as the n array.
588function inverseMod_(x,n) {
589 var k=1+2*Math.max(x.length,n.length);
590
591 if(!(x[0]&1) && !(n[0]&1)) { //if both inputs are even, then inverse doesn't exist
592 copyInt_(x,0);
593 return 0;
594 }
595
596 if (eg_u.length!=k) {
597 eg_u=new Array(k);
598 eg_v=new Array(k);
599 eg_A=new Array(k);
600 eg_B=new Array(k);
601 eg_C=new Array(k);
602 eg_D=new Array(k);
603 }
604
605 copy_(eg_u,x);
606 copy_(eg_v,n);
607 copyInt_(eg_A,1);
608 copyInt_(eg_B,0);
609 copyInt_(eg_C,0);
610 copyInt_(eg_D,1);
611 for (;;) {
612 while(!(eg_u[0]&1)) { //while eg_u is even
613 halve_(eg_u);
614 if (!(eg_A[0]&1) && !(eg_B[0]&1)) { //if eg_A==eg_B==0 mod 2
615 halve_(eg_A);
616 halve_(eg_B);
617 } else {
618 add_(eg_A,n); halve_(eg_A);
619 sub_(eg_B,x); halve_(eg_B);
620 }
621 }
622
623 while (!(eg_v[0]&1)) { //while eg_v is even
624 halve_(eg_v);
625 if (!(eg_C[0]&1) && !(eg_D[0]&1)) { //if eg_C==eg_D==0 mod 2
626 halve_(eg_C);
627 halve_(eg_D);
628 } else {
629 add_(eg_C,n); halve_(eg_C);
630 sub_(eg_D,x); halve_(eg_D);
631 }
632 }
633
634 if (!greater(eg_v,eg_u)) { //eg_v <= eg_u
635 sub_(eg_u,eg_v);
636 sub_(eg_A,eg_C);
637 sub_(eg_B,eg_D);
638 } else { //eg_v > eg_u
639 sub_(eg_v,eg_u);
640 sub_(eg_C,eg_A);
641 sub_(eg_D,eg_B);
642 }
643
644 if (equalsInt(eg_u,0)) {
645 if (negative(eg_C)) //make sure answer is nonnegative
646 add_(eg_C,n);
647 copy_(x,eg_C);
648
649 if (!equalsInt(eg_v,1)) { //if GCD_(x,n)!=1, then there is no inverse
650 copyInt_(x,0);
651 return 0;
652 }
653 return 1;
654 }
655 }
656}
657
658//return x**(-1) mod n, for integers x and n. Return 0 if there is no inverse
659function inverseModInt_(x,n) {
660 var a=1,b=0,t;
661 for (;;) {
662 if (x==1) return a;
663 if (x==0) return 0;
664 b-=a*Math.floor(n/x);
665 n%=x;
666
667 if (n==1) return b; //to avoid negatives, change this b to n-b, and each -= to +=
668 if (n==0) return 0;
669 a-=b*Math.floor(x/n);
670 x%=n;
671 }
672}
673
674//Given positive bigInts x and y, change the bigints v, a, and b to positive bigInts such that:
675// v = GCD_(x,y) = a*x-b*y
676//The bigInts v, a, b, must have exactly as many elements as the larger of x and y.
677function eGCD_(x,y,v,a,b) {
678 var g=0;
679 var k=Math.max(x.length,y.length);
680 if (eg_u.length!=k) {
681 eg_u=new Array(k);
682 eg_A=new Array(k);
683 eg_B=new Array(k);
684 eg_C=new Array(k);
685 eg_D=new Array(k);
686 }
687 while(!(x[0]&1) && !(y[0]&1)) { //while x and y both even
688 halve_(x);
689 halve_(y);
690 g++;
691 }
692 copy_(eg_u,x);
693 copy_(v,y);
694 copyInt_(eg_A,1);
695 copyInt_(eg_B,0);
696 copyInt_(eg_C,0);
697 copyInt_(eg_D,1);
698 for (;;) {
699 while(!(eg_u[0]&1)) { //while u is even
700 halve_(eg_u);
701 if (!(eg_A[0]&1) && !(eg_B[0]&1)) { //if A==B==0 mod 2
702 halve_(eg_A);
703 halve_(eg_B);
704 } else {
705 add_(eg_A,y); halve_(eg_A);
706 sub_(eg_B,x); halve_(eg_B);
707 }
708 }
709
710 while (!(v[0]&1)) { //while v is even
711 halve_(v);
712 if (!(eg_C[0]&1) && !(eg_D[0]&1)) { //if C==D==0 mod 2
713 halve_(eg_C);
714 halve_(eg_D);
715 } else {
716 add_(eg_C,y); halve_(eg_C);
717 sub_(eg_D,x); halve_(eg_D);
718 }
719 }
720
721 if (!greater(v,eg_u)) { //v<=u
722 sub_(eg_u,v);
723 sub_(eg_A,eg_C);
724 sub_(eg_B,eg_D);
725 } else { //v>u
726 sub_(v,eg_u);
727 sub_(eg_C,eg_A);
728 sub_(eg_D,eg_B);
729 }
730 if (equalsInt(eg_u,0)) {
731 if (negative(eg_C)) { //make sure a (C)is nonnegative
732 add_(eg_C,y);
733 sub_(eg_D,x);
734 }
735 multInt_(eg_D,-1); ///make sure b (D) is nonnegative
736 copy_(a,eg_C);
737 copy_(b,eg_D);
738 leftShift_(v,g);
739 return;
740 }
741 }
742}
743
744
745//is bigInt x negative?
746function negative(x) {
747 return ((x[x.length-1]>>(bpe-1))&1);
748}
749
750
751//is (x << (shift*bpe)) > y?
752//x and y are nonnegative bigInts
753//shift is a nonnegative integer
754function greaterShift(x,y,shift) {
755 var kx=x.length, ky=y.length;
756 k=((kx+shift)<ky) ? (kx+shift) : ky;
757 for (i=ky-1-shift; i<kx && i>=0; i++)
758 if (x[i]>0)
759 return 1; //if there are nonzeros in x to the left of the first column of y, then x is bigger
760 for (i=kx-1+shift; i<ky; i++)
761 if (y[i]>0)
762 return 0; //if there are nonzeros in y to the left of the first column of x, then x is not bigger
763 for (i=k-1; i>=shift; i--)
764 if (x[i-shift]>y[i]) return 1;
765 else if (x[i-shift]<y[i]) return 0;
766 return 0;
767}
768
769//is x > y? (x and y both nonnegative)
770function greater(x,y) {
771 var i;
772 var k=(x.length<y.length) ? x.length : y.length;
773
774 for (i=x.length;i<y.length;i++)
775 if (y[i])
776 return 0; //y has more digits
777
778 for (i=y.length;i<x.length;i++)
779 if (x[i])
780 return 1; //x has more digits
781
782 for (i=k-1;i>=0;i--)
783 if (x[i]>y[i])
784 return 1;
785 else if (x[i]<y[i])
786 return 0;
787 return 0;
788}
789
790//divide_ x by y giving quotient q and remainder r. (q=floor(x/y), r=x mod y). All 4 are bigints.
791//x must have at least one leading zero element.
792//y must be nonzero.
793//q and r must be arrays that are exactly the same length as x.
794//the x array must have at least as many elements as y.
795function divide_(x,y,q,r) {
796 var kx, ky;
797 var i,j,y1,y2,c,a,b;
798 copy_(r,x);
799 for (ky=y.length;y[ky-1]==0;ky--); //kx,ky is number of elements in x,y, not including leading zeros
800 for (kx=r.length;r[kx-1]==0 && kx>ky;kx--);
801
802 //normalize: ensure the most significant element of y has its highest bit set
803 b=y[ky-1];
804 for (a=0; b; a++)
805 b>>=1;
806 a=bpe-a; //a is how many bits to shift so that the high order bit of y is leftmost in its array element
807 leftShift_(y,a); //multiply both by 1<<a now, then divide_ both by that at the end
808 leftShift_(r,a);
809
810 copyInt_(q,0); // q=0
811 while (!greaterShift(y,r,kx-ky)) { // while (leftShift_(y,kx-ky) <= r) {
812 subShift_(r,y,kx-ky); // r=r-leftShift_(y,kx-ky)
813 q[kx-ky]++; // q[kx-ky]++;
814 } // }
815
816 for (i=kx-1; i>=ky; i--) {
817 if (r[i]==y[ky-1])
818 q[i-ky]=mask;
819 else
820 q[i-ky]=Math.floor((r[i]*radix+r[i-1])/y[ky-1]);
821
822 //The following for(;;) loop is equivalent to the commented while loop,
823 //except that the uncommented version avoids overflow.
824 //The commented loop comes from HAC, which assumes r[-1]==y[-1]==0
825 // while (q[i-ky]*(y[ky-1]*radix+y[ky-2]) > r[i]*radix*radix+r[i-1]*radix+r[i-2])
826 // q[i-ky]--;
827 for (;;) {
828 y2=(ky>1 ? y[ky-2] : 0)*q[i-ky];
829 c=y2>>bpe;
830 y2=y2 & mask;
831 y1=c+q[i-ky]*y[ky-1];
832 c=y1>>bpe;
833 y1=y1 & mask;
834
835 if (c==r[i] ? y1==r[i-1] ? y2>(i>1 ? r[i-2] : 0) : y1>r[i-1] : c>r[i])
836 q[i-ky]--;
837 else
838 break;
839 }
840
841 linCombShift_(r,y,-q[i-ky],i-ky); //r=r-q[i-ky]*leftShift_(y,i-ky)
842 if (negative(r)) {
843 addShift_(r,y,i-ky); //r=r+leftShift_(y,i-ky)
844 q[i-ky]--;
845 }
846 }
847
848 rightShift_(y,a); //undo the normalization step
849 rightShift_(r,a); //undo the normalization step
850}
851
852//do carries and borrows so each element of the bigInt x fits in bpe bits.
853function carry_(x) {
854 var i,k,c,b;
855 k=x.length;
856 c=0;
857 for (i=0;i<k;i++) {
858 c+=x[i];
859 b=0;
860 if (c<0) {
861 b=-(c>>bpe);
862 c+=b*radix;
863 }
864 x[i]=c & mask;
865 c=(c>>bpe)-b;
866 }
867}
868
869//return x mod n for bigInt x and integer n.
870function modInt(x,n) {
871 var i,c=0;
872 for (i=x.length-1; i>=0; i--)
873 c=(c*radix+x[i])%n;
874 return c;
875}
876
877//convert the integer t into a bigInt with at least the given number of bits.
878//the returned array stores the bigInt in bpe-bit chunks, little endian (buff[0] is least significant word)
879//Pad the array with leading zeros so that it has at least minSize elements.
880//There will always be at least one leading 0 element.
881function int2bigInt(t,bits,minSize) {
882 var i,k;
883 k=Math.ceil(bits/bpe)+1;
884 k=minSize>k ? minSize : k;
885 buff=new Array(k);
886 copyInt_(buff,t);
887 return buff;
888}
889
890//return the bigInt given a string representation in a given base.
891//Pad the array with leading zeros so that it has at least minSize elements.
892//If base=-1, then it reads in a space-separated list of array elements in decimal.
893//The array will always have at least one leading zero, unless base=-1.
894function str2bigInt(s,base,minSize) {
895 var d, i, j, x, y, kk;
896 var k=s.length;
897 if (base==-1) { //comma-separated list of array elements in decimal
898 x=new Array(0);
899 for (;;) {
900 y=new Array(x.length+1);
901 for (i=0;i<x.length;i++)
902 y[i+1]=x[i];
903 y[0]=parseInt(s,10);
904 x=y;
905 d=s.indexOf(',',0);
906 if (d<1)
907 break;
908 s=s.substring(d+1);
909 if (s.length==0)
910 break;
911 }
912 if (x.length<minSize) {
913 y=new Array(minSize);
914 copy_(y,x);
915 return y;
916 }
917 return x;
918 }
919
920 x=int2bigInt(0,base*k,0);
921 for (i=0;i<k;i++) {
922 d=digitsStr.indexOf(s.substring(i,i+1),0);
923 if (base<=36 && d>=36) //convert lowercase to uppercase if base<=36
924 d-=26;
925 if (d<base && d>=0) { //ignore illegal characters
926 multInt_(x,base);
927 addInt_(x,d);
928 }
929 }
930
931 for (k=x.length;k>0 && !x[k-1];k--); //strip off leading zeros
932 k=minSize>k+1 ? minSize : k+1;
933 y=new Array(k);
934 kk=k<x.length ? k : x.length;
935 for (i=0;i<kk;i++)
936 y[i]=x[i];
937 for (;i<k;i++)
938 y[i]=0;
939 return y;
940}
941
942//is bigint x equal to integer y?
943//y must have less than bpe bits
944function equalsInt(x,y) {
945 var i;
946 if (x[0]!=y)
947 return 0;
948 for (i=1;i<x.length;i++)
949 if (x[i])
950 return 0;
951 return 1;
952}
953
954//are bigints x and y equal?
955//this works even if x and y are different lengths and have arbitrarily many leading zeros
956function equals(x,y) {
957 var i;
958 var k=x.length<y.length ? x.length : y.length;
959 for (i=0;i<k;i++)
960 if (x[i]!=y[i])
961 return 0;
962 if (x.length>y.length) {
963 for (;i<x.length;i++)
964 if (x[i])
965 return 0;
966 } else {
967 for (;i<y.length;i++)
968 if (y[i])
969 return 0;
970 }
971 return 1;
972}
973
974//is the bigInt x equal to zero?
975function isZero(x) {
976 var i;
977 for (i=0;i<x.length;i++)
978 if (x[i])
979 return 0;
980 return 1;
981}
982
983//convert a bigInt into a string in a given base, from base 2 up to base 95.
984//Base -1 prints the contents of the array representing the number.
985function bigInt2str(x,base) {
986 var i,t,s="";
987
988 if (s6.length!=x.length)
989 s6=dup(x);
990 else
991 copy_(s6,x);
992
993 if (base==-1) { //return the list of array contents
994 for (i=x.length-1;i>0;i--)
995 s+=x[i]+',';
996 s+=x[0];
997 }
998 else { //return it in the given base
999 while (!isZero(s6)) {
1000 t=divInt_(s6,base); //t=s6 % base; s6=floor(s6/base);
1001 s=digitsStr.substring(t,t+1)+s;
1002 }
1003 }
1004 if (s.length==0)
1005 s="0";
1006 return s;
1007}
1008
1009//returns a duplicate of bigInt x
1010function dup(x) {
1011 var i;
1012 buff=new Array(x.length);
1013 copy_(buff,x);
1014 return buff;
1015}
1016
1017//do x=y on bigInts x and y. x must be an array at least as big as y (not counting the leading zeros in y).
1018function copy_(x,y) {
1019 var i;
1020 var k=x.length<y.length ? x.length : y.length;
1021 for (i=0;i<k;i++)
1022 x[i]=y[i];
1023 for (i=k;i<x.length;i++)
1024 x[i]=0;
1025}
1026
1027//do x=y on bigInt x and integer y.
1028function copyInt_(x,n) {
1029 var i,c;
1030 for (c=n,i=0;i<x.length;i++) {
1031 x[i]=c & mask;
1032 c>>=bpe;
1033 }
1034}
1035
1036//do x=x+n where x is a bigInt and n is an integer.
1037//x must be large enough to hold the result.
1038function addInt_(x,n) {
1039 var i,k,c,b;
1040 x[0]+=n;
1041 k=x.length;
1042 c=0;
1043 for (i=0;i<k;i++) {
1044 c+=x[i];
1045 b=0;
1046 if (c<0) {
1047 b=-(c>>bpe);
1048 c+=b*radix;
1049 }
1050 x[i]=c & mask;
1051 c=(c>>bpe)-b;
1052 if (!c) return; //stop carrying as soon as the carry_ is zero
1053 }
1054}
1055
1056//right shift bigInt x by n bits. 0 <= n < bpe.
1057function rightShift_(x,n) {
1058 var i;
1059 var k=Math.floor(n/bpe);
1060 if (k) {
1061 for (i=0;i<x.length-k;i++) //right shift x by k elements
1062 x[i]=x[i+k];
1063 for (;i<x.length;i++)
1064 x[i]=0;
1065 n%=bpe;
1066 }
1067 for (i=0;i<x.length-1;i++) {
1068 x[i]=mask & ((x[i+1]<<(bpe-n)) | (x[i]>>n));
1069 }
1070 x[i]>>=n;
1071}
1072
1073//do x=floor(|x|/2)*sgn(x) for bigInt x in 2's complement
1074function halve_(x) {
1075 var i;
1076 for (i=0;i<x.length-1;i++) {
1077 x[i]=mask & ((x[i+1]<<(bpe-1)) | (x[i]>>1));
1078 }
1079 x[i]=(x[i]>>1) | (x[i] & (radix>>1)); //most significant bit stays the same
1080}
1081
1082//left shift bigInt x by n bits.
1083function leftShift_(x,n) {
1084 var i;
1085 var k=Math.floor(n/bpe);
1086 if (k) {
1087 for (i=x.length; i>=k; i--) //left shift x by k elements
1088 x[i]=x[i-k];
1089 for (;i>=0;i--)
1090 x[i]=0;
1091 n%=bpe;
1092 }
1093 if (!n)
1094 return;
1095 for (i=x.length-1;i>0;i--) {
1096 x[i]=mask & ((x[i]<<n) | (x[i-1]>>(bpe-n)));
1097 }
1098 x[i]=mask & (x[i]<<n);
1099}
1100
1101//do x=x*n where x is a bigInt and n is an integer.
1102//x must be large enough to hold the result.
1103function multInt_(x,n) {
1104 var i,k,c,b;
1105 if (!n)
1106 return;
1107 k=x.length;
1108 c=0;
1109 for (i=0;i<k;i++) {
1110 c+=x[i]*n;
1111 b=0;
1112 if (c<0) {
1113 b=-(c>>bpe);
1114 c+=b*radix;
1115 }
1116 x[i]=c & mask;
1117 c=(c>>bpe)-b;
1118 }
1119}
1120
1121//do x=floor(x/n) for bigInt x and integer n, and return the remainder
1122function divInt_(x,n) {
1123 var i,r=0,s;
1124 for (i=x.length-1;i>=0;i--) {
1125 s=r*radix+x[i];
1126 x[i]=Math.floor(s/n);
1127 r=s%n;
1128 }
1129 return r;
1130}
1131
1132//do the linear combination x=a*x+b*y for bigInts x and y, and integers a and b.
1133//x must be large enough to hold the answer.
1134function linComb_(x,y,a,b) {
1135 var i,c,k,kk;
1136 k=x.length<y.length ? x.length : y.length;
1137 kk=x.length;
1138 for (c=0,i=0;i<k;i++) {
1139 c+=a*x[i]+b*y[i];
1140 x[i]=c & mask;
1141 c>>=bpe;
1142 }
1143 for (i=k;i<kk;i++) {
1144 c+=a*x[i];
1145 x[i]=c & mask;
1146 c>>=bpe;
1147 }
1148}
1149
1150//do the linear combination x=a*x+b*(y<<(ys*bpe)) for bigInts x and y, and integers a, b and ys.
1151//x must be large enough to hold the answer.
1152function linCombShift_(x,y,b,ys) {
1153 var i,c,k,kk;
1154 k=x.length<ys+y.length ? x.length : ys+y.length;
1155 kk=x.length;
1156 for (c=0,i=ys;i<k;i++) {
1157 c+=x[i]+b*y[i-ys];
1158 x[i]=c & mask;
1159 c>>=bpe;
1160 }
1161 for (i=k;c && i<kk;i++) {
1162 c+=x[i];
1163 x[i]=c & mask;
1164 c>>=bpe;
1165 }
1166}
1167
1168//do x=x+(y<<(ys*bpe)) for bigInts x and y, and integers a,b and ys.
1169//x must be large enough to hold the answer.
1170function addShift_(x,y,ys) {
1171 var i,c,k,kk;
1172 k=x.length<ys+y.length ? x.length : ys+y.length;
1173 kk=x.length;
1174 for (c=0,i=ys;i<k;i++) {
1175 c+=x[i]+y[i-ys];
1176 x[i]=c & mask;
1177 c>>=bpe;
1178 }
1179 for (i=k;c && i<kk;i++) {
1180 c+=x[i];
1181 x[i]=c & mask;
1182 c>>=bpe;
1183 }
1184}
1185
1186//do x=x-(y<<(ys*bpe)) for bigInts x and y, and integers a,b and ys.
1187//x must be large enough to hold the answer.
1188function subShift_(x,y,ys) {
1189 var i,c,k,kk;
1190 k=x.length<ys+y.length ? x.length : ys+y.length;
1191 kk=x.length;
1192 for (c=0,i=ys;i<k;i++) {
1193 c+=x[i]-y[i-ys];
1194 x[i]=c & mask;
1195 c>>=bpe;
1196 }
1197 for (i=k;c && i<kk;i++) {
1198 c+=x[i];
1199 x[i]=c & mask;
1200 c>>=bpe;
1201 }
1202}
1203
1204//do x=x-y for bigInts x and y.
1205//x must be large enough to hold the answer.
1206//negative answers will be 2s complement
1207function sub_(x,y) {
1208 var i,c,k,kk;
1209 k=x.length<y.length ? x.length : y.length;
1210 for (c=0,i=0;i<k;i++) {
1211 c+=x[i]-y[i];
1212 x[i]=c & mask;
1213 c>>=bpe;
1214 }
1215 for (i=k;c && i<x.length;i++) {
1216 c+=x[i];
1217 x[i]=c & mask;
1218 c>>=bpe;
1219 }
1220}
1221
1222//do x=x+y for bigInts x and y.
1223//x must be large enough to hold the answer.
1224function add_(x,y) {
1225 var i,c,k,kk;
1226 k=x.length<y.length ? x.length : y.length;
1227 for (c=0,i=0;i<k;i++) {
1228 c+=x[i]+y[i];
1229 x[i]=c & mask;
1230 c>>=bpe;
1231 }
1232 for (i=k;c && i<x.length;i++) {
1233 c+=x[i];
1234 x[i]=c & mask;
1235 c>>=bpe;
1236 }
1237}
1238
1239//do x=x*y for bigInts x and y. This is faster when y<x.
1240function mult_(x,y) {
1241 var i;
1242 if (ss.length!=2*x.length)
1243 ss=new Array(2*x.length);
1244 copyInt_(ss,0);
1245 for (i=0;i<y.length;i++)
1246 if (y[i])
1247 linCombShift_(ss,x,y[i],i); //ss=1*ss+y[i]*(x<<(i*bpe))
1248 copy_(x,ss);
1249}
1250
1251//do x=x mod n for bigInts x and n.
1252function mod_(x,n) {
1253 if (s4.length!=x.length)
1254 s4=dup(x);
1255 else
1256 copy_(s4,x);
1257 if (s5.length!=x.length)
1258 s5=dup(x);
1259 divide_(s4,n,s5,x); //x = remainder of s4 / n
1260}
1261
1262//do x=x*y mod n for bigInts x,y,n.
1263//for greater speed, let y<x.
1264function multMod_(x,y,n) {
1265 var i;
1266 if (s0.length!=2*x.length)
1267 s0=new Array(2*x.length);
1268 copyInt_(s0,0);
1269 for (i=0;i<y.length;i++)
1270 if (y[i])
1271 linCombShift_(s0,x,y[i],i); //s0=1*s0+y[i]*(x<<(i*bpe))
1272 mod_(s0,n);
1273 copy_(x,s0);
1274}
1275
1276//do x=x*x mod n for bigInts x,n.
1277function squareMod_(x,n) {
1278 var i,j,d,c,kx,kn,k;
1279 for (kx=x.length; kx>0 && !x[kx-1]; kx--); //ignore leading zeros in x
1280 k=kx>n.length ? 2*kx : 2*n.length; //k=# elements in the product, which is twice the elements in the larger of x and n
1281 if (s0.length!=k)
1282 s0=new Array(k);
1283 copyInt_(s0,0);
1284 for (i=0;i<kx;i++) {
1285 c=s0[2*i]+x[i]*x[i];
1286 s0[2*i]=c & mask;
1287 c>>=bpe;
1288 for (j=i+1;j<kx;j++) {
1289 c=s0[i+j]+2*x[i]*x[j]+c;
1290 s0[i+j]=(c & mask);
1291 c>>=bpe;
1292 }
1293 s0[i+kx]=c;
1294 }
1295 mod_(s0,n);
1296 copy_(x,s0);
1297}
1298
1299//return x with exactly k leading zero elements
1300function trim(x,k) {
1301 var i,y;
1302 for (i=x.length; i>0 && !x[i-1]; i--);
1303 y=new Array(i+k);
1304 copy_(y,x);
1305 return y;
1306}
1307
1308//do x=x**y mod n, where x,y,n are bigInts and ** is exponentiation. 0**0=1.
1309//this is faster when n is odd. x usually needs to have as many elements as n.
1310function powMod_(x,y,n) {
1311 var k1,k2,kn,np;
1312 if(s7.length!=n.length)
1313 s7=dup(n);
1314
1315 //for even modulus, use a simple square-and-multiply algorithm,
1316 //rather than using the more complex Montgomery algorithm.
1317 if ((n[0]&1)==0) {
1318 copy_(s7,x);
1319 copyInt_(x,1);
1320 while(!equalsInt(y,0)) {
1321 if (y[0]&1)
1322 multMod_(x,s7,n);
1323 divInt_(y,2);
1324 squareMod_(s7,n);
1325 }
1326 return;
1327 }
1328
1329 //calculate np from n for the Montgomery multiplications
1330 copyInt_(s7,0);
1331 for (kn=n.length;kn>0 && !n[kn-1];kn--);
1332 np=radix-inverseModInt_(modInt(n,radix),radix);
1333 s7[kn]=1;
1334 multMod_(x ,s7,n); // x = x * 2**(kn*bp) mod n
1335
1336 if (s3.length!=x.length)
1337 s3=dup(x);
1338 else
1339 copy_(s3,x);
1340
1341 for (k1=y.length-1;k1>0 & !y[k1]; k1--); //k1=first nonzero element of y
1342 if (y[k1]==0) { //anything to the 0th power is 1
1343 copyInt_(x,1);
1344 return;
1345 }
1346 for (k2=1<<(bpe-1);k2 && !(y[k1] & k2); k2>>=1); //k2=position of first 1 bit in y[k1]
1347 for (;;) {
1348 if (!(k2>>=1)) { //look at next bit of y
1349 k1--;
1350 if (k1<0) {
1351 mont_(x,one,n,np);
1352 return;
1353 }
1354 k2=1<<(bpe-1);
1355 }
1356 mont_(x,x,n,np);
1357
1358 if (k2 & y[k1]) //if next bit is a 1
1359 mont_(x,s3,n,np);
1360 }
1361}
1362
1363//do x=x*y*Ri mod n for bigInts x,y,n,
1364// where Ri = 2**(-kn*bpe) mod n, and kn is the
1365// number of elements in the n array, not
1366// counting leading zeros.
1367//x must be large enough to hold the answer.
1368//It's OK if x and y are the same variable.
1369//must have:
1370// x,y < n
1371// n is odd
1372// np = -(n^(-1)) mod radix
1373function mont_(x,y,n,np) {
1374 var i,j,c,ui,t;
1375 var kn=n.length;
1376 var ky=y.length;
1377
1378 if (sa.length!=kn)
1379 sa=new Array(kn);
1380
1381 for (;kn>0 && n[kn-1]==0;kn--); //ignore leading zeros of n
1382 //this function sometimes gives wrong answers when the next line is uncommented
1383 //for (;ky>0 && y[ky-1]==0;ky--); //ignore leading zeros of y
1384
1385 copyInt_(sa,0);
1386
1387 //the following loop consumes 95% of the runtime for randTruePrime_() and powMod_() for large keys
1388 for (i=0; i<kn; i++) {
1389 t=sa[0]+x[i]*y[0];
1390 ui=((t & mask) * np) & mask; //the inner "& mask" is needed on Macintosh MSIE, but not windows MSIE
1391 c=(t+ui*n[0]) >> bpe;
1392 t=x[i];
1393
1394 //do sa=(sa+x[i]*y+ui*n)/b where b=2**bpe
1395 for (j=1;j<ky;j++) {
1396 c+=sa[j]+t*y[j]+ui*n[j];
1397 sa[j-1]=c & mask;
1398 c>>=bpe;
1399 }
1400 for (;j<kn;j++) {
1401 c+=sa[j]+ui*n[j];
1402 sa[j-1]=c & mask;
1403 c>>=bpe;
1404 }
1405 sa[j-1]=c & mask;
1406 }
1407
1408 if (!greater(n,sa))
1409 sub_(sa,n);
1410 copy_(x,sa);
1411}
1412
1413
1414
1415
1416//#############################################################################
1417//#############################################################################
1418//#############################################################################
1419//#############################################################################
1420//#############################################################################
1421//#############################################################################
1422//#############################################################################
1423
1424
1425
1426
1427
1428//#############################################################################
1429
1430Clipperz.Crypto.BigInt = function (aValue, aBase) {
1431 varbase;
1432 varvalue;
1433
1434 if (typeof(aValue) == 'object') {
1435 this._internalValue = aValue;
1436 } else {
1437 if (typeof(aValue) == 'undefined') {
1438 value = "0";
1439 } else {
1440 value = aValue + "";
1441 }
1442
1443 if (typeof(aBase) == 'undefined') {
1444 base = 10;
1445 } else {
1446 base = aBase;
1447 }
1448
1449 this._internalValue = str2bigInt(value, base, 1, 1);
1450 }
1451
1452 return this;
1453}
1454
1455//=============================================================================
1456
1457MochiKit.Base.update(Clipperz.Crypto.BigInt.prototype, {
1458
1459 //-------------------------------------------------------------------------
1460
1461 'internalValue': function () {
1462 return this._internalValue;
1463 },
1464
1465 //-------------------------------------------------------------------------
1466
1467 'isBigInt': true,
1468
1469 //-------------------------------------------------------------------------
1470
1471 'toString': function(aBase) {
1472 return this.asString(aBase);
1473 },
1474
1475 //-------------------------------------------------------------------------
1476
1477 'asString': function (aBase) {
1478 varbase;
1479
1480 if (typeof(aBase) == 'undefined') {
1481 base = 10;
1482 } else {
1483 base = aBase;
1484 }
1485
1486 return bigInt2str(this.internalValue(), base).toLowerCase();
1487 },
1488
1489 //-------------------------------------------------------------------------
1490
1491 'equals': function (aValue) {
1492 var result;
1493
1494 if (aValue.isBigInt) {
1495 result = equals(this.internalValue(), aValue.internalValue());
1496 } else if (typeof(aValue) == "number") {
1497 result = equalsInt(this.internalValue(), aValue);
1498 } else {
1499 throw Clipperz.Crypt.BigInt.exception.UnknownType;
1500 }
1501
1502 return result;
1503 },
1504
1505 //-------------------------------------------------------------------------
1506
1507 'add': function (aValue) {
1508 var result;
1509
1510 if (aValue.isBigInt) {
1511 result = add(this.internalValue(), aValue.internalValue());
1512 } else {
1513 result = addInt(this.internalValue(), aValue);
1514 }
1515
1516 return new Clipperz.Crypto.BigInt(result);
1517 },
1518
1519 //-------------------------------------------------------------------------
1520
1521 'subtract': function (aValue) {
1522 var result;
1523 var value;
1524
1525 if (aValue.isBigInt) {
1526 value = aValue;
1527 } else {
1528 value = new Clipperz.Crypto.BigInt(aValue);
1529 }
1530
1531 result = sub(this.internalValue(), value.internalValue());
1532
1533 return new Clipperz.Crypto.BigInt(result);
1534 },
1535
1536 //-------------------------------------------------------------------------
1537
1538 'multiply': function (aValue, aModule) {
1539 var result;
1540 var value;
1541
1542 if (aValue.isBigInt) {
1543 value = aValue;
1544 } else {
1545 value = new Clipperz.Crypto.BigInt(aValue);
1546 }
1547
1548 if (typeof(aModule) == 'undefined') {
1549 result = mult(this.internalValue(), value.internalValue());
1550 } else {
1551 result = multMod(this.internalValue(), value.internalValue(), aModule);
1552 }
1553
1554 return new Clipperz.Crypto.BigInt(result);
1555 },
1556
1557 //-------------------------------------------------------------------------
1558
1559 'module': function (aModule) {
1560 varresult;
1561 var module;
1562
1563 if (aModule.isBigInt) {
1564 module = aModule;
1565 } else {
1566 module = new Clipperz.Crypto.BigInt(aModule);
1567 }
1568
1569 result = mod(this.internalValue(), module.internalValue());
1570
1571 return new Clipperz.Crypto.BigInt(result);
1572 },
1573
1574 //-------------------------------------------------------------------------
1575
1576 'powerModule': function(aValue, aModule) {
1577 varresult;
1578 varvalue;
1579 var module;
1580
1581 if (aValue.isBigInt) {
1582 value = aValue;
1583 } else {
1584 value = new Clipperz.Crypto.BigInt(aValue);
1585 }
1586
1587 if (aModule.isBigInt) {
1588 module = aModule;
1589 } else {
1590 module = new Clipperz.Crypto.BigInt(aModule);
1591 }
1592
1593 if (aValue == -1) {
1594 result = inverseMod(this.internalValue(), module.internalValue());
1595 } else {
1596 result = powMod(this.internalValue(), value.internalValue(), module.internalValue());
1597 }
1598
1599 return new Clipperz.Crypto.BigInt(result);
1600 },
1601
1602 //-------------------------------------------------------------------------
1603
1604 'bitSize': function() {
1605 return bitSize(this.internalValue());
1606 },
1607
1608 //-------------------------------------------------------------------------
1609 __syntaxFix__: "syntax fix"
1610
1611});
1612
1613//#############################################################################
1614
1615Clipperz.Crypto.BigInt.randomPrime = function(aBitSize) {
1616 return new Clipperz.Crypto.BigInt(randTruePrime(aBitSize));
1617}
1618
1619//#############################################################################
1620//#############################################################################
1621//#############################################################################
1622
1623Clipperz.Crypto.BigInt.equals = function(a, b) {
1624 return a.equals(b);
1625}
1626
1627Clipperz.Crypto.BigInt.add = function(a, b) {
1628 return a.add(b);
1629}
1630
1631Clipperz.Crypto.BigInt.subtract = function(a, b) {
1632 return a.subtract(b);
1633}
1634
1635Clipperz.Crypto.BigInt.multiply = function(a, b, module) {
1636 return a.multiply(b, module);
1637}
1638
1639Clipperz.Crypto.BigInt.module = function(a, module) {
1640 return a.module(module);
1641}
1642
1643Clipperz.Crypto.BigInt.powerModule = function(a, b, module) {
1644 return a.powerModule(b, module);
1645}
1646
1647Clipperz.Crypto.BigInt.exception = {
1648 UnknownType: new MochiKit.Base.NamedError("Clipperz.Crypto.BigInt.exception.UnknownType")
1649}
diff --git a/frontend/beta/js/Clipperz/Crypto/ECC.js b/frontend/beta/js/Clipperz/Crypto/ECC.js
new file mode 100644
index 0000000..c3dcec3
--- a/dev/null
+++ b/frontend/beta/js/Clipperz/Crypto/ECC.js
@@ -0,0 +1,960 @@
1/*
2
3Copyright 2008-2011 Clipperz Srl
4
5This file is part of Clipperz's Javascript Crypto Library.
6Javascript Crypto Library provides web developers with an extensive
7and efficient set of cryptographic functions. The library aims to
8obtain maximum execution speed while preserving modularity and
9reusability.
10For further information about its features and functionalities please
11refer to http://www.clipperz.com
12
13* Javascript Crypto Library is free software: you can redistribute
14 it and/or modify it under the terms of the GNU Affero General Public
15 License as published by the Free Software Foundation, either version
16 3 of the License, or (at your option) any later version.
17
18* Javascript Crypto Library is distributed in the hope that it will
19 be useful, but WITHOUT ANY WARRANTY; without even the implied
20 warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
21 See the GNU Affero General Public License for more details.
22
23* You should have received a copy of the GNU Affero General Public
24 License along with Javascript Crypto Library. If not, see
25 <http://www.gnu.org/licenses/>.
26
27*/
28
29/*
30try { if (typeof(Clipperz.ByteArray) == 'undefined') { throw ""; }} catch (e) {
31 throw "Clipperz.Crypto.ECC depends on Clipperz.ByteArray!";
32}
33
34if (typeof(Clipperz.Crypto.ECC) == 'undefined') { Clipperz.Crypto.ECC = {}; }
35
36
37//#############################################################################
38
39Clipperz.Crypto.ECC.BinaryField = {};
40
41//#############################################################################
42
43Clipperz.Crypto.ECC.BinaryField.AbstractValue = function(aValue, aBase) {
44 return this;
45}
46
47Clipperz.Crypto.ECC.BinaryField.AbstractValue.prototype = MochiKit.Base.update(null, {
48
49 'asString': function(aBase) {
50 throw Clipperz.Base.exception.AbstractMethod;
51 },
52
53 'isZero': function() {
54 throw Clipperz.Base.exception.AbstractMethod;
55 },
56
57 'shiftLeft': function(aNumberOfBitsToShift) {
58 throw Clipperz.Base.exception.AbstractMethod;
59 },
60
61 'bitSize': function() {
62 throw Clipperz.Base.exception.AbstractMethod;
63 },
64
65 'isBitSet': function(aBitPosition) {
66 throw Clipperz.Base.exception.AbstractMethod;
67 },
68
69 'xor': function(aValue) {
70 throw Clipperz.Base.exception.AbstractMethod;
71 },
72
73 'compare': function(aValue) {
74 throw Clipperz.Base.exception.AbstractMethod;
75 },
76
77 //-----------------------------------------------------------------------------
78 __syntaxFix__: "syntax fix"
79});
80
81//*****************************************************************************
82/ *
83Clipperz.Crypto.ECC.BinaryField.BigIntValue = function(aValue, aBase) {
84 this._value = new Clipperz.Crypto.BigInt(aValue, aBase);
85 return this;
86}
87
88Clipperz.Crypto.ECC.BinaryField.BigIntValue.prototype = MochiKit.Base.update(new Clipperz.Crypto.ECC.BinaryField.AbstractValue(), {
89
90 'value': function() {
91 return this._value;
92 },
93
94 //-----------------------------------------------------------------------------
95
96 'isZero': function() {
97 return (this.value().compare(Clipperz.Crypto.ECC.BinaryField.BigIntValue.O) == 0);
98 },
99
100 //-----------------------------------------------------------------------------
101
102 'asString': function(aBase) {
103 return this.value().asString(aBase);
104 },
105
106 //-----------------------------------------------------------------------------
107
108 'shiftLeft': function(aNumberOfBitsToShift) {
109 return new Clipperz.Crypto.ECC.BinaryField.BigIntValue(this.value().shiftLeft(aNumberOfBitsToShift));
110 },
111
112 //-----------------------------------------------------------------------------
113
114 'bitSize': function() {
115 return this.value().bitSize();
116 },
117
118 //-----------------------------------------------------------------------------
119
120 'isBitSet': function(aBitPosition) {
121 return this.value().isBitSet(aBitPosition);
122 },
123
124 //-----------------------------------------------------------------------------
125
126 'xor': function(aValue) {
127 return new Clipperz.Crypto.ECC.BinaryField.BigIntValue(this.value().xor(aValue.value()));
128 },
129
130 //-----------------------------------------------------------------------------
131
132 'compare': function(aValue) {
133 return this.value().compare(aValue.value());
134 },
135
136 //-----------------------------------------------------------------------------
137 __syntaxFix__: "syntax fix"
138});
139
140Clipperz.Crypto.ECC.BinaryField.BigIntValue.O = new Clipperz.Crypto.BigInt(0);
141Clipperz.Crypto.ECC.BinaryField.BigIntValue.I = new Clipperz.Crypto.BigInt(1);
142* /
143//*****************************************************************************
144
145Clipperz.Crypto.ECC.BinaryField.WordArrayValue = function(aValue, aBase) {
146 if (aValue.constructor == String) {
147 varvalue;
148 varstringLength;
149 var numberOfWords;
150 vari,c;
151
152 if (aBase != 16) {
153 throw Clipperz.Crypto.ECC.BinaryField.WordArrayValue.exception.UnsupportedBase;
154 }
155
156 value = aValue.replace(/ /g, '');
157 stringLength = value.length;
158 numberOfWords = Math.ceil(stringLength / 8);
159 this._value = new Array(numberOfWords);
160
161 c = numberOfWords;
162 for (i=0; i<c; i++) {
163 varword;
164
165 if (i < (c-1)) {
166 word = parseInt(value.substr(stringLength-((i+1)*8), 8), 16);
167 } else {
168 word = parseInt(value.substr(0, stringLength-(i*8)), 16);
169 }
170
171 this._value[i] = word;
172 }
173 } else if (aValue.constructor == Array) {
174 var itemsToCopy;
175
176 itemsToCopy = aValue.length;
177 while (aValue[itemsToCopy - 1] == 0) {
178 itemsToCopy --;
179 }
180
181 this._value = aValue.slice(0, itemsToCopy);
182 } else if (aValue.constructor == Number) {
183 this._value = [aValue];
184 } else {
185 // throw Clipperz.Crypto.ECC.BinaryField.WordArrayValue.exception.UnsupportedConstructorValueType;
186 }
187
188 return this;
189}
190
191Clipperz.Crypto.ECC.BinaryField.WordArrayValue.prototype = MochiKit.Base.update(new Clipperz.Crypto.ECC.BinaryField.AbstractValue(), {
192
193 'value': function() {
194 return this._value;
195 },
196
197 //-----------------------------------------------------------------------------
198
199 'wordSize': function() {
200 return this._value.length
201 },
202
203 //-----------------------------------------------------------------------------
204
205 'clone': function() {
206 return new Clipperz.Crypto.ECC.BinaryField.WordArrayValue(this._value.slice(0));
207 },
208
209 //-----------------------------------------------------------------------------
210
211 'isZero': function() {
212 return (this.compare(Clipperz.Crypto.ECC.BinaryField.WordArrayValue.O) == 0);
213 },
214
215 //-----------------------------------------------------------------------------
216
217 'asString': function(aBase) {
218 varresult;
219 var i,c;
220
221 if (aBase != 16) {
222 throw Clipperz.Crypto.ECC.BinaryField.WordArrayValue.exception.UnsupportedBase;
223 }
224
225 result = "";
226 c = this.wordSize();
227 for (i=0; i<c; i++) {
228 varwordAsString;
229
230 // wordAsString = ("00000000" + this.value()[i].toString(16));
231 wordAsString = ("00000000" + this._value[i].toString(16));
232 wordAsString = wordAsString.substring(wordAsString.length - 8);
233 result = wordAsString + result;
234 }
235
236 result = result.replace(/^(00)* SPACEs THAT SHOULD BE REMOVED TO FIX THIS REGEX /, "");
237
238 if (result == "") {
239 result = "0";
240 }
241
242 return result;
243 },
244
245 //-----------------------------------------------------------------------------
246
247 'shiftLeft': function(aNumberOfBitsToShift) {
248 return new Clipperz.Crypto.ECC.BinaryField.WordArrayValue(Clipperz.Crypto.ECC.BinaryField.WordArrayValue.shiftLeft(this._value, aNumberOfBitsToShift));
249 },
250
251 //-----------------------------------------------------------------------------
252
253 'bitSize': function() {
254 return Clipperz.Crypto.ECC.BinaryField.WordArrayValue.bitSize(this._value);
255 },
256
257 //-----------------------------------------------------------------------------
258
259 'isBitSet': function(aBitPosition) {
260 return Clipperz.Crypto.ECC.BinaryField.WordArrayValue.isBitSet(this._value, aBitPosition);
261 },
262
263 //-----------------------------------------------------------------------------
264
265 'xor': function(aValue) {
266 return new Clipperz.Crypto.ECC.BinaryField.WordArrayValue(Clipperz.Crypto.ECC.BinaryField.WordArrayValue.xor(this._value, aValue._value));
267 },
268
269 //-----------------------------------------------------------------------------
270
271 'compare': function(aValue) {
272 return Clipperz.Crypto.ECC.BinaryField.WordArrayValue.compare(this._value, aValue._value);
273 },
274
275 //-----------------------------------------------------------------------------
276 __syntaxFix__: "syntax fix"
277});
278
279Clipperz.Crypto.ECC.BinaryField.WordArrayValue.O = new Clipperz.Crypto.ECC.BinaryField.WordArrayValue('0', 16);
280Clipperz.Crypto.ECC.BinaryField.WordArrayValue.I = new Clipperz.Crypto.ECC.BinaryField.WordArrayValue('1', 16);
281
282Clipperz.Crypto.ECC.BinaryField.WordArrayValue.xor = function(a, b) {
283 var result;
284 var resultSize;
285 var i,c;
286
287 resultSize = Math.max(a.length, b.length);
288
289 result = new Array(resultSize);
290 c = resultSize;
291 for (i=0; i<c; i++) {
292 // resultValue[i] = (((this.value()[i] || 0) ^ (aValue.value()[i] || 0)) >>> 0);
293 result[i] = (((a[i] || 0) ^ (b[i] || 0)) >>> 0);
294 }
295
296 return result;
297};
298
299Clipperz.Crypto.ECC.BinaryField.WordArrayValue.shiftLeft = function(aWordArray, aNumberOfBitsToShift) {
300 var numberOfWordsToShift;
301 varnumberOfBitsToShift;
302 var result;
303 varoverflowValue;
304 vari,c;
305
306 numberOfWordsToShift = Math.floor(aNumberOfBitsToShift / 32);
307 numberOfBitsToShift = aNumberOfBitsToShift % 32;
308
309 result = new Array(aWordArray.length + numberOfWordsToShift);
310
311 c = numberOfWordsToShift;
312 for (i=0; i<c; i++) {
313 result[i] = 0;
314 }
315
316 overflowValue = 0;
317 nextOverflowValue = 0;
318
319 c = aWordArray.length;
320 for (i=0; i<c; i++) {
321 varvalue;
322 varresultWord;
323
324 // value = this.value()[i];
325 value = aWordArray[i];
326
327 if (numberOfBitsToShift > 0) {
328 var nextOverflowValue;
329
330 nextOverflowValue = (value >>> (32 - numberOfBitsToShift));
331 value = value & (0xffffffff >>> numberOfBitsToShift);
332 resultWord = (((value << numberOfBitsToShift) | overflowValue) >>> 0);
333 } else {
334 resultWord = value;
335 }
336
337 result[i+numberOfWordsToShift] = resultWord;
338 overflowValue = nextOverflowValue;
339 }
340
341 if (overflowValue != 0) {
342 result[aWordArray.length + numberOfWordsToShift] = overflowValue;
343 }
344
345 return result;
346};
347
348Clipperz.Crypto.ECC.BinaryField.WordArrayValue.bitSize = function(aWordArray) {
349 varresult;
350 varnotNullElements;
351 var mostValuableWord;
352 var matchingBitsInMostImportantWord;
353 var mask;
354 var i,c;
355
356 notNullElements = aWordArray.length;
357
358 if ((aWordArray.length == 1) && (aWordArray[0] == 0)) {
359 result = 0;
360 } else {
361 while((aWordArray[notNullElements - 1] == 0) && (notNullElements > 0)) {
362 notNullElements --;
363 }
364
365 result = (notNullElements - 1) * 32;
366 mostValuableWord = aWordArray[notNullElements - 1];
367
368 matchingBits = 32;
369 mask = 0x80000000;
370
371 while ((matchingBits > 0) && ((mostValuableWord & mask) == 0)) {
372 matchingBits --;
373 mask >>>= 1;
374 }
375
376 result += matchingBits;
377 }
378
379 return result;
380};
381
382Clipperz.Crypto.ECC.BinaryField.WordArrayValue.isBitSet = function(aWordArray, aBitPosition) {
383 var result;
384 varbyteIndex;
385 var bitIndexInSelectedByte;
386
387 byteIndex = Math.floor(aBitPosition / 32);
388 bitIndexInSelectedByte = aBitPosition % 32;
389
390 if (byteIndex <= aWordArray.length) {
391 result = ((aWordArray[byteIndex] & (1 << bitIndexInSelectedByte)) != 0);
392 } else {
393 result = false;
394 }
395
396 return result;
397};
398
399Clipperz.Crypto.ECC.BinaryField.WordArrayValue.compare = function(a,b) {
400 varresult;
401 var i,c;
402
403 result = MochiKit.Base.compare(a.length, b.length);
404
405 c = a.length;
406 for (i=0; (i<c) && (result==0); i++) {
407//console.log("compare[" + c + " - " + i + " - 1] " + this.value()[c-i-1] + ", " + aValue.value()[c-i-1]);
408 // result = MochiKit.Base.compare(this.value()[c-i-1], aValue.value()[c-i-1]);
409 result = MochiKit.Base.compare(a[c-i-1], b[c-i-1]);
410 }
411
412 return result;
413};
414
415
416Clipperz.Crypto.ECC.BinaryField.WordArrayValue['exception']= {
417 'UnsupportedBase': new MochiKit.Base.NamedError("Clipperz.Crypto.ECC.BinaryField.WordArrayValue.exception.UnsupportedBase"),
418 'UnsupportedConstructorValueType':new MochiKit.Base.NamedError("Clipperz.Crypto.ECC.BinaryField.WordArrayValue.exception.UnsupportedConstructorValueType")
419};
420
421//*****************************************************************************
422
423 //Clipperz.Crypto.ECC.BinaryField.Value =Clipperz.Crypto.ECC.BinaryField.BigIntValue;
424 Clipperz.Crypto.ECC.BinaryField.Value =Clipperz.Crypto.ECC.BinaryField.WordArrayValue;
425
426//#############################################################################
427
428Clipperz.Crypto.ECC.BinaryField.Point = function(args) {
429 args = args || {};
430 this._x = args.x;
431 this._y = args.y;
432
433 return this;
434}
435
436Clipperz.Crypto.ECC.BinaryField.Point.prototype = MochiKit.Base.update(null, {
437
438 'asString': function() {
439 return "Clipperz.Crypto.ECC.BinaryField.Point (" + this.x() + ", " + this.y() + ")";
440 },
441
442 //-----------------------------------------------------------------------------
443
444 'x': function() {
445 return this._x;
446 },
447
448 'y': function() {
449 return this._y;
450 },
451
452 //-----------------------------------------------------------------------------
453
454 'isZero': function() {
455 return (this.x().isZero() && this.y().isZero())
456 },
457
458 //-----------------------------------------------------------------------------
459 __syntaxFix__: "syntax fix"
460});
461
462//#############################################################################
463
464Clipperz.Crypto.ECC.BinaryField.FiniteField = function(args) {
465 args = args || {};
466 this._modulus = args.modulus;
467
468 return this;
469}
470
471Clipperz.Crypto.ECC.BinaryField.FiniteField.prototype = MochiKit.Base.update(null, {
472
473 'asString': function() {
474 return "Clipperz.Crypto.ECC.BinaryField.FiniteField (" + this.modulus().asString() + ")";
475 },
476
477 //-----------------------------------------------------------------------------
478
479 'modulus': function() {
480 return this._modulus;
481 },
482
483 //-----------------------------------------------------------------------------
484
485 '_module': function(aValue) {
486 varresult;
487 var modulusComparison;
488//console.log(">>> binaryField.finiteField.(standard)module");
489
490 modulusComparison = Clipperz.Crypto.ECC.BinaryField.WordArrayValue.compare(aValue, this.modulus()._value);
491
492 if (modulusComparison < 0) {
493 result = aValue;
494 } else if (modulusComparison == 0) {
495 result = [0];
496 } else {
497 var modulusBitSize;
498 var resultBitSize;
499
500 result = aValue;
501
502 modulusBitSize = this.modulus().bitSize();
503 resultBitSize = Clipperz.Crypto.ECC.BinaryField.WordArrayValue.bitSize(result);
504 while (resultBitSize >= modulusBitSize) {
505 result = Clipperz.Crypto.ECC.BinaryField.WordArrayValue.xor(result, Clipperz.Crypto.ECC.BinaryField.WordArrayValue.shiftLeft(this.modulus()._value, resultBitSize - modulusBitSize));
506 resultBitSize = Clipperz.Crypto.ECC.BinaryField.WordArrayValue.bitSize(result);
507 }
508 }
509//console.log("<<< binaryField.finiteField.(standard)module");
510
511 return result;
512 },
513
514 'module': function(aValue) {
515 return new Clipperz.Crypto.ECC.BinaryField.Value(this._module(aValue._value));
516 },
517
518 //-----------------------------------------------------------------------------
519
520 '_add': function(a, b) {
521 return Clipperz.Crypto.ECC.BinaryField.WordArrayValue.xor(a, b);
522 },
523
524 'add': function(a, b) {
525 return new Clipperz.Crypto.ECC.BinaryField.Value(this._add(a._value, b._value));
526 },
527
528 //-----------------------------------------------------------------------------
529
530 'negate': function(aValue) {
531 return aValue.clone();
532 },
533
534 //-----------------------------------------------------------------------------
535/ *
536 'multiply': function(a, b) {
537 var result;
538 var valueToXor;
539 var i,c;
540
541 result = Clipperz.Crypto.ECC.BinaryField.Value.O;
542 valueToXor = b;
543 c = a.bitSize();
544 for (i=0; i<c; i++) {
545 if (a.isBitSet(i) === true) {
546 result = result.xor(valueToXor);
547 }
548 valueToXor = valueToXor.shiftLeft(1);
549 }
550 result = this.module(result);
551
552 return result;
553 },
554* /
555
556 '_multiply': function(a, b) {
557 var result;
558 var valueToXor;
559 var i,c;
560
561 result = [0];
562 valueToXor = b;
563 c = Clipperz.Crypto.ECC.BinaryField.WordArrayValue.bitSize(a);
564 for (i=0; i<c; i++) {
565 if (Clipperz.Crypto.ECC.BinaryField.WordArrayValue.isBitSet(a, i) === true) {
566 result = Clipperz.Crypto.ECC.BinaryField.WordArrayValue.xor(result, valueToXor);
567 }
568 valueToXor = Clipperz.Crypto.ECC.BinaryField.WordArrayValue.shiftLeft(valueToXor, 1);
569 }
570 result = this._module(result);
571
572 return result;
573 },
574
575 'multiply': function(a, b) {
576 return new Clipperz.Crypto.ECC.BinaryField.Value(this._multiply(a._value, b._value));
577 },
578
579 //-----------------------------------------------------------------------------
580 //
581 //Guide to Elliptic Curve Cryptography
582 //Darrel Hankerson, Alfred Menezes, Scott Vanstone
583 //- Pag: 49, Alorithm 2.34
584 //
585 //-----------------------------------------------------------------------------
586/ *
587 'square': function(aValue) {
588 varresult;
589 vart;
590 var i,c;
591
592 result = [0];
593 t = Math.max(a)
594 c = 32;
595 for (i=0; i<c; i++) {
596 var ii, cc;
597
598 cc =
599 }
600
601
602
603
604 return result;
605 },
606 * /
607 //-----------------------------------------------------------------------------
608
609 'inverse': function(aValue) {
610 varresult;
611 var b, c;
612 var u, v;
613
614 b = Clipperz.Crypto.ECC.BinaryField.Value.I;
615 c = Clipperz.Crypto.ECC.BinaryField.Value.O;
616 u = this.module(aValue);
617 v = this.modulus();
618
619 while (u.bitSize() > 1) {
620 varbitDifferenceSize;
621
622 bitDifferenceSize = u.bitSize() - v.bitSize();
623 if (bitDifferenceSize < 0) {
624 var swap;
625
626 swap = u;
627 u = v;
628 v = swap;
629
630 swap = c;
631 c = b;
632 b = swap;
633
634 bitDifferenceSize = -bitDifferenceSize;
635 }
636
637 u = this.add(u, v.shiftLeft(bitDifferenceSize));
638 b = this.add(b, c.shiftLeft(bitDifferenceSize))
639 }
640
641 result = this.module(b);
642
643 return result;
644 },
645
646 //-----------------------------------------------------------------------------
647 __syntaxFix__: "syntax fix"
648});
649
650//#############################################################################
651
652Clipperz.Crypto.ECC.BinaryField.Curve = function(args) {
653 args = args || {};
654
655 this._modulus = args.modulus;
656
657 this._a = args.a;
658 this._b = args.b;
659 this._G = args.G;
660 this._r = args.r;
661 this._h = args.h;
662
663 this._finiteField = null;
664
665 return this;
666}
667
668Clipperz.Crypto.ECC.BinaryField.Curve.prototype = MochiKit.Base.update(null, {
669
670 'asString': function() {
671 return "Clipperz.Crypto.ECC.BinaryField.Curve";
672 },
673
674 //-----------------------------------------------------------------------------
675
676 'modulus': function() {
677 return this._modulus;
678 },
679
680 'a': function() {
681 return this._a;
682 },
683
684 'b': function() {
685 return this._b;
686 },
687
688 'G': function() {
689 return this._G;
690 },
691
692 'r': function() {
693 return this._r;
694 },
695
696 'h': function() {
697 return this._h;
698 },
699
700 //-----------------------------------------------------------------------------
701
702 'finiteField': function() {
703 if (this._finiteField == null) {
704 this._finiteField = new Clipperz.Crypto.ECC.BinaryField.FiniteField({modulus:this.modulus()})
705 }
706
707 return this._finiteField;
708 },
709
710 //-----------------------------------------------------------------------------
711
712 'negate': function(aPointA) {
713 var result;
714
715 result = new Clipperz.Crypto.ECC.Point({x:aPointA.x(), y:this.finiteField().add(aPointA.y(), aPointA.x())})
716
717 return result;
718 },
719
720 //-----------------------------------------------------------------------------
721
722 'add': function(aPointA, aPointB) {
723 var result;
724
725//console.log(">>> ECC.BinaryField.Curve.add");
726 if (aPointA.isZero()) {
727//console.log("--- pointA == zero");
728 result = aPointB;
729 } else if (aPointB.isZero()) {
730//console.log("--- pointB == zero");
731 result = aPointA;
732 } else if ((aPointA.x().compare(aPointB.x()) == 0) &&
733 ((aPointA.y().compare(aPointB.y()) != 0) || aPointB.x().isZero()))
734 {
735//console.log("compare A.x - B.x: ", aPointA.x().compare(aPointB.x()));
736//console.log("compare A.y - B.y: ", (aPointA.y().compare(aPointB.y()) != 0));
737//console.log("compare B.x.isZero(): ", aPointB.x().isZero());
738
739//console.log("--- result = zero");
740 result = new Clipperz.Crypto.ECC.BinaryField.Point({x:Clipperz.Crypto.ECC.BinaryField.Value.O, y:Clipperz.Crypto.ECC.BinaryField.Value.O});
741 } else {
742//console.log("--- result = ELSE");
743 varf2m;
744 var x, y;
745 var lambda;
746
747 f2m = this.finiteField();
748
749 if (aPointA.x().compare(aPointB.x()) != 0) {
750//console.log(" a.x != b.x");
751 lambda =f2m.multiply(
752 f2m.add(aPointA.y(), aPointB.y()),
753 f2m.inverse(f2m.add(aPointA.x(), aPointB.x()))
754 );
755 x = f2m.add(this.a(), f2m.multiply(lambda, lambda));
756 x = f2m.add(x, lambda);
757 x = f2m.add(x, aPointA.x());
758 x = f2m.add(x, aPointB.x());
759 } else {
760//console.log(" a.x == b.x");
761 lambda = f2m.add(aPointB.x(), f2m.multiply(aPointB.y(), f2m.inverse(aPointB.x())));
762//console.log(" lambda: " + lambda.asString(16));
763 x = f2m.add(this.a(), f2m.multiply(lambda, lambda));
764//console.log(" x (step 1): " + x.asString(16));
765 x = f2m.add(x, lambda);
766//console.log(" x (step 2): " + x.asString(16));
767 }
768
769 y = f2m.multiply(f2m.add(aPointB.x(), x), lambda);
770//console.log(" y (step 1): " + y.asString(16));
771 y = f2m.add(y, x);
772//console.log(" y (step 2): " + y.asString(16));
773 y = f2m.add(y, aPointB.y());
774//console.log(" y (step 3): " + y.asString(16));
775
776 result = new Clipperz.Crypto.ECC.BinaryField.Point({x:x, y:y})
777 }
778//console.log("<<< ECC.BinaryField.Curve.add");
779
780 return result;
781 },
782
783 //-----------------------------------------------------------------------------
784
785 'multiply': function(aValue, aPoint) {
786 var result;
787
788console.profile();
789 result = new Clipperz.Crypto.ECC.BinaryField.Point({x:Clipperz.Crypto.ECC.BinaryField.Value.O, y:Clipperz.Crypto.ECC.BinaryField.Value.O});
790
791 if (aValue.isZero() == false) {
792 var k, Q;
793 var i;
794 var countIndex; countIndex = 0;
795
796 if (aValue.compare(Clipperz.Crypto.ECC.BinaryField.WordArrayValue.O) > 0) {
797 k = aValue;
798 Q = aPoint;
799 } else {
800MochiKit.Logging.logError("The Clipperz.Crypto.ECC.BinaryFields.Value does not work with negative values!!!!");
801 k = aValue.negate();
802 Q = this.negate(aPoint);
803 }
804
805//console.log("k: " + k.toString(16));
806//console.log("k.bitSize: " + k.bitSize());
807 for (i=k.bitSize()-1; i>=0; i--) {
808 result = this.add(result, result);
809 if (k.isBitSet(i)) {
810 result = this.add(result, Q);
811 }
812
813 // if (countIndex==100) {console.log("multiply.break"); break;} else countIndex++;
814 }
815 }
816console.profileEnd();
817
818 return result;
819 },
820
821 //-----------------------------------------------------------------------------
822 __syntaxFix__: "syntax fix"
823});
824
825//#############################################################################
826
827//#############################################################################
828/ *
829Clipperz.Crypto.ECC.Key = function(args) {
830 args = args || {};
831
832 return this;
833}
834
835Clipperz.Crypto.ECC.Key.prototype = MochiKit.Base.update(null, {
836
837 'asString': function() {
838 return "Clipperz.Crypto.ECC.Key";
839 },
840
841 //-----------------------------------------------------------------------------
842 __syntaxFix__: "syntax fix"
843});
844* /
845//#############################################################################
846
847
848//#############################################################################
849
850Clipperz.Crypto.ECC.StandardCurves = {};
851
852MochiKit.Base.update(Clipperz.Crypto.ECC.StandardCurves, {
853/ *
854 '_K571': null,
855 'K571': function() {
856 if (Clipperz.Crypto.ECC.StandardCurves._K571 == null) {
857 Clipperz.Crypto.ECC.StandardCurves._K571 = new Clipperz.Crypto.ECC.Curve.Koblitz({
858 exadecimalForm: '80000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000425',
859 a: new Clipperz.Crypto.BigInt(0),
860 G: new Clipperz.Crypto.ECC.Point({
861 x: new Clipperz.Crypto.BigInt('26eb7a859923fbc82189631f8103fe4ac9ca2970012d5d46024804801841ca44370958493b205e647da304db4ceb08cbbd1ba39494776fb988b47174dca88c7e2945283a01c8972', 16),
862 y: new Clipperz.Crypto.BigInt('349dc807f4fbf374f4aeade3bca95314dd58cec9f307a54ffc61efc006d8a2c9d4979c0ac44aea74fbebbb9f772aedcb620b01a7ba7af1b320430c8591984f601cd4c143ef1c7a3', 16)
863 }),
864 n: new Clipperz.Crypto.BigInt('1932268761508629172347675945465993672149463664853217499328617625725759571144780212268133978522706711834706712800825351461273674974066617311929682421617092503555733685276673', 16),
865 h: new Clipperz.Crypto.BigInt(4)
866 });
867 }
868
869 return Clipperz.Crypto.ECC.StandardCurves._K571;
870 },
871* /
872 //-----------------------------------------------------------------------------
873
874 '_B571': null,
875 'B571': function() { //f(z) = z^571 + z^10 + z^5 + z^2 + 1
876 if (Clipperz.Crypto.ECC.StandardCurves._B571 == null) {
877 Clipperz.Crypto.ECC.StandardCurves._B571 = new Clipperz.Crypto.ECC.BinaryField.Curve({
878 modulus: new Clipperz.Crypto.ECC.BinaryField.Value('80000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000425', 16),
879 a: new Clipperz.Crypto.ECC.BinaryField.Value('1', 16),
880 b: new Clipperz.Crypto.ECC.BinaryField.Value('02f40e7e2221f295de297117b7f3d62f5c6a97ffcb8ceff1cd6ba8ce4a9a18ad84ffabbd8efa59332be7ad6756a66e294afd185a78ff12aa520e4de739baca0c7ffeff7f2955727a', 16),
881 G: new Clipperz.Crypto.ECC.BinaryField.Point({
882 x: new Clipperz.Crypto.ECC.BinaryField.Value('0303001d34b856296c16c0d40d3cd7750a93d1d2955fa80aa5f40fc8db7b2abdbde53950f4c0d293cdd711a35b67fb1499ae60038614f1394abfa3b4c850d927e1e7769c8eec2d19', 16),
883 y: new Clipperz.Crypto.ECC.BinaryField.Value('037bf27342da639b6dccfffeb73d69d78c6c27a6009cbbca1980f8533921e8a684423e43bab08a576291af8f461bb2a8b3531d2f0485c19b16e2f1516e23dd3c1a4827af1b8ac15b', 16)
884 }),
885 // r: new Clipperz.Crypto.ECC.BinaryField.Value('3864537523017258344695351890931987344298927329706434998657235251451519142289560424536143999389415773083133881121926944486246872462816813070234528288303332411393191105285703', 10),
886 r: new Clipperz.Crypto.ECC.BinaryField.Value('03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe661ce18ff55987308059b186823851ec7dd9ca1161de93d5174d66e8382e9bb2fe84e47', 16),
887 h: new Clipperz.Crypto.ECC.BinaryField.Value('2', 16)
888
889 // S: new Clipperz.Crypto.ECC.BinaryField.Value('2aa058f73a0e33ab486b0f610410c53a7f132310', 10),
890 // n: new Clipperz.Crypto.ECC.BinaryField.Value('03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe661ce18ff55987308059b186823851ec7dd9ca1161de93d5174d66e8382e9bb2fe84e47', 16),
891 });
892
893 //-----------------------------------------------------------------------------
894 //
895 //Guide to Elliptic Curve Cryptography
896 //Darrel Hankerson, Alfred Menezes, Scott Vanstone
897 //- Pag: 56, Alorithm 2.45 (with a typo!!!)
898 //
899 //-----------------------------------------------------------------------------
900 //
901 // http://www.milw0rm.com/papers/136
902 //
903 // -------------------------------------------------------------------------
904 // Polynomial Reduction Algorithm Modulo f571
905 // -------------------------------------------------------------------------
906 //
907 // Input: Polynomial p(x) of degree 1140 or less, stored as
908 // an array of 2T machinewords.
909 // Output: p(x) mod f571(x)
910 //
911 // FOR i = T-1, ..., 0 DO
912 // SET X := P[i+T]
913 // P[i] := P[i] ^ (X<<5) ^ (X<<7) ^ (X<<10) ^ (X<<15)
914 // P[i+1] := P[i+1] ^ (X>>17) ^ (X>>22) ^ (X>>25) ^ (X>>27)
915 //
916 // SET X := P[T-1] >> 27
917 // P[0] := P[0] ^ X ^ (X<<2) ^ (X<<5) ^ (X<<10)
918 // P[T-1] := P[T-1] & 0x07ffffff
919 //
920 // RETURN P[T-1],...,P[0]
921 //
922 // -------------------------------------------------------------------------
923 //
924 Clipperz.Crypto.ECC.StandardCurves._B571.finiteField().module = function(aValue) {
925 varresult;
926 varC, T;
927 var i;
928
929//console.log(">>> binaryField.finiteField.(improved)module");
930 // C = aValue.value().slice(0);
931 C = aValue._value.slice(0);
932 for (i=35; i>=18; i--) {
933 T = C[i];
934 C[i-18] = (((C[i-18] ^ (T<<5) ^ (T<<7) ^ (T<<10) ^ (T<<15)) & 0xffffffff) >>> 0);
935 C[i-17] = ((C[i-17] ^ (T>>>27) ^ (T>>>25) ^ (T>>>22) ^ (T>>>17)) >>> 0);
936 }
937 T = (C[17] >>> 27);
938 C[0] = ((C[0] ^ T ^ ((T<<2) ^ (T<<5) ^ (T<<10)) & 0xffffffff) >>> 0);
939 C[17] = (C[17] & 0x07ffffff);
940
941 for(i=18; i<=35; i++) {
942 C[i] = 0;
943 }
944
945 result = new Clipperz.Crypto.ECC.BinaryField.WordArrayValue(C);
946//console.log("<<< binaryField.finiteField.(improved)module");
947
948 return result;
949 };
950 }
951
952 return Clipperz.Crypto.ECC.StandardCurves._B571;
953 },
954
955 //-----------------------------------------------------------------------------
956 __syntaxFix__: "syntax fix"
957});
958
959//#############################################################################
960*/
diff --git a/frontend/beta/js/Clipperz/Crypto/ECC/BinaryField/Curve.js b/frontend/beta/js/Clipperz/Crypto/ECC/BinaryField/Curve.js
new file mode 100644
index 0000000..042ca6c
--- a/dev/null
+++ b/frontend/beta/js/Clipperz/Crypto/ECC/BinaryField/Curve.js
@@ -0,0 +1,461 @@
1/*
2
3Copyright 2008-2011 Clipperz Srl
4
5This file is part of Clipperz's Javascript Crypto Library.
6Javascript Crypto Library provides web developers with an extensive
7and efficient set of cryptographic functions. The library aims to
8obtain maximum execution speed while preserving modularity and
9reusability.
10For further information about its features and functionalities please
11refer to http://www.clipperz.com
12
13* Javascript Crypto Library is free software: you can redistribute
14 it and/or modify it under the terms of the GNU Affero General Public
15 License as published by the Free Software Foundation, either version
16 3 of the License, or (at your option) any later version.
17
18* Javascript Crypto Library is distributed in the hope that it will
19 be useful, but WITHOUT ANY WARRANTY; without even the implied
20 warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
21 See the GNU Affero General Public License for more details.
22
23* You should have received a copy of the GNU Affero General Public
24 License along with Javascript Crypto Library. If not, see
25 <http://www.gnu.org/licenses/>.
26
27*/
28
29try { if (typeof(Clipperz.ByteArray) == 'undefined') { throw ""; }} catch (e) {
30 throw "Clipperz.Crypto.ECC depends on Clipperz.ByteArray!";
31}
32if (typeof(Clipperz.Crypto.ECC) == 'undefined') { Clipperz.Crypto.ECC = {}; }
33if (typeof(Clipperz.Crypto.ECC.BinaryField) == 'undefined') { Clipperz.Crypto.ECC.BinaryField = {}; }
34
35Clipperz.Crypto.ECC.BinaryField.Curve = function(args) {
36 args = args || {};
37
38 this._modulus = args.modulus;
39
40 this._a = args.a;
41 this._b = args.b;
42 this._G = args.G;
43 this._r = args.r;
44 this._h = args.h;
45
46 this._finiteField = null;
47
48 return this;
49}
50
51Clipperz.Crypto.ECC.BinaryField.Curve.prototype = MochiKit.Base.update(null, {
52
53 'asString': function() {
54 return "Clipperz.Crypto.ECC.BinaryField.Curve";
55 },
56
57 //-----------------------------------------------------------------------------
58
59 'modulus': function() {
60 return this._modulus;
61 },
62
63 'a': function() {
64 return this._a;
65 },
66
67 'b': function() {
68 return this._b;
69 },
70
71 'G': function() {
72 return this._G;
73 },
74
75 'r': function() {
76 return this._r;
77 },
78
79 'h': function() {
80 return this._h;
81 },
82
83 //-----------------------------------------------------------------------------
84
85 'finiteField': function() {
86 if (this._finiteField == null) {
87 this._finiteField = new Clipperz.Crypto.ECC.BinaryField.FiniteField({modulus:this.modulus()})
88 }
89
90 return this._finiteField;
91 },
92
93 //-----------------------------------------------------------------------------
94
95 'negate': function(aPointA) {
96 var result;
97
98 result = new Clipperz.Crypto.ECC.Point({x:aPointA.x(), y:this.finiteField().add(aPointA.y(), aPointA.x())})
99
100 return result;
101 },
102
103 //-----------------------------------------------------------------------------
104
105 'add': function(aPointA, aPointB) {
106 var result;
107
108//console.log(">>> ECC.BinaryField.Curve.add");
109 if (aPointA.isZero()) {
110//console.log("--- pointA == zero");
111 result = aPointB;
112 } else if (aPointB.isZero()) {
113//console.log("--- pointB == zero");
114 result = aPointA;
115 } else if ((aPointA.x().compare(aPointB.x()) == 0) && ((aPointA.y().compare(aPointB.y()) != 0) || aPointB.x().isZero())) {
116//console.log("compare A.x - B.x: ", aPointA.x().compare(aPointB.x()));
117//console.log("compare A.y - B.y: ", (aPointA.y().compare(aPointB.y()) != 0));
118//console.log("compare B.x.isZero(): ", aPointB.x().isZero());
119
120//console.log("--- result = zero");
121 result = new Clipperz.Crypto.ECC.BinaryField.Point({x:Clipperz.Crypto.ECC.BinaryField.Value.O, y:Clipperz.Crypto.ECC.BinaryField.Value.O});
122 } else {
123//console.log("--- result = ELSE");
124 varf2m;
125 var x, y;
126 var lambda;
127 var aX, aY, bX, bY;
128
129 aX = aPointA.x()._value;
130 aY = aPointA.y()._value;
131 bX = aPointB.x()._value;
132 bY = aPointB.y()._value;
133
134 f2m = this.finiteField();
135
136 if (aPointA.x().compare(aPointB.x()) != 0) {
137//console.log(" a.x != b.x");
138 lambda =f2m._fastMultiply(
139 f2m._add(aY, bY),
140 f2m._inverse(f2m._add(aX, bX))
141 );
142 x = f2m._add(this.a()._value, f2m._square(lambda));
143 f2m._overwriteAdd(x, lambda);
144 f2m._overwriteAdd(x, aX);
145 f2m._overwriteAdd(x, bX);
146 } else {
147//console.log(" a.x == b.x");
148 lambda = f2m._add(bX, f2m._fastMultiply(bY, f2m._inverse(bX)));
149//console.log(" lambda: " + lambda.asString(16));
150 x = f2m._add(this.a()._value, f2m._square(lambda));
151//console.log(" x (step 1): " + x.asString(16));
152 f2m._overwriteAdd(x, lambda);
153//console.log(" x (step 2): " + x.asString(16));
154 }
155
156 y = f2m._fastMultiply(f2m._add(bX, x), lambda);
157//console.log(" y (step 1): " + y.asString(16));
158 f2m._overwriteAdd(y, x);
159//console.log(" y (step 2): " + y.asString(16));
160 f2m._overwriteAdd(y, bY);
161//console.log(" y (step 3): " + y.asString(16));
162
163 result = new Clipperz.Crypto.ECC.BinaryField.Point({x:new Clipperz.Crypto.ECC.BinaryField.Value(x), y:new Clipperz.Crypto.ECC.BinaryField.Value(y)})
164 }
165//console.log("<<< ECC.BinaryField.Curve.add");
166
167 return result;
168 },
169
170 //-----------------------------------------------------------------------------
171
172 'overwriteAdd': function(aPointA, aPointB) {
173 if (aPointA.isZero()) {
174 // result = aPointB;
175 aPointA._x._value = aPointB._x._value;
176 aPointA._y._value = aPointB._y._value;
177 } else if (aPointB.isZero()) {
178 // result = aPointA;
179 } else if ((aPointA.x().compare(aPointB.x()) == 0) && ((aPointA.y().compare(aPointB.y()) != 0) || aPointB.x().isZero())) {
180 // result = new Clipperz.Crypto.ECC.BinaryField.Point({x:Clipperz.Crypto.ECC.BinaryField.Value.O, y:Clipperz.Crypto.ECC.BinaryField.Value.O});
181 aPointA._x = Clipperz.Crypto.ECC.BinaryField.Value.O;
182 aPointA._y = Clipperz.Crypto.ECC.BinaryField.Value.O;
183 } else {
184 varf2m;
185 var x, y;
186 var lambda;
187 var aX, aY, bX, bY;
188
189 aX = aPointA.x()._value;
190 aY = aPointA.y()._value;
191 bX = aPointB.x()._value;
192 bY = aPointB.y()._value;
193
194 f2m = this.finiteField();
195
196 if (aPointA.x().compare(aPointB.x()) != 0) {
197//console.log(" a.x != b.x");
198 lambda =f2m._fastMultiply(
199 f2m._add(aY, bY),
200 f2m._inverse(f2m._add(aX, bX))
201 );
202 x = f2m._add(this.a()._value, f2m._square(lambda));
203 f2m._overwriteAdd(x, lambda);
204 f2m._overwriteAdd(x, aX);
205 f2m._overwriteAdd(x, bX);
206 } else {
207//console.log(" a.x == b.x");
208 lambda = f2m._add(bX, f2m._fastMultiply(bY, f2m._inverse(bX)));
209//console.log(" lambda: " + lambda.asString(16));
210 x = f2m._add(this.a()._value, f2m._square(lambda));
211//console.log(" x (step 1): " + x.asString(16));
212 f2m._overwriteAdd(x, lambda);
213//console.log(" x (step 2): " + x.asString(16));
214 }
215
216 y = f2m._fastMultiply(f2m._add(bX, x), lambda);
217//console.log(" y (step 1): " + y.asString(16));
218 f2m._overwriteAdd(y, x);
219//console.log(" y (step 2): " + y.asString(16));
220 f2m._overwriteAdd(y, bY);
221//console.log(" y (step 3): " + y.asString(16));
222
223 // result = new Clipperz.Crypto.ECC.BinaryField.Point({x:new Clipperz.Crypto.ECC.BinaryField.Value(x), y:new Clipperz.Crypto.ECC.BinaryField.Value(y)})
224 aPointA._x._value = x;
225 aPointA._y._value = y;
226
227 }
228//console.log("<<< ECC.BinaryField.Curve.add");
229
230 return result;
231 },
232
233 //-----------------------------------------------------------------------------
234
235 'multiply': function(aValue, aPoint) {
236 var result;
237
238//console.profile();
239 result = new Clipperz.Crypto.ECC.BinaryField.Point({x:Clipperz.Crypto.ECC.BinaryField.Value.O, y:Clipperz.Crypto.ECC.BinaryField.Value.O});
240
241 if (aValue.isZero() == false) {
242 var k, Q;
243 var i;
244 var countIndex; countIndex = 0;
245
246 if (aValue.compare(Clipperz.Crypto.ECC.BinaryField.Value.O) > 0) {
247 k = aValue;
248 Q = aPoint;
249 } else {
250MochiKit.Logging.logError("The Clipperz.Crypto.ECC.BinaryFields.Value does not work with negative values!!!!");
251 k = aValue.negate();
252 Q = this.negate(aPoint);
253 }
254
255//console.log("k: " + k.toString(16));
256//console.log("k.bitSize: " + k.bitSize());
257 for (i=k.bitSize()-1; i>=0; i--) {
258 result = this.add(result, result);
259 // this.overwriteAdd(result, result);
260 if (k.isBitSet(i)) {
261 result = this.add(result, Q);
262 // this.overwriteAdd(result, Q);
263 }
264
265 // if (countIndex==100) {console.log("multiply.break"); break;} else countIndex++;
266 }
267 }
268//console.profileEnd();
269
270 return result;
271 },
272
273 //-----------------------------------------------------------------------------
274 __syntaxFix__: "syntax fix"
275});
276
277
278//#############################################################################
279
280Clipperz.Crypto.ECC.StandardCurves = {};
281
282MochiKit.Base.update(Clipperz.Crypto.ECC.StandardCurves, {
283/*
284 '_K571': null,
285 'K571': function() {
286 if (Clipperz.Crypto.ECC.StandardCurves._K571 == null) {
287 Clipperz.Crypto.ECC.StandardCurves._K571 = new Clipperz.Crypto.ECC.Curve.Koblitz({
288 exadecimalForm: '80000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000425',
289 a: new Clipperz.Crypto.BigInt(0),
290 G: new Clipperz.Crypto.ECC.Point({
291 x: new Clipperz.Crypto.BigInt('26eb7a859923fbc82189631f8103fe4ac9ca2970012d5d46024804801841ca44370958493b205e647da304db4ceb08cbbd1ba39494776fb988b47174dca88c7e2945283a01c8972', 16),
292 y: new Clipperz.Crypto.BigInt('349dc807f4fbf374f4aeade3bca95314dd58cec9f307a54ffc61efc006d8a2c9d4979c0ac44aea74fbebbb9f772aedcb620b01a7ba7af1b320430c8591984f601cd4c143ef1c7a3', 16)
293 }),
294 n: new Clipperz.Crypto.BigInt('1932268761508629172347675945465993672149463664853217499328617625725759571144780212268133978522706711834706712800825351461273674974066617311929682421617092503555733685276673', 16),
295 h: new Clipperz.Crypto.BigInt(4)
296 });
297 }
298
299 return Clipperz.Crypto.ECC.StandardCurves._K571;
300 },
301*/
302 //-----------------------------------------------------------------------------
303
304 '_B571': null,
305 'B571': function() { //f(z) = z^571 + z^10 + z^5 + z^2 + 1
306 if (Clipperz.Crypto.ECC.StandardCurves._B571 == null) {
307 Clipperz.Crypto.ECC.StandardCurves._B571 = new Clipperz.Crypto.ECC.BinaryField.Curve({
308 modulus: new Clipperz.Crypto.ECC.BinaryField.Value('80000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000425', 16),
309 a: new Clipperz.Crypto.ECC.BinaryField.Value('1', 16),
310 b: new Clipperz.Crypto.ECC.BinaryField.Value('02f40e7e2221f295de297117b7f3d62f5c6a97ffcb8ceff1cd6ba8ce4a9a18ad84ffabbd8efa59332be7ad6756a66e294afd185a78ff12aa520e4de739baca0c7ffeff7f2955727a', 16),
311 G: new Clipperz.Crypto.ECC.BinaryField.Point({
312 x: new Clipperz.Crypto.ECC.BinaryField.Value('0303001d 34b85629 6c16c0d4 0d3cd775 0a93d1d2 955fa80a a5f40fc8 db7b2abd bde53950 f4c0d293 cdd711a3 5b67fb14 99ae6003 8614f139 4abfa3b4 c850d927 e1e7769c 8eec2d19', 16),
313 y: new Clipperz.Crypto.ECC.BinaryField.Value('037bf273 42da639b 6dccfffe b73d69d7 8c6c27a6 009cbbca 1980f853 3921e8a6 84423e43 bab08a57 6291af8f 461bb2a8 b3531d2f 0485c19b 16e2f151 6e23dd3c 1a4827af 1b8ac15b', 16)
314 }),
315 r: new Clipperz.Crypto.ECC.BinaryField.Value('03ffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff e661ce18 ff559873 08059b18 6823851e c7dd9ca1 161de93d 5174d66e 8382e9bb 2fe84e47', 16),
316 h: new Clipperz.Crypto.ECC.BinaryField.Value('2', 16)
317
318 // S: new Clipperz.Crypto.ECC.BinaryField.Value('2aa058f73a0e33ab486b0f610410c53a7f132310', 10),
319 // n: new Clipperz.Crypto.ECC.BinaryField.Value('03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe661ce18ff55987308059b186823851ec7dd9ca1161de93d5174d66e8382e9bb2fe84e47', 16),
320 });
321
322 //-----------------------------------------------------------------------------
323 //
324 //Guide to Elliptic Curve Cryptography
325 //Darrel Hankerson, Alfred Menezes, Scott Vanstone
326 //- Pag: 56, Alorithm 2.45 (with a typo!!!)
327 //
328 //-----------------------------------------------------------------------------
329 //
330 // http://www.milw0rm.com/papers/136
331 //
332 // -------------------------------------------------------------------------
333 // Polynomial Reduction Algorithm Modulo f571
334 // -------------------------------------------------------------------------
335 //
336 // Input: Polynomial p(x) of degree 1140 or less, stored as
337 // an array of 2T machinewords.
338 // Output: p(x) mod f571(x)
339 //
340 // FOR i = T-1, ..., 0 DO
341 // SET X := P[i+T]
342 // P[i] := P[i] ^ (X<<5) ^ (X<<7) ^ (X<<10) ^ (X<<15)
343 // P[i+1] := P[i+1] ^ (X>>17) ^ (X>>22) ^ (X>>25) ^ (X>>27)
344 //
345 // SET X := P[T-1] >> 27
346 // P[0] := P[0] ^ X ^ (X<<2) ^ (X<<5) ^ (X<<10)
347 // P[T-1] := P[T-1] & 0x07ffffff
348 //
349 // RETURN P[T-1],...,P[0]
350 //
351 // -------------------------------------------------------------------------
352 //
353 Clipperz.Crypto.ECC.StandardCurves._B571.finiteField().slowModule = Clipperz.Crypto.ECC.StandardCurves._B571.finiteField().module;
354 Clipperz.Crypto.ECC.StandardCurves._B571.finiteField().module = function(aValue) {
355 varresult;
356
357 if (aValue.bitSize() > 1140) {
358 MochiKit.Logging.logWarning("ECC.StandarCurves.B571.finiteField().module: falling back to default implementation");
359 result = Clipperz.Crypto.ECC.StandardCurves._B571.finiteField().slowModule(aValue);
360 } else {
361 varC, T;
362 var i;
363
364//console.log(">>> binaryField.finiteField.(improved)module");
365 // C = aValue.value().slice(0);
366 C = aValue._value.slice(0);
367 for (i=35; i>=18; i--) {
368 T = C[i];
369 C[i-18] = (((C[i-18] ^ (T<<5) ^ (T<<7) ^ (T<<10) ^ (T<<15)) & 0xffffffff) >>> 0);
370 C[i-17] = ((C[i-17] ^ (T>>>27) ^ (T>>>25) ^ (T>>>22) ^ (T>>>17)) >>> 0);
371 }
372 T = (C[17] >>> 27);
373 C[0] = ((C[0] ^ T ^ ((T<<2) ^ (T<<5) ^ (T<<10)) & 0xffffffff) >>> 0);
374 C[17] = (C[17] & 0x07ffffff);
375
376 for(i=18; i<=35; i++) {
377 C[i] = 0;
378 }
379
380 result = new Clipperz.Crypto.ECC.BinaryField.Value(C);
381//console.log("<<< binaryField.finiteField.(improved)module");
382 }
383
384 return result;
385 };
386 }
387
388 return Clipperz.Crypto.ECC.StandardCurves._B571;
389 },
390
391 //-----------------------------------------------------------------------------
392
393 '_B283': null,
394 'B283': function() { //f(z) = z^283 + z^12 + z^7 + z^5 + 1
395 if (Clipperz.Crypto.ECC.StandardCurves._B283 == null) {
396 Clipperz.Crypto.ECC.StandardCurves._B283 = new Clipperz.Crypto.ECC.BinaryField.Curve({
397 // modulus: new Clipperz.Crypto.ECC.BinaryField.Value('10000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 000010a1', 16),
398 modulus: new Clipperz.Crypto.ECC.BinaryField.Value('08000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 000010a1', 16),
399 a: new Clipperz.Crypto.ECC.BinaryField.Value('1', 16),
400 b: new Clipperz.Crypto.ECC.BinaryField.Value('027b680a c8b8596d a5a4af8a 19a0303f ca97fd76 45309fa2 a581485a f6263e31 3b79a2f5', 16),
401 G: new Clipperz.Crypto.ECC.BinaryField.Point({
402 x: new Clipperz.Crypto.ECC.BinaryField.Value('05f93925 8db7dd90 e1934f8c 70b0dfec 2eed25b8 557eac9c 80e2e198 f8cdbecd 86b12053', 16),
403 y: new Clipperz.Crypto.ECC.BinaryField.Value('03676854 fe24141c b98fe6d4 b20d02b4 516ff702 350eddb0 826779c8 13f0df45 be8112f4', 16)
404 }),
405 r: new Clipperz.Crypto.ECC.BinaryField.Value('03ffffff ffffffff ffffffff ffffffff ffffef90 399660fc 938a9016 5b042a7c efadb307', 16),
406 h: new Clipperz.Crypto.ECC.BinaryField.Value('2', 16)
407
408 // S: new Clipperz.Crypto.ECC.BinaryField.Value('2aa058f73a0e33ab486b0f610410c53a7f132310', 10),
409 // n: new Clipperz.Crypto.ECC.BinaryField.Value('03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe661ce18ff55987308059b186823851ec7dd9ca1161de93d5174d66e8382e9bb2fe84e47', 16),
410 });
411
412 //-----------------------------------------------------------------------------
413 //
414 //Guide to Elliptic Curve Cryptography
415 //Darrel Hankerson, Alfred Menezes, Scott Vanstone
416 //- Pag: 56, Alorithm 2.43
417 //
418 //-----------------------------------------------------------------------------
419 Clipperz.Crypto.ECC.StandardCurves._B283.finiteField().slowModule = Clipperz.Crypto.ECC.StandardCurves._B283.finiteField().module;
420 Clipperz.Crypto.ECC.StandardCurves._B283.finiteField().module = function(aValue) {
421 varresult;
422
423 if (aValue.bitSize() > 564) {
424 MochiKit.Logging.logWarning("ECC.StandarCurves.B283.finiteField().module: falling back to default implementation");
425 result = Clipperz.Crypto.ECC.StandardCurves._B283.finiteField().slowModule(aValue);
426 } else {
427 varC, T;
428 var i;
429
430//console.log(">>> binaryField.finiteField.(improved)module");
431 C = aValue._value.slice(0);
432 for (i=17; i>=9; i--) {
433 T = C[i];
434 C[i-9] = (((C[i-9] ^ (T<<5) ^ (T<<10) ^ (T<<12) ^ (T<<17)) & 0xffffffff) >>> 0);
435 C[i-8] = ((C[i-8] ^ (T>>>27) ^ (T>>>22) ^ (T>>>20) ^ (T>>>15)) >>> 0);
436 }
437 T = (C[8] >>> 27);
438 C[0] = ((C[0] ^ T ^ ((T<<5) ^ (T<<7) ^ (T<<12)) & 0xffffffff) >>> 0);
439 C[8] = (C[8] & 0x07ffffff);
440
441 for(i=9; i<=17; i++) {
442 C[i] = 0;
443 }
444
445 result = new Clipperz.Crypto.ECC.BinaryField.Value(C);
446//console.log("<<< binaryField.finiteField.(improved)module");
447 }
448
449 return result;
450 };
451 }
452
453 return Clipperz.Crypto.ECC.StandardCurves._B283;
454 },
455
456 //-----------------------------------------------------------------------------
457 __syntaxFix__: "syntax fix"
458});
459
460//#############################################################################
461
diff --git a/frontend/beta/js/Clipperz/Crypto/ECC/BinaryField/FiniteField.js b/frontend/beta/js/Clipperz/Crypto/ECC/BinaryField/FiniteField.js
new file mode 100644
index 0000000..3ddf2ec
--- a/dev/null
+++ b/frontend/beta/js/Clipperz/Crypto/ECC/BinaryField/FiniteField.js
@@ -0,0 +1,526 @@
1/*
2
3Copyright 2008-2011 Clipperz Srl
4
5This file is part of Clipperz's Javascript Crypto Library.
6Javascript Crypto Library provides web developers with an extensive
7and efficient set of cryptographic functions. The library aims to
8obtain maximum execution speed while preserving modularity and
9reusability.
10For further information about its features and functionalities please
11refer to http://www.clipperz.com
12
13* Javascript Crypto Library is free software: you can redistribute
14 it and/or modify it under the terms of the GNU Affero General Public
15 License as published by the Free Software Foundation, either version
16 3 of the License, or (at your option) any later version.
17
18* Javascript Crypto Library is distributed in the hope that it will
19 be useful, but WITHOUT ANY WARRANTY; without even the implied
20 warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
21 See the GNU Affero General Public License for more details.
22
23* You should have received a copy of the GNU Affero General Public
24 License along with Javascript Crypto Library. If not, see
25 <http://www.gnu.org/licenses/>.
26
27*/
28
29try { if (typeof(Clipperz.ByteArray) == 'undefined') { throw ""; }} catch (e) {
30 throw "Clipperz.Crypto.ECC depends on Clipperz.ByteArray!";
31}
32if (typeof(Clipperz.Crypto.ECC) == 'undefined') { Clipperz.Crypto.ECC = {}; }
33if (typeof(Clipperz.Crypto.ECC.BinaryField) == 'undefined') { Clipperz.Crypto.ECC.BinaryField = {}; }
34
35Clipperz.Crypto.ECC.BinaryField.FiniteField = function(args) {
36 args = args || {};
37 this._modulus = args.modulus;
38
39 return this;
40}
41
42Clipperz.Crypto.ECC.BinaryField.FiniteField.prototype = MochiKit.Base.update(null, {
43
44 'asString': function() {
45 return "Clipperz.Crypto.ECC.BinaryField.FiniteField (" + this.modulus().asString() + ")";
46 },
47
48 //-----------------------------------------------------------------------------
49
50 'modulus': function() {
51 return this._modulus;
52 },
53
54 //-----------------------------------------------------------------------------
55
56 '_module': function(aValue) {
57 varresult;
58 var modulusComparison;
59//console.log(">>> binaryField.finiteField.(standard)module");
60
61 modulusComparison = Clipperz.Crypto.ECC.BinaryField.Value._compare(aValue, this.modulus()._value);
62
63 if (modulusComparison < 0) {
64 result = aValue;
65 } else if (modulusComparison == 0) {
66 result = [0];
67 } else {
68 var modulusBitSize;
69 var resultBitSize;
70
71 result = aValue;
72
73 modulusBitSize = this.modulus().bitSize();
74 resultBitSize = Clipperz.Crypto.ECC.BinaryField.Value._bitSize(result);
75 while (resultBitSize >= modulusBitSize) {
76 Clipperz.Crypto.ECC.BinaryField.Value._overwriteXor(result, Clipperz.Crypto.ECC.BinaryField.Value._shiftLeft(this.modulus()._value, resultBitSize - modulusBitSize));
77 resultBitSize = Clipperz.Crypto.ECC.BinaryField.Value._bitSize(result);
78 }
79 }
80//console.log("<<< binaryField.finiteField.(standard)module");
81
82 return result;
83 },
84
85 'module': function(aValue) {
86 return new Clipperz.Crypto.ECC.BinaryField.Value(this._module(aValue._value.slice(0)));
87 },
88
89 //-----------------------------------------------------------------------------
90
91 '_add': function(a, b) {
92 return Clipperz.Crypto.ECC.BinaryField.Value._xor(a, b);
93 },
94
95 '_overwriteAdd': function(a, b) {
96 Clipperz.Crypto.ECC.BinaryField.Value._overwriteXor(a, b);
97 },
98
99 'add': function(a, b) {
100 return new Clipperz.Crypto.ECC.BinaryField.Value(this._add(a._value, b._value));
101 },
102
103 //-----------------------------------------------------------------------------
104
105 'negate': function(aValue) {
106 return aValue.clone();
107 },
108
109 //-----------------------------------------------------------------------------
110
111 '_multiply': function(a, b) {
112 var result;
113 var valueToXor;
114 var i,c;
115
116 result = [0];
117 valueToXor = b;
118 c = Clipperz.Crypto.ECC.BinaryField.Value._bitSize(a);
119 for (i=0; i<c; i++) {
120 if (Clipperz.Crypto.ECC.BinaryField.Value._isBitSet(a, i) === true) {
121 Clipperz.Crypto.ECC.BinaryField.Value._overwriteXor(result, valueToXor);
122 }
123 valueToXor = Clipperz.Crypto.ECC.BinaryField.Value._overwriteShiftLeft(valueToXor, 1);
124 }
125 result = this._module(result);
126
127 return result;
128 },
129
130 'multiply': function(a, b) {
131 return new Clipperz.Crypto.ECC.BinaryField.Value(this._multiply(a._value, b._value));
132 },
133
134 //-----------------------------------------------------------------------------
135
136 '_fastMultiply': function(a, b) {
137 var result;
138 var B;
139 var i,c;
140
141 result = [0];
142 B = b.slice(0); //Is this array copy avoidable?
143 c = 32;
144 for (i=0; i<c; i++) {
145 var ii, cc;
146
147 cc = a.length;
148 for (ii=0; ii<cc; ii++) {
149 if (((a[ii] >>> i) & 0x01) == 1) {
150 Clipperz.Crypto.ECC.BinaryField.Value._overwriteXor(result, B, ii);
151 }
152 }
153
154 if (i < (c-1)) {
155 B = Clipperz.Crypto.ECC.BinaryField.Value._overwriteShiftLeft(B, 1);
156 }
157 }
158 result = this._module(result);
159
160 return result;
161 },
162
163 'fastMultiply': function(a, b) {
164 return new Clipperz.Crypto.ECC.BinaryField.Value(this._fastMultiply(a._value, b._value));
165 },
166
167 //-----------------------------------------------------------------------------
168 //
169 //Guide to Elliptic Curve Cryptography
170 //Darrel Hankerson, Alfred Menezes, Scott Vanstone
171 //- Pag: 49, Alorithm 2.34
172 //
173 //-----------------------------------------------------------------------------
174
175 '_square': function(aValue) {
176 var result;
177 var value;
178 var c,i;
179 var precomputedValues;
180
181 value = aValue;
182 result = new Array(value.length * 2);
183 precomputedValues = Clipperz.Crypto.ECC.BinaryField.FiniteField.squarePrecomputedBytes;
184
185 c = value.length;
186 for (i=0; i<c; i++) {
187 result[i*2] = precomputedValues[(value[i] & 0x000000ff)];
188 result[i*2] |= ((precomputedValues[(value[i] & 0x0000ff00) >>> 8]) << 16);
189
190 result[i*2 + 1] = precomputedValues[(value[i] & 0x00ff0000) >>> 16];
191 result[i*2 + 1] |= ((precomputedValues[(value[i] & 0xff000000) >>> 24]) << 16);
192 }
193
194 return this._module(result);
195 },
196
197 'square': function(aValue) {
198 return new Clipperz.Crypto.ECC.BinaryField.Value(this._square(aValue._value));
199 },
200
201 //-----------------------------------------------------------------------------
202
203 '_inverse': function(aValue) {
204 varresult;
205 var b, c;
206 var u, v;
207
208 // b = Clipperz.Crypto.ECC.BinaryField.Value.I._value;
209 b = [1];
210 // c = Clipperz.Crypto.ECC.BinaryField.Value.O._value;
211 c = [0];
212 u = this._module(aValue);
213 v = this.modulus()._value.slice(0);
214
215 while (Clipperz.Crypto.ECC.BinaryField.Value._bitSize(u) > 1) {
216 varbitDifferenceSize;
217
218 bitDifferenceSize = Clipperz.Crypto.ECC.BinaryField.Value._bitSize(u) - Clipperz.Crypto.ECC.BinaryField.Value._bitSize(v);
219 if (bitDifferenceSize < 0) {
220 var swap;
221
222 swap = u;
223 u = v;
224 v = swap;
225
226 swap = c;
227 c = b;
228 b = swap;
229
230 bitDifferenceSize = -bitDifferenceSize;
231 }
232
233 u = this._add(u, Clipperz.Crypto.ECC.BinaryField.Value._shiftLeft(v, bitDifferenceSize));
234 b = this._add(b, Clipperz.Crypto.ECC.BinaryField.Value._shiftLeft(c, bitDifferenceSize));
235 // this._overwriteAdd(u, Clipperz.Crypto.ECC.BinaryField.Value._shiftLeft(v, bitDifferenceSize));
236 // this._overwriteAdd(b, Clipperz.Crypto.ECC.BinaryField.Value._shiftLeft(c, bitDifferenceSize));
237 }
238
239 result = this._module(b);
240
241 return result;
242 },
243
244 'inverse': function(aValue) {
245 return new Clipperz.Crypto.ECC.BinaryField.Value(this._inverse(aValue._value));
246 },
247
248 //-----------------------------------------------------------------------------
249 __syntaxFix__: "syntax fix"
250});
251
252
253Clipperz.Crypto.ECC.BinaryField.FiniteField.squarePrecomputedBytes = [
254 0x0000, // 0 = 0000 0000 -> 0000 0000 0000 0000
255 0x0001, // 1 = 0000 0001 -> 0000 0000 0000 0001
256 0x0004, // 2 = 0000 0010 -> 0000 0000 0000 0100
257 0x0005, // 3 = 0000 0011 -> 0000 0000 0000 0101
258 0x0010, // 4 = 0000 0100 -> 0000 0000 0001 0000
259 0x0011, // 5 = 0000 0101 -> 0000 0000 0001 0001
260 0x0014, // 6 = 0000 0110 -> 0000 0000 0001 0100
261 0x0015, // 7 = 0000 0111 -> 0000 0000 0001 0101
262 0x0040, // 8 = 0000 1000 -> 0000 0000 0100 0000
263 0x0041, // 9 = 0000 1001 -> 0000 0000 0100 0001
264 0x0044, // 10 = 0000 1010 -> 0000 0000 0100 0100
265 0x0045, // 11 = 0000 1011 -> 0000 0000 0100 0101
266 0x0050, // 12 = 0000 1100 -> 0000 0000 0101 0000
267 0x0051, // 13 = 0000 1101 -> 0000 0000 0101 0001
268 0x0054, // 14 = 0000 1110 -> 0000 0000 0101 0100
269 0x0055, // 15 = 0000 1111 -> 0000 0000 0101 0101
270
271 0x0100, // 16 = 0001 0000 -> 0000 0001 0000 0000
272 0x0101, // 17 = 0001 0001 -> 0000 0001 0000 0001
273 0x0104, // 18 = 0001 0010 -> 0000 0001 0000 0100
274 0x0105, // 19 = 0001 0011 -> 0000 0001 0000 0101
275 0x0110, // 20 = 0001 0100 -> 0000 0001 0001 0000
276 0x0111, // 21 = 0001 0101 -> 0000 0001 0001 0001
277 0x0114, // 22 = 0001 0110 -> 0000 0001 0001 0100
278 0x0115, // 23 = 0001 0111 -> 0000 0001 0001 0101
279 0x0140, // 24 = 0001 1000 -> 0000 0001 0100 0000
280 0x0141, // 25 = 0001 1001 -> 0000 0001 0100 0001
281 0x0144, // 26 = 0001 1010 -> 0000 0001 0100 0100
282 0x0145, // 27 = 0001 1011 -> 0000 0001 0100 0101
283 0x0150, // 28 = 0001 1100 -> 0000 0001 0101 0000
284 0x0151, // 28 = 0001 1101 -> 0000 0001 0101 0001
285 0x0154, // 30 = 0001 1110 -> 0000 0001 0101 0100
286 0x0155, // 31 = 0001 1111 -> 0000 0001 0101 0101
287
288 0x0400, // 32 = 0010 0000 -> 0000 0100 0000 0000
289 0x0401, // 33 = 0010 0001 -> 0000 0100 0000 0001
290 0x0404, // 34 = 0010 0010 -> 0000 0100 0000 0100
291 0x0405, // 35 = 0010 0011 -> 0000 0100 0000 0101
292 0x0410, // 36 = 0010 0100 -> 0000 0100 0001 0000
293 0x0411, // 37 = 0010 0101 -> 0000 0100 0001 0001
294 0x0414, // 38 = 0010 0110 -> 0000 0100 0001 0100
295 0x0415, // 39 = 0010 0111 -> 0000 0100 0001 0101
296 0x0440, // 40 = 0010 1000 -> 0000 0100 0100 0000
297 0x0441, // 41 = 0010 1001 -> 0000 0100 0100 0001
298 0x0444, // 42 = 0010 1010 -> 0000 0100 0100 0100
299 0x0445, // 43 = 0010 1011 -> 0000 0100 0100 0101
300 0x0450, // 44 = 0010 1100 -> 0000 0100 0101 0000
301 0x0451, // 45 = 0010 1101 -> 0000 0100 0101 0001
302 0x0454, // 46 = 0010 1110 -> 0000 0100 0101 0100
303 0x0455, // 47 = 0010 1111 -> 0000 0100 0101 0101
304
305 0x0500, // 48 = 0011 0000 -> 0000 0101 0000 0000
306 0x0501, // 49 = 0011 0001 -> 0000 0101 0000 0001
307 0x0504, // 50 = 0011 0010 -> 0000 0101 0000 0100
308 0x0505, // 51 = 0011 0011 -> 0000 0101 0000 0101
309 0x0510, // 52 = 0011 0100 -> 0000 0101 0001 0000
310 0x0511, // 53 = 0011 0101 -> 0000 0101 0001 0001
311 0x0514, // 54 = 0011 0110 -> 0000 0101 0001 0100
312 0x0515, // 55 = 0011 0111 -> 0000 0101 0001 0101
313 0x0540, // 56 = 0011 1000 -> 0000 0101 0100 0000
314 0x0541, // 57 = 0011 1001 -> 0000 0101 0100 0001
315 0x0544, // 58 = 0011 1010 -> 0000 0101 0100 0100
316 0x0545, // 59 = 0011 1011 -> 0000 0101 0100 0101
317 0x0550, // 60 = 0011 1100 -> 0000 0101 0101 0000
318 0x0551, // 61 = 0011 1101 -> 0000 0101 0101 0001
319 0x0554, // 62 = 0011 1110 -> 0000 0101 0101 0100
320 0x0555, // 63 = 0011 1111 -> 0000 0101 0101 0101
321
322 0x1000, // 64 = 0100 0000 -> 0001 0000 0000 0000
323 0x1001, // 65 = 0100 0001 -> 0001 0000 0000 0001
324 0x1004, // 66 = 0100 0010 -> 0001 0000 0000 0100
325 0x1005, // 67 = 0100 0011 -> 0001 0000 0000 0101
326 0x1010, // 68 = 0100 0100 -> 0001 0000 0001 0000
327 0x1011, // 69 = 0100 0101 -> 0001 0000 0001 0001
328 0x1014, // 70 = 0100 0110 -> 0001 0000 0001 0100
329 0x1015, // 71 = 0100 0111 -> 0001 0000 0001 0101
330 0x1040, // 72 = 0100 1000 -> 0001 0000 0100 0000
331 0x1041, // 73 = 0100 1001 -> 0001 0000 0100 0001
332 0x1044, // 74 = 0100 1010 -> 0001 0000 0100 0100
333 0x1045, // 75 = 0100 1011 -> 0001 0000 0100 0101
334 0x1050, // 76 = 0100 1100 -> 0001 0000 0101 0000
335 0x1051, // 77 = 0100 1101 -> 0001 0000 0101 0001
336 0x1054, // 78 = 0100 1110 -> 0001 0000 0101 0100
337 0x1055, // 79 = 0100 1111 -> 0001 0000 0101 0101
338
339 0x1100, // 80 = 0101 0000 -> 0001 0001 0000 0000
340 0x1101, // 81 = 0101 0001 -> 0001 0001 0000 0001
341 0x1104, // 82 = 0101 0010 -> 0001 0001 0000 0100
342 0x1105, // 83 = 0101 0011 -> 0001 0001 0000 0101
343 0x1110, // 84 = 0101 0100 -> 0001 0001 0001 0000
344 0x1111, // 85 = 0101 0101 -> 0001 0001 0001 0001
345 0x1114, // 86 = 0101 0110 -> 0001 0001 0001 0100
346 0x1115, // 87 = 0101 0111 -> 0001 0001 0001 0101
347 0x1140, // 88 = 0101 1000 -> 0001 0001 0100 0000
348 0x1141, // 89 = 0101 1001 -> 0001 0001 0100 0001
349 0x1144, // 90 = 0101 1010 -> 0001 0001 0100 0100
350 0x1145, // 91 = 0101 1011 -> 0001 0001 0100 0101
351 0x1150, // 92 = 0101 1100 -> 0001 0001 0101 0000
352 0x1151, // 93 = 0101 1101 -> 0001 0001 0101 0001
353 0x1154, // 94 = 0101 1110 -> 0001 0001 0101 0100
354 0x1155, // 95 = 0101 1111 -> 0001 0001 0101 0101
355
356 0x1400, // 96 = 0110 0000 -> 0001 0100 0000 0000
357 0x1401, // 97 = 0110 0001 -> 0001 0100 0000 0001
358 0x1404, // 98 = 0110 0010 -> 0001 0100 0000 0100
359 0x1405, // 99 = 0110 0011 -> 0001 0100 0000 0101
360 0x1410, //100 = 0110 0100 -> 0001 0100 0001 0000
361 0x1411, //101 = 0110 0101 -> 0001 0100 0001 0001
362 0x1414, //102 = 0110 0110 -> 0001 0100 0001 0100
363 0x1415, //103 = 0110 0111 -> 0001 0100 0001 0101
364 0x1440, //104 = 0110 1000 -> 0001 0100 0100 0000
365 0x1441, //105 = 0110 1001 -> 0001 0100 0100 0001
366 0x1444, //106 = 0110 1010 -> 0001 0100 0100 0100
367 0x1445, //107 = 0110 1011 -> 0001 0100 0100 0101
368 0x1450, //108 = 0110 1100 -> 0001 0100 0101 0000
369 0x1451, //109 = 0110 1101 -> 0001 0100 0101 0001
370 0x1454, //110 = 0110 1110 -> 0001 0100 0101 0100
371 0x1455, //111 = 0110 1111 -> 0001 0100 0101 0101
372
373 0x1500, //112 = 0111 0000 -> 0001 0101 0000 0000
374 0x1501, //113 = 0111 0001 -> 0001 0101 0000 0001
375 0x1504, //114 = 0111 0010 -> 0001 0101 0000 0100
376 0x1505, //115 = 0111 0011 -> 0001 0101 0000 0101
377 0x1510, //116 = 0111 0100 -> 0001 0101 0001 0000
378 0x1511, //117 = 0111 0101 -> 0001 0101 0001 0001
379 0x1514, //118 = 0111 0110 -> 0001 0101 0001 0100
380 0x1515, //119 = 0111 0111 -> 0001 0101 0001 0101
381 0x1540, //120 = 0111 1000 -> 0001 0101 0100 0000
382 0x1541, //121 = 0111 1001 -> 0001 0101 0100 0001
383 0x1544, //122 = 0111 1010 -> 0001 0101 0100 0100
384 0x1545, //123 = 0111 1011 -> 0001 0101 0100 0101
385 0x1550, //124 = 0111 1100 -> 0001 0101 0101 0000
386 0x1551, //125 = 0111 1101 -> 0001 0101 0101 0001
387 0x1554, //126 = 0111 1110 -> 0001 0101 0101 0100
388 0x1555, //127 = 0111 1111 -> 0001 0101 0101 0101
389
390 0x4000, //128 = 1000 0000 -> 0100 0000 0000 0000
391 0x4001, //129 = 1000 0001 -> 0100 0000 0000 0001
392 0x4004, //130 = 1000 0010 -> 0100 0000 0000 0100
393 0x4005, //131 = 1000 0011 -> 0100 0000 0000 0101
394 0x4010, //132 = 1000 0100 -> 0100 0000 0001 0000
395 0x4011, //133 = 1000 0101 -> 0100 0000 0001 0001
396 0x4014, //134 = 1000 0110 -> 0100 0000 0001 0100
397 0x4015, //135 = 1000 0111 -> 0100 0000 0001 0101
398 0x4040, //136 = 1000 1000 -> 0100 0000 0100 0000
399 0x4041, //137 = 1000 1001 -> 0100 0000 0100 0001
400 0x4044, //138 = 1000 1010 -> 0100 0000 0100 0100
401 0x4045, //139 = 1000 1011 -> 0100 0000 0100 0101
402 0x4050, //140 = 1000 1100 -> 0100 0000 0101 0000
403 0x4051, //141 = 1000 1101 -> 0100 0000 0101 0001
404 0x4054, //142 = 1000 1110 -> 0100 0000 0101 0100
405 0x4055, //143 = 1000 1111 -> 0100 0000 0101 0101
406
407 0x4100, //144 = 1001 0000 -> 0100 0001 0000 0000
408 0x4101, //145 = 1001 0001 -> 0100 0001 0000 0001
409 0x4104, //146 = 1001 0010 -> 0100 0001 0000 0100
410 0x4105, //147 = 1001 0011 -> 0100 0001 0000 0101
411 0x4110, //148 = 1001 0100 -> 0100 0001 0001 0000
412 0x4111, //149 = 1001 0101 -> 0100 0001 0001 0001
413 0x4114, //150 = 1001 0110 -> 0100 0001 0001 0100
414 0x4115, //151 = 1001 0111 -> 0100 0001 0001 0101
415 0x4140, //152 = 1001 1000 -> 0100 0001 0100 0000
416 0x4141, //153 = 1001 1001 -> 0100 0001 0100 0001
417 0x4144, //154 = 1001 1010 -> 0100 0001 0100 0100
418 0x4145, //155 = 1001 1011 -> 0100 0001 0100 0101
419 0x4150, //156 = 1001 1100 -> 0100 0001 0101 0000
420 0x4151, //157 = 1001 1101 -> 0100 0001 0101 0001
421 0x4154, //158 = 1001 1110 -> 0100 0001 0101 0100
422 0x4155, //159 = 1001 1111 -> 0100 0001 0101 0101
423
424 0x4400, //160 = 1010 0000 -> 0100 0100 0000 0000
425 0x4401, //161 = 1010 0001 -> 0100 0100 0000 0001
426 0x4404, //162 = 1010 0010 -> 0100 0100 0000 0100
427 0x4405, //163 = 1010 0011 -> 0100 0100 0000 0101
428 0x4410, //164 = 1010 0100 -> 0100 0100 0001 0000
429 0x4411, //165 = 1010 0101 -> 0100 0100 0001 0001
430 0x4414, //166 = 1010 0110 -> 0100 0100 0001 0100
431 0x4415, //167 = 1010 0111 -> 0100 0100 0001 0101
432 0x4440, //168 = 1010 1000 -> 0100 0100 0100 0000
433 0x4441, //169 = 1010 1001 -> 0100 0100 0100 0001
434 0x4444, //170 = 1010 1010 -> 0100 0100 0100 0100
435 0x4445, //171 = 1010 1011 -> 0100 0100 0100 0101
436 0x4450, //172 = 1010 1100 -> 0100 0100 0101 0000
437 0x4451, //173 = 1010 1101 -> 0100 0100 0101 0001
438 0x4454, //174 = 1010 1110 -> 0100 0100 0101 0100
439 0x4455, //175 = 1010 1111 -> 0100 0100 0101 0101
440
441 0x4500, //176 = 1011 0000 -> 0100 0101 0000 0000
442 0x4501, //177 = 1011 0001 -> 0100 0101 0000 0001
443 0x4504, //178 = 1011 0010 -> 0100 0101 0000 0100
444 0x4505, //179 = 1011 0011 -> 0100 0101 0000 0101
445 0x4510, //180 = 1011 0100 -> 0100 0101 0001 0000
446 0x4511, //181 = 1011 0101 -> 0100 0101 0001 0001
447 0x4514, //182 = 1011 0110 -> 0100 0101 0001 0100
448 0x4515, //183 = 1011 0111 -> 0100 0101 0001 0101
449 0x4540, //184 = 1011 1000 -> 0100 0101 0100 0000
450 0x4541, //185 = 1011 1001 -> 0100 0101 0100 0001
451 0x4544, //186 = 1011 1010 -> 0100 0101 0100 0100
452 0x4545, //187 = 1011 1011 -> 0100 0101 0100 0101
453 0x4550, //188 = 1011 1100 -> 0100 0101 0101 0000
454 0x4551, //189 = 1011 1101 -> 0100 0101 0101 0001
455 0x4554, //190 = 1011 1110 -> 0100 0101 0101 0100
456 0x4555, //191 = 1011 1111 -> 0100 0101 0101 0101
457
458 0x5000, //192 = 1100 0000 -> 0101 0000 0000 0000
459 0x5001, //193 = 1100 0001 -> 0101 0000 0000 0001
460 0x5004, //194 = 1100 0010 -> 0101 0000 0000 0100
461 0x5005, //195 = 1100 0011 -> 0101 0000 0000 0101
462 0x5010, //196 = 1100 0100 -> 0101 0000 0001 0000
463 0x5011, //197 = 1100 0101 -> 0101 0000 0001 0001
464 0x5014, //198 = 1100 0110 -> 0101 0000 0001 0100
465 0x5015, //199 = 1100 0111 -> 0101 0000 0001 0101
466 0x5040, //200 = 1100 1000 -> 0101 0000 0100 0000
467 0x5041, //201 = 1100 1001 -> 0101 0000 0100 0001
468 0x5044, //202 = 1100 1010 -> 0101 0000 0100 0100
469 0x5045, //203 = 1100 1011 -> 0101 0000 0100 0101
470 0x5050, //204 = 1100 1100 -> 0101 0000 0101 0000
471 0x5051, //205 = 1100 1101 -> 0101 0000 0101 0001
472 0x5054, //206 = 1100 1110 -> 0101 0000 0101 0100
473 0x5055, //207 = 1100 1111 -> 0101 0000 0101 0101
474
475 0x5100, //208 = 1101 0000 -> 0101 0001 0000 0000
476 0x5101, //209 = 1101 0001 -> 0101 0001 0000 0001
477 0x5104, //210 = 1101 0010 -> 0101 0001 0000 0100
478 0x5105, //211 = 1101 0011 -> 0101 0001 0000 0101
479 0x5110, //212 = 1101 0100 -> 0101 0001 0001 0000
480 0x5111, //213 = 1101 0101 -> 0101 0001 0001 0001
481 0x5114, //214 = 1101 0110 -> 0101 0001 0001 0100
482 0x5115, //215 = 1101 0111 -> 0101 0001 0001 0101
483 0x5140, //216 = 1101 1000 -> 0101 0001 0100 0000
484 0x5141, //217 = 1101 1001 -> 0101 0001 0100 0001
485 0x5144, //218 = 1101 1010 -> 0101 0001 0100 0100
486 0x5145, //219 = 1101 1011 -> 0101 0001 0100 0101
487 0x5150, //220 = 1101 1100 -> 0101 0001 0101 0000
488 0x5151, //221 = 1101 1101 -> 0101 0001 0101 0001
489 0x5154, //222 = 1101 1110 -> 0101 0001 0101 0100
490 0x5155, //223 = 1101 1111 -> 0101 0001 0101 0101
491
492 0x5400, //224 = 1110 0000 -> 0101 0100 0000 0000
493 0x5401, //225 = 1110 0001 -> 0101 0100 0000 0001
494 0x5404, //226 = 1110 0010 -> 0101 0100 0000 0100
495 0x5405, //227 = 1110 0011 -> 0101 0100 0000 0101
496 0x5410, //228 = 1110 0100 -> 0101 0100 0001 0000
497 0x5411, //229 = 1110 0101 -> 0101 0100 0001 0001
498 0x5414, //230 = 1110 0110 -> 0101 0100 0001 0100
499 0x5415, //231 = 1110 0111 -> 0101 0100 0001 0101
500 0x5440, //232 = 1110 1000 -> 0101 0100 0100 0000
501 0x5441, //233 = 1110 1001 -> 0101 0100 0100 0001
502 0x5444, //234 = 1110 1010 -> 0101 0100 0100 0100
503 0x5445, //235 = 1110 1011 -> 0101 0100 0100 0101
504 0x5450, //236 = 1110 1100 -> 0101 0100 0101 0000
505 0x5451, //237 = 1110 1101 -> 0101 0100 0101 0001
506 0x5454, //238 = 1110 1110 -> 0101 0100 0101 0100
507 0x5455, //239 = 1110 1111 -> 0101 0100 0101 0101
508
509 0x5500, //240 = 1111 0000 -> 0101 0101 0000 0000
510 0x5501, //241 = 1111 0001 -> 0101 0101 0000 0001
511 0x5504, //242 = 1111 0010 -> 0101 0101 0000 0100
512 0x5505, //243 = 1111 0011 -> 0101 0101 0000 0101
513 0x5510, //244 = 1111 0100 -> 0101 0101 0001 0000
514 0x5511, //245 = 1111 0101 -> 0101 0101 0001 0001
515 0x5514, //246 = 1111 0110 -> 0101 0101 0001 0100
516 0x5515, //247 = 1111 0111 -> 0101 0101 0001 0101
517 0x5540, //248 = 1111 1000 -> 0101 0101 0100 0000
518 0x5541, //249 = 1111 1001 -> 0101 0101 0100 0001
519 0x5544, //250 = 1111 1010 -> 0101 0101 0100 0100
520 0x5545, //251 = 1111 1011 -> 0101 0101 0100 0101
521 0x5550, //252 = 1111 1100 -> 0101 0101 0101 0000
522 0x5551, //253 = 1111 1101 -> 0101 0101 0101 0001
523 0x5554, //254 = 1111 1110 -> 0101 0101 0101 0100
524 0x5555 //255 = 1111 1111 -> 0101 0101 0101 0101
525
526]
diff --git a/frontend/beta/js/Clipperz/Crypto/ECC/BinaryField/Point.js b/frontend/beta/js/Clipperz/Crypto/ECC/BinaryField/Point.js
new file mode 100644
index 0000000..f0739bc
--- a/dev/null
+++ b/frontend/beta/js/Clipperz/Crypto/ECC/BinaryField/Point.js
@@ -0,0 +1,67 @@
1/*
2
3Copyright 2008-2011 Clipperz Srl
4
5This file is part of Clipperz's Javascript Crypto Library.
6Javascript Crypto Library provides web developers with an extensive
7and efficient set of cryptographic functions. The library aims to
8obtain maximum execution speed while preserving modularity and
9reusability.
10For further information about its features and functionalities please
11refer to http://www.clipperz.com
12
13* Javascript Crypto Library is free software: you can redistribute
14 it and/or modify it under the terms of the GNU Affero General Public
15 License as published by the Free Software Foundation, either version
16 3 of the License, or (at your option) any later version.
17
18* Javascript Crypto Library is distributed in the hope that it will
19 be useful, but WITHOUT ANY WARRANTY; without even the implied
20 warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
21 See the GNU Affero General Public License for more details.
22
23* You should have received a copy of the GNU Affero General Public
24 License along with Javascript Crypto Library. If not, see
25 <http://www.gnu.org/licenses/>.
26
27*/
28
29try { if (typeof(Clipperz.ByteArray) == 'undefined') { throw ""; }} catch (e) {
30 throw "Clipperz.Crypto.ECC depends on Clipperz.ByteArray!";
31}
32if (typeof(Clipperz.Crypto.ECC) == 'undefined') { Clipperz.Crypto.ECC = {}; }
33if (typeof(Clipperz.Crypto.ECC.BinaryField) == 'undefined') { Clipperz.Crypto.ECC.BinaryField = {}; }
34
35Clipperz.Crypto.ECC.BinaryField.Point = function(args) {
36 args = args || {};
37 this._x = args.x;
38 this._y = args.y;
39
40 return this;
41}
42
43Clipperz.Crypto.ECC.BinaryField.Point.prototype = MochiKit.Base.update(null, {
44
45 'asString': function() {
46 return "Clipperz.Crypto.ECC.BinaryField.Point (" + this.x() + ", " + this.y() + ")";
47 },
48
49 //-----------------------------------------------------------------------------
50
51 'x': function() {
52 return this._x;
53 },
54
55 'y': function() {
56 return this._y;
57 },
58
59 //-----------------------------------------------------------------------------
60
61 'isZero': function() {
62 return (this.x().isZero() && this.y().isZero())
63 },
64
65 //-----------------------------------------------------------------------------
66 __syntaxFix__: "syntax fix"
67});
diff --git a/frontend/beta/js/Clipperz/Crypto/ECC/BinaryField/Value.js b/frontend/beta/js/Clipperz/Crypto/ECC/BinaryField/Value.js
new file mode 100644
index 0000000..10d055e
--- a/dev/null
+++ b/frontend/beta/js/Clipperz/Crypto/ECC/BinaryField/Value.js
@@ -0,0 +1,377 @@
1/*
2
3Copyright 2008-2011 Clipperz Srl
4
5This file is part of Clipperz's Javascript Crypto Library.
6Javascript Crypto Library provides web developers with an extensive
7and efficient set of cryptographic functions. The library aims to
8obtain maximum execution speed while preserving modularity and
9reusability.
10For further information about its features and functionalities please
11refer to http://www.clipperz.com
12
13* Javascript Crypto Library is free software: you can redistribute
14 it and/or modify it under the terms of the GNU Affero General Public
15 License as published by the Free Software Foundation, either version
16 3 of the License, or (at your option) any later version.
17
18* Javascript Crypto Library is distributed in the hope that it will
19 be useful, but WITHOUT ANY WARRANTY; without even the implied
20 warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
21 See the GNU Affero General Public License for more details.
22
23* You should have received a copy of the GNU Affero General Public
24 License along with Javascript Crypto Library. If not, see
25 <http://www.gnu.org/licenses/>.
26
27*/
28
29try { if (typeof(Clipperz.ByteArray) == 'undefined') { throw ""; }} catch (e) {
30 throw "Clipperz.Crypto.ECC depends on Clipperz.ByteArray!";
31}
32if (typeof(Clipperz.Crypto.ECC) == 'undefined') { Clipperz.Crypto.ECC = {}; }
33if (typeof(Clipperz.Crypto.ECC.BinaryField) == 'undefined') { Clipperz.Crypto.ECC.BinaryField = {}; }
34
35Clipperz.Crypto.ECC.BinaryField.Value = function(aValue, aBase) {
36 if (aValue.constructor == String) {
37 varvalue;
38 varstringLength;
39 var numberOfWords;
40 vari,c;
41
42 if (aBase != 16) {
43 throw Clipperz.Crypto.ECC.BinaryField.Value.exception.UnsupportedBase;
44 }
45
46 value = aValue.replace(/ /g, '');
47 stringLength = value.length;
48 numberOfWords = Math.ceil(stringLength / 8);
49 this._value = new Array(numberOfWords);
50
51 c = numberOfWords;
52 for (i=0; i<c; i++) {
53 varword;
54
55 if (i < (c-1)) {
56 word = parseInt(value.substr(stringLength-((i+1)*8), 8), 16);
57 } else {
58 word = parseInt(value.substr(0, stringLength-(i*8)), 16);
59 }
60
61 this._value[i] = word;
62 }
63 } else if (aValue.constructor == Array) {
64 var itemsToCopy;
65
66 itemsToCopy = aValue.length;
67 while (aValue[itemsToCopy - 1] == 0) {
68 itemsToCopy --;
69 }
70
71 this._value = aValue.slice(0, itemsToCopy);
72 } else if (aValue.constructor == Number) {
73 this._value = [aValue];
74 } else {
75 // throw Clipperz.Crypto.ECC.BinaryField.Value.exception.UnsupportedConstructorValueType;
76 }
77
78 return this;
79}
80
81Clipperz.Crypto.ECC.BinaryField.Value.prototype = MochiKit.Base.update(null, {
82
83 'value': function() {
84 return this._value;
85 },
86
87 //-----------------------------------------------------------------------------
88
89 'wordSize': function() {
90 return this._value.length
91 },
92
93 //-----------------------------------------------------------------------------
94
95 'clone': function() {
96 return new Clipperz.Crypto.ECC.BinaryField.Value(this._value.slice(0));
97 },
98
99 //-----------------------------------------------------------------------------
100
101 'isZero': function() {
102 return (this.compare(Clipperz.Crypto.ECC.BinaryField.Value.O) == 0);
103 },
104
105 //-----------------------------------------------------------------------------
106
107 'asString': function(aBase) {
108 varresult;
109 var i,c;
110
111 if (aBase != 16) {
112 throw Clipperz.Crypto.ECC.BinaryField.Value.exception.UnsupportedBase;
113 }
114
115 result = "";
116 c = this.wordSize();
117 for (i=0; i<c; i++) {
118 varwordAsString;
119
120 // wordAsString = ("00000000" + this.value()[i].toString(16));
121 wordAsString = ("00000000" + this._value[i].toString(16));
122 wordAsString = wordAsString.substring(wordAsString.length - 8);
123 result = wordAsString + result;
124 }
125
126 result = result.replace(/^(00)*/, "");
127
128 if (result == "") {
129 result = "0";
130 }
131
132 return result;
133 },
134
135 //-----------------------------------------------------------------------------
136
137 'shiftLeft': function(aNumberOfBitsToShift) {
138 return new Clipperz.Crypto.ECC.BinaryField.Value(Clipperz.Crypto.ECC.BinaryField.Value._shiftLeft(this._value, aNumberOfBitsToShift));
139 },
140
141 //-----------------------------------------------------------------------------
142
143 'bitSize': function() {
144 return Clipperz.Crypto.ECC.BinaryField.Value._bitSize(this._value);
145 },
146
147 //-----------------------------------------------------------------------------
148
149 'isBitSet': function(aBitPosition) {
150 return Clipperz.Crypto.ECC.BinaryField.Value._isBitSet(this._value, aBitPosition);
151 },
152
153 //-----------------------------------------------------------------------------
154
155 'xor': function(aValue) {
156 return new Clipperz.Crypto.ECC.BinaryField.Value(Clipperz.Crypto.ECC.BinaryField.Value._xor(this._value, aValue._value));
157 },
158
159 //-----------------------------------------------------------------------------
160
161 'compare': function(aValue) {
162 return Clipperz.Crypto.ECC.BinaryField.Value._compare(this._value, aValue._value);
163 },
164
165 //-----------------------------------------------------------------------------
166 __syntaxFix__: "syntax fix"
167});
168
169Clipperz.Crypto.ECC.BinaryField.Value.O = new Clipperz.Crypto.ECC.BinaryField.Value('0', 16);
170Clipperz.Crypto.ECC.BinaryField.Value.I = new Clipperz.Crypto.ECC.BinaryField.Value('1', 16);
171
172Clipperz.Crypto.ECC.BinaryField.Value._xor = function(a, b, aFirstItemOffset) {
173 var result;
174 var resultSize;
175 var i,c;
176 var firstItemOffset;
177
178 firstItemOffset = aFirstItemOffset || 0;
179 resultSize = Math.max((a.length - firstItemOffset), b.length) + firstItemOffset;
180
181 result = new Array(resultSize);
182
183 c = firstItemOffset;
184 for (i=0; i<c; i++) {
185 result[i] = a[i];
186 }
187
188 c = resultSize;
189 for (i=firstItemOffset; i<c; i++) {
190 result[i] = (((a[i] || 0) ^ (b[i - firstItemOffset] || 0)) >>> 0);
191 }
192
193 return result;
194};
195
196Clipperz.Crypto.ECC.BinaryField.Value._overwriteXor = function(a, b, aFirstItemOffset) {
197 var i,c;
198 var firstItemOffset;
199
200 firstItemOffset = aFirstItemOffset || 0;
201
202 c = Math.max((a.length - firstItemOffset), b.length) + firstItemOffset;
203 for (i=firstItemOffset; i<c; i++) {
204 a[i] = (((a[i] || 0) ^ (b[i - firstItemOffset] || 0)) >>> 0);
205 }
206};
207
208Clipperz.Crypto.ECC.BinaryField.Value._shiftLeft = function(aWordArray, aNumberOfBitsToShift) {
209 var numberOfWordsToShift;
210 varnumberOfBitsToShift;
211 var result;
212 varoverflowValue;
213 vari,c;
214
215 numberOfWordsToShift = Math.floor(aNumberOfBitsToShift / 32);
216 numberOfBitsToShift = aNumberOfBitsToShift % 32;
217
218 result = new Array(aWordArray.length + numberOfWordsToShift);
219
220 c = numberOfWordsToShift;
221 for (i=0; i<c; i++) {
222 result[i] = 0;
223 }
224
225 overflowValue = 0;
226 nextOverflowValue = 0;
227
228 c = aWordArray.length;
229 for (i=0; i<c; i++) {
230 varvalue;
231 varresultWord;
232
233 // value = this.value()[i];
234 value = aWordArray[i];
235
236 if (numberOfBitsToShift > 0) {
237 var nextOverflowValue;
238
239 nextOverflowValue = (value >>> (32 - numberOfBitsToShift));
240 value = value & (0xffffffff >>> numberOfBitsToShift);
241 resultWord = (((value << numberOfBitsToShift) | overflowValue) >>> 0);
242 } else {
243 resultWord = value;
244 }
245
246 result[i+numberOfWordsToShift] = resultWord;
247 overflowValue = nextOverflowValue;
248 }
249
250 if (overflowValue != 0) {
251 result[aWordArray.length + numberOfWordsToShift] = overflowValue;
252 }
253
254 return result;
255};
256
257Clipperz.Crypto.ECC.BinaryField.Value._overwriteShiftLeft = function(aWordArray, aNumberOfBitsToShift) {
258 var numberOfWordsToShift;
259 varnumberOfBitsToShift;
260 var result;
261 varoverflowValue;
262 vari,c;
263
264 numberOfWordsToShift = Math.floor(aNumberOfBitsToShift / 32);
265 numberOfBitsToShift = aNumberOfBitsToShift % 32;
266
267 result = new Array(aWordArray.length + numberOfWordsToShift);
268
269 c = numberOfWordsToShift;
270 for (i=0; i<c; i++) {
271 result[i] = 0;
272 }
273
274 overflowValue = 0;
275 nextOverflowValue = 0;
276
277 c = aWordArray.length;
278 for (i=0; i<c; i++) {
279 varvalue;
280 varresultWord;
281
282 // value = this.value()[i];
283 value = aWordArray[i];
284
285 if (numberOfBitsToShift > 0) {
286 var nextOverflowValue;
287
288 nextOverflowValue = (value >>> (32 - numberOfBitsToShift));
289 value = value & (0xffffffff >>> numberOfBitsToShift);
290 resultWord = (((value << numberOfBitsToShift) | overflowValue) >>> 0);
291 } else {
292 resultWord = value;
293 }
294
295 result[i+numberOfWordsToShift] = resultWord;
296 overflowValue = nextOverflowValue;
297 }
298
299 if (overflowValue != 0) {
300 result[aWordArray.length + numberOfWordsToShift] = overflowValue;
301 }
302
303 return result;
304};
305
306Clipperz.Crypto.ECC.BinaryField.Value._bitSize = function(aWordArray) {
307 varresult;
308 varnotNullElements;
309 var mostValuableWord;
310 var matchingBitsInMostImportantWord;
311 var mask;
312 var i,c;
313
314 notNullElements = aWordArray.length;
315
316 if ((aWordArray.length == 1) && (aWordArray[0] == 0)) {
317 result = 0;
318 } else {
319 while((aWordArray[notNullElements - 1] == 0) && (notNullElements > 0)) {
320 notNullElements --;
321 }
322
323 result = (notNullElements - 1) * 32;
324 mostValuableWord = aWordArray[notNullElements - 1];
325
326 matchingBits = 32;
327 mask = 0x80000000;
328
329 while ((matchingBits > 0) && ((mostValuableWord & mask) == 0)) {
330 matchingBits --;
331 mask >>>= 1;
332 }
333
334 result += matchingBits;
335 }
336
337 return result;
338};
339
340Clipperz.Crypto.ECC.BinaryField.Value._isBitSet = function(aWordArray, aBitPosition) {
341 var result;
342 varbyteIndex;
343 var bitIndexInSelectedByte;
344
345 byteIndex = Math.floor(aBitPosition / 32);
346 bitIndexInSelectedByte = aBitPosition % 32;
347
348 if (byteIndex <= aWordArray.length) {
349 result = ((aWordArray[byteIndex] & (1 << bitIndexInSelectedByte)) != 0);
350 } else {
351 result = false;
352 }
353
354 return result;
355};
356
357Clipperz.Crypto.ECC.BinaryField.Value._compare = function(a,b) {
358 varresult;
359 var i,c;
360
361 result = MochiKit.Base.compare(a.length, b.length);
362
363 c = a.length;
364 for (i=0; (i<c) && (result==0); i++) {
365//console.log("compare[" + c + " - " + i + " - 1] " + this.value()[c-i-1] + ", " + aValue.value()[c-i-1]);
366 // result = MochiKit.Base.compare(this.value()[c-i-1], aValue.value()[c-i-1]);
367 result = MochiKit.Base.compare(a[c-i-1], b[c-i-1]);
368 }
369
370 return result;
371};
372
373
374Clipperz.Crypto.ECC.BinaryField.Value['exception']= {
375 'UnsupportedBase': new MochiKit.Base.NamedError("Clipperz.Crypto.ECC.BinaryField.Value.exception.UnsupportedBase"),
376 'UnsupportedConstructorValueType':new MochiKit.Base.NamedError("Clipperz.Crypto.ECC.BinaryField.Value.exception.UnsupportedConstructorValueType")
377};
diff --git a/frontend/beta/js/Clipperz/Crypto/PRNG.js b/frontend/beta/js/Clipperz/Crypto/PRNG.js
new file mode 100644
index 0000000..770ceb1
--- a/dev/null
+++ b/frontend/beta/js/Clipperz/Crypto/PRNG.js
@@ -0,0 +1,854 @@
1/*
2
3Copyright 2008-2011 Clipperz Srl
4
5This file is part of Clipperz's Javascript Crypto Library.
6Javascript Crypto Library provides web developers with an extensive
7and efficient set of cryptographic functions. The library aims to
8obtain maximum execution speed while preserving modularity and
9reusability.
10For further information about its features and functionalities please
11refer to http://www.clipperz.com
12
13* Javascript Crypto Library is free software: you can redistribute
14 it and/or modify it under the terms of the GNU Affero General Public
15 License as published by the Free Software Foundation, either version
16 3 of the License, or (at your option) any later version.
17
18* Javascript Crypto Library is distributed in the hope that it will
19 be useful, but WITHOUT ANY WARRANTY; without even the implied
20 warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
21 See the GNU Affero General Public License for more details.
22
23* You should have received a copy of the GNU Affero General Public
24 License along with Javascript Crypto Library. If not, see
25 <http://www.gnu.org/licenses/>.
26
27*/
28
29try { if (typeof(Clipperz.ByteArray) == 'undefined') { throw ""; }} catch (e) {
30 throw "Clipperz.Crypto.PRNG depends on Clipperz.ByteArray!";
31}
32
33try { if (typeof(Clipperz.Crypto.SHA) == 'undefined') { throw ""; }} catch (e) {
34 throw "Clipperz.Crypto.PRNG depends on Clipperz.Crypto.SHA!";
35}
36
37try { if (typeof(Clipperz.Crypto.AES) == 'undefined') { throw ""; }} catch (e) {
38 throw "Clipperz.Crypto.PRNG depends on Clipperz.Crypto.AES!";
39}
40
41if (typeof(Clipperz.Crypto.PRNG) == 'undefined') { Clipperz.Crypto.PRNG = {}; }
42
43//#############################################################################
44
45Clipperz.Crypto.PRNG.EntropyAccumulator = function(args) {
46 args = args || {};
47 //MochiKit.Base.bindMethods(this);
48
49 this._stack = new Clipperz.ByteArray();
50 this._maxStackLengthBeforeHashing = args.maxStackLengthBeforeHashing || 256;
51 return this;
52}
53
54Clipperz.Crypto.PRNG.EntropyAccumulator.prototype = MochiKit.Base.update(null, {
55
56 'toString': function() {
57 return "Clipperz.Crypto.PRNG.EntropyAccumulator";
58 },
59
60 //-------------------------------------------------------------------------
61
62 'stack': function() {
63 return this._stack;
64 },
65
66 'setStack': function(aValue) {
67 this._stack = aValue;
68 },
69
70 'resetStack': function() {
71 this.stack().reset();
72 },
73
74 'maxStackLengthBeforeHashing': function() {
75 return this._maxStackLengthBeforeHashing;
76 },
77
78 //-------------------------------------------------------------------------
79
80 'addRandomByte': function(aValue) {
81 this.stack().appendByte(aValue);
82
83 if (this.stack().length() > this.maxStackLengthBeforeHashing()) {
84 this.setStack(Clipperz.Crypto.SHA.sha_d256(this.stack()));
85 }
86 },
87
88 //-------------------------------------------------------------------------
89 __syntaxFix__: "syntax fix"
90});
91
92//#############################################################################
93
94Clipperz.Crypto.PRNG.RandomnessSource = function(args) {
95 args = args || {};
96 MochiKit.Base.bindMethods(this);
97
98 this._generator = args.generator || null;
99 this._sourceId = args.sourceId || null;
100 this._boostMode = args.boostMode || false;
101
102 this._nextPoolIndex = 0;
103
104 return this;
105}
106
107Clipperz.Crypto.PRNG.RandomnessSource.prototype = MochiKit.Base.update(null, {
108
109 'generator': function() {
110 return this._generator;
111 },
112
113 'setGenerator': function(aValue) {
114 this._generator = aValue;
115 },
116
117 //-------------------------------------------------------------------------
118
119 'boostMode': function() {
120 return this._boostMode;
121 },
122
123 'setBoostMode': function(aValue) {
124 this._boostMode = aValue;
125 },
126
127 //-------------------------------------------------------------------------
128
129 'sourceId': function() {
130 return this._sourceId;
131 },
132
133 'setSourceId': function(aValue) {
134 this._sourceId = aValue;
135 },
136
137 //-------------------------------------------------------------------------
138
139 'nextPoolIndex': function() {
140 return this._nextPoolIndex;
141 },
142
143 'incrementNextPoolIndex': function() {
144 this._nextPoolIndex = ((this._nextPoolIndex + 1) % this.generator().numberOfEntropyAccumulators());
145 },
146
147 //-------------------------------------------------------------------------
148
149 'updateGeneratorWithValue': function(aRandomValue) {
150 if (this.generator() != null) {
151 this.generator().addRandomByte(this.sourceId(), this.nextPoolIndex(), aRandomValue);
152 this.incrementNextPoolIndex();
153 }
154 },
155
156 //-------------------------------------------------------------------------
157 __syntaxFix__: "syntax fix"
158});
159
160//#############################################################################
161
162Clipperz.Crypto.PRNG.TimeRandomnessSource = function(args) {
163 args = args || {};
164 //MochiKit.Base.bindMethods(this);
165
166 this._intervalTime = args.intervalTime || 1000;
167
168 Clipperz.Crypto.PRNG.RandomnessSource.call(this, args);
169
170 this.collectEntropy();
171 return this;
172}
173
174Clipperz.Crypto.PRNG.TimeRandomnessSource.prototype = MochiKit.Base.update(new Clipperz.Crypto.PRNG.RandomnessSource, {
175
176 'intervalTime': function() {
177 return this._intervalTime;
178 },
179
180 //-------------------------------------------------------------------------
181
182 'collectEntropy': function() {
183 varnow;
184 varentropyByte;
185 var intervalTime;
186 now = new Date();
187 entropyByte = (now.getTime() & 0xff);
188
189 intervalTime = this.intervalTime();
190 if (this.boostMode() == true) {
191 intervalTime = intervalTime / 9;
192 }
193
194 this.updateGeneratorWithValue(entropyByte);
195 setTimeout(this.collectEntropy, intervalTime);
196 },
197
198 //-------------------------------------------------------------------------
199
200 'numberOfRandomBits': function() {
201 return 5;
202 },
203
204 //-------------------------------------------------------------------------
205
206 'pollingFrequency': function() {
207 return 10;
208 },
209
210 //-------------------------------------------------------------------------
211 __syntaxFix__: "syntax fix"
212});
213
214//*****************************************************************************
215
216Clipperz.Crypto.PRNG.MouseRandomnessSource = function(args) {
217 args = args || {};
218
219 Clipperz.Crypto.PRNG.RandomnessSource.call(this, args);
220
221 this._numberOfBitsToCollectAtEachEvent = 4;
222 this._randomBitsCollector = 0;
223 this._numberOfRandomBitsCollected = 0;
224
225 MochiKit.Signal.connect(document, 'onmousemove', this, 'collectEntropy');
226
227 return this;
228}
229
230Clipperz.Crypto.PRNG.MouseRandomnessSource.prototype = MochiKit.Base.update(new Clipperz.Crypto.PRNG.RandomnessSource, {
231
232 //-------------------------------------------------------------------------
233
234 'numberOfBitsToCollectAtEachEvent': function() {
235 return this._numberOfBitsToCollectAtEachEvent;
236 },
237
238 //-------------------------------------------------------------------------
239
240 'randomBitsCollector': function() {
241 return this._randomBitsCollector;
242 },
243
244 'setRandomBitsCollector': function(aValue) {
245 this._randomBitsCollector = aValue;
246 },
247
248 'appendRandomBitsToRandomBitsCollector': function(aValue) {
249 var collectedBits;
250 var numberOfRandomBitsCollected;
251
252 numberOfRandomBitsCollected = this.numberOfRandomBitsCollected();
253 collectetBits = this.randomBitsCollector() | (aValue << numberOfRandomBitsCollected);
254 this.setRandomBitsCollector(collectetBits);
255 numberOfRandomBitsCollected += this.numberOfBitsToCollectAtEachEvent();
256
257 if (numberOfRandomBitsCollected == 8) {
258 this.updateGeneratorWithValue(collectetBits);
259 numberOfRandomBitsCollected = 0;
260 this.setRandomBitsCollector(0);
261 }
262
263 this.setNumberOfRandomBitsCollected(numberOfRandomBitsCollected)
264 },
265
266 //-------------------------------------------------------------------------
267
268 'numberOfRandomBitsCollected': function() {
269 return this._numberOfRandomBitsCollected;
270 },
271
272 'setNumberOfRandomBitsCollected': function(aValue) {
273 this._numberOfRandomBitsCollected = aValue;
274 },
275
276 //-------------------------------------------------------------------------
277
278 'collectEntropy': function(anEvent) {
279 var mouseLocation;
280 var randomBit;
281 var mask;
282
283 mask = 0xffffffff >>> (32 - this.numberOfBitsToCollectAtEachEvent());
284
285 mouseLocation = anEvent.mouse().client;
286 randomBit = ((mouseLocation.x ^ mouseLocation.y) & mask);
287 this.appendRandomBitsToRandomBitsCollector(randomBit)
288 },
289
290 //-------------------------------------------------------------------------
291
292 'numberOfRandomBits': function() {
293 return 1;
294 },
295
296 //-------------------------------------------------------------------------
297
298 'pollingFrequency': function() {
299 return 10;
300 },
301
302 //-------------------------------------------------------------------------
303 __syntaxFix__: "syntax fix"
304});
305
306//*****************************************************************************
307
308Clipperz.Crypto.PRNG.KeyboardRandomnessSource = function(args) {
309 args = args || {};
310 Clipperz.Crypto.PRNG.RandomnessSource.call(this, args);
311
312 this._randomBitsCollector = 0;
313 this._numberOfRandomBitsCollected = 0;
314
315 MochiKit.Signal.connect(document, 'onkeypress', this, 'collectEntropy');
316
317 return this;
318}
319
320Clipperz.Crypto.PRNG.KeyboardRandomnessSource.prototype = MochiKit.Base.update(new Clipperz.Crypto.PRNG.RandomnessSource, {
321
322 //-------------------------------------------------------------------------
323
324 'randomBitsCollector': function() {
325 return this._randomBitsCollector;
326 },
327
328 'setRandomBitsCollector': function(aValue) {
329 this._randomBitsCollector = aValue;
330 },
331
332 'appendRandomBitToRandomBitsCollector': function(aValue) {
333 var collectedBits;
334 var numberOfRandomBitsCollected;
335
336 numberOfRandomBitsCollected = this.numberOfRandomBitsCollected();
337 collectetBits = this.randomBitsCollector() | (aValue << numberOfRandomBitsCollected);
338 this.setRandomBitsCollector(collectetBits);
339 numberOfRandomBitsCollected ++;
340
341 if (numberOfRandomBitsCollected == 8) {
342 this.updateGeneratorWithValue(collectetBits);
343 numberOfRandomBitsCollected = 0;
344 this.setRandomBitsCollector(0);
345 }
346
347 this.setNumberOfRandomBitsCollected(numberOfRandomBitsCollected)
348 },
349
350 //-------------------------------------------------------------------------
351
352 'numberOfRandomBitsCollected': function() {
353 return this._numberOfRandomBitsCollected;
354 },
355
356 'setNumberOfRandomBitsCollected': function(aValue) {
357 this._numberOfRandomBitsCollected = aValue;
358 },
359
360 //-------------------------------------------------------------------------
361
362 'collectEntropy': function(anEvent) {
363/*
364 var mouseLocation;
365 var randomBit;
366
367 mouseLocation = anEvent.mouse().client;
368
369 randomBit = ((mouseLocation.x ^ mouseLocation.y) & 0x1);
370 this.appendRandomBitToRandomBitsCollector(randomBit);
371*/
372 },
373
374 //-------------------------------------------------------------------------
375
376 'numberOfRandomBits': function() {
377 return 1;
378 },
379
380 //-------------------------------------------------------------------------
381
382 'pollingFrequency': function() {
383 return 10;
384 },
385
386 //-------------------------------------------------------------------------
387 __syntaxFix__: "syntax fix"
388});
389
390//#############################################################################
391
392Clipperz.Crypto.PRNG.Fortuna = function(args) {
393 vari,c;
394
395 args = args || {};
396
397 this._key = args.seed || null;
398 if (this._key == null) {
399 this._counter = 0;
400 this._key = new Clipperz.ByteArray();
401 } else {
402 this._counter = 1;
403 }
404
405 this._aesKey = null;
406
407 this._firstPoolReseedLevel = args.firstPoolReseedLevel || 32 || 64;
408 this._numberOfEntropyAccumulators = args.numberOfEntropyAccumulators || 32;
409
410 this._accumulators = [];
411 c = this.numberOfEntropyAccumulators();
412 for (i=0; i<c; i++) {
413 this._accumulators.push(new Clipperz.Crypto.PRNG.EntropyAccumulator());
414 }
415
416 this._randomnessSources = [];
417 this._reseedCounter = 0;
418
419 return this;
420}
421
422Clipperz.Crypto.PRNG.Fortuna.prototype = MochiKit.Base.update(null, {
423
424 'toString': function() {
425 return "Clipperz.Crypto.PRNG.Fortuna";
426 },
427
428 //-------------------------------------------------------------------------
429
430 'key': function() {
431 return this._key;
432 },
433
434 'setKey': function(aValue) {
435 this._key = aValue;
436 this._aesKey = null;
437 },
438
439 'aesKey': function() {
440 if (this._aesKey == null) {
441 this._aesKey = new Clipperz.Crypto.AES.Key({key:this.key()});
442 }
443
444 return this._aesKey;
445 },
446
447 'accumulators': function() {
448 return this._accumulators;
449 },
450
451 'firstPoolReseedLevel': function() {
452 return this._firstPoolReseedLevel;
453 },
454
455 //-------------------------------------------------------------------------
456
457 'reseedCounter': function() {
458 return this._reseedCounter;
459 },
460
461 'incrementReseedCounter': function() {
462 this._reseedCounter = this._reseedCounter +1;
463 },
464
465 //-------------------------------------------------------------------------
466
467 'reseed': function() {
468 varnewKeySeed;
469 var reseedCounter;
470 varreseedCounterMask;
471 var i, c;
472
473 newKeySeed = this.key();
474 this.incrementReseedCounter();
475 reseedCounter = this.reseedCounter();
476
477 c = this.numberOfEntropyAccumulators();
478 reseedCounterMask = 0xffffffff >>> (32 - c);
479 for (i=0; i<c; i++) {
480 if ((i == 0) || ((reseedCounter & (reseedCounterMask >>> (c - i))) == 0)) {
481 newKeySeed.appendBlock(this.accumulators()[i].stack());
482 this.accumulators()[i].resetStack();
483 }
484 }
485
486 if (reseedCounter == 1) {
487 c = this.randomnessSources().length;
488 for (i=0; i<c; i++) {
489 this.randomnessSources()[i].setBoostMode(false);
490 }
491 }
492
493 this.setKey(Clipperz.Crypto.SHA.sha_d256(newKeySeed));
494 if (reseedCounter == 1) {
495MochiKit.Logging.logDebug("### PRNG.readyToGenerateRandomBytes");
496 MochiKit.Signal.signal(this, 'readyToGenerateRandomBytes');
497 }
498 MochiKit.Signal.signal(this, 'reseeded');
499 },
500
501 //-------------------------------------------------------------------------
502
503 'isReadyToGenerateRandomValues': function() {
504 return this.reseedCounter() != 0;
505 },
506
507 //-------------------------------------------------------------------------
508
509 'entropyLevel': function() {
510 return this.accumulators()[0].stack().length() + (this.reseedCounter() * this.firstPoolReseedLevel());
511 },
512
513 //-------------------------------------------------------------------------
514
515 'counter': function() {
516 return this._counter;
517 },
518
519 'incrementCounter': function() {
520 this._counter += 1;
521 },
522
523 'counterBlock': function() {
524 var result;
525
526 result = new Clipperz.ByteArray().appendWords(this.counter(), 0, 0, 0);
527
528 return result;
529 },
530
531 //-------------------------------------------------------------------------
532
533 'getRandomBlock': function() {
534 var result;
535
536 result = new Clipperz.ByteArray(Clipperz.Crypto.AES.encryptBlock(this.aesKey(), this.counterBlock().arrayValues()));
537 this.incrementCounter();
538
539 return result;
540 },
541
542 //-------------------------------------------------------------------------
543
544 'getRandomBytes': function(aSize) {
545 var result;
546
547 if (this.isReadyToGenerateRandomValues()) {
548 var i,c;
549 var newKey;
550
551 result = new Clipperz.ByteArray();
552
553 c = Math.ceil(aSize / (128 / 8));
554 for (i=0; i<c; i++) {
555 result.appendBlock(this.getRandomBlock());
556 }
557
558 if (result.length() != aSize) {
559 result = result.split(0, aSize);
560 }
561
562 newKey = this.getRandomBlock().appendBlock(this.getRandomBlock());
563 this.setKey(newKey);
564 } else {
565MochiKit.Logging.logWarning("Fortuna generator has not enough entropy, yet!");
566 throw Clipperz.Crypto.PRNG.exception.NotEnoughEntropy;
567 }
568
569 return result;
570 },
571
572 //-------------------------------------------------------------------------
573
574 'addRandomByte': function(aSourceId, aPoolId, aRandomValue) {
575 varselectedAccumulator;
576
577 selectedAccumulator = this.accumulators()[aPoolId];
578 selectedAccumulator.addRandomByte(aRandomValue);
579
580 if (aPoolId == 0) {
581 MochiKit.Signal.signal(this, 'addedRandomByte')
582 if (selectedAccumulator.stack().length() > this.firstPoolReseedLevel()) {
583 this.reseed();
584 }
585 }
586 },
587
588 //-------------------------------------------------------------------------
589
590 'numberOfEntropyAccumulators': function() {
591 return this._numberOfEntropyAccumulators;
592 },
593
594 //-------------------------------------------------------------------------
595
596 'randomnessSources': function() {
597 return this._randomnessSources;
598 },
599
600 'addRandomnessSource': function(aRandomnessSource) {
601 aRandomnessSource.setGenerator(this);
602 aRandomnessSource.setSourceId(this.randomnessSources().length);
603 this.randomnessSources().push(aRandomnessSource);
604
605 if (this.isReadyToGenerateRandomValues() == false) {
606 aRandomnessSource.setBoostMode(true);
607 }
608 },
609
610 //-------------------------------------------------------------------------
611
612 'deferredEntropyCollection': function(aValue) {
613 var result;
614
615//MochiKit.Logging.logDebug(">>> PRNG.deferredEntropyCollection");
616
617 if (this.isReadyToGenerateRandomValues()) {
618//MochiKit.Logging.logDebug("--- PRNG.deferredEntropyCollection - 1");
619 result = aValue;
620 } else {
621//MochiKit.Logging.logDebug("--- PRNG.deferredEntropyCollection - 2");
622 var deferredResult;
623
624 Clipperz.NotificationCenter.notify(this, 'updatedProgressState', 'collectingEntropy', true);
625
626 deferredResult = new MochiKit.Async.Deferred();
627 // deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("1.2.1 - PRNG.deferredEntropyCollection - 1: " + res); return res;});
628 deferredResult.addCallback(MochiKit.Base.partial(MochiKit.Async.succeed, aValue));
629 // deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("1.2.2 - PRNG.deferredEntropyCollection - 2: " + res); return res;});
630 MochiKit.Signal.connect(this,
631 'readyToGenerateRandomBytes',
632 deferredResult,
633 'callback');
634
635 result = deferredResult;
636 }
637//MochiKit.Logging.logDebug("<<< PRNG.deferredEntropyCollection - result: " + result);
638
639 return result;
640 },
641
642 //-------------------------------------------------------------------------
643
644 'fastEntropyAccumulationForTestingPurpose': function() {
645 while (! this.isReadyToGenerateRandomValues()) {
646 this.addRandomByte(Math.floor(Math.random() * 32), Math.floor(Math.random() * 32), Math.floor(Math.random() * 256));
647 }
648 },
649
650 //-------------------------------------------------------------------------
651
652 'dump': function(appendToDoc) {
653 var tbl;
654 var i,c;
655
656 tbl = document.createElement("table");
657 tbl.border = 0;
658 with (tbl.style) {
659 border = "1px solid lightgrey";
660 fontFamily = 'Helvetica, Arial, sans-serif';
661 fontSize = '8pt';
662 //borderCollapse = "collapse";
663 }
664 var hdr = tbl.createTHead();
665 var hdrtr = hdr.insertRow(0);
666 // document.createElement("tr");
667 {
668 var ntd;
669
670 ntd = hdrtr.insertCell(0);
671 ntd.style.borderBottom = "1px solid lightgrey";
672 ntd.style.borderRight = "1px solid lightgrey";
673 ntd.appendChild(document.createTextNode("#"));
674
675 ntd = hdrtr.insertCell(1);
676 ntd.style.borderBottom = "1px solid lightgrey";
677 ntd.style.borderRight = "1px solid lightgrey";
678 ntd.appendChild(document.createTextNode("s"));
679
680 ntd = hdrtr.insertCell(2);
681 ntd.colSpan = this.firstPoolReseedLevel();
682 ntd.style.borderBottom = "1px solid lightgrey";
683 ntd.style.borderRight = "1px solid lightgrey";
684 ntd.appendChild(document.createTextNode("base values"));
685
686 ntd = hdrtr.insertCell(3);
687 ntd.colSpan = 20;
688 ntd.style.borderBottom = "1px solid lightgrey";
689 ntd.appendChild(document.createTextNode("extra values"));
690
691 }
692
693 c = this.accumulators().length;
694 for (i=0; i<c ; i++) {
695 varcurrentAccumulator;
696 var bdytr;
697 var bdytd;
698 var ii, cc;
699
700 currentAccumulator = this.accumulators()[i]
701
702 bdytr = tbl.insertRow(true);
703
704 bdytd = bdytr.insertCell(0);
705 bdytd.style.borderRight = "1px solid lightgrey";
706 bdytd.style.color = "lightgrey";
707 bdytd.appendChild(document.createTextNode("" + i));
708
709 bdytd = bdytr.insertCell(1);
710 bdytd.style.borderRight = "1px solid lightgrey";
711 bdytd.style.color = "gray";
712 bdytd.appendChild(document.createTextNode("" + currentAccumulator.stack().length()));
713
714
715 cc = Math.max(currentAccumulator.stack().length(), this.firstPoolReseedLevel());
716 for (ii=0; ii<cc; ii++) {
717 var cellText;
718
719 bdytd = bdytr.insertCell(ii + 2);
720
721 if (ii < currentAccumulator.stack().length()) {
722 cellText = Clipperz.ByteArray.byteToHex(currentAccumulator.stack().byteAtIndex(ii));
723 } else {
724 cellText = "_";
725 }
726
727 if (ii == (this.firstPoolReseedLevel() - 1)) {
728 bdytd.style.borderRight = "1px solid lightgrey";
729 }
730
731 bdytd.appendChild(document.createTextNode(cellText));
732 }
733
734 }
735
736
737 if (appendToDoc) {
738 var ne = document.createElement("div");
739 ne.id = "entropyGeneratorStatus";
740 with (ne.style) {
741 fontFamily = "Courier New, monospace";
742 fontSize = "12px";
743 lineHeight = "16px";
744 borderTop = "1px solid black";
745 padding = "10px";
746 }
747 if (document.getElementById(ne.id)) {
748 MochiKit.DOM.swapDOM(ne.id, ne);
749 } else {
750 document.body.appendChild(ne);
751 }
752 ne.appendChild(tbl);
753 }
754
755 return tbl;
756 },
757
758 //-----------------------------------------------------------------------------
759 __syntaxFix__: "syntax fix"
760});
761
762//#############################################################################
763
764Clipperz.Crypto.PRNG.Random = function(args) {
765 args = args || {};
766 //MochiKit.Base.bindMethods(this);
767
768 return this;
769}
770
771Clipperz.Crypto.PRNG.Random.prototype = MochiKit.Base.update(null, {
772
773 'toString': function() {
774 return "Clipperz.Crypto.PRNG.Random";
775 },
776
777 //-------------------------------------------------------------------------
778
779 'getRandomBytes': function(aSize) {
780//Clipperz.Profile.start("Clipperz.Crypto.PRNG.Random.getRandomBytes");
781 varresult;
782 var i,c;
783
784 result = new Clipperz.ByteArray()
785 c = aSize || 1;
786 for (i=0; i<c; i++) {
787 result.appendByte((Math.random()*255) & 0xff);
788 }
789
790//Clipperz.Profile.stop("Clipperz.Crypto.PRNG.Random.getRandomBytes");
791 return result;
792 },
793
794 //-------------------------------------------------------------------------
795 __syntaxFix__: "syntax fix"
796});
797
798//#############################################################################
799
800_clipperz_crypt_prng_defaultPRNG = null;
801
802Clipperz.Crypto.PRNG.defaultRandomGenerator = function() {
803 if (_clipperz_crypt_prng_defaultPRNG == null) {
804 _clipperz_crypt_prng_defaultPRNG = new Clipperz.Crypto.PRNG.Fortuna();
805
806 //.............................................................
807 //
808 // TimeRandomnessSource
809 //
810 //.............................................................
811 {
812 var newRandomnessSource;
813
814 newRandomnessSource = new Clipperz.Crypto.PRNG.TimeRandomnessSource({intervalTime:111});
815 _clipperz_crypt_prng_defaultPRNG.addRandomnessSource(newRandomnessSource);
816 }
817
818 //.............................................................
819 //
820 // MouseRandomnessSource
821 //
822 //.............................................................
823 {
824 varnewRandomnessSource;
825
826 newRandomnessSource = new Clipperz.Crypto.PRNG.MouseRandomnessSource();
827 _clipperz_crypt_prng_defaultPRNG.addRandomnessSource(newRandomnessSource);
828 }
829
830 //.............................................................
831 //
832 // KeyboardRandomnessSource
833 //
834 //.............................................................
835 {
836 varnewRandomnessSource;
837
838 newRandomnessSource = new Clipperz.Crypto.PRNG.KeyboardRandomnessSource();
839 _clipperz_crypt_prng_defaultPRNG.addRandomnessSource(newRandomnessSource);
840 }
841
842 }
843
844 return _clipperz_crypt_prng_defaultPRNG;
845};
846
847//#############################################################################
848
849Clipperz.Crypto.PRNG.exception = {
850 NotEnoughEntropy: new MochiKit.Base.NamedError("Clipperz.Crypto.PRNG.exception.NotEnoughEntropy")
851};
852
853
854MochiKit.DOM.addLoadEvent(Clipperz.Crypto.PRNG.defaultRandomGenerator);
diff --git a/frontend/beta/js/Clipperz/Crypto/RSA.js b/frontend/beta/js/Clipperz/Crypto/RSA.js
new file mode 100644
index 0000000..4dad8f7
--- a/dev/null
+++ b/frontend/beta/js/Clipperz/Crypto/RSA.js
@@ -0,0 +1,151 @@
1/*
2
3Copyright 2008-2011 Clipperz Srl
4
5This file is part of Clipperz's Javascript Crypto Library.
6Javascript Crypto Library provides web developers with an extensive
7and efficient set of cryptographic functions. The library aims to
8obtain maximum execution speed while preserving modularity and
9reusability.
10For further information about its features and functionalities please
11refer to http://www.clipperz.com
12
13* Javascript Crypto Library is free software: you can redistribute
14 it and/or modify it under the terms of the GNU Affero General Public
15 License as published by the Free Software Foundation, either version
16 3 of the License, or (at your option) any later version.
17
18* Javascript Crypto Library is distributed in the hope that it will
19 be useful, but WITHOUT ANY WARRANTY; without even the implied
20 warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
21 See the GNU Affero General Public License for more details.
22
23* You should have received a copy of the GNU Affero General Public
24 License along with Javascript Crypto Library. If not, see
25 <http://www.gnu.org/licenses/>.
26
27*/
28
29try { if (typeof(Clipperz.Crypto.BigInt) == 'undefined') { throw ""; }} catch (e) {
30 throw "Clipperz.Crypto.RSA depends on Clipperz.Crypto.BigInt!";
31}
32
33if (typeof(Clipperz.Crypto.RSA) == 'undefined') { Clipperz.Crypto.RSA = {}; }
34
35Clipperz.Crypto.RSA.VERSION = "0.1";
36Clipperz.Crypto.RSA.NAME = "Clipperz.RSA";
37
38//#############################################################################
39
40MochiKit.Base.update(Clipperz.Crypto.RSA, {
41
42 //-------------------------------------------------------------------------
43
44 'publicKeyWithValues': function (e, d, n) {
45 varresult;
46
47 result = {};
48
49 if (e.isBigInt) {
50 result.e = e;
51 } else {
52 result.e = new Clipperz.Crypto.BigInt(e, 16);
53 }
54
55 if (d.isBigInt) {
56 result.d = d;
57 } else {
58 result.d = new Clipperz.Crypto.BigInt(d, 16);
59 }
60
61 if (n.isBigInt) {
62 result.n = n;
63 } else {
64 result.n = new Clipperz.Crypto.BigInt(n, 16);
65 }
66
67 return result;
68 },
69
70 'privateKeyWithValues': function(e, d, n) {
71 return Clipperz.Crypto.RSA.publicKeyWithValues(e, d, n);
72 },
73
74 //-----------------------------------------------------------------------------
75
76 'encryptUsingPublicKey': function (aKey, aMessage) {
77 varmessageValue;
78 varresult;
79
80 messageValue = new Clipperz.Crypto.BigInt(aMessage, 16);
81 result = messageValue.powerModule(aKey.e, aKey.n);
82
83 return result.asString(16);
84 },
85
86 //.............................................................................
87
88 'decryptUsingPublicKey': function (aKey, aMessage) {
89 return Clipperz.Crypto.RSA.encryptUsingPublicKey(aKey, aMessage);
90 },
91
92 //-----------------------------------------------------------------------------
93
94 'encryptUsingPrivateKey': function (aKey, aMessage) {
95 varmessageValue;
96 varresult;
97
98 messageValue = new Clipperz.Crypto.BigInt(aMessage, 16);
99 result = messageValue.powerModule(aKey.d, aKey.n);
100
101 return result.asString(16);
102 },
103
104 //.............................................................................
105
106 'decryptUsingPrivateKey': function (aKey, aMessage) {
107 return Clipperz.Crypto.RSA.encryptUsingPrivateKey(aKey, aMessage);
108 },
109
110 //-----------------------------------------------------------------------------
111
112 'generatePublicKey': function(aNumberOfBits) {
113 varresult;
114 vare;
115 vard;
116 varn;
117
118 e = new Clipperz.Crypto.BigInt("10001", 16);
119
120 {
121 var p, q;
122 varphi;
123
124 do {
125 p = Clipperz.Crypto.BigInt.randomPrime(aNumberOfBits);
126 } while (p.module(e).equals(1));
127
128 do {
129 q = Clipperz.Crypto.BigInt.randomPrime(aNumberOfBits);
130 } while ((q.equals(p)) || (q.module(e).equals(1)));
131
132 n = p.multiply(q);
133 phi = (p.subtract(1).multiply(q.subtract(1)));
134 d = e.powerModule(-1, phi);
135 }
136
137 result = Clipperz.Crypto.RSA.publicKeyWithValues(e, d, n);
138
139 return result;
140 },
141
142 //-------------------------------------------------------------------------
143
144 __syntaxFix__: "syntax fix"
145
146 //-------------------------------------------------------------------------
147
148});
149
150//#############################################################################
151
diff --git a/frontend/beta/js/Clipperz/Crypto/SHA.js b/frontend/beta/js/Clipperz/Crypto/SHA.js
new file mode 100644
index 0000000..bb50b4f
--- a/dev/null
+++ b/frontend/beta/js/Clipperz/Crypto/SHA.js
@@ -0,0 +1,296 @@
1/*
2
3Copyright 2008-2011 Clipperz Srl
4
5This file is part of Clipperz's Javascript Crypto Library.
6Javascript Crypto Library provides web developers with an extensive
7and efficient set of cryptographic functions. The library aims to
8obtain maximum execution speed while preserving modularity and
9reusability.
10For further information about its features and functionalities please
11refer to http://www.clipperz.com
12
13* Javascript Crypto Library is free software: you can redistribute
14 it and/or modify it under the terms of the GNU Affero General Public
15 License as published by the Free Software Foundation, either version
16 3 of the License, or (at your option) any later version.
17
18* Javascript Crypto Library is distributed in the hope that it will
19 be useful, but WITHOUT ANY WARRANTY; without even the implied
20 warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
21 See the GNU Affero General Public License for more details.
22
23* You should have received a copy of the GNU Affero General Public
24 License along with Javascript Crypto Library. If not, see
25 <http://www.gnu.org/licenses/>.
26
27*/
28
29try { if (typeof(Clipperz.ByteArray) == 'undefined') { throw ""; }} catch (e) {
30 throw "Clipperz.Crypto.PRNG depends on Clipperz.ByteArray!";
31}
32
33if (typeof(Clipperz.Crypto) == 'undefined') { Clipperz.Crypto = {}; }
34if (typeof(Clipperz.Crypto.SHA) == 'undefined') { Clipperz.Crypto.SHA = {}; }
35
36Clipperz.Crypto.SHA.VERSION = "0.3";
37Clipperz.Crypto.SHA.NAME = "Clipperz.Crypto.SHA";
38
39MochiKit.Base.update(Clipperz.Crypto.SHA, {
40
41 '__repr__': function () {
42 return "[" + this.NAME + " " + this.VERSION + "]";
43 },
44
45 'toString': function () {
46 return this.__repr__();
47 },
48
49 //-----------------------------------------------------------------------------
50
51 'rotateRight': function(aValue, aNumberOfBits) {
52//Clipperz.Profile.start("Clipperz.Crypto.SHA.rotateRight");
53 var result;
54
55 result = (aValue >>> aNumberOfBits) | (aValue << (32 - aNumberOfBits));
56
57//Clipperz.Profile.stop("Clipperz.Crypto.SHA.rotateRight");
58 return result;
59 },
60
61 'shiftRight': function(aValue, aNumberOfBits) {
62//Clipperz.Profile.start("Clipperz.Crypto.SHA.shiftRight");
63 var result;
64
65 result = aValue >>> aNumberOfBits;
66
67//Clipperz.Profile.stop("Clipperz.Crypto.SHA.shiftRight");
68 return result;
69 },
70
71 //-----------------------------------------------------------------------------
72
73 'safeAdd': function() {
74//Clipperz.Profile.start("Clipperz.Crypto.SHA.safeAdd");
75 varresult;
76 vari, c;
77
78 result = arguments[0];
79 c = arguments.length;
80 for (i=1; i<c; i++) {
81 varlowerBytesSum;
82
83 lowerBytesSum = (result & 0xffff) + (arguments[i] & 0xffff);
84 result = (((result >> 16) + (arguments[i] >> 16) + (lowerBytesSum >> 16)) << 16) | (lowerBytesSum & 0xffff);
85 }
86
87//Clipperz.Profile.stop("Clipperz.Crypto.SHA.safeAdd");
88 return result;
89 },
90
91 //-----------------------------------------------------------------------------
92
93 'sha256_array': function(aValue) {
94//Clipperz.Profile.start("Clipperz.Crypto.SHA.sha256_array");
95 varresult;
96 varmessage;
97 var h0, h1, h2, h3, h4, h5, h6, h7;
98 vark;
99 varmessageLength;
100 varmessageLengthInBits;
101 var_i, _c;
102 var charBits;
103 var rotateRight;
104 var shiftRight;
105 var safeAdd;
106 varbytesPerBlock;
107 var currentMessageIndex;
108
109 bytesPerBlock = 512/8;
110 rotateRight = Clipperz.Crypto.SHA.rotateRight;
111 shiftRight = Clipperz.Crypto.SHA.shiftRight;
112 safeAdd = Clipperz.Crypto.SHA.safeAdd;
113
114 charBits = 8;
115
116 h0 = 0x6a09e667;
117 h1 = 0xbb67ae85;
118 h2 = 0x3c6ef372;
119 h3 = 0xa54ff53a;
120 h4 = 0x510e527f;
121 h5 = 0x9b05688c;
122 h6 = 0x1f83d9ab;
123 h7 = 0x5be0cd19;
124
125 k = [0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
126 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
127 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
128 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
129 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
130 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
131 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
132 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2];
133
134 message = aValue;
135 messageLength = message.length;
136
137 //Pre-processing:
138 message.push(0x80); //append a single "1" bit to message
139
140 _c = (512 - (((messageLength + 1) * charBits) % 512) - 64) / charBits;
141 for (_i=0; _i<_c; _i++) {
142 message.push(0x00); //append "0" bits until message length ≡ 448 ≡ -64 (mod 512)
143 }
144 messageLengthInBits = messageLength * charBits;
145 message.push(0x00); //the 4 most high byte are alway 0 as message length is represented with a 32bit value;
146 message.push(0x00);
147 message.push(0x00);
148 message.push(0x00);
149 message.push((messageLengthInBits >> 24)& 0xff);
150 message.push((messageLengthInBits >> 16)& 0xff);
151 message.push((messageLengthInBits >> 8) & 0xff);
152 message.push( messageLengthInBits & 0xff);
153
154 currentMessageIndex = 0;
155 while(currentMessageIndex < message.length) {
156 varw;
157 vara, b, c, d, e, f, g, h;
158
159 w = Array(64);
160
161 _c = 16;
162 for (_i=0; _i<_c; _i++) {
163 var _j;
164
165 _j = currentMessageIndex + _i*4;
166 w[_i] = (message[_j] << 24) | (message[_j + 1] << 16) | (message[_j + 2] << 8) | (message[_j + 3] << 0);
167 }
168
169 _c = 64;
170 for (_i=16; _i<_c; _i++) {
171 vars0, s1;
172
173 s0 = (rotateRight(w[_i-15], 7)) ^ (rotateRight(w[_i-15], 18)) ^ (shiftRight(w[_i-15], 3));
174 s1 = (rotateRight(w[_i-2], 17)) ^ (rotateRight(w[_i-2], 19)) ^ (shiftRight(w[_i-2], 10));
175 w[_i] = safeAdd(w[_i-16], s0, w[_i-7], s1);
176 }
177
178 a=h0; b=h1; c=h2; d=h3; e=h4; f=h5; g=h6; h=h7;
179
180 _c = 64;
181 for (_i=0; _i<_c; _i++) {
182 var s0, s1, ch, maj, t1, t2;
183
184 s0 = (rotateRight(a, 2)) ^ (rotateRight(a, 13)) ^ (rotateRight(a, 22));
185 maj = (a & b) ^ (a & c) ^ (b & c);
186 t2 = safeAdd(s0, maj);
187 s1 = (rotateRight(e, 6)) ^ (rotateRight(e, 11)) ^ (rotateRight(e, 25));
188 ch = (e & f) ^ ((~e) & g);
189 t1 = safeAdd(h, s1, ch, k[_i], w[_i]);
190
191 h = g;
192 g = f;
193 f = e;
194 e = safeAdd(d, t1);
195 d = c;
196 c = b;
197 b = a;
198 a = safeAdd(t1, t2);
199 }
200
201 h0 = safeAdd(h0, a);
202 h1 = safeAdd(h1, b);
203 h2 = safeAdd(h2, c);
204 h3 = safeAdd(h3, d);
205 h4 = safeAdd(h4, e);
206 h5 = safeAdd(h5, f);
207 h6 = safeAdd(h6, g);
208 h7 = safeAdd(h7, h);
209
210 currentMessageIndex += bytesPerBlock;
211 }
212
213 result = new Array(256/8);
214 result[0] = (h0 >> 24)& 0xff;
215 result[1] = (h0 >> 16)& 0xff;
216 result[2] = (h0 >> 8)& 0xff;
217 result[3] = h0 & 0xff;
218
219 result[4] = (h1 >> 24)& 0xff;
220 result[5] = (h1 >> 16)& 0xff;
221 result[6] = (h1 >> 8)& 0xff;
222 result[7] = h1 & 0xff;
223
224 result[8] = (h2 >> 24)& 0xff;
225 result[9] = (h2 >> 16)& 0xff;
226 result[10] = (h2 >> 8)& 0xff;
227 result[11] = h2 & 0xff;
228
229 result[12] = (h3 >> 24)& 0xff;
230 result[13] = (h3 >> 16)& 0xff;
231 result[14] = (h3 >> 8)& 0xff;
232 result[15] = h3 & 0xff;
233
234 result[16] = (h4 >> 24)& 0xff;
235 result[17] = (h4 >> 16)& 0xff;
236 result[18] = (h4 >> 8)& 0xff;
237 result[19] = h4 & 0xff;
238
239 result[20] = (h5 >> 24)& 0xff;
240 result[21] = (h5 >> 16)& 0xff;
241 result[22] = (h5 >> 8)& 0xff;
242 result[23] = h5 & 0xff;
243
244 result[24] = (h6 >> 24)& 0xff;
245 result[25] = (h6 >> 16)& 0xff;
246 result[26] = (h6 >> 8)& 0xff;
247 result[27] = h6 & 0xff;
248
249 result[28] = (h7 >> 24)& 0xff;
250 result[29] = (h7 >> 16)& 0xff;
251 result[30] = (h7 >> 8)& 0xff;
252 result[31] = h7 & 0xff;
253
254//Clipperz.Profile.stop("Clipperz.Crypto.SHA.sha256_array");
255 return result;
256 },
257
258 //-----------------------------------------------------------------------------
259
260 'sha256': function(aValue) {
261//Clipperz.Profile.start("Clipperz.Crypto.SHA.sha256");
262 var result;
263 var resultArray;
264 varvalueArray;
265
266 valueArray = aValue.arrayValues();
267 resultArray = Clipperz.Crypto.SHA.sha256_array(valueArray);
268
269 result = new Clipperz.ByteArray(resultArray);
270
271//Clipperz.Profile.stop("Clipperz.Crypto.SHA.sha256");
272 return result;
273 },
274
275 //-----------------------------------------------------------------------------
276
277 'sha_d256': function(aValue) {
278//Clipperz.Profile.start("Clipperz.Crypto.SHA.sha_d256");
279 var result;
280 var resultArray;
281 varvalueArray;
282
283 valueArray = aValue.arrayValues();
284 resultArray = Clipperz.Crypto.SHA.sha256_array(valueArray);
285 resultArray = Clipperz.Crypto.SHA.sha256_array(resultArray);
286
287 result = new Clipperz.ByteArray(resultArray);
288
289//Clipperz.Profile.stop("Clipperz.Crypto.SHA.sha256");
290 return result;
291 },
292
293 //-----------------------------------------------------------------------------
294 __syntaxFix__: "syntax fix"
295
296});
diff --git a/frontend/beta/js/Clipperz/Crypto/SRP.js b/frontend/beta/js/Clipperz/Crypto/SRP.js
new file mode 100644
index 0000000..0eef6ec
--- a/dev/null
+++ b/frontend/beta/js/Clipperz/Crypto/SRP.js
@@ -0,0 +1,331 @@
1/*
2
3Copyright 2008-2011 Clipperz Srl
4
5This file is part of Clipperz's Javascript Crypto Library.
6Javascript Crypto Library provides web developers with an extensive
7and efficient set of cryptographic functions. The library aims to
8obtain maximum execution speed while preserving modularity and
9reusability.
10For further information about its features and functionalities please
11refer to http://www.clipperz.com
12
13* Javascript Crypto Library is free software: you can redistribute
14 it and/or modify it under the terms of the GNU Affero General Public
15 License as published by the Free Software Foundation, either version
16 3 of the License, or (at your option) any later version.
17
18* Javascript Crypto Library is distributed in the hope that it will
19 be useful, but WITHOUT ANY WARRANTY; without even the implied
20 warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
21 See the GNU Affero General Public License for more details.
22
23* You should have received a copy of the GNU Affero General Public
24 License along with Javascript Crypto Library. If not, see
25 <http://www.gnu.org/licenses/>.
26
27*/
28
29try { if (typeof(Clipperz.ByteArray) == 'undefined') { throw ""; }} catch (e) {
30 throw "Clipperz.Crypto.PRNG depends on Clipperz.ByteArray!";
31}
32
33try { if (typeof(Clipperz.Crypto.BigInt) == 'undefined') { throw ""; }} catch (e) {
34 throw "Clipperz.Crypto.SRP depends on Clipperz.Crypto.BigInt!";
35}
36
37try { if (typeof(Clipperz.Crypto.PRNG) == 'undefined') { throw ""; }} catch (e) {
38 throw "Clipperz.Crypto.SRP depends on Clipperz.Crypto.PRNG!";
39}
40
41if (typeof(Clipperz.Crypto.SRP) == 'undefined') { Clipperz.Crypto.SRP = {}; }
42
43Clipperz.Crypto.SRP.VERSION = "0.1";
44Clipperz.Crypto.SRP.NAME = "Clipperz.Crypto.SRP";
45
46//#############################################################################
47
48MochiKit.Base.update(Clipperz.Crypto.SRP, {
49
50 '_n': null,
51 '_g': null,
52 //-------------------------------------------------------------------------
53
54 'n': function() {
55 if (Clipperz.Crypto.SRP._n == null) {
56 Clipperz.Crypto.SRP._n = new Clipperz.Crypto.BigInt("115b8b692e0e045692cf280b436735c77a5a9e8a9e7ed56c965f87db5b2a2ece3", 16);
57 }
58
59 return Clipperz.Crypto.SRP._n;
60 },
61
62 //-------------------------------------------------------------------------
63
64 'g': function() {
65 if (Clipperz.Crypto.SRP._g == null) {
66 Clipperz.Crypto.SRP._g = new Clipperz.Crypto.BigInt(2); //eventually 5 (as suggested on the Diffi-Helmann documentation)
67 }
68
69 return Clipperz.Crypto.SRP._g;
70 },
71
72 //-----------------------------------------------------------------------------
73
74 'exception': {
75 'InvalidValue': new MochiKit.Base.NamedError("Clipperz.Crypto.SRP.exception.InvalidValue")
76 },
77
78 //-------------------------------------------------------------------------
79 __syntaxFix__: "syntax fix"
80
81});
82
83//#############################################################################
84//
85 // S R P C o n n e c t i o n version 1.0
86//
87//=============================================================================
88Clipperz.Crypto.SRP.Connection = function (args) {
89 args = args || {};
90
91 this._C = args.C;
92 this._P = args.P;
93 this.hash = args.hash;
94
95 this._a = null;
96 this._A = null;
97
98 this._s = null;
99 this._B = null;
100
101 this._x = null;
102
103 this._u = null;
104 this._K = null;
105 this._M1 = null;
106 this._M2 = null;
107
108 this._sessionKey = null;
109
110 return this;
111}
112
113Clipperz.Crypto.SRP.Connection.prototype = MochiKit.Base.update(null, {
114
115 'toString': function () {
116 return "Clipperz.Crypto.SRP.Connection (username: " + this.username() + "). Status: " + this.statusDescription();
117 },
118
119 //-------------------------------------------------------------------------
120
121 'C': function () {
122 return this._C;
123 },
124
125 //-------------------------------------------------------------------------
126
127 'P': function () {
128 return this._P;
129 },
130
131 //-------------------------------------------------------------------------
132
133 'a': function () {
134 if (this._a == null) {
135 this._a = new Clipperz.Crypto.BigInt(Clipperz.Crypto.PRNG.defaultRandomGenerator().getRandomBytes(32).toHexString().substring(2), 16);
136 // this._a = new Clipperz.Crypto.BigInt("37532428169486597638072888476611365392249575518156687476805936694442691012367", 10);
137//MochiKit.Logging.logDebug("SRP a: " + this._a);
138 }
139
140 return this._a;
141 },
142
143 //-------------------------------------------------------------------------
144
145 'A': function () {
146 if (this._A == null) {
147 //Warning: this value should be strictly greater than zero: how should we perform this check?
148 this._A = Clipperz.Crypto.SRP.g().powerModule(this.a(), Clipperz.Crypto.SRP.n());
149
150 if (this._A.equals(0)) {
151MochiKit.Logging.logError("Clipperz.Crypto.SRP.Connection: trying to set 'A' to 0.");
152 throw Clipperz.Crypto.SRP.exception.InvalidValue;
153 }
154//MochiKit.Logging.logDebug("SRP A: " + this._A);
155 }
156
157 return this._A;
158 },
159
160 //-------------------------------------------------------------------------
161
162 's': function () {
163 return this._s;
164//MochiKit.Logging.logDebug("SRP s: " + this._S);
165 },
166
167 'set_s': function(aValue) {
168 this._s = aValue;
169 },
170
171 //-------------------------------------------------------------------------
172
173 'B': function () {
174 return this._B;
175 },
176
177 'set_B': function(aValue) {
178 //Warning: this value should be strictly greater than zero: how should we perform this check?
179 if (! aValue.equals(0)) {
180 this._B = aValue;
181//MochiKit.Logging.logDebug("SRP B: " + this._B);
182 } else {
183MochiKit.Logging.logError("Clipperz.Crypto.SRP.Connection: trying to set 'B' to 0.");
184 throw Clipperz.Crypto.SRP.exception.InvalidValue;
185 }
186 },
187
188 //-------------------------------------------------------------------------
189
190 'x': function () {
191 if (this._x == null) {
192 this._x = new Clipperz.Crypto.BigInt(this.stringHash(this.s().asString(16, 64) + this.P()), 16);
193//MochiKit.Logging.logDebug("SRP x: " + this._x);
194 }
195
196 return this._x;
197 },
198
199 //-------------------------------------------------------------------------
200
201 'u': function () {
202 if (this._u == null) {
203 this._u = new Clipperz.Crypto.BigInt(this.stringHash(this.B().asString()), 16);
204//MochiKit.Logging.logDebug("SRP u: " + this._u);
205 }
206
207 return this._u;
208 },
209
210 //-------------------------------------------------------------------------
211
212 'S': function () {
213 if (this._S == null) {
214 var bigint;
215 varsrp;
216
217 bigint = Clipperz.Crypto.BigInt;
218 srp = Clipperz.Crypto.SRP;
219
220 this._S =bigint.powerModule(
221 bigint.subtract(this.B(), bigint.powerModule(srp.g(), this.x(), srp.n())),
222 bigint.add(this.a(), bigint.multiply(this.u(), this.x())),
223 srp.n()
224 )
225//MochiKit.Logging.logDebug("SRP S: " + this._S);
226 }
227
228 return this._S;
229 },
230
231 //-------------------------------------------------------------------------
232
233 'K': function () {
234 if (this._K == null) {
235 this._K = this.stringHash(this.S().asString());
236//MochiKit.Logging.logDebug("SRP K: " + this._K);
237 }
238
239 return this._K;
240 },
241
242 //-------------------------------------------------------------------------
243
244 'M1': function () {
245 if (this._M1 == null) {
246 this._M1 = this.stringHash(this.A().asString(10) + this.B().asString(10) + this.K());
247//MochiKit.Logging.logDebug("SRP M1: " + this._M1);
248 }
249
250 return this._M1;
251 },
252
253 //-------------------------------------------------------------------------
254
255 'M2': function () {
256 if (this._M2 == null) {
257 this._M2 = this.stringHash(this.A().asString(10) + this.M1() + this.K());
258//MochiKit.Logging.logDebug("SRP M2: " + this._M2);
259 }
260
261 return this._M2;
262 },
263
264 //=========================================================================
265
266 'serverSideCredentialsWithSalt': function(aSalt) {
267 var result;
268 var s, x, v;
269
270 s = aSalt;
271 x = this.stringHash(s + this.P());
272 v = Clipperz.Crypto.SRP.g().powerModule(new Clipperz.Crypto.BigInt(x, 16), Clipperz.Crypto.SRP.n());
273
274 result = {};
275 result['C'] = this.C();
276 result['s'] = s;
277 result['v'] = v.asString(16);
278
279 return result;
280 },
281
282 'serverSideCredentials': function() {
283 var result;
284 var s;
285
286 s = Clipperz.Crypto.PRNG.defaultRandomGenerator().getRandomBytes(32).toHexString().substring(2);
287
288 result = this.serverSideCredentialsWithSalt(s);
289
290 return result;
291 },
292
293 //=========================================================================
294/*
295 'computeServerSide_S': function(b) {
296 var result;
297 var v;
298 var bigint;
299 varsrp;
300
301 bigint = Clipperz.Crypto.BigInt;
302 srp = Clipperz.Crypto.SRP;
303
304 v = new Clipperz.Crypto.BigInt(srpConnection.serverSideCredentialsWithSalt(this.s().asString(16, 64)).v, 16);
305 // _S = (this.A().multiply(this.v().modPow(this.u(), this.n()))).modPow(this.b(), this.n());
306 result = bigint.powerModule(
307 bigint.multiply(
308 this.A(),
309 bigint.powerModule(v, this.u(), srp.n())
310 ), new Clipperz.Crypto.BigInt(b, 10), srp.n()
311 );
312
313 return result;
314 },
315*/
316 //=========================================================================
317
318 'stringHash': function(aValue) {
319 varresult;
320
321 result = this.hash(new Clipperz.ByteArray(aValue)).toHexString().substring(2);
322
323 return result;
324 },
325
326 //=========================================================================
327 __syntaxFix__: "syntax fix"
328
329});
330
331//#############################################################################
diff --git a/frontend/beta/js/Clipperz/DOM.js b/frontend/beta/js/Clipperz/DOM.js
new file mode 100644
index 0000000..7c27359
--- a/dev/null
+++ b/frontend/beta/js/Clipperz/DOM.js
@@ -0,0 +1,131 @@
1/*
2
3Copyright 2008-2011 Clipperz Srl
4
5This file is part of Clipperz's Javascript Crypto Library.
6Javascript Crypto Library provides web developers with an extensive
7and efficient set of cryptographic functions. The library aims to
8obtain maximum execution speed while preserving modularity and
9reusability.
10For further information about its features and functionalities please
11refer to http://www.clipperz.com
12
13* Javascript Crypto Library is free software: you can redistribute
14 it and/or modify it under the terms of the GNU Affero General Public
15 License as published by the Free Software Foundation, either version
16 3 of the License, or (at your option) any later version.
17
18* Javascript Crypto Library is distributed in the hope that it will
19 be useful, but WITHOUT ANY WARRANTY; without even the implied
20 warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
21 See the GNU Affero General Public License for more details.
22
23* You should have received a copy of the GNU Affero General Public
24 License along with Javascript Crypto Library. If not, see
25 <http://www.gnu.org/licenses/>.
26
27*/
28
29if (typeof(Clipperz) == 'undefined') { Clipperz = {}; }
30if (typeof(Clipperz.DOM) == 'undefined') { Clipperz.DOM = {}; }
31
32Clipperz.DOM.VERSION = "0.1";
33Clipperz.DOM.NAME = "Clipperz.DOM";
34
35MochiKit.Base.update(Clipperz.DOM, {
36
37 //-------------------------------------------------------------------------
38
39 '__repr__': function () {
40 return "[" + this.NAME + " " + this.VERSION + "]";
41 },
42
43 //-------------------------------------------------------------------------
44
45 'toString': function () {
46 return this.__repr__();
47 },
48
49 //-------------------------------------------------------------------------
50
51 'selectOptionMatchingValue': function (aSelectElement, aValue, shouldUseCaseInsensitiveTest) {
52 var selectedOptionIndex;
53 var i, c;
54
55 selectedOptionIndex = -1;
56
57 c = aSelectElement.options.length;
58 for (i=0; (i<c) && (selectedOptionIndex == -1); i++) {
59 if (shouldUseCaseInsensitiveTest == true) {
60 if (aSelectElement.options[i].value.toLowerCase() == aValue.toLowerCase()) {
61 selectedOptionIndex = i;
62 }
63 } else {
64 if (aSelectElement.options[i].value == aValue) {
65 selectedOptionIndex = i;
66 }
67 }
68 }
69
70 if (selectedOptionIndex != -1) {
71 aSelectElement.selectedIndex = selectedOptionIndex;
72 }
73 },
74
75 //-------------------------------------------------------------------------
76
77 'setFormContents': function(aNode, someValues) {
78 var node;
79 var values;
80 var i, c;
81
82 values = {};
83 c = someValues[0].length;
84 for (i=0; i<c; i++) {
85 values[someValues[0][i]] = someValues[1][i];
86 }
87
88 // var m = MochiKit.Base;
89 // var self = MochiKit.DOM;
90 if (typeof(aNode) == "undefined" || aNode === null) {
91 node = MochiKit.DOM._document.body;
92 } else {
93 node = MochiKit.DOM.getElement(aNode);
94 }
95
96 MochiKit.Base.nodeWalk(node, function(aNode) {
97 var result;
98 var name;
99
100 result = null;
101 name = aNode.name;
102 if (MochiKit.Base.isNotEmpty(name) && (typeof(values[name]) != 'undefined')) {
103 var tagName;
104
105 tagName = aNode.tagName.toUpperCase();
106 if (tagName === "INPUT" && (aNode.type == "radio" || aNode.type == "checkbox")) {
107 aNode.checked = values[name];
108 } else if (tagName === "SELECT") {
109 if (aNode.type == "select-one") {
110 Clipperz.DOM.selectOptionMatchingValue(aNode, values[name]);
111 } else { //aNode.type == "select-multiple"
112MochiKit.Logging.logWarning("### unhandled Select.type = 'select-multiple' condition");
113 }
114 } else if (tagName === "FORM" || tagName === "P" || tagName === "SPAN" || tagName === "DIV") {
115 result = aNode.childNodes;
116 } else {
117 aNode.value = values[name]
118 }
119 } else {
120 result = aNode.childNodes;
121 }
122
123 return result;
124 });
125 },
126
127 //-------------------------------------------------------------------------
128 __syntaxFix__: "syntax fix"
129
130});
131
diff --git a/frontend/beta/js/Clipperz/Date.js b/frontend/beta/js/Clipperz/Date.js
new file mode 100644
index 0000000..4103b88
--- a/dev/null
+++ b/frontend/beta/js/Clipperz/Date.js
@@ -0,0 +1,305 @@
1/*
2
3Copyright 2008-2011 Clipperz Srl
4
5This file is part of Clipperz's Javascript Crypto Library.
6Javascript Crypto Library provides web developers with an extensive
7and efficient set of cryptographic functions. The library aims to
8obtain maximum execution speed while preserving modularity and
9reusability.
10For further information about its features and functionalities please
11refer to http://www.clipperz.com
12
13* Javascript Crypto Library is free software: you can redistribute
14 it and/or modify it under the terms of the GNU Affero General Public
15 License as published by the Free Software Foundation, either version
16 3 of the License, or (at your option) any later version.
17
18* Javascript Crypto Library is distributed in the hope that it will
19 be useful, but WITHOUT ANY WARRANTY; without even the implied
20 warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
21 See the GNU Affero General Public License for more details.
22
23* You should have received a copy of the GNU Affero General Public
24 License along with Javascript Crypto Library. If not, see
25 <http://www.gnu.org/licenses/>.
26
27*/
28
29if (typeof(Clipperz) == 'undefined') { Clipperz = {}; }
30if (typeof(Clipperz.Date) == 'undefined') { Clipperz.Date = {}; }
31
32Clipperz.Date.VERSION = "0.1";
33Clipperz.Date.NAME = "Clipperz.Date";
34
35MochiKit.Base.update(Clipperz.Date, {
36
37 //-------------------------------------------------------------------------
38
39 '__repr__': function () {
40 return "[" + this.NAME + " " + this.VERSION + "]";
41 },
42
43 //-------------------------------------------------------------------------
44
45 'toString': function () {
46 return this.__repr__();
47 },
48
49 //-------------------------------------------------------------------------
50
51 'daysInMonth': [31,28,31,30,31,30,31,31,30,31,30,31],
52
53 //-------------------------------------------------------------------------
54
55 'englishOrdinalDaySuffixForDate': function(aDate) {
56 var result;
57
58 switch (aDate.getDate()) {
59 case 1:
60 case 21:
61 case 31:
62 result = "st";
63 break;
64 case 2:
65 case 22:
66 result = "nd";
67 break;
68 case 3:
69 case 23:
70 result = "rd";
71 break;
72 default:
73 result = "th";
74 break;
75 }
76
77 return result;
78 },
79
80 //-------------------------------------------------------------------------
81
82 'isLeapYear': function(aDate) {
83 var year;
84 var result;
85
86 year = aDate.getFullYear();
87 result = ((year & 0x03) == 0 && (year % 100 || (year % 400 == 0 && year)));
88
89 return result;
90 },
91
92 //-------------------------------------------------------------------------
93
94 'getDaysInMonth': function(aDate) {
95 var result;
96
97 if (aDate.getMonth() == 1) {
98 Clipperz.Date.isLeapYear(aDate)
99 result += Clipperz.Date.isLeapYear(aDate) ? 29 : 28;
100 } else {
101 result = Clipperz.Date.daysInMonth[aDate.getMonth()];
102 }
103
104 return result;
105 },
106
107 //-------------------------------------------------------------------------
108
109 'getTimezone': function(aDate) {
110 var result;
111
112 result = aDate.toString();
113 result = result.replace(/([A-Z]{3}) [0-9]{4}/, '$1');
114 result = result.replace(/^.*?\(([A-Z])[a-z]+ ([A-Z])[a-z]+ ([A-Z])[a-z]+\)$/, "$1$2$3");
115
116 return result;
117 },
118
119 'getGMTOffset': function(aDate) {
120 return (aDate.getTimezoneOffset() > 0 ? "-" : "+")+ MochiKit.Format.numberFormatter('00')(Math.floor(this.getTimezoneOffset() / 60))
121 + MochiKit.Format.numberFormatter('00')(this.getTimezoneOffset() % 60);
122 },
123
124 //-------------------------------------------------------------------------
125
126 'dayOfYear': function(aDate) {
127 var result;
128 var i,c;
129
130 result = 0;
131 c = aDate.getMonth();
132 for (i=0; i<c; i++) {
133 if (i == 1) {
134 result += Clipperz.Date.isLeapYear(aDate) ? 29 : 28;
135 } else {
136 result += Clipperz.Date.daysInMonth[i];
137 }
138 }
139 return num + this.getDate() - 1;
140 },
141
142 //-------------------------------------------------------------------------
143
144 'getPHPLikeFormatCode': function(aCharacter) {
145 var result;
146
147 switch (aCharacter) {
148 case "d":
149 result = " + MochiKit.Format.numberFormatter('00')(aDate.getDate())";
150 break;
151 case "D":
152 result = " + aLocale['shortDays'][aDate.getDay()]";
153 break;
154 case "j":
155 result = " + aDate.getDate()";
156 break;
157 case "l":
158 result = " + aLocale['days'][aDate.getDay()]";
159 break;
160 case "S":
161 result = " + Clipperz.Date.englishOrdinalDaySuffixForDate(aDate)";
162 break;
163 case "w":
164 result = " + aDate.getDay()";
165 break;
166 case "z":
167 result = " + aDate.getDayOfYear()";
168 break;
169 case "W":
170 result = " + aDate.getWeekOfYear()";
171 break;
172 case "F":
173 result = " + aLocale['months'][aDate.getMonth()]";
174 break;
175 case "m":
176 result = " + MochiKit.Format.numberFormatter('00')(aDate.getMonth() + 1)";
177 break;
178 case "M":
179 result = " + aLocale['shortMonths'][aDate.getMonth()]";
180 break;
181 case "n":
182 result = " + (aDate.getMonth() + 1)";
183 break;
184 case "t":
185 result = " + Clipperz.Date.getDaysInMonth(aDate)";
186 break;
187 case "L":
188 result = " + (Clipperz.Date.isLeapYear(aDate) ? 1 : 0)";
189 break;
190 case "Y":
191 result = " + aDate.getFullYear()";
192 break;
193 case "y":
194 result = " + ('' + aDate.getFullYear()).substring(2, 4)";
195 break;
196 case "a":
197 result = " + (aDate.getHours() < 12 ? aLocale['amDesignation'] : aLocale['pmDesignation'])";
198 break;
199 case "A":
200 result = " + (aDate.getHours() < 12 ? aLocale['amDesignation'].toUpperCase() : aLocale['pmDesignation'].toUpperCase())";
201 break;
202 case "g":
203 result = " + ((aDate.getHours() %12) ? aDate.getHours() % 12 : 12)";
204 break;
205 case "G":
206 result = " + aDate.getHours()";
207 break;
208 case "h":
209 result = " + MochiKit.Format.numberFormatter('00')((aDate.getHours() %12) ? aDate.getHours() % 12 : 12)";
210 break;
211 case "H":
212 result = " + MochiKit.Format.numberFormatter('00')(aDate.getHours())";
213 break;
214 case "i":
215 result = " + MochiKit.Format.numberFormatter('00')(aDate.getMinutes())";
216 break;
217 case "s":
218 result = " + MochiKit.Format.numberFormatter('00')(aDate.getSeconds())";
219 break;
220 case "O":
221 result = " + aDate.getGMTOffset()";
222 break;
223 case "T":
224 result = " + Clipperz.Date.getTimezone(aDate)";
225 break;
226 case "Z":
227 result = " + ( + aDate.getTimezoneOffset() * -60)";
228 break;
229 default:
230 result = " + '" + aCharacter + "'";
231 break;
232 };
233
234 return result;
235 },
236
237 //=========================================================================
238
239 'formatDateWithPHPLikeTemplateAndLocale': function(aDate, aFormat, aLocale) {
240 var result;
241 var formatterCode;
242 var formatter;
243 var i,c;
244
245//MochiKit.Logging.logDebug(">>> Clipperz.Date.formatDateWithPHPLikeTemplateAndLocale");
246 formatterCode = "Clipperz.Date.__scratchFormatter = function(aDate, aLocale){return ''";
247
248 c = aFormat.length;
249 i = 0;
250
251 while (i<c) {
252 var character;
253
254 character = aFormat.charAt(i);
255 if (character == "\\") {
256 i++;
257 character = aFormat.charAt(i);
258 formatterCode += " + '" + character + "'"
259 } else {
260 formatterCode += Clipperz.Date.getPHPLikeFormatCode(character);
261 }
262
263 i++;
264 }
265
266 formatterCode += ";}";
267//MochiKit.Logging.logDebug("--- Clipperz.Date.formatDateWithPHPLikeTemplateAndLocale - formatterCode: " + formatterCode);
268 eval(formatterCode);
269
270 result = Clipperz.Date.__scratchFormatter.call(this, aDate, aLocale);
271 delete Clipperz.Date.__scratchFormatter;
272//MochiKit.Logging.logDebug("<<< Clipperz.Date.formatDateWithPHPLikeTemplateAndLocale");
273
274 return result;
275 },
276
277 //-------------------------------------------------------------------------
278
279 'parseDateWithPHPLikeTemplateAndLocale': function(aString, aFormat, aLocale) {
280 return new Date();
281 },
282
283 //=========================================================================
284
285 'formatDateWithUTCFormatAndLocale': function(aDate, aLocale) {
286 // return Clipperz.Date.formatWithJavaLikeTemplateAndLocale(aDate, "EEE, dd MMMM yyyy HH:mm:ss zzz", aLocale);
287 return aDate.toString();
288 },
289
290 'parseDateWithUTCFormatAndLocale': function(aValue, aLocale) {
291 return new Date(Date.parse(aValue));
292 },
293
294 //=========================================================================
295
296 'exception': {
297 // 'AbstractMethod': new MochiKit.Base.NamedError("Clipperz.Base.exception.AbstractMethod"),
298 // 'UnknownType': new MochiKit.Base.NamedError("Clipperz.Base.exception.UnknownType")
299 },
300
301 //-------------------------------------------------------------------------
302 __syntaxFix__: "syntax fix"
303
304});
305
diff --git a/frontend/beta/js/Clipperz/KeePassExportProcessor.js b/frontend/beta/js/Clipperz/KeePassExportProcessor.js
new file mode 100644
index 0000000..ba56b8e
--- a/dev/null
+++ b/frontend/beta/js/Clipperz/KeePassExportProcessor.js
@@ -0,0 +1,251 @@
1/*
2
3Copyright 2008-2011 Clipperz Srl
4
5This file is part of Clipperz's Javascript Crypto Library.
6Javascript Crypto Library provides web developers with an extensive
7and efficient set of cryptographic functions. The library aims to
8obtain maximum execution speed while preserving modularity and
9reusability.
10For further information about its features and functionalities please
11refer to http://www.clipperz.com
12
13* Javascript Crypto Library is free software: you can redistribute
14 it and/or modify it under the terms of the GNU Affero General Public
15 License as published by the Free Software Foundation, either version
16 3 of the License, or (at your option) any later version.
17
18* Javascript Crypto Library is distributed in the hope that it will
19 be useful, but WITHOUT ANY WARRANTY; without even the implied
20 warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
21 See the GNU Affero General Public License for more details.
22
23* You should have received a copy of the GNU Affero General Public
24 License along with Javascript Crypto Library. If not, see
25 <http://www.gnu.org/licenses/>.
26
27*/
28
29if (typeof(Clipperz) == 'undefined') { Clipperz = {}; }
30
31
32Clipperz.KeePassExportProcessor = function(args) {
33 args = args || {};
34
35 return this;
36}
37
38//=============================================================================
39
40Clipperz.KeePassExportProcessor.prototype = MochiKit.Base.update(null, {
41
42 //-------------------------------------------------------------------------
43/*
44 'parse': function(aValue) {
45 var result;
46
47//MochiKit.Logging.logDebug(">>> KeePassExportProcessor.parse");
48 result = [];
49//MochiKit.Logging.logDebug("--- KeePassExportProcessor.parse - result: " + Clipperz.Base.serializeJSON(result));
50//MochiKit.Logging.logDebug("<<< KeePassExportProcessor.parse");
51
52 return result;
53 },
54*/
55 //-------------------------------------------------------------------------
56
57 'deferredParse_core': function(aContext) {
58 var deferredResult;
59
60 //MochiKit.Logging.logDebug(">>> KeePassExportProcessor.deferredParse_core");
61 //MochiKit.Logging.logDebug("--- KeePassExportProcessor.deferredParse_core - (1) aContext.line: " + aContext.line.replace(/\n/g, "\\n").substring(0,50));
62 //MochiKit.Logging.logDebug("--- KeePassExportProcessor.deferredParse_core - aContext: " + Clipperz.Base.serializeJSON(aContext).substring(0,50));
63 //MochiKit.Logging.logDebug("--- KeePassExportProcessor.deferredParse_core - (2) aContext.line: " + aContext.line.replace(/\n/g, "\\n").substring(0,50));
64//console.log("deferredParse_core - aContext", aContext);
65 //MochiKit.Logging.logDebug("--- KeePassExportProcessor.deferredParse_core - (3) aContext.line: " + aContext.line.replace(/\n/g, "\\n").substring(0,50));
66 if (aContext.line == "") {
67 deferredResult = MochiKit.Async.succeed(aContext.result);
68 } else {
69 var record;
70
71 record = this.parseRecord(aContext);
72 if (record != null) {
73 aContext.result.push(record);
74 }
75
76 //MochiKit.Logging.logDebug("--> KeePassExportProcessor.deferredParse_core - aContext.line: " + aContext.line.replace(/\n/g, "\\n").substring(0,50));
77 aContext.line = aContext.line.replace(/^\n*/g, "").replace(/\n$/g, "");
78 //MochiKit.Logging.logDebug("<-- KeePassExportProcessor.deferredParse_core - aContext.line: " + aContext.line.replace(/\n/g, "\\n").substring(0,50));
79
80 deferredResult = new MochiKit.Async.Deferred();
81//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("KeePassExportProcessor.deferredParse_core - 1.1 " + res); return res;});
82 deferredResult.addCallback(Clipperz.NotificationCenter.deferredNotification, this, 'importProcessorProgressUpdate', {status:'processing', size:aContext.size, progress:(aContext.size - aContext.line.length)});
83//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("KeePassExportProcessor.deferredParse_core - 1.2 " + res); return res;});
84 deferredResult.addCallback(MochiKit.Async.wait, 0.2);
85//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("KeePassExportProcessor.deferredParse_core - 1.3 " + res); return res;});
86//deferredResult.addBoth(function(res) {console.log("KeePassExportProcessor.deferredParse_core - 1.3 ", res); return res;});
87 deferredResult.addCallback(MochiKit.Base.method(this, 'deferredParse_core'))
88//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("KeePassExportProcessor.deferredParse_core - 1.4 " + res); return res;});
89 deferredResult.callback(aContext);
90 }
91 //MochiKit.Logging.logDebug("<<< KeePassExportProcessor.deferredParse_core");
92
93 return deferredResult;
94 },
95
96 //.........................................................................
97
98 'deferredParse': function(aValue) {
99 var deferredResult;
100 var lines;
101 var context;
102
103//MochiKit.Logging.logDebug(">>> KeePassExportProcessor.deferredParse");
104//MochiKit.Logging.logDebug("--- KeePassExportProcessor.deferredParse - aValue: " + aValue.length);
105 lines = aValue.replace(/\r?\n/g, "\n");
106//MochiKit.Logging.logDebug("--- KeePassExportProcessor.deferredParse - lines: " + lines.length);
107 context = {
108 line: lines,
109 size: lines.length,
110 result: []
111 }
112//MochiKit.Logging.logDebug("--- KeePassExportProcessor.deferredParse - context: " + Clipperz.Base.serializeJSON(context).substring(0,50));
113//console.log("--- KeePassExportProcessor.deferredParse - context: ", context);
114
115 deferredResult = new MochiKit.Async.Deferred();
116//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("KeePassExportProcessor.deferredParse - 1 " + res); return res;});
117//deferredResult.addBoth(function(res) {console.log("KeePassExportProcessor.deferredParse - 1 ", res); return res;});
118 deferredResult.addCallback(MochiKit.Base.method(this, 'deferredParse_core'));
119//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("KeePassExportProcessor.deferredParse - 2 " + res); return res;});
120 deferredResult.callback(context);
121//MochiKit.Logging.logDebug("<<< KeePassExportProcessor.deferredParse");
122
123 return deferredResult;
124 },
125
126 //-------------------------------------------------------------------------
127
128 'parseRecord': function(aContext) {
129 var result;
130 var recordLabelRegexp;
131 varfieldLabelRegexp;
132 var fieldValueRegexp;
133 var fullLineRegexp;
134/*
135[Record name]
136Group Tree:
137UserName:
138URL:
139Password:
140Notes: test
141UUID: 525f62430079bae48b79ed2961924b05
142Icon: 0
143Creation Time: 2007-06-26 17:56:03
144Last Access: 2007-10-25 16:23:51
145Last Modification: 2007-10-25 16:23:51
146Expires: 2999-12-28 23:59:59
147
148 [Record name] ==> Title
149 Group: General ==> Group
150 Group Tree: ==> Group Tree
151 UserName: ==> UserName
152 URL: ==>URL
153 Password: ==>Password
154 Notes: test ==>Notes
155 UUID: 525f62430079bae48b79ed2961924b05 ==>UUID
156 Icon: 0 ==>Icon
157 Creation Time: 2007-06-26 17:56:03 ==>Creation Time
158 Last Access: 2007-10-25 16:23:51 ==>Last Access
159 Last Modification: 2007-10-25 16:23:51 ==>Last Modification
160 Expires: 2999-12-28 23:59:59 ==> Expires
161 Attachment Description: ==> Attachment Description
162 Attachment: ==> Attachment
163*/
164 recordLabelRegexp = new RegExp("^\\[(.*)\\]\\n");
165 // recordLabelRegexp = new RegExp("^\\[(.*)\\]$", "m");
166 fieldLabelRegexp = new RegExp("^(Group|Group Tree|UserName|URL|Password|Notes|UUID|Icon|Creation Time|Last Access|Last Modification|Expires|Attachment Description|Attachment|Valid until): ");
167 fieldValueRegexp = new RegExp("(.*)(\\n|$)");
168 fullLineRegexp = new RegExp("^(.*\\n)");
169
170
171 if (recordLabelRegexp.test(aContext.line) == true) {
172 var line;
173
174//MochiKit.Logging.logDebug("1.0");
175 line = aContext.line;
176//MochiKit.Logging.logDebug("0 - line: " + line.replace(/\n/g, "\\n").substring(0,50));
177
178 result = {};
179 result['Title'] = line.match(recordLabelRegexp)[1];
180//MochiKit.Logging.logDebug("1 - title: " + result['Title']);
181 line = line.replace(/^.*\n/, "");
182//MochiKit.Logging.logDebug("2 - line: " + line.replace(/\n/g, "\\n").substring(0,50));
183//MochiKit.Logging.logDebug("=======================================");
184 while (fieldLabelRegexp.test(line) == true) {
185 var fieldName;
186 var fieldValue;
187
188 fieldName = RegExp.$1;
189//MochiKit.Logging.logDebug("3 - fieldName: " + fieldName);
190 line = RegExp.rightContext;
191//MochiKit.Logging.logDebug("4 - line: " + line.replace(/\n/g, "\\n").substring(0,50));
192
193 fieldValue = line.match(fieldValueRegexp)[1];
194//MochiKit.Logging.logDebug("5 - fieldValue: " + fieldValue);
195 line = RegExp.rightContext;
196//MochiKit.Logging.logDebug("6 - line: " + line.replace(/\n/g, "\\n").substring(0,50));
197
198 if (fieldName == 'Notes') {
199 var isMultiline;
200
201 isMultiline = false;
202
203//MochiKit.Logging.logDebug("7 - fieldLabelRegexp.test(line): " + fieldLabelRegexp.test(line) + " - recordLabelRegexp.test(line): " + recordLabelRegexp.test(line));
204 if ((line != "") && (fieldLabelRegexp.test(line) == false) && (recordLabelRegexp.test(line) == false)) {
205 fieldValue += '\n';
206 }
207
208 while ((line != "") && (fieldLabelRegexp.test(line) == false) && (recordLabelRegexp.test(line) == false)) {
209 var newLineValue;
210
211 newLineValue = line.match(fullLineRegexp)[1];
212 if (newLineValue != "\n") {
213 isMultiline = true;
214 }
215 fieldValue += newLineValue;
216//MochiKit.Logging.logDebug("8 - fieldValue: " + fieldValue);
217 line = RegExp.rightContext;
218//MochiKit.Logging.logDebug("9 - line: " + line.replace(/\n/g, "\\n").substring(0,50));
219//MochiKit.Logging.logDebug("10 - fieldLabelRegexp.test(line): " + fieldLabelRegexp.test(line) + " - recordLabelRegexp.test(line): " + recordLabelRegexp.test(line));
220 }
221
222 if (isMultiline) {
223 fieldValue = fieldValue.replace(/\n$/g, "");
224 } else {
225 fieldValue = fieldValue.replace(/\n\n$/g, "");
226 }
227
228 line = line.replace(/^\n/, '');
229 }
230//MochiKit.Logging.logDebug("5 - fieldValue: " + fieldValue);
231
232 result[fieldName] = fieldValue;
233//MochiKit.Logging.logDebug("6 - line: " + line.replace(/\n/g, "\\n").substring(0,50));
234//MochiKit.Logging.logDebug("---------------------------------------");
235 }
236 } else {
237//MochiKit.Logging.logDebug("2.0");
238 result = null;
239 }
240
241 aContext.line = line;
242//MochiKit.Logging.logDebug("#######################################");
243
244 return result;
245 },
246
247 //-------------------------------------------------------------------------
248 __syntaxFix__: "syntax fix"
249});
250
251
diff --git a/frontend/beta/js/Clipperz/NotificationCenter.js b/frontend/beta/js/Clipperz/NotificationCenter.js
new file mode 100644
index 0000000..815d4fd
--- a/dev/null
+++ b/frontend/beta/js/Clipperz/NotificationCenter.js
@@ -0,0 +1,325 @@
1/*
2
3Copyright 2008-2011 Clipperz Srl
4
5This file is part of Clipperz's Javascript Crypto Library.
6Javascript Crypto Library provides web developers with an extensive
7and efficient set of cryptographic functions. The library aims to
8obtain maximum execution speed while preserving modularity and
9reusability.
10For further information about its features and functionalities please
11refer to http://www.clipperz.com
12
13* Javascript Crypto Library is free software: you can redistribute
14 it and/or modify it under the terms of the GNU Affero General Public
15 License as published by the Free Software Foundation, either version
16 3 of the License, or (at your option) any later version.
17
18* Javascript Crypto Library is distributed in the hope that it will
19 be useful, but WITHOUT ANY WARRANTY; without even the implied
20 warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
21 See the GNU Affero General Public License for more details.
22
23* You should have received a copy of the GNU Affero General Public
24 License along with Javascript Crypto Library. If not, see
25 <http://www.gnu.org/licenses/>.
26
27*/
28
29if (typeof(Clipperz) == 'undefined') { Clipperz = {}; }
30if (typeof(Clipperz.NotificationCenter) == 'undefined') { Clipperz.NotificationCenter = {}; }
31
32
33//#############################################################################
34
35Clipperz.NotificationCenterEvent = function(args) {
36 args = args || {};
37 //MochiKit.Base.bindMethods(this);
38
39 this._source = args.source || null;
40 this._event = args.event || null;
41 this._parameters = args.parameters || null;
42 this._isSynchronous = args.isSynchronous || false;
43
44 return this;
45}
46
47//=============================================================================
48
49Clipperz.NotificationCenterEvent.prototype = MochiKit.Base.update(null, {
50
51 //-------------------------------------------------------------------------
52
53 'toString': function() {
54 return "Clipperz.NotificationCenterEvent";
55 //return "Clipperz.NotificationCenterEvent {source: " + this.source() + ", event: " + this.event() + ", parameters: " + this.parameters() + "}";
56 },
57
58 //-------------------------------------------------------------------------
59
60 'source': function() {
61 return this._source;
62 },
63
64 'setSource': function(aValue) {
65 this._source = aValue;
66 },
67
68 //-------------------------------------------------------------------------
69
70 'event': function() {
71 return this._event;
72 },
73
74 'setEvent': function(aValue) {
75 this._event = aValue;
76 },
77
78 //-------------------------------------------------------------------------
79
80 'parameters': function() {
81 return this._parameters;
82 },
83
84 'setParameters': function(aValue) {
85 this._parameters = aValue;
86 },
87
88 //-------------------------------------------------------------------------
89
90 'isSynchronous': function() {
91 return this._isSynchronous;
92 },
93
94 //-------------------------------------------------------------------------
95 __syntaxFix__: "syntax fix"
96});
97
98
99//#############################################################################
100//#############################################################################
101
102Clipperz.NotificationCenter = function(args) {
103 args = args || {};
104 //MochiKit.Base.bindMethods(this);
105
106 this._listeners = {};
107 this._useSynchronousListenerInvocation = args.useSynchronousListenerInvocation || false;
108 this._timeoutDelay = args.timeoutDelay || 0.1;
109
110 return this;
111}
112
113//=============================================================================
114
115Clipperz.NotificationCenter.prototype = MochiKit.Base.update(null, {
116
117 //-------------------------------------------------------------------------
118
119 'toString': function() {
120 return "Clipperz.NotificationCenter";
121 },
122
123 //-------------------------------------------------------------------------
124
125 'useSynchronousListenerInvocation': function() {
126 return this._useSynchronousListenerInvocation;
127 },
128
129 'setUseSynchronousListenerInvocation': function(aValue) {
130 this._useSynchronousListenerInvocation = aValue;
131 },
132
133 //-------------------------------------------------------------------------
134
135 'timeoutDelay': function() {
136 return this._timeoutDelay;
137 },
138
139 'setTimeoutDelay': function(aValue) {
140 this._timeoutDelay = aValue;
141 },
142
143 //-------------------------------------------------------------------------
144
145 'listeners': function() {
146 return this._listeners;
147 },
148
149 //-------------------------------------------------------------------------
150
151 'register': function(aSource, anEvent, aListener, aMethod) {
152 vareventListeners;
153 varlistenerInfo;
154 vareventKey;
155
156 if (anEvent != null) {
157 eventKey = anEvent;
158 } else {
159 eventKey = '_notificationCenter_matchAnyEvent_key_';
160 }
161
162 eventListeners = this.listeners()[eventKey];
163
164 if (eventListeners == null) {
165 eventListeners = [];
166 this.listeners()[eventKey] = eventListeners;
167 }
168
169 listenerInfo = {};
170 if (aSource != null) {
171 listenerInfo['source'] = aSource;
172 } else {
173 listenerInfo['source'] = 'any';
174 }
175
176 listenerInfo['listener'] = aListener;
177 listenerInfo['method'] = aMethod;
178
179 eventListeners.push(listenerInfo);
180
181 return listenerInfo;
182 },
183
184 //-------------------------------------------------------------------------
185
186 'removeListenerInfoFromListeners': function(aListener, someListeners) {
187 varlistenerIndex;
188 vari,c;
189
190 if (someListeners != null) {
191 listenerIndex = -1;
192 c = someListeners.length;
193 for (i=0; i<c; i++) {
194 varlistenerInfo;
195
196 listenerInfo = someListeners[i];
197 if (listenerInfo['listener'] === aListener) {
198 listenerIndex = i;
199 }
200 }
201
202 if (listenerIndex != -1) {
203 Clipperz.Base.removeObjectAtIndexFromArray(listenerIndex, someListeners);
204 }
205 }
206 },
207
208 //-------------------------------------------------------------------------
209
210 'unregister': function(aListener, anEvent) {
211 if (anEvent == null) {
212 varallListenerList;
213 vari, c;
214
215 // allListenerList = Clipperz.Base.values(this.listeners());
216 allListenerList = MochiKit.Base.values(this.listeners());
217 c = allListenerList.length;
218 for (i=0; i<c; i++) {
219 this.removeListenerInfoFromListeners(aListener, allListenerList[i]);
220 }
221 } else {
222 this.removeListenerInfoFromListeners(aListener, this.listeners()[anEvent]);
223 }
224 },
225
226 //-------------------------------------------------------------------------
227
228 'asysnchronousListenerNotification': function(anEventInfo, aMethod, aListener) {
229 MochiKit.Async.callLater(this.timeoutDelay(), MochiKit.Base.partial(MochiKit.Base.methodcaller(aMethod, anEventInfo), aListener));
230 // setTimeout(MochiKit.Base.partial(MochiKit.Base.methodcaller(aMethod, anEventInfo), aListener), this.timeoutDelay());
231 },
232
233 //-------------------------------------------------------------------------
234
235 'processListenerInfo': function(anEventInfo, aListenerInfo) {
236 varshouldInvokeListenerMethod;
237
238 if (aListenerInfo['source'] == 'any') {
239 shouldInvokeListenerMethod = true;
240 } else {
241 if (aListenerInfo['source'] === anEventInfo.source()) {
242 shouldInvokeListenerMethod = true;
243 } else {
244 shouldInvokeListenerMethod = false;
245 }
246 }
247
248 if (shouldInvokeListenerMethod) {
249 if (this.useSynchronousListenerInvocation() || anEventInfo.isSynchronous()) {
250//MochiKit.Logging.logDebug("syncrhronous listener invocation");
251 try {
252 // MochiKit.Base.map(MochiKit.Base.methodcaller(aListenerInfo['method'], anEventInfo), [aListenerInfo['listener']]);
253//console.log("notification: ", aListenerInfo['listener'], aListenerInfo['method'], anEventInfo);
254 MochiKit.Base.method(aListenerInfo['listener'], aListenerInfo['method'], anEventInfo)();
255 } catch(exception) {
256 MochiKit.Logging.logError('NotificationCenter ERROR: unable to invoke method \'' + aListenerInfo['method'] + '\' on object ' + aListenerInfo['listener']);
257 }
258 } else {
259 var asyncMethod;
260
261//MochiKit.Logging.logDebug("asyncrhronous listener invocation");
262 asyncMethod = MochiKit.Base.bind(this.asysnchronousListenerNotification, this)
263 MochiKit.Base.map(MochiKit.Base.partial(asyncMethod, anEventInfo, aListenerInfo['method']), [aListenerInfo['listener']]);
264 }
265 }
266 },
267
268 //-------------------------------------------------------------------------
269
270 'notify': function(aSource, anEvent, someEventParameters, isSynchronous) {
271 vareventInfo;
272 var processInfoMethod;
273
274//MochiKit.Logging.logDebug(">>> NotificationCenter.notify");
275 eventInfo = new Clipperz.NotificationCenterEvent({source:aSource, event:anEvent, parameters:someEventParameters, isSynchronous:isSynchronous});
276//MochiKit.Logging.logDebug("--- NotificationCenter.notify - 1");
277 processInfoMethod = MochiKit.Base.bind(this.processListenerInfo, this);
278//MochiKit.Logging.logDebug("--- NotificationCenter.notify - 2");
279
280 MochiKit.Base.map(MochiKit.Base.partial(processInfoMethod, eventInfo), this.listeners()[anEvent] || []);
281//MochiKit.Logging.logDebug("--- NotificationCenter.notify - 3");
282 MochiKit.Base.map(MochiKit.Base.partial(processInfoMethod, eventInfo), this.listeners()['_notificationCenter_matchAnyEvent_key_'] || []);
283//MochiKit.Logging.logDebug("<<< NotificationCenter.notify");
284 },
285
286 //-------------------------------------------------------------------------
287
288 'deferredNotification': function(aSource, anEvent, someEventParameters, aDeferredResult) {
289
290 this.notify(aSource, anEvent, someEventParameters, true);
291
292 return aDeferredResult;
293 // return MochiKit.Async.wait(1, aDeferredResult);
294 },
295
296 //-------------------------------------------------------------------------
297
298 'resetStatus': function() {
299 this._listeners = {};
300 },
301
302 //-------------------------------------------------------------------------
303 __syntaxFix__: "syntax fix"
304
305});
306
307//#############################################################################
308
309Clipperz.NotificationCenter.defaultNotificationCenter = new Clipperz.NotificationCenter();
310
311Clipperz.NotificationCenter.notify = MochiKit.Base.method(Clipperz.NotificationCenter.defaultNotificationCenter, 'notify');
312Clipperz.NotificationCenter.register = MochiKit.Base.method(Clipperz.NotificationCenter.defaultNotificationCenter, 'register');
313Clipperz.NotificationCenter.unregister = MochiKit.Base.method(Clipperz.NotificationCenter.defaultNotificationCenter, 'unregister');
314Clipperz.NotificationCenter.deferredNotification = MochiKit.Base.method(Clipperz.NotificationCenter.defaultNotificationCenter, 'deferredNotification');
315/*
316_clipperz_notificationCenter_defaultNotificationCenter = null;
317
318Clipperz.NotificationCenter.defaultNotificationCenter = function() {
319 if (_clipperz_notificationCenter_defaultNotificationCenter == null) {
320 _clipperz_notificationCenter_defaultNotificationCenter = new Clipperz.NotificationCenter();
321 }
322
323 return _clipperz_notificationCenter_defaultNotificationCenter;
324};
325*/
diff --git a/frontend/beta/js/Clipperz/PM/BookmarkletProcessor.js b/frontend/beta/js/Clipperz/PM/BookmarkletProcessor.js
new file mode 100644
index 0000000..4dfdd8e
--- a/dev/null
+++ b/frontend/beta/js/Clipperz/PM/BookmarkletProcessor.js
@@ -0,0 +1,288 @@
1/*
2
3Copyright 2008-2011 Clipperz Srl
4
5This file is part of Clipperz's Javascript Crypto Library.
6Javascript Crypto Library provides web developers with an extensive
7and efficient set of cryptographic functions. The library aims to
8obtain maximum execution speed while preserving modularity and
9reusability.
10For further information about its features and functionalities please
11refer to http://www.clipperz.com
12
13* Javascript Crypto Library is free software: you can redistribute
14 it and/or modify it under the terms of the GNU Affero General Public
15 License as published by the Free Software Foundation, either version
16 3 of the License, or (at your option) any later version.
17
18* Javascript Crypto Library is distributed in the hope that it will
19 be useful, but WITHOUT ANY WARRANTY; without even the implied
20 warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
21 See the GNU Affero General Public License for more details.
22
23* You should have received a copy of the GNU Affero General Public
24 License along with Javascript Crypto Library. If not, see
25 <http://www.gnu.org/licenses/>.
26
27*/
28
29if (typeof(Clipperz) == 'undefined') { Clipperz = {}; }
30if (typeof(Clipperz.PM) == 'undefined') { Clipperz.PM = {}; }
31//if (typeof(Clipperz.PM.BookmarkletProcessor) == 'undefined') { Clipperz.PM.BookmarkletProcessor = {}; }
32//if (typeof(Clipperz.PM.BookmarkletProcessor.versions) == 'undefined') { Clipperz.PM.BookmarkletProcessor.versions = {}; }
33
34/*
35Clipperz.PM.BookmarkletProcessor.versions['abstract'] = function(anUser, aConfiguration) {
36 this._user = anUser;
37 this._configuration = aConfiguration;
38
39 this._recordTitle = null;
40 this._record = null;
41 this._editableFields = null;
42
43 return this;
44}
45
46
47Clipperz.PM.BookmarkletProcessor.versions['abstract'].prototype = MochiKit.Base.update(null, {
48
49 'toString': function() {
50 return "BookmarkletProcessor - " + this.user();
51 },
52
53 //-------------------------------------------------------------------------
54
55 'user': function() {
56 return this._user;
57 },
58
59 //-------------------------------------------------------------------------
60
61 'configuration': function() {
62 return this._configuration;
63 },
64
65 //-------------------------------------------------------------------------
66
67 'record': function() {
68 throw Clipperz.Base.exception.AbstractMethod;
69 },
70
71 //-------------------------------------------------------------------------
72 __syntaxFix__: "syntax fix"
73});
74*/
75
76Clipperz.PM.BookmarkletProcessor = function(anUser, aConfiguration) {
77 this._user = anUser;
78 this._configuration = aConfiguration;
79
80 this._recordTitle = null;
81 this._record = null;
82 this._editableFields = null;
83 this._favicon = null;
84
85 return this;
86}
87
88Clipperz.PM.BookmarkletProcessor.prototype = MochiKit.Base.update(null, {
89
90 'toString': function() {
91 return "BookmarkletProcessor - " + this.user();
92 },
93
94 //-------------------------------------------------------------------------
95
96 'user': function() {
97 return this._user;
98 },
99
100 //-------------------------------------------------------------------------
101
102 'configuration': function() {
103 return this._configuration;
104 },
105
106 //-------------------------------------------------------------------------
107
108 'recordTitle': function() {
109 if (this._recordTitle == null) {
110 this._recordTitle = this.configuration().page.title;
111 }
112
113 return this._recordTitle;
114 },
115
116 //-------------------------------------------------------------------------
117
118 'fields': function() {
119 return this.configuration().form.inputs;
120 },
121
122 //-------------------------------------------------------------------------
123
124 'editableFields': function() {
125 if (this._editableFields == null) {
126 this._editableFields = MochiKit.Base.filter(function(aField) {
127 var result;
128 var type;
129
130 type = aField['type'].toLowerCase();
131 result = ((type != 'hidden') && (type != 'submit') && (type != 'checkbox') && (type != 'radio') && (type != 'select'));
132
133 return result;
134 }, this.fields())
135 }
136
137 return this._editableFields;
138 },
139
140 //-------------------------------------------------------------------------
141
142 'hostname': function() {
143 if (this._hostname == null) {
144 var actionUrl;
145
146 actionUrl = this.configuration()['form']['attributes']['action'];
147//MochiKit.Logging.logDebug("+++ actionUrl: " + actionUrl);
148 this._hostname = actionUrl.replace(/^https?:\/\/([^\/]*)\/.*/, '$1');
149 }
150
151 return this._hostname;
152 },
153
154 'favicon': function() {
155 if (this._favicon == null) {
156 this._favicon = "http://" + this.hostname() + "/favicon.ico";
157//MochiKit.Logging.logDebug("+++ favicon: " + this._favicon);
158 }
159
160 return this._favicon;
161 },
162
163 //-------------------------------------------------------------------------
164
165 'record': function() {
166 if (this._record == null) {
167 var record;
168 var recordVersion;
169 var directLogin;
170 var bindings;
171 var i,c;
172
173 record = new Clipperz.PM.DataModel.Record({
174 label:this.recordTitle(),
175 notes:"",
176 user:this.user()
177 });
178 recordVersion = new Clipperz.PM.DataModel.RecordVersion(record, {})
179 record.setCurrentVersion(recordVersion);
180
181 bindings = {};
182
183 c = this.editableFields().length;
184 for (i=0; i<c; i++) {
185 var formField;
186 var recordField;
187
188//MochiKit.Logging.logDebug(">>> adding a field");
189 formField = this.editableFields()[i];
190 recordField = new Clipperz.PM.DataModel.RecordField({
191 recordVersion:recordVersion,
192 label:formField['name'],
193 value:formField['value'],
194 type:Clipperz.PM.Strings.inputTypeToRecordFieldType[formField['type']],
195 hidden:false
196 });
197 recordVersion.addField(recordField);
198
199 bindings[formField['name']] = recordField.key();
200//MochiKit.Logging.logDebug("<<< adding a field");
201 }
202
203 directLogin = new Clipperz.PM.DataModel.DirectLogin({
204 record:record,
205 label:this.recordTitle() + Clipperz.PM.Strings['newDirectLoginLabelSuffix'],
206 // bookmarkletVersion:this.version(),
207 bookmarkletVersion:'0.2',
208 favicon:this.favicon(),
209 formData:this.configuration()['form'],
210 bindingData:bindings
211 });
212 record.addDirectLogin(directLogin);
213
214 this.user().addRecord(record);
215
216 this._record = record;
217 }
218
219 return this._record;
220 },
221
222 //-------------------------------------------------------------------------
223 __syntaxFix__: "syntax fix"
224});
225
226//#############################################################################
227
228Clipperz.PM.BookmarkletProcessor.createRecordFromBookmarkletConfiguration = function(anUser, aConfiguration) {
229 var processor;
230
231 processor = new Clipperz.PM.BookmarkletProcessor(anUser, aConfiguration);
232
233 return processor.record();
234};
235
236//-----------------------------------------------------------------------------
237
238Clipperz.PM.BookmarkletProcessor.sanitizeBookmarkletConfiguration = function(aConfiguration) {
239 var result;
240
241 //throw "XSS Bookmarklet attempt";
242
243 result = aConfiguration;
244
245 return result;
246};
247
248//-----------------------------------------------------------------------------
249
250Clipperz.PM.BookmarkletProcessor.checkBookmarkletConfiguration = function(aConfiguration, aButton, aCallback) {
251 var result;
252
253 try {
254 result = Clipperz.Base.evalJSON(aConfiguration);
255 result = Clipperz.PM.BookmarkletProcessor.sanitizeBookmarkletConfiguration(result);
256
257 if (result['version'] != '0.2.3') {
258 throw "WrongBookmarkletVersion";
259 }
260 } catch (exception) {
261 var title;
262 var message;
263
264 if (exception == "WrongBookmarkletVersion") {
265 title = Clipperz.PM.Strings['newRecordPanelWrongBookmarkletVersionExceptionTitle'];
266 message = Clipperz.PM.Strings['newRecordPanelWrongBookmarkletVersionExceptionMessage'];
267 } else {
268 title = Clipperz.PM.Strings['newRecordPanelGeneralExceptionTitle'];
269 message = Clipperz.PM.Strings['newRecordPanelGeneralExceptionMessage'];
270 }
271 Clipperz.PM.Components.MessageBox().show({
272 title:title,
273 text:message,
274 width:240,
275 fn:aCallback,
276 closable:false,
277 showProgressBar:false,
278 showCloseButton:false,
279 buttons:{'ok':Clipperz.PM.Strings['newRecordPanelExceptionPanelCloseButtonLabel']}
280 }, aButton);
281
282 throw exception;
283 }
284
285 return result;
286};
287
288//-----------------------------------------------------------------------------
diff --git a/frontend/beta/js/Clipperz/PM/Components/BaseComponent.js b/frontend/beta/js/Clipperz/PM/Components/BaseComponent.js
new file mode 100644
index 0000000..67e257b
--- a/dev/null
+++ b/frontend/beta/js/Clipperz/PM/Components/BaseComponent.js
@@ -0,0 +1,124 @@
1/*
2
3Copyright 2008-2011 Clipperz Srl
4
5This file is part of Clipperz's Javascript Crypto Library.
6Javascript Crypto Library provides web developers with an extensive
7and efficient set of cryptographic functions. The library aims to
8obtain maximum execution speed while preserving modularity and
9reusability.
10For further information about its features and functionalities please
11refer to http://www.clipperz.com
12
13* Javascript Crypto Library is free software: you can redistribute
14 it and/or modify it under the terms of the GNU Affero General Public
15 License as published by the Free Software Foundation, either version
16 3 of the License, or (at your option) any later version.
17
18* Javascript Crypto Library is distributed in the hope that it will
19 be useful, but WITHOUT ANY WARRANTY; without even the implied
20 warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
21 See the GNU Affero General Public License for more details.
22
23* You should have received a copy of the GNU Affero General Public
24 License along with Javascript Crypto Library. If not, see
25 <http://www.gnu.org/licenses/>.
26
27*/
28
29if (typeof(Clipperz) == 'undefined') { Clipperz = {}; }
30if (typeof(Clipperz.PM) == 'undefined') { Clipperz.PM = {}; }
31if (typeof(Clipperz.PM.Components) == 'undefined') { Clipperz.PM.Components = {}; }
32
33//#############################################################################
34
35var _Clipperz_PM_Components_Panels_base_id_ = 0;
36
37//#############################################################################
38
39Clipperz.PM.Components.BaseComponent = function(anElement, args) {
40 args = args || {};
41 //MochiKit.Base.bindMethods(this);
42 //Clipperz.PM.Components.BaseComponent.superclass.constructor.call(this, args);
43
44 this._element = anElement;
45 this._ids = {};
46
47 return this;
48}
49
50//=============================================================================
51
52//MochiKit.Base.update(Clipperz.PM.Components.BaseComponent.prototype, {
53YAHOO.extendX(Clipperz.PM.Components.BaseComponent, YAHOO.ext.util.Observable, {
54
55 'isClipperzPMComponent': true,
56
57 //-------------------------------------------------------------------------
58
59 'toString': function () {
60 return "Clipperz.PM.Components.BaseComponent component";
61 },
62
63 //-------------------------------------------------------------------------
64
65 'domHelper': function() {
66 return Clipperz.YUI.DomHelper;
67 },
68
69 //-------------------------------------------------------------------------
70
71 'element': function() {
72//MochiKit.Logging.logDebug(">>> BaseComponent.element");
73 return this._element;
74 },
75
76 'setElement': function(aValue) {
77 this._element = aValue;
78 },
79
80 //-----------------------------------------------------
81
82 'remove': function() {
83//MochiKit.Logging.logDebug(">>> BaseComponent.remove");
84 Clipperz.NotificationCenter.unregister(this);
85 MochiKit.Signal.disconnectAllTo(this);
86//MochiKit.Logging.logDebug("<<< BaseComponent.remove");
87 },
88
89 //-------------------------------------------------------------------------
90
91 'getId': function(aValue) {
92 varresult;
93
94 result = this._ids[aValue];
95
96 if (typeof(result) == 'undefined') {
97 _Clipperz_PM_Components_Panels_base_id_ ++;
98
99 result = "Clipperz_PM_Components_Panels_" + aValue + "_" + _Clipperz_PM_Components_Panels_base_id_;
100 this._ids[aValue] = result;
101//MochiKit.Logging.logDebug(">>> getId(" + aValue + ") = " + result);
102 } else {
103//MochiKit.Logging.logDebug("<<< getId(" + aValue + ") = " + result);
104 }
105
106 return result;
107 },
108
109 'getDom': function(aValue) {
110 return YAHOO.util.Dom.get(this.getId(aValue));
111 },
112
113 'getElement': function(aValue) {
114 return YAHOO.ext.Element.get(this.getId(aValue));
115 },
116
117 'getActor': function(aValue, anAnimator) {
118 return new YAHOO.ext.Actor(this.getDom(aValue), anAnimator);
119 },
120
121 //-------------------------------------------------------------------------
122 __syntaxFix__: "syntax fix"
123
124});
diff --git a/frontend/beta/js/Clipperz/PM/Components/Compact/CompactHeader.js b/frontend/beta/js/Clipperz/PM/Components/Compact/CompactHeader.js
new file mode 100644
index 0000000..e51b56f
--- a/dev/null
+++ b/frontend/beta/js/Clipperz/PM/Components/Compact/CompactHeader.js
@@ -0,0 +1,86 @@
1/*
2
3Copyright 2008-2011 Clipperz Srl
4
5This file is part of Clipperz's Javascript Crypto Library.
6Javascript Crypto Library provides web developers with an extensive
7and efficient set of cryptographic functions. The library aims to
8obtain maximum execution speed while preserving modularity and
9reusability.
10For further information about its features and functionalities please
11refer to http://www.clipperz.com
12
13* Javascript Crypto Library is free software: you can redistribute
14 it and/or modify it under the terms of the GNU Affero General Public
15 License as published by the Free Software Foundation, either version
16 3 of the License, or (at your option) any later version.
17
18* Javascript Crypto Library is distributed in the hope that it will
19 be useful, but WITHOUT ANY WARRANTY; without even the implied
20 warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
21 See the GNU Affero General Public License for more details.
22
23* You should have received a copy of the GNU Affero General Public
24 License along with Javascript Crypto Library. If not, see
25 <http://www.gnu.org/licenses/>.
26
27*/
28
29if (typeof(Clipperz) == 'undefined') { Clipperz = {}; }
30if (typeof(Clipperz.PM) == 'undefined') { Clipperz.PM = {}; }
31if (typeof(Clipperz.PM.Components) == 'undefined') { Clipperz.PM.Components = {}; }
32if (typeof(Clipperz.PM.Components.Compact) == 'undefined') { Clipperz.PM.Components.Compact = {}; }
33
34Clipperz.PM.Components.Compact.CompactHeader = function(anElement, args) {
35
36 Clipperz.PM.Components.Compact.CompactHeader.superclass.constructor.call(this, anElement, args);
37
38 this.render();
39
40 return this;
41};
42
43YAHOO.extendX(Clipperz.PM.Components.Compact.CompactHeader, Clipperz.PM.Components.BaseComponent, {
44
45 'toString': function() {
46 return "Clipperz.PM.Components.Compact.CompactHeader";
47 },
48
49 //-----------------------------------------------------
50
51 'render': function() {
52 this.element().update("");
53
54 Clipperz.YUI.DomHelper.append(this.element().dom, {tag:'div', children:[
55 {tag:'img', src:'./images/logo.gif'},
56 {tag:'div', id:'lockBlock', children:[
57 {tag:'input', type:'checkbox', id:'autolock'},
58 {tag:'span', html:'auto'},
59 {tag:'a', href:'#', htmlString:Clipperz.PM.Strings['lockMenuLabel'], id:'lock'}
60 ]}
61 ]});
62
63 Clipperz.YUI.DomHelper.append(this.element().dom,
64 {tag:'div', id:'compactMiscLinks', children:[
65 {tag:'a', id:'donateHeaderIconLink', target:'_blank', href:Clipperz.PM.Strings['donateHeaderLinkUrl'], children:[
66 {tag:'img', id:'donateHeaderLinkIcon', src:'./images/smiles_small.gif'}
67 ]},
68 {tag:'ul', children:[
69 {tag:'li', children:[{tag:'a', id:'donateHeaderLink', html:'donate', target:'_blank'}]},
70 {tag:'li', children:[{tag:'a', id:'creditsHeaderLink', html:'credits', target:'_blank'}]},
71 {tag:'li', children:[{tag:'a', id:'feedbackHeaderLink', html:'feedback', target:'_blank'}]},
72 {tag:'li', children:[{tag:'a', id:'helpHeaderLink', html:'help', target:'_blank'}]},
73 {tag:'li', children:[{tag:'a', id:'forumHeaderLink', html:'forum', target:'_blank'}]}
74 ]}
75 ]}
76 );
77
78 YAHOO.ext.Element.get('lockBlock').setVisibilityMode(YAHOO.ext.Element.DISPLAY).hide();
79 Clipperz.NotificationCenter.notify(this, 'switchLanguage');
80 },
81
82 //-----------------------------------------------------
83 __syntaxFix__: '__syntaxFix__'
84});
85
86
diff --git a/frontend/beta/js/Clipperz/PM/Components/Compact/CompactInterface.js b/frontend/beta/js/Clipperz/PM/Components/Compact/CompactInterface.js
new file mode 100644
index 0000000..492f815
--- a/dev/null
+++ b/frontend/beta/js/Clipperz/PM/Components/Compact/CompactInterface.js
@@ -0,0 +1,312 @@
1/*
2
3Copyright 2008-2011 Clipperz Srl
4
5This file is part of Clipperz's Javascript Crypto Library.
6Javascript Crypto Library provides web developers with an extensive
7and efficient set of cryptographic functions. The library aims to
8obtain maximum execution speed while preserving modularity and
9reusability.
10For further information about its features and functionalities please
11refer to http://www.clipperz.com
12
13* Javascript Crypto Library is free software: you can redistribute
14 it and/or modify it under the terms of the GNU Affero General Public
15 License as published by the Free Software Foundation, either version
16 3 of the License, or (at your option) any later version.
17
18* Javascript Crypto Library is distributed in the hope that it will
19 be useful, but WITHOUT ANY WARRANTY; without even the implied
20 warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
21 See the GNU Affero General Public License for more details.
22
23* You should have received a copy of the GNU Affero General Public
24 License along with Javascript Crypto Library. If not, see
25 <http://www.gnu.org/licenses/>.
26
27*/
28
29if (typeof(Clipperz) == 'undefined') { Clipperz = {}; }
30if (typeof(Clipperz.PM) == 'undefined') { Clipperz.PM = {}; }
31if (typeof(Clipperz.PM.Components) == 'undefined') { Clipperz.PM.Components = {}; }
32if (typeof(Clipperz.PM.Components.Compact) == 'undefined') { Clipperz.PM.Components.Compact = {}; }
33
34Clipperz.PM.Components.Compact.CompactInterface = function(anElement, args) {
35
36 Clipperz.PM.Components.Compact.CompactInterface.superclass.constructor.call(this, anElement, args);
37
38 this._directLoginItemTemplate = null;
39 this._user = args.user;
40 this._autoLockTimer = null;
41
42 Clipperz.NotificationCenter.register(null, 'updatedProgressState', this, 'userNotificationHandler')
43 Clipperz.NotificationCenter.register(null, 'directLoginAdded', this, 'directLoginAddedHandler');
44
45 this.render();
46
47 return this;
48};
49
50YAHOO.extendX(Clipperz.PM.Components.Compact.CompactInterface, Clipperz.PM.Components.BaseComponent, {
51
52 'toString': function() {
53 return "Clipperz.PM.Components.Compact.CompactInterface";
54 },
55
56 //-----------------------------------------------------
57
58 'render': function() {
59 var result;
60 varlayout;
61 var registerButton;
62
63//MochiKit.Logging.logDebug(">>> CompactInterface.render");
64 this.element().update("");
65
66 Clipperz.YUI.DomHelper.append(this.element().dom, {tag:'div', children:[
67 {tag:'div', id:this.getId('cantentPanel'), children:[
68 {tag:'h4', id:this.getId('message')},
69 {tag:'ul', id:'directLogins', children:[]}
70 ]},
71 {tag:'div', id:this.getId('lockPanel'), cls:'lockPanel', children:[
72 {tag:'div', htmlString:Clipperz.PM.Strings['lockDescription']},
73 {tag:'form', id:'lockDialogForm', children:[
74 {tag:'input', type:'password', id:this.getId('lockPassphrase')}
75 ]},
76 {tag:'div', id:this.getId('unlock')}
77 ]}
78 ]});
79
80 this.getElement('lockPanel').setVisibilityMode(YAHOO.ext.Element.DISPLAY).hide();
81
82 YAHOO.ext.Element.get('lockBlock').show();
83 MochiKit.Signal.connect(YAHOO.ext.Element.get('lock').dom, 'onclick', this, 'doLockEventHandler');
84 new YAHOO.ext.Button(this.getId('unlock'), {text:Clipperz.PM.Strings['unlockButtonLabel'], handler:this.doUnlockEventHandler, scope:this, minWidth:0});
85 this.getElement('unlock').swallowEvent('click', true);
86 new Clipperz.PM.Components.PasswordEntropyDisplay(this.getElement('lockPassphrase'));
87 MochiKit.Signal.connect('lockDialogForm', 'onsubmit', this, 'doUnlockEventHandler');
88
89 this.getElement('cantentPanel').setVisibilityMode(YAHOO.ext.Element.DISPLAY);
90//MochiKit.Logging.logDebug("<<< CompactInterface.render");
91
92 return result;
93 },
94
95 //-----------------------------------------------------
96
97 'directLoginAddedHandler': function(anEvent) {
98 this.redrawDirectLoginItems();
99 },
100
101 //-----------------------------------------------------
102
103 'compareDirectLogins': function(a, b) {
104 return MochiKit.Base.compare(a.label().toLowerCase(), b.label().toLowerCase());
105 },
106
107 //-----------------------------------------------------
108
109 'redrawDirectLoginItems': function() {
110 var template;
111 var allDirectLogins;
112
113 this.getElement('message').setVisibilityMode(YAHOO.ext.Element.DISPLAY).hide();
114//MochiKit.Logging.logDebug(">>> CompactInterface.redrawDirectLoginItems");
115//MochiKit.Logging.logDebug("--- CompactInterface.redrawDirectLoginItems - 0");
116 MochiKit.Iter.forEach(YAHOO.ext.Element.get('directLogins').getChildrenByTagName('li'), function(aDirectLoginElement) {
117 MochiKit.Signal.disconnectAll(aDirectLoginElement.dom);
118//MochiKit.Logging.logDebug("disconnecting IMG " + aDirectLoginElement.getChildrenByTagName('img')[0].dom.src);
119 MochiKit.Signal.disconnectAll(aDirectLoginElement.getChildrenByTagName('img')[0].dom);
120 })
121//MochiKit.Logging.logDebug("--- CompactInterface.redrawDirectLoginItems - 1");
122 YAHOO.ext.Element.get('directLogins').update("");
123//MochiKit.Logging.logDebug("--- CompactInterface.redrawDirectLoginItems - 2");
124 allDirectLogins = MochiKit.Base.values(this.user().directLoginReferences());
125//MochiKit.Logging.logDebug("--- CompactInterface.redrawDirectLoginItems - 3");
126 allDirectLogins.sort(this.compareDirectLogins);
127
128//MochiKit.Logging.logDebug("--- CompactInterface.redrawDirectLoginItems - 4");
129 template = this.directLoginItemTemplate();
130//MochiKit.Logging.logDebug("--- CompactInterface.redrawDirectLoginItems - 5");
131 MochiKit.Iter.forEach(allDirectLogins, MochiKit.Base.bind(function(aDirectLogin) {
132 vardirectLoginElement;
133 varfaviconImageElementID;
134
135 faviconImageElementID = aDirectLogin.reference() + "_faviconIMG";
136 directLoginElement = template.append('directLogins', {
137 elementID:faviconImageElementID,
138 faviconUrl:aDirectLogin.fixedFavicon(),
139 directLoginTitle:aDirectLogin.label(),
140 directLoginReference:aDirectLogin.reference()
141 }, true);
142//MochiKit.Logging.logDebug("--- CompactInterface.redrawDirectLoginItems - 6: " + recordElement.dom);
143 directLoginElement.addClassOnOver("hover");
144 MochiKit.Signal.connect(directLoginElement.dom, 'onclick', this, 'handleDirectLoginClick');
145
146 MochiKit.Signal.connect(faviconImageElementID, 'onload', this, 'handleLoadedFaviconImage');
147 MochiKit.Signal.connect(faviconImageElementID, 'onerror', aDirectLogin, 'handleMissingFaviconImage');
148 MochiKit.Signal.connect(faviconImageElementID, 'onabort', aDirectLogin, 'handleMissingFaviconImage');
149
150 // YAHOO.ext.Element.get(faviconImageElementID).dom.src = aDirectLogin.fixedFavicon();
151 }, this));
152
153 this.resetAutoLockTimer();
154//MochiKit.Logging.logDebug("<<< CompactInterface.redrawDirectLoginItems");
155 },
156
157 //-----------------------------------------------------
158
159 'directLoginItemTemplate': function() {
160 if (this._directLoginItemTemplate == null) {
161 this._directLoginItemTemplate = Clipperz.YUI.DomHelper.createTemplate({tag:'li', id:'{directLoginReference}', children:[
162 {tag:'table', border:'0', cellpadding:'0', cellspacing:'0', children:[
163 {tag:'tbody', children:[
164 {tag:'tr', children:[
165 {tag:'td', width:'20', align:'center', valign:'top', children:[
166 {tag:'img', id:'{elementID}', src:'{faviconUrl}'}
167 ]},
168 {tag:'td', valign:'top', children:[
169 {tag:'a', cls:'directLoginItemTitle', html:'{directLoginTitle}'}
170 ]}
171 ]}
172 ]}
173 ]}
174 ]});
175 this._directLoginItemTemplate.compile();
176 }
177
178 return this._directLoginItemTemplate;
179 },
180
181 //-------------------------------------------------------------------------
182
183 'handleDirectLoginClick': function(anEvent) {
184 vardirectLoginReference;
185//MochiKit.Logging.logDebug(">>> MainPanel.handleDirectLoginClick !!!");
186
187 directLoginReference = this.user().directLoginReferences()[anEvent.src().id];
188 this.openDirectLogin(directLoginReference);
189 this.resetAutoLockTimer();
190 //MochiKit.Logging.logDebug("<<< MainPanel.handleDirectLoginClick");
191 },
192
193 //-----------------------------------------------------
194
195 'openDirectLogin': function(aDirectLoginReference) {
196 vardeferredResult;
197 varnewWindow;
198
199//MochiKit.Logging.logDebug(">>> MainPanel.openDirectLogin - " + aDirectLoginReference.label());
200 deferredResult = new MochiKit.Async.Deferred();
201//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("MainPanel.openDirectLogin - 1: " + res); return res;});
202 deferredResult.addCallback(MochiKit.Base.method(aDirectLoginReference, 'setupJumpPageWindow'));
203 deferredResult.addCallback(MochiKit.Base.method(aDirectLoginReference, 'deferredDirectLogin'));
204 deferredResult.addCallback(function(aDirectLogin) {
205 aDirectLogin.runDirectLogin(newWindow);
206 });
207
208 newWindow = window.open(Clipperz.PM.Strings['directLoginJumpPageUrl'], "");
209 // MochiKit.Signal.connect(newWindow, 'onload', MochiKit.Base.method(deferredResult, 'callback', newWindow))
210 // MochiKit.Signal.connect(newWindow, 'onload', MochiKit.Base.partial(alert, "done"));
211 deferredResult.callback(newWindow);
212//MochiKit.Logging.logDebug("<<< MainPanel.openDirectLogin");
213 },
214
215 //-------------------------------------------------------------------------
216
217 'handleLoadedFaviconImage': function(anEvent) {
218//MochiKit.Logging.logDebug(">>> MainPanel.handleLoadedFaviconImage");
219 MochiKit.Signal.disconnectAll(anEvent.src())
220//MochiKit.Logging.logDebug("<<< MainPanel.handleLoadedFaviconImage");
221 },
222
223 //-------------------------------------------------------------------------
224
225 'doLockEventHandler': function(anEvent) {
226 anEvent.stop();
227 this.lock();
228 },
229
230 'doUnlockEventHandler': function(anEvent) {
231 if (typeof(anEvent.stop) != 'undefined') {
232 anEvent.stop();
233 }
234 this.unlock();
235 },
236
237 //-------------------------------------------------------------------------
238
239 'autolock': function() {
240 varshouldAutoLock;
241
242 shouldAutoLock = YAHOO.ext.Element.get('autolock').dom.checked;
243
244 if (shouldAutoLock) {
245 this.lock();
246 } else {
247 this.resetAutoLockTimer();
248 }
249 },
250
251 'lock': function() {
252//MochiKit.Logging.logDebug(">>> lock");
253 this.getDom('lockPassphrase').value = "";
254 this.getElement('lockPanel').show();
255 this.getElement('cantentPanel').hide();
256 YAHOO.ext.Element.get('lockBlock').hide();
257 //this.getElement('lockPassphrase').focus();
258//MochiKit.Logging.logDebug("<<< lock");
259 },
260
261 'unlock': function(anEvent) {
262//MochiKit.Logging.logDebug(">>> unlock");
263 if (this.getDom('lockPassphrase').value == this.user().passphrase()) {
264 this.getElement('lockPanel').hide();
265 this.getElement('cantentPanel').show();
266 YAHOO.ext.Element.get('lockBlock').show();
267 this.resetAutoLockTimer();
268 } else {
269 this.getDom('lockPassphrase').value = "";
270 this.getElement('lockPassphrase').focus();
271 }
272//MochiKit.Logging.logDebug("<<< unlock");
273 },
274
275 //-------------------------------------------------------------------------
276
277 'user': function() {
278 return this._user;
279 },
280
281 //-----------------------------------------------------
282
283 'autoLockTimer': function() {
284 if (this._autoLockTimer == null) {
285//MochiKit.Logging.logDebug("--- timer started - 1");
286 this._autoLockTimer = MochiKit.Async.callLater(60, MochiKit.Base.method(this, 'autolock'));
287//MochiKit.Logging.logDebug("--- timer started - 2");
288 }
289
290 return this._autoLockTimer;
291 },
292
293 'resetAutoLockTimer': function() {
294//MochiKit.Logging.logDebug(">>> timer resetted");
295 this.autoLockTimer().cancel();
296 this._autoLockTimer = null;
297//MochiKit.Logging.logDebug("--- timer resetted - 1");
298 this.autoLockTimer();
299//MochiKit.Logging.logDebug("<<< timer resetted");
300 },
301
302 //-----------------------------------------------------
303
304 'userNotificationHandler': function(anEvent) {
305 this.getElement('message').update(anEvent.parameters().text);
306 },
307
308 //-----------------------------------------------------
309 __syntaxFix__: '__syntaxFix__'
310});
311
312
diff --git a/frontend/beta/js/Clipperz/PM/Components/Compact/LoginForm.js b/frontend/beta/js/Clipperz/PM/Components/Compact/LoginForm.js
new file mode 100644
index 0000000..d708464
--- a/dev/null
+++ b/frontend/beta/js/Clipperz/PM/Components/Compact/LoginForm.js
@@ -0,0 +1,189 @@
1/*
2
3Copyright 2008-2011 Clipperz Srl
4
5This file is part of Clipperz's Javascript Crypto Library.
6Javascript Crypto Library provides web developers with an extensive
7and efficient set of cryptographic functions. The library aims to
8obtain maximum execution speed while preserving modularity and
9reusability.
10For further information about its features and functionalities please
11refer to http://www.clipperz.com
12
13* Javascript Crypto Library is free software: you can redistribute
14 it and/or modify it under the terms of the GNU Affero General Public
15 License as published by the Free Software Foundation, either version
16 3 of the License, or (at your option) any later version.
17
18* Javascript Crypto Library is distributed in the hope that it will
19 be useful, but WITHOUT ANY WARRANTY; without even the implied
20 warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
21 See the GNU Affero General Public License for more details.
22
23* You should have received a copy of the GNU Affero General Public
24 License along with Javascript Crypto Library. If not, see
25 <http://www.gnu.org/licenses/>.
26
27*/
28
29if (typeof(Clipperz) == 'undefined') { Clipperz = {}; }
30if (typeof(Clipperz.PM) == 'undefined') { Clipperz.PM = {}; }
31if (typeof(Clipperz.PM.Components) == 'undefined') { Clipperz.PM.Components = {}; }
32if (typeof(Clipperz.PM.Components.Compact) == 'undefined') { Clipperz.PM.Components.Compact = {}; }
33
34Clipperz.PM.Components.Compact.LoginForm = function(anElement, args) {
35
36 Clipperz.PM.Components.Compact.LoginForm.superclass.constructor.call(this, anElement, args);
37
38 this.render();
39 Clipperz.NotificationCenter.register(null, 'updatedProgressState', this, 'userNotificationHandler')
40
41 return this;
42};
43
44YAHOO.extendX(Clipperz.PM.Components.Compact.LoginForm, Clipperz.PM.Components.BaseComponent, {
45
46 'toString': function() {
47 return "Clipperz.PM.Components.Compact.LoginForm";
48 },
49
50 //-----------------------------------------------------
51
52 'render': function() {
53 var result;
54 varlayout;
55
56 MochiKit.Signal.disconnectAllTo(this);
57 this.element().update("");
58
59 Clipperz.YUI.DomHelper.append(this.element().dom, {tag:'div', id:this.getId('baseDiv'), cls:'LoginPanel', children:[
60 {tag:'div', id:'compactHeader'},
61 {tag:'div', id:'compactBody', children:[
62 {tag:'form', id:this.getId('loginForm_form'), children:[
63 {tag:'dl', children:[
64 {tag:'dt', htmlString:Clipperz.PM.Strings['loginFormUsernameLabel']},
65 {tag:'dd', children:[
66 {tag:'input', id:this.getId('login_username'), type:'text', size:'30', name:'username'}
67 ]},
68 {tag:'dt', htmlString:Clipperz.PM.Strings['loginFormPassphraseLabel']},
69 {tag:'dd', children:[
70 {tag:'input', id:this.getId('login_passphrase'), type:'password', size:'30', name:'passphrase'}
71 ]}
72 ]},
73 {tag:'div', id:this.getId('login_submit')}
74 ]},
75 {tag:'h4', id:this.getId('message')}
76 ]}
77 ]});
78
79 new Clipperz.PM.Components.Compact.CompactHeader(YAHOO.ext.Element.get('compactHeader'));
80
81 MochiKit.Signal.connect(this.getId('loginForm_form'), 'onsubmit', this, 'stopFormSubmit');
82 new YAHOO.ext.Button(this.getId('login_submit'), {text:Clipperz.PM.Strings['loginFormButtonLabel'], handler:this.doLogin, scope:this, minWidth:0});
83 this.getElement('login_submit').swallowEvent('click', true);
84
85 MochiKit.Signal.connect(this.getId('loginForm_form'), 'onkeydown', this, 'onkeydown');
86
87 new Clipperz.PM.Components.PasswordEntropyDisplay(this.getElement('login_passphrase'));
88 this.getElement('login_username').focus();
89
90 return result;
91 },
92
93 //-----------------------------------------------------
94
95 'doLogin': function(e) {
96//MochiKit.Logging.logDebug(">>> compact.LoginForm.doLogin");
97 if (this.checkLoginForm()) {
98 this.doLoginWithUsernameAndPassphrase(this.getDom('login_username').value, this.getDom('login_passphrase').value);
99 }
100//MochiKit.Logging.logDebug("<<< compact.LoginForm.doLogin");
101 },
102
103 //.........................................................................
104
105 'doLoginWithUsernameAndPassphrase': function(anUsername, aPassphrase) {
106 var deferredResult;
107 var user;
108
109//MochiKit.Logging.logDebug(">>> compact.LoginForm.doLoginWithUsernameAndPassphrase");
110 user = new Clipperz.PM.DataModel.User({username:anUsername, passphrase:aPassphrase});
111
112 deferredResult = new MochiKit.Async.Deferred();
113 deferredResult.addCallback(MochiKit.Base.method(user, 'connect'));
114 deferredResult.addCallback(MochiKit.Base.method(user, 'loadPreferences'));
115 deferredResult.addCallback(MochiKit.Base.method(user, 'loadRecords'));
116 deferredResult.addCallback(MochiKit.Base.method(user, 'loadDirectLogins'));
117 deferredResult.addErrback(MochiKit.Base.bind(function() {
118 this.getElement('loginForm_form').setVisibilityMode(YAHOO.ext.Element.DISPLAY).show();
119 this.getElement('message').update(Clipperz.PM.Strings['loginMessagePanelFailureText']);
120 this.getDom('login_passphrase').value = "";
121 this.getElement('login_passphrase').focus();
122 }, this))
123//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("compact.LoginForm.doLogin - 6: " + res); return res;});
124 deferredResult.callback("token");
125//MochiKit.Logging.logDebug("<<< compact.LoginForm.doLoginWithUsernameAndPassphrase");
126
127 return deferredResult;
128 },
129
130 //.........................................................................
131
132 'checkLoginForm': function() {
133 var result;
134 var username
135 varpassphrase;
136
137//MochiKit.Logging.logDebug(">>> checkLoginForm");
138 username = this.getDom('login_username').value;
139 passphrase = this.getDom('login_passphrase').value;
140
141 if ((username != "") && (passphrase != "")) {
142 result = true;
143 } else {
144 if (username == "") {
145 this.getElement('login_username').focus();
146 } else if (passphrase == "") {
147 this.getElement('login_passphrase').focus();
148 }
149
150 result = false;
151 }
152//MochiKit.Logging.logDebug("<<< checkLoginForm - " + result);
153
154 return result;
155 },
156
157 //-------------------------------------------------------------------------
158
159 'stopFormSubmit': function(anEvent) {
160 anEvent.stop();
161 },
162
163 //-------------------------------------------------------------------------
164
165 'onkeydown': function(anEvent) {
166//MochiKit.Logging.logDebug(">>> onkeydown - " + anEvent.src().id);
167 if (anEvent.key().code == 13) {
168 this.doLogin();
169 anEvent.stop();
170 }
171 },
172
173 //-----------------------------------------------------
174
175 'userNotificationHandler': function(anEvent) {
176//MochiKit.Logging.logDebug(">>> compact.LoginForm.userNotificationHandler");
177//MochiKit.Logging.logDebug("userNotificationHandler - event: " + anEvent.event());
178 this.getElement('loginForm_form').setVisibilityMode(YAHOO.ext.Element.DISPLAY).hide();
179 if (this.getDom('message') != null) {
180 this.getElement('message').update(Clipperz.PM.Strings.messagePanelConfigurations[anEvent.parameters()]()['text']);
181 }
182//MochiKit.Logging.logDebug("<<< compact.LoginForm.userNotificationHandler");
183 },
184
185 //-----------------------------------------------------
186 __syntaxFix__: '__syntaxFix__'
187});
188
189
diff --git a/frontend/beta/js/Clipperz/PM/Components/Import/CSVImport/CSVImportColumns.js b/frontend/beta/js/Clipperz/PM/Components/Import/CSVImport/CSVImportColumns.js
new file mode 100644
index 0000000..18b36da
--- a/dev/null
+++ b/frontend/beta/js/Clipperz/PM/Components/Import/CSVImport/CSVImportColumns.js
@@ -0,0 +1,174 @@
1/*
2
3Copyright 2008-2011 Clipperz Srl
4
5This file is part of Clipperz's Javascript Crypto Library.
6Javascript Crypto Library provides web developers with an extensive
7and efficient set of cryptographic functions. The library aims to
8obtain maximum execution speed while preserving modularity and
9reusability.
10For further information about its features and functionalities please
11refer to http://www.clipperz.com
12
13* Javascript Crypto Library is free software: you can redistribute
14 it and/or modify it under the terms of the GNU Affero General Public
15 License as published by the Free Software Foundation, either version
16 3 of the License, or (at your option) any later version.
17
18* Javascript Crypto Library is distributed in the hope that it will
19 be useful, but WITHOUT ANY WARRANTY; without even the implied
20 warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
21 See the GNU Affero General Public License for more details.
22
23* You should have received a copy of the GNU Affero General Public
24 License along with Javascript Crypto Library. If not, see
25 <http://www.gnu.org/licenses/>.
26
27*/
28
29if (typeof(Clipperz) == 'undefined') { Clipperz = {}; }
30if (typeof(Clipperz.PM) == 'undefined') { Clipperz.PM = {}; }
31if (typeof(Clipperz.PM.Components) == 'undefined') { Clipperz.PM.Components = {}; }
32if (typeof(Clipperz.PM.Components.Import) == 'undefined') { Clipperz.PM.Components.Import = {}; }
33if (typeof(Clipperz.PM.Components.Import.CSVImport) == 'undefined') { Clipperz.PM.Components.Import.CSVImport = {}; }
34
35//#############################################################################
36
37Clipperz.PM.Components.Import.CSVImport.CSVImportColumns = function(anElement, args) {
38 args = args || {};
39
40 Clipperz.PM.Components.Import.CSVImport.CSVImportColumns.superclass.constructor.call(this, anElement, args);
41 this._mainComponent = args.mainComponent;
42
43 return this;
44}
45
46//=============================================================================
47
48YAHOO.extendX(Clipperz.PM.Components.Import.CSVImport.CSVImportColumns, Clipperz.PM.Components.BaseComponent, {
49
50 'toString': function() {
51 return "Clipperz.PM.Components.Import.CSVImport.CSVImportColumns component";
52 },
53
54 //-------------------------------------------------------------------------
55
56 'mainComponent': function() {
57 return this._mainComponent;
58 },
59
60 //-------------------------------------------------------------------------
61
62 'render': function() {
63 var i,c;
64 var columnSelectorCheckboxCells;
65 var checkboxes;
66 var data;
67
68//MochiKit.Logging.logDebug(">>> CSVImportColumns.render");
69 Clipperz.NotificationCenter.unregister(this);
70 MochiKit.Signal.disconnectAllTo(this);
71
72 this.element().update("");
73
74 data = this.mainComponent().parsedValues();
75 columnSelectorCheckboxCells = [];
76
77 c =data[0].length;
78 for (i=0; i<c; i++) {
79 columnSelectorCheckboxCells.push({tag:'th', valign:'top', cls:(this.mainComponent().isColumnSelected(i) ? 'selectedColumn': 'skippedColumn'), children:[
80 {tag:'input', type:'checkbox', id:this.getId('columnCheckbox_' + i), value:i}
81 ]})
82 }
83
84 this.domHelper().append(this.element(), {tag:'div', children:[
85 {tag:'div', cls:'importStepDescription', htmlString:Clipperz.PM.Strings['CSV_ImportWizard_Columns']},
86 {tag:'div', id:this.getId('dataDiv'), cls:'csvImportPreview', children:[
87 {tag:'table', id:this.getId('previewDada'), cls:'csvImportPreview columns', cellspacing:'0', children:[
88 {tag:'thead', id:this.getId('previewData_thead'), children:[
89 {tag:'tr', children:columnSelectorCheckboxCells}
90 ]},
91 {tag:'tbody', id:this.getId('previewData_tbody'), children:[]}
92 ]}
93 ]}
94 ]});
95
96 c =data[0].length;
97 for (i=0; i<c; i++) {
98 if (this.mainComponent().isColumnSelected(i)) {
99 this.getDom('columnCheckbox_' + i).checked = true;
100 }
101 }
102
103 this.renderData(this.getElement('previewData_tbody'), data);
104
105 checkboxes = MochiKit.DOM.getElementsByTagAndClassName('input', null, this.getDom('previewData_thead'));
106 c = checkboxes.length;
107 for (i=0; i<c; i++) {
108 MochiKit.Signal.connect(checkboxes[i], 'onclick', this, 'renderDataHandler');
109 }
110//MochiKit.Logging.logDebug("<<< CSVImportColumns.render");
111 },
112
113 //-------------------------------------------------------------------------
114
115 'renderData': function(anElement, someData) {
116 var config;
117 var i,c;
118
119//MochiKit.Logging.logDebug(">>> CSVImportColumns.renderData");
120 // anElement.update("");
121 MochiKit.DOM.replaceChildNodes(anElement.dom);
122
123 config = MochiKit.Base.map(MochiKit.Base.bind(function(aRowData) {
124 var result;
125 var i,c;
126
127 result = {tag:'tr', children:[]};
128 c = aRowData.length;
129 for (i=0; i<c; i++) {
130 var field;
131
132 field = aRowData[i];
133 result.children.push({tag:'td', valign:'top', cls:(this.mainComponent().isColumnSelected(i) ? 'selectedColumn': 'skippedColumn'), html:(MochiKit.Base.isNotEmpty(field) ? field.replace(/\n/g, '<br>') : '&nbsp;')});
134 }
135
136 return result;
137 }, this), someData);
138
139 MochiKit.Base.map(function(aRowConfig) {Clipperz.YUI.DomHelper.append(anElement, aRowConfig);}, config);
140
141 Clipperz.Style.applyZebraStylesToTable(this.getId('previewDada'));
142//MochiKit.Logging.logDebug("<<< CSVImportColumns.renderData");
143 },
144
145 //-------------------------------------------------------------------------
146
147 'renderDataHandler': function(anEvent) {
148 var thElement;
149
150 thElement = YAHOO.ext.Element.get(anEvent.src().parentNode);
151
152 if (anEvent.src().checked == true) {
153 this.mainComponent().skippedColumns().remove(anEvent.src().value);
154 thElement.addClass('selectedColumn');
155 thElement.removeClass('skippedColumn');
156 } else {
157 this.mainComponent().skippedColumns().add(anEvent.src().value);
158 thElement.removeClass('selectedColumn');
159 thElement.addClass('skippedColumn');
160 }
161
162 if (this.mainComponent().skippedColumns().allItems().length == this.mainComponent().parsedValues()[0].length) {
163 this.mainComponent().nextButton().disable();
164 } else {
165 this.mainComponent().nextButton().enable();
166 }
167
168 this.renderData(this.getElement('previewData_tbody'), this.mainComponent().parsedValues());
169 },
170
171 //-------------------------------------------------------------------------
172 __syntaxFix__: "syntax fix"
173});
174
diff --git a/frontend/beta/js/Clipperz/PM/Components/Import/CSVImport/CSVImportFields.js b/frontend/beta/js/Clipperz/PM/Components/Import/CSVImport/CSVImportFields.js
new file mode 100644
index 0000000..a368747
--- a/dev/null
+++ b/frontend/beta/js/Clipperz/PM/Components/Import/CSVImport/CSVImportFields.js
@@ -0,0 +1,247 @@
1/*
2
3Copyright 2008-2011 Clipperz Srl
4
5This file is part of Clipperz's Javascript Crypto Library.
6Javascript Crypto Library provides web developers with an extensive
7and efficient set of cryptographic functions. The library aims to
8obtain maximum execution speed while preserving modularity and
9reusability.
10For further information about its features and functionalities please
11refer to http://www.clipperz.com
12
13* Javascript Crypto Library is free software: you can redistribute
14 it and/or modify it under the terms of the GNU Affero General Public
15 License as published by the Free Software Foundation, either version
16 3 of the License, or (at your option) any later version.
17
18* Javascript Crypto Library is distributed in the hope that it will
19 be useful, but WITHOUT ANY WARRANTY; without even the implied
20 warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
21 See the GNU Affero General Public License for more details.
22
23* You should have received a copy of the GNU Affero General Public
24 License along with Javascript Crypto Library. If not, see
25 <http://www.gnu.org/licenses/>.
26
27*/
28
29if (typeof(Clipperz) == 'undefined') { Clipperz = {}; }
30if (typeof(Clipperz.PM) == 'undefined') { Clipperz.PM = {}; }
31if (typeof(Clipperz.PM.Components) == 'undefined') { Clipperz.PM.Components = {}; }
32if (typeof(Clipperz.PM.Components.Import) == 'undefined') { Clipperz.PM.Components.Import = {}; }
33if (typeof(Clipperz.PM.Components.Import.CSVImport) == 'undefined') { Clipperz.PM.Components.Import.CSVImport = {}; }
34
35//#############################################################################
36
37Clipperz.PM.Components.Import.CSVImport.CSVImportFields = function(anElement, args) {
38 args = args || {};
39
40 Clipperz.PM.Components.Import.CSVImport.CSVImportFields.superclass.constructor.call(this, anElement, args);
41 this._mainComponent = args.mainComponent;
42
43 return this;
44}
45
46//=============================================================================
47
48YAHOO.extendX(Clipperz.PM.Components.Import.CSVImport.CSVImportFields, Clipperz.PM.Components.BaseComponent, {
49
50 'toString': function() {
51 return "Clipperz.PM.Components.Import.CSVImport.CSVImportFields component";
52 },
53
54 //-------------------------------------------------------------------------
55
56 'mainComponent': function() {
57 return this._mainComponent;
58 },
59
60 //-------------------------------------------------------------------------
61
62 'render': function() {
63 varfieldsHeaderCells;
64 var titleColumnIndex;
65 var notesColumnIndex;
66 var i,c;
67
68 Clipperz.NotificationCenter.unregister(this);
69 MochiKit.Signal.disconnectAllTo(this);
70
71 this.element().update("");
72
73 titleColumnIndex = this.mainComponent().titleColumnIndex()
74 notesColumnIndex = this.mainComponent().notesColumnIndex()
75
76 fieldsHeaderCells = [];
77 fieldsHeaderCells.push({tag:'td', valign:'top', cls:'title', html:this.mainComponent().labelForColumn(titleColumnIndex)});
78
79 c =this.mainComponent().parsedValues()[0].length;
80 for (i=0; i<c; i++) {
81 if ((i != titleColumnIndex) && (i != notesColumnIndex) && (this.mainComponent().isColumnSelected(i))) {
82 var trimmedLabel;
83
84 trimmedLabel = Clipperz.Base.trim(this.mainComponent().labelForColumn(i));
85 fieldsHeaderCells.push({tag:'td', valign:'top', id:this.getId('fieldHeaderTD_' + i), cls:((trimmedLabel == "") ? 'missingLabelWarning' : (this.isColumnSetup(i) ? 'configuredColumn': 'unconfiguredColumn')), children:[
86 {tag:'span', html:((trimmedLabel == "") ? Clipperz.PM.Strings['CSV_ImportWizard_Fields_MissingLabelWarning'] : trimmedLabel)/*, cls:((trimmedLabel == "") ? 'missingLabelWarning' : '')*/},
87 {tag:'select', id:this.getId('select_' + i), name:i, children:[
88 {tag:'option', value:'UNDEFINED', html:"select data type", cls:'disabledOption'},
89 {tag:'option', value:'TXT', htmlString:Clipperz.PM.Strings['recordFieldTypologies']['TXT']['shortDescription']},
90 {tag:'option', value:'PWD', htmlString:Clipperz.PM.Strings['recordFieldTypologies']['PWD']['shortDescription']},
91 {tag:'option', value:'URL', htmlString:Clipperz.PM.Strings['recordFieldTypologies']['URL']['shortDescription']},
92 {tag:'option', value:'DATE', htmlString:Clipperz.PM.Strings['recordFieldTypologies']['DATE']['shortDescription']},
93 {tag:'option', value:'ADDR', htmlString:Clipperz.PM.Strings['recordFieldTypologies']['ADDR']['shortDescription']}
94 ]}
95 ]})
96 }
97 }
98
99 if (notesColumnIndex != -1) {
100 fieldsHeaderCells.push({tag:'td', valign:'top', cls:'notes', html:this.mainComponent().labelForColumn(notesColumnIndex)});
101 }
102
103 this.domHelper().append(this.element(), {tag:'div', children:[
104 {tag:'div', cls:'importStepDescription', htmlString:Clipperz.PM.Strings['CSV_ImportWizard_Fields']},
105 {tag:'div', id:this.getId('dataDiv'), children:[
106 {tag:'div', children:[
107 ]},
108 {tag:'div', cls:'csvImportPreview', children:[
109 {tag:'table', id:this.getId('previewDada'), cls:'csvImportPreview', cellspacing:'0', children:[
110 {tag:'thead', id:this.getId('previewData_thead'), children:[
111 {tag:'tr', cls:'CSV_previewData_header', children:fieldsHeaderCells}
112 ]},
113 {tag:'tbody', id:this.getId('previewData_tbody'), children:[]}
114 ]}
115 ]}
116 ]}
117 ]});
118
119 for (i=0; i<c; i++) {
120 if ((i != titleColumnIndex) && (i != notesColumnIndex) && (this.mainComponent().isColumnSelected(i))) {
121 Clipperz.DOM.selectOptionMatchingValue(this.getDom('select_' + i), this.mainComponent().typeForColumn(i));
122 MochiKit.Signal.connect(this.getDom('select_' + i), 'onchange', this, 'renderDataRowsHandler');
123 }
124 }
125
126 this.renderDataRows(this.getElement('previewData_tbody'));
127 // Clipperz.NotificationCenter.register(null, 'updatedCSVImportColumnHeader', this, 'renderDataRowsHandler');
128 },
129
130 //-------------------------------------------------------------------------
131
132 'isColumnSetup': function(aColumnIndex) {
133 return ((Clipperz.Base.trim(this.mainComponent().labelForColumn(aColumnIndex)) != "") && (this.mainComponent().typeForColumn(aColumnIndex) != 'UNDEFINED'));
134 },
135
136 //-------------------------------------------------------------------------
137
138 'renderDataRowsHandler': function(anEvent) {
139 var columnIndex;
140 var tdElement;
141
142//MochiKit.Logging.logDebug(">>> renderDataRowsHandler")
143 columnIndex = anEvent.src().name;
144 this.mainComponent().setTypeForColumn(anEvent.src().value, columnIndex);
145
146 tdElement = this.getElement('fieldHeaderTD_' + columnIndex);
147
148 if (this.isColumnSetup(columnIndex)) {
149 tdElement.removeClass('unconfiguredColumn');
150 tdElement.addClass('configuredColumn');
151 } else {
152 tdElement.addClass('unconfiguredColumn');
153 tdElement.removeClass('configuredColumn');
154 }
155
156 this.renderDataRows(this.getElement('previewData_tbody'));
157 },
158
159 //-------------------------------------------------------------------------
160
161 'renderDataRows': function(anElement) {
162 var titleColumnIndex;
163 var notesColumnIndex;
164 var data
165 var i,c;
166
167//MochiKit.Logging.logDebug("#### >> renderDataRows");
168 // anElement.update("");
169 MochiKit.DOM.replaceChildNodes(anElement.dom);
170
171 if (this.mainComponent().isFirstRowHeader()) {
172 data = this.mainComponent().parsedValues().slice(1);
173 } else {
174 data = this.mainComponent().parsedValues();
175 }
176
177
178 titleColumnIndex = this.mainComponent().titleColumnIndex();
179 notesColumnIndex = this.mainComponent().notesColumnIndex();
180
181 c = data.length;
182 for (i=0; i<c; i++) {
183 var rowData;
184 var rowConfig;
185 var ii, cc;
186
187 rowData = data[i];
188
189 rowConfig = {tag:'tr', children:[
190 {tag:'td', valign:'top', cls:'title', html:(MochiKit.Base.isNotEmpty(rowData[titleColumnIndex]) ? rowData[titleColumnIndex].replace(/\n/g, '<br>') : '&nbsp;')}
191 ]};
192
193 cc = rowData.length;
194 for (ii=0; ii<cc; ii++) {
195 // if ((ii != titleColumnIndex) && (ii != notesColumnIndex)) {
196 if ((ii != titleColumnIndex) && (ii != notesColumnIndex) && (this.mainComponent().isColumnSelected(ii))) {
197 rowConfig.children.push({
198 tag:'td',
199 valign:'top',
200 cls:(this.isColumnSetup(ii) ? 'configuredColumn' : 'unconfiguredColumn'),
201 html:(MochiKit.Base.isNotEmpty(rowData[ii]) ? rowData[ii].replace(/\n/g, '<br>') : '&nbsp;')
202 });
203 }
204 }
205 if (notesColumnIndex != -1) {
206 rowConfig.children.push({tag:'td', valign:'top', cls:'notes', html:(MochiKit.Base.isNotEmpty(rowData[notesColumnIndex]) ? rowData[notesColumnIndex].replace(/\n/g, '<br>') : '&nbsp;')});
207 }
208
209 this.domHelper().append(anElement, rowConfig);
210 }
211
212 Clipperz.Style.applyZebraStylesToTable(this.getId('previewDada'));
213
214 this.checkWetherToEnableNextButton();
215//MochiKit.Logging.logDebug("#### << renderDataRows");
216 },
217
218 //-------------------------------------------------------------------------
219
220 'checkWetherToEnableNextButton': function() {
221 var result;
222 var titleColumnIndex;
223 var notesColumnIndex;
224 var i,c;
225
226 titleColumnIndex = this.mainComponent().titleColumnIndex()
227 notesColumnIndex = this.mainComponent().notesColumnIndex()
228
229 result = true;
230 c =this.mainComponent().parsedValues()[0].length;
231 for (i=0; i<c; i++) {
232 if ((i != titleColumnIndex) && (i != notesColumnIndex) && (this.mainComponent().isColumnSelected(i))) {
233 result = result && this.isColumnSetup(i);
234 }
235 }
236
237 if (result) {
238 this.mainComponent().nextButton().enable();
239 } else {
240 this.mainComponent().nextButton().disable();
241 }
242 },
243
244 //-------------------------------------------------------------------------
245 __syntaxFix__: "syntax fix"
246});
247
diff --git a/frontend/beta/js/Clipperz/PM/Components/Import/CSVImport/CSVImportHeader.js b/frontend/beta/js/Clipperz/PM/Components/Import/CSVImport/CSVImportHeader.js
new file mode 100644
index 0000000..ebd243a
--- a/dev/null
+++ b/frontend/beta/js/Clipperz/PM/Components/Import/CSVImport/CSVImportHeader.js
@@ -0,0 +1,240 @@
1/*
2
3Copyright 2008-2011 Clipperz Srl
4
5This file is part of Clipperz's Javascript Crypto Library.
6Javascript Crypto Library provides web developers with an extensive
7and efficient set of cryptographic functions. The library aims to
8obtain maximum execution speed while preserving modularity and
9reusability.
10For further information about its features and functionalities please
11refer to http://www.clipperz.com
12
13* Javascript Crypto Library is free software: you can redistribute
14 it and/or modify it under the terms of the GNU Affero General Public
15 License as published by the Free Software Foundation, either version
16 3 of the License, or (at your option) any later version.
17
18* Javascript Crypto Library is distributed in the hope that it will
19 be useful, but WITHOUT ANY WARRANTY; without even the implied
20 warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
21 See the GNU Affero General Public License for more details.
22
23* You should have received a copy of the GNU Affero General Public
24 License along with Javascript Crypto Library. If not, see
25 <http://www.gnu.org/licenses/>.
26
27*/
28
29if (typeof(Clipperz) == 'undefined') { Clipperz = {}; }
30if (typeof(Clipperz.PM) == 'undefined') { Clipperz.PM = {}; }
31if (typeof(Clipperz.PM.Components) == 'undefined') { Clipperz.PM.Components = {}; }
32if (typeof(Clipperz.PM.Components.Import) == 'undefined') { Clipperz.PM.Components.Import = {}; }
33if (typeof(Clipperz.PM.Components.Import.CSVImport) == 'undefined') { Clipperz.PM.Components.Import.CSVImport = {}; }
34
35//#############################################################################
36
37Clipperz.PM.Components.Import.CSVImport.CSVImportHeader = function(anElement, args) {
38 args = args || {};
39
40 Clipperz.PM.Components.Import.CSVImport.CSVImportHeader.superclass.constructor.call(this, anElement, args);
41 this._mainComponent = args.mainComponent;
42
43 this._pendingDeferredLabelFieldHandlerEvents = 0;
44
45 return this;
46}
47
48//=============================================================================
49
50YAHOO.extendX(Clipperz.PM.Components.Import.CSVImport.CSVImportHeader, Clipperz.PM.Components.BaseComponent, {
51
52 'toString': function() {
53 return "Clipperz.PM.Components.Import.CSVImport.CSVImportHeader component";
54 },
55
56 //-------------------------------------------------------------------------
57
58 'mainComponent': function() {
59 return this._mainComponent;
60 },
61
62 //-------------------------------------------------------------------------
63
64 'render': function() {
65 var thConfigs;
66 var i,c;
67
68//MochiKit.Logging.logDebug(">>> CSVImportHeader.render");
69 Clipperz.NotificationCenter.unregister(this);
70 MochiKit.Signal.disconnectAllTo(this);
71
72 thConfigs = [];
73 c = this.mainComponent().parsedValues()[0].length;
74 for (i=0; i<c; i++) {
75 if (this.mainComponent().isColumnSelected(i)) {
76 // thConfigs.push({tag:'th', children:[{tag:'input', type:'text', id:this.getId('headerTextField_' + i), value:this.mainComponent().labelForColumn(i)}]});
77 thConfigs.push({tag:'th', children:[{tag:'input', type:'text', id:this.getId('headerTextField_' + i), value:""}]});
78 }
79 }
80
81 this.element().update("");
82 this.domHelper().append(this.element(), {tag:'div', children:[
83 {tag:'div', cls:'importStepDescription', htmlString:Clipperz.PM.Strings['CSV_ImportWizard_Header']},
84 {tag:'div', cls:'importStepParameters', children:[
85 {tag:'input', type:'checkbox', name:'isFistRowHeader', id:this.getId('isFirstRowHeader_checkbox')},
86 {tag:'span', id:this.getId('isFirstRowHeader_span'), cls:'clickableSpan', htmlString:Clipperz.PM.Strings['CSV_ImportWizard_Header_Settings_firstRowHeaderLabel']}
87 ]},
88 {tag:'div', id:this.getId('dataDiv'), children:[
89 {tag:'div', cls:'csvImportPreview', children:[
90 {tag:'table', id:this.getId('previewDada'), cls:'csvImportPreview header', cellspacing:'0', children:[
91 {tag:'thead', children:[{tag:'tr', children:thConfigs}]},
92 {tag:'tbody', id:this.getId('previewData_tbody')}
93 ]}
94 ]}
95 ]}
96 ]});
97
98 for (i=0; i<c; i++) {
99 if (this.mainComponent().isColumnSelected(i)) {
100 this.getElement('headerTextField_' + i).dom.value = this.mainComponent().labelForColumn(i);
101 }
102 }
103
104 this.renderData(this.getElement('previewData_tbody'), this.mainComponent().parsedValues());
105
106 if (this.mainComponent().isFirstRowHeader()) {
107 this.getDom('isFirstRowHeader_checkbox').click();
108 }
109
110 c = this.mainComponent().parsedValues()[0].length;
111 for (i=0; i<c; i++) {
112 if (this.mainComponent().isColumnSelected(i)) {
113 MochiKit.Signal.connect(this.getDom('headerTextField_' + i), 'onchange', MochiKit.Base.partial(MochiKit.Base.method(this, 'labelFieldHandler'), i));
114 MochiKit.Signal.connect(this.getDom('headerTextField_' + i), 'onkeypress', MochiKit.Base.partial(MochiKit.Base.method(this, 'deferredLabelFieldHandler'), i));
115 }
116 }
117
118 MochiKit.Signal.connect(this.getDom('isFirstRowHeader_checkbox'), 'onclick', this, 'toggleFirstRowHeaderCheckboxHandler');
119 if (Clipperz_IEisBroken != true) {
120 MochiKit.Signal.connect(this.getDom('isFirstRowHeader_span'), 'onclick', this.getDom('isFirstRowHeader_checkbox'), 'click');
121 }
122//MochiKit.Logging.logDebug("<<< CSVImportHeader.render");
123 },
124
125 //-------------------------------------------------------------------------
126
127 'renderData': function(anElement, someData) {
128 var trConfigs;
129 var data;
130 var i,c;
131
132 // anElement.update("");
133 MochiKit.DOM.replaceChildNodes(anElement.dom);
134
135 if (this.mainComponent().isFirstRowHeader()) {
136 data = someData.slice(1);
137 } else {
138 data = someData;
139 }
140
141 trConfigs = MochiKit.Base.map(MochiKit.Base.bind(function(aRowData) {
142 var result;
143 var i,c;
144
145 result = {tag:'tr', children:[]};
146 c = aRowData.length;
147 for (i=0; i<c; i++) {
148 if (this.mainComponent().isColumnSelected(i)) {
149 result.children.push({tag:'td', valign:'top', html:(MochiKit.Base.isNotEmpty(aRowData[i]) ? aRowData[i].replace(/\n/g, '<br>') : '&nbsp;')});
150 }
151 }
152
153 return result;
154 }, this), data);
155
156 MochiKit.Base.map(function(aRowConfig) {Clipperz.YUI.DomHelper.append(anElement, aRowConfig);}, trConfigs);
157
158 Clipperz.Style.applyZebraStylesToTable(this.getId('previewDada'));
159 },
160
161 //-------------------------------------------------------------------------
162
163 'toggleFirstRowHeaderCheckboxHandler': function() {
164 var firstRowData;
165 var i,c;
166
167//MochiKit.Logging.logDebug(">>> toggleFirstRowHeaderCheckboxHandler");
168 this.mainComponent().setIsFirstRowHeader(this.getDom('isFirstRowHeader_checkbox').checked);
169
170 firstRowData = this.mainComponent().parsedValues()[0];
171
172 c = firstRowData.length;
173 for (i=0; i<c; i++) {
174 if (this.mainComponent().isColumnSelected(i)) {
175 var label;
176
177 if (this.mainComponent().isFirstRowHeader()) {
178 label = firstRowData[i];
179 } else {
180 label = null;
181 }
182
183 this.mainComponent().setLabelForColumn(label, i);
184 }
185 };
186
187 this.updateInputFieldValues();
188 this.renderData(this.getElement('previewData_tbody'), this.mainComponent().parsedValues());
189//MochiKit.Logging.logDebug("<<< toggleFirstRowHeaderCheckboxHandler");
190 },
191
192 //-------------------------------------------------------------------------
193
194 'updateInputFieldValues': function() {
195 var i,c;
196
197//MochiKit.Logging.logDebug(">>> updateInputFieldValues");
198 c = this.mainComponent().parsedValues()[0].length;
199 for (i=0; i<c; i++) {
200 if (this.mainComponent().isColumnSelected(i)) {
201 this.getDom('headerTextField_' + i).value = this.mainComponent().labelForColumn(i);
202 }
203 }
204//console.log('[1] fieldSettings', fieldSettings);
205//MochiKit.Logging.logDebug("<<< updateInputFieldValues");
206 },
207
208 //-------------------------------------------------------------------------
209
210 'labelFieldHandler': function(aColumnIndex, anEvent) {
211 var inputField;
212
213//MochiKit.Logging.logDebug(">>> labelFieldHandler");
214 inputField = anEvent.src();
215
216 this.mainComponent().setLabelForColumn(inputField.value, aColumnIndex);
217//MochiKit.Logging.logDebug("##### [" + anEvent.src().id + "] -> label[" + aColumnIndex + "]: '" + inputField.value + "'");
218//MochiKit.Logging.logDebug("<<< labelFieldHandler");
219 },
220
221 'deferredLabelFieldHandler': function(aColumnIndex, anEvent) {
222//MochiKit.Logging.logDebug(">>> deferredLabelFieldHandler");
223 this._pendingDeferredLabelFieldHandlerEvents ++;
224 MochiKit.Async.callLater(1, MochiKit.Base.partial(MochiKit.Base.method(this, 'deferredLabelFieldHandlerCatcher'), aColumnIndex, anEvent));
225//MochiKit.Logging.logDebug("<<< deferredLabelFieldHandler");
226 },
227
228 'deferredLabelFieldHandlerCatcher': function(aColumnIndex, anEvent) {
229//MochiKit.Logging.logDebug(">>> deferredLabelFieldHandlerCatcher");
230 this._pendingDeferredLabelFieldHandlerEvents --;
231 if (this._pendingDeferredLabelFieldHandlerEvents == 0) {
232 this.labelFieldHandler(aColumnIndex, anEvent);
233 }
234//MochiKit.Logging.logDebug("<<< deferredLabelFieldHandlerCatcher");
235 },
236
237 //-------------------------------------------------------------------------
238 __syntaxFix__: "syntax fix"
239});
240
diff --git a/frontend/beta/js/Clipperz/PM/Components/Import/CSVImport/CSVImportNotes.js b/frontend/beta/js/Clipperz/PM/Components/Import/CSVImport/CSVImportNotes.js
new file mode 100644
index 0000000..a53c531
--- a/dev/null
+++ b/frontend/beta/js/Clipperz/PM/Components/Import/CSVImport/CSVImportNotes.js
@@ -0,0 +1,212 @@
1/*
2
3Copyright 2008-2011 Clipperz Srl
4
5This file is part of Clipperz's Javascript Crypto Library.
6Javascript Crypto Library provides web developers with an extensive
7and efficient set of cryptographic functions. The library aims to
8obtain maximum execution speed while preserving modularity and
9reusability.
10For further information about its features and functionalities please
11refer to http://www.clipperz.com
12
13* Javascript Crypto Library is free software: you can redistribute
14 it and/or modify it under the terms of the GNU Affero General Public
15 License as published by the Free Software Foundation, either version
16 3 of the License, or (at your option) any later version.
17
18* Javascript Crypto Library is distributed in the hope that it will
19 be useful, but WITHOUT ANY WARRANTY; without even the implied
20 warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
21 See the GNU Affero General Public License for more details.
22
23* You should have received a copy of the GNU Affero General Public
24 License along with Javascript Crypto Library. If not, see
25 <http://www.gnu.org/licenses/>.
26
27*/
28
29if (typeof(Clipperz) == 'undefined') { Clipperz = {}; }
30if (typeof(Clipperz.PM) == 'undefined') { Clipperz.PM = {}; }
31if (typeof(Clipperz.PM.Components) == 'undefined') { Clipperz.PM.Components = {}; }
32if (typeof(Clipperz.PM.Components.Import) == 'undefined') { Clipperz.PM.Components.Import = {}; }
33if (typeof(Clipperz.PM.Components.Import.CSVImport) == 'undefined') { Clipperz.PM.Components.Import.CSVImport = {}; }
34
35//#############################################################################
36
37Clipperz.PM.Components.Import.CSVImport.CSVImportNotes = function(anElement, args) {
38 args = args || {};
39
40 Clipperz.PM.Components.Import.CSVImport.CSVImportNotes.superclass.constructor.call(this, anElement, args);
41 this._mainComponent = args.mainComponent;
42
43 return this;
44}
45
46//=============================================================================
47
48YAHOO.extendX(Clipperz.PM.Components.Import.CSVImport.CSVImportNotes, Clipperz.PM.Components.BaseComponent, {
49
50 'toString': function() {
51 return "Clipperz.PM.Components.Import.CSVImport.CSVImportNotes component";
52 },
53
54 //-------------------------------------------------------------------------
55
56 'mainComponent': function() {
57 return this._mainComponent;
58 },
59
60 //-------------------------------------------------------------------------
61
62 'render': function() {
63 varnotesSelectorCheckboxCells;
64 var totalNumberOfColumns;
65 var titleColumnIndex;
66 var notesColumnIndex;
67 var i,c;
68
69 Clipperz.NotificationCenter.unregister(this);
70 MochiKit.Signal.disconnectAllTo(this);
71
72 this.element().update("");
73
74 titleColumnIndex = this.mainComponent().titleColumnIndex()
75 notesColumnIndex = this.mainComponent().notesColumnIndex()
76
77 totalNumberOfColumns = this.mainComponent().parsedValues()[0].length;
78
79 notesSelectorCheckboxCells = [{tag:'th', cls:'title', html:this.mainComponent().labelForColumn(titleColumnIndex)}];
80 c =totalNumberOfColumns;
81 for (i=0; i<c; i++) {
82 if ((i != titleColumnIndex) && (this.mainComponent().isColumnSelected(i))) {
83 notesSelectorCheckboxCells.push({tag:'th', id:this.getId('th_' + i), valign:'top', children:[
84 {tag:'input', type:'radio', id:this.getId('radio_' + i), name:'CSVImportNotesColumn', value:i},
85 {tag:'span', cls:'clickableSpan', id:this.getId('columnLabel_' + i), html:this.mainComponent().labelForColumn(i)}
86 ]})
87 }
88 }
89
90 this.domHelper().append(this.element(), {tag:'div', children:[
91 {tag:'div', cls:'importStepDescription', htmlString:Clipperz.PM.Strings['CSV_ImportWizard_Notes']},
92 {tag:'div', id:this.getId('dataDiv'), children:[
93 {tag:'div', cls:'importStepParameters', children:[
94 {tag:'input', id:this.getId('doNotSetNotes_radio'), type:'radio', name:'CSVImportNotesColumn', value:-1},
95 {tag:'span', id:this.getId('doNotSetNotes_span'), cls:'clickableSpan', htmlString:Clipperz.PM.Strings['CSV_ImportWizard_Notes_Settings_noSelectionLabel']}
96 ]},
97 {tag:'div', cls:'csvImportPreview', children:[
98 {tag:'table', id:this.getId('previewDada'), cls:'csvImportPreview', cellspacing:'0', children:[
99 {tag:'thead', id:this.getId('previewData_thead'), children:[
100 {tag:'tr', children:notesSelectorCheckboxCells}
101 ]},
102 {tag:'tbody', id:this.getId('previewData_tbody'), children:[]}
103 ]}
104 ]}
105 ]}
106 ]});
107
108 this.renderData(this.getElement('previewData_tbody'), this.mainComponent().parsedValues());
109
110 if ((notesColumnIndex >= totalNumberOfColumns) || (notesColumnIndex == titleColumnIndex) || !(this.mainComponent().isColumnSelected(notesColumnIndex))) {
111 this.mainComponent().setNotesColumnIndex(-1);
112 notesColumnIndex = -1;
113 }
114
115 c =totalNumberOfColumns;
116 for (i=0; i<c; i++) {
117 if ((i != titleColumnIndex) && (this.mainComponent().isColumnSelected(i))) {
118 MochiKit.Signal.connect(this.getDom('radio_' + i), 'onclick', this, 'renderDataHandler');
119 if (Clipperz_IEisBroken != true) {
120 MochiKit.Signal.connect(this.getDom('columnLabel_' + i), 'onclick', this.getDom('radio_' + i), 'click');
121 }
122 }
123 }
124
125 MochiKit.Signal.connect(this.getDom('doNotSetNotes_radio'), 'onclick', this, 'renderDataHandler');
126 if (Clipperz_IEisBroken != true) {
127 MochiKit.Signal.connect(this.getDom('doNotSetNotes_span'), 'onclick', this.getDom('doNotSetNotes_radio'), 'click');
128 }
129
130 if (notesColumnIndex == -1) {
131 this.getDom('doNotSetNotes_radio').click();
132 } else {
133 this.getDom('radio_' + notesColumnIndex).click();
134 }
135 },
136
137 //-------------------------------------------------------------------------
138
139 'renderData': function(anElement, someData) {
140 var data;
141 var config;
142 var titleColumnIndex;
143 var notesColumnIndex;
144 var i,c;
145
146 // anElement.update("");
147 MochiKit.DOM.replaceChildNodes(anElement.dom);
148
149 titleColumnIndex = this.mainComponent().titleColumnIndex();
150 notesColumnIndex = this.mainComponent().notesColumnIndex();
151
152 if (this.mainComponent().isFirstRowHeader()) {
153 data = someData.slice(1);
154 } else {
155 data = someData;
156 }
157
158
159 // config = [{tag:'tr', cls:'CSV_previewData_header', children:[{tag:'td', valign:'top', html:header[titleColumnIndex], cls:'title'}]}];
160 // c = header.length;
161 // for (i=0; i<c; i++) {
162 // if (i != titleColumnIndex) {
163 // config[0].children.push({tag:'td', valign:'top', html:header[i], cls:((notesColumnIndex == i) ? 'notesColumn': '')})
164 // }
165 // }
166
167 config = MochiKit.Base.map(MochiKit.Base.bind(function(aTitleColumnIndex, aRowData) {
168 var result;
169 var i,c;
170
171 result = {tag:'tr', children:[{tag:'td', valign:'top', cls:'title', html:(MochiKit.Base.isNotEmpty(aRowData[aTitleColumnIndex]) ? aRowData[aTitleColumnIndex].replace(/\n/g, '<br>') : '&nbsp;')}]};
172 c = aRowData.length;
173 for (i=0; i<c; i++) {
174 if ((i != titleColumnIndex) && (this.mainComponent().isColumnSelected(i))) {
175 result.children.push({tag:'td', valign:'top', cls:((notesColumnIndex == i) ? 'notesColumn': ''), html:(MochiKit.Base.isNotEmpty(aRowData[i]) ? aRowData[i].replace(/\n/g, '<br>') : '&nbsp;')});
176 }
177 }
178
179 return result;
180 }, this, titleColumnIndex), data);
181
182 MochiKit.Base.map(function(aRowConfig) {Clipperz.YUI.DomHelper.append(anElement, aRowConfig);}, config);
183
184 Clipperz.Style.applyZebraStylesToTable(this.getId('previewDada'));
185 },
186
187 //-------------------------------------------------------------------------
188
189 'renderDataHandler': function(anEvent) {
190 var titleColumnIndex;
191 var i,c;
192
193 this.mainComponent().setNotesColumnIndex(anEvent.src().value);
194 titleColumnIndex = this.mainComponent().titleColumnIndex();
195
196 c = this.mainComponent().parsedValues()[0].length;
197 for (i=0; i<c; i++) {
198 if ((i != titleColumnIndex) && (this.mainComponent().isColumnSelected(i))) {
199 this.getElement('th_' + i).removeClass('notesColumn');
200 }
201 }
202 if (anEvent.src().value != -1) {
203 this.getElement('th_' + anEvent.src().value).addClass('notesColumn');
204 }
205
206 this.renderData(this.getElement('previewData_tbody'), this.mainComponent().parsedValues());
207 },
208
209 //-------------------------------------------------------------------------
210 __syntaxFix__: "syntax fix"
211});
212
diff --git a/frontend/beta/js/Clipperz/PM/Components/Import/CSVImport/CSVImportTitle.js b/frontend/beta/js/Clipperz/PM/Components/Import/CSVImport/CSVImportTitle.js
new file mode 100644
index 0000000..9162867
--- a/dev/null
+++ b/frontend/beta/js/Clipperz/PM/Components/Import/CSVImport/CSVImportTitle.js
@@ -0,0 +1,189 @@
1/*
2
3Copyright 2008-2011 Clipperz Srl
4
5This file is part of Clipperz's Javascript Crypto Library.
6Javascript Crypto Library provides web developers with an extensive
7and efficient set of cryptographic functions. The library aims to
8obtain maximum execution speed while preserving modularity and
9reusability.
10For further information about its features and functionalities please
11refer to http://www.clipperz.com
12
13* Javascript Crypto Library is free software: you can redistribute
14 it and/or modify it under the terms of the GNU Affero General Public
15 License as published by the Free Software Foundation, either version
16 3 of the License, or (at your option) any later version.
17
18* Javascript Crypto Library is distributed in the hope that it will
19 be useful, but WITHOUT ANY WARRANTY; without even the implied
20 warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
21 See the GNU Affero General Public License for more details.
22
23* You should have received a copy of the GNU Affero General Public
24 License along with Javascript Crypto Library. If not, see
25 <http://www.gnu.org/licenses/>.
26
27*/
28
29if (typeof(Clipperz) == 'undefined') { Clipperz = {}; }
30if (typeof(Clipperz.PM) == 'undefined') { Clipperz.PM = {}; }
31if (typeof(Clipperz.PM.Components) == 'undefined') { Clipperz.PM.Components = {}; }
32if (typeof(Clipperz.PM.Components.Import) == 'undefined') { Clipperz.PM.Components.Import = {}; }
33if (typeof(Clipperz.PM.Components.Import.CSVImport) == 'undefined') { Clipperz.PM.Components.Import.CSVImport = {}; }
34
35//#############################################################################
36
37Clipperz.PM.Components.Import.CSVImport.CSVImportTitle = function(anElement, args) {
38 args = args || {};
39
40 Clipperz.PM.Components.Import.CSVImport.CSVImportTitle.superclass.constructor.call(this, anElement, args);
41 this._mainComponent = args.mainComponent;
42
43 return this;
44}
45
46//=============================================================================
47
48YAHOO.extendX(Clipperz.PM.Components.Import.CSVImport.CSVImportTitle, Clipperz.PM.Components.BaseComponent, {
49
50 'toString': function() {
51 return "Clipperz.PM.Components.Import.CSVImport.CSVImportTitle component";
52 },
53
54 //-------------------------------------------------------------------------
55
56 'mainComponent': function() {
57 return this._mainComponent;
58 },
59
60 //-------------------------------------------------------------------------
61
62 'render': function() {
63 vartitleSelectorCheckboxCells;
64 var titleColumnIndex;
65 var i,c;
66
67 Clipperz.NotificationCenter.unregister(this);
68 MochiKit.Signal.disconnectAllTo(this);
69
70 this.element().update("");
71
72 titleColumnIndex = this.mainComponent().titleColumnIndex()
73 titleSelectorCheckboxCells = [];
74 c =this.mainComponent().parsedValues()[0].length;
75 for (i=0; i<c; i++) {
76 if (this.mainComponent().isColumnSelected(i)) {
77 titleSelectorCheckboxCells.push({tag:'th', valign:'top', id:this.getId('th_' + i), children:[
78 {tag:'input', type:'radio', id:this.getId('radio_' + i), name:'CSVImportTitleColumn', value:i},
79 {tag:'span', cls:'clickableSpan', id:this.getId('columnLabel_' + i), html:this.mainComponent().labelForColumn(i)}
80 ]})
81 }
82 }
83
84 if (titleColumnIndex >= titleSelectorCheckboxCells.length) {
85 this.mainComponent().setTitleColumnIndex(-1);
86 }
87
88 this.domHelper().append(this.element(), {tag:'div', children:[
89 {tag:'div', cls:'importStepDescription', htmlString:Clipperz.PM.Strings['CSV_ImportWizard_Title']},
90 {tag:'div', id:this.getId('dataDiv'), cls:'csvImportPreview', children:[
91 {tag:'table', id:this.getId('previewDada'), cls:'csvImportPreview', cellspacing:'0', children:[
92 {tag:'thead', id:this.getId('previewData_thead'), children:[
93 {tag:'tr', children:titleSelectorCheckboxCells}
94 ]},
95 {tag:'tbody', id:this.getId('previewData_tbody'), children:[]}
96 ]}
97 ]}
98 ]});
99
100 this.renderData(this.getElement('previewData_tbody'), this.mainComponent().parsedValues());
101
102 c =this.mainComponent().parsedValues()[0].length;
103 for (i=0; i<c; i++) {
104 if (this.mainComponent().isColumnSelected(i)) {
105 MochiKit.Signal.connect(this.getDom('radio_' + i), 'onclick', this, 'renderDataHandler');
106 if (Clipperz_IEisBroken != true) {
107 MochiKit.Signal.connect(this.getDom('columnLabel_' + i), 'onclick', this.getDom('radio_' + i), 'click');
108 }
109 }
110 }
111
112 if (titleColumnIndex != -1) {
113 this.getDom('radio_' + titleColumnIndex).click();
114 } else {
115 this.mainComponent().nextButton().disable();
116 }
117
118 },
119
120 //-------------------------------------------------------------------------
121
122 'renderData': function(anElement, someData) {
123 var data;
124 var config;
125 var titleColumnIndex;
126 var i,c;
127
128 // anElement.update("");
129 MochiKit.DOM.replaceChildNodes(anElement.dom);
130
131 titleColumnIndex = this.mainComponent().titleColumnIndex()
132
133 if (this.mainComponent().isFirstRowHeader()) {
134 data = someData.slice(1);
135 } else {
136 data = someData;
137 }
138
139 config = MochiKit.Base.map(MochiKit.Base.bind(function(aRowData) {
140 var result;
141 var i,c;
142
143 result = {tag:'tr', children:[]};
144 c = aRowData.length;
145 for (i=0; i<c; i++) {
146 if (this.mainComponent().isColumnSelected(i)) {
147 var field;
148
149 field = aRowData[i];
150 result.children.push({tag:'td', valign:'top', cls:((titleColumnIndex == i) ? 'titleColumn': ''), html:(MochiKit.Base.isNotEmpty(field) ? field.replace(/\n/g, '<br>') : '&nbsp;')});
151 }
152 }
153
154 return result;
155 }, this), data);
156
157 MochiKit.Base.map(function(aRowConfig) {Clipperz.YUI.DomHelper.append(anElement, aRowConfig);}, config);
158
159 Clipperz.Style.applyZebraStylesToTable(this.getId('previewDada'));
160 },
161
162 //-------------------------------------------------------------------------
163
164 'renderDataHandler': function(anEvent) {
165 var i,c;
166
167 this.mainComponent().setTitleColumnIndex(anEvent.src().value);
168
169 c = this.mainComponent().parsedValues()[0].length;
170 for (i=0; i<c; i++) {
171 if (this.mainComponent().isColumnSelected(i)) {
172 this.getElement('th_' + i).removeClass('titleColumn');
173 }
174 }
175 this.getElement('th_' + anEvent.src().value).addClass('titleColumn');
176
177 if (anEvent.src().value != -1) {
178 this.mainComponent().nextButton().enable();
179 } else {
180 this.mainComponent().nextButton().disable();
181 }
182
183 this.renderData(this.getElement('previewData_tbody'), this.mainComponent().parsedValues());
184 },
185
186 //-------------------------------------------------------------------------
187 __syntaxFix__: "syntax fix"
188});
189
diff --git a/frontend/beta/js/Clipperz/PM/Components/Import/CSVImportComponent.js b/frontend/beta/js/Clipperz/PM/Components/Import/CSVImportComponent.js
new file mode 100644
index 0000000..707a3d2
--- a/dev/null
+++ b/frontend/beta/js/Clipperz/PM/Components/Import/CSVImportComponent.js
@@ -0,0 +1,548 @@
1/*
2
3Copyright 2008-2011 Clipperz Srl
4
5This file is part of Clipperz's Javascript Crypto Library.
6Javascript Crypto Library provides web developers with an extensive
7and efficient set of cryptographic functions. The library aims to
8obtain maximum execution speed while preserving modularity and
9reusability.
10For further information about its features and functionalities please
11refer to http://www.clipperz.com
12
13* Javascript Crypto Library is free software: you can redistribute
14 it and/or modify it under the terms of the GNU Affero General Public
15 License as published by the Free Software Foundation, either version
16 3 of the License, or (at your option) any later version.
17
18* Javascript Crypto Library is distributed in the hope that it will
19 be useful, but WITHOUT ANY WARRANTY; without even the implied
20 warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
21 See the GNU Affero General Public License for more details.
22
23* You should have received a copy of the GNU Affero General Public
24 License along with Javascript Crypto Library. If not, see
25 <http://www.gnu.org/licenses/>.
26
27*/
28
29if (typeof(Clipperz) == 'undefined') { Clipperz = {}; }
30if (typeof(Clipperz.PM) == 'undefined') { Clipperz.PM = {}; }
31if (typeof(Clipperz.PM.Components) == 'undefined') { Clipperz.PM.Components = {}; }
32if (typeof(Clipperz.PM.Components.Import) == 'undefined') { Clipperz.PM.Components.Import = {}; }
33
34//#############################################################################
35
36Clipperz.PM.Components.Import.CSVImportComponent = function(anElement, args) {
37 args = args || {};
38
39 this._steps = this._steps || ['CSV_EDIT', 'CSV_COLUMNS', 'CSV_HEADER', 'CSV_TITLE', 'CSV_NOTES', 'CSV_FIELDS', 'PREVIEW', 'IMPORT'];
40
41 Clipperz.PM.Components.Import.CSVImportComponent.superclass.constructor.call(this, anElement, args);
42
43 this._step1Component = null;
44 this._step2Component = null;
45 this._step3Component = null;
46 this._step4Component = null;
47 this._step5Component = null;
48
49 this._isFirstRowHeader = false;
50 this._titleColumnIndex = -1;
51 this._notesColumnIndex = -1;
52 this._fieldSettings = {};
53 this._skippedColumns = new Clipperz.Set();
54
55 this.render();
56
57 return this;
58}
59
60//=============================================================================
61
62YAHOO.extendX(Clipperz.PM.Components.Import.CSVImportComponent, Clipperz.PM.Components.Import.GenericImportComponent, {
63
64 'toString': function() {
65 return "Clipperz.PM.Components.Import.CSVImportComponent component";
66 },
67
68 //-------------------------------------------------------------------------
69
70 'render': function() {
71 this.domHelper().append(this.element(), {tag:'div', cls:'csvImportWizard', children:[
72 {tag:'h3', htmlString:Clipperz.PM.Strings['CSV_ImportWizard_Title']},
73 {tag:'div', cls:'importSteps', id:this.getId('importSteps')},
74 {tag:'div', cls:'importStepBlocks', children:[
75 {tag:'div', cls:'step_0', id:this.getId('step_0'), children:[
76 {tag:'div', children:[
77 {tag:'div', cls:'importOptionsDescription', htmlString:Clipperz.PM.Strings['importOptions_csv_description']},
78 {tag:'div', cls:'importOptionsParameters', children:[
79 {tag:'div', cls:'CSVImportOptionsParameters', children:[
80 {tag:'ul', children:[
81 {tag:'li', children:[
82 {tag:'label', 'for':this.getId('CSV_inputOptions_separator'), html:"separator"},
83 {tag:'select', name:this.getId('CSV_inputOptions_separator'), id:this.getId('CSV_inputOptions_separator'), children:[
84 {tag:'option', name:'comma', value:',', html:"comma (,)", selected:true},
85 {tag:'option', name:'tab', value:'\t', html:"tab"}
86 ]}
87 ]},
88
89 {tag:'li', children:[
90 {tag:'label', 'for':this.getId('CSV_inputOptions_quote'), html:"quote"},
91 {tag:'select', name:this.getId('CSV_inputOptions_quote'), id:this.getId('CSV_inputOptions_quote'), children:[
92 {tag:'option', name:'doubleQuote', value:'\"', html:"double quote (\")", selected:true},
93 {tag:'option', name:'singleQuote', value:'\'', html:"single quote (\')"}
94 ]}
95 ]},
96
97 {tag:'li', children:[
98 {tag:'label', 'for':this.getId('CSV_inputOptions_escape'), html:"escape"},
99 {tag:'select', name:this.getId('CSV_inputOptions_escape'), id:this.getId('CSV_inputOptions_escape'), children:[
100 {tag:'option', name:'doubleQuote', value:'\"', html:"double quote (\")", selected:true},
101 {tag:'option', name:'slash', value:'\/', html:"slash (\/)"},
102 {tag:'option', name:'backslash', value:'\\', html:"backslash (\\)"}
103 ]}
104 ]}
105 ]}
106 ]}
107 ]},
108 this.textAreaConfig()
109 ]}
110 ]},
111 {tag:'div', cls:'step_1', id:this.getId('step_1'), children:[]},
112 {tag:'div', cls:'step_2', id:this.getId('step_2'), children:[]},
113 {tag:'div', cls:'step_3', id:this.getId('step_3'), children:[]},
114 {tag:'div', cls:'step_4', id:this.getId('step_4'), children:[]},
115 {tag:'div', cls:'step_5', id:this.getId('step_5'), children:[]},
116 {tag:'div', cls:'step_6', id:this.getId('step_6'), children:[
117 {tag:'div', children:[
118 {tag:'div', id:this.getId('previewDiv'), html:"preview"}
119 ]}
120 ]},
121 {tag:'div', cls:'step_7', id:this.getId('step_7'), children:[
122 {tag:'div', children:[
123 {tag:'h4', html:"done"}
124 ]}
125 ]}
126 ]},
127 {tag:'div', cls:'importOptionsButtons', children:[
128 {tag:'table', children:[
129 {tag:'tbody', children:[
130 {tag:'tr', children:[
131 {tag:'td', html:'&nbsp;'},
132 {tag:'td', children:[
133 {tag:'div', id:this.getId('backActionButton')}
134 ]},
135 {tag:'td', html:'&nbsp;'},
136 {tag:'td', children:[
137 {tag:'div', id:this.getId('nextActionButton')}
138 ]},
139 {tag:'td', html:'&nbsp;'}
140 ]}
141 ]}
142 ]}
143 ]}
144 ]});
145
146 this.setBackButton(new YAHOO.ext.Button(this.getDom('backActionButton'), {text:"back", handler:this.backAction, scope:this}));
147 this.setNextButton(new YAHOO.ext.Button(this.getDom('nextActionButton'), {text:"next", handler:this.nextAction, scope:this}));
148
149 this.updateSteps();
150
151 this.getElement('step_0').setVisibilityMode(YAHOO.ext.Element.DISPLAY).show()
152 this.getElement('step_1').setVisibilityMode(YAHOO.ext.Element.DISPLAY).hide();
153 this.getElement('step_2').setVisibilityMode(YAHOO.ext.Element.DISPLAY).hide();
154 this.getElement('step_3').setVisibilityMode(YAHOO.ext.Element.DISPLAY).hide();
155 this.getElement('step_4').setVisibilityMode(YAHOO.ext.Element.DISPLAY).hide();
156 this.getElement('step_5').setVisibilityMode(YAHOO.ext.Element.DISPLAY).hide();
157 this.getElement('step_6').setVisibilityMode(YAHOO.ext.Element.DISPLAY).hide();
158 this.getElement('step_7').setVisibilityMode(YAHOO.ext.Element.DISPLAY).hide();
159
160 // this.backButton().disable();
161 },
162
163 //-------------------------------------------------------------------------
164
165 'nextAction': function() {
166 switch (this.currentStep()) {
167 case 0: //-> 1
168 Clipperz.PM.Components.MessageBox.showProgressPanel(
169 MochiKit.Base.method(this, 'deferredParseValues'),
170 MochiKit.Base.method(this, 'handleParseError'),
171 this.getDom('nextActionButton')
172 );
173 break;
174 case 1: //-> 2
175 this.getElement('step_1').hide();
176 this.step2Component().render();
177 this.setCurrentStep(2);
178 this.getElement('step_2').show();
179 break;
180 case 2: //-> 3
181 this.getElement('step_2').hide();
182 this.step3Component().render();
183 this.setCurrentStep(3);
184 this.getElement('step_3').show();
185 break;
186 case 3: //-> 4
187 this.getElement('step_3').hide();
188 this.step4Component().render();
189 this.setCurrentStep(4);
190 this.getElement('step_4').show();
191 break;
192 case 4: //-> 5
193 this.getElement('step_4').hide();
194 this.step5Component().render();
195 this.setCurrentStep(5);
196 this.getElement('step_5').show();
197 break;
198 case 5: //-> 6
199 this.previewValues();
200 break;
201 case 6: //-> 7
202 this.importValues();
203 break;
204 }
205 },
206
207 //-------------------------------------------------------------------------
208
209 'deferredParseValues': function() {
210 var deferredResult;
211
212 deferredResult = new MochiKit.Async.Deferred();
213//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("CSVImportComponent.deferredParseValues - 1 " + res.substring(0,50)); return res;});
214 deferredResult.addCallback(Clipperz.NotificationCenter.deferredNotification, this, 'updatedProgressState', 'parseImportData');
215//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("CSVImportComponent.deferredParseValues - 2 " + res.substring(0,50)); return res;});
216 deferredResult.addCallback(MochiKit.Base.bind(function(res) {
217 this.startProcessing();
218
219 return res;
220 }, this));
221//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("CSVImportComponent.deferredParseValues - 3 " + res.substring(0,50)); return res;});
222 deferredResult.addCallback(MochiKit.Base.method(this, 'parseCSVValues'));
223//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("CSVImportComponent.deferredParseValues - 4 " + res); return res;});
224 deferredResult.addCallback(MochiKit.Base.method(this, 'setParsedValues'));
225//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("CSVImportComponent.deferredParseValues - 5 " + res); return res;});
226 deferredResult.addCallback(MochiKit.Base.method(this.step1Component(), 'render'));
227//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("CSVImportComponent.deferredParseValues - 6 " + res); return res;});
228 deferredResult.addCallback(MochiKit.Base.bind(function(res) {
229 this.processingDone();
230 this.getElement('step_0').hide();
231 this.getElement('step_1').show();
232 this.backButton().enable();
233
234 return res;
235 }, this));
236//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("CSVImportComponent.deferredParseValues - 7 " + res); return res;});
237 deferredResult.callback(this.textAreaContent());
238
239 return deferredResult;
240 },
241
242 //-------------------------------------------------------------------------
243
244 'deferredPreviewValues': function() {
245 var deferredResult;
246
247//MochiKit.Logging.logDebug(">>> CSVImportComponent.deferredPreviewValues");
248 deferredResult = new MochiKit.Async.Deferred();
249//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("KeePassImportComponent.deferredPreviewValues - 1 " + res); return res;});
250 deferredResult.addCallback(Clipperz.NotificationCenter.deferredNotification, this, 'updatedProgressState', 'previewImportData');
251//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("KeePassImportComponent.deferredPreviewValues - 2 " + res); return res;});
252 deferredResult.addCallback(MochiKit.Base.bind(function(res) {
253 this.startProcessing();
254
255 return res;
256 }, this));
257//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("KeePassImportComponent.deferredPreviewValues - 3 " + res); return res;});
258 deferredResult.addCallback(MochiKit.Base.method(this, 'processCSVParsedValues'));
259//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("KeePassImportComponent.deferredPreviewValues - 4 " + res); return res;});
260 deferredResult.addCallback(MochiKit.Base.method(this, 'setProcessedValues'));
261//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("KeePassImportComponent.deferredPreviewValues - 5 " + res); return res;});
262 deferredResult.addCallback(MochiKit.Base.method(this, 'previewRecordValues'));
263//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("KeePassImportComponent.deferredPreviewValues - 6 " + res); return res;});
264 deferredResult.addCallback(MochiKit.Base.bind(function(res) {
265 this.processingDone();
266 this.getElement('step_5').hide();
267 this.getElement('step_6').show();
268 this.backButton().enable();
269
270 return res;
271 }, this));
272 deferredResult.callback(this.parsedValues());
273//MochiKit.Logging.logDebug("<<< CSVImportComponent.deferredPreviewValues");
274
275 return deferredResult;
276 },
277
278 //-------------------------------------------------------------------------
279
280 'csvProcessor': function() {
281 return new Clipperz.CSVProcessor({
282 quoteChar: this.getDom('CSV_inputOptions_quote').value,
283 escapeChar: this.getDom('CSV_inputOptions_escape').value,
284 separatorChar:this.getDom('CSV_inputOptions_separator').value,
285 binary:true
286 });
287 },
288
289 //-------------------------------------------------------------------------
290
291 'parseCSVValues': function(someData) {
292 var deferredResult;
293 var csvProcessor;
294
295 csvProcessor = this.csvProcessor();
296 deferredResult = new MochiKit.Async.Deferred();
297//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("KeePassImportComponent.parseKeePassValues - 1 " + res.substring(0,50)); return res;});
298 deferredResult.addCallback(function(res) {
299 return Clipperz.NotificationCenter.deferredNotification(this, 'updatedProgressState', {steps:(res.length)}, res);
300 })
301//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("KeePassImportComponent.parseKeePassValues - 2 " + res.substring(0,50)); return res;});
302 deferredResult.addCallback(MochiKit.Base.method(csvProcessor, 'deferredParse'));
303//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("KeePassImportComponent.parseKeePassValues - 3 " + res); return res;});
304 deferredResult.callback(someData);
305
306 return deferredResult;
307 },
308
309 //-------------------------------------------------------------------------
310
311 'processCSVParsedValues': function (someValues) {
312 var deferredResult;
313 var records;
314 var titleColumnIndex;
315 var notesColumnIndex;
316 var i,c;
317
318 deferredResult = new MochiKit.Async.Deferred();
319 records = [];
320
321 titleColumnIndex = this.titleColumnIndex();
322 notesColumnIndex = this.notesColumnIndex();
323
324 deferredResult.addCallback(Clipperz.NotificationCenter.deferredNotification, this, 'updatedProgressState', {steps:(someValues.length)});
325
326 c = someValues.length;
327 if (this.isFirstRowHeader()) {
328 i = 1;
329 } else {
330 i = 0;
331 }
332
333 for( ; i<c; i++) {
334 deferredResult.addCallback(MochiKit.Async.wait, 0.2);
335 deferredResult.addCallback(Clipperz.NotificationCenter.deferredNotification, this, 'updatedProgressState', {});
336 deferredResult.addCallback(MochiKit.Base.bind(function(someRecords, someData) {
337 var record;
338 var recordVersion;
339 var ii;
340
341 record = new Clipperz.PM.DataModel.Record({user:this.user()});
342 record.setLabel(someData[titleColumnIndex]);
343 if (notesColumnIndex != -1) {
344 record.setNotes(someData[notesColumnIndex]);
345 }
346 recordVersion = record.currentVersion()
347
348 for (ii in someData) {
349 // if ((ii != titleColumnIndex) && (ii != notesColumnIndex) && (typeof(this.fieldSettings()[ii]) != 'undefined')) {
350 if ((ii != titleColumnIndex) && (ii != notesColumnIndex) && (this.isColumnSelected(ii))) {
351 var recordField;
352
353 recordField = new Clipperz.PM.DataModel.RecordField({
354 recordVersion:recordVersion,
355 label: this.labelForColumn(ii),
356 value: someData[ii],
357 type: this.typeForColumn(ii)
358 });
359 recordVersion.addField(recordField);
360 }
361 }
362
363 someRecords.push(record);
364
365 return someRecords;
366 }, this), records, someValues[i]);
367 }
368 deferredResult.addCallback(MochiKit.Async.succeed, records);
369 deferredResult.callback();
370
371 return deferredResult;
372 },
373
374 //-------------------------------------------------------------------------
375
376 'step1Component': function() {
377 if (this._step1Component == null) {
378 this._step1Component = new Clipperz.PM.Components.Import.CSVImport.CSVImportColumns(this.getElement('step_1'), {mainComponent:this});
379 }
380
381 return this._step1Component;
382 },
383
384 'step2Component': function() {
385 if (this._step2Component == null) {
386 this._step2Component = new Clipperz.PM.Components.Import.CSVImport.CSVImportHeader(this.getElement('step_2'), {mainComponent:this});
387 }
388
389 return this._step2Component;
390 },
391
392 'step3Component': function() {
393 if (this._step3Component == null) {
394 this._step3Component = new Clipperz.PM.Components.Import.CSVImport.CSVImportTitle(this.getElement('step_3'), {mainComponent:this});
395 }
396
397 return this._step3Component;
398 },
399
400 'step4Component': function() {
401 if (this._step4Component == null) {
402 this._step4Component = new Clipperz.PM.Components.Import.CSVImport.CSVImportNotes(this.getElement('step_4'), {mainComponent:this});
403 }
404
405 return this._step4Component;
406 },
407
408 'step5Component': function() {
409 if (this._step5Component == null) {
410 this._step5Component = new Clipperz.PM.Components.Import.CSVImport.CSVImportFields(this.getElement('step_5'), {mainComponent:this});
411 }
412
413 return this._step5Component;
414 },
415
416 //-------------------------------------------------------------------------
417
418 'isFirstRowHeader': function() {
419 return this._isFirstRowHeader;
420 },
421
422 'setIsFirstRowHeader': function(aValue) {
423 this._isFirstRowHeader = aValue;
424 },
425
426 //-------------------------------------------------------------------------
427
428 'titleColumnIndex': function() {
429 return this._titleColumnIndex;
430 },
431
432 'setTitleColumnIndex': function(aValue) {
433 this._titleColumnIndex = aValue;
434 },
435
436 //-------------------------------------------------------------------------
437
438 'notesColumnIndex': function() {
439 return this._notesColumnIndex;
440 },
441
442 'setNotesColumnIndex': function(aValue) {
443 this._notesColumnIndex = aValue;
444 },
445
446 //-------------------------------------------------------------------------
447
448 'fieldSettings': function() {
449 return this._fieldSettings;
450 },
451
452 //-------------------------------------------------------------------------
453
454 'skippedColumns': function() {
455 return this._skippedColumns;
456 },
457
458 //-------------------------------------------------------------------------
459
460 'isColumnSelected': function(aColumnIndex) {
461 return !this.skippedColumns().contains("" + aColumnIndex);
462 },
463
464 //=========================================================================
465
466 'labelForColumn': function(aColumnIndex) {
467 var result;
468
469 if ((typeof(this.fieldSettings()) != 'undefined') && (typeof(this.fieldSettings()[aColumnIndex]) != 'undefined')) {
470 if (this.isFirstRowHeader()) {
471 result = this.fieldSettings()[aColumnIndex]['_firstRowLabel'];
472//MochiKit.Logging.logDebug("--- updateInputFieldValues - [" + aColumnIndex + "] _firstRowLabel: " + label);
473 } else {
474 result = this.fieldSettings()[aColumnIndex]['_emptyLabel'];
475//MochiKit.Logging.logDebug("--- updateInputFieldValues - [" + aColumnIndex + "] _emptyLabel: " + label);
476 }
477 } else {
478 result = "";
479 }
480
481 return result;
482 },
483
484 //-------------------------------------------------------------------------
485
486 'setLabelForColumn': function(aLabel, aColumnIndex) {
487 var fieldSettings;
488
489//MochiKit.Logging.logDebug(">>> setLabelForColumn[" + aColumnIndex + "]: " + aLabel);
490 fieldSettings = this.fieldSettings();
491
492 if (typeof(fieldSettings[aColumnIndex]) == 'undefined') {
493 fieldSettings[aColumnIndex] = {}
494 }
495
496 if (this.isFirstRowHeader()) {
497//MochiKit.Logging.logDebug("--- setLabelForColumn -> _firstRowLabel");
498 fieldSettings[aColumnIndex]['_firstRowLabel'] = aLabel;
499 } else {
500 if (typeof(fieldSettings[aColumnIndex]['_emptyLabel']) == 'undefined') {
501 if (aLabel == null) {
502//MochiKit.Logging.logDebug("--- setLabelForColumn -> _emptyLabel = \"\"");
503 fieldSettings[aColumnIndex]['_emptyLabel'] = "";
504 } else {
505 fieldSettings[aColumnIndex]['_emptyLabel'] = aLabel;
506 }
507 } else {
508//MochiKit.Logging.logDebug("--- setLabelForColumn -> _emptyLabel = " + aLabel);
509 if (aLabel != null) {
510 fieldSettings[aColumnIndex]['_emptyLabel'] = aLabel;
511 }
512 }
513 }
514//MochiKit.Logging.logDebug("<<< setLabelForColumn[" + aColumnIndex + "]: " + aLabel);
515 },
516
517 //=========================================================================
518
519 'typeForColumn': function(aColumnIndex) {
520 var result;
521
522 if ((typeof(this.fieldSettings()) != 'undefined') && (typeof(this.fieldSettings()[aColumnIndex]) != 'undefined') && (typeof(this.fieldSettings()[aColumnIndex]['type']) != 'undefined')) {
523 result = this.fieldSettings()[aColumnIndex]['type'];
524 } else {
525 result = 'UNDEFINED';
526 }
527
528 return result;
529 },
530
531 //-------------------------------------------------------------------------
532
533 'setTypeForColumn': function(aType, aColumnIndex) {
534 var fieldSettings;
535
536 fieldSettings = this.fieldSettings();
537
538 if (typeof(fieldSettings[aColumnIndex]) == 'undefined') {
539 fieldSettings[aColumnIndex] = {}
540 }
541
542 fieldSettings[aColumnIndex]['type'] = aType;
543 },
544
545 //=========================================================================
546 __syntaxFix__: "syntax fix"
547});
548
diff --git a/frontend/beta/js/Clipperz/PM/Components/Import/ClipperzImportComponent.js b/frontend/beta/js/Clipperz/PM/Components/Import/ClipperzImportComponent.js
new file mode 100644
index 0000000..50dcb93
--- a/dev/null
+++ b/frontend/beta/js/Clipperz/PM/Components/Import/ClipperzImportComponent.js
@@ -0,0 +1,212 @@
1/*
2
3Copyright 2008-2011 Clipperz Srl
4
5This file is part of Clipperz's Javascript Crypto Library.
6Javascript Crypto Library provides web developers with an extensive
7and efficient set of cryptographic functions. The library aims to
8obtain maximum execution speed while preserving modularity and
9reusability.
10For further information about its features and functionalities please
11refer to http://www.clipperz.com
12
13* Javascript Crypto Library is free software: you can redistribute
14 it and/or modify it under the terms of the GNU Affero General Public
15 License as published by the Free Software Foundation, either version
16 3 of the License, or (at your option) any later version.
17
18* Javascript Crypto Library is distributed in the hope that it will
19 be useful, but WITHOUT ANY WARRANTY; without even the implied
20 warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
21 See the GNU Affero General Public License for more details.
22
23* You should have received a copy of the GNU Affero General Public
24 License along with Javascript Crypto Library. If not, see
25 <http://www.gnu.org/licenses/>.
26
27*/
28
29if (typeof(Clipperz) == 'undefined') { Clipperz = {}; }
30if (typeof(Clipperz.PM) == 'undefined') { Clipperz.PM = {}; }
31if (typeof(Clipperz.PM.Components) == 'undefined') { Clipperz.PM.Components = {}; }
32if (typeof(Clipperz.PM.Components.Import) == 'undefined') { Clipperz.PM.Components.Import = {}; }
33
34//#############################################################################
35
36Clipperz.PM.Components.Import.ClipperzImportComponent = function(anElement, args) {
37 args = args || {};
38
39 Clipperz.PM.Components.Import.ClipperzImportComponent.superclass.constructor.call(this, anElement, args);
40
41 this.render();
42
43 return this;
44}
45
46//=============================================================================
47
48YAHOO.extendX(Clipperz.PM.Components.Import.ClipperzImportComponent, Clipperz.PM.Components.Import.GenericImportComponent, {
49
50 'toString': function() {
51 return "Clipperz.PM.Components.Import.ClipperzImportComponent component";
52 },
53
54 //-------------------------------------------------------------------------
55
56 'render': function() {
57//MochiKit.Logging.logDebug(">>> Import.ClipperzImportComponent.render");
58 this.domHelper().append(this.element(), {tag:'div', cls:'clipperzImportWizard', children:[
59 {tag:'h3', htmlString:Clipperz.PM.Strings['Clipperz_ImportWizard_Title']},
60 {tag:'div', cls:'importSteps', id:this.getId('importSteps')},
61 {tag:'div', cls:'importStepBlocks', children:[
62 {tag:'div', cls:'step_0', id:this.getId('step_0'), children:[
63 {tag:'div', children:[
64 {tag:'div', cls:'importOptionsDescription', htmlString:Clipperz.PM.Strings['importOptions_clipperz_description']},
65 {tag:'div', cls:'importOptionsParameters', children:[]},
66 this.textAreaConfig()
67 ]}
68 ]},
69 {tag:'div', cls:'step_1', id:this.getId('step_1'), children:[
70 {tag:'div', children:[
71 {tag:'div', id:this.getId('previewDiv'), html:"preview"}
72 ]}
73 ]},
74 {tag:'div', cls:'step_2', id:this.getId('step_2'), children:[
75 {tag:'div', children:[
76 {tag:'h4', html:"done"}
77 ]}
78 ]}
79 ]},
80 {tag:'div', cls:'importOptionsButtons', children:[
81 {tag:'table', children:[
82 {tag:'tbody', children:[
83 {tag:'tr', children:[
84 {tag:'td', html:'&nbsp;'},
85 {tag:'td', children:[
86 {tag:'div', id:this.getId('backActionButton')}
87 ]},
88 {tag:'td', html:'&nbsp;'},
89 {tag:'td', children:[
90 {tag:'div', id:this.getId('nextActionButton')}
91 ]},
92 {tag:'td', html:'&nbsp;'}
93 ]}
94 ]}
95 ]}
96 ]}
97 ]});
98
99 this.updateSteps();
100
101 this.setBackButton(new YAHOO.ext.Button(this.getDom('backActionButton'), {text:"back", handler:this.backAction, scope:this}));
102 this.setNextButton(new YAHOO.ext.Button(this.getDom('nextActionButton'), {text:"next", handler:this.nextAction, scope:this}));
103
104 this.getElement('step_0').setVisibilityMode(YAHOO.ext.Element.DISPLAY).show()
105 this.getElement('step_1').setVisibilityMode(YAHOO.ext.Element.DISPLAY).hide();
106 this.getElement('step_2').setVisibilityMode(YAHOO.ext.Element.DISPLAY).hide();
107//MochiKit.Logging.logDebug("<<< Import.ClipperzImportComponent.render");
108 },
109
110 //-------------------------------------------------------------------------
111
112 'nextAction': function() {
113 switch (this.currentStep()) {
114 case 0: //-> 1
115 this.previewValues();
116 break;
117 case 1: //-> 2
118 this.importValues();
119 break;
120 }
121 },
122
123 //-------------------------------------------------------------------------
124
125 'deferredPreviewValues': function() {
126 var deferredResult;
127
128 deferredResult = new MochiKit.Async.Deferred();
129 deferredResult.addCallback(MochiKit.Base.bind(function(res) {
130 this.startProcessing();
131
132 return res;
133 }, this));
134 deferredResult.addCallback(MochiKit.Base.method(this, 'processClipperzValues'));
135 deferredResult.addCallback(MochiKit.Base.method(this, 'setProcessedValues'));
136 deferredResult.addCallback(MochiKit.Base.method(this, 'previewRecordValues'));
137 deferredResult.addCallback(MochiKit.Base.bind(function(res) {
138 this.processingDone();
139 this.getElement('step_0').hide();
140 this.getElement('step_1').show();
141 this.backButton().enable();
142
143 return res;
144 }, this));
145 // deferredResult.addErrback(MochiKit.Base.bind(function() {
146 // this.processingAborted();
147 // }, this))
148 deferredResult.callback(this.textAreaContent());
149
150 return deferredResult;
151 },
152
153 //-------------------------------------------------------------------------
154
155 'processClipperzValues': function(someData) {
156 var deferredResult;
157
158 deferredResult = new MochiKit.Async.Deferred();
159//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("Record.processClipperzValues - 1: " + res); return res;});
160 deferredResult.addCallback(Clipperz.NotificationCenter.deferredNotification, this, 'updatedProgressState', 'parseImportData');
161//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("Record.processClipperzValues - 2: " + res); return res;});
162 deferredResult.addCallback(Clipperz.Base.evalJSON);
163//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("Record.processClipperzValues - 3: " + res); return res;});
164 deferredResult.addCallback(function(res) {
165 return Clipperz.NotificationCenter.deferredNotification(this, 'updatedProgressState', {steps:(res.length)}, res);
166 })
167//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("Record.processClipperzValues - 4: " + res); return res;});
168 deferredResult.addCallback(Clipperz.NotificationCenter.deferredNotification, this, 'updatedProgressState', 'previewImportData');
169//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("Record.processClipperzValues - 5: " + res); return res;});
170 deferredResult.addCallback(MochiKit.Base.bind(function(someClipperzValues) {
171 var innerDeferredResult;
172 var records;
173 var i,c;
174
175 innerDeferredResult = new MochiKit.Async.Deferred();
176 records = [];
177
178 c = someClipperzValues.length;
179 for(i=0; i<c; i++) {
180 innerDeferredResult.addCallback(MochiKit.Async.wait, 0.2);
181 innerDeferredResult.addCallback(Clipperz.NotificationCenter.deferredNotification, this, 'updatedProgressState', {});
182 innerDeferredResult.addCallback(MochiKit.Base.bind(function(someRecords, someData) {
183 var record;
184 var recordVersion;
185
186//MochiKit.Logging.logDebug("=== someData: " + Clipperz.Base.serializeJSON(someData));
187 record = new Clipperz.PM.DataModel.Record({user:this.user()});
188 record.setLabel(someData['label']);
189 record.setShouldProcessData(true);
190 record.processData(someData);
191
192 someRecords.push(record);
193
194 return someRecords;
195 }, this), records, someClipperzValues[i]);
196 }
197 innerDeferredResult.addCallback(MochiKit.Async.succeed, records);
198 innerDeferredResult.callback();
199
200 return innerDeferredResult;
201 }, this));
202//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("Record.processClipperzValues - 6: " + res); return res;});
203 deferredResult.callback(someData);
204
205 return deferredResult;
206 },
207
208
209 //-------------------------------------------------------------------------
210 __syntaxFix__: "syntax fix"
211});
212
diff --git a/frontend/beta/js/Clipperz/PM/Components/Import/ExcelImportComponent.js b/frontend/beta/js/Clipperz/PM/Components/Import/ExcelImportComponent.js
new file mode 100644
index 0000000..ecdf509
--- a/dev/null
+++ b/frontend/beta/js/Clipperz/PM/Components/Import/ExcelImportComponent.js
@@ -0,0 +1,134 @@
1/*
2
3Copyright 2008-2011 Clipperz Srl
4
5This file is part of Clipperz's Javascript Crypto Library.
6Javascript Crypto Library provides web developers with an extensive
7and efficient set of cryptographic functions. The library aims to
8obtain maximum execution speed while preserving modularity and
9reusability.
10For further information about its features and functionalities please
11refer to http://www.clipperz.com
12
13* Javascript Crypto Library is free software: you can redistribute
14 it and/or modify it under the terms of the GNU Affero General Public
15 License as published by the Free Software Foundation, either version
16 3 of the License, or (at your option) any later version.
17
18* Javascript Crypto Library is distributed in the hope that it will
19 be useful, but WITHOUT ANY WARRANTY; without even the implied
20 warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
21 See the GNU Affero General Public License for more details.
22
23* You should have received a copy of the GNU Affero General Public
24 License along with Javascript Crypto Library. If not, see
25 <http://www.gnu.org/licenses/>.
26
27*/
28
29if (typeof(Clipperz) == 'undefined') { Clipperz = {}; }
30if (typeof(Clipperz.PM) == 'undefined') { Clipperz.PM = {}; }
31if (typeof(Clipperz.PM.Components) == 'undefined') { Clipperz.PM.Components = {}; }
32if (typeof(Clipperz.PM.Components.Import) == 'undefined') { Clipperz.PM.Components.Import = {}; }
33
34//#############################################################################
35
36Clipperz.PM.Components.Import.ExcelImportComponent = function(anElement, args) {
37 args = args || {};
38
39 this._steps = ['EXCEL_EDIT', 'CSV_COLUMNS', 'CSV_HEADER', 'CSV_TITLE', 'CSV_NOTES', 'CSV_FIELDS', 'PREVIEW', 'IMPORT'];
40
41 Clipperz.PM.Components.Import.ExcelImportComponent.superclass.constructor.call(this, anElement, args);
42
43 return this;
44}
45
46//=============================================================================
47
48YAHOO.extendX(Clipperz.PM.Components.Import.ExcelImportComponent, Clipperz.PM.Components.Import.CSVImportComponent, {
49
50 'toString': function() {
51 return "Clipperz.PM.Components.Import.ExcelImportComponent component";
52 },
53
54 //-------------------------------------------------------------------------
55
56 'render': function() {
57//MochiKit.Logging.logDebug(">>> Import.ExcelImportComponent.render");
58 this.domHelper().append(this.element(), {tag:'div', cls:'excelImportWizard', children:[
59 {tag:'h3', htmlString:Clipperz.PM.Strings['Excel_ImportWizard_Title']},
60 {tag:'div', cls:'importSteps', id:this.getId('importSteps')},
61 {tag:'div', cls:'importStepBlocks', children:[
62 {tag:'div', cls:'step_0', id:this.getId('step_0'), children:[
63 {tag:'div', children:[
64 {tag:'div', cls:'importOptionsDescription', htmlString:Clipperz.PM.Strings['importOptions_excel_description']},
65 {tag:'div', cls:'importOptionsParameters', children:[]},
66 this.textAreaConfig()
67 ]}
68 ]},
69 {tag:'div', cls:'step_1', id:this.getId('step_1'), children:[]},
70 {tag:'div', cls:'step_2', id:this.getId('step_2'), children:[]},
71 {tag:'div', cls:'step_3', id:this.getId('step_3'), children:[]},
72 {tag:'div', cls:'step_4', id:this.getId('step_4'), children:[]},
73 {tag:'div', cls:'step_5', id:this.getId('step_5'), children:[]},
74 {tag:'div', cls:'step_6', id:this.getId('step_6'), children:[
75 {tag:'div', children:[
76 {tag:'div', id:this.getId('previewDiv'), html:"preview"}
77 ]}
78 ]},
79 {tag:'div', cls:'step_7', id:this.getId('step_7'), children:[
80 {tag:'div', children:[
81 {tag:'h4', html:"done"}
82 ]}
83 ]}
84 ]},
85 {tag:'div', cls:'importOptionsButtons', children:[
86 {tag:'table', children:[
87 {tag:'tbody', children:[
88 {tag:'tr', children:[
89 {tag:'td', html:'&nbsp;'},
90 {tag:'td', children:[
91 {tag:'div', id:this.getId('backActionButton')}
92 ]},
93 {tag:'td', html:'&nbsp;'},
94 {tag:'td', children:[
95 {tag:'div', id:this.getId('nextActionButton')}
96 ]},
97 {tag:'td', html:'&nbsp;'}
98 ]}
99 ]}
100 ]}
101 ]}
102 ]});
103
104 this.updateSteps();
105
106 this.setBackButton(new YAHOO.ext.Button(this.getDom('backActionButton'), {text:"back", handler:this.backAction, scope:this}));
107 this.setNextButton(new YAHOO.ext.Button(this.getDom('nextActionButton'), {text:"next", handler:this.nextAction, scope:this}));
108
109 this.getElement('step_0').setVisibilityMode(YAHOO.ext.Element.DISPLAY).show()
110 this.getElement('step_1').setVisibilityMode(YAHOO.ext.Element.DISPLAY).hide();
111 this.getElement('step_2').setVisibilityMode(YAHOO.ext.Element.DISPLAY).hide();
112 this.getElement('step_3').setVisibilityMode(YAHOO.ext.Element.DISPLAY).hide();
113 this.getElement('step_4').setVisibilityMode(YAHOO.ext.Element.DISPLAY).hide();
114 this.getElement('step_5').setVisibilityMode(YAHOO.ext.Element.DISPLAY).hide();
115 this.getElement('step_6').setVisibilityMode(YAHOO.ext.Element.DISPLAY).hide();
116 this.getElement('step_7').setVisibilityMode(YAHOO.ext.Element.DISPLAY).hide();
117//MochiKit.Logging.logDebug("<<< Import.ExcelImportComponent.render");
118 },
119
120 //-------------------------------------------------------------------------
121
122 'csvProcessor': function() {
123 return new Clipperz.CSVProcessor({
124 // quoteChar: this.getDom('CSV_inputOptions_quote').value,
125 // escapeChar: this.getDom('CSV_inputOptions_escape').value,
126 separatorChar:'\t',
127 binary:true
128 });
129 },
130
131 //-------------------------------------------------------------------------
132 __syntaxFix__: "syntax fix"
133});
134
diff --git a/frontend/beta/js/Clipperz/PM/Components/Import/GenericImportComponent.js b/frontend/beta/js/Clipperz/PM/Components/Import/GenericImportComponent.js
new file mode 100644
index 0000000..4f6b1e4
--- a/dev/null
+++ b/frontend/beta/js/Clipperz/PM/Components/Import/GenericImportComponent.js
@@ -0,0 +1,523 @@
1/*
2
3Copyright 2008-2011 Clipperz Srl
4
5This file is part of Clipperz's Javascript Crypto Library.
6Javascript Crypto Library provides web developers with an extensive
7and efficient set of cryptographic functions. The library aims to
8obtain maximum execution speed while preserving modularity and
9reusability.
10For further information about its features and functionalities please
11refer to http://www.clipperz.com
12
13* Javascript Crypto Library is free software: you can redistribute
14 it and/or modify it under the terms of the GNU Affero General Public
15 License as published by the Free Software Foundation, either version
16 3 of the License, or (at your option) any later version.
17
18* Javascript Crypto Library is distributed in the hope that it will
19 be useful, but WITHOUT ANY WARRANTY; without even the implied
20 warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
21 See the GNU Affero General Public License for more details.
22
23* You should have received a copy of the GNU Affero General Public
24 License along with Javascript Crypto Library. If not, see
25 <http://www.gnu.org/licenses/>.
26
27*/
28
29if (typeof(Clipperz) == 'undefined') { Clipperz = {}; }
30if (typeof(Clipperz.PM) == 'undefined') { Clipperz.PM = {}; }
31if (typeof(Clipperz.PM.Components) == 'undefined') { Clipperz.PM.Components = {}; }
32if (typeof(Clipperz.PM.Components.Import) == 'undefined') { Clipperz.PM.Components.Import = {}; }
33
34//#############################################################################
35
36Clipperz.PM.Components.Import.GenericImportComponent = function(anElement, args) {
37 args = args || {};
38
39 this._steps = this._steps || ['EDIT', 'PREVIEW', 'IMPORT'];
40
41 Clipperz.PM.Components.Import.GenericImportComponent.superclass.constructor.call(this, anElement, args);
42
43 this._user = args['user'];
44
45 this._currentStep = 0;
46 this._currentStatus = 'IDLE'; //'PROCESSING'
47
48 this._parsedValues = null;
49 this._processedValues = null;
50
51 this._backButton = null;
52 this._nextButton = null;
53
54 Clipperz.NotificationCenter.register(null, 'importProcessorProgressUpdate', this, 'updateProgressDialogStatus');
55
56 return this;
57}
58
59//=============================================================================
60
61YAHOO.extendX(Clipperz.PM.Components.Import.GenericImportComponent, Clipperz.PM.Components.BaseComponent, {
62
63 'toString': function() {
64 return "Clipperz.PM.Components.Import.GenericImportComponent component";
65 },
66
67 //-------------------------------------------------------------------------
68
69 'user': function() {
70 return this._user;
71 },
72
73 //-------------------------------------------------------------------------
74
75 'textAreaConfig': function() {
76 return {tag:'textarea', name:this.getId('importTextArea'), cls:'importTextArea', id:this.getId('importTextArea'), cols:60, rows:15, html:""};
77 },
78
79 'textAreaContent': function() {
80 return this.getDom('importTextArea').value
81 },
82
83 //-------------------------------------------------------------------------
84
85 'steps': function() {
86 return this._steps;
87 },
88
89 'currentStep': function() {
90 return this._currentStep;
91 },
92
93 'setCurrentStep': function(aValue) {
94 this._currentStep = aValue;
95 this.updateSteps();
96 },
97
98 //-------------------------------------------------------------------------
99
100 'currentStatus': function() {
101 return this._currentStatus;
102 },
103
104 'startProcessing': function() {
105 this._currentStatus = 'PROCESSING';
106 this.updateSteps();
107 },
108
109 'processingDone': function() {
110 this._currentStatus = 'IDLE';
111 this.setCurrentStep(this.currentStep() + 1);
112 },
113
114 'processingAborted': function() {
115 this._currentStatus = 'IDLE';
116 this.updateSteps();
117 },
118
119 //-------------------------------------------------------------------------
120
121 'stepsConfig': function() {
122 var result;
123 var i,c;
124
125 result = [];
126 c = this.steps().length;
127 for (i=0; i<c; i++) {
128 var cls;
129
130 if (this.currentStep() == i) {
131 if (this.currentStatus() == 'IDLE') {
132 cls = 'current';
133 } else {
134 cls = 'currentProcessing';
135 }
136 } else {
137 cls = "";
138 }
139
140 result.push({tag:'td', cls:cls, children:[
141 {tag:'div', children:[{tag:'span', htmlString:Clipperz.PM.Strings['ImportWizard'][this.steps()[i]]}]}
142 ]})
143 if (i < (c-1)) {
144 if ((this.currentStep() == i) && (this.currentStatus() == 'PROCESSING')) {
145 cls = 'stepSeparatorProcessing';
146 } else {
147 cls = 'stepSeparator';
148 }
149
150 result.push({tag:'td', cls:cls, children:[
151 {tag:'div', children:[{tag:'span', html:">"}]}
152 ]});
153 }
154 }
155
156 result = [{tag:'div', cls:'importWizardStepsBox', children:[
157 {tag:'div', cls:'importWizardStepsInnerBox', children:[
158 {tag:'table', cls:'importWizardSteps', children:[
159 {tag:'tbody', children:[
160 {tag:'tr', children:result}
161 ]}
162 ]}
163 ]},
164 {tag:'div', cls:'importWizardStepsBoxFooter'}
165 ]}];
166
167 return result;
168 },
169
170 'updateSteps': function() {
171 this.getElement('importSteps').update("");
172 Clipperz.YUI.DomHelper.append(this.getDom('importSteps'), {tag:'div', children:this.stepsConfig()});
173 },
174
175 //-------------------------------------------------------------------------
176
177 'backAction': function() {
178//MochiKit.Logging.logDebug(">>> backAction");
179 if (this.currentStep() == 0) {
180 Clipperz.NotificationCenter.notify(this, 'importCancelled');
181 } else {
182 this.getElement('step_' + this.currentStep()).hide();
183 this.setCurrentStep(this.currentStep() - 1);
184 this.getElement('step_' + this.currentStep()).show();
185
186 this.nextButton().enable();
187 }
188//MochiKit.Logging.logDebug("<<< backAction");
189 },
190
191 //-------------------------------------------------------------------------
192
193 'backButton': function() {
194 return this._backButton;
195 },
196
197 'setBackButton': function(aValue) {
198 this._backButton = aValue;
199 },
200
201 'nextButton': function() {
202 return this._nextButton;
203 },
204
205 'setNextButton': function(aValue) {
206 this._nextButton = aValue;
207 },
208
209 //-------------------------------------------------------------------------
210
211 'render': function() {
212//MochiKit.Logging.logDebug(">>> Import.GenericImportComponent.render");
213 this.domHelper().append(this.element(), {tag:'div', children:[
214 {tag:'h2', html:this.toString()}
215 ]});
216//MochiKit.Logging.logDebug("<<< Import.GenericImportComponent.render");
217 },
218
219 //-------------------------------------------------------------------------
220
221 'previewValues': function() {
222 Clipperz.PM.Components.MessageBox.showProgressPanel(
223 MochiKit.Base.method(this, 'deferredPreviewValues'),
224 MochiKit.Base.method(this, 'handlePreviewError'),
225 this.getDom('nextActionButton')
226 );
227 },
228
229 'deferredPreviewValues': function() {
230 throw Clipperz.Base.exception.AbstractMethod;
231 },
232
233 'handlePreviewError': function(anError) {
234console.log("anError", anError);
235 MochiKit.Logging.logError("An error occurred while previewing the data: " + anError);
236 alert("An error occurred while previewing the data");
237 Clipperz.PM.Components.MessageBox().hide();
238 },
239
240 //-------------------------------------------------------------------------
241
242 'previewRecordValues': function(someProcessedRecords) {
243//MochiKit.Logging.logDebug(">>> previewRecordValues");
244 this.getElement('previewDiv').update("");
245//MochiKit.Logging.logDebug("--- previewRecordValues - 1");
246 this.domHelper().append(this.getElement('previewDiv'), {tag:'div', cls:'importPreviewDiv', children:[{tag:'table', id:'importPreview', cellspacing:'0', children:[
247 {tag:'tbody', children:
248 MochiKit.Base.map(MochiKit.Base.bind(function(aRecord) {
249 var result;
250//MochiKit.Logging.logDebug("--- previewRecordValues - 1.1");
251//console.log("fields", aRecord.currentVersion().fields());
252 result = {tag:'tr', children:[{tag:'td', children:[
253 {tag:'table', cls:'importPreview_record', children:[
254 {tag:'tbody', children:[
255 {tag:'tr', children:[
256 {tag:'td', rowspan:'2', valign:'top', children:[
257 {tag:'input', type:'checkbox', id:this.getId(aRecord.reference()), value:"aRecord.reference()", checked:true}
258 ]},
259 {tag:'td', colspan:'2', children:[
260 {tag:'span', cls:'importPreview_title', html:aRecord.label()}
261 ]}
262 ]},
263 {tag:'tr', children:[
264 {tag:'td', valign:'top', children:[
265 {tag:'span', cls:'importPreview_notes', html:(MochiKit.Base.isNotEmpty(aRecord.notes()) ? aRecord.notes().replace(/\n/g, '<br>') : '&nbsp;')}
266 ]},
267 {tag:'td', valign:'top', cls:'importPreview_fieds', children:[
268 {tag:'table', cls:'importPreview_fields', children:[
269 {tag:'tbody', children:MochiKit.Base.map(function(aField) {
270 var result;
271//MochiKit.Logging.logDebug("--- previewRecordValues - 1.1.1");
272 result = {tag:'tr', children:[
273 {tag:'td', valign:'top', children:[
274 {tag:'span', cls:'importPreview_fields_label', html:aField.label()}
275 ]},
276 {tag:'td', valign:'top', children:[
277 {tag:'span', cls:'importPreview_fields_value', html:aField.value()}
278 ]}
279 ]};
280//MochiKit.Logging.logDebug("--- previewRecordValues - 1.1.2");
281 return result;
282 }, MochiKit.Base.values(aRecord.currentVersion().fields()))}
283 ]}
284 ]}
285 ]}
286 ]}
287 ]}
288 ]}]};
289//MochiKit.Logging.logDebug("--- previewRecordValues - 1.2");
290 return result;
291 }, this), someProcessedRecords)
292 }
293 ]}]});
294//MochiKit.Logging.logDebug("--- previewRecordValues - 2");
295
296 MochiKit.Base.map(MochiKit.Base.bind(function(aRecord) {
297 this.getElement(aRecord.reference()).dom.value = aRecord.reference();
298 }, this), someProcessedRecords);
299
300 Clipperz.Style.applyZebraStylesToTable('importPreview');
301//MochiKit.Logging.logDebug("<<< previewRecordValues");
302 },
303
304 //-------------------------------------------------------------------------
305
306 'updateProgressDialogStatus': function(anEvent) {
307 Clipperz.PM.Components.MessageBox().update({step:anEvent.parameters().progress});
308 },
309
310 //-------------------------------------------------------------------------
311
312 'parsedValues': function() {
313 return this._parsedValues;
314 },
315
316 'setParsedValues': function(aValue) {
317 this._parsedValues = aValue;
318
319 return this._parsedValues;
320 },
321
322 //-------------------------------------------------------------------------
323
324 'processedValues': function() {
325 return this._processedValues;
326 },
327
328 'setProcessedValues': function(aValue) {
329 this._processedValues = aValue;
330 return this._processedValues;
331 },
332
333 //-------------------------------------------------------------------------
334
335 'importValues': function() {
336 var deferredResult;
337
338 deferredResult = new MochiKit.Async.Deferred();
339
340 deferredResult.addCallback(MochiKit.Base.bind(function() {
341 this.nextButton().disable();
342 this.startProcessing();
343 },this));
344 deferredResult.addCallback(MochiKit.Base.method(this, 'importProcessedValues'));
345 deferredResult.addCallback(MochiKit.Base.method(this, 'processingDone'));
346 deferredResult.addErrback (MochiKit.Base.method(this, 'processingAborted'));
347 deferredResult.callback();
348
349 return deferredResult;
350 },
351
352 //-------------------------------------------------------------------------
353
354 'importProcessedValues': function() {
355 var deferredResult;
356 var processedValues;
357 var selectedRecords;
358 var i,c;
359
360//MochiKit.Logging.logDebug(">>> GenericImportComponent.importProcessedValues");
361 processedValues = this.processedValues();
362 selectedRecords = [];
363
364 c = processedValues.length;
365 for (i=0; i<c; i++) {
366 var currentRecord;
367
368 currentRecord = processedValues[i];
369 if (this.getDom(currentRecord.reference()).checked == true) {
370 selectedRecords.push(currentRecord);
371 }
372 }
373
374 deferredResult = new MochiKit.Async.Deferred();
375//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("GenericImportComponent - 1: " + res); return res;});
376 deferredResult.addCallback(function(someRecords) {
377 var innerDeferredResult;
378 var text;
379
380 text = Clipperz.PM.Strings['importData_importConfirmation_text'];
381 text = text.replace(/__numberOfRecords__/, someRecords.length);
382
383 innerDeferredResult = new MochiKit.Async.Deferred();
384//innerDeferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("GenericImportComponent - 1.1: " + res); return res;});
385 innerDeferredResult.addCallback(MochiKit.Async.succeed, someRecords);
386//innerDeferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("GenericImportComponent - 1.2: " + res); return res;});
387
388 Clipperz.PM.Components.MessageBox().deferredShow({
389 title:Clipperz.PM.Strings['importData_importConfirmation_title'],
390 text:text,
391 width:240,
392 showProgressBar:false,
393 showCloseButton:false,
394 buttons:{
395 'yes':"yes", //Clipperz.PM.Strings['mainPanelDeleteRecordPanelConfirmButtonLabel'],
396 'no':"no" //Clipperz.PM.Strings['mainPanelDeleteRecordPanelDenyButtonLabel']
397 },
398 fn:MochiKit.Base.partial(function(aDeferred, aResult) {
399 if (aResult == 'yes') {
400 aDeferred.callback(aResult);
401 } else {
402 aDeferred.errback(aResult);
403 }
404 }, innerDeferredResult)
405 }/*, this.getId('nextActionButton')*/);
406
407 return innerDeferredResult;
408 });
409
410//-------------------
411 // deferredResult.addCallback(MochiKit.Base.bind(function(someRecords) {
412 // Clipperz.PM.Components.MessageBox.showProgressPanel(
413 // MochiKit.Base.method(this, 'importProcessedValues_core', someRecords),
414 // MochiKit.Base.method(this, 'handleProcessError'),
415 // this.getDom('mainDiv')
416 // );
417 // }, this));
418
419//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("GenericImportComponent - 2: " + res); return res;});
420 deferredResult.addCallback(MochiKit.Base.method(Clipperz.PM.Components.MessageBox(), 'deferredShow'),
421 {
422 // title:Clipperz.PM.Strings['accountPanelDeletingAccountPanelProgressTitle'],
423 // text:Clipperz.PM.Strings['accountPanelDeletingAccountPanelProgressText'],
424 width:240,
425 showProgressBar:true,
426 showCloseButton:false
427 }
428 );
429//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("GenericImportComponent - 3: " + res); return res;});
430
431 deferredResult.addCallback(MochiKit.Base.bind(function(someRecords) {
432 var innerDeferredResult;
433
434//MochiKit.Logging.logDebug(">>> inner deferred");
435 innerDeferredResult = new MochiKit.Async.Deferred();
436
437//innerDeferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("GenericImportComponent - 3.1: " + res); return res;});
438 innerDeferredResult.addCallback(MochiKit.Base.method(this, 'importProcessedValues_core', someRecords));
439//innerDeferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("GenericImportComponent - 3.2: " + res); return res;});
440 innerDeferredResult.addErrback(MochiKit.Base.method(this, 'handleProcessError'));
441//innerDeferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("GenericImportComponent - 3.3: " + res); return res;});
442 innerDeferredResult.callback(someRecords);
443//MochiKit.Logging.logDebug("<<< inner deferred");
444
445 return innerDeferredResult;
446 }, this), selectedRecords);
447//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("GenericImportComponent - 4: " + res); return res;});
448
449 deferredResult.addCallback(MochiKit.Base.method(Clipperz.PM.Components.MessageBox(), 'hide'), 'mainDiv');
450
451 deferredResult.addErrback(MochiKit.Base.bind(function() {
452 this.nextButton().enable();
453 this.setCurrentStep(this.currentStep() -1);
454 }, this));
455//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("GenericImportComponent - 5: " + res); return res;});
456
457 deferredResult.callback(selectedRecords);
458//MochiKit.Logging.logDebug("<<< GenericImportComponent.importProcessedValues");
459
460 return deferredResult;
461 },
462
463 //-------------------------------------------------------------------------
464
465 'importProcessedValues_core': function(someRecords) {
466 var deferredResult;
467
468 deferredResult = new MochiKit.Async.Deferred();
469
470 deferredResult.addCallback(Clipperz.NotificationCenter.deferredNotification, this, 'updatedProgressState', 'processingImportData');
471 deferredResult.addCallback(Clipperz.NotificationCenter.deferredNotification, this, 'updatedProgressState', {steps:(someRecords.length + 6 + 1)});
472 deferredResult.addCallback(MochiKit.Async.wait, 0.5);
473//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("importProcessedValues_core - 3: " + res); return res;});
474 deferredResult.addCallback(MochiKit.Base.bind(function(someRecords) {
475 var i,c;
476
477 c = someRecords.length;
478 for (i=0; i<c; i++) {
479 this.user().addRecord(someRecords[i], true);
480 }
481
482 return someRecords;
483 }, this));
484 deferredResult.addCallback(MochiKit.Async.wait, 0.5);
485//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("importProcessedValues_core - 4: " + res); return res;});
486 deferredResult.addCallback(Clipperz.NotificationCenter.deferredNotification, this, 'recordAdded', null);
487//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("importProcessedValues_core - 5: " + res); return res;});
488 deferredResult.addCallback(MochiKit.Base.method(this.user(), 'saveRecords'));
489//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("importProcessedValues_core - 6: " + res); return res;});
490 deferredResult.addCallback(Clipperz.NotificationCenter.deferredNotification, this, 'selectTab', 'mainTabPanel.recordsTab');
491//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("importProcessedValues_core - 7: " + res); return res;});
492
493 if (this.user().preferences().shouldShowDonationPanel()) {
494 deferredResult.addCallback(Clipperz.PM.showDonationSplashScreen, this.user(), 'mainDiv');
495 }
496
497 deferredResult.addCallback(Clipperz.NotificationCenter.deferredNotification, this, 'importCompleted', null);
498
499 deferredResult.callback(someRecords);
500
501 return deferredResult;
502 },
503
504 //-------------------------------------------------------------------------
505
506 'handleParseError': function(res) {
507 this.processingAborted();
508 MochiKit.Logging.logError("An error occurred while parsing the values: " + res);
509 alert("An error occurred while parsing the values: " + res);
510 Clipperz.PM.Components.MessageBox().hide();
511 },
512
513 'handleProcessError': function(res) {
514 this.processingAborted();
515 MochiKit.Logging.logError("An error occurred while processing the values: " + res);
516 alert("An error occurred while processing the values: " + res);
517 Clipperz.PM.Components.MessageBox().hide();
518 },
519
520 //-------------------------------------------------------------------------
521 __syntaxFix__: "syntax fix"
522});
523
diff --git a/frontend/beta/js/Clipperz/PM/Components/Import/KeePassImportComponent.js b/frontend/beta/js/Clipperz/PM/Components/Import/KeePassImportComponent.js
new file mode 100644
index 0000000..0657520
--- a/dev/null
+++ b/frontend/beta/js/Clipperz/PM/Components/Import/KeePassImportComponent.js
@@ -0,0 +1,450 @@
1/*
2
3Copyright 2008-2011 Clipperz Srl
4
5This file is part of Clipperz's Javascript Crypto Library.
6Javascript Crypto Library provides web developers with an extensive
7and efficient set of cryptographic functions. The library aims to
8obtain maximum execution speed while preserving modularity and
9reusability.
10For further information about its features and functionalities please
11refer to http://www.clipperz.com
12
13* Javascript Crypto Library is free software: you can redistribute
14 it and/or modify it under the terms of the GNU Affero General Public
15 License as published by the Free Software Foundation, either version
16 3 of the License, or (at your option) any later version.
17
18* Javascript Crypto Library is distributed in the hope that it will
19 be useful, but WITHOUT ANY WARRANTY; without even the implied
20 warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
21 See the GNU Affero General Public License for more details.
22
23* You should have received a copy of the GNU Affero General Public
24 License along with Javascript Crypto Library. If not, see
25 <http://www.gnu.org/licenses/>.
26
27*/
28
29if (typeof(Clipperz) == 'undefined') { Clipperz = {}; }
30if (typeof(Clipperz.PM) == 'undefined') { Clipperz.PM = {}; }
31if (typeof(Clipperz.PM.Components) == 'undefined') { Clipperz.PM.Components = {}; }
32if (typeof(Clipperz.PM.Components.Import) == 'undefined') { Clipperz.PM.Components.Import = {}; }
33
34//#############################################################################
35
36Clipperz.PM.Components.Import.KeePassImportComponent = function(anElement, args) {
37 args = args || {};
38
39 Clipperz.PM.Components.Import.KeePassImportComponent.superclass.constructor.call(this, anElement, args);
40
41 this._steps = ['EDIT', 'KEEPASS_SETTINGS', 'PREVIEW', 'IMPORT'];
42 this._definedFields = ['Group', 'Group Tree', 'UserName', 'URL', 'Password', 'Notes', 'UUID', 'Icon', 'Creation Time', 'Last Access', 'Last Modification', 'Expires', 'Attachment Description', 'Attachment'];
43
44 this.render();
45
46 return this;
47}
48
49//=============================================================================
50
51YAHOO.extendX(Clipperz.PM.Components.Import.KeePassImportComponent, Clipperz.PM.Components.Import.GenericImportComponent, {
52
53 'toString': function() {
54 return "Clipperz.PM.Components.Import.KeePassImportComponent component";
55 },
56
57 //-------------------------------------------------------------------------
58
59 'render': function() {
60//MochiKit.Logging.logDebug(">>> Import.KeePassImportComponent.render");
61 this.domHelper().append(this.element(), {tag:'div', cls:'keePassImportWizard', children:[
62 {tag:'h3', htmlString:Clipperz.PM.Strings['KeePass_ImportWizard_Title']},
63 {tag:'div', cls:'importSteps', id:this.getId('importSteps')},
64 {tag:'div', cls:'importStepBlocks', children:[
65 {tag:'div', cls:'step_0', id:this.getId('step_0'), children:[
66 {tag:'div', children:[
67 {tag:'div', cls:'importOptionsDescription', htmlString:Clipperz.PM.Strings['importOptions_keePass_description']},
68 {tag:'div', cls:'importOptionsParameters', children:[]},
69 this.textAreaConfig()
70 ]}
71 ]},
72 {tag:'div', cls:'step_1', id:this.getId('step_1'), children:[
73 {tag:'div', children:[
74 {tag:'div', id:this.getId('settingsDiv'), children:[
75 {tag:'table', id:'KeePassSettings', children:[
76 {tag:'tbody', children:[
77 {tag:'tr', children:[
78 {tag:'td', width:'50%', valign:'top', children:[
79 {tag:'table', children:[
80 {tag:'tbody', children:[
81 {tag:'tr', children:[
82 {tag:'td', valign:'top', children:[{tag:'input', type:'checkbox', id:this.getId('Group_checkbox'), name:'Group'/*, checked:true*/}]},
83 {tag:'td', width:'150', valign:'top', children:[{tag:'span', cls:'keePassFieldLabel', id:this.getId('Group_label'), html:"Group"}]}
84 ]},
85 {tag:'tr', children:[
86 {tag:'td', valign:'top', children:[{tag:'input', type:'checkbox', id:this.getId('Group Tree_checkbox'), name:'Group Tree'/*, checked:true*/}]},
87 {tag:'td', valign:'top', children:[{tag:'span', cls:'keePassFieldLabel', id:this.getId('Group Tree_label'), html:"Group Tree"}]}
88 ]},
89 {tag:'tr', children:[
90 {tag:'td', valign:'top', children:[{tag:'input', type:'checkbox', id:this.getId('UserName_checkbox'), name:'UserName', checked:true}]},
91 {tag:'td', valign:'top', children:[{tag:'span', cls:'keePassFieldLabel', id:this.getId('UserName_label'), html:"UserName"}]}
92 ]},
93 {tag:'tr', children:[
94 {tag:'td', valign:'top', children:[{tag:'input', type:'checkbox', id:this.getId('URL_checkbox'), name:'URL', checked:true}]},
95 {tag:'td', valign:'top', children:[{tag:'span', cls:'keePassFieldLabel', id:this.getId('URL_label'), html:"URL"}]}
96 ]},
97 {tag:'tr', children:[
98 {tag:'td', valign:'top', children:[{tag:'input', type:'checkbox', id:this.getId('Password_checkbox'), name:'Password', checked:true}]},
99 {tag:'td', valign:'top', children:[{tag:'span', cls:'keePassFieldLabel', id:this.getId('Password_label'), html:"Password"}]}
100 ]},
101 {tag:'tr', children:[
102 {tag:'td', valign:'top', children:[{tag:'input', type:'checkbox', id:this.getId('Notes_checkbox'), name:'Notes', checked:true}]},
103 {tag:'td', valign:'top', children:[{tag:'span', cls:'keePassFieldLabel', id:this.getId('Notes_label'), html:"Notes"}]}
104 ]},
105 {tag:'tr', children:[
106 {tag:'td', valign:'top', children:[{tag:'input', type:'checkbox', id:this.getId('UUID_checkbox'), name:'UUID'/*, checked:true*/}]},
107 {tag:'td', valign:'top', children:[{tag:'span', cls:'keePassFieldLabel', id:this.getId('UUID_label'), html:"UUID"}]}
108 ]}
109 ]}
110 ]}
111 ]},
112 {tag:'td', width:'50%', valign:'top', children:[
113 {tag:'table', children:[
114 {tag:'tbody', children:[
115 {tag:'tr', children:[
116 {tag:'td', valign:'top', children:[{tag:'input', type:'checkbox', id:this.getId('Icon_checkbox'), name:'Icon'/*, checked:true*/}]},
117 {tag:'td', width:'150', valign:'top', children:[{tag:'span', cls:'keePassFieldLabel', id:this.getId('Icon_label'), html:"Icon"}]}
118 ]},
119 {tag:'tr', children:[
120 {tag:'td', valign:'top', children:[{tag:'input', type:'checkbox', id:this.getId('Creation Time_checkbox'), name:'Creation Time'/*, checked:true*/}]},
121 {tag:'td', valign:'top', children:[{tag:'span', cls:'keePassFieldLabel', id:this.getId('Creation Time_label'), html:"Creation Time"}]}
122 ]},
123 {tag:'tr', children:[
124 {tag:'td', valign:'top', children:[{tag:'input', type:'checkbox', id:this.getId('Last Access_checkbox'), name:'Last Access'/*, checked:true*/}]},
125 {tag:'td', valign:'top', children:[{tag:'span', cls:'keePassFieldLabel', id:this.getId('Last Access_label'), html:"Last Access"}]}
126 ]},
127 {tag:'tr', children:[
128 {tag:'td', valign:'top', children:[{tag:'input', type:'checkbox', id:this.getId('Last Modification_checkbox'), name:'Last Modification'/*, checked:true*/}]},
129 {tag:'td', valign:'top', children:[{tag:'span', cls:'keePassFieldLabel', id:this.getId('Last Modification_label'), html:"Last Modification"}]}
130 ]},
131 {tag:'tr', children:[
132 {tag:'td', valign:'top', children:[{tag:'input', type:'checkbox', id:this.getId('Expires_checkbox'), name:'Expires'/*, checked:true*/}]},
133 {tag:'td', valign:'top', children:[{tag:'span', cls:'keePassFieldLabel', id:this.getId('Expires_label'), html:"Expires"}]}
134 ]},
135 {tag:'tr', children:[
136 {tag:'td', valign:'top', children:[{tag:'input', type:'checkbox', id:this.getId('Attachment Description_checkbox'), name:'Attachment Description', checked:true}]},
137 {tag:'td', valign:'top', children:[{tag:'span', cls:'keePassFieldLabel', id:this.getId('Attachment Description_label'), html:"Attachment Description"}]}
138 ]},
139 {tag:'tr', children:[
140 {tag:'td', valign:'top', children:[{tag:'input', type:'checkbox', id:this.getId('Attachment_checkbox'), name:'Attachment', checked:true}]},
141 {tag:'td', valign:'top', children:[{tag:'span', cls:'keePassFieldLabel', id:this.getId('Attachment_label'), html:"Attachment"}]}
142 ]}
143 ]}
144 ]}
145 ]}
146 ]}
147 ]}
148 ]}
149 ]}
150 ]}
151 ]},
152 {tag:'div', cls:'step_2', id:this.getId('step_2'), children:[
153 {tag:'div', children:[
154 {tag:'div', id:this.getId('previewDiv'), html:"preview"}
155 ]}
156 ]},
157 {tag:'div', cls:'step_3', id:this.getId('step_3'), children:[
158 {tag:'div', children:[
159 {tag:'h4', html:"done"}
160 ]}
161 ]}
162 ]},
163 {tag:'div', cls:'importOptionsButtons', children:[
164 {tag:'table', children:[
165 {tag:'tbody', children:[
166 {tag:'tr', children:[
167 {tag:'td', html:'&nbsp;'},
168 {tag:'td', children:[
169 {tag:'div', id:this.getId('backActionButton')}
170 ]},
171 {tag:'td', html:'&nbsp;'},
172 {tag:'td', children:[
173 {tag:'div', id:this.getId('nextActionButton')}
174 ]},
175 {tag:'td', html:'&nbsp;'}
176 ]}
177 ]}
178 ]}
179 ]}
180 ]});
181
182 this.updateSteps();
183
184 this.setBackButton(new YAHOO.ext.Button(this.getDom('backActionButton'), {text:"back", handler:this.backAction, scope:this}));
185 this.setNextButton(new YAHOO.ext.Button(this.getDom('nextActionButton'), {text:"next", handler:this.nextAction, scope:this}));
186
187 this.getElement('step_0').setVisibilityMode(YAHOO.ext.Element.DISPLAY).show()
188 this.getElement('step_1').setVisibilityMode(YAHOO.ext.Element.DISPLAY).hide();
189 this.getElement('step_2').setVisibilityMode(YAHOO.ext.Element.DISPLAY).hide();
190 this.getElement('step_3').setVisibilityMode(YAHOO.ext.Element.DISPLAY).hide();
191//MochiKit.Logging.logDebug("<<< Import.KeePassImportComponent.render");
192 },
193
194 //-------------------------------------------------------------------------
195
196 'nextAction': function() {
197 switch (this.currentStep()) {
198 case 0: //-> 1
199 Clipperz.PM.Components.MessageBox.showProgressPanel(
200 MochiKit.Base.method(this, 'deferredParseValues'),
201 MochiKit.Base.method(this, 'handleParseError'),
202 this.getDom('nextActionButton')
203 );
204 break;
205 case 1: //-> 2
206 this.previewValues();
207 break;
208 case 2: //-> 3
209 this.importValues();
210 break;
211 }
212 },
213
214 //-------------------------------------------------------------------------
215
216 'deferredParseValues': function() {
217 var deferredResult;
218
219 deferredResult = new MochiKit.Async.Deferred();
220//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("KeePassImportComponent.deferredParseValues - 1 " + res.substring(0,50)); return res;});
221 deferredResult.addCallback(Clipperz.NotificationCenter.deferredNotification, this, 'updatedProgressState', 'parseImportData');
222//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("KeePassImportComponent.deferredParseValues - 2 " + res.substring(0,50)); return res;});
223 deferredResult.addCallback(MochiKit.Base.bind(function(res) {
224 this.startProcessing();
225
226 return res;
227 }, this));
228//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("KeePassImportComponent.deferredParseValues - 3 " + res.substring(0,50)); return res;});
229 deferredResult.addCallback(MochiKit.Base.method(this, 'parseKeePassValues')); //processPasswordPlusValues
230//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("KeePassImportComponent.deferredParseValues - 4 " + res); return res;});
231 deferredResult.addCallback(MochiKit.Base.method(this, 'setParsedValues')); //setProcessedValues
232//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("KeePassImportComponent.deferredParseValues - 5 " + res); return res;});
233 deferredResult.addCallback(MochiKit.Base.method(this, 'showSettings')); //previewRecordValues
234//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("KeePassImportComponent.deferredParseValues - 6 " + res); return res;});
235 deferredResult.addCallback(MochiKit.Base.bind(function(res) {
236 this.processingDone();
237 this.getElement('step_0').hide();
238 this.getElement('step_1').show();
239 this.backButton().enable();
240
241 return res;
242 }, this));
243//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("KeePassImportComponent.deferredParseValues - 7 " + res); return res;});
244 deferredResult.callback(this.textAreaContent());
245
246 return deferredResult;
247 },
248
249 //-------------------------------------------------------------------------
250
251 'deferredPreviewValues': function() {
252 var deferredResult;
253
254//MochiKit.Logging.logDebug(">>> KeePassImportComonent.deferredPreviewValues");
255 deferredResult = new MochiKit.Async.Deferred();
256//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("KeePassImportComponent.deferredPreviewValues - 1 " + res); return res;});
257 deferredResult.addCallback(Clipperz.NotificationCenter.deferredNotification, this, 'updatedProgressState', 'previewImportData');
258//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("KeePassImportComponent.deferredPreviewValues - 2 " + res); return res;});
259 deferredResult.addCallback(MochiKit.Base.bind(function(res) {
260 this.startProcessing();
261
262 return res;
263 }, this));
264//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("KeePassImportComponent.deferredPreviewValues - 3 " + res); return res;});
265 deferredResult.addCallback(MochiKit.Base.method(this, 'processKeePassParsedValues'));
266//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("KeePassImportComponent.deferredPreviewValues - 4 " + res); return res;});
267 deferredResult.addCallback(MochiKit.Base.method(this, 'setProcessedValues'));
268//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("KeePassImportComponent.deferredPreviewValues - 5 " + res); return res;});
269 deferredResult.addCallback(MochiKit.Base.method(this, 'previewRecordValues'));
270//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("KeePassImportComponent.deferredPreviewValues - 6 " + res); return res;});
271 deferredResult.addCallback(MochiKit.Base.bind(function(res) {
272 this.processingDone();
273 this.getElement('step_1').hide();
274 this.getElement('step_2').show();
275 this.backButton().enable();
276
277 return res;
278 }, this));
279//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("KeePassImportComponent.deferredPreviewValues - 7 " + res); return res;});
280 // deferredResult.addErrback(MochiKit.Base.bind(function() {
281 // this.processingAborted();
282 // }, this))
283//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("KeePassImportComponent.deferredPreviewValues - 8 " + res); return res;});
284 deferredResult.callback(this.parsedValues());
285//MochiKit.Logging.logDebug("<<< KeePassImportComonent.deferredPreviewValues");
286
287 return deferredResult;
288 },
289
290 //-------------------------------------------------------------------------
291
292 'definedFields': function() {
293 return this._definedFields;
294 },
295
296 //-------------------------------------------------------------------------
297
298 'parseKeePassValues': function(someData) {
299 var deferredResult;
300 var keePassProcessor;
301
302 keePassProcessor = new Clipperz.KeePassExportProcessor();
303
304 deferredResult = new MochiKit.Async.Deferred();
305//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("KeePassImportComponent.parseKeePassValues - 1 " + res.substring(0,50)); return res;});
306 deferredResult.addCallback(function(res) {
307 return Clipperz.NotificationCenter.deferredNotification(this, 'updatedProgressState', {steps:(res.length)}, res);
308 })
309//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("KeePassImportComponent.parseKeePassValues - 2 " + res.substring(0,50)); return res;});
310 deferredResult.addCallback(MochiKit.Base.method(keePassProcessor, 'deferredParse'));
311//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("KeePassImportComponent.parseKeePassValues - 3 " + res); return res;});
312 deferredResult.callback(someData);
313
314 return deferredResult;
315 },
316
317 //-------------------------------------------------------------------------
318
319 'showSettings': function(someValues) {
320 var availableFields;
321 var i,c;
322
323//MochiKit.Logging.logDebug(">>> KeePassImportCOmponent.showSettings");
324 availableFields = new Clipperz.Set();
325 c = this.parsedValues().length;
326 for (i=0; i<c; i++) {
327 var fieldLabel;
328
329 for (fieldLabel in this.parsedValues()[i]) {
330 availableFields.add(fieldLabel);
331 }
332 }
333
334 c = this.definedFields().length;
335 for (i=0; i<c; i++) {
336 var definedField;
337
338 definedField = this.definedFields()[i];
339 if (availableFields.contains(definedField)) {
340//MochiKit.Logging.logDebug("enabling field " + definedField);
341 this.getDom(definedField + '_checkbox').disabled = false;
342 this.getElement(definedField + '_label').removeClass('disabled');
343 } else {
344//MochiKit.Logging.logDebug("disabling field " + definedField);
345 this.getDom(definedField + '_checkbox').disabled = true;
346 this.getDom(definedField + '_checkbox').checked = false; //????
347 this.getElement(definedField + '_label').addClass('disabled');
348 }
349 }
350//MochiKit.Logging.logDebug("<<< KeePassImportCOmponent.showSettings");
351
352 return MochiKit.Async.succeed(someValues);
353 },
354
355 //-------------------------------------------------------------------------
356
357 'shouldImportField': function(aFieldName) {
358 var fieldCheckbox;
359 var result;
360
361//MochiKit.Logging.logDebug(">>> shouldImportField: " + aFieldName);
362 // fieldCheckbox = this.getDom(aFieldName + '_checkbox');
363 fieldCheckbox = MochiKit.DOM.getElement(this.getId(aFieldName + '_checkbox'));
364 if (fieldCheckbox != null) {
365 result = fieldCheckbox.checked;
366 } else {
367 result = false;
368 }
369//MochiKit.Logging.logDebug("<<< shouldImportField: " + result);
370
371 return result;
372 },
373
374 //-------------------------------------------------------------------------
375
376 'processKeePassParsedValues': function(someValues) {
377 var deferredResult;
378 var records;
379 var i,c;
380
381//MochiKit.Logging.logDebug(">>> processKeePassParsedValues");
382 deferredResult = new MochiKit.Async.Deferred();
383 records = [];
384
385//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("processKeePassParsedValues - 1: " + res); return res;});
386 c = someValues.length;
387 deferredResult.addCallback(function(res) {
388 return Clipperz.NotificationCenter.deferredNotification(this, 'updatedProgressState', {steps:c}, res);
389 })
390 for(i=0; i<c; i++) {
391//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("[" + i + "] processKeePassParsedValues - 1.1: " + res); return res;});
392 deferredResult.addCallback(MochiKit.Async.wait, 0.2);
393//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("[" + i + "] processKeePassParsedValues - 1.2: " + res); return res;});
394 deferredResult.addCallback(Clipperz.NotificationCenter.deferredNotification, this, 'updatedProgressState', {});
395//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("[" + i + "] processKeePassParsedValues - 1.3: " + res); return res;});
396 deferredResult.addCallback(MochiKit.Base.bind(function(someRecords, someData) {
397 var record;
398 var recordVersion;
399 var ii;
400
401 record = new Clipperz.PM.DataModel.Record({user:this.user()});
402 record.setLabel(someData['Title']);
403 if (this.shouldImportField('Notes')) {
404 record.setNotes(someData['Notes']);
405 }
406 recordVersion = record.currentVersion()
407
408 for (ii in someData) {
409 if ((ii != 'Title') && (ii != 'Notes') && (typeof(someData[ii]) != "undefined") && (this.shouldImportField(ii))) {
410 var recordField;
411 var recordFieldType;
412
413 recordFieldType = 'TXT';
414 if (ii == 'Password') {
415 recordFieldType = 'PWD';
416 } else if (ii == 'URL') {
417 recordFieldType = 'URL';
418 } else if ((ii == 'Creation Time') || (ii == 'Last Access') || (ii == 'Last Modification') || (ii == 'Expires')) {
419 recordFieldType = 'Date';
420 }
421
422 recordField = new Clipperz.PM.DataModel.RecordField({
423 recordVersion:recordVersion,
424 label: ii,
425 value: someData[ii],
426 type: recordFieldType
427 });
428 recordVersion.addField(recordField);
429 }
430 }
431
432 someRecords.push(record);
433
434 return someRecords;
435 }, this), records, someValues[i]);
436//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("[" + i + "] processKeePassParsedValues - 1.4: " + res); return res;});
437 }
438//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("processKeePassParsedValues - 2: " + res); return res;});
439 deferredResult.addCallback(MochiKit.Async.succeed, records);
440//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("processKeePassParsedValues - 3: " + res); return res;});
441 deferredResult.callback();
442//MochiKit.Logging.logDebug("<<< processKeePassParsedValues");
443
444 return deferredResult;
445 },
446
447 //-------------------------------------------------------------------------
448 __syntaxFix__: "syntax fix"
449});
450
diff --git a/frontend/beta/js/Clipperz/PM/Components/Import/MainComponent.js b/frontend/beta/js/Clipperz/PM/Components/Import/MainComponent.js
new file mode 100644
index 0000000..54813bc
--- a/dev/null
+++ b/frontend/beta/js/Clipperz/PM/Components/Import/MainComponent.js
@@ -0,0 +1,332 @@
1/*
2
3Copyright 2008-2011 Clipperz Srl
4
5This file is part of Clipperz's Javascript Crypto Library.
6Javascript Crypto Library provides web developers with an extensive
7and efficient set of cryptographic functions. The library aims to
8obtain maximum execution speed while preserving modularity and
9reusability.
10For further information about its features and functionalities please
11refer to http://www.clipperz.com
12
13* Javascript Crypto Library is free software: you can redistribute
14 it and/or modify it under the terms of the GNU Affero General Public
15 License as published by the Free Software Foundation, either version
16 3 of the License, or (at your option) any later version.
17
18* Javascript Crypto Library is distributed in the hope that it will
19 be useful, but WITHOUT ANY WARRANTY; without even the implied
20 warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
21 See the GNU Affero General Public License for more details.
22
23* You should have received a copy of the GNU Affero General Public
24 License along with Javascript Crypto Library. If not, see
25 <http://www.gnu.org/licenses/>.
26
27*/
28
29if (typeof(Clipperz) == 'undefined') { Clipperz = {}; }
30if (typeof(Clipperz.PM) == 'undefined') { Clipperz.PM = {}; }
31if (typeof(Clipperz.PM.Components) == 'undefined') { Clipperz.PM.Components = {}; }
32if (typeof(Clipperz.PM.Components.Import) == 'undefined') { Clipperz.PM.Components.Import = {}; }
33
34//#############################################################################
35
36Clipperz.PM.Components.Import.MainComponent = function(anElement, args) {
37 args = args || {};
38
39 Clipperz.PM.Components.Import.MainComponent.superclass.constructor.call(this, anElement, args);
40
41 this._user = args.user;
42 this._wizardComponent = null;
43
44 this._backButton = null;
45 this._nextButton = null;
46
47 this._selectedComponent = null;
48
49 this.render();
50
51 return this;
52}
53
54//=============================================================================
55
56YAHOO.extendX(Clipperz.PM.Components.Import.MainComponent, Clipperz.PM.Components.BaseComponent, {
57
58 'toString': function() {
59 return "Clipperz.PM.Components.Import.MainComponent component";
60 },
61
62 //-------------------------------------------------------------------------
63
64 'user': function() {
65 return this._user;
66 },
67
68 //-------------------------------------------------------------------------
69
70 'wizardComponent': function() {
71 return this._wizardComponent;
72 },
73
74 'setWizardComponent': function(aValue) {
75 if (this._wizardComponent != null) {
76 this._wizardComponent.remove();
77 }
78
79 if (aValue != null) {
80 this.getElement('importCover').hide();
81 this.getElement('importWizard').show();
82 }
83 this._wizardComponent = aValue;
84 },
85
86 'resetImportComponent': function() {
87//MochiKit.Logging.logDebug(">>> resetImportComponent");
88 this.setWizardComponent(null);
89 this.getElement('wizardComponent').update("");
90
91 this.getElement('importCover').show();
92 this.getElement('importWizard').hide();
93//MochiKit.Logging.logDebug("<<< resetImportComponent");
94 },
95
96 //-------------------------------------------------------------------------
97
98 'backButton': function() {
99 return this._backButton;
100 },
101
102 'setBackButton': function(aValue) {
103 this._backButton = aValue;
104 },
105
106 'nextButton': function() {
107 return this._nextButton;
108 },
109
110 'setNextButton': function(aValue) {
111 this._nextButton = aValue;
112 },
113
114 //-------------------------------------------------------------------------
115
116 'render': function() {
117//MochiKit.Logging.logDebug(">>> Import.MainComponent.render");
118 Clipperz.NotificationCenter.unregister(this);
119 MochiKit.Signal.disconnectAllTo(this);
120
121 this.element().update("");
122 this.domHelper().append(this.element(), {tag:'div', id:this.getId('mainDiv'), children:[
123 {tag:'div', id:this.getId('importCover'), children:[
124 {tag:'h5', htmlString:Clipperz.PM.Strings['importTabTitle']},
125 {tag:'div', cls:'panelDescription', htmlString:Clipperz.PM.Strings['importTabDescription']},
126 {tag:'div', cls:'importFormats', children:[
127 {tag:'ul', cls:'radioList', children:[
128 {tag:'li', children:[
129 {tag:'table', children:[{tag:'tbody', children:[{tag:'tr', children:[
130 {tag:'td', valign:'top', children:[
131 {tag:'input', id:this.getId('CSV_radio'), type:'radio', name:'importFormat', value:'CSV'}
132 ]},
133 {tag:'td', valign:'top', children:[
134 {tag:'h4', id:this.getId('CSV_title'), htmlString:Clipperz.PM.Strings['importFormats']['CSV']['label']},
135 {tag:'div', cls:'templateDescription', htmlString:Clipperz.PM.Strings['importFormats']['CSV']['description']}
136 ]}
137 ]}]}]}
138 ]},
139 {tag:'li', children:[
140 {tag:'table', children:[{tag:'tbody', children:[{tag:'tr', children:[
141 {tag:'td', valign:'top', children:[
142 {tag:'input', id:this.getId('Excel_radio'), type:'radio', name:'importFormat', value:'EXCEL'}
143 ]},
144 {tag:'td', valign:'top', children:[
145 {tag:'h4', id:this.getId('Excel_title'), htmlString:Clipperz.PM.Strings['importFormats']['Excel']['label']},
146 {tag:'div', cls:'templateDescription', htmlString:Clipperz.PM.Strings['importFormats']['Excel']['description']}
147 ]}
148 ]}]}]}
149 ]},
150 {tag:'li', children:[
151 {tag:'table', children:[{tag:'tbody', children:[{tag:'tr', children:[
152 {tag:'td', valign:'top', children:[
153 {tag:'input', id:this.getId('KeePass_radio'), type:'radio', name:'importFormat', value:'KEEPASS'}
154 ]},
155 {tag:'td', valign:'top', children:[
156 {tag:'h4', id:this.getId('KeePass_title'), htmlString:Clipperz.PM.Strings['importFormats']['KeePass']['label']},
157 {tag:'div', cls:'templateDescription', htmlString:Clipperz.PM.Strings['importFormats']['KeePass']['description']}
158 ]}
159 ]}]}]}
160 ]},
161 {tag:'li', children:[
162 {tag:'table', children:[{tag:'tbody', children:[{tag:'tr', children:[
163 {tag:'td', valign:'top', children:[
164 {tag:'input', id:this.getId('Roboform_radio'), type:'radio', name:'importFormat', value:'ROBOFORM'}
165 ]},
166 {tag:'td', valign:'top', children:[
167 {tag:'h4', id:this.getId('Roboform_title'), htmlString:Clipperz.PM.Strings['importFormats']['Roboform']['label']},
168 {tag:'div', cls:'templateDescription', htmlString:Clipperz.PM.Strings['importFormats']['Roboform']['description']}
169 ]}
170 ]}]}]}
171 ]},
172 {tag:'li', children:[
173 {tag:'table', children:[{tag:'tbody', children:[{tag:'tr', children:[
174 {tag:'td', valign:'top', children:[
175 {tag:'input', id:this.getId('PasswordPlus_radio'), type:'radio', name:'importFormat', value:'PASSWORD_PLUS'}
176 ]},
177 {tag:'td', valign:'top', children:[
178 {tag:'h4', id:this.getId('PasswordPlus_title'), htmlString:Clipperz.PM.Strings['importFormats']['PasswordPlus']['label']},
179 {tag:'div', cls:'templateDescription', htmlString:Clipperz.PM.Strings['importFormats']['PasswordPlus']['description']}
180 ]}
181 ]}]}]}
182 ]},
183 {tag:'li', children:[
184 {tag:'table', children:[{tag:'tbody', children:[{tag:'tr', children:[
185 {tag:'td', valign:'top', children:[
186 {tag:'input', id:this.getId('ClipperzExport_radio'), type:'radio', name:'importFormat', value:'CLIPPERZ_EXPORT'}
187 ]},
188 {tag:'td', valign:'top', children:[
189 {tag:'h4', id:this.getId('ClipperzExport_title'), htmlString:Clipperz.PM.Strings['importFormats']['ClipperzExport']['label']},
190 {tag:'div', cls:'templateDescription', htmlString:Clipperz.PM.Strings['importFormats']['ClipperzExport']['description']}
191 ]}
192 ]}]}]}
193 ]}
194 ]},
195
196 {tag:'div', cls:'importOptionsButtons', children:[
197 {tag:'table', children:[
198 {tag:'tbody', children:[
199 {tag:'tr', children:[
200 {tag:'td', html:'&nbsp;'},
201 {tag:'td', children:[
202 {tag:'div', id:this.getId('backActionButton')}
203 ]},
204 {tag:'td', html:'&nbsp;'},
205 {tag:'td', children:[
206 {tag:'div', id:this.getId('nextActionButton')}
207 ]},
208 {tag:'td', html:'&nbsp;'}
209 ]}
210 ]}
211 ]}
212 ]}
213 ]}
214 ]},
215 {tag:'div', id:this.getId('importWizard'), children:[
216 {tag:'form', id:this.getId('importWizardForm'), children:[
217 {tag:'div', cls:'wizardComponent', id:this.getId('wizardComponent'), children:[]}
218 ]}
219 ]}
220 ]});
221
222 this.setBackButton(new YAHOO.ext.Button(this.getDom('backActionButton'), {text:"back", handler:this.backAction, scope:this}));
223 this.setNextButton(new YAHOO.ext.Button(this.getDom('nextActionButton'), {text:"next", handler:this.nextAction, scope:this}));
224
225 this.backButton().disable();
226 this.nextButton().disable();
227
228 this.getElement('importCover').setVisibilityMode(YAHOO.ext.Element.DISPLAY).show();
229 this.getElement('importWizard').setVisibilityMode(YAHOO.ext.Element.DISPLAY).hide();
230
231 if (Clipperz.PM.Proxy.defaultProxy.isReadOnly()) {
232 this.getElement('mainDiv').addClass('read-only');
233
234 this.getDom('ClipperzExport_radio').disabled = true;
235 this.getDom('CSV_radio').disabled = true;
236 this.getDom('Excel_radio').disabled = true;
237 this.getDom('PasswordPlus_radio').disabled = true;
238 this.getDom('Roboform_radio').disabled = true;
239 this.getDom('KeePass_radio').disabled = true;
240 } else {
241 MochiKit.Signal.connect(this.getId('ClipperzExport_radio'), 'onclick', MochiKit.Base.method(this, 'selectComponent'));
242 MochiKit.Signal.connect(this.getId('CSV_radio'), 'onclick', MochiKit.Base.method(this, 'selectComponent'));
243 MochiKit.Signal.connect(this.getId('Excel_radio'), 'onclick', MochiKit.Base.method(this, 'selectComponent'));
244 MochiKit.Signal.connect(this.getId('PasswordPlus_radio'), 'onclick', MochiKit.Base.method(this, 'selectComponent'));
245 MochiKit.Signal.connect(this.getId('Roboform_radio'), 'onclick', MochiKit.Base.method(this, 'selectComponent'));
246 MochiKit.Signal.connect(this.getId('KeePass_radio'), 'onclick', MochiKit.Base.method(this, 'selectComponent'));
247
248 if (Clipperz_IEisBroken != true) {
249 MochiKit.Signal.connect(this.getId('ClipperzExport_title'), 'onclick', this.getDom('ClipperzExport_radio'), 'click');
250 MochiKit.Signal.connect(this.getId('CSV_title'), 'onclick', this.getDom('CSV_radio'), 'click');
251 MochiKit.Signal.connect(this.getId('Excel_title'), 'onclick', this.getDom('Excel_radio'), 'click');
252 MochiKit.Signal.connect(this.getId('PasswordPlus_title'), 'onclick', this.getDom('PasswordPlus_radio'), 'click');
253 MochiKit.Signal.connect(this.getId('Roboform_title'), 'onclick', this.getDom('Roboform_radio'), 'click');
254 MochiKit.Signal.connect(this.getId('KeePass_title'), 'onclick', this.getDom('KeePass_radio'), 'click');
255 }
256
257 Clipperz.NotificationCenter.register(null, 'importCompleted', this, 'resetImportComponent');
258 Clipperz.NotificationCenter.register(null, 'importCancelled', this, 'resetImportComponent');
259 }
260
261//MochiKit.Logging.logDebug("<<< Import.MainComponent.render");
262 },
263
264 //-------------------------------------------------------------------------
265/*
266 'selectedFormat': function() {
267 return this.getDom('importSelectionOptions').value;
268 },
269*/
270 //-------------------------------------------------------------------------
271
272 'updateSelectedImportWizardComponent': function(aComponent) {
273 var newWizardComponent;
274
275//MochiKit.Logging.logDebug(">>> Import.MainComponent.updateSelectedImportWizardComponent");
276 this.getElement('wizardComponent').update("");
277
278 switch(aComponent) {
279 case 'CLIPPERZ_EXPORT':
280 newWizardComponent = new Clipperz.PM.Components.Import.ClipperzImportComponent(this.getElement('wizardComponent'), {user:this.user()});
281 break;
282 case 'CSV':
283 newWizardComponent = new Clipperz.PM.Components.Import.CSVImportComponent(this.getElement('wizardComponent'), {user:this.user()});
284 break;
285 case 'EXCEL':
286 newWizardComponent = new Clipperz.PM.Components.Import.ExcelImportComponent(this.getElement('wizardComponent'), {user:this.user()});
287 break;
288 case 'PASSWORD_PLUS':
289 newWizardComponent = new Clipperz.PM.Components.Import.PasswordPlusImportComponent(this.getElement('wizardComponent'), {user:this.user()});
290 break;
291 case 'ROBOFORM':
292 newWizardComponent = new Clipperz.PM.Components.Import.RoboFormImportComponent(this.getElement('wizardComponent'), {user:this.user()});;
293 break;
294 case 'KEEPASS':
295 newWizardComponent = new Clipperz.PM.Components.Import.KeePassImportComponent(this.getElement('wizardComponent'), {user:this.user()});
296 break;
297 }
298
299 this.setWizardComponent(newWizardComponent);
300//MochiKit.Logging.logDebug("<<< Import.MainComponent.updateSelectedWizardComponent");
301 },
302
303 //-------------------------------------------------------------------------
304
305 'selectComponent': function(anEvent) {
306 this.setSelectedComponent(anEvent.src().value);
307 this.nextButton().enable();
308 },
309
310 'selectedComponent': function() {
311 return this._selectedComponent;
312 },
313
314 'setSelectedComponent': function(aValue) {
315 this._selectedComponent = aValue;
316 },
317
318 //-------------------------------------------------------------------------
319
320 'backAction': function() {
321 },
322
323 //-------------------------------------------------------------------------
324
325 'nextAction': function() {
326 this.updateSelectedImportWizardComponent(this.selectedComponent());
327 },
328
329 //-------------------------------------------------------------------------
330 __syntaxFix__: "syntax fix"
331});
332
diff --git a/frontend/beta/js/Clipperz/PM/Components/Import/PasswordPlusImportComponent.js b/frontend/beta/js/Clipperz/PM/Components/Import/PasswordPlusImportComponent.js
new file mode 100644
index 0000000..f476ac2
--- a/dev/null
+++ b/frontend/beta/js/Clipperz/PM/Components/Import/PasswordPlusImportComponent.js
@@ -0,0 +1,315 @@
1/*
2
3Copyright 2008-2011 Clipperz Srl
4
5This file is part of Clipperz's Javascript Crypto Library.
6Javascript Crypto Library provides web developers with an extensive
7and efficient set of cryptographic functions. The library aims to
8obtain maximum execution speed while preserving modularity and
9reusability.
10For further information about its features and functionalities please
11refer to http://www.clipperz.com
12
13* Javascript Crypto Library is free software: you can redistribute
14 it and/or modify it under the terms of the GNU Affero General Public
15 License as published by the Free Software Foundation, either version
16 3 of the License, or (at your option) any later version.
17
18* Javascript Crypto Library is distributed in the hope that it will
19 be useful, but WITHOUT ANY WARRANTY; without even the implied
20 warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
21 See the GNU Affero General Public License for more details.
22
23* You should have received a copy of the GNU Affero General Public
24 License along with Javascript Crypto Library. If not, see
25 <http://www.gnu.org/licenses/>.
26
27*/
28
29if (typeof(Clipperz) == 'undefined') { Clipperz = {}; }
30if (typeof(Clipperz.PM) == 'undefined') { Clipperz.PM = {}; }
31if (typeof(Clipperz.PM.Components) == 'undefined') { Clipperz.PM.Components = {}; }
32if (typeof(Clipperz.PM.Components.Import) == 'undefined') { Clipperz.PM.Components.Import = {}; }
33
34//#############################################################################
35
36Clipperz.PM.Components.Import.PasswordPlusImportComponent = function(anElement, args) {
37 args = args || {};
38
39 Clipperz.PM.Components.Import.PasswordPlusImportComponent.superclass.constructor.call(this, anElement, args);
40
41 this.render();
42
43 return this;
44}
45
46//=============================================================================
47
48YAHOO.extendX(Clipperz.PM.Components.Import.PasswordPlusImportComponent, Clipperz.PM.Components.Import.GenericImportComponent, {
49
50 'toString': function() {
51 return "Clipperz.PM.Components.Import.PasswordPlusImportComponent component";
52 },
53
54 //-------------------------------------------------------------------------
55
56 'render': function() {
57//MochiKit.Logging.logDebug(">>> Import.PasswordPlusImportComponent.render");
58 this.domHelper().append(this.element(), {tag:'div', cls:'passwordPlusImportWizard', children:[
59 {tag:'h3', htmlString:Clipperz.PM.Strings['PasswordPlus_ImportWizard_Title']},
60 {tag:'div', cls:'importSteps', id:this.getId('importSteps')},
61 {tag:'div', cls:'importStepBlocks', children:[
62 {tag:'div', cls:'step_0', id:this.getId('step_0'), children:[
63 {tag:'div', children:[
64 {tag:'div', cls:'importOptionsDescription', htmlString:Clipperz.PM.Strings['importOptions_passwordPlus_description']},
65 {tag:'div', cls:'importOptionsParameters', children:[]},
66 this.textAreaConfig()
67 ]}
68 ]},
69 {tag:'div', cls:'step_1', id:this.getId('step_1'), children:[
70 {tag:'div', children:[
71 {tag:'div', id:this.getId('previewDiv'), html:"preview"}
72 ]}
73 ]},
74 {tag:'div', cls:'step_2', id:this.getId('step_2'), children:[
75 {tag:'div', children:[
76 {tag:'h4', html:"done"}
77 ]}
78 ]}
79 ]},
80 {tag:'div', cls:'importOptionsButtons', children:[
81 {tag:'table', children:[
82 {tag:'tbody', children:[
83 {tag:'tr', children:[
84 {tag:'td', html:'&nbsp;'},
85 {tag:'td', children:[
86 {tag:'div', id:this.getId('backActionButton')}
87 ]},
88 {tag:'td', html:'&nbsp;'},
89 {tag:'td', children:[
90 {tag:'div', id:this.getId('nextActionButton')}
91 ]},
92 {tag:'td', html:'&nbsp;'}
93 ]}
94 ]}
95 ]}
96 ]}
97 ]});
98
99 this.updateSteps();
100
101 this.setBackButton(new YAHOO.ext.Button(this.getDom('backActionButton'), {text:"back", handler:this.backAction, scope:this}));
102 this.setNextButton(new YAHOO.ext.Button(this.getDom('nextActionButton'), {text:"next", handler:this.nextAction, scope:this}));
103
104 this.getElement('step_0').setVisibilityMode(YAHOO.ext.Element.DISPLAY).show()
105 this.getElement('step_1').setVisibilityMode(YAHOO.ext.Element.DISPLAY).hide();
106 this.getElement('step_2').setVisibilityMode(YAHOO.ext.Element.DISPLAY).hide();
107//MochiKit.Logging.logDebug("<<< Import.PasswordPlusImportComponent.render");
108 },
109
110 //-------------------------------------------------------------------------
111/*
112 'backAction': function() {
113 switch (this.currentStep()) {
114 case 1: //-> 0
115 this.backButton().disable();
116 this.getElement('step_1').hide();
117 this.setCurrentStep(0);
118 this.getElement('step_0').show();
119 break;
120 }
121 },
122*/
123 //-------------------------------------------------------------------------
124
125 'nextAction': function() {
126 switch (this.currentStep()) {
127 case 0: //-> 1
128 this.previewValues();
129 break;
130 case 1: //-> 2
131 this.importValues();
132 break;
133 }
134 },
135
136 //-------------------------------------------------------------------------
137
138 'deferredPreviewValues': function() {
139 var deferredResult;
140
141 // this.setFormValues(MochiKit.DOM.formContents(this.getDom('dataForm')));
142
143 deferredResult = new MochiKit.Async.Deferred();
144 deferredResult.addCallback(MochiKit.Base.bind(function(res) {
145 this.startProcessing();
146
147 return res;
148 }, this));
149 deferredResult.addCallback(MochiKit.Base.method(this, 'processPasswordPlusValues'));
150 deferredResult.addCallback(MochiKit.Base.method(this, 'setProcessedValues'));
151 deferredResult.addCallback(MochiKit.Base.method(this, 'previewRecordValues'));
152 deferredResult.addCallback(MochiKit.Base.bind(function(res) {
153 this.processingDone();
154 this.getElement('step_0').hide();
155 this.getElement('step_1').show();
156 this.backButton().enable();
157
158 return res;
159 }, this));
160 // deferredResult.addErrback(MochiKit.Base.bind(function() {
161 // this.processingAborted();
162 // }, this))
163 deferredResult.callback(this.textAreaContent());
164
165 return deferredResult;
166 },
167
168 //-------------------------------------------------------------------------
169
170 'processPasswordPlusValues': function(someData) {
171 var deferredResult;
172 var csvProcessor;
173
174 csvProcessor = new Clipperz.CSVProcessor({binary:true});
175
176 deferredResult = new MochiKit.Async.Deferred();
177 deferredResult.addCallback(Clipperz.NotificationCenter.deferredNotification, this, 'updatedProgressState', 'parseImportData');
178 deferredResult.addCallback(function(res) {
179 return Clipperz.NotificationCenter.deferredNotification(this, 'updatedProgressState', {steps:(res.length * 2)}, res);
180 })
181 deferredResult.addCallback(MochiKit.Base.method(csvProcessor, 'deferredParse'));
182 deferredResult.addCallback(Clipperz.NotificationCenter.deferredNotification, this, 'updatedProgressState', 'previewImportData');
183 deferredResult.addCallback(function(res) {
184 return Clipperz.NotificationCenter.deferredNotification(this, 'updatedProgressState', {steps:(res.length * 2), step:res.length}, res);
185 })
186 deferredResult.addCallback(MochiKit.Base.bind(function(someCSVValues) {
187 var innerDeferredResult;
188 var records;
189 var i,c;
190
191 innerDeferredResult = new MochiKit.Async.Deferred();
192 records = [];
193
194 c = someCSVValues.length;
195 i=0;
196 i++; //Dataviz Passwords Plus Export, Version,1, Minimum Version To Read,1
197 i++; //Is Template,Title,Category,Field 1 Label,Field 1 Value,Field 1 Hidden,Field 2 Label,Field 2 Value,Field 2 Hidden,Field 3 Label,Field 3 Value,Field 3 Hidden,Field 4 Label,Field 4 Value,Field 4 Hidden,Field 5 Label,Field 5 Value,Field 5 Hidden,Field 6 Label,Field 6 Value,Field 6 Hidden,Field 7 Label,Field 7 Value,Field 7 Hidden,Field 8 Label,Field 8 Value,Field 8 Hidden,Field 9 Label,Field 9 Value,Field 9 Hidden,Field 10 Label,Field 10 Value,Field 10 Hidden,Note
198
199 for( ; i<c; i++) {
200 innerDeferredResult.addCallback(MochiKit.Async.wait, 0.2);
201 innerDeferredResult.addCallback(Clipperz.NotificationCenter.deferredNotification, this, 'updatedProgressState', {});
202 innerDeferredResult.addCallback(MochiKit.Base.bind(function(someRecords, someData) {
203 if (someData[0] == '0') {
204 var record;
205 var recordVersion;
206 var ii, cc;
207
208 record = new Clipperz.PM.DataModel.Record({user:this.user()});
209 if (someData[1] != "") {
210 record.setLabel(someData[1]);
211 } else {
212 record.setLabel("imported record [" + (i+1) + "]");
213 }
214 record.setNotes(someData[33]);
215 recordVersion = record.currentVersion()
216
217 cc = 10;
218 for (ii=0; ii<cc; ii++) {
219 var currentFieldValueIndex;
220 var currentType;
221
222 currentFieldValueIndex = (ii * 3) + 4;
223
224 if (someData[currentFieldValueIndex] != "") {
225 var recordField;
226 var recordFieldType;
227
228 recordFieldType = 'TXT';
229 if (someData[currentFieldValueIndex + 1] == 1) {
230 recordFieldType = 'PWD';
231 } else if (/^http/.test(someData[currentFieldValueIndex])) {
232 recordFieldType = 'URL';
233 }
234
235 recordField = new Clipperz.PM.DataModel.RecordField({
236 recordVersion:recordVersion,
237 label: someData[currentFieldValueIndex - 1],
238 value: someData[currentFieldValueIndex],
239 type: recordFieldType
240 });
241 recordVersion.addField(recordField);
242 }
243 }
244
245 // this.user().addRecord(record, true);
246
247 someRecords.push(record);
248 }
249
250 return someRecords;
251 }, this), records, someCSVValues[i]);
252 }
253 innerDeferredResult.addCallback(MochiKit.Async.succeed, records);
254 innerDeferredResult.callback();
255
256 return innerDeferredResult;
257 }, this));
258 deferredResult.callback(someData);
259
260 return deferredResult;
261
262/*
263 0Is Template
264 1Title
265 2Category
266
267 3Field 1 Label
268 4Field 1 Value
269 5Field 1 Hidden
270
271 6Field 2 Label
272 7Field 2 Value
273 8Field 2 Hidden
274
275 9Field 3 Label
276 10Field 3 Value
277 11Field 3 Hidden
278
279 12Field 4 Label
280 13Field 4 Value
281 14Field 4 Hidden
282
283 15Field 5 Label
284 16Field 5 Value
285 17Field 5 Hidden
286
287 18Field 6 Label
288 19Field 6 Value
289 20Field 6 Hidden
290
291 21Field 7 Label
292 22Field 7 Value
293 23Field 7 Hidden
294
295 24Field 8 Label
296 25Field 8 Value
297 26Field 8 Hidden
298
299 27Field 9 Label
300 28Field 9 Value
301 29Field 9 Hidden
302
303 30Field 10 Label
304 31Field 10 Value
305 32Field 10 Hidden
306
307 33Note
308*/
309 },
310
311
312 //-------------------------------------------------------------------------
313 __syntaxFix__: "syntax fix"
314});
315
diff --git a/frontend/beta/js/Clipperz/PM/Components/Import/RoboFormImportComponent.js b/frontend/beta/js/Clipperz/PM/Components/Import/RoboFormImportComponent.js
new file mode 100644
index 0000000..d35bdc6
--- a/dev/null
+++ b/frontend/beta/js/Clipperz/PM/Components/Import/RoboFormImportComponent.js
@@ -0,0 +1,392 @@
1/*
2
3Copyright 2008-2011 Clipperz Srl
4
5This file is part of Clipperz's Javascript Crypto Library.
6Javascript Crypto Library provides web developers with an extensive
7and efficient set of cryptographic functions. The library aims to
8obtain maximum execution speed while preserving modularity and
9reusability.
10For further information about its features and functionalities please
11refer to http://www.clipperz.com
12
13* Javascript Crypto Library is free software: you can redistribute
14 it and/or modify it under the terms of the GNU Affero General Public
15 License as published by the Free Software Foundation, either version
16 3 of the License, or (at your option) any later version.
17
18* Javascript Crypto Library is distributed in the hope that it will
19 be useful, but WITHOUT ANY WARRANTY; without even the implied
20 warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
21 See the GNU Affero General Public License for more details.
22
23* You should have received a copy of the GNU Affero General Public
24 License along with Javascript Crypto Library. If not, see
25 <http://www.gnu.org/licenses/>.
26
27*/
28
29if (typeof(Clipperz) == 'undefined') { Clipperz = {}; }
30if (typeof(Clipperz.PM) == 'undefined') { Clipperz.PM = {}; }
31if (typeof(Clipperz.PM.Components) == 'undefined') { Clipperz.PM.Components = {}; }
32if (typeof(Clipperz.PM.Components.Import) == 'undefined') { Clipperz.PM.Components.Import = {}; }
33
34//#############################################################################
35
36Clipperz.PM.Components.Import.RoboFormImportComponent = function(anElement, args) {
37 args = args || {};
38
39 Clipperz.PM.Components.Import.RoboFormImportComponent.superclass.constructor.call(this, anElement, args);
40
41 this.render();
42
43 return this;
44}
45
46//=============================================================================
47
48YAHOO.extendX(Clipperz.PM.Components.Import.RoboFormImportComponent, Clipperz.PM.Components.Import.GenericImportComponent, {
49
50 'toString': function() {
51 return "Clipperz.PM.Components.Import.RoboFormImportComponent component";
52 },
53
54 //-------------------------------------------------------------------------
55
56 'render': function() {
57//MochiKit.Logging.logDebug(">>> Import.RoboFormImportComponent.render");
58 this.domHelper().append(this.element(), {tag:'div', cls:'roboFormImportWizard', children:[
59 {tag:'h3', htmlString:Clipperz.PM.Strings['RoboForm_ImportWizard_Title']},
60 {tag:'div', cls:'importSteps', id:this.getId('importSteps')},
61 {tag:'div', cls:'importStepBlocks', children:[
62 {tag:'div', cls:'step_0', id:this.getId('step_0'), children:[
63 {tag:'div', children:[
64 {tag:'div', cls:'importOptionsDescription', htmlString:Clipperz.PM.Strings['importOptions_roboForm_description']},
65 {tag:'div', cls:'importOptionsParameters', children:[]},
66 this.textAreaConfig()
67 ]}
68 ]},
69 {tag:'div', cls:'step_1', id:this.getId('step_1'), children:[
70 {tag:'div', children:[
71 {tag:'div', id:this.getId('previewDiv'), html:"preview"}
72 ]}
73 ]},
74 {tag:'div', cls:'step_2', id:this.getId('step_2'), children:[
75 {tag:'div', children:[
76 {tag:'h4', html:"done"}
77 ]}
78 ]}
79 ]},
80 {tag:'div', cls:'importOptionsButtons', children:[
81 {tag:'table', children:[
82 {tag:'tbody', children:[
83 {tag:'tr', children:[
84 {tag:'td', html:'&nbsp;'},
85 {tag:'td', children:[
86 {tag:'div', id:this.getId('backActionButton')}
87 ]},
88 {tag:'td', html:'&nbsp;'},
89 {tag:'td', children:[
90 {tag:'div', id:this.getId('nextActionButton')}
91 ]},
92 {tag:'td', html:'&nbsp;'}
93 ]}
94 ]}
95 ]}
96 ]}
97 ]});
98
99 this.updateSteps();
100
101 this.setBackButton(new YAHOO.ext.Button(this.getDom('backActionButton'), {text:"back", handler:this.backAction, scope:this}));
102 this.setNextButton(new YAHOO.ext.Button(this.getDom('nextActionButton'), {text:"next", handler:this.nextAction, scope:this}));
103
104 this.getElement('step_0').setVisibilityMode(YAHOO.ext.Element.DISPLAY).show()
105 this.getElement('step_1').setVisibilityMode(YAHOO.ext.Element.DISPLAY).hide();
106 this.getElement('step_2').setVisibilityMode(YAHOO.ext.Element.DISPLAY).hide();
107//MochiKit.Logging.logDebug("<<< Import.RoboFormImportComponent.render");
108 },
109
110 //-------------------------------------------------------------------------
111
112 'nextAction': function() {
113 switch (this.currentStep()) {
114 case 0: //-> 1
115 this.previewValues();
116 break;
117 case 1: //-> 2
118 this.importValues();
119 break;
120 }
121 },
122
123 //-------------------------------------------------------------------------
124
125 'deferredPreviewValues': function() {
126 var deferredResult;
127
128 // this.setFormValues(MochiKit.DOM.formContents(this.getDom('dataForm')));
129
130 deferredResult = new MochiKit.Async.Deferred();
131 deferredResult.addCallback(MochiKit.Base.bind(function(res) {
132 this.startProcessing();
133
134 return res;
135 }, this));
136 deferredResult.addCallback(MochiKit.Base.method(this, 'processRoboFormValues'));
137 deferredResult.addCallback(MochiKit.Base.method(this, 'setProcessedValues'));
138 deferredResult.addCallback(MochiKit.Base.method(this, 'previewRecordValues'));
139 deferredResult.addCallback(MochiKit.Base.bind(function(res) {
140 this.processingDone();
141 this.getElement('step_0').hide();
142 this.getElement('step_1').show();
143 this.backButton().enable();
144
145 return res;
146 }, this));
147 // deferredResult.addErrback(MochiKit.Base.bind(function() {
148 // this.processingAborted();
149 // }, this))
150 deferredResult.callback(this.textAreaContent());
151
152 return deferredResult;
153 },
154
155 //-------------------------------------------------------------------------
156
157 'processRoboFormValues': function(someData) {
158 var result;
159
160 if (someData.match(/^\<HTML\>\<HEAD\>\<TITLE\>RoboForm Passcards List /g)) {
161 result = this.processRoboFormPasscardsValues(someData);
162 } else if (someData.match(/\<HTML\>\<HEAD\>\<TITLE\>RoboForm Safenotes List /g)) {
163 result = this.processRoboFormSafenotesValues(someData);
164 }
165
166 return result;
167 },
168
169 //.........................................................................
170
171 'processRoboFormPasscardsValues': function(someData) {
172 var deferredResult;
173
174 deferredResult = new MochiKit.Async.Deferred();
175//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("RoboFormImportComponent.processRoboFormValues - 1: "/* + res*/); return res;});
176 deferredResult.addCallback(Clipperz.NotificationCenter.deferredNotification, this, 'updatedProgressState', 'parseImportData');
177//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("RoboFormImportComponent.processRoboFormValues - 2: "/* + res*/); return res;});
178 deferredResult.addCallback(function(someData) {
179 var result;
180 var data;
181
182 data = someData.replace(/\r?\n/g, "");
183 result = data.match(/\<TABLE width\=\"100\%\"\>.*?\<\/TABLE\>/g);
184
185 return result;
186 });
187//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("RoboFormImportComponent.processRoboFormValues - 3: "/* + res*/); return res;});
188//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("RoboFormImportComponent.processRoboFormValues - 3.1: " + res.length); return res;});
189 deferredResult.addCallback(function(res) {
190 return Clipperz.NotificationCenter.deferredNotification(this, 'updatedProgressState', {steps:(res.length)}, res);
191 })
192//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("RoboFormImportComponent.processRoboFormValues - 4: "/* + res*/); return res;});
193 deferredResult.addCallback(MochiKit.Base.bind(function(someRecordValues) {
194 var innerDeferredResult;
195 var records;
196 var i,c;
197
198 innerDeferredResult = new MochiKit.Async.Deferred();
199 records = [];
200
201 c = someRecordValues.length;
202 for(i=0; i<c; i++) {
203//innerDeferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("RoboFormImportComponent.processRoboFormValues __inner loop__ - 1: " + res); return res;});
204 innerDeferredResult.addCallback(MochiKit.Async.wait, 0.2);
205//innerDeferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("RoboFormImportComponent.processRoboFormValues __inner loop__ - 2: " + res); return res;});
206 innerDeferredResult.addCallback(Clipperz.NotificationCenter.deferredNotification, this, 'updatedProgressState', {});
207//innerDeferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("RoboFormImportComponent.processRoboFormValues __inner loop__ - 3: " + res); return res;});
208 innerDeferredResult.addCallback(MochiKit.Base.bind(function(someRecords, someData) {
209 var data;
210 var record;
211 var recordVersion;
212 var fields;
213 var ii, cc;
214 var hasNotes;
215
216 var caption;
217 var subcaption;
218
219//MochiKit.Logging.logDebug("data: " + someData);
220 data = someData.replace(/\<WBR\>/g, "");
221 hasNotes = false;
222
223 /\<TD class\=caption colSpan\=3\>(.*?)\<\/TD\>/.test(data); //<TD class=caption colSpan=3>110mb</TD>
224 caption = RegExp.$1;
225//MochiKit.Logging.logDebug("caption: " + caption);
226
227 /\<TD class\=subcaption colSpan\=3\>(.*?)\<\/TD\>/.test(data); //<TD class=subcaption colSpan=3>110<WBR>mb.com</TD>
228 subcaption = RegExp.$1;
229//MochiKit.Logging.logDebug("subcaption: " + subcaption);
230
231 record = new Clipperz.PM.DataModel.Record({user:this.user()});
232 recordVersion = record.currentVersion()
233
234 record.setLabel(caption);
235 // record.setNotes(subcaption);
236 if (subcaption != null) {
237 var recordField;
238
239 recordField = new Clipperz.PM.DataModel.RecordField({
240 recordVersion:recordVersion,
241 label: "url",
242 value: subcaption,
243 type: 'URL'
244 });
245 recordVersion.addField(recordField);
246 }
247
248 fields = data.match(/\<TR\>.*?\<\/TR\>/g) || [];
249 cc = fields.length;
250//MochiKit.Logging.logDebug("fields.length: " + cc);
251 for (ii=0; ii<cc; ii++) {
252 var recordField;
253 var fieldString;
254 var fieldName;
255 var fieldValue;
256
257//MochiKit.Logging.logDebug("fieldString: " + fields[ii]);
258 fieldString = fields[ii];
259//MochiKit.Logging.logDebug("fieldString (cleaned): " + fieldString);
260 /\<TD class\=field vAlign\=top align\=left width\=\"40\%\"\>(.*?)\<\/TD\>/.test(fieldString);
261 fieldName = RegExp.$1;
262
263 /\<TD class\=wordbreakfield vAlign\=top align\=left width\=\"55\%\"\>(.*?)\<\/TD\>/.test(fieldString);
264 fieldValue = RegExp.$1;
265
266 if (fieldName == "Note$") {
267 record.setNotes(fieldValue);
268 hasNotes = true;
269 } else {
270 var fieldType;
271
272 if (((ii == 1) && (hasNotes == false)) || ((ii == 2) && (hasNotes == true))) {
273 fieldType = 'PWD';
274 } else {
275 fieldType = 'TXT';
276 }
277
278 recordField = new Clipperz.PM.DataModel.RecordField({
279 recordVersion:recordVersion,
280 label: fieldName,
281 value: fieldValue,
282 type: fieldType
283 });
284 recordVersion.addField(recordField);
285 }
286 }
287
288 someRecords.push(record);
289
290 return someRecords;
291 }, this), records, someRecordValues[i]);
292 }
293//innerDeferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("RoboFormImportComponent.processRoboFormValues __inner loop__ - 4: " + res); return res;});
294 innerDeferredResult.addCallback(MochiKit.Async.succeed, records);
295//innerDeferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("RoboFormImportComponent.processRoboFormValues __inner loop__ - 5: " + res); return res;});
296 innerDeferredResult.callback();
297
298 return innerDeferredResult;
299 }, this));
300 deferredResult.callback(someData);
301
302 return deferredResult;
303 },
304
305
306 //.........................................................................
307
308 'processRoboFormSafenotesValues': function(someData) {
309 var deferredResult;
310
311 deferredResult = new MochiKit.Async.Deferred();
312//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("RoboFormImportComponent.processRoboFormValues - 1: "/* + res*/); return res;});
313 deferredResult.addCallback(Clipperz.NotificationCenter.deferredNotification, this, 'updatedProgressState', 'parseImportData');
314//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("RoboFormImportComponent.processRoboFormValues - 2: "/* + res*/); return res;});
315 deferredResult.addCallback(function(someData) {
316 var result;
317 var data;
318
319 data = someData.replace(/\r?\n/g, "");
320 result = data.match(/\<TABLE width\=\"100\%\"\>.*?\<\/TABLE\>/g);
321
322 return result;
323 });
324//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("RoboFormImportComponent.processRoboFormValues - 3: "/* + res*/); return res;});
325//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("RoboFormImportComponent.processRoboFormValues - 3.1: " + res.length); return res;});
326 deferredResult.addCallback(function(res) {
327 return Clipperz.NotificationCenter.deferredNotification(this, 'updatedProgressState', {steps:(res.length)}, res);
328 })
329//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("RoboFormImportComponent.processRoboFormValues - 4: "/* + res*/); return res;});
330 deferredResult.addCallback(MochiKit.Base.bind(function(someRecordValues) {
331 var innerDeferredResult;
332 var records;
333 var i,c;
334
335 innerDeferredResult = new MochiKit.Async.Deferred();
336 records = [];
337
338 c = someRecordValues.length;
339 for(i=0; i<c; i++) {
340//innerDeferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("RoboFormImportComponent.processRoboFormValues __inner loop__ - 1: " + res); return res;});
341 innerDeferredResult.addCallback(MochiKit.Async.wait, 0.2);
342//innerDeferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("RoboFormImportComponent.processRoboFormValues __inner loop__ - 2: " + res); return res;});
343 innerDeferredResult.addCallback(Clipperz.NotificationCenter.deferredNotification, this, 'updatedProgressState', {});
344//innerDeferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("RoboFormImportComponent.processRoboFormValues __inner loop__ - 3: " + res); return res;});
345 innerDeferredResult.addCallback(MochiKit.Base.bind(function(someRecords, someData) {
346 var data;
347 var record;
348 var recordVersion;
349
350 var caption;
351 var wordbreakfield;
352
353//MochiKit.Logging.logDebug("data: " + someData);
354 data = someData.replace(/\<WBR\>/g, "");
355 hasNotes = false;
356
357 /\<TD class\=caption colSpan\=3\>(.*?)\<\/TD\>/.test(data); //<TD class=caption colSpan=3>110mb</TD>
358 caption = RegExp.$1;
359//MochiKit.Logging.logDebug("caption: " + caption);
360
361 /\<TD class\=wordbreakfield vAlign=top align\=left width\=\"\1\0\0\%\"\>(.*?)\<\/TD\>/.test(data); //<TD class=wordbreakfield vAlign=top align=left width="100%">7759500</TD>
362 wordbreakfield = RegExp.$1;
363//MochiKit.Logging.logDebug("subcaption: " + subcaption);
364
365 record = new Clipperz.PM.DataModel.Record({user:this.user()});
366 recordVersion = record.currentVersion()
367
368 record.setLabel(caption);
369 record.setNotes(wordbreakfield);
370
371 someRecords.push(record);
372
373 return someRecords;
374 }, this), records, someRecordValues[i]);
375 }
376//innerDeferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("RoboFormImportComponent.processRoboFormValues __inner loop__ - 4: " + res); return res;});
377 innerDeferredResult.addCallback(MochiKit.Async.succeed, records);
378//innerDeferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("RoboFormImportComponent.processRoboFormValues __inner loop__ - 5: " + res); return res;});
379 innerDeferredResult.callback();
380
381 return innerDeferredResult;
382 }, this));
383 deferredResult.callback(someData);
384
385 return deferredResult;
386 },
387
388
389 //-------------------------------------------------------------------------
390 __syntaxFix__: "syntax fix"
391});
392
diff --git a/frontend/beta/js/Clipperz/PM/Components/MessageBox.js b/frontend/beta/js/Clipperz/PM/Components/MessageBox.js
new file mode 100644
index 0000000..d2bc09a
--- a/dev/null
+++ b/frontend/beta/js/Clipperz/PM/Components/MessageBox.js
@@ -0,0 +1,224 @@
1/*
2
3Copyright 2008-2011 Clipperz Srl
4
5This file is part of Clipperz's Javascript Crypto Library.
6Javascript Crypto Library provides web developers with an extensive
7and efficient set of cryptographic functions. The library aims to
8obtain maximum execution speed while preserving modularity and
9reusability.
10For further information about its features and functionalities please
11refer to http://www.clipperz.com
12
13* Javascript Crypto Library is free software: you can redistribute
14 it and/or modify it under the terms of the GNU Affero General Public
15 License as published by the Free Software Foundation, either version
16 3 of the License, or (at your option) any later version.
17
18* Javascript Crypto Library is distributed in the hope that it will
19 be useful, but WITHOUT ANY WARRANTY; without even the implied
20 warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
21 See the GNU Affero General Public License for more details.
22
23* You should have received a copy of the GNU Affero General Public
24 License along with Javascript Crypto Library. If not, see
25 <http://www.gnu.org/licenses/>.
26
27*/
28
29if (typeof(Clipperz) == 'undefined') { Clipperz = {}; }
30if (typeof(Clipperz.PM) == 'undefined') { Clipperz.PM = {}; }
31if (typeof(Clipperz.PM.Components) == 'undefined') { Clipperz.PM.Components = {}; }
32
33
34
35Clipperz.PM.Components.MessageBoxImplementation = function() {
36 this._step = 0;
37 this._steps = 0;
38
39 return this;
40};
41
42//YAHOO.extendX(Clipperz.PM.Components.MessageBoxImplementation, Clipperz.PM.Components.BaseComponent, {
43Clipperz.PM.Components.MessageBoxImplementation.prototype = MochiKit.Base.update(null, {
44
45 'toString': function() {
46 return "Clipperz.PM.Components.MessageBox";
47 },
48
49 //-----------------------------------------------------
50
51 'step': function() {
52 return this._step;
53 },
54
55 'setStep': function(aValue) {
56 if (aValue == 'next') {
57 this._step = this._step + 1;
58 } else {
59 this._step = aValue;
60 }
61
62 if (this._step > this.steps()) {
63//MochiKit.Logging.logDebug("overstepping: " + this._step + " (" + this.steps() + ")");
64 this._step = this.steps();
65 }
66 },
67
68 //-----------------------------------------------------
69
70 'steps': function() {
71 return this._steps;
72 },
73
74 'setSteps': function(aValue) {
75 if (aValue.constructor == String) {
76 if (aValue.charAt(0) == '+') {
77 this._steps += aValue.substring(1)*1;
78 } else if (aValue.charAt(0) == '-') {
79 this._steps -= aValue.substring(1)*1;
80 } else {
81 this._steps = aValue.substring(1)*1;
82 }
83 } else {
84 this._steps = aValue;
85 }
86 },
87
88 //-----------------------------------------------------
89
90 'deferredShow': function(aConfiguration, anAnimationTargetElement, aValue) {
91 this.show(aConfiguration, anAnimationTargetElement);
92
93 return aValue;
94 },
95
96 'show': function(aConfiguration, anAnimationTargetElement) {
97 varmessageBoxConfiguration;
98
99 messageBoxConfiguration = MochiKit.Base.clone(aConfiguration);
100 messageBoxConfiguration.msg = messageBoxConfiguration.text;
101 messageBoxConfiguration.animEl = anAnimationTargetElement;
102 messageBoxConfiguration.progress = messageBoxConfiguration.showProgressBar;
103 messageBoxConfiguration.closable = messageBoxConfiguration.showCloseButton;
104 this.setSteps(aConfiguration.steps || 0);
105 this.setStep(aConfiguration.step || 0);
106 delete messageBoxConfiguration.buttons;
107
108 Clipperz.YUI.MessageBox.show(messageBoxConfiguration);
109 },
110
111 //-----------------------------------------------------
112
113 'update': function(someValues) {
114//MochiKit.Logging.logDebug(">>> MessageBox.update");
115 if (someValues.title) {
116 Clipperz.YUI.MessageBox.getDialog().setTitle(someValues.title);
117 };
118
119 if (someValues.text) {
120 Clipperz.YUI.MessageBox.updateText(someValues.text);
121 };
122
123 if (typeof(someValues.showProgressBar) != 'undefined') {
124 Clipperz.YUI.MessageBox.progressElement().setDisplayed(someValues.showProgressBar);
125 Clipperz.YUI.MessageBox.updateProgress(0);
126 };
127
128 if (typeof(someValues.steps) != 'undefined') {
129 this.setSteps(someValues.steps);
130 };
131
132 if (typeof(someValues.step) != 'undefined') {
133 this.setStep(someValues.step);
134 } else {
135 this.setStep('next');
136 }
137 Clipperz.YUI.MessageBox.updateProgress(this.step() / this.steps());
138
139
140 if (typeof(someValues.fn) != 'undefined') {
141 Clipperz.YUI.MessageBox.opt().fn = someValues.fn;
142 };
143
144 if (typeof(someValues.scope) != 'undefined') {
145 Clipperz.YUI.MessageBox.opt().scope = someValues.scope;
146 };
147
148 if (someValues.buttons) {
149 Clipperz.YUI.MessageBox.updateButtons(someValues.buttons);
150 };
151
152 // if (someValues.title) {
153 // Clipperz.YUI.MessageBox.getDialog().setTitle(someValues.title + " [" + this.step() + " / " + this.steps() + "]");
154 // };
155
156//MochiKit.Logging.logDebug("--- MessageBox.update - step: " + this.step() + " / " + this.steps() + " - " + someValues.text);
157//MochiKit.Logging.logDebug("<<< MessageBox.update");
158 },
159
160 //-----------------------------------------------------
161
162 'hide': function(anAnimationTargetElement) {
163 if (anAnimationTargetElement) {
164 Clipperz.YUI.MessageBox.getDialog().animateTarget = anAnimationTargetElement;
165 }
166
167 Clipperz.YUI.MessageBox.hide();
168 },
169
170 //-----------------------------------------------------
171 __syntaxFix__: '__syntaxFix__'
172});
173
174
175//##########################################################
176
177_clipperz_pm_components_messageBox = null;
178
179Clipperz.PM.Components.MessageBox = function() {
180 if (_clipperz_pm_components_messageBox == null) {
181 _clipperz_pm_components_messageBox = new Clipperz.PM.Components.MessageBoxImplementation();
182 }
183
184 return _clipperz_pm_components_messageBox;
185}
186
187//---------------------------------------------------------
188
189Clipperz.PM.Components.MessageBox.showProgressPanel = function(aCallback, anErrback, anActivationItem) {
190 var deferredResult;
191
192 deferredResult = new MochiKit.Async.Deferred();
193//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("Clipperz.PM.Components.MessageBox.showProgressPanel - 0: " + res); return res;});
194 deferredResult.addCallback(MochiKit.Base.method(Clipperz.PM.Components.MessageBox(), 'deferredShow'),
195 {
196 title: "",
197 text: "",
198 width:240,
199 showProgressBar:true,
200 showCloseButton:false,
201 fn:MochiKit.Base.method(deferredResult, 'cancel'),
202 scope:this,
203 buttons:{
204 //'ok':Clipperz.PM.Strings['loginMessagePanelInitialButtonLabel']
205 }
206 },
207 anActivationItem
208 );
209//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("Clipperz.PM.Components.MessageBox.showProgressPanel - 1: " + res); return res;});
210 deferredResult.addCallback(aCallback);
211//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("Clipperz.PM.Components.MessageBox.showProgressPanel - 2: " + res); return res;});
212 deferredResult.addCallback(MochiKit.Async.wait, 0.5);
213 deferredResult.addCallback(function(res) {
214 Clipperz.PM.Components.MessageBox().hide(YAHOO.ext.Element.get(anActivationItem));
215 return res;
216 });
217//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("Clipperz.PM.Components.MessageBox.showProgressPanel - 3: " + res); return res;});
218 deferredResult.addErrback(anErrback);
219//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("Clipperz.PM.Components.MessageBox.showProgressPanel - 4: " + res); return res;});
220 deferredResult.callback();
221
222 return deferredResult;
223};
224
diff --git a/frontend/beta/js/Clipperz/PM/Components/OTP/MainComponent.js b/frontend/beta/js/Clipperz/PM/Components/OTP/MainComponent.js
new file mode 100644
index 0000000..9d191f6
--- a/dev/null
+++ b/frontend/beta/js/Clipperz/PM/Components/OTP/MainComponent.js
@@ -0,0 +1,490 @@
1/*
2
3Copyright 2008-2011 Clipperz Srl
4
5This file is part of Clipperz's Javascript Crypto Library.
6Javascript Crypto Library provides web developers with an extensive
7and efficient set of cryptographic functions. The library aims to
8obtain maximum execution speed while preserving modularity and
9reusability.
10For further information about its features and functionalities please
11refer to http://www.clipperz.com
12
13* Javascript Crypto Library is free software: you can redistribute
14 it and/or modify it under the terms of the GNU Affero General Public
15 License as published by the Free Software Foundation, either version
16 3 of the License, or (at your option) any later version.
17
18* Javascript Crypto Library is distributed in the hope that it will
19 be useful, but WITHOUT ANY WARRANTY; without even the implied
20 warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
21 See the GNU Affero General Public License for more details.
22
23* You should have received a copy of the GNU Affero General Public
24 License along with Javascript Crypto Library. If not, see
25 <http://www.gnu.org/licenses/>.
26
27*/
28
29if (typeof(Clipperz) == 'undefined') { Clipperz = {}; }
30if (typeof(Clipperz.PM) == 'undefined') { Clipperz.PM = {}; }
31if (typeof(Clipperz.PM.Components) == 'undefined') { Clipperz.PM.Components = {}; }
32if (typeof(Clipperz.PM.Components.OTP) == 'undefined') { Clipperz.PM.Components.OTP = {}; }
33
34//#############################################################################
35
36Clipperz.PM.Components.OTP.MainComponent = function(anElement, args) {
37 args = args || {};
38
39//MochiKit.Logging.logDebug("new OTP.MainComponent");
40 Clipperz.PM.Components.OTP.MainComponent.superclass.constructor.call(this, anElement, args);
41
42 this._user = args.user;
43 this._shouldRender = true;
44
45 this._deleteButton = null;
46 this._printButton = null;
47
48 Clipperz.NotificationCenter.register(null, 'tabSelected', this, 'tabSelectedHandler');
49 //Clipperz.NotificationCenter.register(null, 'oneTimePasswordAdded', this, 'render');
50
51 return this;
52}
53
54//=============================================================================
55
56YAHOO.extendX(Clipperz.PM.Components.OTP.MainComponent, Clipperz.PM.Components.BaseComponent, {
57
58 'toString': function() {
59 return "Clipperz.PM.Components.OTP.MainComponent component";
60 },
61
62 //-------------------------------------------------------------------------
63
64 'render': function() {
65//MochiKit.Logging.logDebug("### OTP.MainComponent.render");
66 Clipperz.NotificationCenter.unregister(this);
67 MochiKit.Signal.disconnectAllTo(this);
68
69 if (Clipperz.PM.Proxy.defaultProxy.isReadOnly()) {
70 this.element().update("");
71 this.domHelper().append(this.element(), {tag:'div', cls:'oneTimePasswordReadOnlyMessage', htmlString:Clipperz.PM.Strings['oneTimePasswordReadOnlyMessage']});
72 } else {
73 var deferredResult;
74
75 deferredResult = new MochiKit.Async.Deferred();
76
77//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("OTP.MainComponent.render - 1: " + res); return res;});
78 deferredResult.addCallback(MochiKit.Base.bind(function() {
79 this.element().update("");
80 Clipperz.YUI.DomHelper.append(this.element(), {tag:'div', htmlString:Clipperz.PM.Strings['oneTimePasswordLoadingMessage']});
81 }, this));
82//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("OTP.MainComponent.render - 2: " + res); return res;});
83 deferredResult.addCallback(MochiKit.Base.method(this.user(), 'loadOneTimePasswords'));
84//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("OTP.MainComponent.render - 3: " + res); return res;});
85//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("OTP.MainComponent.render - 3.1: " + Clipperz.Base.serializeJSON(res.serializedData())); return res;});
86 deferredResult.addCallback(MochiKit.Base.bind(function(aResult) {
87 vartbodyElement;
88 varoneTimePasswordReferenceKeys;
89 var imageExtension;
90 var isThereAnyActiveOneTimePassword;
91
92 isThereAnyActiveOneTimePassword = false;
93
94 this.element().update("");
95 Clipperz.YUI.DomHelper.append(this.element(), {tag:'div', id:'oneTimePasswordList', children:[
96 {tag:'div', id:'oneTimePasswords_header', children:[
97 {tag:'table', width:'100%', children:[
98 {tag:'tbody', children:[
99 {tag:'tr', children:[
100 {tag:'td', width:'10%', children:[
101 {tag:'div', id:this.getId('createNewOneTimePasswordButton')}
102 ]},
103 {tag:'td', width:'40%', children:[
104 {tag:'div', id:this.getId('deleteSelectedOneTimePasswordButton')}
105 ]},
106 {tag:'td', width:'50%', align:'right', children:[
107 {tag:'div', id:this.getId('printOneTimePasswordButton')}
108 ]}
109 ]}
110 ]}
111 ]},
112 {tag:'div', children:[
113 {tag:'ul', children:[
114 {tag:'li', children:[
115 {tag:'span', htmlString:Clipperz.PM.Strings['oneTimePasswordSelectionLink_selectLabel']}
116 ]},
117 {tag:'li', children:[
118 {tag:'a', href:'#', id:this.getId('selectAllOneTimePasswords_link'), htmlString:Clipperz.PM.Strings['oneTimePasswordSelectionLink_all']}
119 ]},
120 {tag:'li', children:[
121 {tag:'a', href:'#', id:this.getId('selectNoneOneTimePasswords_link'), htmlString:Clipperz.PM.Strings['oneTimePasswordSelectionLink_none']}
122 ]},
123 {tag:'li', children:[
124 {tag:'a', href:'#', id:this.getId('selectUsedOneTimePasswords_link'), htmlString:Clipperz.PM.Strings['oneTimePasswordSelectionLink_used']}
125 ]},
126 {tag:'li', children:[
127 {tag:'a', href:'#', id:this.getId('selectUnusedOneTimePasswords_link'), htmlString:Clipperz.PM.Strings['oneTimePasswordSelectionLink_unused']}
128 ]}
129 ]}
130 ]}
131 ]},
132 {tag:'form', id:this.getId('oneTimePasswords_form'), children:[
133 {tag:'table', cls:'oneTimePassword', cellspacing:'0', cellpadding:'2', children:[
134 {tag:'tbody', id:this.getId('oneTimePasswords_tbody'), children:[
135 ]}
136 ]}
137 ]}
138 ]});
139
140 imageExtension = (Clipperz_IEisBroken == true) ? 'gif': 'png';
141
142 tbodyElement = this.getElement('oneTimePasswords_tbody');
143 oneTimePasswordReferenceKeys = MochiKit.Base.keys(this.user().oneTimePasswordManager().oneTimePasswords()).reverse();
144 c = oneTimePasswordReferenceKeys.length;
145 if (c>0) {
146 for (i=0; i<c; i++) {
147 var otpReference;
148 var currentOTP;
149 var loginSessionInfoConfig;
150
151 imageExtension = (Clipperz_IEisBroken == true) ? 'gif': 'png';
152
153 otpReference = oneTimePasswordReferenceKeys[i];
154 currentOTP = this.user().oneTimePasswordManager().oneTimePasswords()[otpReference];
155
156 switch (currentOTP.status()) {
157 case 'USED':
158 var loginSessionInfo;
159
160 loginSessionInfo = currentOTP.connectionInfo();
161 try {
162 var ip;
163
164 ip = (currentOTP.connectionInfo()['ip'].match(/^\d{1,3}(.\d{1,3}){3}$/)) ? currentOTP.connectionInfo()['ip'] : Clipperz.PM.Strings['unknown_ip'];
165
166 loginSessionInfoConfig = [
167 {tag:'div', cls:'oneTimePassword_usageDateDescription', children:[
168 {tag:'span', cls:'value', html:Clipperz.PM.Date.getElapsedTimeDescription(currentOTP.usageDate())}
169 ]},
170 {tag:'div', cls:'oneTimePassword_usageDetails', children:[
171 {tag:'img', cls:'flag', title:Clipperz.PM.Strings['countries'][ loginSessionInfo['country']], src:Clipperz.PM.Strings['icons_baseUrl'] + "/flags/" + loginSessionInfo['country'].toLowerCase() + "." + imageExtension, width:'32', height:'32'},
172 {tag:'img', cls:'browser', title:Clipperz.PM.Strings['browsers'][ loginSessionInfo['browser']], src:Clipperz.PM.Strings['icons_baseUrl'] + "/browsers/" + loginSessionInfo['browser'].toLowerCase() + "." + imageExtension, width:'32', height:'32'},
173 {tag:'img', cls:'operatingSystem', title:Clipperz.PM.Strings['operatingSystems'][loginSessionInfo['operatingSystem']], src:Clipperz.PM.Strings['icons_baseUrl'] + "/operatingSystems/" + loginSessionInfo['operatingSystem'].toLowerCase() + "." + imageExtension, width:'32', height:'32'}
174 ]},
175 {tag:'div', cls:'oneTimePassword_usageDate', html:Clipperz.PM.Date.formatDateWithTemplate(currentOTP.usageDate(), Clipperz.PM.Strings['fullDate_format'])},
176 {tag:'div', cls:'oneTimePassword_IP', children:[
177 {tag:'span', cls:'oneTimePassword_IPLabel', htmlString:Clipperz.PM.Strings['loginHistoryIPLabel']},
178 {tag:'span', cls:'oneTimePassword_IPValue', html:ip}
179 ]}
180 ];
181 } catch(exception) {
182 MochiKit.Logging.logWarning("an error occured while showing the One Time Password session details");
183 loginSessionInfoConfig = [];
184 }
185 break;
186 case 'DISABLED':
187 loginSessionInfoConfig = [
188 {tag:'span', cls:'disabledOneTimePassword', htmlString:Clipperz.PM.Strings['disabledOneTimePassword_warning']}
189 ];
190 break;
191 case 'ACTIVE':
192 default:
193 loginSessionInfoConfig = [];
194 break;
195 }
196
197
198 if (currentOTP.isExpired() == false) {
199 isThereAnyActiveOneTimePassword = true;
200 };
201
202
203 this.domHelper().append(tbodyElement, {tag:'tr', cls:(currentOTP.isExpired() ? 'oneTimePassword_used': 'oneTimePassword_new'), children:[
204 {tag:'td', valign:'top', children:[
205 {tag:'input', type:'checkbox', cls:'otpCheckbox', name:currentOTP.reference()}
206 ]},
207 {tag:'td', valign:'top', children:[
208 {tag:'span', cls:'oneTimePassword_value', html:currentOTP.password()}
209 ]},
210 {tag:'td', valign:'top', children:[
211 {tag:'div', cls:'oneTimePassword_usageStats', children:loginSessionInfoConfig}
212 ]}
213 ]});
214 }
215 } else {
216 this.domHelper().append(tbodyElement, {tag:'tr', children:[
217 {tag:'td', children:[
218 {tag:'div', cls:'oneTimePassword_noPasswordPresent', htmlString:Clipperz.PM.Strings['oneTimePasswordNoPasswordAvailable']}
219 ]}
220 ]});
221 }
222
223 new YAHOO.ext.Button(this.getDom('createNewOneTimePasswordButton'), {text:Clipperz.PM.Strings['createNewOTPButtonLabel'], handler:this.createNewOneTimePassword, scope:this});
224 this.setDeleteButton(new YAHOO.ext.Button(this.getDom('deleteSelectedOneTimePasswordButton'), {text:Clipperz.PM.Strings['deleteOTPButtonLabel'], handler:this.deleteSelectedOneTimePasswords, scope:this}));
225 this.setPrintButton(new YAHOO.ext.Button(this.getDom('printOneTimePasswordButton'), {text:Clipperz.PM.Strings['printOTPButtonLabel'], handler:this.printOneTimePasswords, scope:this}));
226
227 MochiKit.Signal.connect(this.getId('selectAllOneTimePasswords_link'),'onclick', this, 'selectAllOneTimePasswords');
228 MochiKit.Signal.connect(this.getId('selectNoneOneTimePasswords_link'),'onclick', this, 'selectNoneOneTimePasswords');
229 MochiKit.Signal.connect(this.getId('selectUsedOneTimePasswords_link'),'onclick', this, 'selectUsedOneTimePasswords');
230 MochiKit.Signal.connect(this.getId('selectUnusedOneTimePasswords_link'),'onclick', this, 'selectUnusedOneTimePasswords');
231
232 MochiKit.Base.map(MochiKit.Base.bind(function(aCheckbox) {
233 MochiKit.Signal.connect(aCheckbox, 'onclick', this, 'handleCheckboxClick');
234 }, this), this.oneTimePasswordCheckboxes());
235
236 this.updateDeleteButtonStatus();
237
238 if (isThereAnyActiveOneTimePassword == true) {
239 this.printButton().enable();
240 } else {
241 this.printButton().disable();
242 }
243
244 // Clipperz.NotificationCenter.register(null, 'oneTimePasswordAdded', this, 'render');
245 Clipperz.NotificationCenter.register(null, 'oneTimePassword_saveChanges_done', this, 'render');
246
247 }, this));
248//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("OTP.MainComponent.render - 4: " + res); return res;});
249
250 deferredResult.callback();
251 }
252 },
253
254 //-------------------------------------------------------------------------
255
256 'printOneTimePasswords': function() {
257 var newWindow;
258 var activeOneTimePasswords;
259
260//MochiKit.Logging.logDebug(">>> printAllData");
261 newWindow = window.open("", "");
262 newWindow.document.write(
263"<html>" +
264"<header>" +
265 "<title>Clipperz One Time Password</title>" +
266"<style>" +
267"div.oneTimePassword_print h2 {" +
268 "font-family: monospace;" +
269 "font-weight: normal;" +
270 "padding: 10px 20px;" +
271"}" +
272"</style>" +
273"" +
274"<!--[if IE]>" +
275"<style>" +
276"</style>" +
277"<![endif]-->" +
278"" +
279"</header>" +
280"<body>" +
281"</body>" +
282"</html>"
283 );
284
285 activeOneTimePasswords = MochiKit.Base.filter(function(aOneTimePassword) {return (aOneTimePassword.isExpired() == false)}, MochiKit.Base.values(this.user().oneTimePasswordManager().oneTimePasswords()).reverse());
286
287 MochiKit.Iter.forEach(activeOneTimePasswords, MochiKit.Base.partial(function(aWindow, aOneTimePassword) {
288 MochiKit.DOM.withWindow(aWindow, MochiKit.Base.partial(function(aOneTimePassword) {
289 var newBlock;
290
291 newBlock = MochiKit.DOM.DIV({'class': 'oneTimePassword_print'},
292 MochiKit.DOM.H2(null, aOneTimePassword.password())
293 );
294 MochiKit.DOM.appendChildNodes(MochiKit.DOM.currentDocument().body, newBlock);
295
296 }, aOneTimePassword));
297 }, newWindow));
298 },
299
300 //-------------------------------------------------------------------------
301
302 'generateRandomBase32OTPValue': function(aButton) {
303 var randomValue;
304 varresult;
305
306 randomValue = Clipperz.Crypto.PRNG.defaultRandomGenerator().getRandomBytes(160/8);
307 result = randomValue.toBase32String();
308 result = result.replace(/.{4}\B/g, '$&' + ' ');
309 result = result.replace(/(.{4} ){2}/g, '$&' + '- ');
310
311 return result;
312 },
313
314 //-------------------------------------------------------------------------
315
316 'createNewOneTimePassword': function() {
317 var newOneTimePassword;
318 var password;
319
320 password = this.generateRandomBase32OTPValue();
321 newOneTimePassword = new Clipperz.PM.DataModel.OneTimePassword({
322 user:this.user(),
323 password:password
324 });
325 this.user().oneTimePasswordManager().addOneTimePassword(newOneTimePassword);
326 Clipperz.PM.Components.MessageBox.showProgressPanel(MochiKit.Base.method(newOneTimePassword, 'saveChanges'), null, this.getDom('createNewOneTimePasswordButton'));
327 },
328
329 //-------------------------------------------------------------------------
330
331 'oneTimePasswordCheckboxes': function() {
332 return MochiKit.DOM.getElementsByTagAndClassName('input', 'otpCheckbox', this.getId('oneTimePasswords_tbody'));
333 },
334
335 'checkedOneTimePasswordCheckboxes': function() {
336 return MochiKit.Base.filter(function(aCheckbox) {return (aCheckbox.checked == true)}, this.oneTimePasswordCheckboxes());
337 },
338
339 //-------------------------------------------------------------------------
340
341 'selectAllOneTimePasswords': function(anEvent) {
342 var checkboxes;
343 var i,c;
344
345 anEvent.stop();
346 checkboxes = this.oneTimePasswordCheckboxes();
347 c = checkboxes.length;
348 for (i=0; i<c; i++) {
349 checkboxes[i].checked = true;
350 }
351
352 this.updateDeleteButtonStatus();
353 },
354
355 'selectNoneOneTimePasswords': function(anEvent) {
356 var checkboxes;
357 var i,c;
358
359 anEvent.stop();
360 checkboxes = this.oneTimePasswordCheckboxes();
361 c = checkboxes.length;
362 for (i=0; i<c; i++) {
363 checkboxes[i].checked = false;
364 }
365
366 this.updateDeleteButtonStatus();
367 },
368
369 'selectUsedOneTimePasswords': function(anEvent) {
370 var checkboxes;
371 var oneTimePasswordManager;
372 var i,c;
373
374 anEvent.stop();
375 oneTimePasswordManager = this.user().oneTimePasswordManager();
376 checkboxes = this.oneTimePasswordCheckboxes();
377 c = checkboxes.length;
378 for (i=0; i<c; i++) {
379 var matchingOneTimePassword;
380
381 matchingOneTimePassword = oneTimePasswordManager.oneTimePasswordWithReference(checkboxes[i].name);
382 checkboxes[i].checked = matchingOneTimePassword.isExpired();
383 }
384
385 this.updateDeleteButtonStatus();
386 },
387
388 'selectUnusedOneTimePasswords': function(anEvent) {
389 var checkboxes;
390 var oneTimePasswordManager;
391 var i,c;
392
393 anEvent.stop();
394 oneTimePasswordManager = this.user().oneTimePasswordManager();
395 checkboxes = this.oneTimePasswordCheckboxes();
396 c = checkboxes.length;
397 for (i=0; i<c; i++) {
398 var matchingOneTimePassword;
399
400 matchingOneTimePassword = oneTimePasswordManager.oneTimePasswordWithReference(checkboxes[i].name);
401 checkboxes[i].checked = !matchingOneTimePassword.isExpired();
402 }
403
404 this.updateDeleteButtonStatus();
405 },
406
407 //-------------------------------------------------------------------------
408
409 'handleCheckboxClick': function(anEvent) {
410 this.updateDeleteButtonStatus();
411 },
412
413 //-------------------------------------------------------------------------
414
415 'deleteSelectedOneTimePasswords': function() {
416 var deferredResult;
417 var otpToDelete;
418 var i,c;
419
420 otpToDelete = this.checkedOneTimePasswordCheckboxes();
421 c = otpToDelete.length;
422 for (i=0; i<c; i++) {
423//MochiKit.Logging.logDebug("otp to delete: " + otpToDelete[i].name);
424 this.user().oneTimePasswordManager().deleteOneTimePasswordWithReference(otpToDelete[i].name);
425 };
426
427 deferredResult = new MochiKit.Async.Deferred();
428//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("ActiveOTPPanel.deleteSelectedOneTimePasswords - 0: " + res); return res;});
429 deferredResult.addCallback(Clipperz.PM.Components.MessageBox.showProgressPanel, MochiKit.Base.method(this.user().oneTimePasswordManager(), 'saveChanges'), null, null);
430//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("ActiveOTPPanel.deleteSelectedOneTimePasswords - 1: " + res); return res;});
431 deferredResult.addCallback(MochiKit.Base.method(this, 'render'));
432//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("ActiveOTPPanel.deleteSelectedOneTimePasswords - 2: " + res); return res;});
433 deferredResult.callback();
434 },
435
436 //-------------------------------------------------------------------------
437
438 'user': function() {
439 return this._user;
440 },
441
442 //-------------------------------------------------------------------------
443
444 'shouldRender': function() {
445 return this._shouldRender;
446 },
447
448 'setShouldRender': function(aValue) {
449 this._shouldRender = aValue;
450 },
451
452 'tabSelectedHandler': function(anEvent) {
453 if ((this.shouldRender()) && (anEvent.source().selectedTab() == 'manageOTPTab')) {
454 this.render();
455 this.setShouldRender(false);
456 }
457 },
458
459 //-------------------------------------------------------------------------
460
461 'deleteButton': function() {
462 return this._deleteButton;
463 },
464
465 'setDeleteButton': function(aValue) {
466 this._deleteButton = aValue;
467 },
468
469 'updateDeleteButtonStatus': function() {
470 if (this.checkedOneTimePasswordCheckboxes().length > 0) {
471 this.deleteButton().enable();
472 } else {
473 this.deleteButton().disable();
474 }
475 },
476
477 //-------------------------------------------------------------------------
478
479 'printButton': function() {
480 return this._printButton;
481 },
482
483 'setPrintButton': function(aValue) {
484 this._printButton = aValue;
485 },
486
487 //-------------------------------------------------------------------------
488 __syntaxFix__: "syntax fix"
489});
490
diff --git a/frontend/beta/js/Clipperz/PM/Components/Panels/AccountPanel.js b/frontend/beta/js/Clipperz/PM/Components/Panels/AccountPanel.js
new file mode 100644
index 0000000..6b467d0
--- a/dev/null
+++ b/frontend/beta/js/Clipperz/PM/Components/Panels/AccountPanel.js
@@ -0,0 +1,784 @@
1/*
2
3Copyright 2008-2011 Clipperz Srl
4
5This file is part of Clipperz's Javascript Crypto Library.
6Javascript Crypto Library provides web developers with an extensive
7and efficient set of cryptographic functions. The library aims to
8obtain maximum execution speed while preserving modularity and
9reusability.
10For further information about its features and functionalities please
11refer to http://www.clipperz.com
12
13* Javascript Crypto Library is free software: you can redistribute
14 it and/or modify it under the terms of the GNU Affero General Public
15 License as published by the Free Software Foundation, either version
16 3 of the License, or (at your option) any later version.
17
18* Javascript Crypto Library is distributed in the hope that it will
19 be useful, but WITHOUT ANY WARRANTY; without even the implied
20 warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
21 See the GNU Affero General Public License for more details.
22
23* You should have received a copy of the GNU Affero General Public
24 License along with Javascript Crypto Library. If not, see
25 <http://www.gnu.org/licenses/>.
26
27*/
28
29if (typeof(Clipperz) == 'undefined') { Clipperz = {}; }
30if (typeof(Clipperz.PM) == 'undefined') { Clipperz.PM = {}; }
31if (typeof(Clipperz.PM.Components) == 'undefined') { Clipperz.PM.Components = {}; }
32if (typeof(Clipperz.PM.Components.Panels) == 'undefined') { Clipperz.PM.Components.Panels = {}; }
33
34//#############################################################################
35
36Clipperz.PM.Components.Panels.AccountPanel = function(anElement, args) {
37//MochiKit.Logging.logDebug(">>> new AccountPanel");
38 args = args || {};
39
40 Clipperz.PM.Components.Panels.AccountPanel.superclass.constructor.call(this, anElement, args);
41
42 Clipperz.NotificationCenter.register(null, 'setupDone', this, 'render');
43
44 this._shouldLoadLoginHistory = true;
45
46 //this.render();
47//MochiKit.Logging.logDebug("<<< new AccountPanel");
48
49 return this;
50}
51
52//=============================================================================
53
54YAHOO.extendX(Clipperz.PM.Components.Panels.AccountPanel, Clipperz.PM.Components.Panels.BasePanel, {
55
56 'toString': function() {
57 return "Clipperz.PM.Components.AccountPanel component";
58 },
59
60 //-------------------------------------------------------------------------
61
62 'render': function() {
63 var errorMessageActor;
64 varchangePasswordButton;
65 var deleteAccountButton;
66
67try {
68//MochiKit.Logging.logDebug(">>> AccountPanel.render");
69 Clipperz.NotificationCenter.unregister(this);
70 MochiKit.Signal.disconnectAllTo(this);
71
72 this.element().update("");
73 Clipperz.YUI.DomHelper.append(this.element().dom, {tag:'table', border:'0', cellspacing:'0', cellpadding:'0', children:[
74 {tag:'tbody', children:[
75 {tag:'tr', children:[
76 {tag:'td', valign:'top', width:'200', children:[
77 {tag:'ul', id:"accountSubMenu", cls:'subMenu', children:[
78 {tag:'li', id:'changePassphraseTab', htmlString:Clipperz.PM.Strings['changePasswordTabLabel']},
79 {tag:'li', id:'manageOTPTab', htmlString:Clipperz.PM.Strings['manageOTPTabLabel']},
80 {tag:'li', id:'accountPreferencesTab', htmlString:Clipperz.PM.Strings['accountPreferencesLabel']},
81 {tag:'li', id:'loginHistoryTab', htmlString:Clipperz.PM.Strings['accountLoginHistoryLabel']},
82 {tag:'li', id:'deleteAccountTab', htmlString:Clipperz.PM.Strings['deleteAccountTabLabel']}
83 // {tag:'li', id:'paidAccountTab'), htmlString:Clipperz.PM.Strings['paidAccountTabLabel']}
84 ]}
85 ]},
86 {tag:'td', valign:'top', children:[
87 {tag:'ul', cls:'clipperzTabPanels', children:[
88 {tag:'li', id:this.getId('changePassphrasePanel'), children:[
89 {tag:'div', cls:'clipperzSubPanel', children:[
90 {tag:'h5', htmlString:Clipperz.PM.Strings['changePasswordTabTitle']},
91 {tag:'div', cls:'panelBody', id:'changePassphraseBlock', children:[
92 {tag:'form', id:this.getId('changePassphraseForm'), children:[
93 {tag:'h5', cls:'errorMessage', id:this.getId('changePassphrase_errorMessage')},
94 {tag:'table', cls:'panelBody', children:[
95 {tag:'tr', children:[
96 {tag:'td', children:[
97 {tag:'span', cls:'formLabel', htmlString:Clipperz.PM.Strings['changePasswordFormUsernameLabel']}
98 ]},
99 {tag:'td', children:[
100 {tag:'input', type:'text', name:'username', id:this.getId('changePassphrase_username')}
101 ]}
102 ]},
103 {tag:'tr', children:[
104 {tag:'td', children:[
105 {tag:'span', cls:'formLabel', htmlString:Clipperz.PM.Strings['changePasswordFormOldPassphraseLabel']}
106 ]},
107 {tag:'td', children:[
108 {tag:'input', type:'password', name:'oldPassphrase', id:this.getId('changePassphrase_oldPassphrase')}
109 ]}
110 ]},
111 {tag:'tr', children:[
112 {tag:'td', children:[
113 {tag:'span', cls:'formLabel', htmlString:Clipperz.PM.Strings['changePasswordFormNewPassphraseLabel']}
114 ]},
115 {tag:'td', children:[
116 {tag:'input', type:'password', name:'newPassphrase', id:this.getId('changePassphrase_newPassphrase')}
117 ]}
118 ]},
119 {tag:'tr', children:[
120 {tag:'td', children:[
121 {tag:'span', cls:'formLabel', htmlString:Clipperz.PM.Strings['changePasswordFormRetypePassphraseLabel']}
122 ]},
123 {tag:'td', children:[
124 {tag:'input', type:'password', name:'renewPassphrase', id:this.getId('changePassphrase_renewPassphrase')}
125 ]}
126 ]},
127 {tag:'tr', children:[
128 {tag:'td', align:'right', children:[
129 {tag:'input', type:'checkbox', id:this.getId('changePassphrase_safetyCheck')}
130 ]},
131 {tag:'td', children:[
132 {tag:'span', htmlString:Clipperz.PM.Strings['changePasswordFormSafetyCheckboxLabel']}
133 ]}
134 ]}
135 ]},
136 {tag:'div', cls:'clipperzSubPanelButtonBox', children:[
137 {tag:'div', id:this.getId('changePassphraseButton')}
138 ]}
139 ]}
140 ]}
141 ]}
142 ]},
143 {tag:'li', id:this.getId('manageOTPPanel'), children:[
144 {tag:'div', cls:'clipperzSubPanel', children:[
145 {tag:'h5', htmlString:Clipperz.PM.Strings['manageOTPTabTitle']},
146 {tag:'div', cls:'panelDescription', htmlString:Clipperz.PM.Strings['manageOTPTabDescription']},
147 {tag:'div', id:'OTPComponent'}
148 ]}
149 ]},
150 {tag:'li', id:this.getId('accountPreferencesPanel'), children:[
151 {tag:'div', cls:'clipperzSubPanel', children:[
152 {tag:'h5', htmlString:Clipperz.PM.Strings['accountPreferencesTabTitle']},
153 {tag:'div', cls:'panelBody', id:this.getId('preferencesPanelBody')}
154 ]}
155 ]},
156 {tag:'li', id:this.getId('loginHistoryAccountPanel'), children:[
157 {tag:'div', cls:'clipperzSubPanel', children:[
158 {tag:'h5', htmlString:Clipperz.PM.Strings['loginHistoryTabTitle']},
159 {tag:'div', cls:'panelBody', id:'loginHistoryAccountBlock'}
160 ]}
161 ]},
162 {tag:'li', id:this.getId('deleteAccountPanel'), children:[
163 {tag:'div', cls:'clipperzSubPanel', children:[
164 {tag:'h5', htmlString:Clipperz.PM.Strings['deleteAccountTabTitle']},
165
166 {tag:'div', cls:'panelBody', id:'deleteAccountBlock', children:[
167 {tag:'form', id:this.getId('deleteAccountForm'), children:[
168 {tag:'h5', cls:'errorMessage', id:this.getId('deleteAccount_errorMessage')},
169 {tag:'table', cls:'panelBody', children:[
170 {tag:'tr', children:[
171 {tag:'td', children:[
172 {tag:'span', cls:'formLabel', htmlString:Clipperz.PM.Strings['deleteAccountFormUsernameLabel']}
173 ]},
174 {tag:'td', children:[
175 {tag:'input', type:'text', name:'username', id:this.getId('deleteAccount_username')}
176 ]}
177 ]},
178 {tag:'tr', children:[
179 {tag:'td', children:[
180 {tag:'span', cls:'formLabel', htmlString:Clipperz.PM.Strings['deleteAccountFormPassphraseLabel']}
181 ]},
182 {tag:'td', children:[
183 {tag:'input', type:'password', name:'passphrase', id:this.getId('deleteAccount_passphrase')}
184 ]}
185 ]},
186 {tag:'tr', children:[
187 {tag:'td', align:'right', children:[
188 {tag:'input', type:'checkbox', id:this.getId('deleteAccount_safetyCheck')}
189 ]},
190 {tag:'td', children:[
191 {tag:'span', htmlString:Clipperz.PM.Strings['deleteAccountFormSafetyCheckboxLabel']}
192 ]}
193 ]}
194 ]},
195 {tag:'div', cls:'clipperzSubPanelButtonBox', children:[
196 {tag:'div', id:this.getId('deleteAccountButton')}
197 ]}
198 ]}
199 ]}
200 ]}
201 ]}
202 /*
203 {tag:'li', id:this.getId('paidAccountPanel'), children:[
204 {tag:'div', cls:'clipperzSubPanel', children:[
205 {tag:'h5', htmlString:Clipperz.PM.Strings['upgradeAccountTabTitle']},
206 {tag:'div', htmlString:Clipperz.PM.Strings['comingSoon']}
207 ]}
208 ]}
209*/
210 ]}
211 ]}
212 ]}
213 ]}
214 ]});
215
216//MochiKit.Logging.logDebug("--- AccountPanel.render - 1");
217 MochiKit.Signal.connect(this.getId('changePassphraseForm'), 'onkeydown', this, 'onkeydown');
218 errorMessageActor = this.getActor('changePassphrase_errorMessage');
219 errorMessageActor.setVisibilityMode(YAHOO.ext.Element.DISPLAY);
220 errorMessageActor.update("---");
221 errorMessageActor.hide();
222 changePasswordButton = new YAHOO.ext.Button(this.getDom('changePassphraseButton'), {text:Clipperz.PM.Strings['changePasswordFormSubmitLabel'], handler:this.doChangePassphrase, scope:this});
223
224//MochiKit.Logging.logDebug("--- AccountPanel.render - 2");
225
226 MochiKit.Signal.connect(this.getId('deleteAccountForm'), 'onkeydown', this, 'onkeydown');
227 errorMessageActor = this.getActor('deleteAccount_errorMessage');
228 errorMessageActor.setVisibilityMode(YAHOO.ext.Element.DISPLAY);
229 errorMessageActor.update(Clipperz.PM.Strings['deleteAccountFormEmptyErrorMessage']);
230 errorMessageActor.hide();
231 deleteAccountButton = new YAHOO.ext.Button(this.getDom('deleteAccountButton'), {text:Clipperz.PM.Strings['deleteAccountFormSubmitLabel'], handler:this.doDeleteAccount, scope:this});
232//MochiKit.Logging.logDebug("--- AccountPanel.render - 5");
233
234 if (Clipperz.PM.Proxy.defaultProxy.isReadOnly()) {
235 this.getElement('changePassphraseForm').addClass('read-only');
236 // this.getElement('accountPreferencesForm').addClass('read-only');
237 this.getElement('deleteAccountForm').addClass('read-only');
238 changePasswordButton.disable();
239 deleteAccountButton.disable();
240 }
241//MochiKit.Logging.logDebug("--- AccountPanel.render - 6");
242
243 new Clipperz.PM.Components.PasswordEntropyDisplay(this.getElement('changePassphrase_oldPassphrase'));
244 new Clipperz.PM.Components.PasswordEntropyDisplay(this.getElement('changePassphrase_newPassphrase'));
245
246 new Clipperz.PM.Components.OTP.MainComponent(YAHOO.ext.Element.get('OTPComponent'), {user:this.user()});
247
248 this.tabPanelController().setUp();
249 Clipperz.NotificationCenter.register(null, 'tabSelected', this, 'tabSelectedHandler');
250 Clipperz.NotificationCenter.register(null, 'updatedPreferences', this, 'renderPreferences');
251 Clipperz.NotificationCenter.register(null, 'switchLanguage', this, 'switchLanguageHandler');
252//MochiKit.Logging.logDebug("<<< AccountPanel.render");
253
254} catch(exception) {
255 MochiKit.Logging.logError("### " + exception);
256 throw exception;
257}
258 },
259
260 //-------------------------------------------------------------------------
261
262 'tabPanelController': function() {
263 if (this._tabPanelController == null) {
264 var tabPanelControllerConfig;
265
266 tabPanelControllerConfig = {}
267 tabPanelControllerConfig['changePassphraseTab'] = this.getId('changePassphrasePanel');
268 tabPanelControllerConfig['manageOTPTab'] = this.getId('manageOTPPanel');
269 tabPanelControllerConfig['accountPreferencesTab'] = this.getId('accountPreferencesPanel');
270 tabPanelControllerConfig['loginHistoryTab'] = this.getId('loginHistoryAccountPanel');
271 tabPanelControllerConfig['deleteAccountTab'] = this.getId('deleteAccountPanel');
272 // tabPanelControllerConfig['paidAccountTab'] = this.getId('paidAccountPanel');
273
274 this._tabPanelController = new Clipperz.PM.Components.TabPanel.TabPanelController({
275 name:'accountTabPanel',
276 config:tabPanelControllerConfig,
277 selectedTab:'changePassphraseTab'
278 });
279 }
280
281 return this._tabPanelController;
282 },
283
284 //-------------------------------------------------------------------------
285
286 'doChangePassphrase': function() {
287 if (Clipperz.PM.Proxy.defaultProxy.isReadOnly() == false) {
288 varusername;
289 varoldPassphrase;
290 var newPassphrase;
291 var renewPassphrase;
292 var safetyCheck;
293 varareThereAnyErrors;
294 var errorMessageActor;
295
296 errorMessageActor = this.getActor('changePassphrase_errorMessage');
297
298 areThereAnyErrors = false;
299 username = this.getDom('changePassphrase_username').value;
300 oldPassphrase= this.getDom('changePassphrase_oldPassphrase').value;
301 newPassphrase= this.getDom('changePassphrase_newPassphrase').value;
302 renewPassphrase= this.getDom('changePassphrase_renewPassphrase').value;
303 safetyCheck = this.getDom('changePassphrase_safetyCheck').checked;
304
305 if (this.user().username() != username) {
306 this.showFormErrorMessageAnimation(errorMessageActor, Clipperz.PM.Strings['changePasswordFormWrongUsernameWarning']);
307 this.getElement('changePassphrase_username').focus().dom.select();
308 areThereAnyErrors = true;
309 } else if (this.user().passphrase() != oldPassphrase) {
310 this.showFormErrorMessageAnimation(errorMessageActor, Clipperz.PM.Strings['changePasswordFormWrongPassphraseWarning']);
311 this.getElement('changePassphrase_oldPassphrase').focus().dom.select();
312 areThereAnyErrors = true;
313 } else if (newPassphrase != renewPassphrase) {
314 this.showFormErrorMessageAnimation(errorMessageActor, Clipperz.PM.Strings['changePasswordFormWrongRetypePassphraseWarning']);
315 this.getElement('changePassphrase_renewPassphrase').focus().dom.select();
316 areThereAnyErrors = true;
317 } else if (safetyCheck != true) {
318 this.showFormErrorMessageAnimation(errorMessageActor, Clipperz.PM.Strings['changePasswordFormSafetyCheckWarning']);
319 this.getElement('changePassphrase_safetyCheck').focus();
320 areThereAnyErrors = true;
321 }
322
323 if (areThereAnyErrors == false) {
324 errorMessageActor.hide();
325 this.doChangePassphraseWithUsernameAndPassphrase(username, newPassphrase);
326 }
327 }
328 },
329
330 //-------------------------------------------------------------------------
331
332 'doChangePassphraseWithUsernameAndPassphrase': function(anUsername, aPassphrase) {
333 var deferredResult;
334
335//MochiKit.Logging.logDebug(">>> AccountPanel.doChangePassphraseWithUsernameAndPassphrase - this.user: " + this.user());
336 deferredResult = new MochiKit.Async.Deferred();
337//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug(" AccountPanel.doChangePassphraseWithUsernameAndPassphrase 1: " + res); return res;});
338 deferredResult.addCallback(MochiKit.Base.method(Clipperz.PM.Components.MessageBox(), 'deferredShow'),
339 {
340 title:Clipperz.PM.Strings['changePasswordFormProgressDialogTitle'],
341 text:Clipperz.PM.Strings['changePasswordFormProgressDialogEmptyText'],
342 width:240,
343 showProgressBar:true,
344 showCloseButton:false,
345 steps:4
346 },
347 this.getDom('changePassphraseButton')
348 );
349//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug(" AccountPanel.doChangePassphraseWithUsernameAndPassphrase 2: " + res); return res;});
350 deferredResult.addCallback(MochiKit.Base.method(this.user(), 'changeCredentials'), anUsername, aPassphrase);
351//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug(" AccountPanel.doChangePassphraseWithUsernameAndPassphrase 3: " + res); return res;});
352 deferredResult.addCallback(function() {
353 Clipperz.PM.Components.MessageBox().update({
354 title:Clipperz.PM.Strings['changePasswordFormProgressDialogConnectedMessageTitle'],
355 text:Clipperz.PM.Strings['changePasswordFormProgressDialogConnectedMessageText'],
356 /*showProgressBar:false,*/
357 step:'next'
358 });
359 });
360//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug(" AccountPanel.doChangePassphraseWithUsernameAndPassphrase 4: " + res); return res;});
361 deferredResult.addCallback(MochiKit.Async.wait, 1);
362//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug(" AccountPanel.doChangePassphraseWithUsernameAndPassphrase 5: " + res); return res;});
363 deferredResult.addCallback(function(anAccountPanel, res) {
364 Clipperz.PM.Components.MessageBox().hide(YAHOO.ext.Element.get('main'));
365
366 anAccountPanel.getDom('changePassphrase_username').value = "";
367 anAccountPanel.getDom('changePassphrase_oldPassphrase').value = "";
368 anAccountPanel.getElement('changePassphrase_oldPassphrase').focus();
369 anAccountPanel.getDom('changePassphrase_newPassphrase').value = "";
370 anAccountPanel.getElement('changePassphrase_newPassphrase').focus();
371 anAccountPanel.getDom('changePassphrase_renewPassphrase').value = "";
372 anAccountPanel.getDom('changePassphrase_safetyCheck').checked = false;
373
374 anAccountPanel.getElement('changePassphrase_username').focus();
375 return res;
376 }, this);
377//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug(" AccountPanel.doChangePassphraseWithUsernameAndPassphrase 6: " + res); return res;});
378 deferredResult.addErrback(function() {
379 Clipperz.PM.Components.MessageBox().update({
380 title:Clipperz.PM.Strings['changePasswordFormProgressDialogErrorMessageTitle'],
381 text:Clipperz.PM.Strings['changePasswordFormProgressDialogErrorMessageText'],
382 buttons:{'ok':"close"}
383 });
384 });
385//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug(" AccountPanel.doChangePassphraseWithUsernameAndPassphrase 7: " + res); return res;});
386 deferredResult.callback();
387
388//MochiKit.Logging.logDebug("<<< AccountPanel.doChangePassphraseWithUsernameAndPassphrase");
389 },
390
391 //-------------------------------------------------------------------------
392
393 'doDeleteAccount': function() {
394 if (Clipperz.PM.Proxy.defaultProxy.isReadOnly() == false) {
395 varusername;
396 varpassphrase;
397 var safetyCheck;
398 varareThereAnyErrors;
399 var errorMessageActor;
400
401 errorMessageActor = this.getActor('deleteAccount_errorMessage');
402
403 areThereAnyErrors = false;
404 username = this.getDom('deleteAccount_username').value;
405 passphrase= this.getDom('deleteAccount_passphrase').value;
406 safetyCheck = this.getDom('deleteAccount_safetyCheck').checked;
407
408 if (this.user().username() != username) {
409 this.showFormErrorMessageAnimation(errorMessageActor, Clipperz.PM.Strings['deleteAccountFormWrongUsernameWarning']);
410 this.getElement('deleteAccount_username').focus().dom.select();
411 areThereAnyErrors = true;
412 } else if (this.user().passphrase() != passphrase) {
413 this.showFormErrorMessageAnimation(errorMessageActor, Clipperz.PM.Strings['deleteAccountFormWrongPassphraseWarning']);
414 this.getElement('deleteAccount_passphrase').focus().dom.select();
415 areThereAnyErrors = true;
416 } else if (safetyCheck != true) {
417 this.showFormErrorMessageAnimation(errorMessageActor, Clipperz.PM.Strings['deleteAccountFormSafetyCheckWarning']);
418 this.getElement('deleteAccount_safetyCheck').focus();
419 areThereAnyErrors = true;
420 }
421
422 if (areThereAnyErrors == false) {
423 var deferred;
424
425 deferred = new MochiKit.Async.Deferred();
426 errorMessageActor.hide();
427
428 deferred.addCallback(function() {
429 var deferredResult;
430
431 //TODO: if the form is submitted with the return key, the confirmation dialog is skipped!?
432 deferredResult = new MochiKit.Async.Deferred();
433 Clipperz.PM.Components.MessageBox().deferredShow({
434 title:Clipperz.PM.Strings['accountPanelDeletingAccountPanelConfirmationTitle'],
435 text:Clipperz.PM.Strings['accountPanelDeleteAccountPanelConfirmationText'],
436 width:240,
437 showProgressBar:false,
438 showCloseButton:false,
439 buttons:{
440 'yes':Clipperz.PM.Strings['accountPanelDeleteAccountPanelConfirmButtonLabel'],
441 'no':Clipperz.PM.Strings['accountPanelDeleteAccountPanelDenyButtonLabel']
442 },
443 fn:MochiKit.Base.partial(function(aDeferred, aResult) {
444 if (aResult == 'yes') {
445 aDeferred.callback(aResult);
446 } else {
447 aDeferred.errback(aResult);
448 }
449 }, deferredResult)
450 });
451
452 return deferredResult;
453 });
454 deferred.addCallback(MochiKit.Base.method(Clipperz.PM.Components.MessageBox(), 'deferredShow'),
455 {
456 title:Clipperz.PM.Strings['accountPanelDeletingAccountPanelProgressTitle'],
457 text:Clipperz.PM.Strings['accountPanelDeletingAccountPanelProgressText'],
458 width:240,
459 showProgressBar:true,
460 showCloseButton:false
461 }
462 );
463 deferred.addCallback(MochiKit.Base.method(this.user(), 'deleteAccountAction'));
464 deferred.addCallback(Clipperz.PM.exit, 'accountDeleted.html');
465 deferred.addErrback(function(res) {
466 alert(res);
467 })
468 deferred.callback();
469 }
470 }
471 },
472
473 //-------------------------------------------------------------------------
474
475 'showFormErrorMessageAnimation': function(anActor, anErrorMessage, aCallback) {
476 anActor.update(anErrorMessage);
477 anActor.show(true);
478 anActor.play(aCallback);
479 },
480
481 //-------------------------------------------------------------------------
482
483 'onkeydown': function(anEvent) {
484//MochiKit.Logging.logDebug(">>> onkeydown - " + anEvent.src().id);
485 if (anEvent.key().code == 13) {
486 anEvent.stop();
487
488 if (anEvent.src() == this.getDom('changePassphraseForm')) {
489 this.doChangePassphrase();
490 } else if (anEvent.src() == this.getDom('deleteAccountForm')) {
491 this.doDeleteAccount();
492 } else {
493 }
494
495 }
496 },
497
498 //-------------------------------------------------------------------------
499
500 'selectSelectedLanguageOption': function() {
501 varuserSelectedLanguage;
502
503 userSelectedLanguage = this.user().preferences().preferredLanguage() || "default";
504 MochiKit.Base.filter(function(anOption) {return (anOption.value == userSelectedLanguage)}, this.getDom('languageSelector').childNodes)[0].selected = true;
505 },
506
507 //-------------------------------------------------------------------------
508
509 'doSaveUserPreferences': function() {
510 var selectedLanguage;
511 var showDonationReminderDialog;
512 // var disableUnsecureFaviconLoadingForIE;
513
514//MochiKit.Logging.logDebug(">>> AccountPanel.doSaveUserPreferences");
515 selectedLanguage = this.getDom('languageSelector').value;
516 if (selectedLanguage == "default") {
517 selectedLanguage = null;
518 }
519 this.user().preferences().setPreferredLanguage(selectedLanguage);
520
521 showDonationReminderDialog = this.getDom('showDonationReminderCheckbox').checked;
522 this.user().preferences().setShouldShowDonationPanel(showDonationReminderDialog);
523
524 // disableUnsecureFaviconLoadingForIE = this.getDom('disableFaviconForIECheckbox').checked;
525 // this.user().preferences().setDisableUnsecureFaviconLoadingForIE(disableUnsecureFaviconLoadingForIE);
526
527 this.user().preferences().saveChanges(this.getDom('saveUserPreferences'));
528 },
529
530 'doCancelUserPreferences': function() {
531 this.renderPreferences();
532 },
533
534 //'switchLanguage': function(anEvent) {
535 // Clipperz.PM.Strings.Languages.setSelectedLanguage(anEvent.src().value);
536 //},
537
538 //-------------------------------------------------------------------------
539
540 'renderLoginHistory': function() {
541 var element;
542
543//MochiKit.Logging.logDebug(">>> AccountPanel.renderLoginHistory");
544 element = YAHOO.ext.Element.get('loginHistoryAccountBlock');
545
546 if (Clipperz.PM.Proxy.defaultProxy.isReadOnly()) {
547 element.update("");
548 this.domHelper().append(element, {tag:'div', cls:'loginHistoryReadOnlyMessage', htmlString:Clipperz.PM.Strings['loginHistoryReadOnlyMessage']});
549 } else {
550 var deferredResult;
551
552 deferredResult = new MochiKit.Async.Deferred();
553 deferredResult.addCallback(MochiKit.Base.bind(function(anElement) {
554 anElement.update("");
555 Clipperz.YUI.DomHelper.append(anElement, {tag:'div', cls:'loadingMessage', htmlString:Clipperz.PM.Strings['loginHistoryLoadingMessage']});
556 }, this), element);
557 deferredResult.addCallback(MochiKit.Base.method(this.user(), 'loadLoginHistory'));
558 deferredResult.addCallback(MochiKit.Base.bind(function(anElement, aResult) {
559 var loginListItems;
560 var tBodyElement;
561 var imageExtension;
562 var now;
563 var i, c;
564
565 loginListItems = aResult;
566//MochiKit.Logging.logDebug("=== loginListItems: " + Clipperz.Base.serializeJSON(loginListItems));
567 imageExtension = (Clipperz_IEisBroken == true) ? 'gif': 'png';
568
569 now = new Date();
570 anElement.update("");
571 Clipperz.YUI.DomHelper.append(anElement, {tag:'div', cls:'panelDescription', htmlString:Clipperz.PM.Strings['loginHistoryLoadedMessage']});
572 Clipperz.YUI.DomHelper.append(anElement, {tag:'table', id:'loginHistoryTable', cellspacing:'0', cellpadding:'2', border:'0', children:[
573 {tag:'tbody', id:this.getId('loginHistoryTBody'), children:[]}
574 ]});
575 //# Clipperz.YUI.DomHelper.append(anElement, {tag:'div', id:'loginHistoryFooter', children:[
576 Clipperz.YUI.DomHelper.append(anElement, {tag:'div', cls:'clipperzSubPanelButtonBox', children:[
577 {tag:'div', id:this.getId('reloadHistoryButton')}
578 ]});
579
580 new YAHOO.ext.Button(this.getDom('reloadHistoryButton'), {text:Clipperz.PM.Strings['loginHistoryReloadButtonLabel'], handler:this.reloadHistory, scope:this});
581
582 tBodyElement = this.getElement('loginHistoryTBody');
583 c = loginListItems.length;
584 for (i=0; i<c; i++) {
585 var ip;
586 var date;
587 var mainText;
588
589 date = Clipperz.PM.Date.parseDateWithUTCFormat(loginListItems[i]['date']);
590
591 if (loginListItems[i]['isCurrent'] === true) {
592 mainText ={tag:'div', cls:'currentSession', htmlString:Clipperz.PM.Strings['loginHistoryCurrentSessionText']}
593 } else {
594 mainText = {tag:'div', cls:'elapsedTime', html:Clipperz.PM.Date.getElapsedTimeDescription(date)}
595 }
596
597 if (loginListItems[i]['connectionType'] == "ONE_TIME_PASSPHRASE") {
598 optionalInfo = [
599 {tag:'span', html:"OTP"}
600 ];
601 } else {
602 optionalInfo = [];
603 }
604
605 ip = (loginListItems[i]['ip'].match(/^\d{1,3}(.\d{1,3}){3}$/)) ? loginListItems[i]['ip'] : Clipperz.PM.Strings['unknown_ip'];
606 Clipperz.YUI.DomHelper.append(tBodyElement, {tag:'tr', children:[
607 {tag:'td', cls:'loginHistoryValues', valign:'top', children:[
608 mainText,
609 {tag:'div', cls:'fullDate', html:Clipperz.PM.Date.formatDateWithTemplate(date, Clipperz.PM.Strings['fullDate_format'])},
610 {tag:'div', cls:'loginHistoryIP', children:[
611 {tag:'span', cls:'loginHistoryIPLabel', htmlString:Clipperz.PM.Strings['loginHistoryIPLabel']},
612 {tag:'span', cls:'loginHistoryIPValue', html:ip}
613 ]}
614 ]},
615 {tag:'td', cls:'loginHistoryCountry', valign:'top', children:optionalInfo},
616 {tag:'td', cls:'loginHistoryCountry', valign:'top', align:'center', children:[
617 {tag:'img', title:Clipperz.PM.Strings['countries'][loginListItems[i]['country']], cls:'flag', src:Clipperz.PM.Strings['icons_baseUrl'] + "/flags/" + loginListItems[i]['country'].toLowerCase() + "." + imageExtension, width:'32', height:'32'}
618 // {tag:'span', cls:'label', htmlString:Clipperz.PM.Strings['countries'][loginListItems[i]['country']]}
619 ]},
620 {tag:'td', cls:'loginHistoryBrowser', valign:'top', align:'center', children:[
621 {tag:'img', title:Clipperz.PM.Strings['browsers'][loginListItems[i]['browser']], cls:'browser', src:Clipperz.PM.Strings['icons_baseUrl'] + "/browsers/" + loginListItems[i]['browser'].toLowerCase() + "." + imageExtension, width:'32', height:'32'}
622 // {tag:'span', cls:'label', htmlString:Clipperz.PM.Strings['browsers'][loginListItems[i]['browser']]}
623 ]},
624 {tag:'td', cls:'loginHistoryOperatingSystem', valign:'top', align:'center', children:[
625 {tag:'img', title:Clipperz.PM.Strings['operatingSystems'][loginListItems[i]['operatingSystem']], cls:'operatingSystem', src:Clipperz.PM.Strings['icons_baseUrl'] + "/operatingSystems/" + loginListItems[i]['operatingSystem'].toLowerCase() + "." + imageExtension, width:'32', height:'32'}
626 // {tag:'span', cls:'label', htmlString:Clipperz.PM.Strings['operatingSystems'][loginListItems[i]['operatingSystem']]}
627 ]}
628 ]});
629 }
630
631 Clipperz.Style.applyZebraStylesToTable('loginHistoryTable');
632 }, this), element);
633
634 deferredResult.callback();
635 }
636//MochiKit.Logging.logDebug("<<< AccountPanel.renderLoginHistory");
637 },
638
639 //-------------------------------------------------------------------------
640
641 'renderPreferences': function() {
642 var saveUserPreferencesButton;
643 var cancelUserPreferencesButton;
644 var preferencedPanelBodyElement;
645
646 preferencedPanelBodyElement = this.getElement('preferencesPanelBody');
647
648 preferencedPanelBodyElement.update("");
649 Clipperz.YUI.DomHelper.append(preferencedPanelBodyElement,
650 {tag:'form', id:this.getId('accountPreferencesForm'), children:[
651 {tag:'table', cls:'panelBody', children:[
652 {tag:'tr', cls:'openPreferenceBlock', children:[
653 {tag:'td', children:[
654 {tag:'div', cls:'preferenceBlockTitle', htmlString:Clipperz.PM.Strings['accountPreferencesLanguageTitle']},
655 {tag:'div', cls:'panelDescription', htmlString:Clipperz.PM.Strings['accountPreferencesLanguageDescription']},
656 {tag:'div', cls:'panelDescription', children:[
657 {tag:'select',
658 id:this.getId('languageSelector'),
659 children:MochiKit.Base.concat([{tag:'option', value:"default", html:"---"}], Clipperz.PM.Strings['loginPanelSwitchLanguageSelectOptions'])
660 }
661 ]}
662 ]}
663 ]},
664 {tag:'tr', cls:'openPreferenceBlock', children:[
665 {tag:'td', children:[
666 {tag:'div', cls:'preferenceBlockTitle', htmlString:Clipperz.PM.Strings['showDonationReminderPanelTitle']},
667 {tag:'table', cellpadding:'0', cellspacing:'0', children:[
668 {tag:'tbody', children:[
669 {tag:'tr', children:[
670 {tag:'td', valign:'top', children:[
671 {tag:'div', cls:'panelDescription', children:[
672 {tag:'input', type:'checkbox', id:this.getId('showDonationReminderCheckbox')}
673 ]}
674 ]},
675 {tag:'td', valign:'top', children:[
676 {tag:'div', cls:'panelDescription', htmlString:Clipperz.PM.Strings['showDonationReminderPanelDescription']}
677 ]}
678 ]}
679 ]}
680 ]}
681 ]}
682 ]}//,
683/*
684 {tag:'tr', cls:'openPreferenceBlock', children:[
685 {tag:'td', children:[
686 {tag:'div', cls:'preferenceBlockTitle', htmlString:Clipperz.PM.Strings['disableFaviconForIETitle']},
687 {tag:'table', cellpadding:'0', cellspacing:'0', children:[
688 {tag:'tbody', children:[
689 {tag:'tr', children:[
690 {tag:'td', valign:'top', children:[
691 {tag:'div', cls:'panelDescription', children:[
692 {tag:'input', type:'checkbox', id:this.getId('disableFaviconForIECheckbox')}
693 ]}
694 ]},
695 {tag:'td', valign:'top', children:[
696 {tag:'div', cls:'panelDescription', children:Clipperz.PM.Strings['disableFaviconForIEDescriptionConfig']}
697 ]}
698 ]}
699 ]}
700 ]}
701 ]}
702 ]},
703*/
704 // {tag:'tr', cls:'openPreferenceBlock', children:[
705 // {tag:'td', children:[
706 // {tag:'div', cls:'preferenceBlockTitle', htmlString:Clipperz.PM.Strings['accountPreferencesInterfaceTitle']},
707 // {tag:'div', cls:'panelDescription', children:Clipperz.PM.Strings['accountPreferencesInterfaceDescriptionConfig']}
708 // ]}
709 // ]}
710 ]},
711 {tag:'div', cls:'clipperzSubPanelButtonBox', children:[
712 {tag:'table', border:'0', cellspacing:'0', cellpadding:'0', children:[
713 {tag:'tbody', children:[
714 {tag:'tr', children:[
715 {tag:'td', width:'100', align:'right', cls:'newRecordPanelButtonTD', children:[
716 {tag:'div', id:this.getId('saveUserPreferences')}
717 ]},
718 {tag:'td', width:'10', html:"&nbsp;"},
719 {tag:'td', cls:'newRecordPanelButtonTD', children:[
720 {tag:'div', id:this.getId('cancelUserPreferences')}
721 ]}
722 ]}
723 ]}
724 ]}
725 ]}
726 ]}
727 );
728
729 this.selectSelectedLanguageOption();
730 if (this.user().preferences().shouldShowDonationPanel()) {
731 this.getDom('showDonationReminderCheckbox').checked = true;
732 }
733 // if (this.user().preferences().disableUnsecureFaviconLoadingForIE()) {
734 // this.getDom('disableFaviconForIECheckbox').checked = true;
735 // }
736
737//MochiKit.Logging.logDebug("--- AccountPanel.render - 3");
738 //# saveUserPreferencesButton = new YAHOO.ext.Button(this.getDom('saveUserPreferences'), {text:Clipperz.PM.Strings['saveUserPreferencesFormSubmitLabel'], handler:this.doSaveUserPreferences, scope:this});
739 saveUserPreferencesButton = new YAHOO.ext.Button(this.getDom('saveUserPreferences'), {text:'-----------------', handler:this.doSaveUserPreferences, scope:this});
740 saveUserPreferencesButton.setText(Clipperz.PM.Strings['saveUserPreferencesFormSubmitLabel']);
741 //# cancelUserPreferencesButton = new YAHOO.ext.Button(this.getDom('cancelUserPreferences'), {text:Clipperz.PM.Strings['cancelUserPreferencesFormSubmitLabel'], handler:this.doCancelUserPreferences, scope:this});
742 cancelUserPreferencesButton = new YAHOO.ext.Button(this.getDom('cancelUserPreferences'), {text:'-----------------', handler:this.doCancelUserPreferences, scope:this});
743 cancelUserPreferencesButton.setText(Clipperz.PM.Strings['cancelUserPreferencesFormSubmitLabel']);
744//MochiKit.Logging.logDebug("--- AccountPanel.render - 4");
745
746 if (Clipperz.PM.Proxy.defaultProxy.isReadOnly()) {
747 this.getElement('accountPreferencesForm').addClass('read-only');
748 saveUserPreferencesButton.disable();
749 cancelUserPreferencesButton.disable();
750 }
751
752 },
753
754 //-------------------------------------------------------------------------
755
756 'reloadHistory': function() {
757 this.setShouldLoadLoginHistory(true);
758 this.renderLoginHistory();
759 },
760
761 'shouldLoadLoginHistory': function() {
762 return this._shouldLoadLoginHistory;
763 },
764
765 'setShouldLoadLoginHistory': function(aValue) {
766 this._shouldLoadLoginHistory = aValue;
767 },
768
769 'tabSelectedHandler': function(anEvent) {
770 if (anEvent.parameters() == 'accountPreferencesTab') {
771 this.renderPreferences();
772 }
773
774 if ((this.shouldLoadLoginHistory()) && (anEvent.parameters() == 'loginHistoryTab')) {
775 this.renderLoginHistory();
776 this.setShouldLoadLoginHistory(false);
777 }
778 },
779
780 //-------------------------------------------------------------------------
781 __syntaxFix__: "syntax fix"
782
783});
784
diff --git a/frontend/beta/js/Clipperz/PM/Components/Panels/BasePanel.js b/frontend/beta/js/Clipperz/PM/Components/Panels/BasePanel.js
new file mode 100644
index 0000000..bf60f45
--- a/dev/null
+++ b/frontend/beta/js/Clipperz/PM/Components/Panels/BasePanel.js
@@ -0,0 +1,96 @@
1/*
2
3Copyright 2008-2011 Clipperz Srl
4
5This file is part of Clipperz's Javascript Crypto Library.
6Javascript Crypto Library provides web developers with an extensive
7and efficient set of cryptographic functions. The library aims to
8obtain maximum execution speed while preserving modularity and
9reusability.
10For further information about its features and functionalities please
11refer to http://www.clipperz.com
12
13* Javascript Crypto Library is free software: you can redistribute
14 it and/or modify it under the terms of the GNU Affero General Public
15 License as published by the Free Software Foundation, either version
16 3 of the License, or (at your option) any later version.
17
18* Javascript Crypto Library is distributed in the hope that it will
19 be useful, but WITHOUT ANY WARRANTY; without even the implied
20 warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
21 See the GNU Affero General Public License for more details.
22
23* You should have received a copy of the GNU Affero General Public
24 License along with Javascript Crypto Library. If not, see
25 <http://www.gnu.org/licenses/>.
26
27*/
28
29if (typeof(Clipperz) == 'undefined') { Clipperz = {}; }
30if (typeof(Clipperz.PM) == 'undefined') { Clipperz.PM = {}; }
31if (typeof(Clipperz.PM.Components) == 'undefined') { Clipperz.PM.Components = {}; }
32if (typeof(Clipperz.PM.Components.Panels) == 'undefined') { Clipperz.PM.Components.Panels = {}; }
33
34//var _Clipperz_PM_Components_Panels_base_id_ = 0;
35
36//#############################################################################
37
38Clipperz.PM.Components.Panels.BasePanel = function(anElement, args) {
39 args = args || {};
40
41 Clipperz.PM.Components.Panels.BasePanel.superclass.constructor.call(this, anElement, args);
42
43 this._user = args.user || null;
44 this._delegate = args.delegate || null;
45 this._tabPanelController = null;
46 //Clipperz.NotificationCenter.register(null, 'switchLanguage', this, 'switchLanguageHandler');
47
48 //this._ids = {};
49
50 return this;
51}
52
53//=============================================================================
54
55YAHOO.extendX(Clipperz.PM.Components.Panels.BasePanel, Clipperz.PM.Components.BaseComponent, {
56
57 'toString': function() {
58 return "Clipperz.PM.Components.Panels.BasePanel component";
59 },
60
61 //-------------------------------------------------------------------------
62
63 'user': function() {
64 return this._user;
65 },
66
67 'setUser': function(aValue) {
68 this._user = aValue;
69 },
70
71 //-------------------------------------------------------------------------
72
73 'delegate': function() {
74 return this._delegate;
75 },
76
77 'setDelegate': function(aValue) {
78 this._delegate = aValue;
79 },
80
81 //-------------------------------------------------------------------------
82
83 'tabPanelController': function() {
84 return this._tabPanelController;
85 },
86
87 'switchLanguageHandler': function() {
88//MochiKit.Logging.logDebug(">>> BasePanel.switchLanguageHandler [" + this.toString() + "]");
89 this.render();
90//MochiKit.Logging.logDebug("<<< BasePanel.switchLanguageHandler [" + this.toString() + "]");
91 },
92
93 //-------------------------------------------------------------------------
94 __syntaxFix__: "syntax fix"
95
96});
diff --git a/frontend/beta/js/Clipperz/PM/Components/Panels/ContactsPanel.js b/frontend/beta/js/Clipperz/PM/Components/Panels/ContactsPanel.js
new file mode 100644
index 0000000..f0eb9c8
--- a/dev/null
+++ b/frontend/beta/js/Clipperz/PM/Components/Panels/ContactsPanel.js
@@ -0,0 +1,105 @@
1/*
2
3Copyright 2008-2011 Clipperz Srl
4
5This file is part of Clipperz's Javascript Crypto Library.
6Javascript Crypto Library provides web developers with an extensive
7and efficient set of cryptographic functions. The library aims to
8obtain maximum execution speed while preserving modularity and
9reusability.
10For further information about its features and functionalities please
11refer to http://www.clipperz.com
12
13* Javascript Crypto Library is free software: you can redistribute
14 it and/or modify it under the terms of the GNU Affero General Public
15 License as published by the Free Software Foundation, either version
16 3 of the License, or (at your option) any later version.
17
18* Javascript Crypto Library is distributed in the hope that it will
19 be useful, but WITHOUT ANY WARRANTY; without even the implied
20 warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
21 See the GNU Affero General Public License for more details.
22
23* You should have received a copy of the GNU Affero General Public
24 License along with Javascript Crypto Library. If not, see
25 <http://www.gnu.org/licenses/>.
26
27*/
28
29if (typeof(Clipperz) == 'undefined') { Clipperz = {}; }
30if (typeof(Clipperz.PM) == 'undefined') { Clipperz.PM = {}; }
31if (typeof(Clipperz.PM.Components) == 'undefined') { Clipperz.PM.Components = {}; }
32if (typeof(Clipperz.PM.Components.Panels) == 'undefined') { Clipperz.PM.Components.Panels = {}; }
33
34//#############################################################################
35
36Clipperz.PM.Components.Panels.ContactsPanel = function(anElement, args) {
37 args = args || {};
38
39 Clipperz.PM.Components.Panels.ContactsPanel.superclass.constructor.call(this, anElement, args);
40
41 this.render();
42
43 return this;
44}
45
46//=============================================================================
47
48YAHOO.extendX(Clipperz.PM.Components.Panels.ContactsPanel, Clipperz.PM.Components.Panels.BasePanel, {
49
50 'toString': function() {
51 return "Clipperz.PM.Components.ContactsPanel component";
52 },
53
54 //-------------------------------------------------------------------------
55
56 'render': function() {
57 // var tabPanelControllerConfig;
58
59 Clipperz.YUI.DomHelper.append(this.element().dom, {tag:'table', border:'0', cellspacing:'0', cellpadding:'0', children:[
60 {tag:'tbody', children:[
61 {tag:'tr', children:[
62 {tag:'td', valign:'top', width:'200', children:[
63 {tag:'ul', id:"dataSubMenu", cls:'subMenu', children:[
64 {tag:'li', id:this.getId('contacts'), htmlString:Clipperz.PM.Strings['contactsTabLabel']},
65 ]}
66 ]},
67 {tag:'td', valign:'top', children:[
68 {tag:'ul', cls:'clipperzTabPanels', children:[
69 {tag:'li', id:this.getId('contactsPanel'), children:[
70 {tag:'div', cls:'clipperzSubPanel', children:[
71 {tag:'h5', htmlString:Clipperz.PM.Strings['contactsTabTitle']},
72 {tag:'div', htmlString:Clipperz.PM.Strings['comingSoon']}
73 ]}
74 ]}
75 ]}
76 ]}
77 ]}
78 ]}
79 ]});
80
81 // tabPanelControllerConfig = {}
82 // tabPanelControllerConfig[this.getId('contacts')] = this.getId('contactsPanel');
83 // new Clipperz.PM.Components.TabPanel.TabPanelController({ config:tabPanelControllerConfig, selectedTab:this.getId('contacts') });
84 this.tabPanelController().setUp();
85 },
86
87 //-------------------------------------------------------------------------
88
89 'tabPanelController': function() {
90 if (this._tabPanelController == null) {
91 var tabPanelControllerConfig;
92
93 tabPanelControllerConfig = {}
94 tabPanelControllerConfig[this.getId('contacts')] = this.getId('contactsPanel');
95 this._tabPanelController = new Clipperz.PM.Components.TabPanel.TabPanelController({ config:tabPanelControllerConfig, selectedTab:this.getId('contacts') });
96 }
97
98 return this._tabPanelController;
99 },
100
101 //-------------------------------------------------------------------------
102 __syntaxFix__: "syntax fix"
103
104});
105
diff --git a/frontend/beta/js/Clipperz/PM/Components/Panels/DataPanel.js b/frontend/beta/js/Clipperz/PM/Components/Panels/DataPanel.js
new file mode 100644
index 0000000..759903f
--- a/dev/null
+++ b/frontend/beta/js/Clipperz/PM/Components/Panels/DataPanel.js
@@ -0,0 +1,486 @@
1/*
2
3Copyright 2008-2011 Clipperz Srl
4
5This file is part of Clipperz's Javascript Crypto Library.
6Javascript Crypto Library provides web developers with an extensive
7and efficient set of cryptographic functions. The library aims to
8obtain maximum execution speed while preserving modularity and
9reusability.
10For further information about its features and functionalities please
11refer to http://www.clipperz.com
12
13* Javascript Crypto Library is free software: you can redistribute
14 it and/or modify it under the terms of the GNU Affero General Public
15 License as published by the Free Software Foundation, either version
16 3 of the License, or (at your option) any later version.
17
18* Javascript Crypto Library is distributed in the hope that it will
19 be useful, but WITHOUT ANY WARRANTY; without even the implied
20 warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
21 See the GNU Affero General Public License for more details.
22
23* You should have received a copy of the GNU Affero General Public
24 License along with Javascript Crypto Library. If not, see
25 <http://www.gnu.org/licenses/>.
26
27*/
28
29if (typeof(Clipperz) == 'undefined') { Clipperz = {}; }
30if (typeof(Clipperz.PM) == 'undefined') { Clipperz.PM = {}; }
31if (typeof(Clipperz.PM.Components) == 'undefined') { Clipperz.PM.Components = {}; }
32if (typeof(Clipperz.PM.Components.Panels) == 'undefined') { Clipperz.PM.Components.Panels = {}; }
33
34//#############################################################################
35
36Clipperz.PM.Components.Panels.DataPanel = function(anElement, args) {
37 args = args || {};
38
39 Clipperz.PM.Components.Panels.DataPanel.superclass.constructor.call(this, anElement, args);
40
41 this._progressWidth = 400;
42
43
44 this.render();
45
46 return this;
47}
48
49//=============================================================================
50
51YAHOO.extendX(Clipperz.PM.Components.Panels.DataPanel, Clipperz.PM.Components.Panels.BasePanel, {
52
53 'toString': function() {
54 return "Clipperz.PM.Components.DataPanel component";
55 },
56
57 //-------------------------------------------------------------------------
58
59 'render': function() {
60 MochiKit.Signal.disconnectAllTo(this);
61 Clipperz.NotificationCenter.unregister(this);
62 this.element().update("");
63
64 Clipperz.YUI.DomHelper.append(this.element().dom, {tag:'table', border:'0', cellspacing:'0', cellpadding:'0', children:[
65 {tag:'tbody', children:[
66 {tag:'tr', children:[
67 {tag:'td', valign:'top', width:'200', children:[
68 {tag:'ul', id:"dataSubMenu", cls:'subMenu', children:[
69 {tag:'li', id:'offlineCopyTab', htmlString:Clipperz.PM.Strings['offlineCopyTabLabel']},
70 {tag:'li', id:'sharingTab', htmlString:Clipperz.PM.Strings['sharingTabLabel']},
71 {tag:'li', id:'importTab', htmlString:Clipperz.PM.Strings['importTabLabel']},
72 {tag:'li', id:'printingTab', htmlString:Clipperz.PM.Strings['printingTabLabel']}
73 ]}
74 ]},
75 {tag:'td', valign:'top', children:[
76 {tag:'ul', cls:'clipperzTabPanels', children:[
77 {tag:'li', id:this.getId('offlineCopyPanel'), children:[
78 {tag:'div', cls:'clipperzSubPanel', children:[
79 {tag:'h5', htmlString:Clipperz.PM.Strings['offlineCopyTabTitle']},
80 {tag:'div', cls:'panelDescription', htmlString:Clipperz.PM.Strings['offlineCopyTabDescription']},
81 {tag:'div', id:this.getId('offlineCopyLinkBox'), children:[
82 {tag:'a', id:'offlineCopyLink', href:'#', htmlString:Clipperz.PM.Strings['offlineCopyDownloadLinkLabel']}
83 ]},
84 {tag:'div', id:this.getId('offlineCopyLinkBox_read-only'), children:[
85 {tag:'span', cls:'read-only', htmlString:Clipperz.PM.Strings['offlineCopyDownloadLinkLabel']}
86 ]}
87 ]}
88 ]},
89 {tag:'li', id:this.getId('sharingPanel'), children:[
90 {tag:'div', cls:'clipperzSubPanel', children:[
91 {tag:'h5', htmlString:Clipperz.PM.Strings['sharingTabTitle']},
92 {tag:'div', cls:'panelDescription', htmlString:Clipperz.PM.Strings['sharingTabDescription']}
93 ]}
94 ]},
95 {tag:'li', id:this.getId('importPanel'), children:[
96 {tag:'div', cls:'clipperzSubPanel', children:[
97 {tag:'div', id:this.getId('importPanelMainComponent')}
98 ]}
99 ]},
100 {tag:'li', id:this.getId('printingPanel'), children:[
101 {tag:'div', cls:'clipperzSubPanel', children:[
102 {tag:'h5', htmlString:Clipperz.PM.Strings['printingTabTitle']},
103
104 {tag:'div', cls:'panelDescription', htmlString:Clipperz.PM.Strings['printingTabDescription']},
105 {tag:'div', id:this.getId('printingLinkBox'), children:[
106 {tag:'a', id:'printingLink', href:'#', htmlString:Clipperz.PM.Strings['printingLinkLabel']}
107 ]},
108
109 {tag:'hr'},
110
111 {tag:'div', cls:'panelDescription', htmlString:Clipperz.PM.Strings['exportTabDescription']},
112 {tag:'div', id:this.getId('exportLinkBox'), children:[
113 {tag:'a', id:'exportLink', href:'#', htmlString:Clipperz.PM.Strings['exportLinkLabel']}
114 ]}
115 ]}
116 ]}
117 ]}
118 ]}
119 ]}
120 ]}
121 ]});
122
123 this.tabPanelController().setUp();
124
125 if (Clipperz.PM.Proxy.defaultProxy.isReadOnly()) {
126 this.getElement('offlineCopyLinkBox').setVisibilityMode(YAHOO.ext.Element.DISPLAY).hide();
127 } else {
128 this.getElement('offlineCopyLinkBox_read-only').setVisibilityMode(YAHOO.ext.Element.DISPLAY).hide();
129 MochiKit.Signal.connect('offlineCopyLink', 'onclick', this, 'downloadOfflineCopy');
130 }
131
132 new Clipperz.PM.Components.Import.MainComponent(this.getElement('importPanelMainComponent'), {user:this.user()});
133
134 MochiKit.Signal.connect('printingLink', 'onclick', this, 'printAllData');
135 MochiKit.Signal.connect('exportLink', 'onclick', this, 'exportAllData');
136
137 Clipperz.NotificationCenter.register(null, 'switchLanguage', this, 'switchLanguageHandler');
138 },
139
140 //-------------------------------------------------------------------------
141
142 'tabPanelController': function() {
143 if (this._tabPanelController == null) {
144 var tabPanelControllerConfig;
145
146 tabPanelControllerConfig = {}
147 tabPanelControllerConfig['offlineCopyTab'] = this.getId('offlineCopyPanel');
148 tabPanelControllerConfig['sharingTab'] = this.getId('sharingPanel');
149 tabPanelControllerConfig['importTab'] = this.getId('importPanel');
150 tabPanelControllerConfig['printingTab'] = this.getId('printingPanel');
151 this._tabPanelController = new Clipperz.PM.Components.TabPanel.TabPanelController({
152 name: 'dataTabPanel',
153 config:tabPanelControllerConfig,
154 selectedTab:'offlineCopyTab'
155 });
156 }
157
158 return this._tabPanelController;
159 },
160
161 //-------------------------------------------------------------------------
162
163 'downloadOfflineCopy': function(anEvent) {
164 var downloadHref;
165
166 downloadHref = window.location.href.replace(/\/[^\/]*$/,'') + Clipperz_dumpUrl;
167
168 if (Clipperz_IEisBroken == true) {
169 window.open(downloadHref, "");
170 } else {
171 vardeferredResult;
172 var newWindow;
173
174 newWindow = window.open("", "");
175
176 anEvent.preventDefault();
177
178 deferredResult = new MochiKit.Async.Deferred();
179 deferredResult.addCallback(MochiKit.Base.method(this.user().connection(), 'message'), 'echo', {'echo':"echo"});
180 deferredResult.addCallback(function(aWindow) {
181 aWindow.location.href = downloadHref;
182 }, newWindow);
183 deferredResult.callback();
184 }
185 },
186
187 //-------------------------------------------------------------------------
188
189 'compareRecords': function(a, b) {
190 return MochiKit.Base.compare(a.label().toLowerCase(), b.label().toLowerCase());
191 },
192
193 'logo': function() {
194 var result;
195
196 if (Clipperz_IEisBroken == true) {
197 if (Clipperz.PM.Proxy.defaultProxy.isReadOnly()) {
198 result = "<span><span class=\"clipperzLogoSpan\">clipper</span><span class=\"clipperzLoggoZSpan\">z</span></span>";
199 } else {
200 result = "<img src=\"./images/exportLogo.png\" />";
201 }
202 } else {
203 result = "<img src=\"data:image/png;charset=utf-8;base64,iVBORw0KGgoAAAANSUhEUgAAANYAAABOCAIAAADTtH9XAAANIWlDQ1BJQ0MgUHJvZmlsZQAAeJyV13k0lG8bB/BrFsYyZhhjDyO77LKHLJFItmwp2bdhJiZRypIUIkso2iiSFC0kEtWPLCHJkq2oyJI9kmXeP6R6f+f9ve95rz+ecz3385xz389zzud7nxsAr+FKpZKRABAQSAuyNjEgOTg6kTBdgAJewAEzaLi6B1P1LS3N4R9roRMQAADtcq5UKvmf3/uPhQtycHQCQMgCANF7vd8OAES39d4WAIhHaFQaAMIHAIjuPq4eAIhwAJANsrU2BEAUAADOe70vBwCc23pfDwC4EHdvGgCiG4CREOjhGwiAmQBg1PXwDHYHwMkCgIdHsHsAAC4ZACwCAigeALgPACDlTg2iAeCZAEDOwdGJtL7kffEAW/kAmMx+jx1JByjNAZDa/XtM9BEAtytAbuLvsTlrQAAAgrs12EtFGQAAEFgDAIYBOn1OAgCTCrCaQqcv59Lpq9cBUH0ANWT3w0EhP/8XAtEM8L/u17/5Z6EQAEgAhBgiH3kUFY4OZzjBGImJZjrJbMRcy3Ka9Qw2ju0srozdhyOFkMKZSjzPlc6dzpPJW8tPEcjelC14WaiedFgkd/N10VbxYxL5km3SJ2Rub+mUi5a/o9CjdFr5vsp71bNqZeqDmklaFdrDOmm6T/XG9DMMnhtO7sgyrjOZNb26q9FsYXeuRcue15avrdqsV2wL93bYddp3OXQ7offdc+7b339gwOX9wQ9uWPfHHp88P3sNe4/4fPEd9eciPwv4GjhJmaJOH5oJmg2ep80f/haycGQx9HvY0tEfx1bCV46vRkhHdkQjTiJjUKfQsQynGc9g4pjimRNYzrImYpPYzuGS8SnsqRxphPOc6cQMrkzuCzwXebP4svkvCVzedEXwqtA14RxSrsj1zTdE88TyxW9KFkjekiqUvi1ze7yIfEf2rlyxQoniPaX7Sg+UH24tVS1TK1t4FFKu/lijQqtS+8m2qm1PdZ6uVUfU6D3b/lz/hcFfhrXo2pi6HS+N600aTBtNm1iaEl6ZNZu3WLTiWs+9tmyzemPdTmhPfWvTYdu5t4u7K7Pb/p1Dj1Mvf292n3O/88D+90Lvr35wGTw4JDKU+9Htk/tnj2Hx4fwRry/eoz5j0mOF434T/l/Jk3KTd6cCpykz1Fml2ftzQfPB32gLqgtliyHfQ5fCfoQtay1XrhxbDV/TWXtKpwMgRJE45DSqCX2bIY0xHOPNZMtsyLKVVRIrycaL48HzsvNycBEkOKWIGlzm3Ad4gnmT+Ir5mwRGBTmF1IS9SRdEXooixHTED0nck5ySlpIhb6mUQ8nrK6QoDipLq8Ru7VKTUadq1GrxaIdue6XLrUfZ/txAzPCYUZuxkEnozirTJTMlc8/d6RZtljgrE+tQmzzbt3Ys9tsdDjledqrbN7Vf+MAel6MHc11r3UY9uDz1vBy8T/hc863x6/dfCuAM3EIxovocCg9KDs6llR6uD+k9Mha6cBR1jCOcdFz2hGrE9kizqD3R+04ejPE8RY6lnQ46ExkXGX8yIe5samJCUta5i8mZKSmpl9JSz2ekX8goyLx54e7Fgqzb2cWXnlx+cqX26qtrbTntue3X22/05n3KH7k5VPD51lThzO2posk7s3enisdLJu6N3B98MPSwp7StrOFRTfmjx8UVlypTn0RWBTzdV21Ws+2ZzHPC86UXH/5qrH1Yl/YyqN6mQa1RoJHe1PPqYXN8i1OraOvw6wdtx9/saMe197+91uHXqdK52tXcnfZuf490z1xvRV90v9kAcWDg/a0PwYPaQ+ihxo/nPx34LPl5YrhiJOrLrlGu0f6xG+PkCdWJta8Nk6lT+6bFpidmHsyGz5nME+a7v+UtUBY1v6O+v1xK+bFvWXT560rZauSaKZ2bTgeAk4hQ5FGUNqoCfZxBj6GaMQpzismYqZY5luU0azx2F7aJLRGXiE9i38PeypFMSOVMI6Zx2XK95c7gyeC9wJfFny2QvemSoLNgv9BV4WukHJGczTmi18VuiOdJ5EvelCqQviXjKzO2pVC2SO6O/F2FYsUSpXvK91UebH2oWqZWpl6mEarxXbNCq0K7ctsTnSrdE7pretXba/SfGTw3fGEUswO9o9a4zuTlznrThl2NZgnmWPNXu5stWva0WiZbsVu1Wb+xabd9u7fTLsOe277LodvxnVPPvmxnAee+/f0H3rt8OPjBNcdNxG3I/aPHJ8/PXvneEusJ4jfmf5ssS574txSZ+5Ui5WEaYUtHfxxbDl85vnpiLYIeBdHIX0mCOYOJY4priN+VwHoWm4hNYjuHT2ZP4fiVJdyZPBd4f2bJpj+zJHfouvsN0TyxfImbEhtpUiR7R+6u/B9ZolK6tUz1kXq5+mONCs1K7SfaVdue6lbr/pEjO+qMXxrXmzTsbDRtMnsV0rK51eK1ZZvlG6v24x0ynXZd9t3RPQq9Tn2xAyrv4wZVh85+8hjWHkkZ9R33+0qeoszEzzstnFtKWLWm0wHW9z4AAEY1gIwtAHZZADa5ALFbACRdALgLACzZAGw1AckgBEgdKiB26WzsH4AAdhAEeTAARwiGZCiB7wgSwgwRiihAtCBGkHikCTIKWYVcQemgolB1qBW0CNoRnY/+xmDMcIqhmGGK0YQxh3EYw4VxxlQxYZg0mWKYxpm1mCnMNSxyLJEs5aw41ijWd1giNhD7hW0H20m2QZwr7jkehffCT7BbsWewr3LEccwStAh5nOqceZxTRBfiIpcvVxn3Fu6XPF68GN5CPnG+I3zz/JcFTATmNl0TFBMMF0IIlQr7kURIPSLnN2/eHCmKF20VSxHfK8EvMSR5W8pQ6pa0gQyHzOCWB7Kn5ZzlVRSwCiOKfynlKkereGw1UZVV41RbUR/WyNTEadZolWjnbDuvc0Y3Qu/I9kP6ZANfQx8jnx3+xoEmtJ3HTGN2nTPLNr+1u9yiYU+f5Yw1xkbIVmOvjR3VPsnhruNrpzln3v26B7xckg9Wun5x5/Ew8QzzKvLl9bP0jyfXBiIp+tSoQy+CGWlmh1NDxcIoR5+Esxx3OlEUQY+yjUGeco59dIYz7lB8W2J60lKyS0pdmsL5rMzgCx+zbLJrr9y9Jp5z+TpPPvvNpFu4wnN3MosFS27clys1Kmsrd308U8XztKjG4AWtFl9XVL+rKb5ZrqXtdUh7XQe1S6C7vk+iv/t9/KDep6Jhjy/Coz1f7aa4p7tms+ZdFieWSpcj6Lx0OgAggQV4QBr0wAEOQzqUwwACg1BEuCCSENWIOaQM0gWZhXyLwqN2o86imtFs6D3odHQvA4nBl6GE4TujIeM5xncYccxhzAsmApMHUzkzK7Mz810WNMsBloesLKzurNVYLiwV28wmw5bINoEzxxXj2fAUfCf7dvYbHDiOEI5egjHhHieJM5VzjRhM/MrlxzXGTeae5aHxLPAe5UPwneXn5y8U0BSo22S3aVQwUohPqEzYSniMFCsiIVK/OVCUR/SpmLs4VvyZRKCksOQbqThpA+lVmcot4bI6soty1fJnFGwVRRSnlKqVU1T8thqpCqkuq3WoP9a4rBml5a1tv01HR0FXRI+wHa2P0p81mDGcMhrfMWw8ZzK+89supBnRnGe3koXunj2W1lb+1mE22bb3976y67VfcSQ6KeyzcD60/+KBWpcRV2Y3RXcfjyzPaq9pH2lfT79M/44AgcC9lGzqlyCp4BBaQ4jgkeDQxqOix5LCx044RtRHqUXnxRBOJZ0mnMmI503ITlRNakn2TPmRlpiunvH5wpUsv0t7r0hfY8iZuP48r/TmxVuxt93vOBcb39N4sLVU/pHcY6lK8SqpasVnei921lq9JDccakppvtb6pG2gnd4p3K3T49GXMFDxYeIj32eDkcjRgvFPk/zTXrNX5ocXpZYCl8vWEHQ6ADACOwiCAThCMpTAmw37G+7X1aPxaEf0NwZjhqyf3tcwzkzCTDFM48y2zDUsciyXWHGsUayL2EDsFzYPnCvuI94LP8EezL7KEUfgJuRxqnM2El2Ii1zJv0xb8M3/9GwphBAq/WnZal3yT8ch0gZ/Gv4t+KffN5o1WiW/7f6W+89u/5ta70FfXj/Lv6sN6fm72+jCP+WeVf4tN4Nxw+5lzQ29N9I2/BYRNgQ/KN8wXHlyXfGzng3HDaNN8a/+as5oaXsd8kawva6D2lnSFdtd3xPSJ9HvP2D0Pn5Qb+j0R7dPRZ8Xhtu/CI/6j5mOS01gvtpN5k/FTnvP7JyVmWOdm5x//e3BQsai7eLE95glgx+SP4aXI1Z4V66scqzGrC6u3aAn0OkA6+clAABgMaSQKUEkc0Oj//Ow978qgHx4Yw4kAGA9A/faAAABAKR8aaa2AEAEAC0wBAqQgQJBQAJzMASjn1cSuP964guwfpYDAGBkB7hkDwBQ/f1Y5N/npXmG0gAADCnUsCBfbx8aSZ9KJXuSDCkB1MM0zyBZkmmgu7wsSVlRURUA4F93RgACxGzQPQAAAAlwSFlzAAALEwAACxMBAJqcGAAAC25JREFUeJztnHlUE9cex38JYY2JGhQ14Hae1BSXKoK4C0UtbtRqRUWlomi1NK5Y6tKKQpG2qK0pWo8oPp+ix+rRFlCPyxEVV9TXpx7klOdxKQFERQ1CWMLM+wMfDZk7k5nJMsHez8k/+d3f/d1fJt+5d+6SiEiSBAxGOMRCJ4D5u4MliBEYLEGMwGAJYgQGSxAjMFiCGIHBEsQIDJYgRmCwBDECgyWIERgsQYzAYAliBAZLECMwWIIYgcESxAgMliBGYLAEMQKDJYgRGCxBjMBgCWIEBksQIzASoRN4w+93X25YpWkl8zCyifr37bDsy5mcfDAtDkeRYFFRmVZbbmKsrixeBjM5+WBaHI4yEJNg/ufMbHwwLQ5HkSDmb0uLl6BM1kroFDAW0ZIkqNfXU43FJU/snwnGijjKdIQNUTP6hoelmhjdXEWCJIOxFi1JgiIRtFW4Cp0Fxsq0pIEY81ZitV5QV0nmZOUfz877o/CBkZlQqbpMmDB0TJh/a4UHbWV2NBBQ/PiFi4uzkU3k7ka2UTSbkehr4GnZC2cjt/q6ui7d2gKIAOB5heHg/tyjR85W6l43JRkYqPpkTlhAUA+RmHZYt1FYJNoS/bEjl86culqi/etJVy53DwsLipg+onO39szVmVMFgCfl9ds0x07kXGh8HxTos3VHPAmkqP4uiC0YZ5ze4VFJZPn/CxaX1EVFrqv669LTYUhPX9HHvwey7NDRe5sSt5kYO3s7H87a3PT2n5m3t6XuNPGRy+tO5+4wtiDdzp5Z79FW8WF4crm2lCHFz2PHzZ43Fllko7AmXLqiXRqbYm5sMqSlqQMG+9EVI1PNyV7bTtmhpg6mTjHNtvE6G8iHkp+6s0mSFnUDj3HV0oE4OeXklAkrWOgPACQxMT9GRyYBSfBry93dmWr0UXZg4/bgYfWAAWpmoQDAT2nHRwerkRnaKGwTBgImTkxebl5/ACCJjd2++FPTmRlzqq1kHroqGDGINlsnEaKWHbBIgtMjt/56KIdTlYLCJ0EDFvBWIZXKSjbqh5iYb13YBdTpYHTIEpatWytsTR0MCjAvZWOu5T/6eOIXrN2JoiJd8HC1Ay4f8Jfg0hUHHxQW8arqHj3za97t2gGdDhZ/utFuYQkShg5SO3EP+KdWv3rFD+x8xTExKcL0cubgKcF7RdVXzl2iKw0J6bciLnLs+BF0DgWFr67k3uDXtOXI5a5zosctip3aybsTnc+1/JJnHBe9eYddHneQblYYGKj6LHby8rjZdDHPnrtfdPc+pzzpaCARK/92gOeMeMa0eOTEKXx8/zUb5v5/4gXrEqfuz7ylSc2gen6dsOt0bgC/1i3AkJX9jZdS0fhmzrwRryrh/ZFq5FVYGafJyEyyddjyCkDezEGBXX9IWyaWvOkcp0UOLC6p/2jCcmqfMSsq8dqtPezybIa3dzsSxFptuUzmAQASUTdQmx5EMkICUA0aH8aQfHo0PhJ8XNKA1F9oiO+axLnGFhHArEj/1/r6jLR9Js46HQkkASJ7LkwaLl3eLHFzNza1lsG1G5qgAIRcCgpfNNTVObmYfdizKOyqVbuoEUNDfJM3LTYx+iidcy9rQoZQn+dkL8sr2ngpzOX5hs7erXfsivf0kqEKmZZ7nh+f5MlQrK5imYAJfBSwadMvKHNt8iY10j9qdhBq4cf55dOXPFrnzfa0hSZCaUQihqPZW1A1xKdy8mwattYAd/J/pzjUJ6d+jmxL6gbhEROo9j27s8zm2Uj4+D6Hs5Jo9MeELi/S8/4F2mJ1OQDPdV8+EryIGjji46Y0rXya4OECfQPfk8ulMqMXAOHqbs/dtlr/wX3pyrooJa5yxImbQ7/k2jTsvUId9ZLFRAczDA6fxX5ANR44dAlYHKaUyw1rEheYdaNSdS9B/u8DtMULbzN3n8xwHoiratB1RocFMdRK3xHDtSHrEhriR3eHNKJe8klqYpqdw2ZlX6Ea0zMudvTp+bxCh6pB3ClATpKcSEODSGLm20zfGc/sgISoyJKeWU9bPPM3cO7DI2wTnCX4SkeiLnm9rK3ckjxszfBhtH1VIyNHqlITTY0FhcUAJIPILAx75dJNVCVxUuJu5rAUJM/Kn7enrNI3R9/VtyvHsAD1d8T7w2lLx34HiomcYzaH80AskSC/DwOIHHDV0xh+8x4XMLOBaVFYpRnRcMBZYmbVz0/VkbnDpkKCFn6mv8f6z4AeKzkFRML5Crq7Ih46eHw8O+PX27LdT9uElbZCzGNsRGVlNSd/EqprGZZglO/BsExLcwIAHhKsrEIMxAWF5WwehwXkZn6BA4YtK31mrUwMBjMLy5EzRrOPRgDxTCN1oyt2bwNTqBN5nljrsJYYSNLhx2ImDAa02cIPxSNsUKDyx+2rDAYOtzRBgCutXvhQlu6pZCiOeW7FtjhLsJUUee2cn5U+bUf/ZLNFc/FgxiETY0rytJCwYVwT4EfmgbOTI5mOS2VlXaca/VRK5gcMC8OGhAZlUPbZgwa+KxKDs4tg9/OTI/2UevolW3WVdU86c44llwKyx9+39yRDrb0U/QFAn76+XFvnzZ9aPVFXx+Dwc9q/UGYzJ3osDDsqtB+1bGvaMeZGCQJqa0jjV4PBaiePKvIiO5T8h7ZYXcx7CZoOPnL+YHwo1Xjg0HVDjR7pX1IOqE0ug6dXGx6t80WckriHruzClTLkNtyCBZNsGrZbF1eUdmSPih4xNBkQoB4xZLHxK2zUInN5sqL6v98rGJag5+cDeFulIWP4SHDZMuQXIx46ZBF1UlJvgAlhiI27zt5SkcSuv0X6NefOiaPnqfbScmJl7DeoGobBIxC9lBXDSsQQirqfI6al6GkmsEtXZFJXXzYkzDebp1mIiiyPE/QHEOdeBDebHCvhMx3xUkA3le9DxGFBWZD/or171/Ts1RlEQBCQe+HhquWbkAtW69cLsF+SkHj4+MmbSRsXNv6QpaYG9u2/vDMNfd+HhviCmNX1sSTsV2smncs5S/GSBI+Mnxs9Jnr+OBc3JwAgCLh6rXhJ7LeoPqN28Eh/NnkyQAJZtT+caef48RmoRD5UNGfgDvM+zeE5I965c/Ho4chDCc5RUd+ZrS6XG3r5q/g1bSHX8x+MGcVqn2rdhoV2CCt1g+nRHx/MOEz13J1xanfGKWMLcsxKSZ5jlQNH6Ll7Ewx7dMYM3M51aOWZulwKSZt5r4wTJ05uNu8lKAlfTXGVWvm5my7sMvVI5GkGNvip2oaEDbE4LyHhf/eMDu6SmraaR8Xs7ATk6SYbw2HOOCNi4NiPgu0Z9nzuxvb0Z63pkMshI5Nd5+TAWNSBDx/cKfvM1gbW/n6qDpevbm6vRB7sYbMMxn+pLCV5RvYZDRvPL+I+XPrlbDuHFQFkZ62eH8vhjxInju9/OldjxX1Rof5Yw9JniPYK0Y1bmm3pazt6M+24v6vq9Fv2+ozMtU4u6N30jh0RCzQmu/hsfOh4UVHZXgF51zWTI8LofAID/3Hu/PdTIkexCWiLsDHzBuVe1syKnsS8MTItYnje5S1rmx9QN8YddRATaTTGzLMgWzjfElb4KXsTBAFlZdVFf2hfvdC5uruVasu9vT1VKh+fLgp7ns9H/io+Pm5c0zYGSUJpafWd2w9q9TXV+jpPhZRNkjYKS0dVFfnwwVNt8dMafTUJkhq9vnt3r3d6erdRuDn4iRCuWLP3FYtBqfRQKpv2PHpZMbgVEYka87RyetYNK5WKevX26tXbyyrRHBn8t0YYgcESxAgMliBGYLAEMQKDJYgRmLdQgno90wE+RwuLaUn/Nc2S4UN8n0a8LzXain1dVeMf2Nsxw2KsuTSNwfDgLRyIMS0LLEGMwGAJYgQGSxAjMFiCGIHBEsQIDJYgRmCwBDECgyWIERgsQYzAYAliBOZ/jys2NWyvP3gAAAAASUVORK5CYIIK\" />";
204 }
205
206 return result;
207 },
208
209 'progressWidth': function() {
210 return this._progressWidth;
211 },
212
213 'updateProgress': function(aProgressComponent, aPercentage) {
214
215
216 },
217
218 //-------------------------------------------------------------------------
219
220 'printAllData': function(anEvent) {
221 var newWindow;
222 var allRecords;
223
224//MochiKit.Logging.logDebug(">>> printAllData");
225 newWindow = window.open("", "");
226 newWindow.document.write(
227"<html>" +
228"<header>" +
229 "<title>Clipperz export data</title>" +
230"<style>" +
231"#exportedData {" +
232 " width: 600px;"+
233"}" +
234".ext-mb-progress-wrap {" +
235 "border:1px solid #6593cf;" +
236 "margin-bottom: 10px;" +
237 "width: " + this.progressWidth() + "px;" +
238"}" +
239".ext-mb-progress {" +
240 "height:18px;" +
241 "background:transparent url(./images/default/basic-dialog/progress2.gif) repeat-x 1px 1px;" +
242"}" +
243".ext-mb-progress-bar {" +
244 "height:18px;" +
245 "overflow:hidden;" +
246 "width:0;" +
247 "background:#8bb8f3;" +
248"}" +
249"body {" +
250 "font-family: sans-serif;" +
251"}" +
252"div#logo {" +
253 "border-bottom: 1px dotted #aaaaaa;" +
254 "margin-bottom: 15px;" +
255"}" +
256"div.recordBlock h2 {" +
257 "font-size: 14pt;" +
258 "margin: 0px;" +
259 "padding: 0px;" +
260 "border: 0px;" +
261 "color: #666666;" +
262"}" +
263"div.recordBlock div.recordNotes p {" +
264 "margin: 0px;" +
265 "padding: 0px;" +
266 "border: 0px;" +
267 "color: #aaaaaa;" +
268 "font-size: 10pt;" +
269 "line-height: 18pt;" +
270 "border-left: 1px solid #aaaaaa;" +
271 "padding-left: 10px;" +
272"}" +
273"div.recordBlock dl {" +
274 "margin: 0px;" +
275 "padding: 0px;" +
276 "border: 0px;" +
277 "color: #999999;" +
278 "padding-bottom: 10px;" +
279 "border-bottom: 1px dotted #aaaaaa;" +
280 "margin-top: 10px;" +
281 "margin-bottom: 15px;" +
282"}" +
283"div.recordBlock dl dt {" +
284 "display: block;" +
285 "float: left;" +
286 "min-width: 100px;" +
287 "white-space: nowrap;" +
288 "overflow: hidden;" +
289 "margin-right: 10px;" +
290 "font-size: 10pt;" +
291 "line-height: 18pt;" +
292"}" +
293"div.recordBlock dl dd {" +
294 "color: #666666;" +
295 "font-size: 10pt;" +
296 "line-height: 18pt;" +
297"}" +
298"" +
299"</style>" +
300"" +
301"<!--[if IE]>" +
302"<style>" +
303"div.recordBlock dl dt {" +
304 "width: 100px;" +
305"}" +
306"</style>" +
307"<![endif]-->" +
308"" +
309"</header>" +
310"<body>" +
311 "<div id=\"logo\">" + this.logo() +
312 "<div id=\"progressWrapper\"><div class=\"ext-mb-progress-wrap\"><div class=\"ext-mb-progress\"><div id=\"progress\" class=\"ext-mb-progress-bar\">&#160;</div></div></div></div>" +
313" </div>" +
314"</body>" +
315"</html>"
316 );
317
318 anEvent.preventDefault();
319
320 allRecords = MochiKit.Base.values(this.user().records());
321 allRecords.sort(this.compareRecords);
322
323/*
324 deferredResult = new MochiKit.Async.Deferred();
325 MochiKit.Iter.forEach(allRecords, MochiKit.Base.partial(function(aDeferredResult, aWindow, aRecord) {
326 var printerRecord;
327
328 printerRecord = new Clipperz.PM.Components.Printing.Record({record:aRecord});
329 aDeferredResult.addCallback(MochiKit.Base.method(printerRecord, 'deferredDrawToWindow', aWindow));
330 }, deferredResult, newWindow));
331 deferredResult.callback();
332
333 return deferredResult;
334 */
335
336 MochiKit.DOM.withWindow(newWindow, MochiKit.Base.bind(function(someRecords) {
337 var currentWindow;
338 vardeferredResult;
339 var progressBar;
340 var progressWrapper;
341 var i, c;
342
343 currentWindow = MochiKit.DOM.currentWindow();
344 progressBar = MochiKit.DOM.getElement('progress');
345 progressWrapper = MochiKit.DOM.getElement('progressWrapper');
346
347 deferredResult = new MochiKit.Async.Deferred();
348 c = someRecords.length;
349 for (i=0; i<c; i++) {
350 deferredResult.addCallback(function(aWindow, aRecord) {
351 var printerRecord;
352
353 printerRecord = new Clipperz.PM.Components.Printing.Record({record:aRecord});
354 return printerRecord.deferredDrawToWindow(aWindow);
355 }, currentWindow, someRecords[i])
356 deferredResult.addCallback(MochiKit.Base.bind(function(aProgressBar, aProgress) {
357 MochiKit.Style.setElementDimensions(aProgressBar, {w:aProgress * this.progressWidth()});
358 }, this, progressBar, ((i+1)/c)));
359 deferredResult.addCallback(MochiKit.Async.wait, 0.2);
360 }
361
362 deferredResult.addCallback(function(aWindow, aProgressWrapper) {
363 MochiKit.DOM.replaceChildNodes(aProgressWrapper);
364 MochiKit.Style.hideElement(aProgressWrapper);
365 aWindow.stop();
366 }, currentWindow, progressWrapper);
367
368
369 deferredResult.callback();
370 }, this, allRecords));
371 },
372
373 //-------------------------------------------------------------------------
374
375 'exportAllData': function(anEvent) {
376 // vardeferredResult;
377 var newWindow;
378 var allRecords;
379
380//MochiKit.Logging.logDebug(">>> printAllData");
381 newWindow = window.open("", "");
382 newWindow.document.write(
383"<html>" +
384"<header>" +
385 "<title>Clipperz export data</title>" +
386"<style>" +
387"#exportedData {" +
388 " width: 600px;"+
389"}" +
390".ext-mb-progress-wrap {" +
391 "margin-top:4px;" +
392 "margin-bottom: 10px;" +
393 "border:1px solid #6593cf;" +
394 "width: " + this.progressWidth() + "px;" +
395"}" +
396".ext-mb-progress {" +
397 "height:18px;" +
398 "background:transparent url(./images/default/basic-dialog/progress2.gif) repeat-x 1px 1px;" +
399"}" +
400".ext-mb-progress-bar {" +
401 "height:18px;" +
402 "overflow:hidden;" +
403 "width:0;" +
404 "background:#8bb8f3;" +
405"}" +
406"</style>" +
407"" +
408"<!--[if IE]>" +
409"<style>" +
410"</style>" +
411"<![endif]-->" +
412"" +
413"</header>" +
414"<body>" +
415 "<div id=\"logo\">" + this.logo() + "</div>" +
416 "<div id=\"progressWrapper\">" +
417 " <div class=\"description\">" + Clipperz.PM.Strings['exportDataInProgressDescription'] + "</div>" +
418 " <div class=\"ext-mb-progress-wrap\"><div class=\"ext-mb-progress\"><div id=\"progress\" class=\"ext-mb-progress-bar\">&#160;</div></div></div>" +
419 "</div>" +
420 "<div id=\"textareaWrapper\">" +
421 " <div class=\"description\">" + Clipperz.PM.Strings['exportDataDescription'] + "</div>" +
422 " <textarea id=\"exportedData\" cols=\"80\" rows=\"20\">[</textarea>" +
423 "</div>" +
424"</body>" +
425"</html>"
426 );
427
428 anEvent.preventDefault();
429
430 allRecords = MochiKit.Base.values(this.user().records());
431 allRecords.sort(this.compareRecords);
432
433 MochiKit.DOM.withWindow(newWindow, MochiKit.Base.bind(function(someRecords) {
434 var currentWindow;
435 vardeferredResult;
436 var textareaWrapper;
437 vartextarea;
438 var progressBar;
439 var progressWrapper;
440 var i, c;
441
442 currentWindow = MochiKit.DOM.currentWindow();
443 textarea = MochiKit.DOM.getElement('exportedData');
444 textareaWrapper = MochiKit.DOM.getElement('textareaWrapper');
445 MochiKit.Style.hideElement(textareaWrapper);
446 progressBar = MochiKit.DOM.getElement('progress');
447 progressWrapper = MochiKit.DOM.getElement('progressWrapper');
448
449 deferredResult = new MochiKit.Async.Deferred();
450
451//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("exportAllData - 1: " + res); return res;});
452 c = someRecords.length;
453 for (i=0; i<c; i++) {
454 deferredResult.addCallback(MochiKit.Base.method(someRecords[i], 'deferredData'));
455 deferredResult.addCallback(MochiKit.Base.method(someRecords[i], 'exportedData'));
456 deferredResult.addCallback(MochiKit.Base.bind(function(aTextarea, aProgressBar, aProgress, someRecordExportedData) {
457 aTextarea.value = aTextarea.value + "\n" + someRecordExportedData + ",";
458 MochiKit.Style.setElementDimensions(aProgressBar, {w:aProgress * this.progressWidth()});
459 }, this, textarea, progressBar, ((i+1)/c)));
460 deferredResult.addCallback(MochiKit.Async.wait, 0.2);
461 }
462//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("exportAllData - 2: " + res); return res;});
463 deferredResult.addCallback(function(aTextareaWrapper, aTextarea, aProgressWrapper) {
464 aTextarea.value = aTextarea.value.slice(0, -1) + "\n]";
465 // MochiKit.DOM.replaceChildNodes(aProgressWrapper);
466 MochiKit.Style.hideElement(aProgressWrapper);
467 MochiKit.Style.showElement(aTextareaWrapper);
468 aTextarea.focus();
469 aTextarea.select();
470 }, textareaWrapper, textarea, progressWrapper);
471//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("exportAllData - 3: " + res); return res;});
472 deferredResult.addBoth(function(aWindow) {
473 aWindow.stop();
474 }, currentWindow);
475//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("exportAllData - 4: " + res); return res;});
476
477 deferredResult.callback();
478 }, this, allRecords));
479 },
480
481 //-------------------------------------------------------------------------
482
483 __syntaxFix__: "syntax fix"
484
485});
486
diff --git a/frontend/beta/js/Clipperz/PM/Components/Panels/LoginPanel.js b/frontend/beta/js/Clipperz/PM/Components/Panels/LoginPanel.js
new file mode 100644
index 0000000..84b2475
--- a/dev/null
+++ b/frontend/beta/js/Clipperz/PM/Components/Panels/LoginPanel.js
@@ -0,0 +1,1114 @@
1/*
2
3Copyright 2008-2011 Clipperz Srl
4
5This file is part of Clipperz's Javascript Crypto Library.
6Javascript Crypto Library provides web developers with an extensive
7and efficient set of cryptographic functions. The library aims to
8obtain maximum execution speed while preserving modularity and
9reusability.
10For further information about its features and functionalities please
11refer to http://www.clipperz.com
12
13* Javascript Crypto Library is free software: you can redistribute
14 it and/or modify it under the terms of the GNU Affero General Public
15 License as published by the Free Software Foundation, either version
16 3 of the License, or (at your option) any later version.
17
18* Javascript Crypto Library is distributed in the hope that it will
19 be useful, but WITHOUT ANY WARRANTY; without even the implied
20 warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
21 See the GNU Affero General Public License for more details.
22
23* You should have received a copy of the GNU Affero General Public
24 License along with Javascript Crypto Library. If not, see
25 <http://www.gnu.org/licenses/>.
26
27*/
28
29if (typeof(Clipperz) == 'undefined') { Clipperz = {}; }
30if (typeof(Clipperz.PM) == 'undefined') { Clipperz.PM = {}; }
31if (typeof(Clipperz.PM.Components) == 'undefined') { Clipperz.PM.Components = {}; }
32if (typeof(Clipperz.PM.Components.Panels) == 'undefined') { Clipperz.PM.Components.Panels = {}; }
33
34
35Clipperz.PM.Components.Panels.LoginPanel = function(anElement, args) {
36 args = args || {};
37
38 Clipperz.PM.Components.Panels.LoginPanel.superclass.constructor.call(this, anElement, args);
39
40 this._showLoginFormAnimator = null;
41 this._showRegistrationFormAnimator = null;
42 this._shouldShowRegistrationAlert = true;
43
44 this._visibleForm = null;
45 //this._isPassphraseVisible = true;
46
47 Clipperz.NotificationCenter.register(null, 'switchLanguage', this, 'switchLanguageHandler');
48
49 this.render();
50
51 return this;
52}
53
54//=============================================================================
55
56//MochiKit.Base.update(Clipperz.PM.Components.Panels.LoginPanel.prototype, {
57YAHOO.extendX(Clipperz.PM.Components.Panels.LoginPanel, Clipperz.PM.Components.Panels.BasePanel, {
58
59 'toString': function() {
60 return "Clipperz.PM.Components.LoginPanel component";
61 },
62
63 //-------------------------------------------------------------------------
64
65 'render': function() {
66 var result;
67 varlayout;
68 var registerButton;
69
70 MochiKit.Signal.disconnectAllTo(this);
71 this.element().update("");
72
73//MochiKit.Logging.logDebug(">>> LoginPanel.initPanel");
74 Clipperz.YUI.DomHelper.append(this.element().dom, {tag:'div', id:this.getId('baseDiv'), cls:'LoginPanel', children:[
75 {tag:'table', children:[
76 {tag:'thead'},
77 {tag:'tbody', children:[
78 {tag:'tr', children:[
79 {tag:'td', valign:'top', children:[
80 {tag:'div', cls:'clipperzServiceDescription', htmlString:Clipperz.PM.Strings['clipperzServiceDescription']}
81 ]},
82 {tag:'td', valign:'top', align:'right', children:[
83{tag:'div', id:this.getId('forms'), cls:'clipperzLoginForm', children:[
84 {tag:'div', id:this.getId('loginForm'), cls:'loginForm', children:[
85 {tag:'div', cls:'loginFormHeaderBox', children:[{tag:'h3', htmlString:Clipperz.PM.Strings['loginFormTitle']}]},
86 {tag:'form', id:this.getId('loginForm_form'), autocomplete:'off', children:[
87
88 {tag:'table', cls:'formLayout', children:[
89 {tag:'thead'},
90 {tag:'tbody', children:[
91 {tag:'tr', cls:'formFieldTR', children:[
92 {tag:'td', width:'90', htmlString:Clipperz.PM.Strings['loginFormUsernameLabel']},
93 {tag:'td', children:[
94 {tag:'input', id:this.getId('login_username'), cls:'loginFormField', type:'text', name:'username'}
95 ]}
96 ]},
97 {tag:'tr', cls:'formFieldTR', children:[
98 {tag:'td', htmlString:Clipperz.PM.Strings['loginFormPassphraseLabel']},
99 {tag:'td', children:[
100 {tag:'div', id:this.getId('passphraseDIV'), children:[
101 {tag:'input', id:this.getId('login_passphrase'), cls:'loginFormField', type:'password', name:'passphrase'}
102 ]},
103 {tag:'div', cls:'oneTimePassword', id:this.getId('oneTimePasswordDIV'), children:[
104 {tag:'input', type:'text', id:this.getId('oneTimePassword_1'), name:'passphrase'},
105 {tag:'span', html:'-'},
106 {tag:'input', type:'text', id:this.getId('oneTimePassword_2'), name:'passphrase'},
107 {tag:'span', html:'-'},
108 {tag:'input', type:'text', id:this.getId('oneTimePassword_3'), name:'passphrase'},
109 {tag:'span', html:'-'},
110 {tag:'input', type:'text', id:this.getId('oneTimePassword_4'), name:'passphrase'}
111 ]}
112 ]}
113 ]},
114 {tag:'tr', cls:'formFieldTR', id:this.getId('passwordTypeChooserTR'), children:[
115 {tag:'td', valign:'top', align:'right', children:[
116 {tag:'input', type:'checkbox', cls:'passwordTypeCheckbox', id:this.getId('useOneTimePasswordCheckbox')}
117 ]},
118 {tag:'td', children:[
119 {tag:'div', cls:'passwordTypeChooser', children:[
120 {tag:'h4', htmlString:Clipperz.PM.Strings['loginFormOneTimePasswordCheckboxLabel']},
121 {tag:'span', htmlString:Clipperz.PM.Strings['loginFormOneTimePasswordCheckboxDescription']}
122 ]}
123 ]}
124 ]},
125 {tag:'tr', children:[
126 {tag:'td'},
127 {tag:'td', children:[
128 {tag:'div', id:this.getId('login_submit')}
129 ]}
130 ]}
131 ]},
132 {tag:'tfoot'}
133 ]}
134 ]},
135
136 {tag:'div', cls:'loginFormFooterBox', children:[
137 {tag:'ul', children:[
138 {tag:'li', id:this.getId('showRegistrationLI'), children:[
139 {tag:'span', htmlString:Clipperz.PM.Strings['loginFormDontHaveAnAccountLabel']},
140 {tag:'a', href:'.', id:this.getId('showRegistration'), cls:'clipperzActionLink', htmlString:Clipperz.PM.Strings['loginFormCreateOneLabel']}
141 ]},
142 {tag:'li', children:[
143 {tag:'span', htmlString:Clipperz.PM.Strings['loginFormForgotYourCredentialsLabel']},
144 {tag:'a', href:Clipperz.PM.Strings['loginFormAarghThatsBadUrl'], target:'Clipperz_Help', htmlString:Clipperz.PM.Strings['loginFormAarghThatsBadLabel']}
145 ]},
146 {tag:'li', children:[
147 {tag:'span', htmlString:Clipperz.PM.Strings['loginFormAfraidOfMaliciousScriptsLabel']},
148 {tag:'a', href:Clipperz.PM.Strings['loginFormVerifyTheCodeUrl'], target:'Clipperz_Help', htmlString:Clipperz.PM.Strings['loginFormVerifyTheCodeLabel']}
149 ]}
150 ]}
151 ]}
152 ]},
153
154
155
156 {tag:'div', id:this.getId('registrationForm'), cls:'registrationForm', children:[
157 {tag:'div', cls:'loginFormHeaderBox', children:[{tag:'h3', htmlString:Clipperz.PM.Strings['registrationFormTitle']}]},
158 {tag:'form', id:this.getId('registrationForm_form'), children:[
159 {tag:'h5', cls:'errorMessage', id:this.getId('registration_errorMessage')},
160 {tag:'table', cls:'formLayout', children:[
161 {tag:'thead'},
162 {tag:'tbody', children:[
163 {tag:'tr', cls:'formFieldTR', children:[
164 {tag:'td', width:'90', htmlString:Clipperz.PM.Strings['registrationFormUsernameLabel']},
165 {tag:'td', children:[
166 {tag:'input', id:this.getId('registration_username'), cls:'loginFormField', type:'text', name:'username'}
167 ]}
168 ]},
169 {tag:'tr', cls:'formFieldTR', children:[
170 {tag:'td', htmlString:Clipperz.PM.Strings['registrationFormPassphraseLabel']},
171 {tag:'td', children:[
172 {tag:'input', id:this.getId('registration_passphrase'), cls:'loginFormField', type:'password', name:'passphrase'}
173 ]}
174 ]},
175 {tag:'tr', cls:'formFieldTR', children:[
176 {tag:'td', htmlString:Clipperz.PM.Strings['registrationFormRetypePassphraseLabel']},
177 {tag:'td', children:[
178 {tag:'input', id:this.getId('registration_repassphrase'), cls:'loginFormField', type:'password', name:'repeat-passphrase'}
179 ]}
180 ]},
181 {tag:'tr', cls:'formFieldTR', children:[
182 {tag:'td', align:'right', valign:'top', children:[
183 {tag:'input', id:this.getId('registration_check'), type:'checkbox', name:'safetyCheck'}
184 ]},
185 {tag:'td', children:[
186 {tag:'span', htmlString:Clipperz.PM.Strings['registrationFormSafetyCheckLabel']}
187 ]}
188 ]},
189 {tag:'tr', cls:'formFieldTR', children:[
190 {tag:'td', align:'right', valign:'top', children:[
191 {tag:'input', id:this.getId('registration_termsOfServiceCheck'), type:'checkbox', name:'termsOfServiceCheck'}
192 ]},
193 {tag:'td', children:[
194 {tag:'span', htmlString:Clipperz.PM.Strings['registrationFormTermsOfServiceCheckLabel']}
195 ]}
196 ]},
197 // {tag:'tr', cls:'formFieldTR', children:[
198 // {tag:'td', htmlString:Clipperz.PM.Strings['registrationFormInvitationCodeLabel']},
199 // {tag:'td', children:[
200 // {tag:'input', id:this.getId('registration_invitationCode'), type:'text', size:'30', name:'invitationCode'}
201 // ]}
202 // ]},
203 {tag:'tr', children:[
204 {tag:'td'},
205 {tag:'td', children:[
206 {tag:'div', id:this.getId('registration_submit')}
207 ]}
208 ]}
209 ]},
210 {tag:'tfoot'}
211 ]}
212 ]},
213 {tag:'div', cls:'loginFormFooterBox', children:[
214 {tag:'ul', children:[
215 {tag:'li', children:[
216 {tag:'span', htmlString:Clipperz.PM.Strings['registrationFormDoYouAlreadyHaveAnAccountLabel']},
217 {tag:'a', href:'.', id:this.getId('showLogin'), cls:'clipperzActionLink', htmlString:Clipperz.PM.Strings['registrationFormSimplyLoginLabel']}
218 ]}
219 ]}
220 ]}
221 ]}
222]},
223 {tag:'div', cls:'loginPanelSwitchLanguageBox', children:[
224 {tag:'div', cls:'loginPanelSwitchLanguageDescription', htmlString:Clipperz.PM.Strings['loginPanelSwithLanguageDescription']},
225 {tag:'div', cls:'loginPanelSwitchLanguageSelect', children:[
226 {tag:'select', id:this.getId('languageSelector'), children:Clipperz.PM.Strings['loginPanelSwitchLanguageSelectOptions']}
227 ]}
228 ]},
229 {tag:'div', cls:'browserCompatibilityBox', htmlString:Clipperz.PM.Strings['browserCompatibilityDescription']}
230 ]}
231 ]}
232 ]}
233 ]}
234 ]});
235
236 MochiKit.Signal.connect(this.getId('loginForm_form'), 'onsubmit', function(e){e.stop();});
237 MochiKit.Signal.connect(this.getId('registrationForm_form'), 'onsubmit', function(e){e.stop();});
238
239 MochiKit.Signal.connect(this.getId('showRegistration'), 'onclick', this, 'showRegistrationFormEventHandler');
240 MochiKit.Signal.connect(this.getId('showLogin'), 'onclick', this, 'showLoginFormEventHandler');
241
242 new YAHOO.ext.Button(this.getId('login_submit'), {text:Clipperz.PM.Strings['loginFormButtonLabel'], handler:this.doLogin, scope:this, minWidth:0});
243 registerButton = new YAHOO.ext.Button(this.getId('registration_submit'), {text:Clipperz.PM.Strings['registrationFormButtonLabel'], handler:this.doRegister, scope:this, minWidth:0})
244
245 if (Clipperz.PM.Proxy.defaultProxy.isReadOnly()) {
246 // this.getElement('showRegistrationLI').setVisibilityMode(YAHOO.ext.Element.DISPLAY).hide();
247 this.getElement('registrationForm_form').addClass('read-only');
248 registerButton.disable();
249 this.getElement('passwordTypeChooserTR').addClass('read-only');
250 this.getDom('useOneTimePasswordCheckbox').disabled = true;
251 }
252
253 MochiKit.Signal.connect(this.getId('loginForm'), 'onkeydown', this, 'onkeydown');
254 MochiKit.Signal.connect(this.getId('registrationForm'), 'onkeydown', this, 'onkeydown');
255 // MochiKit.Signal.connect(this.getId('useOneTimePasswordCheckbox'), 'onchange', this, 'renderPasswordField');
256 MochiKit.Signal.connect(this.getId('useOneTimePasswordCheckbox'), 'onclick', this, 'renderPasswordField');
257 this.renderPasswordField();
258
259 this.selectSelectedLanguageOption();
260 MochiKit.Signal.connect(this.getId('languageSelector'), 'onchange', this, 'switchLanguage');
261
262 MochiKit.Signal.connect(this.getId('oneTimePassword_1'), 'onkeypress', this, 'handleOneTimePasswordFieldKeyPress');
263 MochiKit.Signal.connect(this.getId('oneTimePassword_2'), 'onkeypress', this, 'handleOneTimePasswordFieldKeyPress');
264 MochiKit.Signal.connect(this.getId('oneTimePassword_3'), 'onkeypress', this, 'handleOneTimePasswordFieldKeyPress');
265 MochiKit.Signal.connect(this.getId('oneTimePassword_4'), 'onkeypress', this, 'handleOneTimePasswordFieldKeyPress');
266
267 MochiKit.Signal.connect(this.getId('oneTimePassword_1'), 'onkeyup', this, 'handleOneTimePasswordFieldKeyUp');
268 MochiKit.Signal.connect(this.getId('oneTimePassword_2'), 'onkeyup', this, 'handleOneTimePasswordFieldKeyUp');
269 MochiKit.Signal.connect(this.getId('oneTimePassword_3'), 'onkeyup', this, 'handleOneTimePasswordFieldKeyUp');
270 MochiKit.Signal.connect(this.getId('oneTimePassword_4'), 'onkeyup', this, 'handleOneTimePasswordFieldKeyUp');
271
272 new Clipperz.PM.Components.PasswordEntropyDisplay(this.getElement('login_passphrase'));
273 new Clipperz.PM.Components.PasswordEntropyDisplay(this.getElement('registration_passphrase'));
274//MochiKit.Logging.logDebug("<<< LoginPanel.initPanel");
275
276 return result;
277 },
278
279 //-------------------------------------------------------------------------
280
281 'renderPasswordField': function() {
282 if (this.getDom('useOneTimePasswordCheckbox').checked == false) {
283 this.getElement('oneTimePasswordDIV').setVisibilityMode(YAHOO.ext.Element.DISPLAY).hide(false);
284 this.getElement('passphraseDIV').setVisibilityMode(YAHOO.ext.Element.DISPLAY).show(false);
285 this.getElement('login_passphrase').focus();
286 } else {
287 this.getElement('passphraseDIV').setVisibilityMode(YAHOO.ext.Element.DISPLAY).hide();
288 this.getElement('oneTimePasswordDIV').setVisibilityMode(YAHOO.ext.Element.DISPLAY).show();
289 this.getElement('oneTimePassword_1').focus();
290 }
291
292 },
293
294 //.........................................................................
295
296 'handleOneTimePasswordFieldKeyPress': function(anEvent) {
297 if (anEvent.key().string == '-') {
298 switch (anEvent.src().id) {
299 case this.getId('oneTimePassword_1'):
300 this.getElement('oneTimePassword_2').focus();
301 break;
302 case this.getId('oneTimePassword_2'):
303 this.getElement('oneTimePassword_3').focus();
304 break;
305 case this.getId('oneTimePassword_3'):
306 this.getElement('oneTimePassword_4').focus();
307 break;
308 }
309
310 anEvent.stop();
311 }
312 },
313
314/*
315 var ctrl = document.getElementById("txtTargetText");
316 var saveText = ctrl.value;
317 ctrl.focus();
318
319 var range = document.selection.createRange();
320 var specialchar = String.fromCharCode(1);
321 range.text = specialchar;
322 var pos = ctrl.value.indexOf(specialchar);
323 ctrl.value = saveText;
324 range = ctrl.createTextRange();
325 range.move('character', pos);
326 range.select();
327 range.text =
328 document.getElementById("txtSourceText").value;
329 document.getElementById("txtTargetText").focus();
330 window.event.returnValue = false;
331*/
332
333 'handleOneTimePasswordFieldKeyUp': function(anEvent) {
334 varfield;
335 varfieldValue;
336 var key;
337
338//console.log("keyUp", anEvent);
339 field = anEvent.src();
340 fieldValue = field.value;
341 key = anEvent.key();
342
343 // &&(key.string != 'KEY_TAB')
344 // &&(key.string != 'KEY_SHIFT')
345 // &&(key.string != 'KEY_BACKSPACE')
346 // &&(key.string != 'KEY_DELETE')
347 // &&(key.string.indexOf('KEY_ARROW') != 0)
348
349
350 if ((fieldValue.replace(/\s/g, '').length == 8) && (key.string == 'KEY_SPACEBAR')) {
351 // field.value = Clipperz.Base.trim(fieldValue).replace(/.{4}/g, '$&' + ' ');
352
353 switch (field.id) {
354 case this.getId('oneTimePassword_1'):
355 this.getElement('oneTimePassword_2').focus();
356 break;
357 case this.getId('oneTimePassword_2'):
358 this.getElement('oneTimePassword_3').focus();
359 break;
360 case this.getId('oneTimePassword_3'):
361 this.getElement('oneTimePassword_4').focus();
362 break;
363 }
364 // } else if (fieldValue.replace(/\s/g, '').length > 8) {
365 }
366
367//MochiKit.Logging.logDebug("-- fieldValue: " + fieldValue);
368 },
369
370 //.........................................................................
371
372 'doLogin': function() {
373//MochiKit.Logging.logDebug(">>> LoginPanel.doLogin");
374 if (this.checkLoginForm()) {
375 if (this.getDom('useOneTimePasswordCheckbox').checked == false) {
376 this.doLoginWithUsernameAndPassphrase(this.getDom('login_username').value, this.getDom('login_passphrase').value);
377 } else {
378 varoneTimePasswordValue;
379
380 oneTimePasswordValue = this.getDom('oneTimePassword_1').value + this.getDom('oneTimePassword_2').value + this.getDom('oneTimePassword_3').value + this.getDom('oneTimePassword_4').value;
381 this.doLoginWithUsernameAndOneTimePassword(this.getDom('login_username').value, oneTimePasswordValue);
382 }
383 }
384//MochiKit.Logging.logDebug("<<< LoginPanel.doLogin");
385 },
386
387 //.........................................................................
388
389 'doLoginWithUsernameAndPassphrase': function(anUsername, aPassphrase) {
390 var deferredResult;
391 var user;
392 var loginPanel;
393
394//MochiKit.Logging.logDebug(">>> LoginPanel.doLoginWithUsernameAndPassphrase");
395 user = new Clipperz.PM.DataModel.User({username:anUsername, passphrase:aPassphrase});
396 loginPanel = this;
397
398 deferredResult = new MochiKit.Async.Deferred();
399//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("0 - LoginPanel.doLogin - 0: "/* + res*/); return res;});
400//deferredResult.addErrback(function(res) {MochiKit.Logging.logDebug("ERROR: " + res); return res;});
401 deferredResult.addCallback(MochiKit.Base.method(Clipperz.PM.Components.MessageBox(), 'deferredShow'),
402 {
403 title: "",
404 text: "",
405 width:240,
406 showProgressBar:true,
407 showCloseButton:false,
408 fn:MochiKit.Base.method(deferredResult, 'cancel'),
409 scope:this
410 },
411 this.getDom('login_submit')
412 );
413//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("1 - LoginPanel.doLogin - 1: "/* + res*/); return res;});
414//deferredResult.addErrback(function(res) {MochiKit.Logging.logDebug("ERROR: " + res); return res;});
415 deferredResult.addCallback(Clipperz.NotificationCenter.deferredNotification, this, 'updatedProgressState', 'login_start');
416//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("2 - LoginPanel.doLogin - 2: "/* + res*/); return res;});
417//deferredResult.addErrback(function(res) {MochiKit.Logging.logDebug("ERROR: " + res); return res;});
418 deferredResult.addCallback(MochiKit.Base.method(user, 'connect'));
419//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("3 - LoginPanel.doLogin - 3: "/* + res*/); return res;});
420//deferredResult.addErrback(function(res) {MochiKit.Logging.logDebug("ERROR: " + res); return res;});
421 deferredResult.addCallback(Clipperz.NotificationCenter.deferredNotification, this, 'updatedProgressState', 'connection_done');
422//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("4 - LoginPanel.doLogin - 4: "/* + res*/); return res;});
423//deferredResult.addErrback(function(res) {MochiKit.Logging.logDebug("ERROR: " + res); return res;});
424 deferredResult.addCallback(Clipperz.NotificationCenter.deferredNotification, this, 'updatedProgressState', 'connection_loadingUserData');
425//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("5 - LoginPanel.doLogin - 5: "/* + res*/); return res;});
426//deferredResult.addErrback(function(res) {MochiKit.Logging.logDebug("ERROR: " + res); return res;});
427 deferredResult.addCallback(MochiKit.Base.method(user, 'loadPreferences'));
428//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("6 - LoginPanel.doLogin - 6: "/* + res*/); return res;});
429//deferredResult.addErrback(function(res) {MochiKit.Logging.logDebug("ERROR: " + res); return res;});
430 deferredResult.addCallback(MochiKit.Base.method(user, 'loadRecords'));
431//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("7 - LoginPanel.doLogin - 7: "/* + res*/); return res;});
432//deferredResult.addErrback(function(res) {MochiKit.Logging.logDebug("ERROR: " + res); return res;});
433 deferredResult.addCallback(MochiKit.Base.method(user, 'loadDirectLogins'));
434//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("8 - LoginPanel.doLogin - 8: "/* + res*/); return res;});
435//deferredResult.addErrback(function(res) {MochiKit.Logging.logDebug("ERROR: " + res); return res;});
436 deferredResult.addCallback(Clipperz.NotificationCenter.deferredNotification, this, 'updatedProgressState', 'login_connected');
437//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("9 - LoginPanel.doLogin - 9: "/* + res*/); return res;});
438//deferredResult.addErrback(function(res) {MochiKit.Logging.logDebug("ERROR: " + res); return res;});
439 deferredResult.addCallback(Clipperz.NotificationCenter.deferredNotification, user, 'setupDone', null);
440//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("10 - LoginPanel.doLogin - 10: "/* + res*/); return res;});
441//deferredResult.addErrback(function(res) {MochiKit.Logging.logDebug("ERROR: " + res); return res;});
442
443 deferredResult.addCallback(MochiKit.Async.wait, 0.5);
444//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("11 - LoginPanel.doLogin - 11: "/* + res*/); return res;});
445//deferredResult.addErrback(function(res) {MochiKit.Logging.logDebug("ERROR: " + res); return res;});
446
447 deferredResult.addCallback(function(res) {
448 Clipperz.PM.Components.MessageBox().hide(YAHOO.ext.Element.get('main'));
449 return res;
450 });
451//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("12 - LoginPanel.doLogin - 12: "/* + res*/); return res;});
452//deferredResult.addErrback(function(res) {MochiKit.Logging.logDebug("ERROR: " + res); return res;});
453
454 deferredResult.addErrback(MochiKit.Base.bind(function() {
455 Clipperz.PM.Components.MessageBox().update({
456 title:Clipperz.PM.Strings['loginMessagePanelFailureTitle'],
457 text:Clipperz.PM.Strings['loginMessagePanelFailureText'],
458 showProgressBar:false,
459 buttons:{'ok':Clipperz.PM.Strings['loginMessagePanelFailureButtonLabel']},
460 fn:MochiKit.Base.bind(function() {
461 this.getElement('login_passphrase').focus();
462 this.getElement('login_passphrase').dom.select();
463 }, this),
464 scope:this
465 });
466 }, this));
467//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("13 - LoginPanel.doLogin - 13: "/* + res*/); return res;});
468//deferredResult.addErrback(function(res) {MochiKit.Logging.logDebug("ERROR: " + res); return res;});
469
470 deferredResult.callback("token");
471//MochiKit.Logging.logDebug("<<< LoginPanel.doLoginWithUsernameAndPassphrase");
472
473 return deferredResult;
474 },
475
476 //.........................................................................
477
478 'doLoginWithUsernameAndOneTimePassword': function(anUsername, aOneTimePassword) {
479 var deferredResult;
480 var loginPanel;
481 var oneTimePassword;
482
483 oneTimePassword = Clipperz.PM.DataModel.OneTimePassword.normalizedOneTimePassword(aOneTimePassword);
484
485//MochiKit.Logging.logDebug(">>> LoginPanel.doLoginWithUsernameAndPassphrase");
486 deferredResult = new MochiKit.Async.Deferred();
487 deferredResult.addCallback(MochiKit.Base.method(Clipperz.PM.Components.MessageBox(), 'deferredShow'),
488 {
489 title: "",
490 text: "",
491 width:240,
492 showProgressBar:true,
493 showCloseButton:false,
494 fn:MochiKit.Base.method(deferredResult, 'cancel'),
495 scope:this,
496 steps:7,
497 buttons:{
498 //'ok':Clipperz.PM.Strings['loginMessagePanelInitialButtonLabel']
499 }
500 },
501 this.getDom('login_submit')
502 );
503 deferredResult.addCallback(Clipperz.NotificationCenter.deferredNotification, this, 'updatedProgressState', 'OTP_login_start');
504 deferredResult.addCallback(function(anUsername, aOneTimePassword) {
505 var args;
506
507 args = {
508 'message': 'oneTimePassword',
509 'version': Clipperz.PM.Crypto.communicationProtocol.currentVersion,
510 'parameters': {
511 'oneTimePasswordKey': Clipperz.PM.DataModel.OneTimePassword.computeKeyWithUsernameAndPassword(anUsername, aOneTimePassword),
512 'oneTimePasswordKeyChecksum': Clipperz.PM.DataModel.OneTimePassword.computeKeyChecksumWithUsernameAndPassword(anUsername, aOneTimePassword)
513 }
514 }
515
516 return args;
517 }, anUsername, oneTimePassword);
518 deferredResult.addCallback(Clipperz.NotificationCenter.deferredNotification, this, 'updatedProgressState', 'OTP_login_loadingOTP');
519 deferredResult.addCallback(MochiKit.Base.method(Clipperz.PM.Proxy.defaultProxy, 'handshake'));
520 deferredResult.addCallback(Clipperz.NotificationCenter.deferredNotification, this, 'updatedProgressState', 'OTP_login_extractingPassphrase');
521 deferredResult.addCallback(function(aResult) {
522 return Clipperz.PM.Crypto.deferredDecrypt(oneTimePassword, aResult['data'], aResult['version']);
523 });
524//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("LoginPanel.otpLogin - 4: " + res); return res;});
525 deferredResult.addCallback(function(aResult) {
526 //MochiKit.Logging.logDebug("aResult")
527 return (new Clipperz.ByteArray().appendBase64String(aResult['passphrase'])).asString();
528 });
529//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("LoginPanel.otpLogin - 5: " + res); return res;});
530 deferredResult.addCallbacks(
531 MochiKit.Base.method(this, 'doLoginWithUsernameAndPassphrase', anUsername),
532 MochiKit.Base.bind(function(aLoginPanel) {
533 Clipperz.PM.Components.MessageBox().update({
534 title:Clipperz.PM.Strings['loginMessagePanelFailureTitle'],
535 text:Clipperz.PM.Strings['loginMessagePanelFailureText'],
536 showProgressBar:false,
537 buttons:{'ok':Clipperz.PM.Strings['loginMessagePanelFailureButtonLabel']},
538 fn:MochiKit.Base.bind(function() {
539 this.getElement('oneTimePassword_1').focus();
540 }, this),
541 scope:aLoginPanel
542 });
543 }, this)
544 );
545//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("LoginPanel.otpLogin - 6: " + res); return res;});
546 deferredResult.callback("token");
547//MochiKit.Logging.logDebug("<<< LoginPanel.doLoginWithUsernameAndPassphrase");
548
549 return deferredResult;
550 },
551
552 //.........................................................................
553
554 'checkLoginForm': function() {
555 var result;
556 var username
557
558 result = true;
559
560//MochiKit.Logging.logDebug(">>> checkLoginForm");
561 username = Clipperz.Base.trim(this.getDom('login_username').value);
562 if (username == "") {
563 this.getElement('login_username').focus();
564 result = false;
565 } else {
566 if (this.getDom('useOneTimePasswordCheckbox').checked == false) {
567 varpassphrase;
568
569 passphrase = Clipperz.Base.trim(this.getDom('login_passphrase').value);
570
571 if (passphrase == "") {
572 this.getElement('login_passphrase').focus();
573 result = false;
574 }
575 } else {
576 if (Clipperz.Base.trim(this.getDom('oneTimePassword_1').value) == "") {
577 this.getElement('oneTimePassword_1').focus();
578 result = false;
579 } else if (Clipperz.Base.trim(this.getDom('oneTimePassword_2').value) == "") {
580 this.getElement('oneTimePassword_2').focus();
581 result = false;
582 } else if (Clipperz.Base.trim(this.getDom('oneTimePassword_3').value) == "") {
583 this.getElement('oneTimePassword_3').focus();
584 result = false;
585 } else if (Clipperz.Base.trim(this.getDom('oneTimePassword_4').value) == "") {
586 this.getElement('oneTimePassword_4').focus();
587 result = false;
588 }
589 }
590 }
591//MochiKit.Logging.logDebug("<<< checkLoginForm - " + result);
592
593 return result;
594 },
595
596 //.........................................................................
597
598 'doRegister': function(anEvent) {
599 if ((Clipperz.PM.Proxy.defaultProxy.isReadOnly() == false) && (this.checkRegistrationForm())) {
600 this.doRegistrationWithUsernameAndPassphrase(this.getDom('registration_username').value, this.getDom('registration_passphrase').value /*, this.getDom('registration_invitationCode').value*/);
601 }
602 },
603
604 //.........................................................................
605
606 'checkRegistrationForm': function() {
607 var result;
608 var username
609 varpassphrase;
610 varrePassphrase;
611 varsafetyCheck;
612 vartermsOfServiceCheck;
613 // varinvitationCode;
614
615 username = this.getDom('registration_username').value;
616 passphrase = this.getDom('registration_passphrase').value;
617 rePassphrase = this.getDom('registration_repassphrase').value;
618 safetyCheck = this.getDom('registration_check').checked;
619 termsOfServiceCheck = this.getDom('registration_termsOfServiceCheck').checked;
620 // invitationCode = this.getDom('registration_invitationCode').value;
621
622 if ((username != "") && (passphrase != "") && (rePassphrase != "") /*&& (invitationCode != "")*/) {
623 if (passphrase != rePassphrase) {
624 //show alert that the passphrase and rePassphrase should be equal
625//MochiKit.Logging.logDebug("WARNING: passphrase != rePassphrase");
626 this.showRegistrationFormErrorMessageAnimation(Clipperz.PM.Strings['registrationFormWarningMessageNotMatchingPassphrases']);
627 this.getElement('registration_repassphrase').focus().dom.select();
628 // this.getElement('registration_repassphrase').select();
629 result = false;
630 } else if (safetyCheck != true) {
631 //show alert that the safetyCheck should be checed
632//MochiKit.Logging.logDebug("WARNING: safetyCheck not checked");
633 this.showRegistrationFormErrorMessageAnimation(Clipperz.PM.Strings['registrationFormWarningMessageSafetyCheckNotSelected']);
634 this.getElement('registration_check').focus();
635 result = false;
636 } else if (termsOfServiceCheck != true) {
637 this.showRegistrationFormErrorMessageAnimation(Clipperz.PM.Strings['registrationFormWarningMessageTermsOfServiceCheckNotSelected']);
638 this.getElement('registration_termsOfServiceCheck').focus();
639 } else {
640 result = true;
641 }
642 } else {
643 if (username == "") {
644 this.getElement('registration_username').focus();
645 } else if (passphrase == "") {
646 this.getElement('registration_passphrase').focus();
647 } else if (rePassphrase == "") {
648 this.getElement('registration_repassphrase').focus();
649 // } else if (invitationCode == "") {
650 // this.showRegistrationFormErrorMessageAnimation(Clipperz.PM.Strings['registrationFormWarningMessageInvitationCodeMissing']);
651 // this.getElement('registration_invitationCode').focus();
652 }
653
654 result = false;
655 }
656
657 if (result === true) {
658 this.getActor('registration_errorMessage').hide();
659 }
660
661 return result;
662 },
663
664 //.........................................................................
665
666 'showRegistrationFormErrorMessageAnimation': function(anErrorMessage, aCallback) {
667 varerrorMessageActor;
668
669 errorMessageActor = this.getActor('registration_errorMessage');
670 errorMessageActor.update(anErrorMessage);
671 errorMessageActor.show(true);
672 errorMessageActor.play(aCallback);
673 },
674
675 //.........................................................................
676
677 'doRegistrationWithUsernameAndPassphrase': function(anUsername, aPassphrase /*, anInvitationCode */) {
678 var deferredResult;
679 var user;
680 var loginPanel;
681
682//MochiKit.Logging.logDebug(">>> LoginPanel.doRegistrationWithUsernameAndPassphrase");
683 user = new Clipperz.PM.DataModel.User({username:anUsername, passphrase:aPassphrase});
684//MochiKit.Logging.logDebug("--- LoginPanel.doRegistrationWithUsernameAndPassphrase - 1");
685 loginPanel = this;
686//MochiKit.Logging.logDebug("--- LoginPanel.doRegistrationWithUsernameAndPassphrase - 2");
687
688 deferredResult = new MochiKit.Async.Deferred();
689//MochiKit.Logging.logDebug("--- LoginPanel.doRegistrationWithUsernameAndPassphrase - 3");
690//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("LoginPanel.doRegistrationWithUsernameAndPassphrase - 1: " + res); return res;});
691 deferredResult.addCallback(MochiKit.Base.method(Clipperz.PM.Components.MessageBox(), 'deferredShow'),
692 {
693 title:Clipperz.PM.Strings['registrationMessagePanelInitialTitle'],
694 text: Clipperz.PM.Strings['registrationMessagePanelInitialText'],
695 width:240,
696 showProgressBar:true,
697 showCloseButton:false,
698 fn:MochiKit.Base.method(deferredResult, 'cancel'),
699 scope:this,
700 steps:9,
701 buttons:{
702 'ok':Clipperz.PM.Strings['registrationMessagePanelInitialButtonLabel']
703 }
704 },
705 this.getDom('registration_submit')
706 );
707//MochiKit.Logging.logDebug("--- LoginPanel.doRegistrationWithUsernameAndPassphrase - 4");
708//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("LoginPanel.doRegistrationWithUsernameAndPassphrase - 2: " + res); return res;});
709 deferredResult.addCallback(MochiKit.Base.method(user, 'register'), /*anInvitationCode*/ "VeryBraveBetaTester");
710//MochiKit.Logging.logDebug("--- LoginPanel.doRegistrationWithUsernameAndPassphrase - 5");
711//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("LoginPanel.doRegistrationWithUsernameAndPassphrase - 3: " + res); return res;});
712 deferredResult.addCallback(function(res) {
713 Clipperz.PM.Components.MessageBox().update({
714 title:Clipperz.PM.Strings['registrationMessagePanelRegistrationDoneTitle'],
715 text:Clipperz.PM.Strings['registrationMessagePanelRegistrationDoneText'],
716 step:'next'
717 });
718 return res;
719 });
720//MochiKit.Logging.logDebug("--- LoginPanel.doRegistrationWithUsernameAndPassphrase - 6");
721//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("LoginPanel.doRegistrationWithUsernameAndPassphrase - 5: " + res); return res;});
722 deferredResult.addCallback(MochiKit.Async.wait, 1);
723//MochiKit.Logging.logDebug("--- LoginPanel.doRegistrationWithUsernameAndPassphrase - 7");
724//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("LoginPanel.doRegistrationWithUsernameAndPassphrase - 6: " + res); return res;});
725 deferredResult.addCallback(MochiKit.Base.method(user, 'connect'));
726//MochiKit.Logging.logDebug("--- LoginPanel.doRegistrationWithUsernameAndPassphrase - 8");
727//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("LoginPanel.doRegistrationWithUsernameAndPassphrase - 7: " + res); return res;});
728 deferredResult.addCallback(MochiKit.Async.wait, 1);
729//MochiKit.Logging.logDebug("--- LoginPanel.doRegistrationWithUsernameAndPassphrase - 9");
730//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("LoginPanel.doRegistrationWithUsernameAndPassphrase - 8: " + res); return res;});
731 deferredResult.addCallback(function(res) {
732 Clipperz.PM.Components.MessageBox().hide(YAHOO.ext.Element.get('main'));
733 return res;
734 });
735 deferredResult.addCallback(MochiKit.Base.method(this, 'showRegistrationSplashScreen'), user);
736//MochiKit.Logging.logDebug("--- LoginPanel.doRegistrationWithUsernameAndPassphrase - 10");
737//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("LoginPanel.doRegistrationWithUsernameAndPassphrase - 9: " + res); return res;});
738 deferredResult.addErrback(function(anError) {
739 Clipperz.PM.Components.MessageBox().update({
740 title:Clipperz.PM.Strings['registrationMessagePanelFailureTitle'],
741 text:anError.message,
742 showProgressBar:false,
743 buttons:{'ok':Clipperz.PM.Strings['registrationMessagePanelFailureButtonLabel']}});
744 return anError;
745 });
746//MochiKit.Logging.logDebug("--- LoginPanel.doRegistrationWithUsernameAndPassphrase - 11");
747//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("LoginPanel.doRegistrationWithUsernameAndPassphrase - 10: " + res); return res;});
748 deferredResult.addCallback(Clipperz.NotificationCenter.deferredNotification, user, 'setupDone', null);
749 deferredResult.callback("token");
750//MochiKit.Logging.logDebug("--- LoginPanel.doRegistrationWithUsernameAndPassphrase - 12");
751
752 return deferredResult;
753 },
754
755 //-------------------------------------------------------------------------
756
757 'showRegistrationSplashScreen': function(anUser) {
758 var deferredResult;
759 var alertElement;
760 varalertDialog;
761 var closeButton;
762 var closeFunction;
763
764 deferredResult = new MochiKit.Async.Deferred();
765
766//MochiKit.Logging.logDebug(">>> Main.showRegistrationSplashScreen");
767 alertElement = Clipperz.YUI.DomHelper.append(document.body, {tag:'div', id:'registrationSplash', children:[
768 {tag:'div', cls:'ydlg-hd', htmlString:Clipperz.PM.Strings['registrationSplashPanelTitle']},
769 {tag:'div', cls:'ydlg-bd', children:[
770 {tag:'div', cls:'alert-message', id:'splashMessage', children:[
771 {tag:'div', htmlString:Clipperz.PM.Strings['registrationSplashPanelDescription']},
772 {tag:'table', border:'0', cellpadding:'5', children:[
773 {tag:'tbody', children:[
774 {tag:'tr', children:[
775 {tag:'td', valign:'top', children:[
776 {tag:'span', cls:'label', htmlString:Clipperz.PM.Strings['registrationSplashPanelUsernameLabel']}
777 ]},
778 {tag:'td', valign:'top', children:[
779 {tag:'span', cls:'value', html:Clipperz.Base.escapeHTML(anUser.username())}
780 ]}
781 ]},
782 {tag:'tr', children:[
783 {tag:'td', valign:'top', children:[
784 {tag:'span', cls:'label', htmlString:Clipperz.PM.Strings['registrationSplashPanelPassphraseLabel']}
785 ]},
786 {tag:'td', valign:'top', children:[
787 {tag:'div', id:this.getId('showPassphraseDiv'), children:[
788 {tag:'span', cls:'value', html:Clipperz.Base.escapeHTML(anUser.passphrase())}
789 ]},
790 {tag:'div', id:this.getId('hidePassphraseDiv'), cls:'Clipperz_recordFieldData', children:[
791 {tag:'input', id:this.getId('passwordField'), type:'text', cls:'scrambledField', title:Clipperz.PM.Strings['recordDetailPasswordFieldTooltipLabel'], value:"anUser.passphrase()"}
792 ]}
793 ]}
794 ]},
795 {tag:'tr', children:[
796 {tag:'td'},
797 {tag:'td', valign:'top', children:[
798 // {tag:'a', href:"#", id:this.getId('togglePassphraseVisibility'), htmlString:Clipperz.PM.Strings['registrationSplashPanelShowPassphraseButtonLabel']}
799 {tag:'input', type:'checkbox', id:this.getId('showPassphraseCheckbox')},
800 {tag:'span', cls:'activeText', id:this.getId('showPassphraseText'), htmlString:Clipperz.PM.Strings['registrationSplashPanelShowPassphraseButtonLabel']}
801 ]}
802 ]}
803 ]}
804 ]}
805 ]}
806 ]},
807 {tag:'div', cls:'ydlg-ft'}
808 ]}, true);
809//MochiKit.Logging.logDebug("--- Main.showRegistrationSplashScreen - 1");
810
811 this.getElement('passwordField').dom.value = anUser.passphrase();
812 this.getElement('passwordField').wrap({tag:'div', cls:'passwordBackground'}).setStyle('background-position', "0px -" + Math.min(128, Clipperz.PM.Crypto.passwordEntropy(anUser.passphrase())) + "px").setStyle('width', '71px');
813 MochiKit.Signal.connect(this.getId('showPassphraseCheckbox'), 'onclick', this, 'togglePassphraseVisibility');
814 MochiKit.Signal.connect(this.getId('showPassphraseText'), 'onclick', this, 'togglePassphraseCheckbox');
815//MochiKit.Logging.logDebug("--- Main.showRegistrationSplashScreen - 1.1");
816
817 this.getElement('showPassphraseDiv').setVisibilityMode(YAHOO.ext.Element.DISPLAY);
818 this.getElement('hidePassphraseDiv').setVisibilityMode(YAHOO.ext.Element.DISPLAY);
819//MochiKit.Logging.logDebug("--- Main.showRegistrationSplashScreen - 1.1.1");
820 this.togglePassphraseVisibility();
821//MochiKit.Logging.logDebug("--- Main.showRegistrationSplashScreen - 1.2");
822
823 alertDialog = new YAHOO.ext.BasicDialog(
824 alertElement, {
825 closable:false,
826 modal:true,
827 autoTabs:false,
828 resizable:false,
829 fixedcenter:true,
830 constraintoviewport:false,
831 width:450,
832 height:220,
833 shadow:true,
834 minWidth:300,
835 minHeight:300
836 }
837 );
838//MochiKit.Logging.logDebug("--- Main.showRegistrationSplashScreen - 2");
839
840 closeFunction = deferredResult.callback;
841//MochiKit.Logging.logDebug("--- Main.showRegistrationSplashScreen - 3");
842 alertDialog.addKeyListener(27, closeFunction);
843//MochiKit.Logging.logDebug("--- Main.showRegistrationSplashScreen - 4");
844 closeButton = alertDialog.addButton(Clipperz.PM.Strings['splashAlertCloseButtonLabel'], closeFunction, deferredResult);
845//MochiKit.Logging.logDebug("--- Main.showRegistrationSplashScreen - 5");
846 alertDialog.setDefaultButton(closeButton);
847//MochiKit.Logging.logDebug("--- Main.showRegistrationSplashScreen - 6");
848 alertDialog.show('main');
849//MochiKit.Logging.logDebug("--- Main.showRegistrationSplashScreen - 7");
850
851 deferredResult.addBoth(MochiKit.Base.method(alertDialog, 'hide'));
852 deferredResult.addCallback(MochiKit.Signal.disconnectAllTo, this)
853//MochiKit.Logging.logDebug("--- Main.showRegistrationSplashScreen - 8");
854 deferredResult.addCallback(MochiKit.Async.succeed);
855//MochiKit.Logging.logDebug("<<< Main.showRegistrationSplashScreen");
856
857 return deferredResult;
858 },
859
860 //-------------------------------------------------------------------------
861
862 'showLoginFormEventHandler': function(anEvent) {
863 anEvent.stop();
864 this.showLoginForm(true);
865 },
866
867 'showLoginForm': function(shouldAnimate) {
868 if (shouldAnimate) {
869 this.showLoginFormAnimator().play();
870 } else {
871 this.hideRegistrationForm(false);
872 this.getActor('loginForm').show(false);
873 this.getElement('login_username').focus();
874 }
875 this.setVisibleForm('login');
876 },
877
878 'showLoginFormAnimator': function() {
879 if (this._showLoginFormAnimator == null) {
880 var animator;
881 varloginFormActor;
882 var registrationFormActor;
883 var usernameFieldActor;
884
885 animator = new YAHOO.ext.Animator();
886 loginFormActor = this.getActor('loginForm', animator);
887 loginFormActor.setVisibilityMode(YAHOO.ext.Element.DISPLAY);
888 registrationFormActor = this.getActor('registrationForm', animator);
889 registrationFormActor.setVisibilityMode(YAHOO.ext.Element.DISPLAY);
890 usernameFieldActor = this.getActor('login_username', animator);
891
892 animator.startCapture();
893 registrationFormActor.hide(true);
894 loginFormActor.show(true);
895 usernameFieldActor.focus();
896 animator.stopCapture();
897
898 this._showLoginFormAnimator = animator;
899 }
900
901 return this._showLoginFormAnimator;
902 },
903
904
905 'hideLoginForm': function(shouldAnimate) {
906 var loginFormActor;
907
908 loginFormActor = this.getActor('loginForm');
909 loginFormActor.setVisibilityMode(YAHOO.ext.Element.DISPLAY);
910 loginFormActor.hide(shouldAnimate);
911 },
912
913 //-------------------------------------------------------------------------
914
915 'showRegistrationFormEventHandler': function(anEvent) {
916 anEvent.stop();
917 this.showRegistrationForm(true);
918 },
919
920 'showRegistrationForm': function(shouldAnimate) {
921 if (shouldAnimate) {
922 this.showRegistrationFormAnimator().play(MochiKit.Base.bind(this.showRegistrationAlert, this));
923 } else {
924 varerrorMessageActor;
925
926 this.hideLoginForm(shouldAnimate)
927 this.getActor('registrationForm').show(false);
928 this.getElement('registration_username').focus();
929
930 errorMessageActor = this.getActor('registration_errorMessage');
931 errorMessageActor.setVisibilityMode(YAHOO.ext.Element.DISPLAY);
932 errorMessageActor.update("---");
933 errorMessageActor.hide();
934
935 this.showRegistrationAlert();
936 }
937 this.setVisibleForm('registration');
938 },
939
940 'showRegistrationFormAnimator': function() {
941 if (this._showRegistrationFormAnimator == null) {
942 var animator;
943 varloginFormActor;
944 var registrationFormActor;
945 var usernameFieldActor;
946 varerrorMessageActor;
947
948 animator = new YAHOO.ext.Animator();
949 loginFormActor = this.getActor('loginForm', animator);
950 loginFormActor.setVisibilityMode(YAHOO.ext.Element.DISPLAY);
951 registrationFormActor = this.getActor('registrationForm', animator);
952 registrationFormActor.setVisibilityMode(YAHOO.ext.Element.DISPLAY);
953 usernameFieldActor = this.getActor('registration_username', animator);
954 errorMessageActor = this.getActor('registration_errorMessage', animator);
955 errorMessageActor.setVisibilityMode(YAHOO.ext.Element.DISPLAY);
956
957 animator.startCapture();
958 loginFormActor.hide(true);
959 errorMessageActor.update("---");
960 errorMessageActor.hide();
961 registrationFormActor.show(true);
962 usernameFieldActor.focus();
963 animator.stopCapture();
964
965 this._showRegistrationFormAnimator = animator;
966 }
967
968 return this._showRegistrationFormAnimator;
969 },
970
971 'hideRegistrationForm': function(shouldAnimate) {
972 var registrationFormActor;
973
974 registrationFormActor = this.getActor('registrationForm');
975 registrationFormActor.setVisibilityMode(YAHOO.ext.Element.DISPLAY);
976 registrationFormActor.hide(shouldAnimate);
977 },
978
979 //-------------------------------------------------------------------------
980
981 'shouldShowRegistrationAlert': function() {
982 return this._shouldShowRegistrationAlert;
983 },
984
985 'showRegistrationAlert': function() {
986 if ((this.shouldShowRegistrationAlert()) && (Clipperz.PM.Proxy.defaultProxy.isReadOnly() == false)) {
987 var alertElement;
988 varalertDialog;
989 var closeButton;
990 var closeFunction;
991
992 alertElement = Clipperz.YUI.DomHelper.append(document.body, {tag:'div', id:'alert', children:[
993 {tag:'div', cls:'ydlg-hd', htmlString:Clipperz.PM.Strings['splashAlertTitle']},
994 {tag:'div', cls:'ydlg-bd', children:[
995 {tag:'div', cls:'alert-message', id:'splashMessage', htmlString:Clipperz.PM.Strings['splashAlertText']}
996 ]},
997 {tag:'div', cls:'ydlg-ft'}
998 ]}, true);
999
1000 alertDialog = new YAHOO.ext.BasicDialog(
1001 alertElement, {
1002 closable:false,
1003 modal:true,
1004 autoTabs:false,
1005 resizable:false,
1006 fixedcenter:true,
1007 constraintoviewport:false,
1008 width:450,
1009 height:320,
1010 shadow:true,
1011 minWidth:300,
1012 minHeight:300
1013 }
1014 );
1015
1016 closeFunction = MochiKit.Base.partial(MochiKit.Base.bind(this.closeResigrationAlert, this), alertDialog);
1017 alertDialog.addKeyListener(27, closeFunction);
1018 closeButton = alertDialog.addButton(Clipperz.PM.Strings['splashAlertCloseButtonLabel'], closeFunction, this);
1019 alertDialog.setDefaultButton(closeButton);
1020 alertDialog.show('main');
1021
1022 this._shouldShowRegistrationAlert = false;
1023 }
1024 },
1025
1026 'closeResigrationAlert': function(anAlertDialog) {
1027 anAlertDialog.hide(MochiKit.Base.bind(function() {anAlertDialog.destroy(true); this.focusOnVisibleForm();}, this));
1028 },
1029
1030 //-------------------------------------------------------------------------
1031
1032 'onkeydown': function(anEvent) {
1033//MochiKit.Logging.logDebug(">>> onkeydown - " + anEvent.src().id);
1034 if (anEvent.key().code == 13) {
1035 if (anEvent.src() == this.getDom('loginForm')) {
1036 this.doLogin();
1037 } else if (anEvent.src() == this.getDom('registrationForm')) {
1038 this.doRegister();
1039 } else {
1040 }
1041
1042 anEvent.stop();
1043 }
1044 },
1045
1046 //-------------------------------------------------------------------------
1047
1048 'visibleForm': function() {
1049 return this._visibleForm;
1050 },
1051
1052 'setVisibleForm': function(aValue) {
1053 this._visibleForm = aValue;
1054 },
1055
1056 //-------------------------------------------------------------------------
1057
1058 'focusOnVisibleForm': function() {
1059 if (this.visibleForm() == 'registration') {
1060 this.getElement('registration_username').focus();
1061 } else {
1062 this.getElement('login_username').focus();
1063 }
1064 },
1065
1066 //-------------------------------------------------------------------------
1067
1068 'show': function() {
1069 if (this.visibleForm() == 'registration') {
1070 this.showRegistrationForm(false);
1071 } else {
1072 this.showLoginForm(false);
1073 }
1074 },
1075
1076 //-------------------------------------------------------------------------
1077
1078 'switchLanguage': function(anEvent) {
1079 Clipperz.PM.Strings.Languages.setSelectedLanguage(anEvent.src().value);
1080 },
1081
1082 //-------------------------------------------------------------------------
1083
1084 'selectSelectedLanguageOption': function() {
1085 Clipperz.DOM.selectOptionMatchingValue(this.getDom('languageSelector'), Clipperz.PM.Strings.selectedLanguage, true);
1086 },
1087
1088 //-------------------------------------------------------------------------
1089
1090 'switchLanguageHandler': function() {
1091 this.render();
1092 this.show();
1093 },
1094
1095 //-------------------------------------------------------------------------
1096
1097 'togglePassphraseCheckbox': function(anEvent) {
1098 this.getDom('showPassphraseCheckbox').click();
1099 },
1100
1101 'togglePassphraseVisibility': function(anEvent) {
1102 if (this.getDom('showPassphraseCheckbox').checked == true) {
1103 this.getElement('showPassphraseDiv').show();
1104 this.getElement('hidePassphraseDiv').hide();
1105 } else {
1106 this.getElement('showPassphraseDiv').hide();
1107 this.getElement('hidePassphraseDiv').show();
1108 }
1109 },
1110
1111 //-------------------------------------------------------------------------
1112 __syntaxFix__: "syntax fix"
1113
1114});
diff --git a/frontend/beta/js/Clipperz/PM/Components/Panels/LogoutPanel.js b/frontend/beta/js/Clipperz/PM/Components/Panels/LogoutPanel.js
new file mode 100644
index 0000000..d7abfd6
--- a/dev/null
+++ b/frontend/beta/js/Clipperz/PM/Components/Panels/LogoutPanel.js
@@ -0,0 +1,73 @@
1/*
2
3Copyright 2008-2011 Clipperz Srl
4
5This file is part of Clipperz's Javascript Crypto Library.
6Javascript Crypto Library provides web developers with an extensive
7and efficient set of cryptographic functions. The library aims to
8obtain maximum execution speed while preserving modularity and
9reusability.
10For further information about its features and functionalities please
11refer to http://www.clipperz.com
12
13* Javascript Crypto Library is free software: you can redistribute
14 it and/or modify it under the terms of the GNU Affero General Public
15 License as published by the Free Software Foundation, either version
16 3 of the License, or (at your option) any later version.
17
18* Javascript Crypto Library is distributed in the hope that it will
19 be useful, but WITHOUT ANY WARRANTY; without even the implied
20 warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
21 See the GNU Affero General Public License for more details.
22
23* You should have received a copy of the GNU Affero General Public
24 License along with Javascript Crypto Library. If not, see
25 <http://www.gnu.org/licenses/>.
26
27*/
28
29if (typeof(Clipperz) == 'undefined') { Clipperz = {}; }
30if (typeof(Clipperz.PM) == 'undefined') { Clipperz.PM = {}; }
31if (typeof(Clipperz.PM.Components) == 'undefined') { Clipperz.PM.Components = {}; }
32if (typeof(Clipperz.PM.Components.Panels) == 'undefined') { Clipperz.PM.Components.Panels = {}; }
33
34//#############################################################################
35
36Clipperz.PM.Components.Panels.LogoutPanel = function(args) {
37 args = args || {};
38
39 Clipperz.PM.Components.Panels.LogoutPanel.superclass.constructor.call(this, args);
40
41 return this;
42}
43
44//=============================================================================
45
46YAHOO.extendX(Clipperz.PM.Components.Panels.LogoutPanel, Clipperz.PM.Components.Panels.BasePanel, {
47
48 'toString': function() {
49 return "Clipperz.PM.Components.LogoutPanel component";
50 },
51
52 //-------------------------------------------------------------------------
53
54 'initPanel': function() {
55 var result;
56 varlayout;
57
58 result = new YAHOO.ext.ContentPanel(this.getId('panel'), {title:'logout', closable:false, autoCreate:true});
59
60 Clipperz.YUI.DomHelper.append(result.getEl().dom,
61 {tag:'div', children:[
62 {tag:'h2', html:'Logout panel'}
63 ]}
64 );
65
66 return result;
67 },
68
69 //-------------------------------------------------------------------------
70 __syntaxFix__: "syntax fix"
71
72});
73
diff --git a/frontend/beta/js/Clipperz/PM/Components/Panels/MainPanel.js b/frontend/beta/js/Clipperz/PM/Components/Panels/MainPanel.js
new file mode 100644
index 0000000..e2036d0
--- a/dev/null
+++ b/frontend/beta/js/Clipperz/PM/Components/Panels/MainPanel.js
@@ -0,0 +1,906 @@
1/*
2
3Copyright 2008-2011 Clipperz Srl
4
5This file is part of Clipperz's Javascript Crypto Library.
6Javascript Crypto Library provides web developers with an extensive
7and efficient set of cryptographic functions. The library aims to
8obtain maximum execution speed while preserving modularity and
9reusability.
10For further information about its features and functionalities please
11refer to http://www.clipperz.com
12
13* Javascript Crypto Library is free software: you can redistribute
14 it and/or modify it under the terms of the GNU Affero General Public
15 License as published by the Free Software Foundation, either version
16 3 of the License, or (at your option) any later version.
17
18* Javascript Crypto Library is distributed in the hope that it will
19 be useful, but WITHOUT ANY WARRANTY; without even the implied
20 warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
21 See the GNU Affero General Public License for more details.
22
23* You should have received a copy of the GNU Affero General Public
24 License along with Javascript Crypto Library. If not, see
25 <http://www.gnu.org/licenses/>.
26
27*/
28
29if (typeof(Clipperz) == 'undefined') { Clipperz = {}; }
30if (typeof(Clipperz.PM) == 'undefined') { Clipperz.PM = {}; }
31if (typeof(Clipperz.PM.Components) == 'undefined') { Clipperz.PM.Components = {}; }
32if (typeof(Clipperz.PM.Components.Panels) == 'undefined') { Clipperz.PM.Components.Panels = {}; }
33
34//#############################################################################
35
36Clipperz.PM.Components.Panels.MainPanel = function(anElement, args) {
37 args = args || {};
38
39 Clipperz.PM.Components.Panels.MainPanel.superclass.constructor.call(this, anElement, args);
40
41 this._recordListDataModel = null;
42 this._selectedRecord = null;
43 this._recordDetailComponent = null;
44 this._recordListGrid = null;
45
46 this._directLinkItemTemplate = null;
47 this._recordItemTemplate = null;
48
49 this._addNewRecordButton = null;
50 this._deleteRecordButton = null;
51
52 this._creationWizard = null;
53
54 Clipperz.NotificationCenter.register(null, 'selectAndEnterEditMode', this, 'selectRecordAndEnterEditModeHandler');
55
56 Clipperz.NotificationCenter.register(null, 'recordAdded', this, 'recordAddedHandler');
57 Clipperz.NotificationCenter.register(null, 'recordUpdated', this, 'recordUpdatedHandler');
58 Clipperz.NotificationCenter.register(null, 'recordRemoved', this, 'recordRemovedHandler');
59
60 Clipperz.NotificationCenter.register(null, 'directLoginAdded', this, 'directLoginAddedHandler');
61 Clipperz.NotificationCenter.register(null, 'directLoginUpdated', this, 'directLoginUpdatedHandler');
62 Clipperz.NotificationCenter.register(null, 'directLoginRemoved', this, 'directLoginRemovedHandler');
63
64 Clipperz.NotificationCenter.register(null, 'accountLocked', this, 'accountLockedHandler');
65
66 MochiKit.Signal.connect(MochiKit.DOM.currentWindow(), 'onresize', this, 'resizeModalMask');
67 this.render();
68
69 return this;
70}
71
72//=============================================================================
73
74YAHOO.extendX(Clipperz.PM.Components.Panels.MainPanel, Clipperz.PM.Components.Panels.BasePanel, {
75
76 'toString': function() {
77 return "Clipperz.PM.Components.Panels.MainPanel component";
78 },
79
80 //-------------------------------------------------------------------------
81
82 'render': function() {
83 this.element().update("");
84 Clipperz.YUI.DomHelper.append(this.element().dom, {tag:'table', id:'mainPanelTABLE', border:'0', cellspacing:'0', cellpadding:'0', children:[
85 {tag:'tbody', children:[
86 {tag:'tr', children:[
87 {tag:'td', width:'15', children:[
88 {tag:'div', cls:'mainPanelMinHeightDiv'}
89 ]},
90 {tag:'td', valign:'top', id:'directLoginsTD', width:'200', children:[
91 {tag:'div', id:'directLoginsBlock', children:[
92 {tag:'div', cls:'directLoginsBlockHeaderBox', children:[{tag:'h3', id:'directLoginTitle', htmlString:Clipperz.PM.Strings['mainPanelDirectLoginBlockLabel']}]},
93 {tag:'div', id:'directLoginsDescription', htmlString:Clipperz.PM.Strings['mainPanelDirectLoginBlockDescription']},
94 {tag:'ul', id:'directLogins'}
95 ]}
96 ]},
97 {tag:'td', width:'15', children:[
98 {tag:'div', cls:'mainPanelMinHeightDiv'}
99 ]},
100 {tag:'td', valign:'top', children:[
101 {tag:'div', id:'mainContent', children:[
102 {tag:'div', id:'recordListBlockHeader'},
103 {tag:'div', id:'recordListAndDetailBlock', children:[
104 {tag:'table', id:'recordListAndDetailBlockTABLE', border:'0', cellspacing:'0', cellpadding:'0', children:[
105 {tag:'tbody', children:[
106 {tag:'tr', children:[
107 {tag:'td', valign:'top', width:'250', children:[
108 {tag:'div', id:'recordListBlock', children:[
109 {tag:'div', id:'recordListFilterHeader'},
110 {tag:'ul', id:'records'}
111 ]}
112 ]},
113 {tag:'td', id:'recordDetailSeparatorTD', rowspan:'2', valign:'top', bgcolor:'#ddddff', html:'&nbsp;'},
114 {tag:'td', valign:'top', children:[
115 {tag:'div', id:'recordDetailMainBlock', children:[
116 {tag:'div', id:'recordTitleTopBlock'},
117 {tag:'div', id:'recordDetailBlock', children:[
118 {tag:'div', id:'recordDetail'}
119 ]}
120 ]},
121 {tag:'div', id:'recordCreationWizardMainBlock', children:[
122 {tag:'div', id:'recordCreationWizard', html:"WIZARD"}
123 ]}
124 ]}
125 ]},
126 {tag:'tr', children:[
127 {tag:'td', id:'cardBoxLowerLeftTD', html:'&nbsp;'},
128 {tag:'td', id:'cardBoxLowerRightTD', html:'&nbsp;'}
129 ]}
130 ]}
131 ]}
132 ]}
133 ]}
134 ]},
135 {tag:'td', width:'15', html:"&nbsp;"}
136 ]}
137 ]}
138 ]});
139
140 this.renderRecordListBlockHeader();
141 // this.renderRecordListFilterHeader();
142
143 YAHOO.ext.Element.get('directLogins').setVisibilityMode(YAHOO.ext.Element.DISPLAY).hide();
144
145 this.recordDetailComponent();
146
147 YAHOO.ext.Element.get('recordDetailMainBlock').setVisibilityMode(YAHOO.ext.Element.DISPLAY).show();
148 YAHOO.ext.Element.get('recordCreationWizardMainBlock').setVisibilityMode(YAHOO.ext.Element.DISPLAY).hide();
149 },
150
151 //-------------------------------------------------------------------------
152
153 'addNewRecordButton': function() {
154 return this._addNewRecordButton;
155 },
156
157 'setAddNewRecordButton': function(aValue) {
158 this._addNewRecordButton = aValue;
159 },
160
161 'deleteRecordButton': function() {
162 return this._deleteRecordButton;
163 },
164
165 'setDeleteRecordButton': function(aValue) {
166 this._deleteRecordButton = aValue;
167 },
168
169 //-------------------------------------------------------------------------
170
171 'addNewRecord': function(anEvent) {
172 var deferredResult;
173 // var currentNumberOfRecords;
174
175 deferredResult = new MochiKit.Async.Deferred();
176
177 // currentNumberOfRecords = MochiKit.Base.keys(this.user().records()).length;
178/*
179 // if ((this.user().preferences().shouldShowDonationPanel()) && (currentNumberOfRecords > 0) && ((currentNumberOfRecords%10) == 0)) {
180 // if (true) {
181 if ((this.user().preferences().shouldShowDonationPanel()) && (currentNumberOfRecords >= 5)) {
182 deferredResult.addCallback(Clipperz.PM.showDonationSplashScreen, this.user(), 'recordListAddRecordButton');
183 }
184*/
185 deferredResult.addCallback(MochiKit.Base.bind(function() {
186 var currentlySelectedRecord;
187
188 currentlySelecedRecord = this.selectedRecord();
189 this.setSelectedRecord(null);
190
191 YAHOO.ext.Element.get('recordDetailMainBlock').hide();
192 YAHOO.ext.Element.get('recordCreationWizardMainBlock').show();
193 this.setCreationWizard(new Clipperz.PM.Components.RecordDetail.CreationWizard(YAHOO.ext.Element.get('recordCreationWizardMainBlock'), {previouslySelectedRecord:currentlySelecedRecord, mainComponent:this}));
194
195 this.enterModalView();
196 }, this));
197
198 deferredResult.callback();
199 },
200
201 //-------------------------------------------------------------------------
202
203 'creationWizard': function() {
204 return this._creationWizard;
205 },
206
207 'setCreationWizard': function(aValue) {
208 this._creationWizard = aValue;
209 },
210
211 //-------------------------------------------------------------------------
212
213 'exitWizard': function(aSelectedRecord, shouldEnterEditMode) {
214//MochiKit.Logging.logDebug(">>> MainPanel.exitWizard - " + aSelectedRecord)
215 YAHOO.ext.Element.get('recordCreationWizardMainBlock').hide();
216 YAHOO.ext.Element.get('recordDetailMainBlock').show();
217
218 if (shouldEnterEditMode == true) {
219 this.selectRecordAndEnterEditMode(aSelectedRecord);
220 } else {
221 this.setSelectedRecord(aSelectedRecord);
222 this.exitModalView();
223 }
224
225 this.creationWizard().remove();
226 this.setCreationWizard(null);
227//MochiKit.Logging.logDebug("<<< MainPanel.exitWizard");
228 },
229
230 //-------------------------------------------------------------------------
231
232 'selectRecordAndEnterEditMode': function(aRecord) {
233 this.setSelectedRecord(aRecord);
234 this.recordDetailComponent().setEditMode('EDIT');
235 },
236
237 'selectRecordAndEnterEditModeHandler': function(anEvent) {
238 this.selectRecordAndEnterEditMode(anEvent.source());
239 },
240
241 //-------------------------------------------------------------------------
242
243 'resizeModalMask': function() {
244//MochiKit.Logging.logDebug(">>> MainPanel.resizeModalMask");
245 MochiKit.Style.setElementDimensions('recordDetailEditModeHeaderMask', {w:MochiKit.Style.getElementDimensions('mainDiv').w, h:119});
246
247 MochiKit.Style.setElementDimensions('recordDetailEditModeVerticalMask', {w:511, h:MochiKit.Style.getElementDimensions('mainDiv').h - 119});
248//MochiKit.Logging.logDebug("<<< MainPanel.resizeModalMask");
249 },
250
251 //-------------------------------------------------------------------------
252
253 'enterModalView': function() {
254 if (this.user().preferences().useSafeEditMode()) {
255 var headerMaskElement;
256 var verticalMaskElement;
257
258 this.resizeModalMask();
259
260 headerMaskElement = YAHOO.ext.Element.get('recordDetailEditModeHeaderMask');
261 headerMaskElement.show();
262 headerMaskElement.mask();
263
264 verticalMaskElement = YAHOO.ext.Element.get('recordDetailEditModeVerticalMask');
265 verticalMaskElement.show();
266 verticalMaskElement.mask();
267 }
268 },
269
270 //-------------------------------------------------------------------------
271
272 'exitModalView': function() {
273 if (this.user().preferences().useSafeEditMode()) {
274 var headerMaskElement;
275 var verticalMaskElement;
276
277 headerMaskElement = YAHOO.ext.Element.get('recordDetailEditModeHeaderMask');
278 headerMaskElement.unmask();
279 headerMaskElement.hide();
280
281 verticalMaskElement = YAHOO.ext.Element.get('recordDetailEditModeVerticalMask');
282 verticalMaskElement.unmask();
283 verticalMaskElement.hide();
284 }
285 },
286
287 //-------------------------------------------------------------------------
288
289 'removeSelectedRecord': function() {
290 var selectedRecordReferences;
291
292//MochiKit.Logging.logDebug(">>> MainPanel.removeSelectedRecord");
293 if (this.selectedRecord() != null) {
294 selectedRecordReferences = [this.selectedRecord().reference()];
295 } else {
296 selectedRecordReferences = [];
297 }
298
299 if (selectedRecordReferences.length > 0 ) {
300 varrecordReference;
301 varrecords;
302 var deferred;
303
304 records = [];
305 for (recordReference in selectedRecordReferences) {
306 var record;
307
308//MochiKit.Logging.logDebug("### MainPanel.removeSelectedRecord - recordReference: " + selectedRecordReferences[recordReference]);
309 record = this.user().records()[selectedRecordReferences[recordReference]];
310//MochiKit.Logging.logDebug("### MainPanel.removeSelectedRecord - record: " + record);
311 records.push(record);
312 }
313//MochiKit.Logging.logDebug("### MainPanel.removeSelectedRecord - records.length: " + records.length);
314
315 deferred = new MochiKit.Async.Deferred();
316//MochiKit.Logging.logDebug("--- MainPanel.removeSelectedRecord - 1:");
317//deferred.addBoth(function(res) {MochiKit.Logging.logDebug("MainPanel.removeSelectedRecord - 1: " + res); return res;});
318//MochiKit.Logging.logDebug("--- MainPanel.removeSelectedRecord - 2:");
319 deferred.addCallback(function() {
320 var deferredResult;
321
322 deferredResult = new MochiKit.Async.Deferred();
323 Clipperz.PM.Components.MessageBox().deferredShow({
324 title:Clipperz.PM.Strings['mainPanelDeletingRecordPanelConfirmationTitle'],
325 text:Clipperz.PM.Strings['mainPanelDeleteRecordPanelConfirmationText'],
326 width:240,
327 showProgressBar:false,
328 showCloseButton:false,
329 buttons:{
330 'yes':Clipperz.PM.Strings['mainPanelDeleteRecordPanelConfirmButtonLabel'],
331 'no':Clipperz.PM.Strings['mainPanelDeleteRecordPanelDenyButtonLabel']
332 },
333 fn:MochiKit.Base.partial(function(aDeferred, aResult) {
334 if (aResult == 'yes') {
335 aDeferred.callback(aResult);
336 } else {
337 aDeferred.errback(aResult);
338 }
339 }, deferredResult)
340 }, 'recordListRemoveRecordButton');
341
342 return deferredResult;
343 });
344//MochiKit.Logging.logDebug("--- MainPanel.removeSelectedRecord - 3:");
345//deferred.addBoth(function(res) {MochiKit.Logging.logDebug("MainPanel.removeSelectedRecord - 2: " + res); return res;});
346//MochiKit.Logging.logDebug("--- MainPanel.removeSelectedRecord - 4:");
347//deferred.addBoth(function(res) {MochiKit.Logging.logDebug("MainPanel.removeSelectedRecord - 3: " + res); return res;});
348 deferred.addCallback(MochiKit.Base.method(Clipperz.PM.Components.MessageBox(), 'deferredShow'),
349 {
350 title:Clipperz.PM.Strings['mainPanelDeletingRecordPanelInitialTitle'],
351 text:Clipperz.PM.Strings['mainPanelDeletingRecordPanelInitialText'],
352 width:240,
353 showProgressBar:true,
354 showCloseButton:false,
355 steps:5
356 }
357 );
358//MochiKit.Logging.logDebug("--- MainPanel.removeSelectedRecord - 5:");
359//deferred.addBoth(function(res) {MochiKit.Logging.logDebug("MainPanel.removeSelectedRecord - 4: " + res); return res;});
360 deferred.addCallback(MochiKit.Base.method(this.user(), 'deleteRecordsAction'), records);
361//MochiKit.Logging.logDebug("--- MainPanel.removeSelectedRecord - 6:");
362//deferred.addBoth(function(res) {MochiKit.Logging.logDebug("MainPanel.removeSelectedRecord - 5: " + res); return res;});
363//MochiKit.Logging.logDebug("--- MainPanel.removeSelectedRecord - 7:");
364//deferred.addBoth(function(res) {MochiKit.Logging.logDebug("MainPanel.removeSelectedRecord - 6: " + res); return res;});
365 deferred.addCallback(function() {
366 Clipperz.PM.Components.MessageBox().update({
367 title:null,
368 text:Clipperz.PM.Strings['mainPanelDeletingRecordPanelCompletedText'],
369 step:'next',
370 buttons:{}
371 });
372 });
373//MochiKit.Logging.logDebug("--- MainPanel.removeSelectedRecord - 8:");
374//deferred.addBoth(function(res) {MochiKit.Logging.logDebug("MainPanel.removeSelectedRecord - 7: " + res); return res;});
375 deferred.addCallback(MochiKit.Async.wait, 1);
376//MochiKit.Logging.logDebug("--- MainPanel.removeSelectedRecord - 9:");
377//deferred.addBoth(function(res) {MochiKit.Logging.logDebug("MainPanel.removeSelectedRecord - 8: " + res); return res;});
378 deferred.addCallback(function(res) {
379 Clipperz.PM.Components.MessageBox().hide(YAHOO.ext.Element.get('main'));
380 return res;
381 });
382//MochiKit.Logging.logDebug("--- MainPanel.removeSelectedRecord - 10:");
383//deferred.addBoth(function(res) {MochiKit.Logging.logDebug("MainPanel.removeSelectedRecord - 9: " + res); return res;});
384 deferred.callback();
385 } else {
386//MochiKit.Logging.logDebug("+++ MainPanel.removeSelectedRecord - nothing selected");
387 }
388 },
389
390 //-------------------------------------------------------------------------
391
392 'recordDetailComponent': function() {
393//MochiKit.Logging.logDebug(">>> MainPanel.recordDetailComponent");
394 if (this._recordDetailComponent == null) {
395//MochiKit.Logging.logDebug("--- MainPanel.recordDetailComponent - 1");
396//MochiKit.Logging.logDebug("--- MainPanel.recordDetailComponent - 1 - user: " + this.user());
397 this._recordDetailComponent = new Clipperz.PM.Components.RecordDetail.MainComponent(
398 YAHOO.ext.Element.get('recordDetail'),
399 {user:this.user(), mainPanel:this}
400 );
401 }
402
403//MochiKit.Logging.logDebug("<<< MainPanel.recordDetailComponent");
404
405 return this._recordDetailComponent;
406 },
407
408 //-------------------------------------------------------------------------
409
410 'selectedRecord': function() {
411 return this._selectedRecord;
412 },
413
414 'setSelectedRecord': function(aValue) {
415 // this.hideNewRecordPanel();
416//MochiKit.Logging.logDebug(">>> MainPanel.setSelectedRecord");
417 if (aValue != this._selectedRecord) {
418//MochiKit.Logging.logDebug("--- MainPanel.setSelectedRecord - 1");
419 this._selectedRecord = aValue;
420//MochiKit.Logging.logDebug("--- MainPanel.setSelectedRecord - 2");
421 this.redrawRecordItems();
422//MochiKit.Logging.logDebug("--- MainPanel.setSelectedRecord - 3");
423 this.recordDetailComponent().setRecord(aValue);
424//MochiKit.Logging.logDebug("--- MainPanel.setSelectedRecord - 4");
425 }
426
427 if ((aValue == null) || (Clipperz.PM.Proxy.defaultProxy.isReadOnly())) {
428 this.deleteRecordButton().disable();
429 } else {
430 this.deleteRecordButton().enable();
431 }
432//MochiKit.Logging.logDebug("<<< MainPanel.setSelectedRecord");
433 },
434
435 //-------------------------------------------------------------------------
436
437 'recordAddedHandler': function(anEvent) {
438//MochiKit.Logging.logDebug(">>> MainPanel.recordAddedHandler");
439 this.recordDetailComponent();
440 this.redrawRecordItems();
441//MochiKit.Logging.logDebug("<<< MainPanel.recordAddedHandler");
442 },
443
444 'recordUpdatedHandler': function(anEvent) {
445//MochiKit.Logging.logDebug(">>> MainPanel.recordUpdatedHandler");
446 this.redrawRecordItems();
447//MochiKit.Logging.logDebug("<<< MainPanel.recordUpdatedHandler");
448 },
449
450 'recordRemovedHandler': function(anEvent) {
451//MochiKit.Logging.logDebug(">>> MainPanel.recordRemovedHandler");
452 this.setSelectedRecord(null);
453//MochiKit.Logging.logDebug("--- MainPanel.recordRemovedHandler - 1");
454 this.redrawRecordItems();
455//MochiKit.Logging.logDebug("<<< MainPanel.recordRemovedHandler");
456 },
457
458 'compareRecords': function(a, b) {
459//MochiKit.Logging.logDebug("=== compareRecords: " + a.toString() + " - " + b.toString());
460 return MochiKit.Base.compare(a.label().toLowerCase(), b.label().toLowerCase());
461 },
462
463 'redrawRecordItems': function() {
464 var template;
465 var allRecords;
466
467//MochiKit.Logging.logDebug(">>> MainPanel.redrawRecordItems");
468 MochiKit.Iter.forEach(YAHOO.ext.Element.get('records').getChildrenByTagName('li'), function(aRecordElement) {
469 MochiKit.Signal.disconnectAll(aRecordElement.dom);
470 })
471//MochiKit.Logging.logDebug("--- MainPanel.redrawRecordItems - 1");
472 YAHOO.ext.Element.get('records').update("");
473//MochiKit.Logging.logDebug("--- MainPanel.redrawRecordItems - 2");
474 allRecords = MochiKit.Base.values(this.user().records());
475//MochiKit.Logging.logDebug("--- MainPanel.redrawRecordItems - 3");
476 allRecords.sort(this.compareRecords);
477//MochiKit.Logging.logDebug("--- MainPanel.redrawRecordItems - 4");
478 template = this.recordItemTemplate();
479//MochiKit.Logging.logDebug("--- MainPanel.redrawRecordItems - 5");
480 MochiKit.Iter.forEach(allRecords, MochiKit.Base.bind(function(aRecord) {
481 varrecordElement;
482 recordElement = template.append('records', {
483 recordTitle:aRecord.label(),
484 recordReference:aRecord.reference(),
485 cls:((aRecord == this.selectedRecord()) ? 'selected': '')
486 }, true);
487//MochiKit.Logging.logDebug("--- MainPanel.redrawRecordItems - 6: " + recordElement.dom);
488 recordElement.addClassOnOver('hover');
489 MochiKit.Signal.connect(recordElement.dom, 'onclick', this, 'selectRecord');
490 }, this));
491//MochiKit.Logging.logDebug("<<< MainPanel.redrawRecordItems");
492 },
493
494 'selectRecord': function(anEvent) {
495//MochiKit.Logging.logDebug(">>> MainPanel.selectRecord");
496//MochiKit.Logging.logDebug("--- MainPanel.selectRecord !!! - ", this.user().records()[anEvent.src().id].label());
497 this.setSelectedRecord(this.user().records()[anEvent.src().id]);
498 //MochiKit.Logging.logDebug("<<< MainPanel.selectRecord");
499 },
500
501 //-------------------------------------------------------------------------
502
503 'directLoginAddedHandler': function(anEvent) {
504//MochiKit.Logging.logDebug(">>> MainPanel.recordRemovedHandler");
505 this.redrawDirectLoginItems();
506//MochiKit.Logging.logDebug("<<< MainPanel.recordRemovedHandler");
507 },
508
509 'directLoginUpdatedHandler': function(anEvent) {
510//MochiKit.Logging.logDebug(">>> MainPanel.directLoginUpdatedHandler");
511 this.redrawDirectLoginItems();
512//MochiKit.Logging.logDebug("<<< MainPanel.directLoginUpdatedHandler");
513 },
514
515 'directLoginRemovedHandler': function(anEvent) {
516//MochiKit.Logging.logDebug(">>> MainPanel.directLoginRemovedHandler");
517 this.redrawDirectLoginItems();
518//MochiKit.Logging.logDebug("<<< MainPanel.directLoginRemovedHandler");
519 },
520
521 'compareDirectLogins': function(a, b) {
522 return MochiKit.Base.compare(a.label().toLowerCase(), b.label().toLowerCase());
523 },
524
525 'redrawDirectLoginItems': function() {
526 var template;
527 var allDirectLogins;
528
529//MochiKit.Logging.logDebug(">>> MainPanel.redrawDirectLoginItems");
530 MochiKit.Iter.forEach(YAHOO.ext.Element.get('directLogins').getChildrenByTagName('li'), function(aDirectLoginElement) {
531 MochiKit.Signal.disconnectAll(aDirectLoginElement.dom);
532//MochiKit.Logging.logDebug("disconnecting IMG " + aDirectLoginElement.getChildrenByTagName('img')[0].dom.src);
533 MochiKit.Signal.disconnectAll(aDirectLoginElement.getChildrenByTagName('img')[0].dom);
534 })
535//MochiKit.Logging.logDebug("--- MainPanel.redrawDirectLoginItems - 1");
536 YAHOO.ext.Element.get('directLogins').update("");
537//MochiKit.Logging.logDebug("--- MainPanel.redrawDirectLoginItems - 2");
538 allDirectLogins = MochiKit.Base.values(this.user().directLoginReferences());
539//MochiKit.Logging.logDebug("--- MainPanel.redrawDirectLoginItems - 3");
540 allDirectLogins.sort(this.compareDirectLogins);
541
542 if (allDirectLogins.length == 0) {
543 YAHOO.ext.Element.get('directLoginsDescription').show();
544 YAHOO.ext.Element.get('directLogins').setVisibilityMode(YAHOO.ext.Element.DISPLAY).hide();
545 } else {
546 YAHOO.ext.Element.get('directLoginsDescription').setVisibilityMode(YAHOO.ext.Element.DISPLAY).hide();
547 YAHOO.ext.Element.get('directLogins').show();
548 }
549//MochiKit.Logging.logDebug("--- MainPanel.redrawDirectLoginItems - 4");
550 template = this.directLoginItemTemplate();
551//MochiKit.Logging.logDebug("--- MainPanel.redrawDirectLoginItems - 5");
552 MochiKit.Iter.forEach(allDirectLogins, MochiKit.Base.bind(function(aDirectLogin) {
553 vardirectLoginElement;
554 varfaviconImageElementID;
555
556 faviconImageElementID = aDirectLogin.reference() + "_faviconIMG";
557 directLoginElement = template.append('directLogins', {
558 elementID:faviconImageElementID,
559 faviconUrl:aDirectLogin.fixedFavicon(),
560 directLoginTitle:aDirectLogin.label(),
561 directLoginReference:aDirectLogin.reference()
562 }, true);
563//MochiKit.Logging.logDebug("--- MainPanel.redrawDirectLoginItems - 6: " + recordElement.dom);
564 directLoginElement.addClassOnOver("hover");
565 MochiKit.Signal.connect(directLoginElement.dom, 'onclick', this, 'handleDirectLoginClick');
566
567 MochiKit.Signal.connect(faviconImageElementID, 'onload', this, 'handleLoadedFaviconImage');
568 MochiKit.Signal.connect(faviconImageElementID, 'onerror', aDirectLogin, 'handleMissingFaviconImage');
569 MochiKit.Signal.connect(faviconImageElementID, 'onabort', aDirectLogin, 'handleMissingFaviconImage');
570
571 // YAHOO.ext.Element.get(faviconImageElementID).dom.src = aDirectLogin.fixedFavicon();
572 }, this));
573//MochiKit.Logging.logDebug("<<< MainPanel.redrawDirectLoginItems");
574 },
575
576 //-------------------------------------------------------------------------
577
578 'handleDirectLoginClick': function(anEvent) {
579 vardirectLoginReference;
580//MochiKit.Logging.logDebug(">>> MainPanel.handleDirectLoginClick !!!");
581
582 directLoginReference = this.user().directLoginReferences()[anEvent.src().id];
583 if (anEvent.target().className == 'directLoginItemEditButton') {
584 this.editDirectLogin(directLoginReference);
585 } else {
586 this.openDirectLogin(directLoginReference);
587 }
588 //MochiKit.Logging.logDebug("<<< MainPanel.handleDirectLoginClick");
589 },
590
591 'editDirectLogin': function(aDirectLoginReference) {
592//MochiKit.Logging.logDebug("=== MainPanel.editDirectLogin - " + aDirectLoginReference.label());
593 this.setSelectedRecord(aDirectLoginReference.record());
594 },
595
596 'openDirectLogin': function(aDirectLoginReference) {
597 vardeferredResult;
598 varnewWindow;
599
600//MochiKit.Logging.logDebug(">>> MainPanel.openDirectLogin - " + aDirectLoginReference.label());
601 deferredResult = new MochiKit.Async.Deferred();
602//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("MainPanel.openDirectLogin - 1: " + res); return res;});
603 deferredResult.addCallback(MochiKit.Base.method(aDirectLoginReference, 'setupJumpPageWindow'));
604 deferredResult.addCallback(MochiKit.Base.method(aDirectLoginReference, 'deferredDirectLogin'));
605 deferredResult.addCallback(function(aDirectLogin) {
606 aDirectLogin.runDirectLogin(newWindow);
607 });
608
609 newWindow = window.open(Clipperz.PM.Strings['directLoginJumpPageUrl'], "");
610 // MochiKit.Signal.connect(newWindow, 'onload', MochiKit.Base.method(deferredResult, 'callback', newWindow))
611 // MochiKit.Signal.connect(newWindow, 'onload', MochiKit.Base.partial(alert, "done"));
612 deferredResult.callback(newWindow);
613//MochiKit.Logging.logDebug("<<< MainPanel.openDirectLogin");
614 },
615
616 //-------------------------------------------------------------------------
617
618 'handleLoadedFaviconImage': function(anEvent) {
619//MochiKit.Logging.logDebug(">>> MainPanel.handleLoadedFaviconImage");
620 MochiKit.Signal.disconnectAll(anEvent.src())
621//MochiKit.Logging.logDebug("<<< MainPanel.handleLoadedFaviconImage");
622 },
623
624 //-------------------------------------------------------------------------
625
626 'recordItemTemplate': function() {
627 if (this._recordItemTemplate == null) {
628 this._recordItemTemplate = Clipperz.YUI.DomHelper.createTemplate({tag:'li', cls:'{cls}', id:'{recordReference}', children:[
629 {tag:'span', html:'{recordTitle}'}
630 ]});
631 this._recordItemTemplate.compile();
632 }
633
634 return this._recordItemTemplate;
635 },
636
637 'directLoginItemTemplate': function() {
638 if (this._directLoginItemTemplate == null) {
639 this._directLoginItemTemplate = Clipperz.YUI.DomHelper.createTemplate({tag:'li', id:'{directLoginReference}', children:[
640 {tag:'table', border:'0', cellpadding:'0', cellspacing:'0', children:[
641 {tag:'tbody', children:[
642 {tag:'tr', children:[
643 {tag:'td', width:'20', align:'center', valign:'top', children:[
644 {tag:'img', id:'{elementID}', src:'{faviconUrl}'}
645 ]},
646 {tag:'td', valign:'top', children:[
647 {tag:'a', cls:'directLoginItemTitle', html:'{directLoginTitle}'}
648 ]},
649 {tag:'td', valign:'top', align:'right', children:[
650 // {tag:'span', cls:'directLoginItemEditButton', htmlString:Clipperz.PM.Strings['directLinkReferenceShowButtonLabel']}
651 {tag:'a', cls:'directLoginItemEditButton', htmlString:Clipperz.PM.Strings['directLinkReferenceShowButtonLabel']}
652 ]}
653 ]}
654 ]}
655 ]}
656 ]});
657 this._directLoginItemTemplate.compile();
658 }
659
660 return this._directLoginItemTemplate;
661 },
662
663 //-------------------------------------------------------------------------
664/*
665 'newRecordButton': function() {
666 return this._newRecordButton;
667 },
668
669 'setNewRecordButton': function(aValue) {
670 this._newRecordButton = aValue;
671 },
672
673 'newRecordCancelButton': function() {
674 return this._newRecordCancelButton;
675 },
676
677 'setNewRecordCancelButton': function(aValue) {
678 this._newRecordCancelButton = aValue;
679 },
680 */
681 //-------------------------------------------------------------------------
682
683 'onkeydown': function(anEvent) {
684//MochiKit.Logging.logDebug(">>> onkeydown - " + anEvent.src().id + ": " + anEvent.key().code);
685 switch (anEvent.src().id) {
686/*
687 case this.getId('newRecordForm'):
688 if (anEvent.key().code == 13) {
689 this.newRecordButton().focus();
690 // this.addNewRecord();
691 } else if (anEvent.key().code == 27) {
692 this.newRecordCancelButton().focus();
693 this.hideNewRecordPanel(true);
694 }
695 break;
696*/
697 case "recordFilterSearchForm":
698 if (anEvent.key().code == 13) {
699//MochiKit.Logging.logDebug("SEARCH");
700 this.filterCardsWithName(YAHOO.ext.Element.get('recordFilterSearchValue').dom.value);
701 anEvent.event().stopPropagation();
702 YAHOO.ext.Element.get('recordFilterSearchValue').focus();
703 } else if (anEvent.key().code == 27) {
704 this.hideRecordFilterSearchPanel(true);
705 this.showRecordFilterAllPanel();
706 }
707 break;
708 }
709
710 },
711
712 //-------------------------------------------------------------------------
713
714 'renderRecordListBlockHeader': function(){
715 var recordListBlockHeaderElement;
716
717 recordListBlockHeaderElement = YAHOO.ext.Element.get('recordListBlockHeader');
718 recordListBlockHeaderElement.update("");
719 Clipperz.YUI.DomHelper.append(recordListBlockHeaderElement.dom,
720 {tag:'table', cls:'recordListBlockHeaderTABLE', border:'0', cellspacing:'0', cellpadding:'0', children:[
721 {tag:'tbody', children:[
722 {tag:'tr', children:[
723 {tag:'td', /*width:'50%',*/ cls:'recordBlockTitleTD', children:[
724 {tag:'h3', id:'recordBlockTitle', htmlString:Clipperz.PM.Strings['mainPanelRecordsBlockLabel']}
725 ]},
726 {tag:'td', align:'right', children:[
727 {tag:'table', id:'recordListButtonsTABLE', border:'0', cellspacing:'0', cellpadding:'0', children:[
728 {tag:'tbody', children:[
729 {tag:'tr', children:[
730 {tag:'td', cls:'recordButtonTD', align:'right', children:[
731 {tag:'div', cls:'recordButton', id:'recordListAddRecordButton'}
732 ]},
733 {tag:'td', cls:'recordButtonTD', align:'left', children:[
734 {tag:'div', cls:'recordButton', id:'recordListRemoveRecordButton'}
735 ]}
736 ]}
737 ]}
738 ]}
739 ]},
740 {tag:'td', width:'15', html:"&nbsp;"}
741 ]}
742 ]}
743 ]}
744 );
745
746 this.setAddNewRecordButton(new YAHOO.ext.Button('recordListAddRecordButton', {text:Clipperz.PM.Strings['mainPanelAddRecordButtonLabel'], handler:this.addNewRecord, scope:this}));
747 // this.setAddNewRecordButton(new YAHOO.ext.Button('recordListAddRecordButton', {text:Clipperz.PM.Strings['mainPanelAddRecordButtonLabel'], handler:this.showNewRecordPanel, scope:this}));
748 this.setDeleteRecordButton(new YAHOO.ext.Button('recordListRemoveRecordButton', {text:Clipperz.PM.Strings['mainPanelRemoveRecordButtonLabel'], handler:this.removeSelectedRecord, scope:this}));
749
750
751 if ((Clipperz.PM.Proxy.defaultProxy.isReadOnly()) || (this.selectedRecord() == null)) {
752 this.deleteRecordButton().disable();
753 }
754
755 if (Clipperz.PM.Proxy.defaultProxy.isReadOnly()) {
756 this.addNewRecordButton().disable();
757 }
758
759 },
760
761 //-------------------------------------------------------------------------
762
763 'renderRecordListFilterHeader': function(){
764 var recordListFilterHeaderElement;
765
766 recordListFilterHeaderElement = YAHOO.ext.Element.get('recordListFilterHeader');
767 recordListFilterHeaderElement.update("");
768 Clipperz.YUI.DomHelper.append(recordListFilterHeaderElement.dom,
769 {tag:'div', id:'recordFiltersDIV', children:[
770 {tag:'div', id:'recordFiltersTableWrapper', children:[
771 {tag:'table', id:'recordFiltersTABLE', border:'0', cellspacing:'0', cellpadding:'0', children:[
772 {tag:'tbody', children:[
773 {tag:'tr', children:[
774 {tag:'td', id:'recordFilterAllTD', children:[{tag:'div', children:[{tag:'a', id:'recordFilterAll', htmlString:Clipperz.PM.Strings['mainPanelRecordFilterBlockAllLabel']}]}]},
775 {tag:'td', id:'recordFilterTagsTD', children:[{tag:'div', children:[{tag:'a', id:'recordFilterTags', htmlString:Clipperz.PM.Strings['mainPanelRecordFilterBlockTagsLabel']}]}]},
776 {tag:'td', id:'recordFilterSearchTD', children:[{tag:'div', children:[{tag:'a', id:'recordFilterSearch', htmlString:Clipperz.PM.Strings['mainPanelRecordFilterBlockSearchLabel']}]}]}
777 ]}
778 ]}
779 ]}
780 ]},
781 {tag:'div', id:'recordFiltersTagsPanel'},
782 {tag:'div', id:'recordFiltersSearchPanel', children:[{tag:'div', id:'recordFiltersSearchInnerPanel', children:[{tag:'div', id:'recordFiltersSearchInnerInnerPanel', children:[
783 {tag:'form', id:'recordFilterSearchForm', children:[
784 {tag:'input', type:'text', name:'search', id:'recordFilterSearchValue'}
785 ]}
786 ]}]}]}
787 ]}
788 );
789
790 /// YAHOO.ext.Element.get('recordFiltersSearchPanel').setVisibilityMode(YAHOO.ext.Element.DISPLAY).hide();
791 this.showRecordFilterAllPanel(false);
792
793 MochiKit.Signal.connect('recordFilterSearchForm', 'onkeydown', this, 'onkeydown');
794 MochiKit.Signal.connect('recordFilterSearchForm', 'onsubmit', this, 'onkeydown');
795
796 MochiKit.Signal.connect('recordFilterAll', 'onclick', this, 'showRecordFilterAllPanel');
797 MochiKit.Signal.connect('recordFilterTags', 'onclick', this, 'showRecordFilterTagsPanel');
798 MochiKit.Signal.connect('recordFilterSearch', 'onclick', this, 'showRecordFilterSearchPanel');
799 },
800
801 //-------------------------------------------------------------------------
802
803 'showRecordFilterAllPanel': function(shouldSlide) {
804 this.hideRecordFilterTagsPanel(shouldSlide);
805 this.hideRecordFilterSearchPanel(shouldSlide);
806 YAHOO.ext.Element.get('recordFilterAllTD').addClass('selectedTab');
807 },
808
809 'hideRecordFilterAllPanel': function(shouldSlide) {
810 YAHOO.ext.Element.get('recordFilterAllTD').removeClass('selectedTab');
811 },
812
813 //-------------------------------------------------------------------------
814
815 'showRecordFilterTagsPanel': function(shouldSlide) {
816 this.hideRecordFilterAllPanel(shouldSlide);
817 this.hideRecordFilterSearchPanel(shouldSlide);
818 YAHOO.ext.Element.get('recordFilterTagsTD').addClass('selectedTab');
819 },
820
821 'hideRecordFilterTagsPanel': function(shouldSlide) {
822 YAHOO.ext.Element.get('recordFilterTagsTD').removeClass('selectedTab');
823 },
824
825 //-------------------------------------------------------------------------
826
827 'showRecordFilterSearchPanel': function(shouldSlide) {
828 var searchPanelActor;
829
830 this.hideRecordFilterAllPanel(shouldSlide);
831 this.hideRecordFilterTagsPanel(shouldSlide);
832 YAHOO.ext.Element.get('recordFilterSearchTD').addClass('selectedTab');
833 YAHOO.ext.Element.get('recordFilterSearchValue').dom.value = "";
834
835 searchPanelActor = new YAHOO.ext.Actor('recordFiltersSearchPanel');
836
837 searchPanelActor.startCapture(true);
838 searchPanelActor.slideShow('top', 54);
839 searchPanelActor.play(MochiKit.Base.bind(function() {
840 YAHOO.ext.Element.get('recordFilterSearchValue').focus();
841 }, this));
842 },
843
844 'hideRecordFilterSearchPanel': function(shouldSlide) {
845 var searchPanelActor;
846 varcallback;
847
848 YAHOO.ext.Element.get('recordFilterSearchTD').removeClass('selectedTab');
849
850 searchPanelActor = new YAHOO.ext.Actor('recordFiltersSearchPanel');
851
852 searchPanelActor.startCapture(true)
853 if (shouldSlide === false) {
854 searchPanelActor.hide();
855 searchPanelActor.slideHide('top');
856 searchPanelActor.show();
857 } else {
858 searchPanelActor.slideHide('top');
859 }
860
861 callback = MochiKit.Base.bind(function() {
862 }, this);
863
864 searchPanelActor.play(callback);
865 },
866
867 //-------------------------------------------------------------------------
868
869 'filterCardsWithName': function(aValue) {
870MochiKit.Logging.logDebug(">>> filterCardsWithName: " + aValue);
871
872MochiKit.Logging.logDebug("<<< filterCardsWithName");
873 },
874
875 'accountLockedHandler': function() {
876 this.setSelectedRecord(null);
877 },
878
879 //-------------------------------------------------------------------------
880
881 'switchLanguageHandler': function() {
882 YAHOO.ext.Element.get('directLoginTitle').update(Clipperz.PM.Strings['mainPanelDirectLoginBlockLabel']);
883 YAHOO.ext.Element.get('directLoginsDescription').update("");
884 MochiKit.Iter.forEach(Clipperz.PM.Strings['mainPanelDirectLoginBlockDescriptionConfig'], function(aConfigItem) {
885 Clipperz.YUI.DomHelper.append(YAHOO.ext.Element.get('directLoginsDescription').dom, aConfigItem);
886 });
887 YAHOO.ext.Element.get('recordBlockTitle').update(Clipperz.PM.Strings['mainPanelRecordsBlockLabel']);
888 this.renderRecordListBlockHeader();
889 // this.renderRecordListFilterHeader();
890
891 // YAHOO.ext.Element.get('newRecordPanelTitleH2').update(Clipperz.PM.Strings['mainPanelNewRecordPanelTitle']);
892 // YAHOO.ext.Element.get('newRecordPanelTitleLabel').update(Clipperz.PM.Strings['mainPanelNewRecordPanelRecordTitleLabel']);
893 // YAHOO.ext.Element.get('newRecordPanelConfigLabel').update("");
894 // MochiKit.Iter.forEach(Clipperz.PM.Strings['mainPanelNewRecordPanelRecordConfigConfig'], function(aConfigItem) {
895 // Clipperz.YUI.DomHelper.append(YAHOO.ext.Element.get('newRecordPanelConfigLabel').dom, aConfigItem);
896 // });
897 // this.newRecordButton().setText(Clipperz.PM.Strings['mainPanelNewRecordPanelCreateButtonLabel']);
898 // this.newRecordCancelButton().setText(Clipperz.PM.Strings['mainPanelNewRecordPanelCancelButtonLabel']);
899
900 this.recordDetailComponent().render();
901 },
902
903 //-------------------------------------------------------------------------
904 __syntaxFix__: "syntax fix"
905
906});
diff --git a/frontend/beta/js/Clipperz/PM/Components/Panels/ToolsPanel.js b/frontend/beta/js/Clipperz/PM/Components/Panels/ToolsPanel.js
new file mode 100644
index 0000000..abd2621
--- a/dev/null
+++ b/frontend/beta/js/Clipperz/PM/Components/Panels/ToolsPanel.js
@@ -0,0 +1,305 @@
1/*
2
3Copyright 2008-2011 Clipperz Srl
4
5This file is part of Clipperz's Javascript Crypto Library.
6Javascript Crypto Library provides web developers with an extensive
7and efficient set of cryptographic functions. The library aims to
8obtain maximum execution speed while preserving modularity and
9reusability.
10For further information about its features and functionalities please
11refer to http://www.clipperz.com
12
13* Javascript Crypto Library is free software: you can redistribute
14 it and/or modify it under the terms of the GNU Affero General Public
15 License as published by the Free Software Foundation, either version
16 3 of the License, or (at your option) any later version.
17
18* Javascript Crypto Library is distributed in the hope that it will
19 be useful, but WITHOUT ANY WARRANTY; without even the implied
20 warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
21 See the GNU Affero General Public License for more details.
22
23* You should have received a copy of the GNU Affero General Public
24 License along with Javascript Crypto Library. If not, see
25 <http://www.gnu.org/licenses/>.
26
27*/
28
29if (typeof(Clipperz) == 'undefined') { Clipperz = {}; }
30if (typeof(Clipperz.PM) == 'undefined') { Clipperz.PM = {}; }
31if (typeof(Clipperz.PM.Components) == 'undefined') { Clipperz.PM.Components = {}; }
32if (typeof(Clipperz.PM.Components.Panels) == 'undefined') { Clipperz.PM.Components.Panels = {}; }
33
34//#############################################################################
35
36Clipperz.PM.Components.Panels.ToolsPanel = function(anElement, args) {
37 args = args || {};
38
39 Clipperz.PM.Components.Panels.ToolsPanel.superclass.constructor.call(this, anElement, args);
40
41 this._generateButtonElement = null;
42 this._needsRenderingUponTabSwitch = false;
43
44 this.render();
45
46 return this;
47}
48
49//=============================================================================
50
51YAHOO.extendX(Clipperz.PM.Components.Panels.ToolsPanel, Clipperz.PM.Components.Panels.BasePanel, {
52
53 'toString': function() {
54 return "Clipperz.PM.Components.Panels.ToolsPanel component";
55 },
56
57 //-------------------------------------------------------------------------
58
59 'render': function() {
60 var bookmarkletUrl;
61
62//MochiKit.Logging.logDebug(">>> ToolsPanel.render");
63 Clipperz.NotificationCenter.unregister(this);
64 MochiKit.Signal.disconnectAllTo(this);
65
66 if (Clipperz_IEisBroken == true) {
67 bookmarkletUrl = bookmarklet_ie;
68 } else {
69 bookmarkletUrl = bookmarklet;
70 }
71
72 this.element().update("");
73 Clipperz.YUI.DomHelper.append(this.element().dom, {tag:'table', border:'0', cellspacing:'0', cellpadding:'0', children:[
74 {tag:'tbody', children:[
75 {tag:'tr', children:[
76 {tag:'td', valign:'top', width:'200', children:[
77 {tag:'ul', id:"dataSubMenu", cls:'subMenu', children:[
78 {tag:'li', id:this.getId('passwordGenerator'), htmlString:Clipperz.PM.Strings['passwordGeneratorTabLabel']},
79 {tag:'li', id:this.getId('bookmarklet'), htmlString:Clipperz.PM.Strings['bookmarkletTabLabel']},
80 {tag:'li', id:this.getId('compact'), htmlString:Clipperz.PM.Strings['compactTabLabel']},
81 {tag:'li', id:this.getId('httpAuth'), htmlString:Clipperz.PM.Strings['httpAuthTabLabel']}
82 ]}
83 ]},
84 {tag:'td', valign:'top', children:[
85 {tag:'ul', cls:'clipperzTabPanels', children:[
86 {tag:'li', id:this.getId('passwordGeneratorPanel'), children:[
87 {tag:'div', cls:'clipperzSubPanel', children:[
88 {tag:'h5', htmlString:Clipperz.PM.Strings['passwordGeneratorTabTitle']},
89 {tag:'div', cls:'panelDescription', htmlString:Clipperz.PM.Strings['paswordGeneratorTabDescription']},
90
91 //---------------------------------------------------
92 {tag:'div', children:[
93 {tag:'form', id:this.getId('passwordGeneratorForm'), cls:'passwordGenerator', children:[
94 {tag:'input', type:'text', cls:'clipperz_passwordGenerator_password', id:this.getId('passwordField')},
95 {tag:'table', children:[
96 {tag:'tbody', children:[
97 {tag:'tr', children:[
98 {tag:'td', width:'20%', children:[
99 {tag:'input', type:'checkbox', name:'lowercase', id:this.getId('lowercase'), checked:true},
100 {tag:'span', htmlString:Clipperz.PM.Strings['passwordGeneratorLowercaseLabel']}
101 ]},
102 {tag:'td', width:'20%', children:[
103 {tag:'input', type:'checkbox', name:'uppercase', id:this.getId('uppercase'), checked:true},
104 {tag:'span', htmlString:Clipperz.PM.Strings['passwordGeneratorUppercaseLabel']}
105 ]},
106 {tag:'td', width:'20%', children:[
107 {tag:'input', type:'checkbox', name:'numbers', id:this.getId('numbers'), checked:true},
108 {tag:'span', htmlString:Clipperz.PM.Strings['passwordGeneratorNumberLabel']}
109 ]},
110 {tag:'td', width:'20%', children:[
111 {tag:'input', type:'checkbox', name:'symbols', id:this.getId('symbols'), checked:true},
112 {tag:'span', htmlString:Clipperz.PM.Strings['passwordGeneratorSymbolLabel']}
113 ]},
114 {tag:'td', width:'20%', children:[
115 {tag:'span', cls:'passwordGeneratorLength', children:[
116 {tag:'span', htmlString:Clipperz.PM.Strings['passwordGeneratorLengthLabel']},
117 {tag:'span', id:this.getId('passwordLength'), cls:'passwordGeneratorLengthValue', html:'0'}
118 ]}
119 ]}
120 ]}
121 ]}
122 ]}
123 ]},
124 {tag:'div', id:this.getId('generateRandomPassword')}
125 ]}
126 //---------------------------------------------------
127
128 ]}
129 ]},
130 {tag:'li', id:this.getId('bookmarkletPanel'), children:[
131 {tag:'div', cls:'clipperzSubPanel', children:[
132 {tag:'h5', htmlString:Clipperz.PM.Strings['bookmarkletTabTitle']},
133 {tag:'div', cls:'panelDescription', htmlString:Clipperz.PM.Strings['bookmarkletTabDescription']},
134 {tag:'a', href:bookmarkletUrl, cls:'bookmarkletLink', htmlString:Clipperz.PM.Strings['bookmarkletTabBookmarkletTitle']},
135 {tag:'div', cls:'panelDescription', htmlString:Clipperz.PM.Strings['bookmarkletTabInstructions']}
136 ]}
137 ]},
138 {tag:'li', id:this.getId('compactPanel'), children:[
139 {tag:'div', cls:'clipperzSubPanel', children:[
140 {tag:'h5', htmlString:Clipperz.PM.Strings['compactTabTitle']},
141 {tag:'div', cls:'panelDescription', htmlString:Clipperz.PM.Strings['compactTabDescription']}
142 ]}
143 ]},
144 {tag:'li', id:this.getId('httpAuthPanel'), children:[
145 {tag:'div', cls:'clipperzSubPanel', children:[
146 {tag:'h5', htmlString:Clipperz.PM.Strings['httpAuthTabTitle']},
147 {tag:'div', cls:'panelDescription', htmlString:Clipperz.PM.Strings['httpAuthTabDescription']},
148 {tag:'div', cls:'bookmarkletConfiguration', children:[Clipperz.PM.Strings['httpAuthBookmarkletConfiguration']]}
149 ]}
150 ]}
151 ]}
152 ]}
153 ]}
154 ]}
155 ]});
156
157 new Clipperz.PM.Components.PasswordEntropyDisplay(this.getElement('passwordField'));
158
159 MochiKit.Signal.connect(this.getId('lowercase'), 'onclick', this, 'updatePasswordValue');
160 MochiKit.Signal.connect(this.getId('uppercase'), 'onclick', this, 'updatePasswordValue');
161 MochiKit.Signal.connect(this.getId('numbers'), 'onclick', this, 'updatePasswordValue');
162 MochiKit.Signal.connect(this.getId('symbols'), 'onclick', this, 'updatePasswordValue');
163
164 MochiKit.Signal.connect(this.getDom('passwordField'), 'onkeyup', this, 'updatePasswordLengthLabel');
165 MochiKit.Signal.connect(this.getDom('passwordField'), 'onchange', this, 'updatePasswordLengthLabel');
166 MochiKit.Signal.connect(this.getDom('passwordField'), 'onblur', this, 'updatePasswordLengthLabel');
167
168 this.setGenerateButtonElement(new YAHOO.ext.Button(this.getDom('generateRandomPassword'), {text:Clipperz.PM.Strings['passwordGeneratorTabButtonLabel'], handler:this.updatePasswordValue, scope:this}));
169
170 this.setNeedsRenderingUponTabSwitch(false);
171 this.tabPanelController().setUp();
172 Clipperz.NotificationCenter.register(null, 'tabSelected', this, 'tabSelectedHandler');
173 Clipperz.NotificationCenter.register(null, 'switchLanguage', this, 'switchLanguageHandler');
174//MochiKit.Logging.logDebug("<<< ToolsPanel.render");
175 },
176
177 //-------------------------------------------------------------------------
178
179 'needsRenderingUponTabSwitch': function() {
180 return this._needsRenderingUponTabSwitch;
181 },
182
183 'setNeedsRenderingUponTabSwitch': function(aValue) {
184 this._needsRenderingUponTabSwitch = aValue;
185 },
186
187 'tabSelectedHandler': function(anEvent) {
188 if (this.needsRenderingUponTabSwitch()) {
189 this.render();
190 }
191
192 if (anEvent.parameters() == this.getId('httpAuth')) {
193 var textarea;
194
195 textarea = document.getElementById("httpAuthDefaultConfiguration");
196 textarea.focus();
197 textarea.select();
198 }
199 },
200
201 //-------------------------------------------------------------------------
202
203 'tabPanelController': function() {
204 if (this._tabPanelController == null) {
205 var tabPanelControllerConfig;
206
207 tabPanelControllerConfig = {}
208 tabPanelControllerConfig[this.getId('passwordGenerator')] = this.getId('passwordGeneratorPanel');
209 tabPanelControllerConfig[this.getId('bookmarklet')] = this.getId('bookmarkletPanel');
210 tabPanelControllerConfig[this.getId('compact')] = this.getId('compactPanel');
211 tabPanelControllerConfig[this.getId('httpAuth')] = this.getId('httpAuthPanel');
212 this._tabPanelController = new Clipperz.PM.Components.TabPanel.TabPanelController({ config:tabPanelControllerConfig, selectedTab:this.getId('passwordGenerator') });
213 }
214
215 return this._tabPanelController;
216 },
217
218 //-------------------------------------------------------------------------
219
220 'generateButtonElement': function() {
221 return this._generateButtonElement;
222 },
223
224 'setGenerateButtonElement': function(aValue) {
225 this._generateButtonElement = aValue;
226 },
227
228 //-------------------------------------------------------------------------
229
230 'updatePasswordValue': function(anEvent) {
231 varrandomBytes;
232 varrandomValue;
233 var charset;
234 var charsetBitSize;
235 var stringValue;
236 varblockIndex;
237
238//MochiKit.Logging.logDebug(">>> updatePasswordValue");
239 randomBytes = Clipperz.Crypto.PRNG.defaultRandomGenerator().getRandomBytes(50);
240 stringValue = "";
241 blockIndex = 0;
242
243 charset = "";
244 if (this.getDom('lowercase').checked) {
245 charset += Clipperz.PM.Strings['passwordGeneratorLowercaseCharset'];
246 }
247 if (this.getDom('uppercase').checked) {
248 charset += Clipperz.PM.Strings['passwordGeneratorUppercaseCharset'];
249 }
250 if (this.getDom('numbers').checked) {
251 charset += Clipperz.PM.Strings['passwordGeneratorNumberCharset'];
252 }
253 if (this.getDom('symbols').checked) {
254 charset += Clipperz.PM.Strings['passwordGeneratorSymbolCharset'];
255 }
256
257 charsetBitSize = 0;
258 while (Math.pow(2, charsetBitSize) < charset.length) {
259 charsetBitSize ++;
260 }
261
262 if (charsetBitSize > 0) {
263 while (Clipperz.PM.Crypto.passwordEntropy(stringValue) < 128) {
264 if (((blockIndex + 1)*charsetBitSize) > (randomBytes.length() * 8)) {
265 randomBytes = Clipperz.Crypto.PRNG.defaultRandomGenerator().getRandomBytes(50);
266 blockIndex = 0;
267 }
268 randomValue = randomBytes.bitBlockAtIndexWithSize(blockIndex*charsetBitSize, charsetBitSize);
269 if (randomValue < charset.length) {
270 stringValue += charset.charAt(randomValue);
271 }
272
273 blockIndex ++;
274 }
275 } else {
276 stringValue = "";
277 }
278
279 this.getElement('passwordField').dom.focus()
280 this.getElement('passwordField').dom.value = stringValue;
281
282
283 if (anEvent.src) {
284 anEvent.src().focus();
285 } else {
286 this.generateButtonElement().el.focus();
287 }
288
289 this.setNeedsRenderingUponTabSwitch(true);
290
291 return false;
292//MochiKit.Logging.logDebug("<<< updatePasswordValue");
293 },
294
295 //-----------------------------------------------------
296
297 'updatePasswordLengthLabel': function() {
298 this.getElement('passwordLength').update(this.getDom('passwordField').value.length);
299 },
300
301 //-------------------------------------------------------------------------
302 __syntaxFix__: "syntax fix"
303
304});
305
diff --git a/frontend/beta/js/Clipperz/PM/Components/PasswordEntropyDisplay.js b/frontend/beta/js/Clipperz/PM/Components/PasswordEntropyDisplay.js
new file mode 100644
index 0000000..530d2cb
--- a/dev/null
+++ b/frontend/beta/js/Clipperz/PM/Components/PasswordEntropyDisplay.js
@@ -0,0 +1,118 @@
1/*
2
3Copyright 2008-2011 Clipperz Srl
4
5This file is part of Clipperz's Javascript Crypto Library.
6Javascript Crypto Library provides web developers with an extensive
7and efficient set of cryptographic functions. The library aims to
8obtain maximum execution speed while preserving modularity and
9reusability.
10For further information about its features and functionalities please
11refer to http://www.clipperz.com
12
13* Javascript Crypto Library is free software: you can redistribute
14 it and/or modify it under the terms of the GNU Affero General Public
15 License as published by the Free Software Foundation, either version
16 3 of the License, or (at your option) any later version.
17
18* Javascript Crypto Library is distributed in the hope that it will
19 be useful, but WITHOUT ANY WARRANTY; without even the implied
20 warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
21 See the GNU Affero General Public License for more details.
22
23* You should have received a copy of the GNU Affero General Public
24 License along with Javascript Crypto Library. If not, see
25 <http://www.gnu.org/licenses/>.
26
27*/
28
29if (typeof(Clipperz) == 'undefined') { Clipperz = {}; }
30if (typeof(Clipperz.PM) == 'undefined') { Clipperz.PM = {}; }
31if (typeof(Clipperz.PM.Components) == 'undefined') { Clipperz.PM.Components = {}; }
32
33Clipperz.PM.Components.PasswordEntropyDisplay = function(anElement, args) {
34 args = args || {};
35
36//MochiKit.Logging.logDebug(">>> new TextFormField");
37 Clipperz.PM.Components.PasswordEntropyDisplay.superclass.constructor.call(this, anElement, args);
38
39 this._wrapperElement = null;
40 this._entropyElement = null;
41
42 this.render();
43//MochiKit.Logging.logDebug("<<< new TextFormField");
44
45 return this;
46};
47
48YAHOO.extendX(Clipperz.PM.Components.PasswordEntropyDisplay, Clipperz.PM.Components.BaseComponent, {
49
50 'toString': function() {
51 return "Clipperz.PM.Components.PasswordEntropyDisplay";
52 },
53
54 //-----------------------------------------------------
55
56 'wrapperElement': function() {
57 return this._wrapperElement;
58 },
59
60 'setWrapperElement': function(aValue) {
61 this._wrapperElement = aValue;
62 },
63
64 //-----------------------------------------------------
65
66 'passwordElement': function() {
67 return this.element();
68 },
69
70 //-----------------------------------------------------
71
72 'entropyElement': function() {
73 return this._entropyElement;
74 },
75
76 'setEntropyElement': function(aValue) {
77 this._entropyElement = aValue;
78 },
79
80 //-----------------------------------------------------
81
82 'render': function() {
83 MochiKit.Signal.disconnectAllTo(this);
84
85 this.setWrapperElement(this.element().wrap({tag:'div'}));
86 this.setEntropyElement(Clipperz.YUI.DomHelper.append(this.wrapperElement().dom, {tag:'div', cls:'passwordEntropy', html:"&nbsp;"}, true));
87
88 // this.entropyElement().setWidth(this.passwordElement().getWidth());
89 this.updateEntropyElement();
90
91 MochiKit.Signal.connect(this.element().dom, 'onkeyup', this, 'updateEntropyElement');
92 MochiKit.Signal.connect(this.element().dom, 'onchange', this, 'updateEntropyElement');
93 MochiKit.Signal.connect(this.element().dom, 'onblur', this, 'updateEntropyElement');
94 },
95
96 //-----------------------------------------------------
97
98 'computeEntropyForString': function(aValue) {
99 return Clipperz.PM.Crypto.passwordEntropy(aValue);
100 },
101
102 //-----------------------------------------------------
103
104 'updateEntropyElement': function(anEvent) {
105//MochiKit.Logging.logDebug(">>> PasswordEntropyDisplay.updateEntropyElement");
106 varmaxExtent;
107 varentropy;
108
109 entropy = Math.min(128, this.computeEntropyForString(this.passwordElement().dom.value));
110//MochiKit.Logging.logDebug("--- PasswordEntropyDisplay.updateEntropyElement - entropy: " + entropy);
111 this.entropyElement().setStyle('background-position', "0px " + -entropy + "px");
112 this.entropyElement().setWidth(this.passwordElement().getWidth() * (entropy/128));
113//MochiKit.Logging.logDebug("<<< PasswordEntropyDisplay.updateEntropyElement");
114 },
115
116 //-----------------------------------------------------
117 __syntaxFix__: '__syntaxFix__'
118});
diff --git a/frontend/beta/js/Clipperz/PM/Components/PasswordGenerator.js b/frontend/beta/js/Clipperz/PM/Components/PasswordGenerator.js
new file mode 100644
index 0000000..8195f2e
--- a/dev/null
+++ b/frontend/beta/js/Clipperz/PM/Components/PasswordGenerator.js
@@ -0,0 +1,285 @@
1/*
2
3Copyright 2008-2011 Clipperz Srl
4
5This file is part of Clipperz's Javascript Crypto Library.
6Javascript Crypto Library provides web developers with an extensive
7and efficient set of cryptographic functions. The library aims to
8obtain maximum execution speed while preserving modularity and
9reusability.
10For further information about its features and functionalities please
11refer to http://www.clipperz.com
12
13* Javascript Crypto Library is free software: you can redistribute
14 it and/or modify it under the terms of the GNU Affero General Public
15 License as published by the Free Software Foundation, either version
16 3 of the License, or (at your option) any later version.
17
18* Javascript Crypto Library is distributed in the hope that it will
19 be useful, but WITHOUT ANY WARRANTY; without even the implied
20 warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
21 See the GNU Affero General Public License for more details.
22
23* You should have received a copy of the GNU Affero General Public
24 License along with Javascript Crypto Library. If not, see
25 <http://www.gnu.org/licenses/>.
26
27*/
28
29if (typeof(Clipperz) == 'undefined') { Clipperz = {}; }
30if (typeof(Clipperz.PM) == 'undefined') { Clipperz.PM = {}; }
31if (typeof(Clipperz.PM.Components) == 'undefined') { Clipperz.PM.Components = {}; }
32
33Clipperz.PM.Components.PasswordGenerator = function(anElement, aFieldValueComponent, args) {
34 args = args || {};
35
36//MochiKit.Logging.logDebug(">>> new TextFormField");
37 Clipperz.PM.Components.PasswordGenerator.superclass.constructor.call(this, anElement, args);
38
39 this._fieldValueComponent = aFieldValueComponent;
40 this._panelButton = null;
41 this.render();
42//MochiKit.Logging.logDebug("<<< new TextFormField");
43
44 return this;
45};
46
47YAHOO.extendX(Clipperz.PM.Components.PasswordGenerator, Clipperz.PM.Components.BaseComponent, {
48
49 'toString': function() {
50 return "Clipperz.PM.Components.PasswordGenerator";
51 },
52
53 //-----------------------------------------------------
54
55 'fieldValueComponent': function() {
56 return this._fieldValueComponent;
57 },
58
59 //-----------------------------------------------------
60
61 'render': function() {
62 MochiKit.Signal.disconnectAllTo(this);
63
64 // this._panelButton = new YAHOO.ext.Button(this.element().dom, {text:Clipperz.PM.Strings['passwordGeneratorButtonLabel'], handler:this.openPasswordPanel, scope:this});
65 MochiKit.Signal.connect(this.element().dom, 'onmouseenter', this, 'onMouseEnter');
66 MochiKit.Signal.connect(this.element().dom, 'onmouseleave', this, 'onMouseLeave');
67 MochiKit.Signal.connect(this.element().dom, 'onclick', this, 'openPasswordPanel');
68 },
69
70 //-----------------------------------------------------
71
72 'onMouseEnter': function() {
73 this.element().addClass('hover');
74 },
75
76 'onMouseLeave': function() {
77 this.element().removeClass('hover');
78 },
79
80 //-----------------------------------------------------
81
82 'panelButton': function() {
83 return this._panelButton;
84 },
85
86 //-----------------------------------------------------
87
88 'openPasswordPanel': function() {
89 var passwordGeneratorElement;
90 var passwordGeneratorDialog;
91 var cancelButton;
92 var okButton;
93 var cancelFunction;
94 var okFunction;
95
96//MochiKit.Logging.logDebug(">>> PasswordGenerator.openPasswordPanel");
97 passwordGeneratorElement = Clipperz.YUI.DomHelper.append(document.body, {tag:'div', id:'passwordGenerator', children:[
98 {tag:'div', cls:'ydlg-hd', htmlString:Clipperz.PM.Strings['passwordGeneratorPanelTitle']},
99 {tag:'div', cls:'ydlg-bd', children:[
100 {tag:'form', id:this.getId('passwordGeneratorForm'), cls:'passwordGenerator', children:[
101 {tag:'input', type:'text', cls:'clipperz_passwordGenerator_password', id:this.getId('passwordField')},
102 {tag:'table', children:[
103 {tag:'tbody', children:[
104 {tag:'tr', children:[
105 {tag:'td', width:'20%', children:[
106 {tag:'input', type:'checkbox', name:'lowercase', id:this.getId('lowercase'), checked:true},
107 {tag:'span', htmlString:Clipperz.PM.Strings['passwordGeneratorLowercaseLabel']}
108 ]},
109 {tag:'td', width:'20%', children:[
110 {tag:'input', type:'checkbox', name:'uppercase', id:this.getId('uppercase'), checked:true},
111 {tag:'span', htmlString:Clipperz.PM.Strings['passwordGeneratorUppercaseLabel']}
112 ]},
113 {tag:'td', width:'20%', children:[
114 {tag:'input', type:'checkbox', name:'numbers', id:this.getId('numbers'), checked:true},
115 {tag:'span', htmlString:Clipperz.PM.Strings['passwordGeneratorNumberLabel']}
116 ]},
117 {tag:'td', width:'20%', children:[
118 {tag:'input', type:'checkbox', name:'symbols', id:this.getId('symbols'), checked:true},
119 {tag:'span', htmlString:Clipperz.PM.Strings['passwordGeneratorSymbolLabel']}
120 ]},
121 {tag:'td', width:'20%', children:[
122 {tag:'span', cls:'passwordGeneratorLength', children:[
123 {tag:'span', htmlString:Clipperz.PM.Strings['passwordGeneratorLengthLabel']},
124 {tag:'span', id:this.getId('passwordLength'), cls:'passwordGeneratorLengthValue', html:'0'}
125 ]}
126 ]}
127 ]}
128 ]}
129 ]}
130 ]}
131 ]},
132 {tag:'div', cls:'ydlg-ft'}
133 ]}, true);
134
135 new Clipperz.PM.Components.PasswordEntropyDisplay(this.getElement('passwordField'));
136
137 MochiKit.Signal.connect(this.getId('lowercase'), 'onclick', this, 'updatePasswordValue');
138 MochiKit.Signal.connect(this.getId('uppercase'), 'onclick', this, 'updatePasswordValue');
139 MochiKit.Signal.connect(this.getId('numbers'), 'onclick', this, 'updatePasswordValue');
140 MochiKit.Signal.connect(this.getId('symbols'), 'onclick', this, 'updatePasswordValue');
141
142 MochiKit.Signal.connect(this.getDom('passwordField'), 'onkeyup', this, 'updatePasswordLengthLabel');
143 MochiKit.Signal.connect(this.getDom('passwordField'), 'onchange', this, 'updatePasswordLengthLabel');
144 MochiKit.Signal.connect(this.getDom('passwordField'), 'onblur', this, 'updatePasswordLengthLabel');
145
146 this.updatePasswordValue();
147
148 passwordGeneratorDialog = new YAHOO.ext.BasicDialog(
149 passwordGeneratorElement, {
150 autoCreate:false,
151 closable:false,
152 modal:true,
153 autoTabs:false,
154 resizable:false,
155 fixedcenter:true,
156 constraintoviewport:false,
157 width:320,
158 height:130,
159 shadow:true,
160 minWidth:200,
161 minHeight:100
162 }
163 );
164
165 cancelFunction = MochiKit.Base.partial(MochiKit.Base.bind(this.cancelPasswordPanel, this), passwordGeneratorDialog);
166 passwordGeneratorDialog.addKeyListener(27, cancelFunction);
167 cancelButton = passwordGeneratorDialog.addButton(Clipperz.PM.Strings['passwordGeneratorPanelCancelLabel'], cancelFunction, this);
168
169 okFunction = MochiKit.Base.partial(MochiKit.Base.bind(this.okPasswordPanel, this), passwordGeneratorDialog);
170 passwordGeneratorDialog.addKeyListener([10, 13], okFunction);
171 okButton = passwordGeneratorDialog.addButton(Clipperz.PM.Strings['passwordGeneratorPanelOkLabel'], okFunction, this);
172
173 MochiKit.Signal.connect(this.getId('passwordGeneratorForm'), 'onsubmit', okFunction);
174
175 passwordGeneratorDialog.setDefaultButton(okButton);
176
177 this.fieldValueComponent().mainComponent().mainPanel().exitModalView();
178 this.fieldValueComponent().mainComponent().scrollToTop();
179
180 // passwordGeneratorDialog.show(this.panelButton().getEl());
181 passwordGeneratorDialog.show(this.element());
182 this.onMouseLeave();
183 },
184
185 //-----------------------------------------------------
186
187 'cancelPasswordPanel': function(aPasswordGeneratorPanel) {
188 this.fieldValueComponent().mainComponent().mainPanel().enterModalView();
189 aPasswordGeneratorPanel.hide(MochiKit.Base.bind(function() {
190 aPasswordGeneratorPanel.destroy(true);
191 MochiKit.Signal.disconnectAllTo(this);
192 }, this));
193 },
194
195 //-----------------------------------------------------
196
197 'updatePasswordLengthLabel': function() {
198 this.getElement('passwordLength').update(this.getDom('passwordField').value.length);
199 },
200
201 //-----------------------------------------------------
202
203 'okPasswordPanel': function(aPasswordGeneratorPanel, anEvent) {
204//MochiKit.Logging.logDebug(">>> PasswordGenerator.okPasswordPanel");
205
206 if (anEvent.stop) {
207 anEvent.stop();
208 }
209
210 this.fieldValueComponent().inputElement().dom.focus();
211 this.fieldValueComponent().inputElement().dom.value = this.getElement('passwordField').dom.value;
212 this.getElement('passwordField').dom.focus();
213 this.cancelPasswordPanel(aPasswordGeneratorPanel);
214
215 return false;
216 },
217
218 //-----------------------------------------------------
219
220 'updatePasswordValue': function(anEvent) {
221 varrandomBytes;
222 varrandomValue;
223 var charset;
224 var charsetBitSize;
225 var stringValue;
226 varblockIndex;
227
228//MochiKit.Logging.logDebug(">>> updatePasswordValue");
229 randomBytes = Clipperz.Crypto.PRNG.defaultRandomGenerator().getRandomBytes(50);
230 stringValue = "";
231 blockIndex = 0;
232
233 charset = "";
234 if (this.getDom('lowercase').checked) {
235 charset += Clipperz.PM.Strings['passwordGeneratorLowercaseCharset'];
236 }
237 if (this.getDom('uppercase').checked) {
238 charset += Clipperz.PM.Strings['passwordGeneratorUppercaseCharset'];
239 }
240 if (this.getDom('numbers').checked) {
241 charset += Clipperz.PM.Strings['passwordGeneratorNumberCharset'];
242 }
243 if (this.getDom('symbols').checked) {
244 charset += Clipperz.PM.Strings['passwordGeneratorSymbolCharset'];
245 }
246
247 charsetBitSize = 0;
248 while (Math.pow(2, charsetBitSize) < charset.length) {
249 charsetBitSize ++;
250 }
251
252 if (charsetBitSize > 0) {
253 while (Clipperz.PM.Crypto.passwordEntropy(stringValue) < 128) {
254 if (((blockIndex + 1)*charsetBitSize) > (randomBytes.length() * 8)) {
255 randomBytes = Clipperz.Crypto.PRNG.defaultRandomGenerator().getRandomBytes(50);
256 blockIndex = 0;
257 }
258 randomValue = randomBytes.bitBlockAtIndexWithSize(blockIndex*charsetBitSize, charsetBitSize);
259 if (randomValue < charset.length) {
260 stringValue += charset.charAt(randomValue);
261 }
262
263 blockIndex ++;
264 }
265 } else {
266 stringValue = "";
267 }
268
269 this.getElement('passwordField').dom.focus()
270 this.getElement('passwordField').dom.value = stringValue;
271
272
273 if (anEvent) {
274 anEvent.src().focus();
275 } else {
276 this.element().focus();
277 }
278
279 return false;
280//MochiKit.Logging.logDebug("<<< updatePasswordValue");
281 },
282
283 //-----------------------------------------------------
284 __syntaxFix__: '__syntaxFix__'
285});
diff --git a/frontend/beta/js/Clipperz/PM/Components/Printing/Footer.js b/frontend/beta/js/Clipperz/PM/Components/Printing/Footer.js
new file mode 100644
index 0000000..6bede3e
--- a/dev/null
+++ b/frontend/beta/js/Clipperz/PM/Components/Printing/Footer.js
@@ -0,0 +1,28 @@
1/*
2
3Copyright 2008-2011 Clipperz Srl
4
5This file is part of Clipperz's Javascript Crypto Library.
6Javascript Crypto Library provides web developers with an extensive
7and efficient set of cryptographic functions. The library aims to
8obtain maximum execution speed while preserving modularity and
9reusability.
10For further information about its features and functionalities please
11refer to http://www.clipperz.com
12
13* Javascript Crypto Library is free software: you can redistribute
14 it and/or modify it under the terms of the GNU Affero General Public
15 License as published by the Free Software Foundation, either version
16 3 of the License, or (at your option) any later version.
17
18* Javascript Crypto Library is distributed in the hope that it will
19 be useful, but WITHOUT ANY WARRANTY; without even the implied
20 warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
21 See the GNU Affero General Public License for more details.
22
23* You should have received a copy of the GNU Affero General Public
24 License along with Javascript Crypto Library. If not, see
25 <http://www.gnu.org/licenses/>.
26
27*/
28
diff --git a/frontend/beta/js/Clipperz/PM/Components/Printing/Header.js b/frontend/beta/js/Clipperz/PM/Components/Printing/Header.js
new file mode 100644
index 0000000..6bede3e
--- a/dev/null
+++ b/frontend/beta/js/Clipperz/PM/Components/Printing/Header.js
@@ -0,0 +1,28 @@
1/*
2
3Copyright 2008-2011 Clipperz Srl
4
5This file is part of Clipperz's Javascript Crypto Library.
6Javascript Crypto Library provides web developers with an extensive
7and efficient set of cryptographic functions. The library aims to
8obtain maximum execution speed while preserving modularity and
9reusability.
10For further information about its features and functionalities please
11refer to http://www.clipperz.com
12
13* Javascript Crypto Library is free software: you can redistribute
14 it and/or modify it under the terms of the GNU Affero General Public
15 License as published by the Free Software Foundation, either version
16 3 of the License, or (at your option) any later version.
17
18* Javascript Crypto Library is distributed in the hope that it will
19 be useful, but WITHOUT ANY WARRANTY; without even the implied
20 warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
21 See the GNU Affero General Public License for more details.
22
23* You should have received a copy of the GNU Affero General Public
24 License along with Javascript Crypto Library. If not, see
25 <http://www.gnu.org/licenses/>.
26
27*/
28
diff --git a/frontend/beta/js/Clipperz/PM/Components/Printing/Record.js b/frontend/beta/js/Clipperz/PM/Components/Printing/Record.js
new file mode 100644
index 0000000..910d4b1
--- a/dev/null
+++ b/frontend/beta/js/Clipperz/PM/Components/Printing/Record.js
@@ -0,0 +1,95 @@
1/*
2
3Copyright 2008-2011 Clipperz Srl
4
5This file is part of Clipperz's Javascript Crypto Library.
6Javascript Crypto Library provides web developers with an extensive
7and efficient set of cryptographic functions. The library aims to
8obtain maximum execution speed while preserving modularity and
9reusability.
10For further information about its features and functionalities please
11refer to http://www.clipperz.com
12
13* Javascript Crypto Library is free software: you can redistribute
14 it and/or modify it under the terms of the GNU Affero General Public
15 License as published by the Free Software Foundation, either version
16 3 of the License, or (at your option) any later version.
17
18* Javascript Crypto Library is distributed in the hope that it will
19 be useful, but WITHOUT ANY WARRANTY; without even the implied
20 warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
21 See the GNU Affero General Public License for more details.
22
23* You should have received a copy of the GNU Affero General Public
24 License along with Javascript Crypto Library. If not, see
25 <http://www.gnu.org/licenses/>.
26
27*/
28
29if (typeof(Clipperz) == 'undefined') { Clipperz = {}; }
30if (typeof(Clipperz.PM) == 'undefined') { Clipperz.PM = {}; }
31if (typeof(Clipperz.PM.Components) == 'undefined') { Clipperz.PM.Components = {}; }
32if (typeof(Clipperz.PM.Components.Printing) == 'undefined') { Clipperz.PM.Components.Printing = {}; }
33
34Clipperz.PM.Components.Printing.Record = function(args) {
35 args = args || {};
36
37 this._record = args['record'];
38
39 return this;
40}
41
42MochiKit.Base.update(Clipperz.PM.Components.Printing.Record.prototype, {
43
44 'record': function() {
45 return this._record;
46 },
47
48 //-------------------------------------------------------------------------
49
50 'deferredDrawToWindow': function(aWindow) {
51 vardeferredResult;
52
53 deferredResult = new MochiKit.Async.Deferred();
54 deferredResult.addCallback(MochiKit.Base.method(this.record(), 'deferredData'));
55 deferredResult.addCallback(MochiKit.Base.method(this, 'appendToWindow', aWindow));
56 deferredResult.callback();
57 return deferredResult;
58 },
59
60 //-------------------------------------------------------------------------
61
62 'appendToWindow': function(aWindow) {
63 MochiKit.DOM.withWindow(aWindow, MochiKit.Base.bind(function() {
64 var newBlock;
65 var fields;
66
67 fields = MochiKit.Base.concat(
68 MochiKit.Base.map(MochiKit.Base.bind(function(aField) {
69 var result;
70 var dt, dd;
71 var label, value;
72
73 label = aField.label();
74 value = aField.value();
75 dt = MochiKit.DOM.createDOM('DT', null, label);
76 dd = MochiKit.DOM.createDOM('DD', null, value)
77 result = [dt, dd];
78
79 return result
80 }, this), MochiKit.Base.values(this.record().currentVersion().fields()))
81 );
82
83 newBlock = MochiKit.DOM.DIV({'class': 'recordBlock'},
84 MochiKit.DOM.H2(null, this.record().label()),
85 MochiKit.DOM.DIV({'class': 'recordNotes'}, MochiKit.Base.map(MochiKit.Base.partial(MochiKit.DOM.P, null), this.record().notes().split("\n"))),
86 MochiKit.DOM.createDOM('DL', null, fields)
87 );
88 MochiKit.DOM.appendChildNodes(MochiKit.DOM.currentDocument().body, newBlock);
89
90 }, this));
91 },
92
93 //-------------------------------------------------------------------------
94 __syntaxFix__: "syntax fix"
95});
diff --git a/frontend/beta/js/Clipperz/PM/Components/RecordDetail/AbstractComponent.js b/frontend/beta/js/Clipperz/PM/Components/RecordDetail/AbstractComponent.js
new file mode 100644
index 0000000..840d555
--- a/dev/null
+++ b/frontend/beta/js/Clipperz/PM/Components/RecordDetail/AbstractComponent.js
@@ -0,0 +1,105 @@
1/*
2
3Copyright 2008-2011 Clipperz Srl
4
5This file is part of Clipperz's Javascript Crypto Library.
6Javascript Crypto Library provides web developers with an extensive
7and efficient set of cryptographic functions. The library aims to
8obtain maximum execution speed while preserving modularity and
9reusability.
10For further information about its features and functionalities please
11refer to http://www.clipperz.com
12
13* Javascript Crypto Library is free software: you can redistribute
14 it and/or modify it under the terms of the GNU Affero General Public
15 License as published by the Free Software Foundation, either version
16 3 of the License, or (at your option) any later version.
17
18* Javascript Crypto Library is distributed in the hope that it will
19 be useful, but WITHOUT ANY WARRANTY; without even the implied
20 warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
21 See the GNU Affero General Public License for more details.
22
23* You should have received a copy of the GNU Affero General Public
24 License along with Javascript Crypto Library. If not, see
25 <http://www.gnu.org/licenses/>.
26
27*/
28
29if (typeof(Clipperz) == 'undefined') { Clipperz = {}; }
30if (typeof(Clipperz.PM) == 'undefined') { Clipperz.PM = {}; }
31if (typeof(Clipperz.PM.Components) == 'undefined') { Clipperz.PM.Components = {}; }
32if (typeof(Clipperz.PM.Components.RecordDetail) == 'undefined') { Clipperz.PM.Components.RecordDetail = {}; }
33
34//#############################################################################
35
36Clipperz.PM.Components.RecordDetail.AbstractComponent = function(anElement, args) {
37 args = args || {};
38
39 Clipperz.PM.Components.RecordDetail.AbstractComponent.superclass.constructor.call(this, args);
40
41 this._element = anElement;
42 this._mainComponent = args.mainComponent;
43
44 return this;
45}
46
47//=============================================================================
48
49YAHOO.extendX(Clipperz.PM.Components.RecordDetail.AbstractComponent, Clipperz.PM.Components.BaseComponent, {
50
51 'toString': function() {
52 return "Clipperz.PM.Components.RecordDetail.AbstractComponent";
53 },
54
55 //-------------------------------------------------------------------------
56
57 'mainComponent': function() {
58 return this._mainComponent;
59 },
60
61 //-------------------------------------------------------------------------
62
63 'record': function() {
64 return this.mainComponent().record();
65 },
66
67 //-------------------------------------------------------------------------
68
69 'editMode': function() {
70 return this.mainComponent().editMode();
71 },
72
73 //-------------------------------------------------------------------------
74
75 'render': function() {
76 this.element().update("");
77 this.update();
78 },
79
80 //-------------------------------------------------------------------------
81
82 'update': function(anEvent) {
83 if (this.editMode() == 'EDIT') {
84 this.updateEditMode();
85 } else if (this.editMode() == 'VIEW') {
86 this.updateViewMode();
87 }
88 },
89
90 //-------------------------------------------------------------------------
91
92 'updateViewMode': function() {},
93 'updateEditMode': function() {},
94 'synchronizeComponentValues': function() {},
95
96 //-------------------------------------------------------------------------
97
98 'destroy': function() {
99 this.element().remove();
100 },
101
102 //-------------------------------------------------------------------------
103 __syntaxFix__: "syntax fix"
104});
105
diff --git a/frontend/beta/js/Clipperz/PM/Components/RecordDetail/AbstractFieldSubComponent.js b/frontend/beta/js/Clipperz/PM/Components/RecordDetail/AbstractFieldSubComponent.js
new file mode 100644
index 0000000..7596184
--- a/dev/null
+++ b/frontend/beta/js/Clipperz/PM/Components/RecordDetail/AbstractFieldSubComponent.js
@@ -0,0 +1,77 @@
1/*
2
3Copyright 2008-2011 Clipperz Srl
4
5This file is part of Clipperz's Javascript Crypto Library.
6Javascript Crypto Library provides web developers with an extensive
7and efficient set of cryptographic functions. The library aims to
8obtain maximum execution speed while preserving modularity and
9reusability.
10For further information about its features and functionalities please
11refer to http://www.clipperz.com
12
13* Javascript Crypto Library is free software: you can redistribute
14 it and/or modify it under the terms of the GNU Affero General Public
15 License as published by the Free Software Foundation, either version
16 3 of the License, or (at your option) any later version.
17
18* Javascript Crypto Library is distributed in the hope that it will
19 be useful, but WITHOUT ANY WARRANTY; without even the implied
20 warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
21 See the GNU Affero General Public License for more details.
22
23* You should have received a copy of the GNU Affero General Public
24 License along with Javascript Crypto Library. If not, see
25 <http://www.gnu.org/licenses/>.
26
27*/
28
29if (typeof(Clipperz) == 'undefined') { Clipperz = {}; }
30if (typeof(Clipperz.PM) == 'undefined') { Clipperz.PM = {}; }
31if (typeof(Clipperz.PM.Components) == 'undefined') { Clipperz.PM.Components = {}; }
32if (typeof(Clipperz.PM.Components.RecordDetail) == 'undefined') { Clipperz.PM.Components.RecordDetail = {}; }
33
34//#############################################################################
35
36Clipperz.PM.Components.RecordDetail.AbstractFieldSubComponent = function(anElement, args) {
37 args = args || {};
38
39 Clipperz.PM.Components.RecordDetail.AbstractFieldSubComponent.superclass.constructor.call(this, anElement, args);
40
41 this._fieldComponent = args.fieldComponent || null;
42
43 this.render();
44
45 return this;
46}
47
48//=============================================================================
49
50YAHOO.extendX(Clipperz.PM.Components.RecordDetail.AbstractFieldSubComponent, Clipperz.PM.Components.RecordDetail.AbstractComponent, {
51
52 'toString': function() {
53 return "Clipperz.PM.Components.RecordDetail.AbstractFieldSubComponent";
54 },
55
56 //-------------------------------------------------------------------------
57
58 'fieldComponent': function() {
59 return this._fieldComponent;
60 },
61
62 //-------------------------------------------------------------------------
63
64 'mainComponent': function() {
65 return this.fieldComponent().mainComponent();
66 },
67
68 //-------------------------------------------------------------------------
69
70 'recordField': function() {
71 return this.fieldComponent().recordField();
72 },
73
74 //-------------------------------------------------------------------------
75 __syntaxFix__: "syntax fix"
76});
77
diff --git a/frontend/beta/js/Clipperz/PM/Components/RecordDetail/CreationWizard.js b/frontend/beta/js/Clipperz/PM/Components/RecordDetail/CreationWizard.js
new file mode 100644
index 0000000..a92285f
--- a/dev/null
+++ b/frontend/beta/js/Clipperz/PM/Components/RecordDetail/CreationWizard.js
@@ -0,0 +1,317 @@
1/*
2
3Copyright 2008-2011 Clipperz Srl
4
5This file is part of Clipperz's Javascript Crypto Library.
6Javascript Crypto Library provides web developers with an extensive
7and efficient set of cryptographic functions. The library aims to
8obtain maximum execution speed while preserving modularity and
9reusability.
10For further information about its features and functionalities please
11refer to http://www.clipperz.com
12
13* Javascript Crypto Library is free software: you can redistribute
14 it and/or modify it under the terms of the GNU Affero General Public
15 License as published by the Free Software Foundation, either version
16 3 of the License, or (at your option) any later version.
17
18* Javascript Crypto Library is distributed in the hope that it will
19 be useful, but WITHOUT ANY WARRANTY; without even the implied
20 warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
21 See the GNU Affero General Public License for more details.
22
23* You should have received a copy of the GNU Affero General Public
24 License along with Javascript Crypto Library. If not, see
25 <http://www.gnu.org/licenses/>.
26
27*/
28
29if (typeof(Clipperz) == 'undefined') { Clipperz = {}; }
30if (typeof(Clipperz.PM) == 'undefined') { Clipperz.PM = {}; }
31if (typeof(Clipperz.PM.Components) == 'undefined') { Clipperz.PM.Components = {}; }
32if (typeof(Clipperz.PM.Components.RecordDetail) == 'undefined') { Clipperz.PM.Components.RecordDetail = {}; }
33
34//#############################################################################
35
36Clipperz.PM.Components.RecordDetail.CreationWizard = function(anElement, args) {
37 args = args || {};
38
39 Clipperz.PM.Components.RecordDetail.CreationWizard.superclass.constructor.call(this, anElement, args);
40
41 this._mainComponent = args.mainComponent;
42 this._previouslySelectedRecord = args.previouslySelectedRecord;
43//MochiKit.Logging.logDebug("--- new CreationWizard - previouslySelectedRecord: " + args.previouslySelectedRecord);
44 this._createButton_header = null;
45 this._createButton_footer = null;
46
47 this._cancelButton_header = null;
48 this._cancelButton_footer = null;
49
50 this.render();
51
52 return this;
53}
54
55//=============================================================================
56
57YAHOO.extendX(Clipperz.PM.Components.RecordDetail.CreationWizard, Clipperz.PM.Components.BaseComponent, {
58
59 'toString': function() {
60 return "Clipperz.PM.Components.RecordDetail.CreationWizard component";
61 },
62
63 //-------------------------------------------------------------------------
64
65 'previouslySelectedRecord': function() {
66 return this._previouslySelectedRecord;
67 },
68
69 //-------------------------------------------------------------------------
70
71 'render': function() {
72 vartemplateListElement;
73 vartemplates;
74
75 this.element().update("");
76
77 Clipperz.YUI.DomHelper.append(this.element().dom,
78 {tag:'form', cls:'recordDataFORM', id:this.getId('form'), children:[
79 {tag:'div', id:'recordDetailDataBox', cls:'recordDetailDataBox', children:[
80 {tag:'div', id:this.getId('wizardBox'), cls:'recordCreationWizard', children:[
81 {tag:'div', id:this.getId('recordCreationWizardTitleBox'), cls:'recordCreationWizardTitleBox', htmlString:Clipperz.PM.Strings['newRecordWizardTitleBox']},
82 {tag:'ul', id:this.getId('templateList'), cls:'radioList'}
83 ]}
84 ]}
85 ]}
86 );
87
88 Clipperz.YUI.DomHelper.append(this.getDom('recordCreationWizardTitleBox'), {tag:'div', cls:'newRecordWizardHeader', children:[
89 {tag:'table', width:'100%', cellpadding:'5', children:[
90 {tag:'tbody', children:[
91 {tag:'tr', children:[
92 {tag:'td', width:'49%', align:'right', children:[
93 {tag:'div', id:this.getId('cancelButton_header')}
94 ]},
95 {tag:'td', width:'10', html:'&nbsp;'},
96 {tag:'td', width:'49%', align:'left', children:[
97 {tag:'div', id:this.getId('createButton_header')}
98 ]}
99 ]}
100 ]}
101 ]}
102 ]});
103
104 templateListElement = this.getElement('templateList');
105 templates = Clipperz.PM.Strings['recordTemplates'];
106 MochiKit.Iter.forEach(MochiKit.Base.keys(templates), MochiKit.Base.bind(function(aTemplateKey) {
107 Clipperz.YUI.DomHelper.append(templateListElement.dom, {tag:'li', children:[
108 {tag:'table', children:[
109 {tag:'tbody', children:[
110 {tag:'tr', children:[
111 {tag:'td', valign:'top', children:[
112 {tag:'input', id:this.getId(aTemplateKey+"_radio"), type:'radio', name:'recordTemplate', value:"aTemplateKey"}
113 ]},
114 {tag:'td', valign:'top', children:[
115 {tag:'h4', id:this.getId(aTemplateKey+"_title"), html:templates[aTemplateKey]['title']},
116 {tag:'div', cls:'templateDescription', htmlString:templates[aTemplateKey]['description']}
117 ]}
118 ]}
119 ]}
120 ]}
121 ]});
122 this.getElement(aTemplateKey+"_radio").dom.value = aTemplateKey;
123 MochiKit.Signal.connect(this.getDom(aTemplateKey+"_title"), 'onclick', MochiKit.Base.partial(function(aRadioButton) {aRadioButton.click();}, this.getDom(aTemplateKey+"_radio")));
124 }, this));
125
126 Clipperz.YUI.DomHelper.append(templateListElement.dom, {tag:'li', children:[
127 {tag:'table', children:[
128 {tag:'tbody', children:[
129 {tag:'tr', children:[
130 {tag:'td', valign:'top', children:[
131 {tag:'input', type:'radio', name:'recordTemplate', id:this.getId('bookmarkletRadioButton'), value:'BookmarkletConfigurationTemplate'}
132 ]},
133 {tag:'td', valign:'top', children:[
134 {tag:'h4', htmlString:Clipperz.PM.Strings['newRecordWizardBookmarkletConfigurationTitle']},
135 {tag:'div', cls:'templateDescription', htmlString:Clipperz.PM.Strings['newRecordWizardBookmarkletConfigurationDescription']},
136 {tag:'div', cls:'bookmarkletConfiguration', children:[
137 // {tag:'span', htmlString:Clipperz.PM.Strings['newRecordWizardBookmarkletConfigurationLabel']},
138 {tag:'div', htmlString:Clipperz.PM.Strings['recordDetailNewDirectLoginDescription']},
139 {tag:'textarea', id:this.getId('bookmarkletConfiguration')}
140 ]}
141 ]}
142 ]}
143 ]}
144 ]}
145 ]});
146
147 Clipperz.YUI.DomHelper.append(this.getDom('wizardBox'), {tag:'div', cls:'newRecordWizardFooter', children:[
148 {tag:'table', width:'100%', cellpadding:'5', children:[
149 {tag:'tbody', children:[
150 {tag:'tr', children:[
151 {tag:'td', width:'49%', align:'right', children:[
152 {tag:'div', id:this.getId('cancelButton_footer')}
153 ]},
154 {tag:'td', width:'10', html:'&nbsp;'},
155 {tag:'td', width:'49%', align:'left', children:[
156 {tag:'div', id:this.getId('createButton_footer')}
157 ]}
158 ]}
159 ]}
160 ]}
161 ]});
162
163 this.setCreateButton_header(new YAHOO.ext.Button(this.getDom('createButton_header'), {text:Clipperz.PM.Strings['newRecordWizardCreateButtonLabel'], handler:this.createRecord, scope:this}));
164 this.setCreateButton_footer(new YAHOO.ext.Button(this.getDom('createButton_footer'), {text:Clipperz.PM.Strings['newRecordWizardCreateButtonLabel'], handler:this.createRecord, scope:this}));
165
166 this.setCancelButton_header(new YAHOO.ext.Button(this.getDom('cancelButton_header'), {text:Clipperz.PM.Strings['newRecordWizardCancelButtonLabel'], handler:this.exitWizard, scope:this}));
167 this.setCancelButton_footer(new YAHOO.ext.Button(this.getDom('cancelButton_footer'), {text:Clipperz.PM.Strings['newRecordWizardCancelButtonLabel'], handler:this.exitWizard, scope:this}));
168
169 this.createButton_header().disable();
170 this.createButton_footer().disable();
171
172 MochiKit.Iter.forEach(this.getElement('form').getChildrenByTagName('input'), MochiKit.Base.bind(function(anInput) {
173 // MochiKit.Signal.connect(anInput.dom, 'onchange', this, 'enableCreateButton');
174 MochiKit.Signal.connect(anInput.dom, 'onclick', this, 'enableCreateButton'); //for Safari
175 },this));
176
177 MochiKit.Signal.connect(this.getDom('bookmarkletConfiguration'), 'onkeyup', this, 'enableCreateButton');
178 MochiKit.Signal.connect(this.getDom('bookmarkletConfiguration'), 'onkeydown', this, 'enableCreateButton'); //for Safari
179 },
180
181 //-------------------------------------------------------------------------
182
183 'createButton_header': function() {
184 return this._createButton_header;
185 },
186
187 'setCreateButton_header': function(aValue) {
188 this._createButton_header = aValue;
189 },
190
191 //.........................................................................
192
193 'createButton_footer': function() {
194 return this._createButton_footer;
195 },
196
197 'setCreateButton_footer': function(aValue) {
198 this._createButton_footer = aValue;
199 },
200
201
202 //-------------------------------------------------------------------------
203
204 'cancelButton_header': function() {
205 return this._cancelButton_header;
206 },
207
208 'setCancelButton_header': function(aValue) {
209 this._cancelButton_header = aValue;
210 },
211
212 //.........................................................................
213
214 'cancelButton_footer': function() {
215 return this._cancelButton_footer;
216 },
217
218 'setCancelButton_footer': function(aValue) {
219 this._cancelButton_footer = aValue;
220 },
221
222 //-------------------------------------------------------------------------
223
224 'enableCreateButton': function(anEvent, skipKeyDownCheck) {
225//MochiKit.Logging.logDebug(">>> CreationWizard.enableCreateButton (" + anEvent.type() + ")");
226 if ((anEvent.type() == "keydown") && (skipKeyDownCheck != true)) {
227//MochiKit.Logging.logDebug("--- CreationWizard.enableCreateButton - handling 'keydown' event with a postponed execution of the check");
228 MochiKit.Async.callLater(0.3, MochiKit.Base.method(this, 'enableCreateButton', anEvent, true));
229 } else {
230 var shouldEnableCreateButton;
231 var isBookmarkletConfigurationEmpty;
232
233//MochiKit.Logging.logDebug("--- CreationWizard.enableCreateButton - common execution");
234
235 shouldEnableCreateButton = true;
236
237 isBookmarkletConfigurationEmpty = !/[^ \n]/.test(this.getDom('bookmarkletConfiguration').value);
238//MochiKit.Logging.logDebug("--- CreationWizard.enableCreateButton - isBookmarkletConfigurationEmpty: " + isBookmarkletConfigurationEmpty);
239
240 if ((anEvent.src() == this.getDom('bookmarkletConfiguration')) && !isBookmarkletConfigurationEmpty) {
241 this.getDom('bookmarkletRadioButton').checked = true;
242 }
243
244 if ((this.getDom('bookmarkletRadioButton').checked) && isBookmarkletConfigurationEmpty) {
245 shouldEnableCreateButton = false;
246 }
247
248 if (shouldEnableCreateButton) {
249//MochiKit.Logging.logDebug("--- CreationWizard.enableCreateButton - enabling button");
250 this.createButton_header().enable();
251 this.createButton_footer().enable();
252 } else {
253//MochiKit.Logging.logDebug("--- CreationWizard.enableCreateButton - disabling button");
254 this.createButton_header().disable();
255 this.createButton_footer().disable();
256 }
257 }
258//MochiKit.Logging.logDebug("<<< CreationWizard.enableCreateButton");
259 },
260
261 //-------------------------------------------------------------------------
262
263 'createRecord': function() {
264 varselectedTemplateKey;
265 varnewRecord;
266
267 selectedTemplateKey = MochiKit.Base.filter(function(aCheckBoxElement) {
268 return aCheckBoxElement.dom.checked;
269 },this.getElement('form').getChildrenByTagName('input'))[0].dom.value;
270
271//MochiKit.Logging.logDebug("--- CreationWizard.createRecord - selectedTemplateKey: " + selectedTemplateKey);
272 if (selectedTemplateKey == 'BookmarkletConfigurationTemplate') {
273 var bookmarkletConfiguration;
274
275 this.mainComponent().exitModalView();
276 bookmarkletConfiguration = Clipperz.PM.BookmarkletProcessor.checkBookmarkletConfiguration(this.getDom('bookmarkletConfiguration').value, this.getDom('createButton'), MochiKit.Base.method(this.mainComponent(), 'enterModalView'));
277 this.mainComponent().enterModalView();
278 newRecord = Clipperz.PM.BookmarkletProcessor.createRecordFromBookmarkletConfiguration(this.mainComponent().user(), bookmarkletConfiguration);
279 } else {
280 varfieldsConfigurations;
281
282 newRecord = this.mainComponent().user().addNewRecord();
283 newRecord.setLabel(Clipperz.PM.Strings['recordTemplates'][selectedTemplateKey]['title']);
284
285 fieldsConfigurations = Clipperz.PM.Strings['recordTemplates'][selectedTemplateKey]['fields'];
286
287 MochiKit.Iter.forEach(fieldsConfigurations, MochiKit.Base.partial(function(aRecord, aFieldConfiguration) {
288 var newField;
289
290 newField = new Clipperz.PM.DataModel.RecordField({recordVersion:aRecord.currentVersion()});
291 newField.setLabel(aFieldConfiguration['label']);
292 newField.setType(aFieldConfiguration['type']);
293 aRecord.currentVersion().addField(newField);
294 }, newRecord));
295 }
296
297 this.mainComponent().exitWizard(newRecord, true);
298 },
299
300 //-------------------------------------------------------------------------
301
302 'exitWizard': function() {
303//MochiKit.Logging.logDebug(">>> CreationWizard.exitWizard - " + this.previouslySelectedRecord());
304 this.mainComponent().exitWizard(this.previouslySelectedRecord());
305//MochiKit.Logging.logDebug("<<< CreationWizard.exitWizard");
306 },
307
308 //-------------------------------------------------------------------------
309
310 'mainComponent': function() {
311 return this._mainComponent;
312 },
313
314 //-------------------------------------------------------------------------
315 __syntaxFix__: "syntax fix"
316});
317
diff --git a/frontend/beta/js/Clipperz/PM/Components/RecordDetail/DirectLoginBindingComponent.js b/frontend/beta/js/Clipperz/PM/Components/RecordDetail/DirectLoginBindingComponent.js
new file mode 100644
index 0000000..6171a4e
--- a/dev/null
+++ b/frontend/beta/js/Clipperz/PM/Components/RecordDetail/DirectLoginBindingComponent.js
@@ -0,0 +1,174 @@
1/*
2
3Copyright 2008-2011 Clipperz Srl
4
5This file is part of Clipperz's Javascript Crypto Library.
6Javascript Crypto Library provides web developers with an extensive
7and efficient set of cryptographic functions. The library aims to
8obtain maximum execution speed while preserving modularity and
9reusability.
10For further information about its features and functionalities please
11refer to http://www.clipperz.com
12
13* Javascript Crypto Library is free software: you can redistribute
14 it and/or modify it under the terms of the GNU Affero General Public
15 License as published by the Free Software Foundation, either version
16 3 of the License, or (at your option) any later version.
17
18* Javascript Crypto Library is distributed in the hope that it will
19 be useful, but WITHOUT ANY WARRANTY; without even the implied
20 warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
21 See the GNU Affero General Public License for more details.
22
23* You should have received a copy of the GNU Affero General Public
24 License along with Javascript Crypto Library. If not, see
25 <http://www.gnu.org/licenses/>.
26
27*/
28
29if (typeof(Clipperz) == 'undefined') { Clipperz = {}; }
30if (typeof(Clipperz.PM) == 'undefined') { Clipperz.PM = {}; }
31if (typeof(Clipperz.PM.Components) == 'undefined') { Clipperz.PM.Components = {}; }
32if (typeof(Clipperz.PM.Components.RecordDetail) == 'undefined') { Clipperz.PM.Components.RecordDetail = {}; }
33
34//#############################################################################
35
36Clipperz.PM.Components.RecordDetail.DirectLoginBindingComponent = function(anElement, args) {
37//MochiKit.Logging.logDebug(">>> new DirectLoginBindingComponent");
38 args = args || {};
39
40 Clipperz.PM.Components.RecordDetail.DirectLoginBindingComponent.superclass.constructor.call(this, anElement, args);
41
42 this._directLoginBinding = args.directLoginBinding || null;
43 this.render();
44
45 Clipperz.NotificationCenter.register(this.record(), 'addNewRecordField',this, 'syncAndUpdateEditMode');
46 Clipperz.NotificationCenter.register(this.record(), 'removedField', this, 'syncAndUpdateEditMode');
47 Clipperz.NotificationCenter.register(this.record(), 'updatedFieldLabel',this, 'syncAndUpdateEditMode');
48//MochiKit.Logging.logDebug("<<< new DirectLoginBindingComponent");
49
50 return this;
51}
52
53//=============================================================================
54
55YAHOO.extendX(Clipperz.PM.Components.RecordDetail.DirectLoginBindingComponent, Clipperz.PM.Components.RecordDetail.AbstractComponent, {
56
57 'toString': function() {
58 return "Clipperz.PM.Components.RecordDetail.DirectLoginBindingComponent component";
59 },
60
61 //-------------------------------------------------------------------------
62
63 'directLoginBinding': function() {
64 return this._directLoginBinding;
65 },
66
67 //-------------------------------------------------------------------------
68
69 'render': function() {
70 // Clipperz.YUI.DomHelper.append(this.element().dom, {tag:'span', style:'font-weight:bold;', html:this.directLoginBinding().key()})
71 // Clipperz.YUI.DomHelper.append(this.element().dom, {tag:'span', html:this.directLoginBinding().value()})
72//MochiKit.Logging.logDebug(">>> DirectLoginBindingComponent.render");
73 Clipperz.YUI.DomHelper.append(this.element().dom, {tag:'td', cls:'directLoginBindingLabelTD', children:[
74 {tag:'span', html:this.directLoginBinding().key()}
75 ]});
76//MochiKit.Logging.logDebug("--- DirectLoginBindingComponent.render - 1");
77 Clipperz.YUI.DomHelper.append(this.element().dom, {tag:'td', cls:'directLoginBindingValueTD', children:[
78 {tag:'div', id:this.getId('editModeBox'), children:[
79 {tag:'select', id:this.getId('select'), children:this.recordFieldOptions()}
80 ]},
81 {tag:'div', id:this.getId('viewModeBox'), children:[
82 {tag:'span', id:this.getId('viewValue'), html:""}
83 ]}
84 ]});
85//MochiKit.Logging.logDebug("--- DirectLoginBindingComponent.render - 2");
86 this.getElement('editModeBox').setVisibilityMode(YAHOO.ext.Element.DISPLAY);
87 this.getElement('viewModeBox').setVisibilityMode(YAHOO.ext.Element.DISPLAY);
88
89 this.update();
90//MochiKit.Logging.logDebug("<<< DirectLoginBindingComponent.render");
91 },
92
93 //-------------------------------------------------------------------------
94
95 'recordFieldOptions': function() {
96 varresult;
97 var option;
98 varrecordFieldKey;
99 varrecordFields;
100
101//MochiKit.Logging.logDebug(">>> DirectLoginBindingComponent.recordFieldOptions");
102 recordFields = this.directLoginBinding().directLogin().record().currentVersion().fields();
103 result = [];
104 option = {tag:'option', value:null, html:'---'};
105 result.push(option);
106 for (recordFieldKey in recordFields) {
107 //TODO: remove the value: field and replace it with element.dom.value = <some value>
108 option = {tag:'option', value:recordFieldKey, html:recordFields[recordFieldKey].label()}
109 if (recordFieldKey == this.directLoginBinding().fieldKey()) {
110 option['selected'] = true;
111 }
112 result.push(option);
113 }
114//MochiKit.Logging.logDebug("<<< DirectLoginBindingComponent.recordFieldOptions");
115
116 return result;
117 },
118
119 //-------------------------------------------------------------------------
120
121 'syncAndUpdateEditMode': function() {
122 this.synchronizeComponentValues();
123 this.updateEditMode();
124 },
125
126 'updateEditMode': function() {
127 varselectElementBox;
128
129//MochiKit.Logging.logDebug(">>> DirectLoginBindingComponent.updateEditMode");
130 this.getElement('viewModeBox').hide();
131
132 selectElementBox = this.getElement('editModeBox');
133 selectElementBox.update("");
134
135 Clipperz.YUI.DomHelper.append(selectElementBox.dom, {tag:'select', id:this.getId('select'), children:this.recordFieldOptions()});
136
137/*
138 selectElement = this.getElement('select');
139
140 selectElement.update("");
141 MochiKit.Iter.forEach(this.recordFieldOptions(), function(anOption) {
142 Clipperz.YUI.DomHelper.append(selectElement.dom, anOption);
143 });
144*/
145
146
147 this.getElement('editModeBox').show();
148//MochiKit.Logging.logDebug("<<< DirectLoginBindingComponent.updateEditMode");
149 },
150
151 //-------------------------------------------------------------------------
152
153 'updateViewMode': function() {
154//MochiKit.Logging.logDebug(">>> DirectLoginBindingComponent.updateViewMode");
155 this.getElement('editModeBox').hide();
156 this.getElement('viewModeBox').show();
157
158 this.getElement('viewValue').update(this.directLoginBinding().field().label());
159//MochiKit.Logging.logDebug("<<< DirectLoginBindingComponent.updateViewMode");
160 },
161
162 //-------------------------------------------------------------------------
163
164 'synchronizeComponentValues': function() {
165//MochiKit.Logging.logDebug(">>> DirectLoginBindingComponent.synchronizeComponentValues")
166//MochiKit.Logging.logDebug("--- DirectLoginBindingComponent.synchronizeComponentValues - 1 - " + this.getId('select'));
167 this.directLoginBinding().setFieldKey(this.getDom('select').value);
168//MochiKit.Logging.logDebug("<<< DirectLoginBindingComponent.synchronizeComponentValues");
169 },
170
171 //-------------------------------------------------------------------------
172 __syntaxFix__: "syntax fix"
173});
174
diff --git a/frontend/beta/js/Clipperz/PM/Components/RecordDetail/DirectLoginComponent.js b/frontend/beta/js/Clipperz/PM/Components/RecordDetail/DirectLoginComponent.js
new file mode 100644
index 0000000..7638f00
--- a/dev/null
+++ b/frontend/beta/js/Clipperz/PM/Components/RecordDetail/DirectLoginComponent.js
@@ -0,0 +1,362 @@
1/*
2
3Copyright 2008-2011 Clipperz Srl
4
5This file is part of Clipperz's Javascript Crypto Library.
6Javascript Crypto Library provides web developers with an extensive
7and efficient set of cryptographic functions. The library aims to
8obtain maximum execution speed while preserving modularity and
9reusability.
10For further information about its features and functionalities please
11refer to http://www.clipperz.com
12
13* Javascript Crypto Library is free software: you can redistribute
14 it and/or modify it under the terms of the GNU Affero General Public
15 License as published by the Free Software Foundation, either version
16 3 of the License, or (at your option) any later version.
17
18* Javascript Crypto Library is distributed in the hope that it will
19 be useful, but WITHOUT ANY WARRANTY; without even the implied
20 warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
21 See the GNU Affero General Public License for more details.
22
23* You should have received a copy of the GNU Affero General Public
24 License along with Javascript Crypto Library. If not, see
25 <http://www.gnu.org/licenses/>.
26
27*/
28
29if (typeof(Clipperz) == 'undefined') { Clipperz = {}; }
30if (typeof(Clipperz.PM) == 'undefined') { Clipperz.PM = {}; }
31if (typeof(Clipperz.PM.Components) == 'undefined') { Clipperz.PM.Components = {}; }
32if (typeof(Clipperz.PM.Components.RecordDetail) == 'undefined') { Clipperz.PM.Components.RecordDetail = {}; }
33
34//#############################################################################
35
36Clipperz.PM.Components.RecordDetail.DirectLoginComponent = function(anElement, args) {
37 args = args || {};
38
39 Clipperz.PM.Components.RecordDetail.DirectLoginComponent.superclass.constructor.call(this, anElement, args);
40
41 this._directLogin = args.directLogin || null;
42 //this._titleElement = null;
43 this._structureElement = null;
44 this._removeButton = null;
45 this._directLoginBindingComponents = null;
46 this._collapser = null;
47
48 this.mainComponent().addEditComponent(this);
49 this.render();
50
51 return this;
52}
53
54//=============================================================================
55
56YAHOO.extendX(Clipperz.PM.Components.RecordDetail.DirectLoginComponent, Clipperz.PM.Components.RecordDetail.AbstractComponent, {
57
58 'toString': function() {
59 return "Clipperz.PM.Components.RecordDetail.DirectLoginComponent component";
60 },
61
62 //-------------------------------------------------------------------------
63
64 'directLogin': function() {
65 return this._directLogin;
66 },
67
68 'directLoginBindingComponents': function() {
69 return this._directLoginBindingComponents;
70 },
71
72 //-------------------------------------------------------------------------
73
74 'removeDirectLogin': function() {
75//MochiKit.Logging.logDebug(">>> DirectLoginComponent.removeDirectLogin");
76 this.mainComponent().synchronizeComponentValues();
77 this.directLogin().remove();
78 this.mainComponent().removeEditComponent(this);
79 this.mainComponent().render();
80//MochiKit.Logging.logDebug("<<< DirectLoginComponent.removeDirectLogin");
81 },
82
83 //-------------------------------------------------------------------------
84/*
85 'formDataValue': function() {
86 return Clipperz.Base.serializeJSON(this.directLogin().formData());
87 },
88
89 'setFormDataValue': function(aValue) {
90
91 },
92 */
93 //-------------------------------------------------------------------------
94
95 'removeButton': function() {
96 return this._removeButton;
97 },
98
99 'setRemoveButton': function(aValue) {
100 this._removeButton = aValue;
101 },
102
103 //-------------------------------------------------------------------------
104/*
105 'titleElement': function() {
106 return this._titleElement;
107 },
108
109 'setTitleElement': function(aValue) {
110 this._titleElement = aValue;
111 },
112 */
113 //-------------------------------------------------------------------------
114
115 'structureElement': function() {
116 return this._structureElement;
117 },
118
119 'setStructureElement': function(aValue) {
120 this._structureElement = aValue;
121 },
122
123 //-------------------------------------------------------------------------
124
125 'render': function() {
126//MochiKit.Logging.logDebug(">>> DirectLoginComponent.render");
127 try {
128 this.element().update("");
129 Clipperz.YUI.DomHelper.append(this.element().dom,
130 {tag:'li', children:[
131 {tag:'table', width:'100%', border:'0', cellpadding:'0', cellspacing:'0', children:[
132 {tag:'tbody', children:[
133 {tag:'tr', children:[
134 {tag:'td', rowspan:'2', width:'30', valign:'top', html:'&#160', children:[
135 {tag:'div', id:this.getId('removeDirectLogin'), children:[
136 {tag:'div', id:this.getId('removeDirectLoginButton')}
137 ]},
138 {tag:'div', id:this.getId('collapseLink'), cls:'directLoginCollapseLink'}
139 ]},
140 {tag:'td', valign:'top', children:[
141 {tag:'table', width:'100%', border:'0', cellpadding:'0', cellspacing:'0', children:[
142 {tag:'tbody', children:[
143 {tag:'tr', children:[
144 {tag:'td', width:'20', valign:'top', children:[
145 {tag:'a', href:'#', id:this.getId('directLogin'), children:[
146 {tag:'img', id:this.getId('faviconImage'), width:'16', height:'16', src:this.directLogin().fixedFavicon()}
147 ]}
148 ]},
149 {tag:'td', valign:'top', children:[
150 {tag:'div', cls:'directLoginDetailTitle', children:[
151 {tag:'div', id:this.getId('titleViewBox'), children:[
152 {tag:'a', href:'#', id:this.getId('titleLink')}
153 ]},
154 {tag:'div', id:this.getId('titleEditBox'), children:[
155 {tag:'input', type:'text', id:this.getId('titleInput')}
156 ]}
157 ]}
158 ]}
159 ]}
160 ]}
161 ]}
162 ]}
163 ]},
164 {tag:'tr', children:[
165 {tag:'td', /*colspan:'2',*/ children:[
166 {tag:'div', id:this.getId('details'), children:[
167 {tag:'table', cls:'directLoginBindings', border:'0', cellpadding:'0', cellspacing:'0', children:[
168 {tag:'tbody', id:this.getId('tbodyBindings'), children:[]}
169 ]}
170 ]}
171 ]}
172 ]}
173 ]}
174 ]}
175 ]}
176 );
177
178 MochiKit.Signal.connect(this.getId('faviconImage'), 'onload', this, 'handleLoadedFaviconImage');
179 MochiKit.Signal.connect(this.getId('faviconImage'), 'onerror', this.directLogin(), 'handleMissingFaviconImage');
180 MochiKit.Signal.connect(this.getId('faviconImage'), 'onabort', this.directLogin(), 'handleMissingFaviconImage');
181
182 this.getElement('removeDirectLogin').setVisibilityMode(YAHOO.ext.Element.DISPLAY);
183//MochiKit.Logging.logDebug("--- DirectLoginComponent.render - 1");
184 this.getElement('collapseLink').addClassOnOver('hover');
185 this._collapser = new Clipperz.YUI.Collapser(this.getElement('collapseLink'), this.getElement('details'), true);
186//MochiKit.Logging.logDebug("--- DirectLoginComponent.render - 2");
187 MochiKit.Signal.connect(this.getId('directLogin'), 'onclick', this, 'runDirectLogin');
188 // this.getElement('directLogin').on('click', this.runDirectLogin, this, false);
189//MochiKit.Logging.logDebug("--- DirectLoginComponent.render - 3");
190 // this.setTitleElement(new Clipperz.PM.Components.TextFormField(this.getElement('title'), {
191 // editMode:this.editMode(),
192 // value:this.directLogin().label()
193 // }));
194 this.getElement('titleViewBox').setVisibilityMode(YAHOO.ext.Element.DISPLAY);
195 this.getElement('titleEditBox').setVisibilityMode(YAHOO.ext.Element.DISPLAY);
196 //- this.getElement('titleLink').on('click', this.runDirectLogin, this, false);
197 MochiKit.Signal.connect(this.getId('titleLink'), 'onclick', this, 'runDirectLogin');
198
199//MochiKit.Logging.logDebug("--- DirectLoginComponent.render - 4");
200 //- this.setStructureElement(new Clipperz.PM.Components.TextFormField(this.getElement('formStructure'), {
201 //- editMode:this.editMode(),
202 //- value:this.formDataValue(), multiline:true
203 //- }));
204//MochiKit.Logging.logDebug("--- DirectLoginComponent.render - 5");
205 {
206 varbindingKey;
207 var valueName;
208 var inputsRequiringAdditionalValues;
209 var bindingsElement;
210 var i,c;
211
212//MochiKit.Logging.logDebug("--- DirectLoginComponent.render - 6");
213 this._directLoginBindingComponents = [];
214//MochiKit.Logging.logDebug("--- DirectLoginComponent.render - 7");
215 bindingsElement = this.getElement('tbodyBindings');
216//MochiKit.Logging.logDebug("--- DirectLoginComponent.render - 8");
217 for (bindingKey in this.directLogin().bindings()) {
218 try {
219 var directLoginBindingElement;
220 var directLoginBindingComponent;
221
222//MochiKit.Logging.logDebug("--- DirectLoginComponent.render - 9");
223 directLoginBindingElement = Clipperz.YUI.DomHelper.append(bindingsElement.dom, {tag:'tr'}, true);
224//MochiKit.Logging.logDebug("--- DirectLoginComponent.render - 10");
225 directLoginBindingComponent =new Clipperz.PM.Components.RecordDetail.DirectLoginBindingComponent(directLoginBindingElement, {
226 mainComponent:this,
227 directLoginBinding:this.directLogin().bindings()[bindingKey]
228 });
229//MochiKit.Logging.logDebug("--- DirectLoginComponent.render - 11");
230 this._directLoginBindingComponents.push(directLoginBindingComponent);
231 } catch (e) {
232 MochiKit.Logging.logError("Error while rendering a DirectLoginBindingComponent - " + e);
233 }
234//MochiKit.Logging.logDebug("--- DirectLoginComponent.render - 12");
235 }
236//MochiKit.Logging.logDebug("--- DirectLoginComponent.render - 13");
237
238 inputsRequiringAdditionalValues = this.directLogin().inputsRequiringAdditionalValues();
239//MochiKit.Logging.logDebug("--- DirectLoginComponent.render - 13.1");
240 for (valueName in inputsRequiringAdditionalValues) {
241 //- Clipperz.YUI.DomHelper.append(bindingsElement.dom, {tag:'tr', children:[
242 //- {tag:'td', html:valueName},
243 //- {tag:'td', children:inputsRequiringAdditionalValues[valueName].inputElementConfiguration()}
244 //- ]}, true)
245 var directLoginValueElement;
246 var directLoginValueComponent;
247
248//MochiKit.Logging.logDebug("--- DirectLoginComponent.render - 13.2");
249 directLoginValueElement = Clipperz.YUI.DomHelper.append(bindingsElement.dom, {tag:'tr'}, true);
250//MochiKit.Logging.logDebug("--- DirectLoginComponent.render - 13.3");
251 directLoginValueComponent =new Clipperz.PM.Components.RecordDetail.DirectLoginValueComponent(directLoginValueElement, {
252 mainComponent:this,
253 directLoginInputValue:inputsRequiringAdditionalValues[valueName]
254 });
255//MochiKit.Logging.logDebug("--- DirectLoginComponent.render - 13.4");
256 this._directLoginBindingComponents.push(directLoginValueComponent);
257//MochiKit.Logging.logDebug("--- DirectLoginComponent.render - 13.5");
258 }
259//MochiKit.Logging.logDebug("--- DirectLoginComponent.render - 13.6");
260 }
261//MochiKit.Logging.logDebug("--- DirectLoginComponent.render - 14");
262 this.setRemoveButton(new YAHOO.ext.Button(this.getDom('removeDirectLoginButton'), {text:Clipperz.PM.Strings['recordDetailDeleteDirectLoginButtonLabel'], handler:this.removeDirectLogin, scope:this}));
263//MochiKit.Logging.logDebug("--- DirectLoginComponent.render - 15");
264 this.update();
265 } catch (e) {
266 MochiKit.Logging.logError("Error while rendering a DirectLoginComponent - " + e);
267 }
268//MochiKit.Logging.logDebug("<<< DirectLoginComponent.render");
269 },
270
271 //-------------------------------------------------------------------------
272
273 'collapser': function() {
274 return this._collapser;
275 },
276
277 //-------------------------------------------------------------------------
278
279 'handleLoadedFaviconImage': function(anEvent) {
280 MochiKit.Signal.disconnectAll(anEvent.src())
281 },
282
283 //-------------------------------------------------------------------------
284
285 'update': function() {
286 var i,c;
287 var bindingComponents;
288
289//MochiKit.Logging.logDebug(">>> DirectLoginComponent.update");
290 bindingComponents = this.directLoginBindingComponents();
291 c = bindingComponents.length;
292 for (i=0; i<c; i++) {
293 bindingComponents[i].update();
294 }
295
296 Clipperz.PM.Components.RecordDetail.DirectLoginComponent.superclass.update.call(this);
297//MochiKit.Logging.logDebug("<<< DirectLoginComponent.update");
298 },
299
300 //-------------------------------------------------------------------------
301
302 'updateEditMode': function() {
303 // this.element().update("");
304 // Clipperz.YUI.DomHelper.append(this.element().dom, {tag:'div', style:'border:4px solid red; padding:10px;', children:[
305 // {tag:'div', style:'font-weight:bold;', html:this.directLogin().label()},
306 // {tag:'div', style:'border:1px solid #aaaaaa;', html:Clipperz.Base.serializeJSON(this.directLogin().formData())},
307 // {tag:'div', style:'border:1px solid #aaaaaa;', html:Clipperz.Base.serializeJSON(this.directLogin().bindings())}
308 // ]});
309
310 this.getElement('titleEditBox').show();
311 this.getElement('titleViewBox').hide();
312
313 this.getDom('titleInput').value = this.directLogin().label();
314
315//MochiKit.Logging.logDebug(">>> DirectLoginComponent.updateEditMode");
316 this.collapser().expand();
317 this.getElement('collapseLink').hide();
318 this.getElement('removeDirectLogin').show();
319 // this.removeButton().show();
320//MochiKit.Logging.logDebug("<<< DirectLoginComponent.updateEditMode");
321 },
322
323 //-------------------------------------------------------------------------
324
325 'updateViewMode': function() {
326//MochiKit.Logging.logDebug(">>> DirectLoginComponent.updateViewMode");
327 this.getElement('titleEditBox').hide();
328 this.getElement('titleViewBox').show();
329 this.getElement('titleLink').update(this.directLogin().label());
330
331 this.getElement('collapseLink').show();
332 this.getElement('removeDirectLogin').hide();
333 // this.removeButton().hide();
334//MochiKit.Logging.logDebug("<<< DirectLoginComponent.updateViewMode");
335 },
336
337 //-------------------------------------------------------------------------
338
339 'synchronizeComponentValues': function() {
340//MochiKit.Logging.logDebug(">>> DirectLoginComponent.syncronizeComponentValues");
341 this.directLogin().setLabel(this.getDom('titleInput').value);
342 // this.setFormDataValue(this.structureElement().value());
343
344 MochiKit.Iter.forEach(this.directLoginBindingComponents(), MochiKit.Base.methodcaller('synchronizeComponentValues'));
345//MochiKit.Logging.logDebug("<<< DirectLoginComponent.syncronizeComponentValues");
346 },
347
348 //-------------------------------------------------------------------------
349
350 'runDirectLogin': function(anEvent) {
351//MochiKit.Logging.logDebug("--- DirectLoginComponent.runDirectLogin - 1");
352//MochiKit.Logging.logDebug("--- DirectLoginComponent.runDirectLogin - 1 anEvent: " + anEvent);
353 anEvent.stop();
354//MochiKit.Logging.logDebug("--- DirectLoginComponent.runDirectLogin - 2");
355 this.directLogin().runDirectLogin();
356//MochiKit.Logging.logDebug("--- DirectLoginComponent.runDirectLogin - 3");
357 },
358
359 //-------------------------------------------------------------------------
360 __syntaxFix__: "syntax fix"
361});
362
diff --git a/frontend/beta/js/Clipperz/PM/Components/RecordDetail/DirectLoginValueComponent.js b/frontend/beta/js/Clipperz/PM/Components/RecordDetail/DirectLoginValueComponent.js
new file mode 100644
index 0000000..e70229b
--- a/dev/null
+++ b/frontend/beta/js/Clipperz/PM/Components/RecordDetail/DirectLoginValueComponent.js
@@ -0,0 +1,257 @@
1/*
2
3Copyright 2008-2011 Clipperz Srl
4
5This file is part of Clipperz's Javascript Crypto Library.
6Javascript Crypto Library provides web developers with an extensive
7and efficient set of cryptographic functions. The library aims to
8obtain maximum execution speed while preserving modularity and
9reusability.
10For further information about its features and functionalities please
11refer to http://www.clipperz.com
12
13* Javascript Crypto Library is free software: you can redistribute
14 it and/or modify it under the terms of the GNU Affero General Public
15 License as published by the Free Software Foundation, either version
16 3 of the License, or (at your option) any later version.
17
18* Javascript Crypto Library is distributed in the hope that it will
19 be useful, but WITHOUT ANY WARRANTY; without even the implied
20 warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
21 See the GNU Affero General Public License for more details.
22
23* You should have received a copy of the GNU Affero General Public
24 License along with Javascript Crypto Library. If not, see
25 <http://www.gnu.org/licenses/>.
26
27*/
28
29if (typeof(Clipperz) == 'undefined') { Clipperz = {}; }
30if (typeof(Clipperz.PM) == 'undefined') { Clipperz.PM = {}; }
31if (typeof(Clipperz.PM.Components) == 'undefined') { Clipperz.PM.Components = {}; }
32if (typeof(Clipperz.PM.Components.RecordDetail) == 'undefined') { Clipperz.PM.Components.RecordDetail = {}; }
33
34//#############################################################################
35
36Clipperz.PM.Components.RecordDetail.DirectLoginValueComponent = function(anElement, args) {
37//MochiKit.Logging.logDebug(">>> new DirectLoginValueComponent");
38 args = args || {};
39
40 Clipperz.PM.Components.RecordDetail.DirectLoginValueComponent.superclass.constructor.call(this, anElement, args);
41
42 this._directLoginInputValue = args.directLoginInputValue || null;
43 this._value = this.directLoginInputValue().directLogin().formValues()[this.directLoginInputValue().name()];
44
45 this.render();
46//MochiKit.Logging.logDebug("<<< new DirectLoginValueComponent - record: " + this.record());
47
48 return this;
49}
50
51//=============================================================================
52
53YAHOO.extendX(Clipperz.PM.Components.RecordDetail.DirectLoginValueComponent, Clipperz.PM.Components.RecordDetail.AbstractComponent, {
54
55 'toString': function() {
56 return "Clipperz.PM.Components.RecordDetail.DirectLoginValueComponent component - " + this.directLoginInputValue().name();
57 },
58
59 //-------------------------------------------------------------------------
60
61 'directLoginInputValue': function() {
62 return this._directLoginInputValue;
63 },
64
65 //-------------------------------------------------------------------------
66
67 'render': function() {
68//MochiKit.Logging.logDebug(">>> DirectLoginValueComponent.render");
69 Clipperz.YUI.DomHelper.append(this.element().dom, {tag:'td', cls:'directLoginDataLabelTD', children:[
70 {tag:'span', html:this.directLoginInputValue().name()}
71 ]});
72//MochiKit.Logging.logDebug("--- DirectLoginValueComponent.render - 1");
73 Clipperz.YUI.DomHelper.append(this.element().dom, {tag:'td', cls:'directLoginDataValueTD', children:[
74 {tag:'span', id:this.getId('inputElement')}
75 ]});
76//MochiKit.Logging.logDebug("--- DirectLoginValueComponent.render - 2");
77 this.update();
78//MochiKit.Logging.logDebug("<<< DirectLoginValueComponent.render");
79 },
80
81 //-------------------------------------------------------------------------
82
83 'inputElementConfiguration': function() {
84 var result;
85 var currentValue;
86
87//MochiKit.Logging.logDebug(">>> DirectLoginValueComponent.inputElementConfiguration - " + this.directLoginInputValue().name());
88 result = [];
89 currentValue = this.value();
90
91 switch (this.directLoginInputValue().type()) {
92 case 'checkbox':
93 var checkbox;
94//{"type":"checkbox", "name":"rememberUsernameChk", "value":"checkbox"}
95 checkbox = {tag:'input', id:this.getId('checkbox'), type:'checkbox'}
96 if (currentValue == true) {
97 checkbox.checked = true;
98 }
99 result.push(checkbox);
100 break;
101
102 case 'select':
103 var input;
104//{"type":"select", "name":"DOMAIN", "options":[{"selected":true, "label":"@tin.it", "value":"tin.it"}, {"selected":false, "label":"@virgilio.it", "value":"virgilio.it"}]}
105 input = {tag:'select', id:this.getId('select'), name:this.directLoginInputValue().name(), children:[]};
106 input.children.push({tag:'option', value:null, html:"---"});
107 MochiKit.Iter.forEach(this.directLoginInputValue().args()['options'], function(anOption) {
108 var option;
109
110 //TODO: remove the value: field and replace it with element.dom.value = <some value>
111 option = {tag:'option', value:anOption['value'], html:anOption['label']}
112 if (currentValue == anOption['value']) {
113 option.selected = true;
114 }
115 input.children.push(option);
116 })
117 result.push(input);
118 break;
119
120 case 'radio':
121 var name;
122 var radioBox;
123
124//MochiKit.Logging.logDebug("--- DirectLoginValueComponent.inputElementConfiguration - 3");
125 name = this.getId(this.directLoginInputValue().name());
126 radioBox = {tag:'div', id:this.getId('radioBox'), children:[]};
127 result.push(radioBox);
128//MochiKit.Logging.logDebug("--- DirectLoginValueComponent.inputElementConfiguration - 3.1 - options.length: " + this.directLoginInputValue().args()['options'].length);
129//{"name":"dominio", "type":"radio", "options":[{"value":"@alice.it", "checked":true}, {"value":"@tin.it", "checked":false}, {"value":"@virgilio.it", "checked":false}, {"value":"@tim.it", "checked":false}]}
130
131 MochiKit.Iter.forEach(this.directLoginInputValue().args()['options'], function(anOption) {
132 varradio;
133
134//MochiKit.Logging.logDebug("--- DirectLoginValueComponent.inputElementConfiguration - 3.1.1");
135 //TODO: remove the value: field and replace it with element.dom.value = <some value>
136 radio = {tag:'input', type:'radio', name:name, value:anOption['value']};
137//MochiKit.Logging.logDebug("--- DirectLoginValueComponent.inputElementConfiguration - 3.1.2");
138 if (currentValue == anOption['value']) {
139//MochiKit.Logging.logDebug("--- DirectLoginValueComponent.inputElementConfiguration - 3.1.3");
140 radio.checked = true;
141//MochiKit.Logging.logDebug("--- DirectLoginValueComponent.inputElementConfiguration - 3.1.4");
142 }
143//MochiKit.Logging.logDebug("--- DirectLoginValueComponent.inputElementConfiguration - 3.1.5");
144 radioBox.children.push({tag:'div', children:[ radio, {tag:'span', html:anOption['value']} ]})
145//MochiKit.Logging.logDebug("--- DirectLoginValueComponent.inputElementConfiguration - 3.1.6");
146 })
147//MochiKit.Logging.logDebug("--- DirectLoginValueComponent.inputElementConfiguration - 3.2");
148 break;
149 }
150//MochiKit.Logging.logDebug("<<< DirectLoginValueComponent.inputElementConfiguration");
151
152 return result;
153 },
154
155 //-------------------------------------------------------------------------
156
157 'inputValue': function() {
158 var result;
159
160 switch (this.directLoginInputValue().type()) {
161 case 'checkbox':
162 result = this.getDom('checkbox').checked;
163 break;
164 case 'select':
165 result = this.getDom('select').value;
166 break;
167 case 'radio':
168 var checkedRadioButtons;
169
170 checkedRadioButtons = MochiKit.Base.filter(function(aRadioButton) { return aRadioButton.dom.checked },
171 this.getElement('radioBox').getChildrenByTagName('input'));
172
173 if (checkedRadioButtons.length == 0) {
174 result = null;
175 } else {
176 result = checkedRadioButtons[0].dom.value;
177 }
178 break;
179 }
180
181 return result;
182 },
183
184 //-------------------------------------------------------------------------
185
186 'value': function() {
187 return this._value;
188 },
189
190 'setValue': function(aValue) {
191 this._value = aValue;
192 },
193
194 //-------------------------------------------------------------------------
195
196 'updateEditMode': function() {
197//MochiKit.Logging.logDebug(">>> DirectLoginValueComponent.updateEditMode - " + this);
198 this.getElement('inputElement').update("");
199//MochiKit.Logging.logDebug("--- DirectLoginValueComponent.updateEditMode - 1");
200 Clipperz.YUI.DomHelper.append(this.getDom('inputElement'), {tag:'div', children:this.inputElementConfiguration()});
201//MochiKit.Logging.logDebug("<<< DirectLoginValueComponent.updateEditMode");
202 },
203
204 //-------------------------------------------------------------------------
205
206 'updateViewMode': function() {
207//MochiKit.Logging.logDebug(">>> DirectLoginValueComponent.updateViewMode");
208 // this.getElement('inputElement').update(this.directLoginInputValue().value());
209
210 this.getElement('inputElement').update("");
211
212 switch (this.directLoginInputValue().type()) {
213 case 'checkbox':
214 if (this.value() == true) {
215 this.getElement('inputElement').update(Clipperz.PM.Strings['directLoginConfigurationCheckBoxFieldSelectedValue']);
216 } else {
217 this.getElement('inputElement').update(Clipperz.PM.Strings['directLoginConfigurationCheckBoxFieldNotSelectedValue'])
218 }
219 break;
220 case 'select':
221 var displayedValue;
222 var selectedOptions;
223 var currentValue;
224
225 currentValue = this.value();
226 selectedOptions = MochiKit.Base.filter(function(anOption) { return (anOption['value'] == currentValue); },
227 this.directLoginInputValue().args()['options']);
228 if (selectedOptions.length == 0) {
229 displayedValue = "---";
230 } else {
231//MochiKit.Logging.logDebug("+++ " + Clipperz.Base.serializeJSON(selectedOptions));
232//MochiKit.Logging.logDebug("*** " + Clipperz.Base.serializeJSON(selectedOptions[0]));
233 displayedValue = selectedOptions[0]['label'];
234 }
235 this.getElement('inputElement').update(displayedValue);
236 break;
237 case 'radio':
238 this.getElement('inputElement').update(this.value());
239 break;
240 }
241//MochiKit.Logging.logDebug("<<< DirectLoginValueComponent.updateViewMode");
242 },
243
244 //-------------------------------------------------------------------------
245
246 'synchronizeComponentValues': function() {
247//MochiKit.Logging.logDebug(">>> DirectLoginValueComponent.synchronizeComponentValues");
248//MochiKit.Logging.logDebug("--- DirectLoginValueComponent.synchronizeComponentValues - 1; value: " + this.inputValue());
249 this.setValue(this.inputValue());
250 this.directLoginInputValue().directLogin().formValues()[this.directLoginInputValue().name()] = this.value();
251//MochiKit.Logging.logDebug("<<< DirectLoginValueComponent.synchronizeComponentValues");
252 },
253
254 //-------------------------------------------------------------------------
255 __syntaxFix__: "syntax fix"
256});
257
diff --git a/frontend/beta/js/Clipperz/PM/Components/RecordDetail/DirectLoginsComponent.js b/frontend/beta/js/Clipperz/PM/Components/RecordDetail/DirectLoginsComponent.js
new file mode 100644
index 0000000..3292a95
--- a/dev/null
+++ b/frontend/beta/js/Clipperz/PM/Components/RecordDetail/DirectLoginsComponent.js
@@ -0,0 +1,199 @@
1/*
2
3Copyright 2008-2011 Clipperz Srl
4
5This file is part of Clipperz's Javascript Crypto Library.
6Javascript Crypto Library provides web developers with an extensive
7and efficient set of cryptographic functions. The library aims to
8obtain maximum execution speed while preserving modularity and
9reusability.
10For further information about its features and functionalities please
11refer to http://www.clipperz.com
12
13* Javascript Crypto Library is free software: you can redistribute
14 it and/or modify it under the terms of the GNU Affero General Public
15 License as published by the Free Software Foundation, either version
16 3 of the License, or (at your option) any later version.
17
18* Javascript Crypto Library is distributed in the hope that it will
19 be useful, but WITHOUT ANY WARRANTY; without even the implied
20 warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
21 See the GNU Affero General Public License for more details.
22
23* You should have received a copy of the GNU Affero General Public
24 License along with Javascript Crypto Library. If not, see
25 <http://www.gnu.org/licenses/>.
26
27*/
28
29if (typeof(Clipperz) == 'undefined') { Clipperz = {}; }
30if (typeof(Clipperz.PM) == 'undefined') { Clipperz.PM = {}; }
31if (typeof(Clipperz.PM.Components) == 'undefined') { Clipperz.PM.Components = {}; }
32if (typeof(Clipperz.PM.Components.RecordDetail) == 'undefined') { Clipperz.PM.Components.RecordDetail = {}; }
33
34//#############################################################################
35
36Clipperz.PM.Components.RecordDetail.DirectLoginsComponent = function(anElement, args) {
37//MochiKit.Logging.logDebug(">>> new Clipperz.PM.Components.RecordDetail.DirectLoginsComponent");
38 args = args || {};
39
40//MochiKit.Logging.logDebug("--- new Clipperz.PM.Components.RecordDetail.DirectLoginsComponent - 0");
41 Clipperz.PM.Components.RecordDetail.DirectLoginsComponent.superclass.constructor.call(this, anElement, args);
42//MochiKit.Logging.logDebug("--- new Clipperz.PM.Components.RecordDetail.DirectLoginsComponent - 1");
43
44 this._addDirectLoginButton = null;
45
46//MochiKit.Logging.logDebug("--- new Clipperz.PM.Components.RecordDetail.DirectLoginsComponent - 2");
47 this.mainComponent().addEditComponent(this);
48//MochiKit.Logging.logDebug("--- new Clipperz.PM.Components.RecordDetail.DirectLoginsComponent - 3");
49 this.render();
50//MochiKit.Logging.logDebug("<<< new Clipperz.PM.Components.RecordDetail.DirectLoginsComponent");
51
52 return this;
53}
54
55//=============================================================================
56
57YAHOO.extendX(Clipperz.PM.Components.RecordDetail.DirectLoginsComponent, Clipperz.PM.Components.RecordDetail.AbstractComponent, {
58
59 'toString': function() {
60 return "Clipperz.PM.Components.RecordDetail.DirectLoginsComponent component";
61 },
62
63 //-------------------------------------------------------------------------
64
65 'addDirectLoginButton': function() {
66 return this._addDirectLoginButton;
67 },
68
69 'setAddDirectLoginButton': function(aValue) {
70 this._addDirectLoginButton = aValue;
71 },
72
73 //-------------------------------------------------------------------------
74
75 'render': function() {
76 this.element().update("");
77
78 Clipperz.YUI.DomHelper.append(this.element().dom,
79 {tag:'div', cls:'directLoginsRecordBox', children:[
80 {tag:'h3', htmlString:Clipperz.PM.Strings['recordDetailDirectLoginBlockTitle']},
81 {tag:'ul', id:this.getId('directLogins')},
82
83 {tag:'div', cls:'addDirectLoginBox', id:this.getId('addDirectLogin'), children:[
84 {tag:'div', cls:'addDirectLoginBoxContent', children:[
85 {tag:'div', cls:'bookmarkletConfiguration', children:[
86 // {tag:'span', htmlString:Clipperz.PM.Strings['newRecordWizardBookmarkletConfigurationLabel']},
87 {tag:'div', htmlString:Clipperz.PM.Strings['recordDetailNewDirectLoginDescription']},
88 {tag:'textarea', id:this.getId('addDirectLoginTextarea')}
89 ]},
90 {tag:'div', id:this.getId('addDirectLoginButton')}
91 ]}
92 ]}
93 ]}
94 );
95
96 if (MochiKit.Base.keys(this.record().directLogins()).length == 0) {
97//MochiKit.Logging.logDebug("--- DirectLoginsComponent.render - 3");
98 Clipperz.YUI.DomHelper.append(this.getElement('directLogins'),
99 {tag:'li', children:[
100 // {tag:'span', htmlString:Clipperz.PM.Strings['recordDetailDirectLoginBlockNoDirectLoginConfiguredLabel']}
101 {tag:'div', cls:'recordDetailNoDirectLoginDescriptionBox', htmlString:Clipperz.PM.Strings['recordDetailDirectLoginBlockNoDirectLoginConfiguredDescription']}
102 ]}
103 );
104//MochiKit.Logging.logDebug("--- DirectLoginsComponent.render - 4");
105 } else {
106//MochiKit.Logging.logDebug("--- DirectLoginsComponent.render - 5");
107 for (directLoginReference in this.record().directLogins()) {
108//MochiKit.Logging.logDebug("--- DirectLoginsComponent.render - 6");
109 this.addDirectLogin(this.record().directLogins()[directLoginReference]);
110//MochiKit.Logging.logDebug("--- DirectLoginsComponent.render - 7");
111 }
112//MochiKit.Logging.logDebug("--- DirectLoginsComponent.render - 8");
113 }
114//MochiKit.Logging.logDebug("--- DirectLoginsComponent.render - 9");
115
116 this.setAddDirectLoginButton(new YAHOO.ext.Button(this.getDom('addDirectLoginButton'), {
117 text:Clipperz.PM.Strings['recordDetailAddNewDirectLoginButtonLabel'],
118 handler:this.addNewDirectLogin,
119 scope:this
120 }));
121 MochiKit.Signal.connect(this.getId('addDirectLoginTextarea'), 'onkeydown', this, 'onkeydown');
122//MochiKit.Logging.logDebug("--- DirectLoginsComponent.render - 11");
123
124 this.update();
125//MochiKit.Logging.logDebug("<<< DirectLoginsComponent.render");
126 },
127
128 //-------------------------------------------------------------------------
129
130 'addDirectLogin': function(aDirectLogin) {
131//MochiKit.Logging.logDebug(">>> DirectLoginsComponent.addDirectLogin");
132 new Clipperz.PM.Components.RecordDetail.DirectLoginComponent(
133 Clipperz.YUI.DomHelper.append(this.getDom('directLogins'), {tag:'div'}, true),
134 {
135 mainComponent:this.mainComponent(),
136 directLogin:aDirectLogin
137 }
138 );
139//MochiKit.Logging.logDebug("<<< DirectLoginsComponent.addDirectLogin");
140 },
141
142 //-------------------------------------------------------------------------
143
144 'addNewDirectLogin': function() {
145 varnewDirectLogin;
146 varconfiguration;
147
148//MochiKit.Logging.logDebug(">>> DirectLoginsComponent.addNewDirectLogin");
149 if (MochiKit.Base.keys(this.record().directLogins()).length == 0) {
150 this.getElement('directLogins').update("");
151 }
152
153 this.mainComponent().synchronizeComponentValues();
154
155 this.mainComponent().exitModalView();
156 configuration = Clipperz.PM.BookmarkletProcessor.checkBookmarkletConfiguration(
157 this.getDom('addDirectLoginTextarea').value,
158 this.getDom('addDirectLoginButton'),
159 MochiKit.Base.method(this.mainComponent(), 'enterModalView')
160 );
161 this.mainComponent().enterModalView();
162
163 newDirectLogin = new Clipperz.PM.DataModel.DirectLogin({record:this.record(),
164 label:configuration['page']['title'],
165 bookmarkletVersion:'0.2',
166 // bookmarkletVersion:configuration['version'],
167 formData:configuration['form']});
168 this.record().addDirectLogin(newDirectLogin);
169 this.addDirectLogin(newDirectLogin);
170 this.getDom('addDirectLoginTextarea').value = "";
171//MochiKit.Logging.logDebug("<<< DirectLoginsComponent.addNewDirectLogin");
172 },
173
174 //-------------------------------------------------------------------------
175
176 'updateViewMode': function() {
177 this.getElement('addDirectLogin').setVisibilityMode(YAHOO.ext.Element.DISPLAY);
178 this.getElement('addDirectLogin').hide();
179 },
180
181 //-------------------------------------------------------------------------
182
183 'updateEditMode': function() {
184 this.getElement('addDirectLogin').show();
185 },
186
187 //-------------------------------------------------------------------------
188
189 'onkeydown': function(anEvent) {
190//MochiKit.Logging.logDebug(">>> onkeydown - " + anEvent.src().id + ": " + anEvent.key().code);
191 if (anEvent.key().code == 13) {
192 this.addNewDirectLogin();
193 }
194 },
195
196 //-------------------------------------------------------------------------
197 __syntaxFix__: "syntax fix"
198});
199
diff --git a/frontend/beta/js/Clipperz/PM/Components/RecordDetail/FieldButtonComponent.js b/frontend/beta/js/Clipperz/PM/Components/RecordDetail/FieldButtonComponent.js
new file mode 100644
index 0000000..9e1d56a
--- a/dev/null
+++ b/frontend/beta/js/Clipperz/PM/Components/RecordDetail/FieldButtonComponent.js
@@ -0,0 +1,117 @@
1/*
2
3Copyright 2008-2011 Clipperz Srl
4
5This file is part of Clipperz's Javascript Crypto Library.
6Javascript Crypto Library provides web developers with an extensive
7and efficient set of cryptographic functions. The library aims to
8obtain maximum execution speed while preserving modularity and
9reusability.
10For further information about its features and functionalities please
11refer to http://www.clipperz.com
12
13* Javascript Crypto Library is free software: you can redistribute
14 it and/or modify it under the terms of the GNU Affero General Public
15 License as published by the Free Software Foundation, either version
16 3 of the License, or (at your option) any later version.
17
18* Javascript Crypto Library is distributed in the hope that it will
19 be useful, but WITHOUT ANY WARRANTY; without even the implied
20 warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
21 See the GNU Affero General Public License for more details.
22
23* You should have received a copy of the GNU Affero General Public
24 License along with Javascript Crypto Library. If not, see
25 <http://www.gnu.org/licenses/>.
26
27*/
28
29if (typeof(Clipperz) == 'undefined') { Clipperz = {}; }
30if (typeof(Clipperz.PM) == 'undefined') { Clipperz.PM = {}; }
31if (typeof(Clipperz.PM.Components) == 'undefined') { Clipperz.PM.Components = {}; }
32if (typeof(Clipperz.PM.Components.RecordDetail) == 'undefined') { Clipperz.PM.Components.RecordDetail = {}; }
33
34//#############################################################################
35
36Clipperz.PM.Components.RecordDetail.FieldButtonComponent = function(anElement, args) {
37 args = args || {};
38
39 Clipperz.PM.Components.RecordDetail.FieldButtonComponent.superclass.constructor.call(this, anElement, args);
40
41 this._button = null;
42
43 this.render();
44
45 return this;
46}
47
48//=============================================================================
49
50YAHOO.extendX(Clipperz.PM.Components.RecordDetail.FieldButtonComponent, Clipperz.PM.Components.RecordDetail.AbstractFieldSubComponent, {
51
52 'toString': function() {
53 return "Clipperz.PM.Components.RecordDetail.FieldButtonComponent";
54 },
55
56 //-------------------------------------------------------------------------
57
58 'buttonText': function() {
59 varresult;
60
61 if (this.recordField() == null) {
62 //TODO: this is never used. It is just an obsolete legacy chunk of code
63 result = Clipperz.PM.Strings['recordDetailAddFieldButtonLabel'];
64 } else {
65 result = Clipperz.PM.Strings['recordDetailRemoveFieldButtonLabel'];
66 }
67
68 return result;
69 },
70
71 //-------------------------------------------------------------------------
72
73 'button': function() {
74 return this._button;
75 },
76
77 'setButton': function(aValue) {
78 this._button = aValue;
79 },
80
81 //-------------------------------------------------------------------------
82
83 'render': function() {
84 this.element().update("");
85
86 Clipperz.YUI.DomHelper.append(this.element().dom, {tag:'div', id:this.getId('button')})
87 this.setButton(new YAHOO.ext.Button(this.getDom('button'), {text:this.buttonText(), handler:this.handleButtonClick, scope:this}));
88
89 this.update();
90 },
91
92 //-------------------------------------------------------------------------
93
94 'handleButtonClick': function() {
95 if (this.recordField() == null) {
96 this.mainComponent().addNewField();
97 } else {
98 this.mainComponent().removeField(this.fieldComponent());
99 }
100 },
101
102 //-------------------------------------------------------------------------
103
104 'updateEditMode': function() {
105 this.button().show();
106 },
107
108 //-------------------------------------------------------------------------
109
110 'updateViewMode': function() {
111 this.button().hide();
112 },
113
114 //-------------------------------------------------------------------------
115 __syntaxFix__: "syntax fix"
116});
117
diff --git a/frontend/beta/js/Clipperz/PM/Components/RecordDetail/FieldComponent.js b/frontend/beta/js/Clipperz/PM/Components/RecordDetail/FieldComponent.js
new file mode 100644
index 0000000..c2d947e
--- a/dev/null
+++ b/frontend/beta/js/Clipperz/PM/Components/RecordDetail/FieldComponent.js
@@ -0,0 +1,189 @@
1/*
2
3Copyright 2008-2011 Clipperz Srl
4
5This file is part of Clipperz's Javascript Crypto Library.
6Javascript Crypto Library provides web developers with an extensive
7and efficient set of cryptographic functions. The library aims to
8obtain maximum execution speed while preserving modularity and
9reusability.
10For further information about its features and functionalities please
11refer to http://www.clipperz.com
12
13* Javascript Crypto Library is free software: you can redistribute
14 it and/or modify it under the terms of the GNU Affero General Public
15 License as published by the Free Software Foundation, either version
16 3 of the License, or (at your option) any later version.
17
18* Javascript Crypto Library is distributed in the hope that it will
19 be useful, but WITHOUT ANY WARRANTY; without even the implied
20 warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
21 See the GNU Affero General Public License for more details.
22
23* You should have received a copy of the GNU Affero General Public
24 License along with Javascript Crypto Library. If not, see
25 <http://www.gnu.org/licenses/>.
26
27*/
28
29if (typeof(Clipperz) == 'undefined') { Clipperz = {}; }
30if (typeof(Clipperz.PM) == 'undefined') { Clipperz.PM = {}; }
31if (typeof(Clipperz.PM.Components) == 'undefined') { Clipperz.PM.Components = {}; }
32if (typeof(Clipperz.PM.Components.RecordDetail) == 'undefined') { Clipperz.PM.Components.RecordDetail = {}; }
33
34//#############################################################################
35
36Clipperz.PM.Components.RecordDetail.FieldComponent = function(anElement, args) {
37//MochiKit.Logging.logDebug(">>> new FieldComponent");
38 args = args || {};
39
40 Clipperz.PM.Components.RecordDetail.FieldComponent.superclass.constructor.call(this, anElement, args);
41
42 this._element = anElement;
43 this._recordField = args.recordField || null;
44
45 this._buttonComponent = null;
46 this._labelComponent = null;
47 this._dragHandler = null;
48 this._valueComponent = null;
49 this._typeComponent = null;
50
51 this.mainComponent().addEditComponent(this);
52
53 this.render();
54
55 return this;
56}
57
58//=============================================================================
59
60YAHOO.extendX(Clipperz.PM.Components.RecordDetail.FieldComponent, Clipperz.PM.Components.RecordDetail.AbstractComponent, {
61
62 'toString': function() {
63 return "Clipperz.PM.Components.RecordDetail.FieldComponent component";
64 },
65
66 //-------------------------------------------------------------------------
67
68 'recordField': function() {
69 return this._recordField;
70 },
71
72 //-------------------------------------------------------------------------
73
74 'buttonComponent': function() {
75 return this._buttonComponent;
76 },
77
78 'setButtonComponent': function(aValue) {
79 this._buttonComponent = aValue;
80 },
81
82 //-------------------------------------------------------------------------
83
84 'labelComponent': function() {
85 return this._labelComponent;
86 },
87
88 'setLabelComponent': function(aValue) {
89 this._labelComponent = aValue;
90 },
91
92 //-------------------------------------------------------------------------
93
94 'dragHandler': function() {
95 return this._dragHandler;
96 },
97
98 'setDragHandler': function(aValue) {
99 this._dragHandler = aValue;
100 },
101
102 //-------------------------------------------------------------------------
103
104 'valueComponent': function() {
105 return this._valueComponent;
106 },
107
108 'setValueComponent': function(aValue) {
109 this._valueComponent = aValue;
110 },
111
112 //-------------------------------------------------------------------------
113
114 'typeComponent': function() {
115 return this._typeComponent;
116 },
117
118 'setTypeComponent': function(aValue) {
119 this._typeComponent = aValue;
120 },
121
122 //-------------------------------------------------------------------------
123
124 'render': function() {
125//MochiKit.Logging.logDebug(">>> RecordDetail.FieldComponent.render");
126 Clipperz.YUI.DomHelper.append(this.element().dom, {tag:'td',/* width:'32',*/ height:'24', cls:'removeFieldButton', align:'left', valign:'top', id:this.getId('button')});
127 Clipperz.YUI.DomHelper.append(this.element().dom, {tag:'td',/* width:'25%',*/ valign:'top', id:this.getId('label')});
128 Clipperz.YUI.DomHelper.append(this.element().dom, {tag:'td',/* width:'3',*/ valign:'top', id:this.getId('dragHandler')});
129 Clipperz.YUI.DomHelper.append(this.element().dom, {tag:'td',/* width:'50%',*/ valign:'top', children:[
130 {tag:'div', cls:'Clipperz_recordFieldData', id:this.getId('value')}
131 ]});
132
133
134 this.setButtonComponent(new Clipperz.PM.Components.RecordDetail.FieldButtonComponent(this.getElement('button'), {fieldComponent:this}));
135 this.setLabelComponent(new Clipperz.PM.Components.RecordDetail.FieldLabelComponent(this.getElement('label'), {fieldComponent:this}));
136 this.setDragHandler(new Clipperz.PM.Components.RecordDetail.FieldDragHandler(this.getElement('dragHandler'), {fieldComponent:this}));
137 this.setValueComponent(new Clipperz.PM.Components.RecordDetail.FieldValueComponent(this.getElement('value'), {fieldComponent:this}));
138
139 if (this.editMode() == 'EDIT') {
140 Clipperz.YUI.DomHelper.append(this.element().dom, {tag:'td',/* width:'60',*/ align:'left', cls:'fieldTypeTD', valign:'top', id:this.getId('type')});
141 this.setTypeComponent(new Clipperz.PM.Components.RecordDetail.FieldTypeComponent(this.getElement('type'), {fieldComponent:this}));
142 }
143
144 this.update();
145//MochiKit.Logging.logDebug("<<< RecordDetail.FieldComponent.render");
146 },
147
148 //-------------------------------------------------------------------------
149
150 'handleButtonClick': function() {
151 this.mainComponent().record().removeField(this.recordField());
152
153 // if (this.recordField() == null) {
154 // this.mainComponent().record().addNewField();
155 // } else {
156 // this.mainComponent().record().removeField(this.recordField());
157 // }
158 },
159
160 //-------------------------------------------------------------------------
161
162 'update': function(anEvent) {
163//MochiKit.Logging.logDebug(">>> RecordDetail.FieldComponent.update");
164 this.buttonComponent().update();
165 this.labelComponent().update();
166 this.dragHandler().update();
167 this.valueComponent().update();
168 if (this.editMode() == 'EDIT') {
169 this.typeComponent().update();
170 }
171//MochiKit.Logging.logDebug("<<< RecordDetail.FieldComponent.update");
172 },
173
174 //-------------------------------------------------------------------------
175
176 'synchronizeComponentValues': function() {
177//MochiKit.Logging.logDebug(">>> FieldComponent.synchronizeComponentValues");
178 this.labelComponent().synchronizeComponentValues();
179 this.valueComponent().synchronizeComponentValues();
180 if (this.editMode() == 'EDIT') {
181 this.typeComponent().synchronizeComponentValues();
182 }
183//MochiKit.Logging.logDebug("<<< FieldComponent.synchronizeComponentValues");
184 },
185
186 //-------------------------------------------------------------------------
187 __syntaxFix__: "syntax fix"
188});
189
diff --git a/frontend/beta/js/Clipperz/PM/Components/RecordDetail/FieldDragHandler.js b/frontend/beta/js/Clipperz/PM/Components/RecordDetail/FieldDragHandler.js
new file mode 100644
index 0000000..13a08fc
--- a/dev/null
+++ b/frontend/beta/js/Clipperz/PM/Components/RecordDetail/FieldDragHandler.js
@@ -0,0 +1,59 @@
1/*
2
3Copyright 2008-2011 Clipperz Srl
4
5This file is part of Clipperz's Javascript Crypto Library.
6Javascript Crypto Library provides web developers with an extensive
7and efficient set of cryptographic functions. The library aims to
8obtain maximum execution speed while preserving modularity and
9reusability.
10For further information about its features and functionalities please
11refer to http://www.clipperz.com
12
13* Javascript Crypto Library is free software: you can redistribute
14 it and/or modify it under the terms of the GNU Affero General Public
15 License as published by the Free Software Foundation, either version
16 3 of the License, or (at your option) any later version.
17
18* Javascript Crypto Library is distributed in the hope that it will
19 be useful, but WITHOUT ANY WARRANTY; without even the implied
20 warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
21 See the GNU Affero General Public License for more details.
22
23* You should have received a copy of the GNU Affero General Public
24 License along with Javascript Crypto Library. If not, see
25 <http://www.gnu.org/licenses/>.
26
27*/
28
29if (typeof(Clipperz) == 'undefined') { Clipperz = {}; }
30if (typeof(Clipperz.PM) == 'undefined') { Clipperz.PM = {}; }
31if (typeof(Clipperz.PM.Components) == 'undefined') { Clipperz.PM.Components = {}; }
32if (typeof(Clipperz.PM.Components.RecordDetail) == 'undefined') { Clipperz.PM.Components.RecordDetail = {}; }
33
34//#############################################################################
35
36Clipperz.PM.Components.RecordDetail.FieldDragHandler = function(anElement, args) {
37 args = args || {};
38
39 Clipperz.PM.Components.RecordDetail.FieldDragHandler.superclass.constructor.call(this, anElement, args);
40
41 this._element = anElement;
42
43 this.render();
44
45 return this;
46}
47
48//=============================================================================
49
50YAHOO.extendX(Clipperz.PM.Components.RecordDetail.FieldDragHandler, Clipperz.PM.Components.RecordDetail.AbstractFieldSubComponent, {
51
52 'toString': function() {
53 return "Clipperz.PM.Components.RecordDetail.FieldDragHandler component";
54 },
55
56 //-------------------------------------------------------------------------
57 __syntaxFix__: "syntax fix"
58});
59
diff --git a/frontend/beta/js/Clipperz/PM/Components/RecordDetail/FieldLabelComponent.js b/frontend/beta/js/Clipperz/PM/Components/RecordDetail/FieldLabelComponent.js
new file mode 100644
index 0000000..3bbcd1d
--- a/dev/null
+++ b/frontend/beta/js/Clipperz/PM/Components/RecordDetail/FieldLabelComponent.js
@@ -0,0 +1,141 @@
1/*
2
3Copyright 2008-2011 Clipperz Srl
4
5This file is part of Clipperz's Javascript Crypto Library.
6Javascript Crypto Library provides web developers with an extensive
7and efficient set of cryptographic functions. The library aims to
8obtain maximum execution speed while preserving modularity and
9reusability.
10For further information about its features and functionalities please
11refer to http://www.clipperz.com
12
13* Javascript Crypto Library is free software: you can redistribute
14 it and/or modify it under the terms of the GNU Affero General Public
15 License as published by the Free Software Foundation, either version
16 3 of the License, or (at your option) any later version.
17
18* Javascript Crypto Library is distributed in the hope that it will
19 be useful, but WITHOUT ANY WARRANTY; without even the implied
20 warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
21 See the GNU Affero General Public License for more details.
22
23* You should have received a copy of the GNU Affero General Public
24 License along with Javascript Crypto Library. If not, see
25 <http://www.gnu.org/licenses/>.
26
27*/
28
29if (typeof(Clipperz) == 'undefined') { Clipperz = {}; }
30if (typeof(Clipperz.PM) == 'undefined') { Clipperz.PM = {}; }
31if (typeof(Clipperz.PM.Components) == 'undefined') { Clipperz.PM.Components = {}; }
32if (typeof(Clipperz.PM.Components.RecordDetail) == 'undefined') { Clipperz.PM.Components.RecordDetail = {}; }
33
34//#############################################################################
35
36Clipperz.PM.Components.RecordDetail.FieldLabelComponent = function(anElement, args) {
37 args = args || {};
38
39 Clipperz.PM.Components.RecordDetail.FieldLabelComponent.superclass.constructor.call(this, anElement, args);
40
41 this._inputElement = null;
42
43 this.render();
44
45 return this;
46}
47
48//=============================================================================
49
50YAHOO.extendX(Clipperz.PM.Components.RecordDetail.FieldLabelComponent, Clipperz.PM.Components.RecordDetail.AbstractFieldSubComponent, {
51
52 'toString': function() {
53 return "Clipperz.PM.Components.RecordDetail.FieldLabelComponent component";
54 },
55
56 //-------------------------------------------------------------------------
57
58 'value': function() {
59 return this.recordField().label();
60 },
61
62 //-------------------------------------------------------------------------
63
64 'inputElement': function() {
65 return this._inputElement;
66 },
67
68 'setInputElement': function(aValue) {
69 this._inputElement = aValue;
70 },
71
72 //-------------------------------------------------------------------------
73
74 'render': function() {
75 varnewTextFormField;
76 this.element().update("");
77 Clipperz.YUI.DomHelper.append(this.element().dom, {tag:'div', cls:'Clipperz_recordFieldLabel', id:this.getId('label')});
78 // Clipperz.YUI.DomHelper.append(this.element().dom, {tag:'div', style:'font-size:8pt;', html:this.recordField().key()});
79
80 // this.setInputElement(new Clipperz.PM.Components.TextFormField(this.getElement('label'), {editMode:this.editMode(), value:this.value()}));
81 newTextFormField = new Clipperz.PM.Components.TextFormField(this.getElement('label'), {editMode:this.editMode(), value:this.value()});
82 // newTextFormField.inputElement().setStyle({border:'3px solid cyan;'});
83 newTextFormField.on('change', this.notifyChanges, this, true)
84 // this.inputElement().on('change', function() {alert("CHANGE");});
85 // this.inputElement().getElement('editComponent_input').on('change', function() {alert("CHANGE");})
86 // this.inputElement().on('blur', this.notifyChanges, this, true);
87
88 this.setInputElement(newTextFormField);
89 this.update();
90 },
91
92 'notifyChanges': function() {
93//MochiKit.Logging.logDebug(">>> FieldLabelComponent.notifyChanges - " + this);
94 this.synchronizeComponentValues();
95 Clipperz.NotificationCenter.notify(this.recordField().recordVersion().record(), 'updatedFieldLabel');
96//MochiKit.Logging.logDebug("<<< FieldLabelComponent.notifyChanges");
97 },
98
99 //-------------------------------------------------------------------------
100
101 'update': function() {
102//MochiKit.Logging.logDebug(">>> FieldLabelComponent.update");
103 this.inputElement().update({editMode:this.editMode(), value:this.value()});
104//MochiKit.Logging.logDebug("<<< FieldLabelComponent.update");
105 },
106
107 //-------------------------------------------------------------------------
108/*
109 'updateViewMode': function() {
110 varwidth;
111 varelement;
112
113 this.element().update("");
114 width = this.element().getWidth();
115 element = Clipperz.YUI.DomHelper.append(this.element().dom, {tag:'div', html:this.value()}, true);
116 element.setWidth(width-1);
117 },
118
119 //-------------------------------------------------------------------------
120
121 'updateEditMode': function() {
122 varwidth;
123
124 this.element().update("");
125 width = this.element().getWidth(true);
126 this.setInputElement(Clipperz.YUI.DomHelper.append(this.element().dom, {tag:'input', type:'text', value:this.value()}, true));
127 this.inputElement().setWidth(width-1);
128 },
129*/
130 //-------------------------------------------------------------------------
131
132 'synchronizeComponentValues': function() {
133 if (this.inputElement() != null) {
134 this.recordField().setLabel(this.inputElement().value());
135 }
136 },
137
138 //-------------------------------------------------------------------------
139 __syntaxFix__: "syntax fix"
140});
141
diff --git a/frontend/beta/js/Clipperz/PM/Components/RecordDetail/FieldTypeComponent.js b/frontend/beta/js/Clipperz/PM/Components/RecordDetail/FieldTypeComponent.js
new file mode 100644
index 0000000..3bdd093
--- a/dev/null
+++ b/frontend/beta/js/Clipperz/PM/Components/RecordDetail/FieldTypeComponent.js
@@ -0,0 +1,157 @@
1/*
2
3Copyright 2008-2011 Clipperz Srl
4
5This file is part of Clipperz's Javascript Crypto Library.
6Javascript Crypto Library provides web developers with an extensive
7and efficient set of cryptographic functions. The library aims to
8obtain maximum execution speed while preserving modularity and
9reusability.
10For further information about its features and functionalities please
11refer to http://www.clipperz.com
12
13* Javascript Crypto Library is free software: you can redistribute
14 it and/or modify it under the terms of the GNU Affero General Public
15 License as published by the Free Software Foundation, either version
16 3 of the License, or (at your option) any later version.
17
18* Javascript Crypto Library is distributed in the hope that it will
19 be useful, but WITHOUT ANY WARRANTY; without even the implied
20 warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
21 See the GNU Affero General Public License for more details.
22
23* You should have received a copy of the GNU Affero General Public
24 License along with Javascript Crypto Library. If not, see
25 <http://www.gnu.org/licenses/>.
26
27*/
28
29if (typeof(Clipperz) == 'undefined') { Clipperz = {}; }
30if (typeof(Clipperz.PM) == 'undefined') { Clipperz.PM = {}; }
31if (typeof(Clipperz.PM.Components) == 'undefined') { Clipperz.PM.Components = {}; }
32if (typeof(Clipperz.PM.Components.RecordDetail) == 'undefined') { Clipperz.PM.Components.RecordDetail = {}; }
33
34//#############################################################################
35
36Clipperz.PM.Components.RecordDetail.FieldTypeComponent = function(anElement, args) {
37 args = args || {};
38
39 Clipperz.PM.Components.RecordDetail.FieldTypeComponent.superclass.constructor.call(this, anElement, args);
40
41 this._inputElement = null;
42
43 this.render();
44
45 return this;
46}
47
48//=============================================================================
49
50YAHOO.extendX(Clipperz.PM.Components.RecordDetail.FieldTypeComponent, Clipperz.PM.Components.RecordDetail.AbstractFieldSubComponent, {
51
52 'toString': function() {
53 return "Clipperz.PM.Components.RecordDetail.FieldTypeComponent component";
54 },
55
56 //-------------------------------------------------------------------------
57
58 'inputElement': function() {
59 return this._inputElement;
60 },
61
62 'setInputElement': function(aValue) {
63 this._inputElement = aValue;
64 },
65
66 //-------------------------------------------------------------------------
67
68 'value': function() {
69 return this.recordField().type();
70 },
71
72 'canChangeType': function() {
73 var value;
74 var result;
75
76 value = this.value();
77 result = ((value == 'TXT') || (value == 'PWD') || (value == 'URL') || (value == 'DATE') || (value == 'ADDR'));
78
79 return result
80 },
81
82 //-------------------------------------------------------------------------
83
84 'updateViewMode': function() {
85 this.element().update("");
86 if (this.canChangeType()) {
87 varwidth;
88 var element;
89
90 width = this.element().getWidth(true);
91 element = Clipperz.YUI.DomHelper.append(this.element().dom, {tag:'div', html:this.recordField().typeShortDescription()}, true);
92 element.setWidth(width-1);
93 }
94 },
95
96 //-------------------------------------------------------------------------
97
98 'updateEditMode': function() {
99 this.element().update("");
100
101 if (this.canChangeType()) {
102 varwidth;
103
104 width = this.element().getWidth(true);
105 this.setInputElement(Clipperz.YUI.DomHelper.append(this.element().dom, {tag:'select', children:[
106 {tag:'option', value:'TXT', htmlString:Clipperz.PM.Strings['recordFieldTypologies']['TXT']['shortDescription']},
107 {tag:'option', value:'PWD', htmlString:Clipperz.PM.Strings['recordFieldTypologies']['PWD']['shortDescription']},
108 {tag:'option', value:'URL', htmlString:Clipperz.PM.Strings['recordFieldTypologies']['URL']['shortDescription']},
109 {tag:'option', value:'DATE', htmlString:Clipperz.PM.Strings['recordFieldTypologies']['DATE']['shortDescription']},
110 {tag:'option', value:'ADDR', htmlString:Clipperz.PM.Strings['recordFieldTypologies']['ADDR']['shortDescription']}
111
112 // {tag:'option', value:'CHECK', html:Clipperz.PM.DataModel.RecordField.TypeDescriptions['CHECK']['shortDescription']},
113 // {tag:'option', value:'RADIO', html:Clipperz.PM.DataModel.RecordField.TypeDescriptions['RADIO']['shortDescription']},
114 // {tag:'option', value:'CHECK', html:Clipperz.PM.DataModel.RecordField.TypeDescriptions['SELECT']['shortDescription']}
115 // {tag:'option', value:'NOTE', html:Clipperz.PM.DataModel.RecordField.TypeDescriptions['NOTE']['shortDescription']}
116 ]}, true));
117 this.inputElement().setWidth(width-1);
118 this.inputElement().addHandler('change', true, this.onChange, this, true);
119 // this.selectCorrectOption();
120 Clipperz.DOM.selectOptionMatchingValue(this.inputElement().dom, this.value());
121 }
122 },
123
124 //-------------------------------------------------------------------------
125
126 'onChange': function() {
127 this.synchronizeComponentValues();
128 this.fieldComponent().valueComponent().handleTypeChange();
129 },
130
131 //-------------------------------------------------------------------------
132/*
133 'selectCorrectOption': function() {
134 varoptions;
135 var i,c;
136
137 options = this.inputElement().getChildrenByTagName('option');
138 c = options.length;
139 for (i=0; i<c; i++) {
140 if (options[i].dom.value == this.value()) {
141 options[i].dom.selected = true;
142 }
143 }
144 },
145 */
146 //-------------------------------------------------------------------------
147
148 'synchronizeComponentValues': function() {
149 if (this.inputElement() != null) {
150 this.recordField().setType(this.inputElement().dom.value);
151 }
152 },
153
154 //-------------------------------------------------------------------------
155 __syntaxFix__: "syntax fix"
156});
157
diff --git a/frontend/beta/js/Clipperz/PM/Components/RecordDetail/FieldValueComponent.js b/frontend/beta/js/Clipperz/PM/Components/RecordDetail/FieldValueComponent.js
new file mode 100644
index 0000000..a30992a
--- a/dev/null
+++ b/frontend/beta/js/Clipperz/PM/Components/RecordDetail/FieldValueComponent.js
@@ -0,0 +1,275 @@
1/*
2
3Copyright 2008-2011 Clipperz Srl
4
5This file is part of Clipperz's Javascript Crypto Library.
6Javascript Crypto Library provides web developers with an extensive
7and efficient set of cryptographic functions. The library aims to
8obtain maximum execution speed while preserving modularity and
9reusability.
10For further information about its features and functionalities please
11refer to http://www.clipperz.com
12
13* Javascript Crypto Library is free software: you can redistribute
14 it and/or modify it under the terms of the GNU Affero General Public
15 License as published by the Free Software Foundation, either version
16 3 of the License, or (at your option) any later version.
17
18* Javascript Crypto Library is distributed in the hope that it will
19 be useful, but WITHOUT ANY WARRANTY; without even the implied
20 warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
21 See the GNU Affero General Public License for more details.
22
23* You should have received a copy of the GNU Affero General Public
24 License along with Javascript Crypto Library. If not, see
25 <http://www.gnu.org/licenses/>.
26
27*/
28
29if (typeof(Clipperz) == 'undefined') { Clipperz = {}; }
30if (typeof(Clipperz.PM) == 'undefined') { Clipperz.PM = {}; }
31if (typeof(Clipperz.PM.Components) == 'undefined') { Clipperz.PM.Components = {}; }
32if (typeof(Clipperz.PM.Components.RecordDetail) == 'undefined') { Clipperz.PM.Components.RecordDetail = {}; }
33
34//#############################################################################
35
36Clipperz.PM.Components.RecordDetail.FieldValueComponent = function(anElement, args) {
37 args = args || {};
38
39 Clipperz.PM.Components.RecordDetail.FieldValueComponent.superclass.constructor.call(this, anElement, args);
40
41 this._inputElement = null;
42 this._scrambledStatus = 'SCRAMBLED'; //'UNSCRAMBLED'
43
44 this.render();
45
46 return this;
47}
48
49//=============================================================================
50
51YAHOO.extendX(Clipperz.PM.Components.RecordDetail.FieldValueComponent, Clipperz.PM.Components.RecordDetail.AbstractFieldSubComponent, {
52
53 'toString': function() {
54 return "Clipperz.PM.Components.RecordDetail.FieldValueComponent component";
55 },
56
57 //-------------------------------------------------------------------------
58
59 'value': function() {
60 return this.recordField().value();
61 },
62
63 'setValue': function(aValue) {
64 this.recordField().setValue(aValue);
65 },
66
67 //-------------------------------------------------------------------------
68
69 'inputElement': function() {
70 return this._inputElement;
71 },
72
73 'setInputElement': function(aValue) {
74 this._inputElement = aValue;
75 },
76
77 //-------------------------------------------------------------------------
78
79 'scrambledStatus': function() {
80 return this._scrambledStatus;
81 },
82
83 'setScrambledStatus': function(aValue) {
84 this._scrambledStatus = aValue;
85 },
86
87 //-------------------------------------------------------------------------
88
89 'handleTypeChange': function() {
90//MochiKit.Logging.logDebug(">>> handling type change - " + this.recordField().type());
91 this.synchronizeComponentValues();
92 this.update();
93 },
94
95 //-------------------------------------------------------------------------
96
97 'addrUrl': function() {
98 var result;
99
100 result = "http://maps.google.com/maps?q=" + this.value().split(' ').join('+');
101
102 return result;
103 },
104
105 //-------------------------------------------------------------------------
106
107 'updateViewMode': function() {
108 var scarmbledStatus;
109
110 scrambledStatus = this.scrambledStatus() || 'SCRAMBLED';
111
112 this.element().update("");
113 if (this.recordField().hidden() == false) {
114 switch(this.recordField().type()) {
115 case 'TXT':
116 case 'PWD':
117 Clipperz.YUI.DomHelper.append(this.element().dom, {tag:'span', html:this.value()});
118 break;
119 case 'URL':
120 varurlLocation;
121
122 urlLocation = Clipperz.Base.sanitizeString(this.value());
123 if (! (/^(https?|ftp|svn):\/\//.test(urlLocation))) {
124 urlLocation = 'http://' + urlLocation;
125 }
126 Clipperz.YUI.DomHelper.append(this.element().dom, {tag:'a', href:urlLocation, html:this.value(), target:'_blank'});
127 break;
128 case 'DATE':
129 Clipperz.YUI.DomHelper.append(this.element().dom, {tag:'span', html:this.value()});
130 break;
131 case 'ADDR':
132 Clipperz.YUI.DomHelper.append(this.element().dom, {tag:'a', href:this.addrUrl(), html:this.value(), target:'_blank'});
133 break;
134 }
135 } else {
136 var tableElement;
137 var tdElement;
138 var inputElement;
139 var passwordElementConfiguration;
140
141 if (scrambledStatus == 'SCRAMBLED') {
142 varscrambledInputElement;
143
144 if ((Clipperz_IEisBroken === true) && (Clipperz.PM.Proxy.defaultProxy.isReadOnly())) {
145 scrambledInputElement = {tag:'input', type:'password', value:"this.value()"};
146 } else {
147 scrambledInputElement = {tag:'input', type:'text', cls:'scrambledField', title:Clipperz.PM.Strings['recordDetailPasswordFieldTooltipLabel'], value:"this.value()"};
148 }
149
150 passwordElementConfiguration =
151 {tag:'table', border:'0', cellspacing:'2', cellpadding:'0', children:[
152 {tag:'tbody', children:[
153 {tag:'tr', children:[
154 {tag:'td', valign:'top', children:[
155 scrambledInputElement,
156 {tag:'a', cls:'scrambleLink', id:this.getId('scrambleLink'), href:'#', htmlString:Clipperz.PM.Strings['recordDetailPasswordFieldUnscrambleLabel']}
157 ]},
158 {tag:'td', valign:'top', children:[
159 {tag:'span', cls:'scrambledFieldLabel', htmlString:Clipperz.PM.Strings['recordDetailPasswordFieldHelpLabel']}
160 ]}
161 ]}
162 ]}
163 ]};
164 } else {
165 passwordElementConfiguration =
166 {tag:'div', children:[
167 {tag:'input', type:'text', cls:'unscrambledField', value:"this.value()"},
168 {tag:'a', cls:'scrambleLink', id:this.getId('scrambleLink'), href:'#', htmlString:Clipperz.PM.Strings['recordDetailPasswordFieldScrambleLabel']}
169 ]};
170 }
171
172 tableElement = Clipperz.YUI.DomHelper.append(this.element().dom, passwordElementConfiguration, true);
173
174 inputElement = tableElement.getChildrenByTagName('input')[0];
175 inputElement.dom.value = this.value();
176 inputElement.wrap({tag:'div', cls:'passwordBackground'}).setStyle('background-position', "0px -" + Math.min(128, Clipperz.PM.Crypto.passwordEntropy(this.value())) + "px");
177
178 MochiKit.Signal.connect(inputElement.dom, 'onfocus', this, 'selectHiddenFieldOnFocus');
179 MochiKit.Signal.connect(this.getDom('scrambleLink'), 'onclick', this, 'toggleScramble');
180 }
181 },
182
183 //-------------------------------------------------------------------------
184
185 'updateEditMode': function() {
186 var inputElement;
187 var scarmbledStatus;
188
189 scrambledStatus = this.scrambledStatus() || 'SCRAMBLED';
190
191 this.element().update("");
192 switch(this.recordField().type()) {
193 case 'TXT':
194 case 'URL':
195 case 'ADDR':
196 inputElement = Clipperz.YUI.DomHelper.append(this.element().dom, {tag:'input', type:'text', value:"this.value()"}, true);
197 inputElement.dom.value = this.value();
198 break;
199 case 'PWD':
200 Clipperz.YUI.DomHelper.append(this.element().dom, {tag:'table', width:'100%', cellpadding:'0', cellspacing:'0', children:[
201 {tag:'tbody', children:[
202 {tag:'tr', children:[
203 {tag:'td', valign:'top', children:[
204 {tag:'input', type:((scrambledStatus == 'SCRAMBLED') ? 'password' : 'text'), id:this.getId('passwordInputElement'), value:"this.value()"},
205 {tag:'a', cls:'scrambleLink', id:this.getId('scrambleLink'), href:'#', html:(scrambledStatus == 'SCRAMBLED' ? Clipperz.PM.Strings['recordDetailPasswordFieldUnscrambleLabel'] : Clipperz.PM.Strings['recordDetailPasswordFieldScrambleLabel'])}
206 ]},
207 {tag:'td', valign:'top', children:[
208 {tag:'div', id:this.getId('passwordGenerator'), cls:'Clipperz_PasswordGenerator_button', html:'&nbsp;'}
209 ]}
210 ]}
211 ]}
212 ]})
213 inputElement = this.getElement('passwordInputElement');
214 inputElement.dom.value = this.value();
215 new Clipperz.PM.Components.PasswordEntropyDisplay(this.getElement('passwordInputElement'));
216 new Clipperz.PM.Components.PasswordGenerator(this.getElement('passwordGenerator'), this);
217 MochiKit.Signal.connect(this.getDom('scrambleLink'), 'onclick', this, 'toggleScramble');
218 break;
219 // case 'NOTE':
220 // inputElement = Clipperz.YUI.DomHelper.append(this.element().dom, {tag:'textarea', rows:'5', html:this.value()}, true);
221 // break
222 case 'DATE':
223 inputElement = Clipperz.YUI.DomHelper.append(this.element().dom, {tag:'input', type:'text', value:"this.value()"}, true);
224 inputElement.dom.value = this.value();
225 break;
226 }
227
228 this.setInputElement(inputElement);
229 },
230
231 //-------------------------------------------------------------------------
232
233 'synchronizeComponentValues': function() {
234//MochiKit.Logging.logDebug(">>> FieldValueComponent.synchronizeComponentValues");
235 if (this.inputElement() != null) {
236 var value;
237
238 switch(this.recordField().type()) {
239 case 'TXT':
240 case 'URL':
241 case 'ADDR':
242 case 'PWD':
243 case 'DATE':
244 value = this.inputElement().dom.value;
245 break;
246 }
247 this.setValue(value);
248 }
249//MochiKit.Logging.logDebug("<<< FieldValueComponent.synchronizeComponentValues");
250 },
251
252 //-------------------------------------------------------------------------
253
254 'selectHiddenFieldOnFocus': function(anEvent) {
255 anEvent.src().select();
256 },
257
258 //-------------------------------------------------------------------------
259
260 'toggleScramble': function(anEvent) {
261 this.synchronizeComponentValues();
262
263 if (this.scrambledStatus() == 'SCRAMBLED') {
264 this.setScrambledStatus('UNSCRAMBLED');
265 } else {
266 this.setScrambledStatus('SCRAMBLED');
267 };
268
269 this.update();
270 },
271
272 //-------------------------------------------------------------------------
273 __syntaxFix__: "syntax fix"
274});
275
diff --git a/frontend/beta/js/Clipperz/PM/Components/RecordDetail/HeaderComponent.js b/frontend/beta/js/Clipperz/PM/Components/RecordDetail/HeaderComponent.js
new file mode 100644
index 0000000..7aaca3e
--- a/dev/null
+++ b/frontend/beta/js/Clipperz/PM/Components/RecordDetail/HeaderComponent.js
@@ -0,0 +1,165 @@
1/*
2
3Copyright 2008-2011 Clipperz Srl
4
5This file is part of Clipperz's Javascript Crypto Library.
6Javascript Crypto Library provides web developers with an extensive
7and efficient set of cryptographic functions. The library aims to
8obtain maximum execution speed while preserving modularity and
9reusability.
10For further information about its features and functionalities please
11refer to http://www.clipperz.com
12
13* Javascript Crypto Library is free software: you can redistribute
14 it and/or modify it under the terms of the GNU Affero General Public
15 License as published by the Free Software Foundation, either version
16 3 of the License, or (at your option) any later version.
17
18* Javascript Crypto Library is distributed in the hope that it will
19 be useful, but WITHOUT ANY WARRANTY; without even the implied
20 warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
21 See the GNU Affero General Public License for more details.
22
23* You should have received a copy of the GNU Affero General Public
24 License along with Javascript Crypto Library. If not, see
25 <http://www.gnu.org/licenses/>.
26
27*/
28
29if (typeof(Clipperz) == 'undefined') { Clipperz = {}; }
30if (typeof(Clipperz.PM) == 'undefined') { Clipperz.PM = {}; }
31if (typeof(Clipperz.PM.Components) == 'undefined') { Clipperz.PM.Components = {}; }
32if (typeof(Clipperz.PM.Components.RecordDetail) == 'undefined') { Clipperz.PM.Components.RecordDetail = {}; }
33
34//#############################################################################
35
36Clipperz.PM.Components.RecordDetail.HeaderComponent = function(anElement, args) {
37 args = args || {};
38
39 Clipperz.PM.Components.RecordDetail.HeaderComponent.superclass.constructor.call(this, anElement, args);
40 this.mainComponent().addEditComponent(this);
41
42 this._saveButton = null;
43
44 this.render();
45
46 return this;
47}
48
49//=============================================================================
50
51YAHOO.extendX(Clipperz.PM.Components.RecordDetail.HeaderComponent, Clipperz.PM.Components.RecordDetail.AbstractComponent, {
52
53 'toString': function() {
54 return "Clipperz.PM.Components.RecordDetail.HeaderComponent component";
55 },
56
57 //-------------------------------------------------------------------------
58
59 'render': function() {
60 var editButton;
61
62//MochiKit.Logging.logDebug(">>> RecordDetail.HeaderComponent.appendTo");
63 Clipperz.YUI.DomHelper.append(this.element().dom, {tag:'div', cls:'recordDetailButtonsBox', children:[
64 {tag:'div', id:this.getId('editButtonBox'), children:[
65 {tag:'table', cls:'recordDetailButtonsTABLE', border:'0', cellpadding:'0', cellspacing:'0', children:[
66 {tag:'tbody', children:[
67 {tag:'tr', children:[
68 {tag:'td', align:'center', children:[
69 {tag:'div', id:this.getId('editButton')}
70 ]}
71 ]}
72 ]}
73 ]}
74 ]},
75 {tag:'div', id:this.getId('saveCancelButtonBox'), children:[
76 {tag:'table', cls:'recordDetailButtonsTABLE', border:'0', cellpadding:'0', cellspacing:'0', children:[
77 {tag:'tbody', children:[
78 {tag:'tr', children:[
79 {tag:'td', width:'49%', align:'right', children:[
80 {tag:'div', id:this.getId('saveButton')}
81 ]},
82 {tag:'td', html:'&nbsp'},
83 {tag:'td', width:'49%', align:'left', children:[
84 {tag:'div', id:this.getId('cancelButton')}
85 ]}
86 ]}
87 ]}
88 ]}
89 ]}
90 ]});
91
92 this.getElement('editButtonBox').setVisibilityMode(YAHOO.ext.Element.DISPLAY);
93 this.getElement('saveCancelButtonBox').setVisibilityMode(YAHOO.ext.Element.DISPLAY);
94
95 editButton = new YAHOO.ext.Button(this.getDom('editButton'), {text:Clipperz.PM.Strings['recordDetailEditButtonLabel'], handler:this.editButtonHandler, scope:this});
96 this.setSaveButton(new YAHOO.ext.Button(this.getDom('saveButton'), {text:Clipperz.PM.Strings['recordDetailSaveButtonLabel'], handler:this.saveButtonHandler, scope:this}));
97 new YAHOO.ext.Button(this.getDom('cancelButton'), {text:Clipperz.PM.Strings['recordDetailCancelButtonLabel'], handler:this.cancelButtonHandler, scope:this});
98
99 if (Clipperz.PM.Proxy.defaultProxy.isReadOnly()) {
100 editButton.disable();
101 }
102
103 this.update();
104//MochiKit.Logging.logDebug("<<< RecordDetail.HeaderComponent.appendTo");
105 },
106
107 //-------------------------------------------------------------------------
108
109 'updateViewMode': function() {
110//MochiKit.Logging.logDebug(">>> HeaderComponent.updateViewMode");
111 this.getElement('editButtonBox').show();
112 this.getElement('saveCancelButtonBox').hide();
113//MochiKit.Logging.logDebug("<<< HeaderComponent.updateViewMode");
114 },
115
116 //-------------------------------------------------------------------------
117
118 'updateEditMode': function() {
119 this.getElement('editButtonBox').hide();
120 this.getElement('saveCancelButtonBox').show();
121 if (this.mainComponent().enableSaveButton() == true) {
122//MochiKit.Logging.logDebug("--- HeaderComponent.updateViewMode - ENABLE");
123 this.saveButton().enable();
124 } else {
125 this.saveButton().disable();
126 }
127 },
128
129 //-------------------------------------------------------------------------
130
131 'saveButton': function() {
132 return this._saveButton;
133 },
134
135 'setSaveButton': function(aValue) {
136 this._saveButton = aValue;
137 },
138
139 //-------------------------------------------------------------------------
140
141 'editButtonHandler': function(anEvent) {
142 this.mainComponent().setEditMode('EDIT');
143 },
144
145 //-------------------------------------------------------------------------
146
147 'saveButtonHandler': function(anEvent) {
148//MochiKit.Logging.logDebug(">>> RecordDetail.HeaderComponent.saveButtonHandler");
149 this.mainComponent().setEditMode('VIEW', this.getElement('saveButton'));
150//MochiKit.Logging.logDebug("<<< RecordDetail.HeaderComponent.saveButtonHandler");
151 },
152
153 //-------------------------------------------------------------------------
154
155 'cancelButtonHandler': function(anEvent) {
156 this.record().cancelChanges();
157//MochiKit.Logging.logDebug("--- HeaderComponent.cancelButtonHandler - " + Clipperz.Base.serializeJSON(this.record().currentDataSnapshot()));
158 this.mainComponent().setEditMode('VIEW', null, true);
159 },
160
161 //-------------------------------------------------------------------------
162
163 __syntaxFix__: "syntax fix"
164});
165
diff --git a/frontend/beta/js/Clipperz/PM/Components/RecordDetail/MainComponent.js b/frontend/beta/js/Clipperz/PM/Components/RecordDetail/MainComponent.js
new file mode 100644
index 0000000..53bf9c5
--- a/dev/null
+++ b/frontend/beta/js/Clipperz/PM/Components/RecordDetail/MainComponent.js
@@ -0,0 +1,758 @@
1/*
2
3Copyright 2008-2011 Clipperz Srl
4
5This file is part of Clipperz's Javascript Crypto Library.
6Javascript Crypto Library provides web developers with an extensive
7and efficient set of cryptographic functions. The library aims to
8obtain maximum execution speed while preserving modularity and
9reusability.
10For further information about its features and functionalities please
11refer to http://www.clipperz.com
12
13* Javascript Crypto Library is free software: you can redistribute
14 it and/or modify it under the terms of the GNU Affero General Public
15 License as published by the Free Software Foundation, either version
16 3 of the License, or (at your option) any later version.
17
18* Javascript Crypto Library is distributed in the hope that it will
19 be useful, but WITHOUT ANY WARRANTY; without even the implied
20 warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
21 See the GNU Affero General Public License for more details.
22
23* You should have received a copy of the GNU Affero General Public
24 License along with Javascript Crypto Library. If not, see
25 <http://www.gnu.org/licenses/>.
26
27*/
28
29if (typeof(Clipperz) == 'undefined') { Clipperz = {}; }
30if (typeof(Clipperz.PM) == 'undefined') { Clipperz.PM = {}; }
31if (typeof(Clipperz.PM.Components) == 'undefined') { Clipperz.PM.Components = {}; }
32if (typeof(Clipperz.PM.Components.RecordDetail) == 'undefined') { Clipperz.PM.Components.RecordDetail = {}; }
33
34//#############################################################################
35
36Clipperz.PM.Components.RecordDetail.MainComponent = function(anElement, args) {
37 args = args || {};
38
39 Clipperz.PM.Components.RecordDetail.MainComponent.superclass.constructor.call(this, anElement, args);
40
41 //this._element = args.element;
42 this._user = args.user;
43 this._editMode = args.editMode || 'VIEW'; //[ 'VIEW' | 'EDIT' ]
44 this._mainPanel = args.mainPanel;
45
46 this._record = null;
47 this._editComponents = [];
48 this._addFieldButton = null;
49
50 this._enableSaveButton = true;
51 this._shouldShowLoginInfo = (Clipperz.PM.Proxy.defaultProxy.isReadOnly() ? false : true);
52
53 //this._mainLayoutManager = null;
54 //this._layoutRegion = null;
55
56 Clipperz.NotificationCenter.register(null, 'loadingRecordData', this, 'render');
57 Clipperz.NotificationCenter.register(null, 'decryptingRecordData', this, 'render');
58 Clipperz.NotificationCenter.register(null, 'loadingRecordVersionData', this, 'render');
59 Clipperz.NotificationCenter.register(null, 'decryptingRecordVersionData', this, 'render');
60 Clipperz.NotificationCenter.register(null, 'setupDone', this, 'render');
61 Clipperz.NotificationCenter.register(null, 'switchLanguage', this, 'render');
62
63 this.render();
64
65 return this;
66}
67
68//=============================================================================
69
70YAHOO.extendX(Clipperz.PM.Components.RecordDetail.MainComponent, Clipperz.PM.Components.BaseComponent, {
71
72 'toString': function() {
73 return "Clipperz.PM.Components.RecordDetail.MainComponent component";
74 },
75
76 //-------------------------------------------------------------------------
77
78 'editMode': function() {
79 return this._editMode;
80 },
81
82 'setEditMode': function(aValue, aButtonElement, shouldSkipComponentSynchronization) {
83//MochiKit.Logging.logDebug(">>> MainComponent.setEditingMode");
84 this.scrollToTop();
85
86 if (aValue == 'VIEW') {
87 if (shouldSkipComponentSynchronization == true) {
88 this.exitModalView();
89 } else {
90 this.synchronizeComponentValues();
91 if (this.record().hasPendingChanges()) {
92 if (this.record().isBrandNew()) {
93 this.record().removeEmptyFields();
94 }
95 this.saveCurrentRecordChanges(aButtonElement);
96 } else {
97 if (this.record().isBrandNew()) {
98 this.record().user().removeRecord(this.record());
99 }
100 this.exitModalView();
101 }
102 }
103 } else if (aValue == 'EDIT') {
104 this.enterModalView();
105 } else {
106 //????
107 }
108
109 this._editMode = aValue;
110 this.render();
111 },
112
113 //-------------------------------------------------------------------------
114
115 'user': function() {
116 return this._user;
117 },
118
119 //-------------------------------------------------------------------------
120
121 'mainPanel': function() {
122 return this._mainPanel;
123 },
124
125 //-------------------------------------------------------------------------
126
127 'render': function() {
128//MochiKit.Logging.logDebug(">>> RecordDetail.MainComponent.render");
129 this.setEnableSaveButton(true);
130 this.element().update("");
131
132 if (this.record() == null) {
133 if (MochiKit.Base.keys(this.user().records()).length == 0) {
134 this.renderWithNoRecordAtAll();
135 } else {
136 this.renderWithNoSelectedRecord();
137 }
138 } else {
139 this.renderWithSelectedRecord();
140 }
141//MochiKit.Logging.logDebug("<<< RecordDetail.MainComponent.render");
142 },
143
144 //-------------------------------------------------------------------------
145
146 'renderWithNoRecordAtAll': function() {
147//MochiKit.Logging.logDebug(">>> RecordDetail.MainComponent.renderWithNoRecordAtAll");
148 Clipperz.YUI.DomHelper.append(this.element().dom,
149 {tag:'form', cls:'noRecordAtAllFORM', children:[
150 {tag:'div', cls:'recordTitleBlock', children:[
151 {tag:'h2', id:'recordTitle', htmlString:Clipperz.PM.Strings['recordDetailNoRecordAtAllTitle']}
152 ]},
153 {tag:'table', border:'0', cellspacing:'0', cellpadding:'0', children:[
154 {tag:'tbody', children:[
155 {tag:'tr', children:[
156 {tag:'td', colspan:'5', children:[
157 {tag:'div', cls:'recordDetailDescriptionBox', htmlString:Clipperz.PM.Strings['recordDetailNoRecordAtAllDescription']}
158 ]}
159 ]}
160 ]}
161 ]}
162 ]}
163 );
164//MochiKit.Logging.logDebug("<<< RecordDetail.MainComponent.renderWithNoRecordAtAll");
165 },
166
167 //-------------------------------------------------------------------------
168
169 'renderWithNoSelectedRecord': function() {
170//MochiKit.Logging.logDebug(">>> RecordDetail.MainComponent.renderWithNoSelectedRecord");
171 Clipperz.YUI.DomHelper.append(this.element().dom,
172 {tag:'form', cls:'noRecordSelectedFORM', children:[
173 {tag:'div', cls:'recordTitleBlock', children:[
174 {tag:'h2', id:'recordTitle', htmlString:Clipperz.PM.Strings['recordDetailNoRecordSelectedTitle']}
175 ]},
176 {tag:'table', border:'0', cellspacing:'0', cellpadding:'0', children:[
177 {tag:'tbody', children:[
178 {tag:'tr', children:[
179 {tag:'td', colspan:'5', children:[
180 {tag:'div', cls:'recordDetailDescriptionBox', htmlString:Clipperz.PM.Strings['recordDetailNoRecordSelectedDescription']}
181 ]}
182 ]},
183 {tag:'tr', colspan:'5', children:[
184 {tag:'td', colspan:'5', children:this.loginInfo()}
185 ]}
186 ]}
187 ]}
188 ]}
189 );
190//MochiKit.Logging.logDebug("--- RecordDetail.MainComponent.renderWithNoSelectedRecord - 1");
191
192 if (MochiKit.DOM.getElement('fullLoginHistoryLink') != null) {
193 MochiKit.Signal.connect('fullLoginHistoryLink', 'onclick', this, 'showLoginHistoryPanel');
194 }
195//MochiKit.Logging.logDebug("--- RecordDetail.MainComponent.renderWithNoSelectedRecord - 2");
196
197 if (MochiKit.DOM.getElement('offlineCopyDownloadWarningLink') != null) {
198 MochiKit.Signal.connect('offlineCopyDownloadWarningLink', 'onclick', this, 'showDownloadOfflineCopyPanel');
199 }
200//MochiKit.Logging.logDebug("<<< RecordDetail.MainComponent.renderWithNoSelectedRecord");
201 },
202
203 //-------------------------------------------------------------------------
204
205 'renderWithSelectedRecord': function() {
206//MochiKit.Logging.logDebug(">>> RecordDetail.MainComponent.renderWithSelectedRecord");
207 if (this.record().shouldLoadData() === true) {
208 // this.renderWithSelectedRecordLoading();
209//MochiKit.Logging.logDebug("--- RecordDetail.MainComponent.renderWithSelectedRecord - 1.1");
210 this.renderWhileProcessingWithMessage(Clipperz.PM.Strings['recordDetailLoadingRecordMessage']);
211//MochiKit.Logging.logDebug("--- RecordDetail.MainComponent.renderWithSelectedRecord - 1.2");
212 } else if (this.record().shouldDecryptData() === true) {
213 // this.renderWithSelectedRecordDecrypting();
214//MochiKit.Logging.logDebug("--- RecordDetail.MainComponent.renderWithSelectedRecord - 2.1");
215 this.renderWhileProcessingWithMessage(Clipperz.PM.Strings['recordDetailDecryptingRecordMessage']);
216//MochiKit.Logging.logDebug("--- RecordDetail.MainComponent.renderWithSelectedRecord - 2.2");
217 } else if (this.record().currentVersion().shouldLoadData() === true) {
218//MochiKit.Logging.logDebug("--- RecordDetail.MainComponent.renderWithSelectedRecord - 3.1");
219 this.renderWhileProcessingWithMessage(Clipperz.PM.Strings['recordDetailLoadingRecordVersionMessage']);
220//MochiKit.Logging.logDebug("--- RecordDetail.MainComponent.renderWithSelectedRecord - 3.2");
221 } else if (this.record().currentVersion().shouldDecryptData() === true) {
222 // this.renderWithSelectedRecordCurrentVersionDecrypting();
223//MochiKit.Logging.logDebug("--- RecordDetail.MainComponent.renderWithSelectedRecord - 4.1");
224 this.renderWhileProcessingWithMessage(Clipperz.PM.Strings['recordDetailDecryptingRecordVersionMessage']);
225//MochiKit.Logging.logDebug("--- RecordDetail.MainComponent.renderWithSelectedRecord - 4.2");
226 } else {
227//MochiKit.Logging.logDebug("--- RecordDetail.MainComponent.renderWithSelectedRecord - 5.1");
228 this.renderWithSelectedRecordData();
229//MochiKit.Logging.logDebug("--- RecordDetail.MainComponent.renderWithSelectedRecord - 5.2");
230 }
231//MochiKit.Logging.logDebug("<<< RecordDetail.MainComponent.renderWithSelectedRecord");
232 },
233
234 //.........................................................................
235
236 'renderWhileProcessingWithMessage': function(aMessage) {
237//MochiKit.Logging.logDebug(">>> RecordDetail.MainComponent.renderWhileProcessingWithMessage");
238 Clipperz.YUI.DomHelper.append(this.element().dom,
239 {tag:'form', cls:'processingRecordFORM', children:[
240 {tag:'div', cls:'recordTitleBlock', children:[
241 {tag:'h2', id:'recordTitle', html:this.record().label()}
242 ]},
243 {tag:'table', border:'0', cellspacing:'0', cellpadding:'0', children:[
244 {tag:'tbody', children:[
245 {tag:'tr', cls:'recordTR', children:[
246 {tag:'td', colspan:'5', children:[
247 {tag:'div', cls:'recordDetailDescriptionBox', children:[
248 {tag:'h5', cls:'recordLoadingMessage', html:aMessage}
249 ]}
250 ]}
251 ]}
252 ]}
253 ]}
254 ]}
255 );
256//MochiKit.Logging.logDebug("<<< RecordDetail.MainComponent.renderWhileProcessingWithMessage");
257 },
258
259 //.........................................................................
260/*
261 'renderWithSelectedRecordLoading': function() {
262 Clipperz.YUI.DomHelper.append(this.element().dom, {tag:'div', cls:'', style:'border:1px solid red; padding: 20px;', children:[
263 {tag:'div', cls:'Clipprez_RecordDetailTitle', children:[
264 {tag:'h3', html:this.record().label()},
265 {tag:'h3', html:"loading"}
266 ]}
267 ]});
268 },
269
270 //.........................................................................
271
272 'renderWithSelectedRecordDecrypting': function() {
273 Clipperz.YUI.DomHelper.append(this.element().dom, {tag:'div', cls:'', style:'border:1px solid red; padding: 20px;', children:[
274 {tag:'div', cls:'Clipprez_RecordDetailTitle', children:[
275 {tag:'h3', html:this.record().label()},
276 {tag:'h3', html:"decrypting ... "}
277 ]}
278 ]});
279 },
280
281 //.........................................................................
282
283 'renderWithSelectedRecordCurrentVersionDecrypting': function() {
284 Clipperz.YUI.DomHelper.append(this.element().dom, {tag:'div', cls:'', style:'border:1px solid red; padding: 20px;', children:[
285 {tag:'div', cls:'Clipprez_RecordDetailTitle', children:[
286 {tag:'h3', html:this.record().label()},
287 {tag:'h3', html:"decrypting version ... "}
288 ]}
289 ]});
290 },
291*/
292 //-------------------------------------------------------------------------
293
294 'renderWithErrorMessage': function(anErrorMessage) {
295//MochiKit.Logging.logDebug(">>> RecordDetail.MainComponent.renderWithErrorMessage");
296 this.element().update("");
297
298//MochiKit.Logging.logDebug("--- RecordDetail.MainComponent.renderWithErrorMessage - 1");
299 Clipperz.YUI.DomHelper.append(this.element().dom,
300 {tag:'form', cls:'errorMessageFORM', children:[
301 {tag:'div', cls:'recordTitleBlock', children:[
302 {tag:'h2', id:'recordTitle', html:this.record().label()}
303 ]},
304 {tag:'table', border:'0', cellspacing:'0', cellpadding:'0', children:[
305 {tag:'tbody', children:[
306 {tag:'tr', cls:'recordTR', children:[
307 {tag:'td', colspan:'5', children:[
308 {tag:'div', cls:'recordDetailDescriptionBox loadingError', children:[
309 {tag:'h5', htmlString:Clipperz.PM.Strings['recordDetailLoadingErrorMessageTitle']},
310 {tag:'p', html:anErrorMessage.message}
311 ]}
312 ]}
313 ]}
314 ]}
315 ]}
316 ]}
317 );
318//MochiKit.Logging.logDebug("<<< RecordDetail.MainComponent.renderWithErrorMessage");
319 },
320
321 //-------------------------------------------------------------------------
322
323 'renderWithSelectedRecordData': function() {
324 varcolumns;
325
326 this.resetEditComponents();
327
328 columns = [
329 {tag:'td', width:'25', html:'&#160'},
330 {tag:'td', width:'25%', htmlString:Clipperz.PM.Strings['recordDetailLabelFieldColumnLabel']},
331 {tag:'td', width:'3', html:'&#160'},
332 {tag:'td', /*width:'80%',*/ htmlString:Clipperz.PM.Strings['recordDetailDataFieldColumnLabel']}
333 ];
334
335 if (this.editMode() == 'EDIT') {
336 columns.push({tag:'td', /*width:'55',*/ htmlString:Clipperz.PM.Strings['recordDetailTypeFieldColumnLabel']})
337 }
338
339//MochiKit.Logging.logDebug(">>> RecordDetail.MainComponent.renderWithSelectedRecordData");
340 Clipperz.YUI.DomHelper.append(this.element().dom,
341 {tag:'form', cls:'recordDataFORM', children:[
342 {tag:'div', cls:'recordTitleBlock', id:this.getId('title')},
343 {tag:'div', id:'recordDetailDataBox', cls:'recordDetailDataBox', children:[
344
345{tag:'table', width:'100%', border:'0', cellspacing:'0', cellpadding:'0', children:[
346 {tag:'tbody', children:[
347 {tag:'tr', children:[
348 {tag:'td', width:'5', html:"&nbsp;"},
349 {tag:'td', children:[
350
351 {tag:'table', cls:'recordDetailDataBoxTABLE', border:'0', cellspacing:'0', cellpadding:'0', children:[
352 {tag:'tbody', id:this.getId('tbody'), children:[
353 {tag:'tr', /*cls:'recordNoteTR',*/ children:[
354 {tag:'td', colspan:'5', id:this.getId('notes')}
355 ]},
356 {tag:'tr', cls:'recordFieldsTR', children:columns /*[
357 {tag:'td', width:'25', html:'&#160'},
358 {tag:'td', width:'25%', htmlString:Clipperz.PM.Strings['recordDetailLabelFieldColumnLabel']},
359 {tag:'td', width:'3', html:'&#160'},
360 {tag:'td', / *width:'80%',* / htmlString:Clipperz.PM.Strings['recordDetailDataFieldColumnLabel']},
361 {tag:'td', / *width:'55',* / htmlString:Clipperz.PM.Strings['recordDetailTypeFieldColumnLabel']}
362 ] */}
363 ]}
364 ]},
365 {tag:'div', cls:'addFieldButton', id:this.getId('addField'), children:[
366 {tag:'div', id:this.getId('addFieldButton')}
367 ]},
368 {tag:'div', id:this.getId('directLogins')},
369 {tag:'div', id:this.getId('footer')}
370
371 ]}
372 ]}
373 ]}
374]}
375
376 ]}
377 ]}
378 );
379
380//MochiKit.Logging.logDebug("--- RecordDetail.MainComponent.renderWithSelectedRecordData - 1");
381
382 new Clipperz.PM.Components.RecordDetail.TitleComponent(this.getElement('title'), {mainComponent:this});
383//MochiKit.Logging.logDebug("--- RecordDetail.MainComponent.renderWithSelectedRecordData - 2");
384 new Clipperz.PM.Components.RecordDetail.NotesComponent(this.getElement('notes'), {mainComponent:this});
385//MochiKit.Logging.logDebug("--- RecordDetail.MainComponent.renderWithSelectedRecordData - 3");
386 new Clipperz.PM.Components.RecordDetail.DirectLoginsComponent(this.getElement('directLogins'), {mainComponent:this});
387//MochiKit.Logging.logDebug("--- RecordDetail.MainComponent.renderWithSelectedRecordData - 4");
388 new Clipperz.PM.Components.RecordDetail.HeaderComponent(this.getElement('footer'), {mainComponent:this});
389//MochiKit.Logging.logDebug("--- RecordDetail.MainComponent.renderWithSelectedRecordData - 5");
390 MochiKit.Iter.forEach(MochiKit.Base.values(this.record().currentVersion().fields()), this.appendFieldComponent, this);
391//MochiKit.Logging.logDebug("--- RecordDetail.MainComponent.renderWithSelectedRecordData - 6");
392 this.setAddFieldButton(new YAHOO.ext.Button(this.getDom('addFieldButton'), {text:Clipperz.PM.Strings['recordDetailAddFieldButtonLabel'], handler:this.addNewRecordField, scope:this}));
393//MochiKit.Logging.logDebug("--- RecordDetail.MainComponent.renderWithSelectedRecordData - 7");
394
395 this.update();
396
397//MochiKit.Logging.logDebug("<<< RecordDetail.MainComponent.renderWithSelectedRecordData");
398 },
399
400 //-------------------------------------------------------------------------
401
402 'editComponents': function() {
403 return this._editComponents;
404 },
405
406 'resetEditComponents': function() {
407 this._editComponents = [];
408 },
409
410 'addEditComponent': function(aValue) {
411 this.editComponents().push(aValue);
412 },
413
414 'removeEditComponent': function(aValue) {
415 Clipperz.Base.removeFromArray(this.editComponents(), aValue);
416 },
417
418 //-------------------------------------------------------------------------
419
420 'record': function() {
421 return this._record;
422 },
423
424 'setRecord': function(aValue) {
425 varresult;
426
427//MochiKit.Logging.logDebug(">>> MainComponent.setRecord")
428 if (this._record != aValue) {
429 vardeferredResult;
430
431 deferredResult = new MochiKit.Async.Deferred();
432
433 if ((this._record != null) && (this.editMode() == 'EDIT')) {
434 this.synchronizeComponentValues();
435 deferredResult.addCallback(MochiKit.Base.method(this._record, 'saveChanges'));
436 }
437
438 this._record = aValue;
439
440 if (aValue != null) {
441 this.setShouldShowLoginInfo(false);
442 deferredResult.addCallback(MochiKit.Base.method(this._record, 'deferredData'));
443 }
444 deferredResult.addCallbacks(
445 MochiKit.Base.method(this, 'render'),
446 MochiKit.Base.method(this, 'renderWithErrorMessage')
447 );
448 deferredResult.callback();
449 this.scrollToTop();
450
451 result = deferredResult;
452 } else {
453 result = MochiKit.Async.success();
454 }
455//MochiKit.Logging.logDebug("<<< MainComponent.setRecord")
456
457 return result;
458 },
459
460 //-------------------------------------------------------------------------
461
462 'saveCurrentRecordChanges': function(aButtonElement) {
463 var deferred;
464 var currentNumberOfRecords;
465
466 deferred = new MochiKit.Async.Deferred();
467 deferred.addCallback(MochiKit.Base.method(Clipperz.PM.Components.MessageBox(), 'deferredShow'),
468 {
469 title:Clipperz.PM.Strings['recordDetailSavingChangesMessagePanelInitialTitle'],
470 text:Clipperz.PM.Strings['recordDetailSavingChangesMessagePanelInitialText'],
471 width:240,
472 showProgressBar:true,
473 showCloseButton:false,
474 steps:6
475 },
476 aButtonElement.dom
477 );
478 deferred.addCallback(MochiKit.Base.method(this, 'exitModalView'));
479 deferred.addCallback(MochiKit.Base.method(this.record(), 'saveChanges'));
480 deferred.addCallback(Clipperz.NotificationCenter.deferredNotification, this.record(), 'recordUpdated');
481 deferred.addCallback(function(res) {
482 Clipperz.PM.Components.MessageBox().hide(YAHOO.ext.Element.get('main'));
483 return res;
484 });
485
486 currentNumberOfRecords = MochiKit.Base.keys(this.user().records()).length;
487 if ((this.record().isBrandNew()) && (this.user().preferences().shouldShowDonationPanel()) && (currentNumberOfRecords >= 5)) {
488 deferred.addCallback(Clipperz.PM.showDonationSplashScreen, this.user(), 'recordListAddRecordButton');
489 }
490
491 deferred.callback();
492 },
493
494 //-------------------------------------------------------------------------
495
496 'update': function(anEvent) {
497 if (this.editMode() == 'EDIT') {
498 this.updateEditMode();
499 } else if (this.editMode() == 'VIEW') {
500 this.updateViewMode();
501 }
502
503 MochiKit.Iter.forEach(this.editComponents(), MochiKit.Base.methodcaller('update'));
504 },
505
506 //-------------------------------------------------------------------------
507
508 'updateViewMode': function() {
509 this.addFieldButton().hide();
510 },
511
512 //-------------------------------------------------------------------------
513
514 'updateEditMode': function() {
515 this.addFieldButton().show();
516 },
517
518 //-------------------------------------------------------------------------
519
520 'appendFieldComponent': function(aRecordField) {
521//MochiKit.Logging.logDebug(">>> MainComponent.appendFieldComponent");
522 new Clipperz.PM.Components.RecordDetail.FieldComponent(
523 Clipperz.YUI.DomHelper.append(this.getDom('tbody'), {tag:'tr'}, true),
524 {recordField:aRecordField, mainComponent:this}
525 );
526//MochiKit.Logging.logDebug("<<< MainComponent.appendFieldComponent");
527 },
528
529 //-------------------------------------------------------------------------
530
531 'removeField': function(aFieldComponent) {
532 varrecordField;
533
534 //MochiKit.Logging.logDebug(">>> MainComponent.removeField")
535 recordField = aFieldComponent.recordField();
536 this.removeEditComponent(aFieldComponent);
537 aFieldComponent.destroy();
538 this.record().removeField(recordField);
539
540 Clipperz.NotificationCenter.notify(this.record(), 'removedField');
541 //MochiKit.Logging.logDebug("<<< MainComponent.removeField")
542 },
543
544 //-------------------------------------------------------------------------
545
546 'synchronizeComponentValues': function() {
547 MochiKit.Iter.forEach(this.editComponents(), MochiKit.Base.methodcaller('synchronizeComponentValues'));
548 },
549
550 //=========================================================================
551
552 'addFieldButton': function() {
553 return this._addFieldButton;
554 },
555
556 'setAddFieldButton': function(aValue) {
557 this._addFieldButton = aValue;
558 },
559
560 'addNewRecordField': function() {
561 varnewField;
562
563 newField = this.record().addNewField();
564 this.appendFieldComponent(newField);
565
566 Clipperz.NotificationCenter.notify(this.record(), 'addNewRecordField');
567 },
568
569 //-------------------------------------------------------------------------
570
571 'enterModalView': function() {
572/*
573 if (this.user().preferences().useSafeEditMode()) {
574 var headerMaskElement;
575 var verticalMaskElement;
576
577 headerMaskElement = YAHOO.ext.Element.get('recordDetailEditModeHeaderMask');
578 headerMaskElement.show().mask();
579
580 verticalMaskElement = YAHOO.ext.Element.get('recordDetailEditModeVerticalMask');
581 verticalMaskElement.show().mask();
582 }
583*/
584 this.mainPanel().enterModalView();
585 },
586
587 //-------------------------------------------------------------------------
588
589 'exitModalView': function() {
590/*
591 if (this.user().preferences().useSafeEditMode()) {
592 var headerMaskElement;
593 var verticalMaskElement;
594
595 headerMaskElement = YAHOO.ext.Element.get('recordDetailEditModeHeaderMask');
596 headerMaskElement.unmask();
597 headerMaskElement.hide();
598
599 verticalMaskElement = YAHOO.ext.Element.get('recordDetailEditModeVerticalMask');
600 verticalMaskElement.unmask();
601 verticalMaskElement.hide();
602 }
603*/
604 this.mainPanel().exitModalView();
605 },
606
607 //-------------------------------------------------------------------------
608
609 'enableSaveButton': function() {
610 return this._enableSaveButton;
611 },
612
613 'setEnableSaveButton': function(aValue) {
614 this._enableSaveButton = aValue;
615 },
616
617 //-------------------------------------------------------------------------
618
619 'scrollToTop': function() {
620 YAHOO.ext.Element.get('recordTitleTopBlock').scrollIntoView(document.body);
621 },
622
623 //-------------------------------------------------------------------------
624
625 'loginInfo': function() {
626 varresult;
627
628 if (this.shouldShowLoginInfo() == true) {
629 // && (typeof(this.user().loginInfo()['latest']) != 'undefined')) {
630 varimageExtension;
631 var currentConnectionText;
632 var currentIP;
633 var contentChildren;
634
635 result = [];
636 contentChildren = [];
637
638 imageExtension = (Clipperz_IEisBroken == true) ? 'gif': 'png';
639
640 contentChildren.push({tag:'h4', valign:'top', htmlString:Clipperz.PM.Strings['WELCOME_BACK']});
641
642 currentIP = (this.user().loginInfo()['current']['ip'].match(/^\d{1,3}(.\d{1,3}){3}$/)) ? this.user().loginInfo()['current']['ip'] : Clipperz.PM.Strings['unknown_ip'];
643 currentConnectionText = Clipperz.PM.Strings['currentConnectionText'];
644 currentConnectionText = currentConnectionText.replace(/__ip__/, "<b>" + Clipperz.Base.sanitizeString(this.user().loginInfo()['current']['ip']) + "</b>");
645 currentConnectionText = currentConnectionText.replace(/__country__/, "<b>" + Clipperz.PM.Strings['countries'][Clipperz.Base.sanitizeString(this.user().loginInfo()['current']['country'])] + "</b>");
646 currentConnectionText = currentConnectionText.replace(/__browser__/, "<b>" + Clipperz.PM.Strings['browsers'][Clipperz.Base.sanitizeString(this.user().loginInfo()['current']['browser'])] + "</b>");
647 currentConnectionText = currentConnectionText.replace(/__operatingSystem__/, "<b>" + Clipperz.PM.Strings['operatingSystems'][Clipperz.Base.sanitizeString(this.user().loginInfo()['current']['operatingSystem'])] + "</b>");
648
649 contentChildren.push(
650 {tag:'div', cls:'loginInfo_now', children:[
651 {tag:'div', cls:'text', htmlString:currentConnectionText},
652 {tag:'div', cls:'icons', children:[
653 {tag:'img', title:Clipperz.PM.Strings['countries'][Clipperz.Base.sanitizeString(this.user().loginInfo()['current']['country'])], cls:'flag', src:Clipperz.PM.Strings['icons_baseUrl'] + "/flags/" + Clipperz.Base.sanitizeString(this.user().loginInfo()['current']['country']).toLowerCase() + "." + imageExtension, width:'32', height:'32'},
654 {tag:'img', title:Clipperz.PM.Strings['browsers'][Clipperz.Base.sanitizeString(this.user().loginInfo()['current']['browser'])], src:Clipperz.PM.Strings['icons_baseUrl'] + "/browsers/" + Clipperz.Base.sanitizeString(this.user().loginInfo()['current']['browser']).toLowerCase() + "." + imageExtension, width:'32', height:'32'},
655 {tag:'img', title:Clipperz.PM.Strings['operatingSystems'][Clipperz.Base.sanitizeString(this.user().loginInfo()['current']['operatingSystem'])], src:Clipperz.PM.Strings['icons_baseUrl'] + "/operatingSystems/" + Clipperz.Base.sanitizeString(this.user().loginInfo()['current']['operatingSystem']).toLowerCase() + "." + imageExtension, width:'32', height:'32'}
656 ]}
657 ]}
658 );
659
660 if (typeof(this.user().loginInfo()['latest']) != 'undefined') {
661 var latestLoginDate;
662 var elapsedTimeDescription;
663 var latestIP;
664 var latestConnectionText;
665
666 latestLoginDate = Clipperz.PM.Date.parseDateWithUTCFormat(Clipperz.Base.sanitizeString(this.user().loginInfo()['latest']['date']));
667
668 elapsedTimeDescription = Clipperz.PM.Date.getElapsedTimeDescription(latestLoginDate);
669 latestIP = (this.user().loginInfo()['latest']['ip'].match(/^\d{1,3}(.\d{1,3}){3}$/)) ? this.user().loginInfo()['latest']['ip'] : Clipperz.PM.Strings['unknown_ip'];
670
671 latestConnectionText = Clipperz.PM.Strings['latestConnectionText'];
672 latestConnectionText = latestConnectionText.replace(/__elapsedTimeDescription__/, "<b>" + elapsedTimeDescription + "</b>");
673 latestConnectionText = latestConnectionText.replace(/__time__/, Clipperz.PM.Date.formatDateWithTemplate(latestLoginDate, Clipperz.PM.Strings['fullDate_format']));
674 latestConnectionText = latestConnectionText.replace(/__ip__/, "<b>" + Clipperz.Base.sanitizeString(this.user().loginInfo()['latest']['ip']) + "</b>");
675 latestConnectionText = latestConnectionText.replace(/__country__/, "<b>" + Clipperz.PM.Strings['countries'][Clipperz.Base.sanitizeString(this.user().loginInfo()['latest']['country'])] + "</b>");
676 latestConnectionText = latestConnectionText.replace(/__browser__/, "<b>" + Clipperz.PM.Strings['browsers'][Clipperz.Base.sanitizeString(this.user().loginInfo()['latest']['browser'])] + "</b>");
677 latestConnectionText = latestConnectionText.replace(/__operatingSystem__/, "<b>" + Clipperz.PM.Strings['operatingSystems'][Clipperz.Base.sanitizeString(this.user().loginInfo()['latest']['operatingSystem'])] + "</b>");
678
679
680 contentChildren.push(
681 {tag:'div', cls:'loginInfo_latest', children:[
682 {tag:'div', cls:'inner_header', html:'&nbsp;'},
683 {tag:'div', cls:'content', children:[
684 {tag:'div', cls:'text', htmlString:latestConnectionText},
685 {tag:'div', cls:'icons', children:[
686 {tag:'img', title:Clipperz.PM.Strings['countries'][Clipperz.Base.sanitizeString(this.user().loginInfo()['latest']['country'])], cls:'flag', src:Clipperz.PM.Strings['icons_baseUrl'] + "/flags/" + Clipperz.Base.sanitizeString(this.user().loginInfo()['latest']['country']).toLowerCase() + "." + imageExtension, width:'32', height:'32'},
687 {tag:'img', title:Clipperz.PM.Strings['browsers'][Clipperz.Base.sanitizeString(this.user().loginInfo()['latest']['browser'])], src:Clipperz.PM.Strings['icons_baseUrl'] + "/browsers/" + Clipperz.Base.sanitizeString(this.user().loginInfo()['latest']['browser']).toLowerCase() + "." + imageExtension, width:'32', height:'32'},
688 {tag:'img', title:Clipperz.PM.Strings['operatingSystems'][Clipperz.Base.sanitizeString(this.user().loginInfo()['latest']['operatingSystem'])], src:Clipperz.PM.Strings['icons_baseUrl'] + "/operatingSystems/" + Clipperz.Base.sanitizeString(this.user().loginInfo()['latest']['operatingSystem']).toLowerCase() + "." + imageExtension, width:'32', height:'32'}
689 ]}
690 ]},
691 {tag:'div', children:[
692 {tag:'a', href:'#', id:'fullLoginHistoryLink', htmlString:Clipperz.PM.Strings['fullLoginHistoryLinkLabel']}
693 ]},
694 {tag:'div', cls:'inner_footer', html:'&nbsp;'}
695 ]}
696 );
697 }
698
699 contentChildren.push(
700 {tag:'table', id:'shouldDownloadOfflineCopyWarningBox', children:[
701 {tag:'tbody', width:'100%', children:[
702 {tag:'tr', children:[
703 {tag:'td', cls:'offlineCopyDownloadWarningIconTD', valign:'top', align:'center', width:'50', children:(this.user().shouldDownloadOfflineCopy() ? [{tag:'img', src:Clipperz.PM.Strings['icons_baseUrl'] + "/misc/offlineCopyWarning.png" , width:'32', height:'32'}]: [])},
704 {tag:'td', children:[
705 {tag:'div', cls:'offlineCopyDownloadWarning', htmlString:(this.user().shouldDownloadOfflineCopy() ? Clipperz.PM.Strings['offlineCopyDownloadWarning']: Clipperz.PM.Strings['offlineCopyDownloadOk'])}
706 ]}
707 ]}
708 ]}
709 ]}
710 );
711
712
713 result = [{tag:'div', id:'loginInfoWrapper', children:[{tag:'div', id:'loginInfo', children:[
714 {tag:'div', cls:'header', html:'&nbsp;'},
715 {tag:'div', cls:'content', children:contentChildren},
716 {tag:'div', cls:'footer', html:'&nbsp;'}
717 ]}]}];
718
719 // this.setShouldShowLoginInfo(false);
720 } else {
721 resut = [];
722 }
723
724 return result;
725 },
726
727 //-------------------------------------------------------------------------
728
729 'shouldShowLoginInfo': function() {
730 return this._shouldShowLoginInfo;
731 },
732
733 'setShouldShowLoginInfo': function(aValue) {
734 this._shouldShowLoginInfo = aValue;
735 },
736
737 //-------------------------------------------------------------------------
738
739 'showLoginHistoryPanel': function(anEvent) {
740 anEvent.stop();
741
742 Clipperz.NotificationCenter.notify(this, 'selectTab', 'mainTabPanel.accountTab', true);
743 Clipperz.NotificationCenter.notify(this, 'selectTab', 'accountTabPanel.loginHistoryTab', true);
744 },
745
746 //-------------------------------------------------------------------------
747
748 'showDownloadOfflineCopyPanel': function(anEvent) {
749 anEvent.stop();
750
751 Clipperz.NotificationCenter.notify(this, 'selectTab', 'mainTabPanel.dataTab', true);
752 Clipperz.NotificationCenter.notify(this, 'selectTab', 'dataTabPanel.offlineCopyTab', true);
753 },
754
755 //-------------------------------------------------------------------------
756 __syntaxFix__: "syntax fix"
757});
758
diff --git a/frontend/beta/js/Clipperz/PM/Components/RecordDetail/NotesComponent.js b/frontend/beta/js/Clipperz/PM/Components/RecordDetail/NotesComponent.js
new file mode 100644
index 0000000..6f454fc
--- a/dev/null
+++ b/frontend/beta/js/Clipperz/PM/Components/RecordDetail/NotesComponent.js
@@ -0,0 +1,240 @@
1/*
2
3Copyright 2008-2011 Clipperz Srl
4
5This file is part of Clipperz's Javascript Crypto Library.
6Javascript Crypto Library provides web developers with an extensive
7and efficient set of cryptographic functions. The library aims to
8obtain maximum execution speed while preserving modularity and
9reusability.
10For further information about its features and functionalities please
11refer to http://www.clipperz.com
12
13* Javascript Crypto Library is free software: you can redistribute
14 it and/or modify it under the terms of the GNU Affero General Public
15 License as published by the Free Software Foundation, either version
16 3 of the License, or (at your option) any later version.
17
18* Javascript Crypto Library is distributed in the hope that it will
19 be useful, but WITHOUT ANY WARRANTY; without even the implied
20 warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
21 See the GNU Affero General Public License for more details.
22
23* You should have received a copy of the GNU Affero General Public
24 License along with Javascript Crypto Library. If not, see
25 <http://www.gnu.org/licenses/>.
26
27*/
28
29if (typeof(Clipperz) == 'undefined') { Clipperz = {}; }
30if (typeof(Clipperz.PM) == 'undefined') { Clipperz.PM = {}; }
31if (typeof(Clipperz.PM.Components) == 'undefined') { Clipperz.PM.Components = {}; }
32if (typeof(Clipperz.PM.Components.RecordDetail) == 'undefined') { Clipperz.PM.Components.RecordDetail = {}; }
33
34//#############################################################################
35
36
37
38Clipperz.PM.Components.RecordDetail.NotesComponent = function(anElement, args) {
39//MochiKit.Logging.logDebug(">>> new NotesComponent");
40 args = args || {};
41
42 Clipperz.PM.Components.RecordDetail.NotesComponent.superclass.constructor.call(this, anElement, args);
43
44 this.mainComponent().addEditComponent(this);
45
46 this._staticOffset = null;
47 this._componentHeight = 50;
48 this._mouseMoveIdentifier = null;
49 this._mouseUpIdentifier = null;
50
51 this.element().setVisibilityMode(YAHOO.ext.Element.DISPLAY);
52
53 this.render();
54//MochiKit.Logging.logDebug("<<< new NotesComponent");
55
56 return this;
57}
58
59//=============================================================================
60
61YAHOO.extendX(Clipperz.PM.Components.RecordDetail.NotesComponent, Clipperz.PM.Components.RecordDetail.AbstractComponent, {
62
63 'toString': function() {
64 return "Clipperz.PM.Components.RecordDetail.NotesComponent component";
65 },
66
67 //-------------------------------------------------------------------------
68
69 'value': function() {
70 return this.record().notes();
71 },
72
73 'setValue': function(aValue) {
74 this.record().setNotes(aValue);
75 },
76
77 //-------------------------------------------------------------------------
78
79 'render': function() {
80//MochiKit.Logging.logDebug(">>> NotesComponent.render");
81/*
82 Clipperz.YUI.DomHelper.append(this.element().dom, {tag:'td', colspan:'5', children:[
83 {tag:'span', cls:'noteFieldLabel', htmlString:Clipperz.PM.Strings['recordDetailNotesLabel']},
84 {tag:'div', cls:'noteFieldContent', id:this.getId('notes')}
85 ]});
86 */
87 Clipperz.YUI.DomHelper.append(this.element().dom, {tag:'span', cls:'noteFieldLabel', htmlString:Clipperz.PM.Strings['recordDetailNotesLabel']});
88 Clipperz.YUI.DomHelper.append(this.element().dom, {tag:'div', cls:'noteFieldContent', id:this.getId('notes'), children:[
89 {tag:'div', id:this.getId('resizableDiv'), cls:'resizable-textarea', children:[
90 {tag:'div', id:this.getId('contentView'), cls:'viewMode', html:""},
91 {tag:'div', id:this.getId('contentEdit'), children:[
92 {tag:'span', children:[
93 {tag:'textarea', id:this.getId('textarea'), html:""}
94 ]}
95 ]},
96 {tag:'div', id:this.getId('grippie'), cls:'grippie'}
97 ]}
98 ]});
99
100 this.getElement('contentView').setVisibilityMode(YAHOO.ext.Element.DISPLAY);
101 this.getElement('contentEdit').setVisibilityMode(YAHOO.ext.Element.DISPLAY);
102
103 MochiKit.Signal.connect(this.getId('grippie'), 'onmousedown', this, 'startResize');
104
105 this.update();
106//MochiKit.Logging.logDebug("<<< NotesComponent.render");
107 },
108
109 //-------------------------------------------------------------------------
110
111 'updateViewMode': function() {
112//MochiKit.Logging.logDebug(">>> NotesComponent.updateViewMode");
113 // this.getElement('notes').update(this.value().replace(/\n/g, '<br>'));
114
115 this.getElement('contentView').update(Clipperz.Base.sanitizeString(this.value()).replace(/\n/g, '<br>'));
116
117 if (this.isNoteEmpty()) {
118 this.element().hide();
119 } else {
120 this.getElement('contentView').show();
121 this.getElement('contentView').setHeight(this.componentHeight());
122 }
123 this.getElement('contentEdit').hide();
124
125//MochiKit.Logging.logDebug("<<< NotesComponent.updateViewMode");
126 },
127
128 //-------------------------------------------------------------------------
129
130 'updateEditMode': function() {
131//MochiKit.Logging.logDebug(">>> NotesComponent.updateEditMode");
132 this.getDom('textarea').value = this.value().replace(/\n/g, Clipperz_normalizedNewLine);
133
134 this.getElement('contentView').hide();
135 this.getElement('contentEdit').show();
136
137 this.getElement('textarea').setHeight(this.componentHeight());
138//MochiKit.Logging.logDebug("<<< NotesComponent.updateEditMode");
139 },
140
141 //-------------------------------------------------------------------------
142
143 'synchronizeComponentValues': function() {
144//MochiKit.Logging.logDebug(">>> NotesComponent.synchronizeComponentValues");
145 if (this.getElement('textarea') != null) {
146 this.setValue(this.getDom('textarea').value.replace(/(\x0a\x0d|\x0d\x0a)/g,'\n'));
147 }
148//MochiKit.Logging.logDebug("<<< NotesComponent.synchronizeComponentValues");
149 },
150
151 //-------------------------------------------------------------------------
152
153 'componentHeight': function() {
154 return this._componentHeight;
155 },
156
157 'setComponentHeight': function(aValue) {
158 this._componentHeight = aValue;
159 },
160
161 //-------------------------------------------------------------------------
162
163 'isNoteEmpty': function() {
164 return !/[^ \n]/.test(this.value());
165 },
166
167 //-------------------------------------------------------------------------
168
169 'staticOffset': function() {
170 return this._staticOffset;
171 },
172
173 'setStaticOffset': function(aValue) {
174 this._staticOffset = aValue;
175 },
176
177 //-------------------------------------------------------------------------
178
179 'startResize': function(anEvent) {
180//MochiKit.Logging.logDebug(">>> startResize");
181 if (this.editMode() == 'VIEW') {
182 this.setStaticOffset(this.getElement('contentView').getHeight() - anEvent.mouse().page['y'])
183 } else {
184 this.setStaticOffset(this.getElement('textarea').getHeight() - anEvent.mouse().page['y'])
185 // this.getElement('textarea').setStyle('opacity', 0.25);
186 }
187 this.setMouseMoveIdentifier(MochiKit.Signal.connect(MochiKit.DOM.currentDocument(), 'onmousemove', this, 'whileResizing'));
188 this.setMouseUpIdentifier(MochiKit.Signal.connect(MochiKit.DOM.currentDocument(), 'onmouseup', this, 'endResize'));
189 anEvent.stop();
190//MochiKit.Logging.logDebug("<<< startResize");
191 },
192
193 //-------------------------------------------------------------------------
194
195 'whileResizing': function(anEvent) {
196//MochiKit.Logging.logDebug(">>> whileResizing");
197 this.getElement('textarea').setHeight(Math.max(32, this.staticOffset() + anEvent.mouse().page['y']) + 'px');
198 this.getElement('contentView').setHeight(Math.max(32, this.staticOffset() + anEvent.mouse().page['y']) + 'px');
199 anEvent.stop();
200//MochiKit.Logging.logDebug("<<< whileResizing");
201 },
202
203 //-------------------------------------------------------------------------
204
205 'endResize': function(anEvent) {
206//MochiKit.Logging.logDebug(">>> endResize");
207 MochiKit.Signal.disconnect(this.mouseMoveIdentifier());
208 this.setMouseMoveIdentifier(null);
209 MochiKit.Signal.disconnect(this.mouseUpIdentifier());
210 this.setMouseUpIdentifier(null);
211 // this.getElement('textarea').setStyle('opacity', 1);
212
213 this.setComponentHeight(this.getElement('textarea').getHeight());
214//MochiKit.Logging.logDebug("<<< endResize");
215 },
216
217 //-------------------------------------------------------------------------
218
219 'mouseMoveIdentifier': function() {
220 return this._mouseMoveIdentifier;
221 },
222
223 'setMouseMoveIdentifier': function(aValue) {
224 this._mouseMoveIdentifier = aValue;
225 },
226
227 //-------------------------------------------------------------------------
228
229 'mouseUpIdentifier': function() {
230 return this._mouseUpIdentifier;
231 },
232
233 'setMouseUpIdentifier': function(aValue) {
234 this._mouseUpIdentifier = aValue;
235 },
236
237 //-------------------------------------------------------------------------
238 __syntaxFix__: "syntax fix"
239});
240
diff --git a/frontend/beta/js/Clipperz/PM/Components/RecordDetail/TitleComponent.js b/frontend/beta/js/Clipperz/PM/Components/RecordDetail/TitleComponent.js
new file mode 100644
index 0000000..52e718c
--- a/dev/null
+++ b/frontend/beta/js/Clipperz/PM/Components/RecordDetail/TitleComponent.js
@@ -0,0 +1,137 @@
1/*
2
3Copyright 2008-2011 Clipperz Srl
4
5This file is part of Clipperz's Javascript Crypto Library.
6Javascript Crypto Library provides web developers with an extensive
7and efficient set of cryptographic functions. The library aims to
8obtain maximum execution speed while preserving modularity and
9reusability.
10For further information about its features and functionalities please
11refer to http://www.clipperz.com
12
13* Javascript Crypto Library is free software: you can redistribute
14 it and/or modify it under the terms of the GNU Affero General Public
15 License as published by the Free Software Foundation, either version
16 3 of the License, or (at your option) any later version.
17
18* Javascript Crypto Library is distributed in the hope that it will
19 be useful, but WITHOUT ANY WARRANTY; without even the implied
20 warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
21 See the GNU Affero General Public License for more details.
22
23* You should have received a copy of the GNU Affero General Public
24 License along with Javascript Crypto Library. If not, see
25 <http://www.gnu.org/licenses/>.
26
27*/
28
29if (typeof(Clipperz) == 'undefined') { Clipperz = {}; }
30if (typeof(Clipperz.PM) == 'undefined') { Clipperz.PM = {}; }
31if (typeof(Clipperz.PM.Components) == 'undefined') { Clipperz.PM.Components = {}; }
32if (typeof(Clipperz.PM.Components.RecordDetail) == 'undefined') { Clipperz.PM.Components.RecordDetail = {}; }
33
34//#############################################################################
35
36Clipperz.PM.Components.RecordDetail.TitleComponent = function(anElement, args) {
37 args = args || {};
38
39 Clipperz.PM.Components.RecordDetail.TitleComponent.superclass.constructor.call(this, anElement, args);
40
41 //this._inputElement = null;
42
43 this.mainComponent().addEditComponent(this);
44
45 this.render();
46
47 return this;
48}
49
50//=============================================================================
51
52YAHOO.extendX(Clipperz.PM.Components.RecordDetail.TitleComponent, Clipperz.PM.Components.RecordDetail.AbstractComponent, {
53
54 'toString': function() {
55 return "Clipperz.PM.Components.RecordDetail.TitleComponent component";
56 },
57
58 //-------------------------------------------------------------------------
59
60 'value': function() {
61 return this.record().label();
62 },
63
64 'setValue': function(aValue) {
65 this.record().setLabel(aValue);
66 },
67
68 //-------------------------------------------------------------------------
69/*
70 'inputElement': function() {
71 return this._inputElement;
72 },
73
74 'setInputElement': function(aValue) {
75 this._inputElement = aValue;
76 },
77*/
78 //-------------------------------------------------------------------------
79
80 'render': function() {
81 // Clipperz.YUI.DomHelper.append(this.element().dom, {tag:'td', html:'&#160'});
82 // Clipperz.YUI.DomHelper.append(this.element().dom, {tag:'td', colspan:"3", html:'&#160', children:[
83 // {tag:'div', /*style:'border: 1px solid green;',*/ id:this.getId('title')}
84 // ]});
85 // Clipperz.YUI.DomHelper.append(this.element().dom, {tag:'td', html:'&#160'});
86 //
87 // this.setInputElement(new Clipperz.PM.Components.TextFormField(this.getElement('title'), {editMode:this.editMode(), value:this.value()}));
88
89 this.update();
90 },
91
92 //-------------------------------------------------------------------------
93/*
94 'update': function() {
95 this.inputElement().update({value:this.value(), editMode:this.editMode()});
96 },
97 */
98 //-------------------------------------------------------------------------
99
100 'updateViewMode': function() {
101 this.element().update("");
102 Clipperz.YUI.DomHelper.append(this.element().dom, {tag:'h2', html:this.value()});
103 },
104
105 //-------------------------------------------------------------------------
106
107 'updateEditMode': function() {
108//MochiKit.Logging.logDebug(">>> TitleComponent.updateEditMode");
109 // this.getElement('title').update("");
110 // Clipperz.YUI.DomHelper.append(this.getDom('title'), {tag:'div', id:this.getId('title_input')});
111 // this.setInputElement(Clipperz.YUI.DomHelper.append(this.getDom('title_input'), {tag:'input', type:'text', value:this.value()}, true));
112
113 this.element().update("");
114 Clipperz.YUI.DomHelper.append(this.element().dom, {tag:'input', id:this.getId('titleField'), type:'text', value:"this.value()"});
115 this.getElement('titleField').dom.value = this.value();
116
117//MochiKit.Logging.logDebug("<<< TitleComponent.updateEditMode");
118 },
119
120 //-------------------------------------------------------------------------
121
122 'synchronizeComponentValues': function() {
123 var inputElement;
124
125//MochiKit.Logging.logDebug(">>> TitleComponent.synchronizeComponentValues");
126 inputElement = this.element().getChildrenByTagName('input')[0];
127
128 if (inputElement != null) {
129 this.setValue(inputElement.dom.value);
130 }
131//MochiKit.Logging.logDebug("<<< TitleComponent.synchronizeComponentValues");
132 },
133
134 //-------------------------------------------------------------------------
135 __syntaxFix__: "syntax fix"
136});
137
diff --git a/frontend/beta/js/Clipperz/PM/Components/TabPanel/TabPanelController.js b/frontend/beta/js/Clipperz/PM/Components/TabPanel/TabPanelController.js
new file mode 100644
index 0000000..c872462
--- a/dev/null
+++ b/frontend/beta/js/Clipperz/PM/Components/TabPanel/TabPanelController.js
@@ -0,0 +1,158 @@
1/*
2
3Copyright 2008-2011 Clipperz Srl
4
5This file is part of Clipperz's Javascript Crypto Library.
6Javascript Crypto Library provides web developers with an extensive
7and efficient set of cryptographic functions. The library aims to
8obtain maximum execution speed while preserving modularity and
9reusability.
10For further information about its features and functionalities please
11refer to http://www.clipperz.com
12
13* Javascript Crypto Library is free software: you can redistribute
14 it and/or modify it under the terms of the GNU Affero General Public
15 License as published by the Free Software Foundation, either version
16 3 of the License, or (at your option) any later version.
17
18* Javascript Crypto Library is distributed in the hope that it will
19 be useful, but WITHOUT ANY WARRANTY; without even the implied
20 warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
21 See the GNU Affero General Public License for more details.
22
23* You should have received a copy of the GNU Affero General Public
24 License along with Javascript Crypto Library. If not, see
25 <http://www.gnu.org/licenses/>.
26
27*/
28
29if (typeof(Clipperz) == 'undefined') { Clipperz = {}; }
30if (typeof(Clipperz.PM) == 'undefined') { Clipperz.PM = {}; }
31if (typeof(Clipperz.PM.Components) == 'undefined') { Clipperz.PM.Components = {}; }
32if (typeof(Clipperz.PM.Components.TabPanel) == 'undefined') { Clipperz.PM.Components.TabPanel = {}; }
33
34Clipperz.PM.Components.TabPanel.TabPanelController = function(args) {
35 args = args || {};
36
37 Clipperz.PM.Components.TabPanel.TabPanelController.superclass.constructor.call(this);
38
39 this._name = args.name || 'undefined';
40 this._config = args.config;
41 this._selectedTab = args.selectedTab || ((MochiKit.Base.keys(args.config).length > 0) ? MochiKit.Base.keys(args.config)[0] : null);
42
43 this._tabs = {};
44 this._panels = {};
45
46 Clipperz.NotificationCenter.register(null, 'selectTab', this, 'handleSelectTabNotification');
47 return this;
48}
49
50//=============================================================================
51
52YAHOO.extendX(Clipperz.PM.Components.TabPanel.TabPanelController, YAHOO.ext.util.Observable, {
53
54 //-------------------------------------------------------------------------
55
56 'name': function() {
57 return this._name;
58 },
59
60 //-------------------------------------------------------------------------
61
62 'tabs': function() {
63 return this._tabs;
64 },
65
66 //-------------------------------------------------------------------------
67
68 'panels': function() {
69 return this._panels;
70 },
71
72 //-------------------------------------------------------------------------
73
74 'config': function() {
75 return this._config;
76 },
77
78 //-------------------------------------------------------------------------
79
80 'selectedTab': function() {
81 return this._selectedTab;
82 },
83
84 'setSelectedTab': function(aValue) {
85 this._selectedTab = aValue;
86 },
87
88 //-------------------------------------------------------------------------
89
90 'setUp': function() {
91 vartabId;
92
93//MochiKit.Logging.logDebug(">>> TabPanelController.setUp - config: " + Clipperz.Base.serializeJSON(this.config()));
94 for (tabId in this.config()) {
95 vartabElement;
96 varpanelElement;
97
98//MochiKit.Logging.logDebug("--- TabPanelController.setUp - tabId: " + tabId);
99//MochiKit.Logging.logDebug("--- TabPanelController.setUp - panelId: " + this.config()[tabId]);
100 tabElement = YAHOO.ext.Element.get(tabId);
101 tabElement.addClassOnOver("hover");
102 MochiKit.Signal.connect(tabId, 'onclick', this, 'selectTabHandler');
103
104 panelElement = YAHOO.ext.Element.get(this.config()[tabId]);
105
106 this._tabs[tabId] = tabElement;
107 this._panels[tabId] = panelElement;
108
109 if (tabId == this.selectedTab()) {
110 tabElement.addClass('selectedTab');
111 panelElement.addClass('selectedPanel');
112 } else {
113 panelElement.addClass('hiddenPanel');
114 }
115 }
116//MochiKit.Logging.logDebug("<<< TabPanelController.setUp");
117 },
118
119 //-------------------------------------------------------------------------
120
121 'selectTab': function(aTab) {
122 if (aTab != this.selectedTab()) {
123 this.tabs()[this.selectedTab()].removeClass('selectedTab');
124 this.panels()[this.selectedTab()].removeClass('selectedPanel').addClass('hiddenPanel');
125
126 this.tabs()[aTab].addClass('selectedTab');
127 this.panels()[aTab].addClass('selectedPanel').removeClass('hiddenPanel');
128
129 this.setSelectedTab(aTab);
130
131 Clipperz.NotificationCenter.notify(this, 'tabSelected', aTab);
132 }
133 },
134
135 //-------------------------------------------------------------------------
136
137 'selectTabHandler': function(anEvent) {
138 this.selectTab(anEvent.src().id);
139 },
140
141 //-------------------------------------------------------------------------
142
143 'handleSelectTabNotification': function(aNotificationEvent) {
144 var parameters;
145 var splittedParamters;
146 vartargetTabPanel;
147
148 parameters = aNotificationEvent.parameters();
149 splittedParamters = parameters.split('.');
150 targetTabPanel = splittedParamters[0];
151 if (targetTabPanel == this.name()) {
152 this.selectTab(splittedParamters[1])
153 }
154 },
155
156 //-------------------------------------------------------------------------
157 __syntaxFix__: "syntax fix"
158});
diff --git a/frontend/beta/js/Clipperz/PM/Components/TextFormField.js b/frontend/beta/js/Clipperz/PM/Components/TextFormField.js
new file mode 100644
index 0000000..cb4f06a
--- a/dev/null
+++ b/frontend/beta/js/Clipperz/PM/Components/TextFormField.js
@@ -0,0 +1,310 @@
1/*
2
3Copyright 2008-2011 Clipperz Srl
4
5This file is part of Clipperz's Javascript Crypto Library.
6Javascript Crypto Library provides web developers with an extensive
7and efficient set of cryptographic functions. The library aims to
8obtain maximum execution speed while preserving modularity and
9reusability.
10For further information about its features and functionalities please
11refer to http://www.clipperz.com
12
13* Javascript Crypto Library is free software: you can redistribute
14 it and/or modify it under the terms of the GNU Affero General Public
15 License as published by the Free Software Foundation, either version
16 3 of the License, or (at your option) any later version.
17
18* Javascript Crypto Library is distributed in the hope that it will
19 be useful, but WITHOUT ANY WARRANTY; without even the implied
20 warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
21 See the GNU Affero General Public License for more details.
22
23* You should have received a copy of the GNU Affero General Public
24 License along with Javascript Crypto Library. If not, see
25 <http://www.gnu.org/licenses/>.
26
27*/
28
29if (typeof(Clipperz) == 'undefined') { Clipperz = {}; }
30if (typeof(Clipperz.PM) == 'undefined') { Clipperz.PM = {}; }
31if (typeof(Clipperz.PM.Components) == 'undefined') { Clipperz.PM.Components = {}; }
32
33Clipperz.PM.Components.TextFormField = function(anElement, args) {
34 args = args || {};
35
36//MochiKit.Logging.logDebug(">>> new TextFormField");
37 Clipperz.PM.Components.TextFormField.superclass.constructor.call(this, args);
38
39 this._element = anElement;
40 this._editMode = args.editMode || 'VIEW';
41 this._value = args.value || "";
42 this._inputElement = null;
43 this._wrapper = null;
44 this._multiline = args.multiline || false;
45
46 //this.multiline = args.multiline || true;
47 //this.editing = true;
48 //this.completeOnBlur = true;
49 //this.autoSizeTask = new YAHOO.ext.util.DelayedTask(this.autoSize, this);
50 //this.textSizeEl = Clipperz.YUI.DomHelper.append(document.body, {
51 // tag: 'div',
52 // cls: 'yinline-editor-sizer ' + (this.cls || '')
53 //});
54
55 this.render();
56//MochiKit.Logging.logDebug("<<< new TextFormField");
57
58 return this;
59};
60
61YAHOO.extendX(Clipperz.PM.Components.TextFormField, Clipperz.PM.Components.BaseComponent, {
62
63 'toString': function() {
64 return "Clipperz.PM.Components.TextFormField";
65 },
66
67 //-----------------------------------------------------
68
69 'value': function() {
70 if (this.inputElement() != null) {
71 this._value = this.inputElement().dom.value;
72 }
73
74 return this._value;
75 // return this.inlineEditor().getValue();
76 },
77
78 'setValue': function(aValue) {
79 this._value = aValue;
80 // this.getElement('viewComponent_Content').update(aValue);
81 // this.inlineEditor().setValue(aValue);
82 },
83
84 //-----------------------------------------------------
85
86 'multiline': function() {
87 return this._multiline;
88 },
89
90 //-----------------------------------------------------
91
92 'editMode': function() {
93 return this._editMode;
94 },
95
96 'setEditMode': function(aValue) {
97 this._editMode = aValue;
98 },
99
100 //-----------------------------------------------------
101
102 'inputElement': function() {
103 return this._inputElement;
104 },
105
106 'setInputElement': function(aValue) {
107 this._inputElement = aValue;
108 },
109
110 //-----------------------------------------------------
111
112 'on': function(anEventName, anHandler, aScope, shouldOverride) {
113//MochiKit.Logging.logDebug(">>> TextFormField.on - inputElement: " + this.inputElement());
114 return this.inputElement().on(anEventName, anHandler, aScope, shouldOverride);
115//MochiKit.Logging.logDebug("<<< TextFormField.on - inputElement: " + this.inputElement());
116 },
117
118 //-----------------------------------------------------
119
120 'wrapper': function() {
121 return this._wrapper;
122 },
123
124 //-----------------------------------------------------
125
126 'render': function() {
127 var editModeConfiguration;
128 var viewModeConfiguration;
129
130 editModeConfiguration = {tag:'div', id:this.getId('editComponent'), children:[]};
131 if (this.multiline() == false) {
132 editModeConfiguration.children.push({tag:'input', type:'text', id:this.getId('editComponent_input'), value:"this.value(1)"});
133 } else {
134 editModeConfiguration.children.push({tag:'textarea', id:this.getId('editComponent_input'), html:"this.value(2)"});
135 }
136
137 viewModeConfiguration = {tag:'div', id:this.getId('viewComponent'), /*style:'border: 1px solid blue;',*/ children:[
138 {tag:'span', id:this.getId('viewComponent_Content'), html:this.value()}
139 ]}
140
141//MochiKit.Logging.logDebug(">>> TextFormField.render");
142 this._wrapper = Clipperz.YUI.DomHelper.append(this.element().dom, {tag:'div', id:this.getId('wrapper'), children:[
143 {tag:'div', id:this.getId('editModeBox'), children:[editModeConfiguration]},
144 {tag:'div', id:this.getId('viewModeBox'), children:[viewModeConfiguration]}
145 ]}, true);
146
147 this.getElement('editModeBox').setVisibilityMode(YAHOO.ext.Element.DISPLAY);
148 this.getElement('viewModeBox').setVisibilityMode(YAHOO.ext.Element.DISPLAY);
149
150 this.getElement('editComponent_input').dom.value = this.value();
151 this.setInputElement(this.getElement('editComponent_input'));
152
153 this.update();
154//MochiKit.Logging.logDebug("<<< TextFormField.render");
155 },
156
157 //-----------------------------------------------------
158
159 'update': function(args) {
160 args = args || {};
161
162//MochiKit.Logging.logDebug(">>> TextFormField.update");
163 if (typeof(args.value) != 'undefined') {
164 this.setValue(args.value);
165 }
166 if (typeof(args.editMode) != 'undefined') {
167 this.setEditMode(args.editMode)
168 }
169
170 if (this.editMode() == 'VIEW') {
171 this.updateViewMode();
172 } else if (this.editMode() == 'EDIT') {
173 this.updateEditMode();
174 } else {
175 //?????
176 }
177//MochiKit.Logging.logDebug("<<< TextFormField.update");
178 },
179
180 //-----------------------------------------------------
181
182 'updateEditMode': function() {
183//MochiKit.Logging.logDebug(">>> TextFormField.updateEditMode");
184 this.getElement('viewModeBox').hide();
185 this.getElement('editModeBox').show();
186
187 if (this.multiline() == false) {
188 this.getElement('editComponent_input').dom.value = this.value();
189 } else {
190 this.getElement('editComponent_input').update(Clipperz.Base.sanitizeString(this.value()));
191 }
192//MochiKit.Logging.logDebug("<<< TextFormField.updateEditMode");
193 },
194
195 //-----------------------------------------------------
196
197 'updateViewMode': function() {
198//MochiKit.Logging.logDebug(">>> TextFormField.updateViewMode");
199 this.getElement('editModeBox').hide();
200 this.getElement('viewModeBox').show();
201
202 this.getElement('viewComponent_Content').update(Clipperz.Base.sanitizeString(this.value()));
203//MochiKit.Logging.logDebug("<<< TextFormField.updateViewMode");
204 },
205
206 //#####################################################
207 //#####################################################
208 //#####################################################
209 //#####################################################
210 /*
211 'onEnter': function(k, e) {
212MochiKit.Logging.logDebug(">>> TextFormField.onEnter");
213 if (this.multiline && (e.ctrlKey || e.shiftKey)) {
214 return;
215 } else {
216 this.completeEdit();
217 e.stopEvent();
218 }
219MochiKit.Logging.logDebug("<<< TextFormField.onEnter");
220 },
221
222 //-----------------------------------------------------
223
224 'onEsc': function() {
225MochiKit.Logging.logDebug(">>> TextFormField.onEsc");
226 // if (this.ignoreNoChange) {
227 // this.revert(true);
228 // } else {
229 this.revert(false);
230 this.completeEdit();
231 // }
232MochiKit.Logging.logDebug("<<< TextFormField.onEsc");
233 },
234
235 //-----------------------------------------------------
236
237 onBlur : function(){
238MochiKit.Logging.logDebug(">>> TextFormField.onBlur");
239 if (this.editing && this.completeOnBlur !== false) {
240 this.completeEdit();
241 }
242MochiKit.Logging.logDebug("<<< TextFormField.onBlur");
243 },
244
245 //-----------------------------------------------------
246
247 'onKeyUp': function(e) {
248 var k = e.getKey();
249 if (this.editing && (k < 33 || k > 40) && k != 27) {
250 this.autoSizeTask.delay(50);
251 }
252 },
253
254 //-----------------------------------------------------
255
256 'autoSize': function() {
257 var el = this.inputElement();
258 var wrap = this.getElement('editComponent');
259 var v = el.dom.value;
260 var ts = this.textSizeEl;
261
262 if (v.length < 1) {
263 ts.innerHTML = "&#160;&#160;";
264 } else {
265 v = v.replace(/[<> ]/g, '&#160;');
266 if (this.multiline) {
267 v = v.replace(/\n/g, '<br />&#160;');
268 }
269 ts.innerHTML = v;
270 }
271
272 var ww = wrap.dom.offsetWidth;
273 var wh = wrap.dom.offsetHeight;
274 var w = ts.offsetWidth;
275 var h = ts.offsetHeight;
276 // lots of magic numbers in this block - wtf?
277 // the logic is to prevent the scrollbars from flashing
278 // in firefox. Updates the right element first
279 // so there's never overflow.
280 if (ww > w+4) {
281 el.setWidth(w+4);
282 wrap.setWidth(w+8);
283 } else {
284 wrap.setWidth(w+8);
285 el.setWidth(w+4);
286 }
287 if (wh > h+4) {
288 el.setHeight(h);
289 wrap.setHeight(h+4);
290 } else {
291 wrap.setHeight(h+4);
292 el.setHeight(h);
293 }
294 },
295
296 //-----------------------------------------------------
297
298 'completeEdit': function() {
299MochiKit.Logging.logDebug(">>> TextFormField.completeEdit");
300
301 },
302
303 'revert': function() {
304MochiKit.Logging.logDebug(">>> TextFormField.revert");
305
306 },
307 */
308 //-----------------------------------------------------
309 __syntaxFix__: '__syntaxFix__'
310});
diff --git a/frontend/beta/js/Clipperz/PM/Connection.js b/frontend/beta/js/Clipperz/PM/Connection.js
new file mode 100644
index 0000000..cf37ccc
--- a/dev/null
+++ b/frontend/beta/js/Clipperz/PM/Connection.js
@@ -0,0 +1,584 @@
1/*
2
3Copyright 2008-2011 Clipperz Srl
4
5This file is part of Clipperz's Javascript Crypto Library.
6Javascript Crypto Library provides web developers with an extensive
7and efficient set of cryptographic functions. The library aims to
8obtain maximum execution speed while preserving modularity and
9reusability.
10For further information about its features and functionalities please
11refer to http://www.clipperz.com
12
13* Javascript Crypto Library is free software: you can redistribute
14 it and/or modify it under the terms of the GNU Affero General Public
15 License as published by the Free Software Foundation, either version
16 3 of the License, or (at your option) any later version.
17
18* Javascript Crypto Library is distributed in the hope that it will
19 be useful, but WITHOUT ANY WARRANTY; without even the implied
20 warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
21 See the GNU Affero General Public License for more details.
22
23* You should have received a copy of the GNU Affero General Public
24 License along with Javascript Crypto Library. If not, see
25 <http://www.gnu.org/licenses/>.
26
27*/
28
29if (typeof(Clipperz) == 'undefined') { Clipperz = {}; }
30if (typeof(Clipperz.PM) == 'undefined') { Clipperz.PM = {}; }
31
32//-----------------------------------------------------------------------------
33//
34 // Abstract C O N N E C T I O N class
35//
36//-----------------------------------------------------------------------------
37
38Clipperz.PM.Connection = function (args) {
39 args = args || {};
40
41 this._user = args.user;
42 this._clipperz_pm_crypto_version = null;
43 this._connectionId = null;
44 this._oneTimePassword = null;
45
46 return this;
47}
48
49Clipperz.PM.Connection.prototype = MochiKit.Base.update(null, {
50
51 'user': function() {
52 return this._user;
53 },
54
55 'toString': function() {
56 return "Connection [" + this.version() + "] - user: " + this.user();
57 },
58
59 //=========================================================================
60
61 'version': function() {
62 throw Clipperz.Base.exception.AbstractMethod;
63 },
64
65 'clipperz_pm_crypto_version': function() {
66 if (this._clipperz_pm_crypto_version == null) {
67 var connectionVersions;
68 varversions;
69 varversion;
70 var i, c;
71
72 version = null;
73 connectionVersions = Clipperz.PM.Crypto.communicationProtocol.versions;
74 versions = MochiKit.Base.keys(connectionVersions);
75 c = versions.length;
76 for (i=0; i<c; i++) {
77 if (! (versions[i] == 'current')) {
78 if (this instanceof connectionVersions[versions[i]]) {
79 version = versions[i];
80 };
81 }
82 }
83
84 this._clipperz_pm_crypto_version = version;
85 }
86
87 return this._clipperz_pm_crypto_version;
88 },
89
90 //-------------------------------------------------------------------------
91
92 'defaultErrorHandler': function(anErrorString, anException) {
93MochiKit.Logging.logError("### Connection.defaultErrorHandler: " + anErrorString + " (" + anException + ")");
94 },
95
96 //-------------------------------------------------------------------------
97
98 'login': function(someArguments, aCallback) {
99 throw Clipperz.Base.exception.AbstractMethod;
100 },
101
102 //-------------------------------------------------------------------------
103
104 'message': function(someArguments, aCallback) {
105 throw Clipperz.Base.exception.AbstractMethod;
106 },
107
108 //-------------------------------------------------------------------------
109
110 'sharedSecret': function() {
111 throw Clipperz.Base.exception.AbstractMethod;
112 },
113
114 'serverSideUserCredentials': function() {
115 throw Clipperz.Base.exception.AbstractMethod;
116 },
117
118 //=========================================================================
119
120 'connectionId': function() {
121 return this._connectionId;
122 },
123
124 'setConnectionId': function(aValue) {
125 this._connectionId = aValue;
126 },
127
128 //=========================================================================
129
130 'oneTimePassword': function() {
131 return this._oneTimePassword;
132 },
133
134 'setOneTimePassword': function(aValue) {
135 this._oneTimePassword = aValue;
136 },
137
138 //=========================================================================
139 __syntaxFix__: "syntax fix"
140
141}
142);
143
144
145if (typeof(Clipperz.PM.Connection.SRP) == 'undefined') { Clipperz.PM.Connection.SRP = {}; }
146//-----------------------------------------------------------------------------
147//
148 // S R P [ 1 . 0 ] C O N N E C T I O N class
149//
150//-----------------------------------------------------------------------------
151
152Clipperz.PM.Connection.SRP['1.0'] = function (args) {
153 args = args || {};
154 Clipperz.PM.Connection.call(this, args);
155
156 this._C = null;
157 this._P = null;
158 this._srpConnection = null;
159
160 return this;
161}
162
163Clipperz.PM.Connection.SRP['1.0'].prototype = MochiKit.Base.update(new Clipperz.PM.Connection(), {
164
165 'version': function() {
166 return '1.0';
167 },
168
169 //=========================================================================
170
171 'register': function(anInvitationCode) {
172 var deferredResult;
173 varparameters;
174
175//MochiKit.Logging.logError(">>> Connection.register: " + this);
176 parameters = {};
177 deferredResult = new MochiKit.Async.Deferred();
178//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("Connection.register - 1: " + res); return res;});
179 deferredResult.addCallback(Clipperz.NotificationCenter.deferredNotification, this, 'updatedProgressState', 'registration_verify');
180//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("Connection.register - 2: " + res); return res;});
181 deferredResult.addCallback(function(aConnection, anInvitationCode) {
182 var args;
183
184 args = {};
185 args.message = 'register';
186 args.version = aConnection.clipperz_pm_crypto_version();
187 args.invitationCode = anInvitationCode;
188
189 return args;
190 }, this);
191//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("Connection.register - 3: " + res); return res;});
192 deferredResult.addCallback(Clipperz.NotificationCenter.deferredNotification, this, 'updatedProgressState', 'registration_sendingCredentials');
193//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("Connection.register - 4: " + res); return res;});
194 deferredResult.addCallback(MochiKit.Base.method(this.user(), 'encryptedData'));
195//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("Connection.register - 5: " + res); return res;});
196 deferredResult.addCallback(function(someParameters, anUser, anEncryptedData) {
197 var currentVersionConnection;
198 var args;
199
200 currentVersionConnection = new Clipperz.PM.Crypto.communicationProtocol.versions['current']({user:anUser});
201
202 args = someParameters
203 args.credentials = currentVersionConnection.serverSideUserCredentials();
204 args.user = anEncryptedData;
205 args.version = args.credentials.version;
206 args.message = "completeRegistration";
207
208 return args;
209 }, parameters, this.user());
210//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("Connection.register - 6: " + res); return res;});
211 deferredResult.addCallback(MochiKit.Base.method(Clipperz.PM.Proxy.defaultProxy, 'registration'));
212//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("Connection.register - 7: " + Clipperz.Base.serializeJSON(res)); return res;});
213 deferredResult.addCallback(MochiKit.Base.bind(function(res) {
214 this.user().setLock(res['lock']);
215
216 return res;
217 }, this));
218 deferredResult.callback(anInvitationCode);
219//MochiKit.Logging.logError("<<< Connection.register");
220
221 return deferredResult;
222 },
223
224 //=========================================================================
225
226 'login': function(isReconnecting) {
227 vardeferredResult;
228
229//MochiKit.Logging.logDebug(">>> Connection.login: "/* + this*/);
230//MochiKit.Logging.logDebug("--- Connection.login - isReconnecting: " + (isReconnecting == true));
231 deferredResult = new MochiKit.Async.Deferred();
232//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("1.3.1 - Connection.login - 1: "/* + res*/); return res;});
233//deferredResult.addErrback(function(res) {MochiKit.Logging.logDebug("ERROR: " + res); return res;});
234 deferredResult.addCallback(Clipperz.NotificationCenter.deferredNotification, this, 'updatedProgressState', 'connection_sendingCredentials');
235//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("1.3.2 - Connection.login - 2: "/* + res*/); return res;});
236//deferredResult.addErrback(function(res) {MochiKit.Logging.logDebug("ERROR: " + res); return res;});
237 deferredResult.addCallback(function(aConnection) {
238 var args;
239
240 args = {};
241 args.message = 'connect';
242 args.version = aConnection.clipperz_pm_crypto_version();
243 args.parameters = {};
244//MochiKit.Logging.logDebug("=== Connection.login - username: " + aConnection.srpConnection().C());
245 args.parameters['C'] = aConnection.srpConnection().C();
246 args.parameters['A'] = aConnection.srpConnection().A().asString(16);
247
248 if (isReconnecting == true) {
249//MochiKit.Logging.logDebug("--- Connection.login - reconnecting");
250 //# args.parameters['reconnecting'] = "yes";
251 args.parameters['reconnecting'] = aConnection.connectionId();
252 }
253//MochiKit.Logging.logDebug("--- Connection.login - args: " + Clipperz.Base.serializeJSON(args));
254//MochiKit.Logging.logDebug("--- Connection.login - srp.a: " + aConnection.srpConnection().a().asString(16));
255
256 return args;
257 });
258//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("1.3.3 - Connection.login - 3: "/* + res*/); return res;});
259//deferredResult.addErrback(function(res) {MochiKit.Logging.logDebug("ERROR: " + res); return res;});
260 deferredResult.addCallback(MochiKit.Base.method(Clipperz.PM.Proxy.defaultProxy, 'handshake'));
261//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("1.3.4 - Connection.login - 4: "/* + res*/); return res;});
262//deferredResult.addErrback(function(res) {MochiKit.Logging.logDebug("ERROR: " + res); return res;});
263 deferredResult.addCallback(Clipperz.NotificationCenter.deferredNotification, this, 'updatedProgressState', 'connection_credentialVerification');
264//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("1.3.5 - Connection.login - 5: "/* + res*/); return res;});
265//deferredResult.addErrback(function(res) {MochiKit.Logging.logDebug("ERROR: " + res); return res;});
266deferredResult.addErrback(MochiKit.Base.bind(function(res) {MochiKit.Logging.logDebug("ERROR - c: " + this.srpConnection().C() + " # version: " + this.clipperz_pm_crypto_version()); return res;}, this));
267 deferredResult.addCallback(MochiKit.Base.bind(function(someParameters) {
268 var args;
269
270 this.srpConnection().set_s(new Clipperz.Crypto.BigInt(someParameters['s'], 16));
271 this.srpConnection().set_B(new Clipperz.Crypto.BigInt(someParameters['B'], 16));
272
273 if (typeof(someParameters['oneTimePassword']) != 'undefined') {
274 this.setOneTimePassword(someParameters['oneTimePassword']);
275 }
276
277 args = {};
278 args.message = 'credentialCheck';
279 args.version = this.clipperz_pm_crypto_version();
280 args.parameters = {};
281 args.parameters['M1'] = this.srpConnection().M1();
282
283 return args;
284 }, this));
285//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("1.3.6 - Connection.login - 6: "/* + res*/); return res;});
286//deferredResult.addErrback(function(res) {MochiKit.Logging.logDebug("ERROR: " + res); return res;});
287 deferredResult.addCallback(MochiKit.Base.method(Clipperz.PM.Proxy.defaultProxy, 'handshake'));
288//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("1.3.7 - Connection.login - 7: "/* + res*/); return res;});
289//deferredResult.addErrback(function(res) {MochiKit.Logging.logDebug("ERROR: " + res); return res;});
290 //# deferredResult.addCallback(MochiKit.Base.method(this, 'loginDone'));
291 deferredResult.addCallback(MochiKit.Base.bind(function(someParameters) {
292 var result;
293
294//MochiKit.Logging.logDebug(">>> Connection.loginDone: " + this + " (M2: " + this.srpConnection().M2() + ")");
295 if (someParameters['M2'] == this.srpConnection().M2()) {
296 result = new MochiKit.Async.Deferred();
297
298//MochiKit.Logging.logDebug("--- Connection.loginDone - someParameters: " + Clipperz.Base.serializeJSON(someParameters));
299 this.setConnectionId(someParameters['connectionId']);
300 this.user().setLoginInfo(someParameters['loginInfo']);
301 this.user().setShouldDownloadOfflineCopy(someParameters['offlineCopyNeeded']);
302 this.user().setLock(someParameters['lock']);
303
304 if (this.oneTimePassword() != null) {
305 result.addCallback(MochiKit.Base.method(this.user().oneTimePasswordManager(), 'archiveOneTimePassword', this.oneTimePassword()));
306 }
307 result.addCallback(Clipperz.NotificationCenter.deferredNotification, this, 'updatedProgressState', 'connection_loggedIn');
308 result.addCallback(MochiKit.Async.succeed, someParameters);
309
310 result.callback();
311//MochiKit.Logging.logDebug("--- Connection.loginDone - 1 - result: "/* + Clipperz.Base.serializeJSON(result)*/);
312 } else {
313//MochiKit.Logging.logDebug("--- Connection.loginDone - 2 - ERROR");
314//deferredResult.addErrback(function(res) {MochiKit.Logging.logDebug("ERROR: " + res); return res;});
315 result = MochiKit.Async.fail(Clipperz.PM.Connection.exception.WrongChecksum);
316 }
317//MochiKit.Logging.logDebug("<<< Connection.loginDone - result: " + Clipperz.Base.serializeJSON(result));
318
319 return result;
320 }, this));
321
322//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("1.3.8 - Connection.login - 8: "/* + res*/); return res;});
323//deferredResult.addErrback(function(res) {MochiKit.Logging.logDebug("ERROR: " + res); return res;});
324 deferredResult.callback(this);
325//MochiKit.Logging.logDebug("<<< Connection.login");
326
327 return deferredResult;
328 },
329
330 //=========================================================================
331
332 'logout': function() {
333 var deferredResult;
334
335//MochiKit.Logging.logDebug(">>> Connection.logout: " + this);
336 deferredResult = new MochiKit.Async.Deferred();
337//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("Connection.logout - 1: " + res); return res;});
338 deferredResult.addCallback(MochiKit.Base.method(Clipperz.PM.Proxy.defaultProxy, 'logout'), {});
339//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("Connection.logout - 2: " + res); return res;});
340 deferredResult.addCallback(MochiKit.Base.method(this, 'resetSrpConnection'));
341//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("Connection.logout - 3: " + res); return res;});
342 deferredResult.callback();
343//MochiKit.Logging.logDebug("<<< Connection.logout");
344
345 return deferredResult;
346 },
347
348 //=========================================================================
349
350 'message': function(aMessageName, someParameters) {
351 var args;
352 var deferredResult;
353
354//MochiKit.Logging.logDebug(">>> Connection.message: " + this);
355 args = {}
356 args['message'] = aMessageName;
357 args['srpSharedSecret'] = this.srpConnection().K();
358 // args['lock'] = this.user().lock();
359
360 if (someParameters != null) {
361 args['parameters'] = someParameters;
362 } else {
363 args['parameters'] = {};
364 }
365//MochiKit.Logging.logDebug("--- Connection.message - args: " + Clipperz.Base.serializeJSON(args));
366
367 // deferredResult = new MochiKit.Async.Deferred(); //### ?????????????
368
369 return this.sendMessage(args);
370 },
371
372 //-------------------------------------------------------------------------
373
374 'sendMessage': function(someArguments) {
375 vardeferredResult;
376
377//MochiKit.Logging.logDebug(">>> Connection.sendMessage: " + this);
378 deferredResult = new MochiKit.Async.Deferred();
379//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("Connection.sendMessage - 1: " + res); return res;});
380 deferredResult.addCallback(MochiKit.Base.method(Clipperz.PM.Proxy.defaultProxy, 'message'), someArguments);
381//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("Connection.sendMessage - 2: " + res); return res;});
382
383 deferredResult.addCallback(MochiKit.Base.bind(function(res) {
384 if (typeof(res['lock']) != 'undefined') {
385 this.user().setLock(res['lock']);
386 }
387 return res;
388 }, this));
389
390 deferredResult.addErrback(MochiKit.Base.method(this, 'messageExceptionHandler'), someArguments);
391//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("Connection.sendMessage - 3: " + res); return res;});
392//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("Connection.sendMessage - 3: " + Clipperz.Base.serializeJSON(res)); return res;});
393 deferredResult.callback();
394//MochiKit.Logging.logDebug("<<< Connection.sendMessage");
395
396 return deferredResult
397 },
398
399 //-------------------------------------------------------------------------
400
401 'messageExceptionHandler': function(anOriginalMessageArguments, anError) {
402 var result;
403
404//MochiKit.Logging.logDebug(">>> Connection.messageExceptionHandler - this: " + this + ", anError: " + anError);
405 if (anError instanceof MochiKit.Async.CancelledError) {
406//MochiKit.Logging.logDebug("--- Connection.messageExceptionHandler - 1");
407 result = anError;
408//MochiKit.Logging.logDebug("--- Connection.messageExceptionHandler - 2");
409 } else {
410//MochiKit.Logging.logDebug("--- Connection.messageExceptionHandler - 3 - anError.name: " + anError.name + ", message: " + anError.message);
411 if ((anError.message == 'Trying to communicate without an active connection')||
412 (anError.message == 'No tollManager available for current session')
413 ) {
414//MochiKit.Logging.logDebug("--- Connection.messageExceptionHandler - 4");
415 result = this.reestablishConnection(anOriginalMessageArguments);
416//MochiKit.Logging.logDebug("--- Connection.messageExceptionHandler - 5");
417 } else if (anError.message == 'Session with stale data') {
418//MochiKit.Logging.logDebug("--- Connection.messageExceptionHandler - 5.1");
419 Clipperz.NotificationCenter.notify(this, 'EXCEPTION');
420//MochiKit.Logging.logDebug("--- Connection.messageExceptionHandler - 5.2");
421 } else {
422//MochiKit.Logging.logDebug("--- Connection.messageExceptionHandler - 6");
423 result = anError;
424//MochiKit.Logging.logDebug("--- Connection.messageExceptionHandler - 7");
425 }
426//MochiKit.Logging.logDebug("--- Connection.messageExceptionHandler - 8");
427 }
428//MochiKit.Logging.logDebug("<<< Connection.messageExceptionHandler");
429
430 return result;;
431 },
432
433 //=========================================================================
434
435 'reestablishConnection': function(anOriginalMessageArguments) {
436 var deferredResult;
437
438//MochiKit.Logging.logDebug("+++ Connection.reestablishConnection: " + Clipperz.Base.serializeJSON(anOriginalMessageArguments));
439
440//MochiKit.Logging.logDebug(">>> Connection.reestablishConnection: " + this);
441 deferredResult = new MochiKit.Async.Deferred();
442//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("Connection.reestablishConnection 1: " + res); return res;});
443 deferredResult.addCallback(MochiKit.Base.method(this, 'resetSrpConnection'));
444//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("Connection.reestablishConnection 2: " + res); return res;});
445 deferredResult.addCallback(MochiKit.Base.method(this, 'login'), true);
446//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("Connection.reestablishConnection 3: " + res); return res;});
447 deferredResult.addCallback(MochiKit.Base.bind(function(aMessage) {
448 aMessage['srpSharedSecret'] = this.srpConnection().K();
449 return aMessage;
450 }, this), anOriginalMessageArguments);
451//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("Connection.reestablishConnection 4: " + Clipperz.Base.serializeJSON(res)); return res;});
452 deferredResult.addCallback(MochiKit.Base.method(this, 'sendMessage'));
453//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("Connection.reestablishConnection 5: " + res); return res;});
454 deferredResult.addErrback(Clipperz.NotificationCenter.deferredNotification, this, 'EXCEPTION', null);
455//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("Connection.reestablishConnection 6: " + res); return res;});
456 deferredResult.callback();
457//MochiKit.Logging.logDebug("<<< Connection.reestablishConnection");
458
459 return deferredResult;
460 },
461
462 //=========================================================================
463
464 'sharedSecret': function() {
465 return this.srpConnection().K();
466 },
467
468 //=========================================================================
469
470 'serverSideUserCredentials': function() {
471 varresult;
472 varnewSrpConnection;
473
474//MochiKit.Logging.logDebug(">>> Connection.serverSideUserCredentials");
475 newSrpConnection = new Clipperz.Crypto.SRP.Connection({ C:this.C(), P:this.P(), hash:this.hash() });
476 result = newSrpConnection.serverSideCredentials();
477 result['version'] = this.clipperz_pm_crypto_version();
478
479//MochiKit.Logging.logDebug("<<< Connection.serverSideUserCredentials - result: " + Clipperz.Base.serializeJSON(result));
480 return result;
481 },
482
483 //=========================================================================
484
485 'C': function() {
486 if (this._C == null) {
487 this._C = this.hash()(new Clipperz.ByteArray(this.user().username())).toHexString().substring(2);
488 }
489
490 return this._C;
491 },
492
493 //-----------------------------------------------------------------------------
494
495 'P': function() {
496 if (this._P == null) {
497 this._P = this.hash()(new Clipperz.ByteArray(this.user().passphrase() + this.user().username())).toHexString().substring(2);
498 }
499
500 return this._P;
501 },
502
503 //-----------------------------------------------------------------------------
504
505 'hash': function() {
506 return Clipperz.PM.Crypto.encryptingFunctions.versions['0.1'].hash;
507 },
508
509 //-----------------------------------------------------------------------------
510
511 'srpConnection': function() {
512 if (this._srpConnection == null) {
513 this._srpConnection = new Clipperz.Crypto.SRP.Connection({ C:this.C(), P:this.P(), hash:this.hash() });
514 }
515
516 return this._srpConnection;
517 },
518
519 'resetSrpConnection': function() {
520 this._C = null;
521 this._P = null;
522 this._srpConnection = null;
523 },
524
525 //-----------------------------------------------------------------------------
526 __syntaxFix__: "syntax fix"
527
528});
529
530
531
532//-----------------------------------------------------------------------------
533//
534 // S R P [ 1 . 1 ] C O N N E C T I O N class
535//
536//-----------------------------------------------------------------------------
537
538Clipperz.PM.Connection.SRP['1.1'] = function (args) {
539 args = args || {};
540 Clipperz.PM.Connection.SRP['1.0'].call(this, args);
541
542 return this;
543}
544
545Clipperz.PM.Connection.SRP['1.1'].prototype = MochiKit.Base.update(new Clipperz.PM.Connection.SRP['1.0'](), {
546
547 'version': function() {
548 return '1.1';
549 },
550
551 //-----------------------------------------------------------------------------
552
553 'C': function() {
554 if (this._C == null) {
555 this._C = this.hash()(new Clipperz.ByteArray(this.user().username() + this.user().passphrase())).toHexString().substring(2);
556 }
557
558 return this._C;
559 },
560
561 //-----------------------------------------------------------------------------
562
563 'P': function() {
564 if (this._P == null) {
565 this._P = this.hash()(new Clipperz.ByteArray(this.user().passphrase() + this.user().username())).toHexString().substring(2);
566 }
567
568 return this._P;
569 },
570
571 //-----------------------------------------------------------------------------
572
573 'hash': function() {
574 return Clipperz.PM.Crypto.encryptingFunctions.versions['0.2'].hash;
575 },
576
577 //-----------------------------------------------------------------------------
578 __syntaxFix__: "syntax fix"
579
580});
581
582Clipperz.PM.Connection.exception = {
583 WrongChecksum: new MochiKit.Base.NamedError("Clipperz.ByteArray.exception.InvalidValue")
584};
diff --git a/frontend/beta/js/Clipperz/PM/Crypto.js b/frontend/beta/js/Clipperz/PM/Crypto.js
new file mode 100644
index 0000000..7636822
--- a/dev/null
+++ b/frontend/beta/js/Clipperz/PM/Crypto.js
@@ -0,0 +1,503 @@
1/*
2
3Copyright 2008-2011 Clipperz Srl
4
5This file is part of Clipperz's Javascript Crypto Library.
6Javascript Crypto Library provides web developers with an extensive
7and efficient set of cryptographic functions. The library aims to
8obtain maximum execution speed while preserving modularity and
9reusability.
10For further information about its features and functionalities please
11refer to http://www.clipperz.com
12
13* Javascript Crypto Library is free software: you can redistribute
14 it and/or modify it under the terms of the GNU Affero General Public
15 License as published by the Free Software Foundation, either version
16 3 of the License, or (at your option) any later version.
17
18* Javascript Crypto Library is distributed in the hope that it will
19 be useful, but WITHOUT ANY WARRANTY; without even the implied
20 warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
21 See the GNU Affero General Public License for more details.
22
23* You should have received a copy of the GNU Affero General Public
24 License along with Javascript Crypto Library. If not, see
25 <http://www.gnu.org/licenses/>.
26
27*/
28
29if (typeof(Clipperz) == 'undefined') { Clipperz = {}; }
30if (typeof(Clipperz.PM) == 'undefined') { Clipperz.PM = {}; }
31if (typeof(Clipperz.PM.Crypto) == 'undefined') { Clipperz.PM.Crypto = {}; }
32
33Clipperz.PM.Crypto.VERSION = "0.2";
34Clipperz.PM.Crypto.NAME = "Clipperz.PM.Crypto";
35
36MochiKit.Base.update(Clipperz.PM.Crypto, {
37
38 '__repr__': function () {
39 return "[" + this.NAME + " " + this.VERSION + "]";
40 },
41
42 //-------------------------------------------------------------------------
43
44 'toString': function () {
45 return this.__repr__();
46 },
47
48 //-------------------------------------------------------------------------
49
50 'communicationProtocol': {
51 'currentVersion': '0.2',
52 'versions': {
53 '0.1': Clipperz.PM.Connection.SRP['1.0'],//Clipperz.Crypto.SRP.versions['1.0'].Connection,
54 '0.2': Clipperz.PM.Connection.SRP['1.1']//Clipperz.Crypto.SRP.versions['1.1'].Connection,
55 },
56 'fallbackVersions': {
57 'current':'0.1',
58 '0.2': '0.1',
59 '0.1': null
60 }
61 },
62
63 //-------------------------------------------------------------------------
64
65 'encryptingFunctions': {
66 'currentVersion': '0.3',
67 'versions': {
68
69 //#####################################################################
70
71 '0.1': {
72 'encrypt': function(aKey, aValue) {
73 return Clipperz.Crypto.Base.encryptUsingSecretKey(aKey, Clipperz.Base.serializeJSON(aValue));
74 },
75
76 'deferredEncrypt': function(aKey, aValue) {
77 var deferredResult;
78
79 deferredResult = new MochiKit.Async.Deferred();
80 deferredResult.addCallback(Clipperz.PM.Crypto.encryptingFunctions.versions['0.1'].encrypt, aKey, aValue);
81 deferredResult.callback();
82
83 return deferredResult;
84 },
85
86 'decrypt': function(aKey, aValue) {
87 var result;
88
89 if (aValue != null) {
90 result = Clipperz.Base.evalJSON(Clipperz.Crypto.Base.decryptUsingSecretKey(aKey, aValue));
91 } else {
92 result = null;
93 }
94
95 return result;
96 },
97
98 'deferredDecrypt': function(aKey, aValue) {
99 var deferredResult;
100
101 deferredResult = new MochiKit.Async.Deferred();
102 deferredResult.addCallback(Clipperz.PM.Crypto.encryptingFunctions.versions['0.1'].decrypt, aKey, aValue);
103 deferredResult.callback();
104
105 return deferredResult;
106 },
107
108 'hash': function(aValue) {
109 var result;
110 var strngResult;
111
112 stringResult = Clipperz.Crypto.Base.computeHashValue(aValue.asString()); //!!!!!!!
113 result = new Clipperz.ByteArray("0x" + stringResult);
114
115 return result;
116 }
117 },
118
119 //#####################################################################
120
121 '0.2': {
122 'encrypt': function(aKey, aValue, aNonce) {
123 var result;
124 varkey, value;
125 var dataToEncrypt;
126 var encryptedData;
127
128 key = Clipperz.Crypto.SHA.sha_d256(new Clipperz.ByteArray(aKey));
129 value = new Clipperz.ByteArray(Clipperz.Base.serializeJSON(aValue));
130 dataToEncrypt = Clipperz.Crypto.SHA.sha_d256(value).appendBlock(value);
131 encryptedData = Clipperz.Crypto.AES.encrypt(key, dataToEncrypt, aNonce);
132 result = encryptedData.toBase64String();
133
134 return result;
135 },
136
137 'deferredEncrypt': function(aKey, aValue, aNonce) {
138 var deferredResult;
139 varkey, value;
140 var dataToEncrypt;
141 var encryptedData;
142
143 key = Clipperz.Crypto.SHA.sha_d256(new Clipperz.ByteArray(aKey));
144 value = new Clipperz.ByteArray(Clipperz.Base.serializeJSON(aValue));
145 dataToEncrypt = Clipperz.Crypto.SHA.sha_d256(value).appendBlock(value);
146
147 deferredResult = new MochiKit.Async.Deferred()
148 deferredResult.addCallback(Clipperz.Crypto.AES.deferredEncrypt, key, dataToEncrypt, aNonce);
149 deferredResult.addCallback(function(aResult) {
150 return aResult.toBase64String();
151 })
152 deferredResult.callback();
153
154 return deferredResult;
155 },
156
157 'decrypt': function(aKey, aValue) {
158 var result;
159
160 if (aValue != null) {
161 var key, value;
162 var decryptedData;
163 var decryptedData;
164
165 key = Clipperz.Crypto.SHA.sha_d256(new Clipperz.ByteArray(aKey));
166 value = new Clipperz.ByteArray().appendBase64String(aValue);
167
168 decryptedData = Clipperz.Crypto.AES.decrypt(key, value);
169 decryptedData = decryptedData.split((256/8));
170
171 try {
172 result = Clipperz.Base.evalJSON(decryptedData.asString());
173 } catch (exception) {
174 MochiKit.Logging.logError("Error while decrypting data");
175 throw Clipperz.Crypto.Base.exception.CorruptedMessage;
176 }
177 } else {
178 result = null;
179 }
180
181 return result;
182 },
183
184 'deferredDecrypt': function(aKey, aValue) {
185 var result;
186
187 if (aValue != null) {
188 var deferredResult;
189 var key, value;
190 var decryptedData;
191
192 result = new MochiKit.Async.Deferred();
193
194 key = Clipperz.Crypto.SHA.sha_d256(new Clipperz.ByteArray(aKey));
195 value = new Clipperz.ByteArray().appendBase64String(aValue);
196
197
198 deferredResult = new MochiKit.Async.Deferred()
199 deferredResult.addCallback(Clipperz.Crypto.AES.deferredDecrypt, key, value);
200 deferredResult.addCallback(function(aResult) {
201 var result;
202 var decryptedData;
203
204 decryptedData = aResult.split((256/8));
205
206 try {
207 result = Clipperz.Base.evalJSON(decryptedData.asString());
208 } catch (exception) {
209 MochiKit.Logging.logError("Error while decrypting data");
210 throw Clipperz.Crypto.Base.exception.CorruptedMessage;
211 }
212
213 return result;
214 })
215 deferredResult.callback();
216
217 result = deferredResult;
218 } else {
219 result = MochiKit.Async.succeed(null);
220 }
221
222 return result;
223 },
224
225 'hash': Clipperz.Crypto.SHA.sha_d256
226 },
227
228 //#####################################################################
229
230 '0.3': {
231 'encrypt': function(aKey, aValue, aNonce) {
232 var result;
233 varkey, value;
234 var data;
235 var dataToEncrypt;
236 var encryptedData;
237
238 key = Clipperz.Crypto.SHA.sha_d256(new Clipperz.ByteArray(aKey));
239 value = Clipperz.Base.serializeJSON(aValue);
240 data = new Clipperz.ByteArray(value);
241 encryptedData = Clipperz.Crypto.AES.encrypt(key, data, aNonce);
242 result = encryptedData.toBase64String();
243
244 return result;
245 },
246
247 'deferredEncrypt': function(aKey, aValue, aNonce) {
248 var deferredResult;
249 varkey, value;
250 var data;
251 var dataToEncrypt;
252 var encryptedData;
253
254 key = Clipperz.Crypto.SHA.sha_d256(new Clipperz.ByteArray(aKey));
255 value = Clipperz.Base.serializeJSON(aValue);
256 data = new Clipperz.ByteArray(value);
257
258 deferredResult = new MochiKit.Async.Deferred()
259//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("Clipperz.PM.Crypto.deferredEncrypt - 1: " + res); return res;});
260 deferredResult.addCallback(Clipperz.Crypto.AES.deferredEncrypt, key, data, aNonce);
261//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("Clipperz.PM.Crypto.deferredEncrypt - 2: " + res); return res;});
262 deferredResult.addCallback(function(aResult) {
263 return aResult.toBase64String();
264 })
265//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("Clipperz.PM.Crypto.deferredEncrypt - 3: " + res); return res;});
266 deferredResult.callback();
267
268 return deferredResult;
269 },
270
271 'decrypt': function(aKey, aValue) {
272 var result;
273
274 if (aValue != null) {
275 var key, value;
276 var decryptedData;
277 var decryptedValue;
278
279 key = Clipperz.Crypto.SHA.sha_d256(new Clipperz.ByteArray(aKey));
280 value = new Clipperz.ByteArray().appendBase64String(aValue);
281
282 decryptedData = Clipperz.Crypto.AES.decrypt(key, value);
283
284 value = decryptedData.asString();
285 try {
286 result = Clipperz.Base.evalJSON(value);
287 } catch (exception) {
288 MochiKit.Logging.logError("Error while decrypting data");
289 throw Clipperz.Crypto.Base.exception.CorruptedMessage;
290 }
291 } else {
292 result = null;
293 }
294
295 return result;
296 },
297
298 'deferredDecrypt': function(aKey, aValue) {
299 var deferredResult;
300 // var now;
301
302 deferredResult = new MochiKit.Async.Deferred();
303 now = new Date;
304
305//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("[" + (new Date() - now) + "] Clipperz.PM.Crypto.deferredDecrypt - 1: " + res); return res;});
306 if (aValue != null) {
307 var key, value;
308 var decryptedData;
309 var decryptedValue;
310
311 key = Clipperz.Crypto.SHA.sha_d256(new Clipperz.ByteArray(aKey));
312//MochiKit.Logging.logDebug("[" + (new Date() - now) + "] computed key");
313 value = new Clipperz.ByteArray().appendBase64String(aValue);
314//MochiKit.Logging.logDebug("[" + (new Date() - now) + "] appendedBase64String");
315
316//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("[" + (new Date() - now) + "] Clipperz.PM.Crypto.deferredDecrypt - 1.1: " /* + res*/); return res;});
317 deferredResult.addCallback(Clipperz.Crypto.AES.deferredDecrypt, key, value);
318//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("[" + (new Date() - now) + "] Clipperz.PM.Crypto.deferredDecrypt - 2: " /* + res*/); return res;});
319 deferredResult.addCallback(MochiKit.Async.wait, 0.1);
320//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("[" + (new Date() - now) + "] Clipperz.PM.Crypto.deferredDecrypt - 3: " /* + res*/); return res;});
321 deferredResult.addCallback(function(aResult) {
322 return aResult.asString();
323 });
324//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("[" + (new Date() - now) + "] Clipperz.PM.Crypto.deferredDecrypt - 4: " /* + res*/); return res;});
325 deferredResult.addCallback(MochiKit.Async.wait, 0.1);
326//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("[" + (new Date() - now) + "] Clipperz.PM.Crypto.deferredDecrypt - 5: " /* + res*/); return res;});
327 deferredResult.addCallback(Clipperz.Base.evalJSON);
328//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("[" + (new Date() - now) + "] Clipperz.PM.Crypto.deferredDecrypt - 6: " /* + res*/); return res;});
329 deferredResult.addErrback(function(anError) {
330 MochiKit.Logging.logError("Error while decrypting data");
331 throw Clipperz.Crypto.Base.exception.CorruptedMessage;
332 })
333//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("[" + (new Date() - now) + "] Clipperz.PM.Crypto.deferredDecrypt - 7: " /* + res*/); return res;});
334 } else {
335 deferredResult.addCallback(function() {
336 return null;
337 });
338 }
339 deferredResult.callback();
340
341 return deferredResult;
342 },
343
344 'hash': Clipperz.Crypto.SHA.sha_d256
345 },
346
347 //#####################################################################
348/*
349 '0.4': {
350 'encrypt': function(aKey, aValue, aNonce) {
351 var result;
352 varkey, value;
353 var data;
354 var dataToEncrypt;
355 var encryptedData;
356
357//MochiKit.Logging.logDebug(">>> [" + (new Date()).valueOf() + "] Clipperz.PM.Crypto.versions[0.3].encrypt");
358 key = Clipperz.Crypto.SHA.sha_d256(new Clipperz.ByteArray(aKey));
359//MochiKit.Logging.logDebug("--- [" + (new Date()).valueOf() + "] Clipperz.PM.Crypto.versions[0.3].encrypt - 1");
360 value = Clipperz.Base.serializeJSON(aValue);
361//MochiKit.Logging.logDebug("--- [" + (new Date()).valueOf() + "] Clipperz.PM.Crypto.versions[0.3].encrypt - 2");
362/ *
363//MochiKit.Logging.logDebug("--> encrypt.fullSize: " + value.length);
364 value = value.replace(/":{"label":"/g, '":{l:"');
365 value = value.replace(/":{"key":"/g, '":{k:"');
366 value = value.replace(/":{"notes":"/g, '":{n:"');
367 value = value.replace(/":{"record":"/g, '":{r:"');
368 value = value.replace(/", "label":"/g, '",l:"');
369 value = value.replace(/", "favicon":"/g,'",f:"');
370//MochiKit.Logging.logDebug("<-- encrypt.compressed: " + value.length);
371* /
372 data = new Clipperz.ByteArray(value);
373//MochiKit.Logging.logDebug("--- [" + (new Date()).valueOf() + "] Clipperz.PM.Crypto.versions[0.3].encrypt - 3");
374 encryptedData = Clipperz.Crypto.AES.encrypt(key, data, aNonce);
375//MochiKit.Logging.logDebug("--- [" + (new Date()).valueOf() + "] Clipperz.PM.Crypto.versions[0.3].encrypt - 4");
376 result = encryptedData.toBase64String();
377//MochiKit.Logging.logDebug("<<< [" + (new Date()).valueOf() + "] Clipperz.PM.Crypto.versions[0.3].encrypt");
378
379 return result;
380 },
381
382 'decrypt': function(aKey, aValue) {
383 var result;
384
385 if (aValue != null) {
386 var key, value;
387 var decryptedData;
388 var decryptedValue;
389
390 key = Clipperz.Crypto.SHA.sha_d256(new Clipperz.ByteArray(aKey));
391 value = new Clipperz.ByteArray().appendBase64String(aValue);
392
393 decryptedData = Clipperz.Crypto.AES.decrypt(key, value);
394
395 value = decryptedData.asString();
396/ *
397 value = value.replace(/":{l:"/g,'":{"label":"');
398 value = value.replace(/":{k:"/g,'":{"key":"');
399 value = value.replace(/":{n:"/g,'":{"notes":"');
400 value = value.replace(/":{r:"/g,'":{"record":"');
401 value = value.replace(/",l:"/g, '", "label":"');
402 value = value.replace(/",f:"/g, '", "favicon":"');
403* /
404 try {
405 result = Clipperz.Base.evalJSON(value);
406 } catch (exception) {
407 MochiKit.Logging.logError("Error while decrypting data");
408 throw Clipperz.Crypto.Base.exception.CorruptedMessage;
409 }
410
411
412 } else {
413 result = null;
414 }
415
416 return result;
417 },
418
419 'hash': Clipperz.Crypto.SHA.sha_d256
420 },
421*/
422 //#####################################################################
423 __syntaxFix__: "syntax fix"
424 }
425 },
426
427 //-------------------------------------------------------------------------
428
429 'encrypt': function(aKey, aValue, aVersion) {
430 return Clipperz.PM.Crypto.encryptingFunctions.versions[aVersion].encrypt(aKey, aValue);
431 },
432
433 'deferredEncrypt': function(aKey, aValue, aVersion) {
434 return Clipperz.PM.Crypto.encryptingFunctions.versions[aVersion].deferredEncrypt(aKey, aValue);
435 },
436
437 'encryptWithCurrentVersion': function(aKey, aValue) {
438 return Clipperz.PM.Crypto.encrypt(aKey, aValue, Clipperz.PM.Crypto.encryptingFunctions.currentVersion);
439 },
440
441 'deferredEncryptWithCurrentVersion': function(aKey, aValue) {
442 return Clipperz.PM.Crypto.deferredEncrypt(aKey, aValue, Clipperz.PM.Crypto.encryptingFunctions.currentVersion);
443 },
444
445 //.........................................................................
446
447 'decrypt': function(aKey, aValue, aVersion) {
448 return Clipperz.PM.Crypto.encryptingFunctions.versions[aVersion].decrypt(aKey, aValue);
449 },
450
451 'deferredDecrypt': function(aKey, aValue, aVersion) {
452 return Clipperz.PM.Crypto.encryptingFunctions.versions[aVersion].deferredDecrypt(aKey, aValue);
453 },
454
455 //-------------------------------------------------------------------------
456
457 'randomKey': function() {
458 return Clipperz.Crypto.PRNG.defaultRandomGenerator().getRandomBytes(32).toHexString().substring(2);
459 },
460
461 //-------------------------------------------------------------------------
462
463 'passwordEntropy': function(aValue) {
464 var result;
465 varbitPerChar;
466
467 bitPerChar = 4;
468 if (/[a-z]/.test(aValue)) {
469 bitPerChar ++;
470 }
471 if (/[A-Z]/.test(aValue)) {
472 bitPerChar ++;
473 }
474 if (/[^a-zA-Z0-9]/.test(aValue)) {
475 bitPerChar ++;
476 }
477//MochiKit.Logging.logDebug("--- bitPerChar: " + bitPerChar);
478
479 result = aValue.length * bitPerChar;
480
481 return result;
482 },
483
484 //-------------------------------------------------------------------------
485
486 'nullValue': "####",
487
488 //-------------------------------------------------------------------------
489 __syntaxFix__: "syntax fix"
490
491});
492
493//*****************************************************************************
494
495MochiKit.Base.update(Clipperz.PM.Crypto.communicationProtocol.versions, {
496 'current': Clipperz.PM.Crypto.communicationProtocol.versions[Clipperz.PM.Crypto.communicationProtocol.currentVersion]
497});
498
499MochiKit.Base.update(Clipperz.PM.Crypto.encryptingFunctions.versions, {
500 'current': Clipperz.PM.Crypto.encryptingFunctions.versions[Clipperz.PM.Crypto.encryptingFunctions.currentVersion]
501});
502
503//*****************************************************************************
diff --git a/frontend/beta/js/Clipperz/PM/DataModel/DirectLogin.js b/frontend/beta/js/Clipperz/PM/DataModel/DirectLogin.js
new file mode 100644
index 0000000..3ebc208
--- a/dev/null
+++ b/frontend/beta/js/Clipperz/PM/DataModel/DirectLogin.js
@@ -0,0 +1,536 @@
1/*
2
3Copyright 2008-2011 Clipperz Srl
4
5This file is part of Clipperz's Javascript Crypto Library.
6Javascript Crypto Library provides web developers with an extensive
7and efficient set of cryptographic functions. The library aims to
8obtain maximum execution speed while preserving modularity and
9reusability.
10For further information about its features and functionalities please
11refer to http://www.clipperz.com
12
13* Javascript Crypto Library is free software: you can redistribute
14 it and/or modify it under the terms of the GNU Affero General Public
15 License as published by the Free Software Foundation, either version
16 3 of the License, or (at your option) any later version.
17
18* Javascript Crypto Library is distributed in the hope that it will
19 be useful, but WITHOUT ANY WARRANTY; without even the implied
20 warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
21 See the GNU Affero General Public License for more details.
22
23* You should have received a copy of the GNU Affero General Public
24 License along with Javascript Crypto Library. If not, see
25 <http://www.gnu.org/licenses/>.
26
27*/
28
29if (typeof(Clipperz) == 'undefined') { Clipperz = {}; }
30if (typeof(Clipperz.PM) == 'undefined') { Clipperz.PM = {}; }
31if (typeof(Clipperz.PM.DataModel) == 'undefined') { Clipperz.PM.DataModel = {}; }
32
33
34//#############################################################################
35
36Clipperz.PM.DataModel.DirectLogin = function(args) {
37//MochiKit.Logging.logDebug(">>> new Clipperz.PM.DataModel.DirectLogin");
38//console.log(">>> new Clipperz.PM.DataModel.DirectLogin - args: %o", args);
39//console.log("--- formData: %s", Clipperz.Base.serializeJSON(args.formData));
40 args = args || {};
41
42//MochiKit.Logging.logDebug("--- new Clipperz.PM.DataModel.DirectLogin - args: " + Clipperz.Base.serializeJSON(MochiKit.Base.keys(args)));
43 this._record = args.record || null;
44 this._label = args.label || "unnamed record"
45 this._reference = args.reference || Clipperz.PM.Crypto.randomKey();
46 this._favicon = args.favicon || null;
47 this._bookmarkletVersion = args.bookmarkletVersion || "0.1";
48
49 this._directLoginInputs = null;
50
51 this._formValues = args.formValues || {};
52 this.setFormData(args.formData || null);
53//console.log("=== formData: %o", this.formData());
54
55 if (args.legacyBindingData == null) {
56 this.setBindingData(args.bindingData || null);
57 } else {
58 this.setLegacyBindingData(args.legacyBindingData);
59 }
60
61 this._fixedFavicon = null;
62
63 //this._formValues = args.formValues || (this.hasValuesToSet() ? {} : null);
64//MochiKit.Logging.logDebug("<<< new Clipperz.PM.DataModel.DirectLogin");
65
66 return this;
67}
68
69Clipperz.PM.DataModel.DirectLogin.prototype = MochiKit.Base.update(null, {
70
71 'remove': function() {
72 this.record().removeDirectLogin(this);
73 },
74
75 //-------------------------------------------------------------------------
76
77 'record': function() {
78 return this._record;
79 },
80
81 //-------------------------------------------------------------------------
82
83 'user': function() {
84 return this.record().user();
85 },
86
87 //-------------------------------------------------------------------------
88
89 'reference': function() {
90 return this._reference;
91 },
92
93 //-------------------------------------------------------------------------
94
95 'label': function() {
96 return this._label;
97 },
98
99 'setLabel': function(aValue) {
100 this._label = aValue;
101 },
102
103 //-------------------------------------------------------------------------
104
105 'favicon': function() {
106 if (this._favicon == null) {
107 varactionUrl;
108 var hostname;
109
110 actionUrl = this.formData()['attributes']['action'];
111 hostname = actionUrl.replace(/^https?:\/\/([^\/]*)\/.*/, '$1');
112 this._favicon = "http://" + hostname + "/favicon.ico";
113 }
114
115 return this._favicon;
116 },
117
118 //-------------------------------------------------------------------------
119
120 'fixedFavicon': function() {
121 var result;
122
123 if (this._fixedFavicon == null) {
124 result = this.favicon();
125
126 if (Clipperz_IEisBroken) {
127 if (this.user().preferences().disableUnsecureFaviconLoadingForIE()) {
128 if (result.indexOf('https://') != 0) {
129 result = Clipperz.PM.Strings['defaultFaviconUrl_IE'];
130 this.setFixedFavicon(result);
131 }
132 }
133 }
134 } else {
135 result = this._fixedFavicon;
136 }
137
138 return result;
139 },
140
141 'setFixedFavicon': function(aValue) {
142 this._fixedFavicon = aValue;
143 },
144
145 //-------------------------------------------------------------------------
146
147 'bookmarkletVersion': function() {
148 return this._bookmarkletVersion;
149 },
150
151 'setBookmarkletVersion': function(aValue) {
152 this._bookmarkletVersion = aValue;
153 },
154
155 //-------------------------------------------------------------------------
156
157 'formData': function() {
158 return this._formData;
159 },
160
161 'setFormData': function(aValue) {
162 var formData;
163
164//MochiKit.Logging.logDebug(">>> DirectLogin.setFormData - " + Clipperz.Base.serializeJSON(aValue));
165 switch (this.bookmarkletVersion()) {
166 case "0.2":
167 formData = aValue;
168 break;
169 case "0.1":
170//MochiKit.Logging.logDebug("--- DirectLogin.setFormData - fixing form data from bookmarklet version 0.1");
171 formData = this.fixFormDataFromBookmarkletVersion_0_1(aValue);
172 break;
173 }
174
175 this._formData = aValue;
176 this.setBookmarkletVersion("0.2");
177
178//MochiKit.Logging.logDebug("--- DirectLogin.setFormData - formData: " + Clipperz.Base.serializeJSON(formData));
179 if (formData != null) {
180 var i,c;
181
182 this._directLoginInputs = [];
183 c = formData['inputs'].length;
184 for (i=0; i<c; i++) {
185 var directLoginInput;
186
187 directLoginInput = new Clipperz.PM.DataModel.DirectLoginInput(this, formData['inputs'][i]);
188 this._directLoginInputs.push(directLoginInput);
189 }
190 }
191//MochiKit.Logging.logDebug("<<< DirectLogin.setFormData");
192 },
193
194 'fixFormDataFromBookmarkletVersion_0_1': function(aValue) {
195//{"type":"radio", "name":"action", "value":"new-user", "checked":false }, { "type":"radio", "name":"action", "value":"sign-in", "checked":true }
196 // ||
197 // \ /
198 // \/
199//{"name":"dominio", "type":"radio", "options":[{"value":"@alice.it", "checked":true}, {"value":"@tin.it", "checked":false}, {"value":"@virgilio.it", "checked":false}, {"value":"@tim.it", "checked":false}]}
200 var result;
201 var inputs;
202 var updatedInputs;
203 var radios;
204
205//MochiKit.Logging.logDebug(">>> DirectLogin.fixFormDataFromBookmarkletVersion_0_1");
206 result = aValue;
207 inputs = aValue['inputs'];
208
209 updatedInputs = MochiKit.Base.filter(function(anInput) {
210 varresult;
211 var type;
212
213 type = anInput['type'] || 'text';
214 result = type.toLowerCase() != 'radio';
215
216 return result;
217 }, inputs);
218 radios = MochiKit.Base.filter(function(anInput) {
219 varresult;
220 var type;
221
222 type = anInput['type'] || 'text';
223 result = type.toLowerCase() == 'radio';
224
225 return result;
226 }, inputs);
227
228 if (radios.length > 0) {
229 var updatedRadios;
230
231 updatedRadios = {};
232 MochiKit.Iter.forEach(radios, MochiKit.Base.bind(function(aRadio) {
233 varradioConfiguration;
234
235 radioConfiguration = updatedRadios[aRadio['name']];
236 if (radioConfiguration == null) {
237 radioConfiguration = {type:'radio', name:aRadio['name'], options:[]};
238 updatedRadios[aRadio['name']] = radioConfiguration;
239 }
240
241 //TODO: remove the value: field and replace it with element.dom.value = <some value>
242 radioConfiguration.options.push({value:aRadio['value'], checked:aRadio['checked']});
243
244 if ((aRadio['checked'] == true) && (this.formValues()[aRadio['name']] == null)) {
245//MochiKit.Logging.logDebug("+++ setting value '" + aRadio['value'] + "' for key: '" + aRadio['name'] + "'");
246 this.formValues()[aRadio['name']] = aRadio['value'];
247 }
248 }, this))
249
250 updatedInputs = MochiKit.Base.concat(updatedInputs, MochiKit.Base.values(updatedRadios));
251 }
252
253 delete result.inputs;
254 result.inputs = updatedInputs;
255//MochiKit.Logging.logDebug("<<< DirectLogin.fixFormDataFromBookmarkletVersion_0_1");
256
257 return result;
258 },
259
260 //.........................................................................
261
262 'directLoginInputs': function() {
263 return this._directLoginInputs;
264 },
265
266 //-------------------------------------------------------------------------
267
268 'formValues': function() {
269 return this._formValues;
270 },
271
272 'hasValuesToSet': function() {
273 var result;
274
275//MochiKit.Logging.logDebug(">>> DirectLogin.hasValuesToSet");
276 if (this.directLoginInputs() != null) {
277 result = MochiKit.Iter.some(this.directLoginInputs(), MochiKit.Base.methodcaller('shouldSetValue'));
278 } else {
279 result = false;
280 }
281//MochiKit.Logging.logDebug("<<< DirectLogin.hasValuesToSet");
282
283 return result;
284 },
285
286 //'additionalValues': function() {
287 'inputsRequiringAdditionalValues': function() {
288 varresult;
289 var inputs;
290
291//MochiKit.Logging.logDebug(">>> DirectLogin.additionalValues");
292 result = {};
293 if (this.directLoginInputs() != null) {
294 inputs = MochiKit.Base.filter(MochiKit.Base.methodcaller('shouldSetValue'), this.directLoginInputs());
295 MochiKit.Iter.forEach(inputs, function(anInput) {
296 result[anInput.name()] = anInput;
297 })
298 }
299//MochiKit.Logging.logDebug("<<< DirectLogin.additionalValues");
300
301 return result;
302 },
303
304 //-------------------------------------------------------------------------
305
306 'bindingData': function() {
307 return this._bindingData;
308 },
309
310 'setBindingData': function(aValue) {
311//MochiKit.Logging.logDebug(">>> DirectLogin.setBindingData");
312 if (aValue != null) {
313 var bindingKey;
314
315 this._bindingData = aValue;
316 this._bindings = {};
317
318 for (bindingKey in aValue) {
319 var directLoginBinding;
320
321 directLoginBinding = new Clipperz.PM.DataModel.DirectLoginBinding(this, bindingKey, {fieldKey:aValue[bindingKey]});
322 this._bindings[bindingKey] = directLoginBinding;
323 }
324 } else {
325 var editableFields;
326 var bindings;
327
328 bindings = {};
329
330 editableFields = MochiKit.Base.filter(function(aField) {
331 var result;
332 var type;
333
334 type = aField['type'].toLowerCase();
335 result = ((type != 'hidden') && (type != 'submit') && (type != 'checkbox') && (type != 'radio') && (type != 'select'));
336
337 return result;
338 }, this.formData().inputs);
339
340 MochiKit.Iter.forEach(editableFields, function(anEditableField) {
341 bindings[anEditableField['name']] = new Clipperz.PM.DataModel.DirectLoginBinding(this, anEditableField['name']);
342 }, this);
343
344 this._bindings = bindings;
345 }
346//MochiKit.Logging.logDebug("<<< DirectLogin.setBindingData");
347 },
348
349 'setLegacyBindingData': function(aValue) {
350//MochiKit.Logging.logDebug(">>> DirectLogin.setLegacyBindingData");
351 var bindingKey;
352
353 this._bindingData = aValue;
354 this._bindings = {};
355
356 for (bindingKey in aValue) {
357 var directLoginBinding;
358
359 directLoginBinding = new Clipperz.PM.DataModel.DirectLoginBinding(this, bindingKey, {fieldName:aValue[bindingKey]});
360 this._bindings[bindingKey] = directLoginBinding;
361 }
362//MochiKit.Logging.logDebug("<<< DirectLogin.setLegacyBindingData");
363 },
364
365 //.........................................................................
366
367 'bindings': function() {
368 return this._bindings;
369 },
370
371 //-------------------------------------------------------------------------
372
373 'serializedData': function() {
374 var result;
375 varbindingKey;
376
377 result = {};
378 // result.reference = this.reference();
379 result.label = this.label();
380 result.favicon = this.favicon() || "";
381 result.bookmarkletVersion = this.bookmarkletVersion();
382 result.formData = this.formData();
383 if (this.hasValuesToSet) {
384 result.formValues = this.formValues();
385 }
386 result.bindingData = {};
387
388 for (bindingKey in this.bindings()) {
389 result.bindingData[bindingKey] = this.bindings()[bindingKey].serializedData();
390 }
391
392 return result;
393 },
394
395 //-------------------------------------------------------------------------
396
397 'handleMissingFaviconImage': function(anEvent) {
398 anEvent.stop();
399 MochiKit.Signal.disconnectAll(anEvent.src());
400 this.setFixedFavicon(Clipperz.PM.Strings['defaultFaviconUrl']);
401 anEvent.src().src = this.fixedFavicon();
402 },
403
404 //=========================================================================
405
406 'runHttpAuthDirectLogin': function(aWindow) {
407 MochiKit.DOM.withWindow(aWindow, MochiKit.Base.bind(function() {
408 var completeUrl;
409 var url;
410
411 url = this.bindings()['url'].field().value();
412
413 if (/^https?\:\/\//.test(url) == false) {
414 url = 'http://' + url;
415 }
416
417 if (Clipperz_IEisBroken === true) {
418 completeUrl = url;
419 } else {
420 var username;
421 var password;
422
423 username = this.bindings()['username'].field().value();
424 password = this.bindings()['password'].field().value();
425
426 /(^https?\:\/\/)?(.*)/.test(url);
427
428 completeUrl = RegExp.$1 + username + ':' + password + '@' + RegExp.$2;
429 }
430
431 MochiKit.DOM.currentWindow().location.href = completeUrl;
432 }, this));
433 },
434
435 //-------------------------------------------------------------------------
436
437 'runSubmitFormDirectLogin': function(aWindow) {
438 MochiKit.DOM.withWindow(aWindow, MochiKit.Base.bind(function() {
439 var formElement;
440 varformSubmitFunction;
441 var submitButtons;
442
443//MochiKit.Logging.logDebug("### runDirectLogin - 3");
444 // MochiKit.DOM.currentDocument().write('<html><head><title>' + this.label() + '</title><META http-equiv="Content-Type" content="text/html; charset=utf-8" /></head><body></body></html>')
445//MochiKit.Logging.logDebug("### runDirectLogin - 3.1");
446 MochiKit.DOM.appendChildNodes(MochiKit.DOM.currentDocument().body, MochiKit.DOM.H3(null, "Loading " + this.label() + " ..."));
447//MochiKit.Logging.logDebug("### runDirectLogin - 4");
448//console.log(this.formData()['attributes']);
449 formElement = MochiKit.DOM.FORM(MochiKit.Base.update({id:'directLoginForm'}, {'method':this.formData()['attributes']['method'],
450 'action':this.formData()['attributes']['action']}));
451//MochiKit.Logging.logDebug("### runDirectLogin - 5");
452 formSubmitFunction = MochiKit.Base.method(formElement, 'submit');
453//MochiKit.Logging.logDebug("### runDirectLogin - 6");
454
455 MochiKit.DOM.appendChildNodes(MochiKit.DOM.currentDocument().body,
456 MochiKit.DOM.DIV({style:'display:none; visibility:hidden;'}, formElement)
457 );
458//MochiKit.Logging.logDebug("### runDirectLogin - 7");
459 MochiKit.DOM.appendChildNodes(formElement, MochiKit.Base.map(MochiKit.Base.methodcaller("formConfiguration"),
460 this.directLoginInputs()));
461//MochiKit.Logging.logDebug("### runDirectLogin - 8");
462
463 submitButtons = MochiKit.Base.filter(function(anInputElement) {
464//MochiKit.Logging.logDebug("### runDirectLogin - 8.1 - " + anInputElement);
465//MochiKit.Logging.logDebug("### runDirectLogin - 8.2 - " + anInputElement.tagName);
466//MochiKit.Logging.logDebug("### runDirectLogin - 8.3 - " + anInputElement.getAttribute('type'));
467 return ((anInputElement.tagName.toLowerCase() == 'input') && (anInputElement.getAttribute('type').toLowerCase() == 'submit'));
468 }, formElement.elements)
469//MochiKit.Logging.logDebug("### runDirectLogin - 9");
470
471 if (submitButtons.length == 0) {
472//MochiKit.Logging.logDebug("### OLD submit")
473 if (Clipperz_IEisBroken == true) {
474//MochiKit.Logging.logDebug("### runDirectLogin - 10");
475 formElement.submit();
476 } else {
477//MochiKit.Logging.logDebug("### runDirectLogin - 11");
478 formSubmitFunction();
479 }
480 } else {
481//MochiKit.Logging.logDebug("### NEW submit")
482 submitButtons[0].click();
483 }
484
485 }, this));
486 },
487
488 //-------------------------------------------------------------------------
489
490 'runDirectLogin': function(aNewWindow) {
491 varnewWindow;
492
493//console.log("formData.attributes", this.formData()['attributes']);
494 // if (/^javascript/.test(this.formData()['attributes']['action'])) {
495 if ((/^(https?|webdav|ftp)\:/.test(this.formData()['attributes']['action']) == false) &&
496 (this.formData()['attributes']['type'] != 'http_auth'))
497 {
498 var messageBoxConfiguration;
499
500 if (typeof(aNewWindow) != 'undefined') {
501 aNewWindow.close();
502 }
503
504 messageBoxConfiguration = {};
505 messageBoxConfiguration.title = Clipperz.PM.Strings['VulnerabilityWarning_Panel_title'];
506 messageBoxConfiguration.msg = Clipperz.PM.Strings['VulnerabilityWarning_Panel_message'];
507 messageBoxConfiguration.animEl = YAHOO.ext.Element.get("mainDiv");
508 messageBoxConfiguration.progress = false;
509 messageBoxConfiguration.closable = false;
510 messageBoxConfiguration.buttons = {'cancel': Clipperz.PM.Strings['VulnerabilityWarning_Panel_buttonLabel']};
511
512 Clipperz.YUI.MessageBox.show(messageBoxConfiguration);
513
514 throw Clipperz.Base.exception.VulnerabilityIssue;
515 }
516
517//MochiKit.Logging.logDebug("### runDirectLogin - 1 : " + Clipperz.Base.serializeJSON(this.serializedData()));
518 if (typeof(aNewWindow) == 'undefined') {
519 newWindow = window.open(Clipperz.PM.Strings['directLoginJumpPageUrl'], "");
520 } else {
521 newWindow = aNewWindow;
522 }
523//MochiKit.Logging.logDebug("### runDirectLogin - 2");
524
525 if (this.formData()['attributes']['type'] == 'http_auth') {
526 this.runHttpAuthDirectLogin(newWindow);
527 } else {
528 this.runSubmitFormDirectLogin(newWindow)
529 }
530 },
531
532 //-------------------------------------------------------------------------
533 __syntaxFix__: "syntax fix"
534
535});
536
diff --git a/frontend/beta/js/Clipperz/PM/DataModel/DirectLoginBinding.js b/frontend/beta/js/Clipperz/PM/DataModel/DirectLoginBinding.js
new file mode 100644
index 0000000..19aa9cb
--- a/dev/null
+++ b/frontend/beta/js/Clipperz/PM/DataModel/DirectLoginBinding.js
@@ -0,0 +1,113 @@
1/*
2
3Copyright 2008-2011 Clipperz Srl
4
5This file is part of Clipperz's Javascript Crypto Library.
6Javascript Crypto Library provides web developers with an extensive
7and efficient set of cryptographic functions. The library aims to
8obtain maximum execution speed while preserving modularity and
9reusability.
10For further information about its features and functionalities please
11refer to http://www.clipperz.com
12
13* Javascript Crypto Library is free software: you can redistribute
14 it and/or modify it under the terms of the GNU Affero General Public
15 License as published by the Free Software Foundation, either version
16 3 of the License, or (at your option) any later version.
17
18* Javascript Crypto Library is distributed in the hope that it will
19 be useful, but WITHOUT ANY WARRANTY; without even the implied
20 warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
21 See the GNU Affero General Public License for more details.
22
23* You should have received a copy of the GNU Affero General Public
24 License along with Javascript Crypto Library. If not, see
25 <http://www.gnu.org/licenses/>.
26
27*/
28
29if (typeof(Clipperz) == 'undefined') { Clipperz = {}; }
30if (typeof(Clipperz.PM) == 'undefined') { Clipperz.PM = {}; }
31if (typeof(Clipperz.PM.DataModel) == 'undefined') { Clipperz.PM.DataModel = {}; }
32
33
34//#############################################################################
35
36Clipperz.PM.DataModel.DirectLoginBinding = function(aDirectLogin, aKey, args) {
37//MochiKit.Logging.logDebug(">>> new DirectLoginBinding")
38 args = args || {};
39//MochiKit.Logging.logDebug("--- new DirectLoginBinding - args: " + Clipperz.Base.serializeJSON(args));
40
41 this._directLogin = aDirectLogin || args.directLogin || null;
42 this._key = aKey;
43
44 this._fieldKey = args.fieldKey || null;
45 this._fieldName = args.fieldName || null;
46//MochiKit.Logging.logDebug("<<< new DirectLoginBinding")
47
48 return this;
49}
50
51Clipperz.PM.DataModel.DirectLoginBinding.prototype = MochiKit.Base.update(null, {
52
53 'directLogin': function() {
54 return this._directLogin;
55 },
56
57 //-------------------------------------------------------------------------
58
59 'key': function() {
60 return this._key;
61 },
62
63 //-------------------------------------------------------------------------
64
65 'fieldKey': function() {
66//MochiKit.Logging.logDebug("=== Clipperz.PM.DataModel.DirectLoginBinding.fieldKey");
67//MochiKit.Logging.logDebug("=== Clipperz.PM.DataModel.DirectLoginBinding.fieldKey - " + this._fieldKey);
68 return this._fieldKey;
69 },
70
71 'setFieldKey': function(aValue) {
72 this._fieldKey = aValue;
73 },
74
75 'fieldName': function() {
76 return this._fieldName;
77 },
78
79 //-------------------------------------------------------------------------
80
81 'field': function() {
82 var result;
83
84 //MochiKit.Logging.logDebug(">>> Clipperz.PM.DataModel.DirectLoginBinding.field")
85//MochiKit.Logging.logDebug("--- Clipperz.PM.DataModel.DirectLoginBinding.field - 1 - this.fieldKey(): " + this.fieldKey());
86//MochiKit.Logging.logDebug("--- Clipperz.PM.DataModel.DirectLoginBinding.field - 2 - this.fieldName(): " + this.fieldName());
87 if (this.fieldKey() != null) {
88 result = this.directLogin().record().currentVersion().fields()[this.fieldKey()];
89//MochiKit.Logging.logDebug("--- Clipperz.PM.DataModel.DirectLoginBinding.field - 3 - result: " + result);
90 } else if (this.fieldName() != null) {
91 result = this.directLogin().record().currentVersion().fieldWithName(this.fieldName());
92//MochiKit.Logging.logDebug("--- Clipperz.PM.DataModel.DirectLoginBinding.field - 4 - result: " + result);
93
94 this.setFieldKey(result.key());
95 } else {
96 result = null;
97 }
98 //MochiKit.Logging.logDebug("<<< Clipperz.PM.DataModel.DirectLoginBinding.field")
99
100 return result;
101 },
102
103 //-------------------------------------------------------------------------
104
105 'serializedData': function() {
106 return this.fieldKey();
107 },
108
109 //-------------------------------------------------------------------------
110 __syntaxFix__: "syntax fix"
111
112});
113
diff --git a/frontend/beta/js/Clipperz/PM/DataModel/DirectLoginInput.js b/frontend/beta/js/Clipperz/PM/DataModel/DirectLoginInput.js
new file mode 100644
index 0000000..3302ed6
--- a/dev/null
+++ b/frontend/beta/js/Clipperz/PM/DataModel/DirectLoginInput.js
@@ -0,0 +1,229 @@
1/*
2
3Copyright 2008-2011 Clipperz Srl
4
5This file is part of Clipperz's Javascript Crypto Library.
6Javascript Crypto Library provides web developers with an extensive
7and efficient set of cryptographic functions. The library aims to
8obtain maximum execution speed while preserving modularity and
9reusability.
10For further information about its features and functionalities please
11refer to http://www.clipperz.com
12
13* Javascript Crypto Library is free software: you can redistribute
14 it and/or modify it under the terms of the GNU Affero General Public
15 License as published by the Free Software Foundation, either version
16 3 of the License, or (at your option) any later version.
17
18* Javascript Crypto Library is distributed in the hope that it will
19 be useful, but WITHOUT ANY WARRANTY; without even the implied
20 warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
21 See the GNU Affero General Public License for more details.
22
23* You should have received a copy of the GNU Affero General Public
24 License along with Javascript Crypto Library. If not, see
25 <http://www.gnu.org/licenses/>.
26
27*/
28
29if (typeof(Clipperz) == 'undefined') { Clipperz = {}; }
30if (typeof(Clipperz.PM) == 'undefined') { Clipperz.PM = {}; }
31if (typeof(Clipperz.PM.DataModel) == 'undefined') { Clipperz.PM.DataModel = {}; }
32
33//#############################################################################
34
35Clipperz.PM.DataModel.DirectLoginInput = function(aDirectLogin, args) {
36 args = args || {};
37
38//console.log(">>> new DirectLoginInput - args: %o" + args);
39 this._directLogin = aDirectLogin;
40 this._args = args;
41
42 return this;
43}
44
45Clipperz.PM.DataModel.DirectLoginInput.prototype = MochiKit.Base.update(null, {
46
47 'directLogin': function() {
48 return this._directLogin;
49 },
50
51 //-------------------------------------------------------------------------
52
53 'args': function() {
54 return this._args;
55 },
56
57 //-------------------------------------------------------------------------
58
59 'name': function() {
60 return this.args()['name'];
61 },
62
63 //-------------------------------------------------------------------------
64
65 'type': function() {
66 var result;
67
68 result = this.args()['type'];
69
70 if (result != null) {
71 result = result.toLowerCase();
72 }
73 return result;
74 },
75
76 //-------------------------------------------------------------------------
77
78 'value': function() {
79 return this.args()['value'];
80 },
81
82 //-------------------------------------------------------------------------
83
84 'formConfiguration': function() {
85 var result;
86
87//MochiKit.Logging.logDebug(">>> DirectLoginInput.formConfiguration - " + this.name());
88 if (this.shouldSetValue()) {
89//MochiKit.Logging.logDebug("--- DirectLoginInput.formConfiguration - 1");
90 switch (this.type()) {
91 case 'select':
92 var currentValue;
93 var options;
94
95//MochiKit.Logging.logDebug("--- DirectLoginInput.formConfiguration - 2");
96 currentValue = this.directLogin().formValues()[this.name()];
97//MochiKit.Logging.logDebug("--- DirectLoginInput.formConfiguration - 2.1");
98 options = this.args()['options'];
99//MochiKit.Logging.logDebug("--- DirectLoginInput.formConfiguration - 2.2");
100
101 result = MochiKit.DOM.SELECT({name:this.name()},
102 MochiKit.Base.map(function(anOption) {
103 var options;
104
105//MochiKit.Logging.logDebug("--- DirectLoginInput.formConfiguration - 2.3");
106 //TODO: remove the value: field and replace it with element.dom.value = <some value>
107 options = {value:anOption['value']};
108//MochiKit.Logging.logDebug("--- DirectLoginInput.formConfiguration - 2.4");
109 if (currentValue == anOption['value']) {
110//MochiKit.Logging.logDebug("--- DirectLoginInput.formConfiguration - 2.5");
111 options.selected = true;
112//MochiKit.Logging.logDebug("--- DirectLoginInput.formConfiguration - 2.6");
113 }
114//MochiKit.Logging.logDebug("--- DirectLoginInput.formConfiguration - 2.7");
115
116 return MochiKit.DOM.OPTION(options, anOption['label'])
117 }, options)
118 )
119//MochiKit.Logging.logDebug("--- DirectLoginInput.formConfiguration - 2.8");
120 break;
121 case 'checkbox':
122 var options;
123
124//MochiKit.Logging.logDebug("--- DirectLoginInput.formConfiguration - 3");
125 options = {type:'checkbox', name: this.name()};
126 if (this.directLogin().formValues()[this.name()] == true) {
127 options['checked'] = true;
128 };
129
130 result = MochiKit.DOM.INPUT(options, null);
131 break;
132 case 'radio':
133 var currentName;
134 var currentValue;
135 var options;
136
137//MochiKit.Logging.logDebug("--- DirectLoginInput.formConfiguration - 4");
138 currentName = this.name();
139//MochiKit.Logging.logDebug("--- DirectLoginInput.formConfiguration - 4.1");
140 currentValue = this.directLogin().formValues()[this.name()];
141//MochiKit.Logging.logDebug("--- DirectLoginInput.formConfiguration - 4.2");
142 options = this.args()['options'];
143//MochiKit.Logging.logDebug("--- DirectLoginInput.formConfiguration - 4.3");
144
145 result = MochiKit.DOM.DIV(null,
146 MochiKit.Base.map(function(anOption) {
147 var options;
148 var isChecked;
149 var inputNode;
150 var divNode;
151
152//MochiKit.Logging.logDebug("--- DirectLoginInput.formConfiguration - 4.4");
153 //TODO: remove the value: field and replace it with element.dom.value = <some value>
154 options = {type:'radio', name:currentName, value:anOption['value']}
155 isChecked = (currentValue == anOption['value']);
156//MochiKit.Logging.logDebug("--- DirectLoginInput.formConfiguration - 4.5");
157 if (isChecked) {
158//MochiKit.Logging.logDebug("--- DirectLoginInput.formConfiguration - 4.6");
159 options.checked = true;
160//MochiKit.Logging.logDebug("--- DirectLoginInput.formConfiguration - 4.7");
161 }
162//MochiKit.Logging.logDebug("--- DirectLoginInput.formConfiguration - 4.8 - options: " + Clipperz.Base.serializeJSON(options));
163//MochiKit.Logging.logDebug("--- DirectLoginInput.formConfiguration - 4.8 - value: " + anOption['value']);
164
165 if (Clipperz_IEisBroken == true) {
166 var checkedValue;
167
168//MochiKit.Logging.logDebug("--- DirectLoginInput.formConfiguration - 4.8.1");
169 checkedValue = (isChecked ? " CHECKED" : "");
170//MochiKit.Logging.logDebug("--- DirectLoginInput.formConfiguration - 4.8.2");
171 inputNode = MochiKit.DOM.currentDocument().createElement("<INPUT TYPE='RADIO' NAME='" + currentName + "' VALUE='" + anOption['value'] + "'" + checkedValue + ">");
172//MochiKit.Logging.logDebug("--- DirectLoginInput.formConfiguration - 4.8.3");
173 } else {
174//MochiKit.Logging.logDebug("--- DirectLoginInput.formConfiguration - 4.8.4");
175 inputNode = MochiKit.DOM.INPUT(options, anOption['value']);
176//MochiKit.Logging.logDebug("--- DirectLoginInput.formConfiguration - 4.8.5");
177 }
178//MochiKit.Logging.logDebug("--- DirectLoginInput.formConfiguration - 4.9");
179 divNode = MochiKit.DOM.DIV(null, inputNode);
180//MochiKit.Logging.logDebug("--- DirectLoginInput.formConfiguration - 4.10");
181
182 return divNode;
183 // return MochiKit.DOM.DIV(null, MochiKit.DOM.INPUT(options, anOption['value']));
184 }, options)
185 );
186//MochiKit.Logging.logDebug("--- DirectLoginInput.formConfiguration - 4.9");
187 break;
188 }
189 } else {
190 var binding;
191//MochiKit.Logging.logDebug("--- DirectLoginInput.formConfiguration - 5");
192 binding = this.directLogin().bindings()[this.name()];
193
194//MochiKit.Logging.logDebug("--- DirectLoginInput.formConfiguration - 6");
195 //TODO: remove the value: field and replace it with element.dom.value = <some value>
196 result = MochiKit.DOM.INPUT({
197 type:((this.type() != 'password') ? this.type() : 'text'),
198 // type:(((this.type() != 'password') && (this.type() != 'submit')) ? this.type() : 'text'),
199 name:this.name(),
200 value:((binding != null)? binding.field().value() : this.value())
201 }, null);
202//MochiKit.Logging.logDebug("--- DirectLoginInput.formConfiguration - 7");
203 }
204
205//MochiKit.Logging.logDebug("<<< DirectLoginInput.formConfiguration: ");
206 return result;
207 },
208
209 //-------------------------------------------------------------------------
210
211 'shouldSetValue': function() {
212 var type;
213 var result;
214
215//MochiKit.Logging.logDebug(">>> DirectLoginInput.shouldSetValue");
216 type = this.type();
217 result = ((type == 'checkbox') || (type == 'radio') || (type == 'select'));
218//if (result == true) {
219 //MochiKit.Logging.logDebug("DIRECT LOGIN INPUT need value: " + Clipperz.Base.serializeJSON(this.args()));
220//}
221//MochiKit.Logging.logDebug("<<< DirectLoginInput.shouldSetValue");
222 return result;
223 },
224
225 //-------------------------------------------------------------------------
226 __syntaxFix__: "syntax fix"
227
228});
229
diff --git a/frontend/beta/js/Clipperz/PM/DataModel/DirectLoginReference.js b/frontend/beta/js/Clipperz/PM/DataModel/DirectLoginReference.js
new file mode 100644
index 0000000..b067a21
--- a/dev/null
+++ b/frontend/beta/js/Clipperz/PM/DataModel/DirectLoginReference.js
@@ -0,0 +1,192 @@
1/*
2
3Copyright 2008-2011 Clipperz Srl
4
5This file is part of Clipperz's Javascript Crypto Library.
6Javascript Crypto Library provides web developers with an extensive
7and efficient set of cryptographic functions. The library aims to
8obtain maximum execution speed while preserving modularity and
9reusability.
10For further information about its features and functionalities please
11refer to http://www.clipperz.com
12
13* Javascript Crypto Library is free software: you can redistribute
14 it and/or modify it under the terms of the GNU Affero General Public
15 License as published by the Free Software Foundation, either version
16 3 of the License, or (at your option) any later version.
17
18* Javascript Crypto Library is distributed in the hope that it will
19 be useful, but WITHOUT ANY WARRANTY; without even the implied
20 warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
21 See the GNU Affero General Public License for more details.
22
23* You should have received a copy of the GNU Affero General Public
24 License along with Javascript Crypto Library. If not, see
25 <http://www.gnu.org/licenses/>.
26
27*/
28
29if (typeof(Clipperz) == 'undefined') { Clipperz = {}; }
30if (typeof(Clipperz.PM) == 'undefined') { Clipperz.PM = {}; }
31if (typeof(Clipperz.PM.DataModel) == 'undefined') { Clipperz.PM.DataModel = {}; }
32
33
34//#############################################################################
35
36Clipperz.PM.DataModel.DirectLoginReference = function(args) {
37 args = args || {};
38
39//MochiKit.Logging.logDebug(">>> new DirectLoginReference: " + Clipperz.Base.serializeJSON(MochiKit.Base.keys(args)));
40//MochiKit.Logging.logDebug(">>> new DirectLoginReference - record: " + args.record);
41 this._user = args.user;
42
43 if (args.directLogin != null) {
44 this._reference = args.directLogin.reference();
45 this._recordReference = args.directLogin.record().reference();
46 this._label = args.directLogin.label();
47 this._favicon = args.directLogin.favicon() || null;
48
49 this._directLogin = args.directLogin;
50 this._record = args.directLogin.record();
51 } else {
52 this._reference = args.reference;
53 this._recordReference = args.record;
54 this._label = args.label;
55 this._favicon = args.favicon || null;
56
57 this._directLogin = null;
58 this._record = null;
59 }
60
61 this._fixedFavicon = null;
62
63 return this;
64}
65
66Clipperz.PM.DataModel.DirectLoginReference.prototype = MochiKit.Base.update(null, {
67
68 'user': function() {
69 return this._user;
70 },
71
72 //-------------------------------------------------------------------------
73
74 'reference': function() {
75 return this._reference;
76 },
77
78 //-------------------------------------------------------------------------
79
80 'synchronizeValues': function(aDirectLogin) {
81 this._label = aDirectLogin.label();
82 this._favicon = aDirectLogin.favicon();
83 },
84
85 //-------------------------------------------------------------------------
86
87 'label': function() {
88 return this._label;
89 },
90
91 //-------------------------------------------------------------------------
92
93 'recordReference': function() {
94 return this._recordReference;
95 },
96
97 //-------------------------------------------------------------------------
98
99 'record': function() {
100//MochiKit.Logging.logDebug(">>> DirectLoginReference.record");
101 if (this._record == null) {
102 this._record = this.user().records()[this.recordReference()];
103 }
104
105//MochiKit.Logging.logDebug("<<< DirectLoginReference.record");
106 return this._record;
107 },
108
109 //-------------------------------------------------------------------------
110
111 'favicon': function() {
112 return this._favicon;
113 },
114
115 //-------------------------------------------------------------------------
116
117 'fixedFavicon': function() {
118 var result;
119
120 if (this._fixedFavicon == null) {
121 result = this.favicon();
122
123 if (Clipperz_IEisBroken && (this.user().preferences().disableUnsecureFaviconLoadingForIE()) && (result.indexOf('https://') != 0)) {
124 result = Clipperz.PM.Strings['defaultFaviconUrl_IE'];
125 this.setFixedFavicon(result);
126 }
127 } else {
128 result = this._fixedFavicon;
129 }
130
131 return result;
132 },
133
134 'setFixedFavicon': function(aValue) {
135 this._fixedFavicon = aValue;
136 },
137
138 //-------------------------------------------------------------------------
139
140 'setupJumpPageWindow': function(aWindow) {
141//MochiKit.Logging.logDebug(">>> DirectLoginReference.setupJumpPageWindow - " + aWindow);
142 try {
143 MochiKit.DOM.withWindow(aWindow, MochiKit.Base.bind(function() {
144 MochiKit.DOM.appendChildNodes(MochiKit.DOM.currentDocument().body,
145 MochiKit.DOM.H1(null, "Loading " + this.label())
146 );
147 }, this));
148 } catch(e) {
149 MochiKit.Logging.logDebug("EXCEPTION: " + e);
150 }
151//MochiKit.Logging.logDebug("<<< DirectLoginReference.setupJumpPageWindow");
152 },
153
154 //-------------------------------------------------------------------------
155
156 'deferredDirectLogin': function() {
157 var deferredResult;
158
159//MochiKit.Logging.logDebug(">>> DirectLoginReference.deferredDirectLogin - " + this);
160 deferredResult = new MochiKit.Async.Deferred();
161//MochiKit.Logging.logDebug("--- DirectLoginReference.deferredDirectLogin - 1");
162 deferredResult.addCallback(MochiKit.Base.method(this.record(), 'deferredData'));
163//MochiKit.Logging.logDebug("--- DirectLoginReference.deferredDirectLogin - 2");
164 deferredResult.addCallback(function(aRecord, aDirectLoginReference) {
165 return aRecord.directLogins()[aDirectLoginReference];
166 }, this.record(), this.reference());
167//MochiKit.Logging.logDebug("--- DirectLoginReference.deferredDirectLogin - 3");
168 deferredResult.callback();
169//MochiKit.Logging.logDebug("<<< DirectLoginReference.deferredDirectLogin");
170
171 return deferredResult;
172 },
173
174 //-------------------------------------------------------------------------
175
176 'handleMissingFaviconImage': function(anEvent) {
177//MochiKit.Logging.logDebug(">>> DirectLoginReference.handleMissingFaviconImage");
178 anEvent.stop();
179 MochiKit.Signal.disconnectAll(anEvent.src());
180 this.setFixedFavicon(Clipperz.PM.Strings['defaultFaviconUrl']);
181//MochiKit.Logging.logDebug("--- DirectLoginReference.handleMissingFaviconImage - fixedFavicon: " + this.fixedFavicon());
182//MochiKit.Logging.logDebug("--- DirectLoginReference.handleMissingFaviconImage - anEvent.src().src: " + anEvent.src().src);
183 // MochiKit.DOM.swapDOM(anEvent.src(), MochiKit.DOM.IMG({src:'this.fixedFavicon()'}));
184 anEvent.src().src = this.fixedFavicon();
185//MochiKit.Logging.logDebug("<<< DirectLoginReference.handleMissingFaviconImage");
186 },
187
188 //-------------------------------------------------------------------------
189 __syntaxFix__: "syntax fix"
190
191});
192
diff --git a/frontend/beta/js/Clipperz/PM/DataModel/Header.js b/frontend/beta/js/Clipperz/PM/DataModel/Header.js
new file mode 100644
index 0000000..ef34732
--- a/dev/null
+++ b/frontend/beta/js/Clipperz/PM/DataModel/Header.js
@@ -0,0 +1,751 @@
1/*
2
3Copyright 2008-2011 Clipperz Srl
4
5This file is part of Clipperz's Javascript Crypto Library.
6Javascript Crypto Library provides web developers with an extensive
7and efficient set of cryptographic functions. The library aims to
8obtain maximum execution speed while preserving modularity and
9reusability.
10For further information about its features and functionalities please
11refer to http://www.clipperz.com
12
13* Javascript Crypto Library is free software: you can redistribute
14 it and/or modify it under the terms of the GNU Affero General Public
15 License as published by the Free Software Foundation, either version
16 3 of the License, or (at your option) any later version.
17
18* Javascript Crypto Library is distributed in the hope that it will
19 be useful, but WITHOUT ANY WARRANTY; without even the implied
20 warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
21 See the GNU Affero General Public License for more details.
22
23* You should have received a copy of the GNU Affero General Public
24 License along with Javascript Crypto Library. If not, see
25 <http://www.gnu.org/licenses/>.
26
27*/
28
29if (typeof(Clipperz) == 'undefined') { Clipperz = {}; }
30if (typeof(Clipperz.PM) == 'undefined') { Clipperz.PM = {}; }
31if (typeof(Clipperz.PM.DataModel) == 'undefined') { Clipperz.PM.DataModel = {}; }
32
33
34//#############################################################################
35
36Clipperz.PM.DataModel.Header = function(args) {
37 args = args || {};
38
39 this._user = args.user;
40
41 this._serverData = null;
42 this._serverDataVersion = null;
43 this._jsonEvaledServerData = null;
44
45 this._decryptedLegacyServerData = null;
46 this._isDecryptingLegacyServerData = false;
47 this._decryptingLegacyServerDataPendingQueue = [];
48
49 this.resetUpdatedSections();
50
51 this._shouldLoadSections = {};
52
53 Clipperz.NotificationCenter.register(this.user(), 'updatedSection', this, 'updatedSectionHandler');
54
55 return this;
56}
57
58Clipperz.PM.DataModel.Header.prototype = MochiKit.Base.update(null, {
59
60 //-------------------------------------------------------------------------
61
62 'user': function() {
63 return this._user;
64 },
65
66 //-------------------------------------------------------------------------
67 //-------------------------------------------------------------------------
68 //-------------------------------------------------------------------------
69 //-------------------------------------------------------------------------
70 //-------------------------------------------------------------------------
71 //-------------------------------------------------------------------------
72 //-------------------------------------------------------------------------
73 //-------------------------------------------------------------------------
74 //-------------------------------------------------------------------------
75
76 'updatedSections': function() {
77 return this._updatedSections;
78 },
79
80 'markSectionAsUpdated': function(aSectionName) {
81 this.updatedSections().push(aSectionName);
82 },
83
84 'resetUpdatedSections': function() {
85 this._updatedSections = []
86 },
87
88 'hasSectionBeenUpdated': function(aSectionName) {
89 return (this.updatedSections().join().indexOf(aSectionName) != -1);
90 },
91
92 'cachedServerDataSection': function(aSectionName) {
93 return (this.hasSectionBeenUpdated(aSectionName)) ? {} : this.jsonEvaledServerData()[aSectionName];
94 },
95
96 'updateAllSections': function() {
97 this.resetUpdatedSections();
98 this.markSectionAsUpdated('records');
99 this.markSectionAsUpdated('directLogins');
100 this.markSectionAsUpdated('preferences');
101 this.markSectionAsUpdated('oneTimePasswords');
102
103 return MochiKit.Async.succeed(this);
104 },
105
106 'updatedSectionHandler': function(anEvent) {
107 this.markSectionAsUpdated(anEvent.parameters());
108 },
109
110 //-------------------------------------------------------------------------
111
112 'getObjectKeyIndex': function(anObject) {
113 var result;
114 varitemReference;
115 var index;
116
117 result = {};
118 index = 0;
119
120 for (itemReference in anObject) {
121 result[itemReference] = index.toString();
122 index ++;
123 }
124
125 return result;
126 },
127
128 //-------------------------------------------------------------------------
129
130 'serializedDataWithRecordAndDirectLoginIndexes': function(aRecordIndexes, aDirectLoginIndexs) {
131 var result;
132 var records;
133 var recordReference;
134
135//MochiKit.Logging.logDebug(">>> Header.serializedData");
136 result = {
137 'records': {},
138 'directLogins': {}
139 };
140
141 records = this.user().records();
142 for (recordReference in records) {
143 result['records'][aRecordIndexes[recordReference]] = this.user().records()[recordReference].headerData();
144 }
145
146 for (directLoginReference in this.user().directLoginReferences()) {
147 var currentDirectLogin;
148 vardirectLoginData;
149
150 currentDirectLogin = this.user().directLoginReferences()[directLoginReference];
151 if (aRecordIndexes[currentDirectLogin.recordReference()] != null) {
152 directLoginData = {
153 // reference: currentDirectLogin.reference(),
154 record: aRecordIndexes[currentDirectLogin.recordReference()].toString(),
155 label: currentDirectLogin.label(),
156 favicon:currentDirectLogin.favicon() || ""
157 }
158
159 result['directLogins'][aDirectLoginIndexs[directLoginReference]] = directLoginData;
160 }
161
162 }
163//MochiKit.Logging.logDebug("<<< Header.serializedData - result: " + Clipperz.Base.serializeJSON(result));
164//MochiKit.Logging.logDebug("<<< Header.serializedData");
165
166 return result;
167 },
168
169 //-------------------------------------------------------------------------
170
171 'encryptedData': function() {
172 var deferredResult;
173 var recordIndex;
174 var directLoginIndex;
175 varserializedData;
176 var result;
177
178//MochiKit.Logging.logDebug(">>> [" + (new Date()).valueOf() + "] Header.encryptedData");
179//MochiKit.Logging.logDebug("### Header.encryptedData - " + Clipperz.Base.serializeJSON(this.updatedSections()));
180 result = {
181 'records': this.cachedServerDataSection('records'),
182 'directLogins': this.cachedServerDataSection('directLogins'),
183 'preferences': this.cachedServerDataSection('preferences'),
184 'oneTimePasswords': this.cachedServerDataSection('oneTimePasswords'),
185 'version': '0.1'
186 };
187
188 if (this.hasSectionBeenUpdated('records')) {
189 recordIndex = this.getObjectKeyIndex(this.user().records());
190 result['records']['index'] = recordIndex;
191 } else {
192 recordIndex = result['records']['index'];
193 }
194
195 if (this.hasSectionBeenUpdated('directLogins')) {
196 directLoginIndex = this.getObjectKeyIndex(this.user().directLoginReferences());
197 result['directLogins']['index'] = directLoginIndex;
198 } else {
199 directLoginIndex = result['directLogins']['index'];
200 }
201
202 if (this.hasSectionBeenUpdated('records') || this.hasSectionBeenUpdated('directLogins')) {
203 serializedData = this.serializedDataWithRecordAndDirectLoginIndexes(recordIndex, directLoginIndex);
204 }
205
206 deferredResult = new MochiKit.Async.Deferred();
207
208//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("Header.encryptedData - 1: " + res); return res;});
209 if (this.hasSectionBeenUpdated('records')) {
210//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("Header.encryptedData - 1.1: " + res); return res;});
211 deferredResult.addCallback(function(anHeader, aResult, aSerializedData, aValue) {
212 return Clipperz.PM.Crypto.deferredEncryptWithCurrentVersion(anHeader.user().passphrase(), aSerializedData['records']);
213 }, this, result, serializedData);
214//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("Header.encryptedData - 1.2: " + res); return res;});
215 deferredResult.addCallback(function(anHeader, aResult, aValue) {
216 aResult['records']['data'] = aValue;
217 }, this, result);
218//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("Header.encryptedData - 1.3: " + res); return res;});
219 }
220
221//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("Header.encryptedData - 2: " + res); return res;});
222 if (this.hasSectionBeenUpdated('directLogins')) {
223//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("Header.encryptedData - 2.1: " + res); return res;});
224 deferredResult.addCallback(function(anHeader, aResult, aSerializedData, aValue) {
225 return Clipperz.PM.Crypto.deferredEncryptWithCurrentVersion(anHeader.user().passphrase(), aSerializedData['directLogins']);
226 }, this, result, serializedData);
227//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("Header.encryptedData - 2.2: " + res); return res;});
228 deferredResult.addCallback(function(anHeader, aResult, aValue) {
229 aResult['directLogins']['data'] = aValue;
230 }, this, result);
231//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("Header.encryptedData - 2.3: " + res); return res;});
232 }
233
234//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("Header.encryptedData - 3: " + res); return res;});
235 if (this.hasSectionBeenUpdated('preferences')) {
236//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("Header.encryptedData - 3.1: " + res); return res;});
237 deferredResult.addCallback(function(anHeader, aResult, aValue) {
238 return Clipperz.PM.Crypto.deferredEncryptWithCurrentVersion(anHeader.user().passphrase(), anHeader.user().preferences().serializedData());
239 }, this, result);
240//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("Header.encryptedData - 3.2: " + res); return res;});
241 deferredResult.addCallback(function(anHeader, aResult, aValue) {
242 aResult['preferences']['data'] = aValue;
243 }, this, result);
244//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("Header.encryptedData - 3.3: " + res); return res;});
245 }
246
247//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("Header.encryptedData - 4: " + res); return res;});
248 if (this.hasSectionBeenUpdated('oneTimePasswords')) {
249//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("Header.encryptedData - 4.1: " + res); return res;});
250 // deferredResult.addCallback(MochiKit.Base.method(this, 'loadOneTimePasswords'));
251//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("Header.encryptedData - 4.2: " + res); return res;});
252 deferredResult.addCallback(function(anHeader, aResult, aValue) {
253 return Clipperz.PM.Crypto.deferredEncryptWithCurrentVersion(anHeader.user().passphrase(), anHeader.user().oneTimePasswordManager().serializedData());
254 }, this, result);
255//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("Header.encryptedData - 4.3: " + res); return res;});
256 deferredResult.addCallback(function(anHeader, aResult, aValue) {
257 aResult['oneTimePasswords']['data'] = aValue;
258 }, this, result);
259//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("Header.encryptedData - 4.4: " + res); return res;});
260 }
261
262//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("Header.encryptedData - 5: " + res); return res;});
263 deferredResult.addCallback(function(anHeader, aResult, aValue) {
264 var serverData;
265
266 serverData = Clipperz.Base.serializeJSON(aResult);
267 anHeader.setServerData(serverData);
268
269 return serverData;
270 }, this, result);
271//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("Header.encryptedData - 6: " + res); return res;});
272
273 deferredResult.callback();
274//MochiKit.Logging.logDebug("<<< [" + (new Date()).valueOf() + "] Header.encryptedData");
275
276 return deferredResult;
277 },
278
279 //-------------------------------------------------------------------------
280
281 'serverData': function() {
282 return this._serverData;
283 },
284
285 'setServerData': function(aValue) {
286//MochiKit.Logging.logDebug(">>> Header.setServerData");
287//MochiKit.Logging.logDebug("[start]=============================================");
288//MochiKit.Logging.logDebug("SERVER_DATA: " + aValue);
289//MochiKit.Logging.logDebug("[end]===============================================");
290 this._serverData = aValue;
291//MochiKit.Logging.logDebug("--- Header.setServerData - 1");
292 this.resetUpdatedSections();
293//MochiKit.Logging.logDebug("--- Header.setServerData - 2");
294 this.resetJsonEvaledServerData();
295//MochiKit.Logging.logDebug("<<< Header.setServerData");
296 },
297
298 'jsonEvaledServerData': function() {
299 if (this._jsonEvaledServerData == null) {
300 this._jsonEvaledServerData = Clipperz.Base.evalJSON(this.serverData());
301 }
302
303 return this._jsonEvaledServerData;
304 },
305
306 'resetJsonEvaledServerData': function() {
307 this._jsonEvaledServerData = null;
308 },
309
310 //-------------------------------------------------------------------------
311
312 'serverDataVersion': function() {
313 return this._serverDataVersion;
314 },
315
316 'setServerDataVersion': function(aValue) {
317 this._serverDataVersion = aValue;
318 },
319
320 //-------------------------------------------------------------------------
321
322 'decryptedLegacyServerData': function() {
323 var deferredResult;
324
325//MochiKit.Logging.logDebug(">>> Header.decryptedLegacyServerData");
326 deferredResult = new MochiKit.Async.Deferred();
327//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("Header.decryptedLegacyServerData 1: "/* + res*/); return res;});
328//deferredResult.addErrback(function(res) {MochiKit.Logging.logDebug("ERROR: " + res); return res;});
329 deferredResult.addCallback(MochiKit.Base.method(this, 'updateAllSections'));
330//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("Header.decryptedLegacyServerData 2: "/* + res*/); return res;});
331//deferredResult.addErrback(function(res) {MochiKit.Logging.logDebug("ERROR: " + res); return res;});
332 if (this._decryptedLegacyServerData == null) {
333//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("Header.decryptedLegacyServerData 3: "/* + res*/); return res;});
334//deferredResult.addErrback(function(res) {MochiKit.Logging.logDebug("ERROR: " + res); return res;});
335 deferredResult.addCallback(Clipperz.NotificationCenter.deferredNotification, this, 'updatedProgressState', 'connection_decryptingUserData');
336//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("Header.decryptedLegacyServerData 4: "/* + res*/); return res;});
337//deferredResult.addErrback(function(res) {MochiKit.Logging.logDebug("ERROR: " + res); return res;});
338 deferredResult.addCallback(Clipperz.PM.Crypto.deferredDecrypt, this.user().passphrase(), this.serverData(), this.serverDataVersion());
339//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("Header.decryptedLegacyServerData 5: "/* + res*/); return res;});
340//deferredResult.addErrback(function(res) {MochiKit.Logging.logDebug("ERROR: " + res); return res;});
341 deferredResult.addCallback(function(anHeader, aValue) {
342 anHeader._decryptedLegacyServerData = aValue;
343 }, this);
344//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("Header.decryptedLegacyServerData 6: "/* + res*/); return res;});
345//deferredResult.addErrback(function(res) {MochiKit.Logging.logDebug("ERROR: " + res); return res;});
346 };
347//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("Header.decryptedLegacyServerData 7: "/* + res*/); return res;});
348//deferredResult.addErrback(function(res) {MochiKit.Logging.logDebug("ERROR: " + res); return res;});
349
350 deferredResult.addCallback(function(anHeader) {
351 return anHeader._decryptedLegacyServerData;
352 }, this);
353//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("Header.decryptedLegacyServerData 8: "/* + res*/); return res;});
354//deferredResult.addErrback(function(res) {MochiKit.Logging.logDebug("ERROR: " + res); return res;});
355 deferredResult.callback();
356//MochiKit.Logging.logDebug("<<< Header.decryptedLegacyServerData");
357
358 return deferredResult;
359 },
360
361 //-------------------------------------------------------------------------
362
363 'serverDataFormat': function() {
364 var result;
365
366//MochiKit.Logging.logDebug(">>> Header.serverDataFormat");
367 if (this.serverData().charAt(0) == '{') {
368 varserverData;
369
370 serverData = Clipperz.Base.evalJSON(this.serverData());
371 result = serverData['version'];
372 } else {
373 result = 'LEGACY';
374 }
375//MochiKit.Logging.logDebug("<<< Header.serverDataFormat");
376
377 return result;
378 },
379
380 //-------------------------------------------------------------------------
381
382 'extractHeaderDataFromUserDetails': function(someUserDetails) {
383 if (this.serverData() == null) {
384 this.setServerData(someUserDetails['header']);
385 this.setServerDataVersion(someUserDetails['version'])
386 }
387 },
388
389 //-------------------------------------------------------------------------
390
391 'extractDataWithKey': function(aKey) {
392 var deferredResult;
393
394//MochiKit.Logging.logDebug(">>> Header.extractDataWithKey");
395 deferredResult = new MochiKit.Async.Deferred();
396
397 switch (this.serverDataFormat()) {
398 case 'LEGACY':
399//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("Header.extractDataWithKey 1: "/* + res*/); return res;});
400//deferredResult.addErrback(function(res) {MochiKit.Logging.logDebug("ERROR: " + res); return res;});
401 deferredResult.addCallback(MochiKit.Base.method(this, 'decryptedLegacyServerData'));
402//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("Header.extractDataWithKey 2: "/* + res*/); return res;});
403//deferredResult.addErrback(function(res) {MochiKit.Logging.logDebug("ERROR: " + res); return res;});
404 deferredResult.addCallback(function(someDecryptedValues) {
405 return someDecryptedValues[aKey] || {};
406 })
407//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("Header.extractDataWithKey 3: "/* + res*/); return res;});
408//deferredResult.addErrback(function(res) {MochiKit.Logging.logDebug("ERROR: " + res); return res;});
409 break;
410 case '0.1':
411 var data;
412
413 //# data = Clipperz.Base.evalJSON(this.serverData());
414 data = this.jsonEvaledServerData();
415 if (typeof(data[aKey]) != 'undefined') {
416//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("Header.extractDataWithKey 4: "/* + res*/); return res;});
417//deferredResult.addErrback(function(res) {MochiKit.Logging.logDebug("ERROR: " + res); return res;});
418 deferredResult.addCallback(Clipperz.NotificationCenter.deferredNotification, this, 'updatedProgressState', 'connection_decryptingUserData');
419//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("Header.extractDataWithKey 5: "/* + res*/); return res;});
420//deferredResult.addErrback(function(res) {MochiKit.Logging.logDebug("ERROR: " + res); return res;});
421 deferredResult.addCallback(Clipperz.PM.Crypto.deferredDecrypt, this.user().passphrase(), data[aKey]['data'], this.serverDataVersion());
422//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("Header.extractDataWithKey 6: "/* + res*/); return res;});
423//deferredResult.addErrback(function(res) {MochiKit.Logging.logDebug("ERROR: " + res); return res;});
424 deferredResult.addCallback(function(/*anHeader,*/ aKey, aData, aRecordIndex, aValue) {
425 var result;
426//MochiKit.Logging.logDebug(">>> [start] ===============================================");
427//MochiKit.Logging.logDebug("--- extractDataWithKey - 0 [" + aKey + "]: " + Clipperz.Base.serializeJSON(aValue));
428//MochiKit.Logging.logDebug("<<< [end] =================================================");
429 if (aKey == 'records') {
430 var recordKey;
431
432 result = {};
433 for (recordKey in aData['index']) {
434 result[recordKey] = aValue[aData['index'][recordKey]];
435 }
436 } else if (aKey == 'directLogins') {
437 varrecordKeyReversedIndex;
438 var recordKey;
439 var directLoginKey;
440
441 result = {};
442 recordKeyReversedIndex = {};
443
444 for (recordKey in aRecordIndex) {
445 recordKeyReversedIndex[aRecordIndex[recordKey]] = recordKey;
446 }
447
448//MochiKit.Logging.logDebug("--- extractDataWithKey - 1 - aData['index']: " + Clipperz.Base.serializeJSON(aData['index']));
449 for (directLoginKey in aData['index']) {
450try {
451 if ((aData['index'][directLoginKey] != null) && (aValue[aData['index'][directLoginKey]] != null)) {
452 result[directLoginKey] = aValue[aData['index'][directLoginKey]];
453 result[directLoginKey]['record'] = recordKeyReversedIndex[result[directLoginKey]['record']];
454 }
455} catch(exception) {
456 //result[directLoginKey] has no properties
457 MochiKit.Logging.logDebug("[Header 391] EXCEPTION: " + exception);
458 throw exception;
459}
460 }
461//MochiKit.Logging.logDebug("--- extractDataWithKey - 2");
462 } else {
463 result = aValue;
464 }
465
466 return result;
467 }, /*this,*/ aKey, data[aKey], data['records']['index']);
468//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("Header.extractDataWithKey 6: "/* + res*/); return res;});
469//deferredResult.addErrback(function(res) {MochiKit.Logging.logDebug("ERROR: " + res); return res;});
470 } else {
471//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("Header.extractDataWithKey 7: "/* + res*/); return res;});
472//deferredResult.addErrback(function(res) {MochiKit.Logging.logDebug("ERROR: " + res); return res;});
473 deferredResult.addCallback(MochiKit.Async.succeed, {});
474//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("Header.extractDataWithKey 8: "/* + res*/); return res;});
475//deferredResult.addErrback(function(res) {MochiKit.Logging.logDebug("ERROR: " + res); return res;});
476 }
477 break;
478 }
479
480//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("Header.extractDataWithKey 9: "/* + res*/); return res;});
481//deferredResult.addErrback(function(res) {MochiKit.Logging.logDebug("ERROR: " + res); return res;});
482 deferredResult.callback();
483//MochiKit.Logging.logDebug("<<< Header.extractDataWithKey");
484
485 return deferredResult;
486 },
487
488 //-------------------------------------------------------------------------
489
490 'processRecordData': function(someRecordData) {
491 var records;
492 varrecordReference;
493
494//console.log("HeaderRecordData parameters", someRecordData);
495//MochiKit.Logging.logDebug(">>> Header.processRecordData");
496 records = someRecordData;
497//MochiKit.Logging.logDebug("--- Header.processRecordData - 1");
498 if (records != null) {
499//MochiKit.Logging.logDebug("--- Header.processRecordData - records: " + Clipperz.Base.serializeJSON(records));
500 for (recordReference in records) {
501 var newRecord;
502 var parameters;
503
504//MochiKit.Logging.logDebug("--- Header.processRecordData - 2 - recordReference: " + recordReference);
505 if (recordReference != "stacktrace") {
506 parameters = records[recordReference];//.slice();
507//MochiKit.Logging.logDebug("--- Header.processRecordData - 3");
508 if (typeof(parameters['notes']) != 'undefined') {
509//MochiKit.Logging.logDebug("--- Header.processRecordData - 4");
510 if (parameters['notes'] != "") {
511//MochiKit.Logging.logDebug("--- Header.processRecordData - 5");
512 parameters['headerNotes'] = parameters['notes'];
513//MochiKit.Logging.logDebug("--- Header.processRecordData - 6");
514 }
515//MochiKit.Logging.logDebug("--- Header.processRecordData - 7");
516 delete parameters['notes'];
517//MochiKit.Logging.logDebug("--- Header.processRecordData - 8");
518 }
519//MochiKit.Logging.logDebug("--- Header.processRecordData - 9");
520 parameters['reference'] = recordReference;
521//MochiKit.Logging.logDebug("--- Header.processRecordData - 10");
522 parameters['user'] = this.user();
523//MochiKit.Logging.logDebug("--- Header.processRecordData - 11");
524
525 newRecord = new Clipperz.PM.DataModel.Record(parameters);
526//MochiKit.Logging.logDebug("--- Header.processRecordData - 12");
527 this.user().addRecord(newRecord, true);
528//MochiKit.Logging.logDebug("--- Header.processRecordData - 13");
529 }
530 }
531
532//MochiKit.Logging.logDebug("--- Header.processRecordData - 14");
533 Clipperz.NotificationCenter.notify(null, 'recordAdded', null, true);
534//MochiKit.Logging.logDebug("--- Header.processRecordData - 15");
535 }
536//MochiKit.Logging.logDebug("<<< Header.processRecordData");
537
538 return this.user().records();
539 },
540
541 //-------------------------------------------------------------------------
542
543 'processDirectLoginData': function(someDirectLoginData) {
544 var directLogins;
545 var directLoginReference;
546
547//MochiKit.Logging.logDebug(">>> Header.processDirectLoginData");
548 directLogins = someDirectLoginData;
549 if (directLogins != null) {
550 for (directLoginReference in directLogins) {
551 var directLoginReference;
552 var parameters;
553
554 parameters = directLogins[directLoginReference];//.slice();
555 parameters.user = this.user();
556 parameters.reference = directLoginReference;
557 directLoginReference = new Clipperz.PM.DataModel.DirectLoginReference(parameters);
558 if (directLoginReference.record() != null) {
559 this.user().addDirectLoginReference(directLoginReference, true);
560 }
561 }
562 }
563
564 Clipperz.NotificationCenter.notify(null, 'directLoginAdded', null, true);
565//MochiKit.Logging.logDebug("<<< Header.processDirectLoginData");
566
567 return this.user().directLoginReferences();
568 },
569
570 //-------------------------------------------------------------------------
571
572 'shouldLoadSections': function() {
573 return this._shouldLoadSections;
574 },
575
576 'shouldLoadSection': function(aSectionName) {
577 var result;
578
579 if (typeof(this.shouldLoadSections()[aSectionName]) != 'undefined') {
580 result = this.shouldLoadSections()[aSectionName];
581 } else {
582 result = true;
583 }
584
585 return result;
586 },
587
588 'setShouldLoadSection': function(aSectionName, aValue) {
589 this.shouldLoadSections()[aSectionName] = aValue;
590 },
591
592 //-------------------------------------------------------------------------
593
594 'loadRecords': function() {
595 var deferredResult;
596
597 if (this.shouldLoadSection('records') == true) {
598 this.setShouldLoadSection('records', false);
599
600 deferredResult = new MochiKit.Async.Deferred();
601//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("Header.loadRecords 1: "/* + res*/); return res;});
602//deferredResult.addErrback(function(res) {MochiKit.Logging.logDebug("ERROR: " + res); return res;});
603 deferredResult.addCallback(MochiKit.Base.method(this.user(), 'getUserDetails'));
604//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("Header.loadRecords 2: "/* + res*/); return res;});
605//deferredResult.addErrback(function(res) {MochiKit.Logging.logDebug("ERROR: " + res); return res;});
606 deferredResult.addCallback(MochiKit.Base.method(this, 'extractHeaderDataFromUserDetails'));
607//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("Header.loadRecords 3: "/* + res*/); return res;});
608//deferredResult.addErrback(function(res) {MochiKit.Logging.logDebug("ERROR: " + res); return res;});
609 deferredResult.addCallback(MochiKit.Base.method(this, 'extractDataWithKey', 'records'));
610//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("Header.loadRecords 4: "/* + res*/); return res;});
611//deferredResult.addErrback(function(res) {MochiKit.Logging.logDebug("ERROR: " + res); return res;});
612 deferredResult.addCallback(MochiKit.Base.method(this, 'processRecordData'));
613//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("Header.loadRecords 5: "/* + res*/); return res;});
614//deferredResult.addErrback(function(res) {MochiKit.Logging.logDebug("ERROR: " + res); return res;});
615 deferredResult.callback();
616 } else {
617 deferredResult = MochiKit.Async.succeed(this.user().records());
618 }
619
620 return deferredResult;
621 },
622
623 //-------------------------------------------------------------------------
624
625 'loadDirectLogins': function() {
626 var deferredResult;
627
628 if (this.shouldLoadSection('directLogins') == true) {
629 this.setShouldLoadSection('directLogins', false);
630
631 deferredResult = new MochiKit.Async.Deferred();
632//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("Header.loadDirectLogins - 1: "/* + res*/); return res;});
633//deferredResult.addErrback(function(res) {MochiKit.Logging.logDebug("ERROR: " + res); return res;});
634 deferredResult.addCallback(MochiKit.Base.method(this.user(), 'getUserDetails'));
635//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("Header.loadDirectLogins - 2: "/* + res*/); return res;});
636//deferredResult.addErrback(function(res) {MochiKit.Logging.logDebug("ERROR: " + res); return res;});
637 deferredResult.addCallback(MochiKit.Base.method(this, 'extractHeaderDataFromUserDetails'));
638//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("Header.loadDirectLogins - 3: "/* + res*/); return res;});
639//deferredResult.addErrback(function(res) {MochiKit.Logging.logDebug("ERROR: " + res); return res;});
640 deferredResult.addCallback(MochiKit.Base.method(this, 'extractDataWithKey', 'directLogins'));
641//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("Header.loadDirectLogins - 4: "/* + res*/); return res;});
642//deferredResult.addErrback(function(res) {MochiKit.Logging.logDebug("ERROR: " + res); return res;});
643 deferredResult.addCallback(MochiKit.Base.method(this, 'processDirectLoginData'));
644//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("Header.loadDirectLogins - 5: "/* + res*/); return res;});
645//deferredResult.addErrback(function(res) {MochiKit.Logging.logDebug("ERROR: " + res); return res;});
646 deferredResult.callback();
647 } else {
648 deferredResult = MochiKit.Async.succeed(this.user().directLoginReferences());
649 }
650
651 return deferredResult;
652 },
653
654 //-------------------------------------------------------------------------
655
656 'loadPreferences': function() {
657 var deferredResult;
658
659 if (this.shouldLoadSection('preferences') == true) {
660 this.setShouldLoadSection('preferences', false);
661
662 deferredResult = new MochiKit.Async.Deferred();
663//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("Header.loadPreferences - 1: "/* + res*/); return res;});
664//deferredResult.addErrback(function(res) {MochiKit.Logging.logDebug("ERROR: " + res); return res;});
665 deferredResult.addCallback(MochiKit.Base.method(this.user(), 'getUserDetails'));
666//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("Header.loadPreferences - 2: "/* + res*/); return res;});
667//deferredResult.addErrback(function(res) {MochiKit.Logging.logDebug("ERROR: " + res); return res;});
668 deferredResult.addCallback(MochiKit.Base.method(this, 'extractHeaderDataFromUserDetails'));
669//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("Header.loadPreferences - 3: "/* + res*/); return res;});
670//deferredResult.addErrback(function(res) {MochiKit.Logging.logDebug("ERROR: " + res); return res;});
671 deferredResult.addCallback(MochiKit.Base.method(this, 'extractDataWithKey', 'preferences'));
672//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("Header.loadPreferences - 4: "/* + res*/); return res;});
673//deferredResult.addErrback(function(res) {MochiKit.Logging.logDebug("ERROR: " + res); return res;});
674 deferredResult.addCallback(MochiKit.Base.method(this.user().preferences(), 'updateWithData'));
675//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("Header.loadPreferences - 5: "/* + res*/); return res;});
676//deferredResult.addErrback(function(res) {MochiKit.Logging.logDebug("ERROR: " + res); return res;});
677 deferredResult.callback();
678 } else {
679 deferredResult = MochiKit.Async.succeed(this.user().preferences());
680 }
681
682 return deferredResult;
683 },
684
685 //-------------------------------------------------------------------------
686
687 'loadOneTimePasswords': function() {
688 var deferredResult;
689
690 if (this.shouldLoadSection('oneTimePasswords') == true) {
691 this.setShouldLoadSection('oneTimePasswords', false);
692
693 deferredResult = new MochiKit.Async.Deferred();
694//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("Header.loadOneTimePasswords - 1: "/* + res*/); return res;});
695//deferredResult.addErrback(function(res) {MochiKit.Logging.logDebug("ERROR: " + res); return res;});
696 deferredResult.addCallback(MochiKit.Base.method(this.user(), 'getUserDetails'));
697//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("Header.loadOneTimePasswords - 2: "/* + res*/); return res;});
698//deferredResult.addErrback(function(res) {MochiKit.Logging.logDebug("ERROR: " + res); return res;});
699 deferredResult.addCallback(MochiKit.Base.method(this, 'extractHeaderDataFromUserDetails'));
700//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("Header.loadOneTimePasswords - 3: "/* + res*/); return res;});
701//deferredResult.addErrback(function(res) {MochiKit.Logging.logDebug("ERROR: " + res); return res;});
702 deferredResult.addCallback(MochiKit.Base.method(this, 'extractDataWithKey', 'oneTimePasswords'));
703//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("Header.loadOneTimePasswords - 4: "/* + res*/); return res;});
704//deferredResult.addErrback(function(res) {MochiKit.Logging.logDebug("ERROR: " + res); return res;});
705 deferredResult.addCallback(MochiKit.Base.method(this.user().oneTimePasswordManager(), 'updateWithData'));
706//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("Header.loadOneTimePasswords - 5: "/* + res*/); return res;});
707//deferredResult.addErrback(function(res) {MochiKit.Logging.logDebug("ERROR: " + res); return res;});
708 deferredResult.addCallback(MochiKit.Base.method(this.user().connection(), 'message'), 'getOneTimePasswordsDetails', {});
709//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("Header.loadOneTimePasswords - 6: "/* + res*/); return res;});
710//deferredResult.addErrback(function(res) {MochiKit.Logging.logDebug("ERROR: " + res); return res;});
711 deferredResult.addCallback(MochiKit.Base.method(this.user().oneTimePasswordManager(), 'updateWithServerData'));
712//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("Header.loadOneTimePasswords - 7: "/* + res*/); return res;});
713//deferredResult.addErrback(function(res) {MochiKit.Logging.logDebug("ERROR: " + res); return res;});
714 deferredResult.callback();
715 } else {
716 deferredResult = MochiKit.Async.succeed(this.user().oneTimePasswordManager());
717 }
718
719 return deferredResult;
720 },
721
722 //-------------------------------------------------------------------------
723
724 'loadAllSections': function() {
725 var deferredResult;
726
727 deferredResult = new MochiKit.Async.Deferred();
728//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("Header.loadAllSections - 1: "/* + res*/); return res;});
729//deferredResult.addErrback(function(res) {MochiKit.Logging.logDebug("ERROR: " + res); return res;});
730 deferredResult.addCallback(MochiKit.Base.method(this, 'loadRecords'));
731//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("Header.loadAllSections - 2: "/* + res*/); return res;});
732//deferredResult.addErrback(function(res) {MochiKit.Logging.logDebug("ERROR: " + res); return res;});
733 deferredResult.addCallback(MochiKit.Base.method(this, 'loadDirectLogins'));
734//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("Header.loadAllSections - 3: "/* + res*/); return res;});
735//deferredResult.addErrback(function(res) {MochiKit.Logging.logDebug("ERROR: " + res); return res;});
736 deferredResult.addCallback(MochiKit.Base.method(this, 'loadPreferences'));
737//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("Header.loadAllSections - 4: "/* + res*/); return res;});
738//deferredResult.addErrback(function(res) {MochiKit.Logging.logDebug("ERROR: " + res); return res;});
739 deferredResult.addCallback(MochiKit.Base.method(this, 'loadOneTimePasswords'));
740//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("Header.loadAllSections - 5: "/* + res*/); return res;});
741//deferredResult.addErrback(function(res) {MochiKit.Logging.logDebug("ERROR: " + res); return res;});
742 deferredResult.callback();
743
744 return deferredResult;
745 },
746
747 //-------------------------------------------------------------------------
748 __syntaxFix__: "syntax fix"
749
750});
751
diff --git a/frontend/beta/js/Clipperz/PM/DataModel/OneTimePassword.js b/frontend/beta/js/Clipperz/PM/DataModel/OneTimePassword.js
new file mode 100644
index 0000000..dd8d5c9
--- a/dev/null
+++ b/frontend/beta/js/Clipperz/PM/DataModel/OneTimePassword.js
@@ -0,0 +1,333 @@
1/*
2
3Copyright 2008-2011 Clipperz Srl
4
5This file is part of Clipperz's Javascript Crypto Library.
6Javascript Crypto Library provides web developers with an extensive
7and efficient set of cryptographic functions. The library aims to
8obtain maximum execution speed while preserving modularity and
9reusability.
10For further information about its features and functionalities please
11refer to http://www.clipperz.com
12
13* Javascript Crypto Library is free software: you can redistribute
14 it and/or modify it under the terms of the GNU Affero General Public
15 License as published by the Free Software Foundation, either version
16 3 of the License, or (at your option) any later version.
17
18* Javascript Crypto Library is distributed in the hope that it will
19 be useful, but WITHOUT ANY WARRANTY; without even the implied
20 warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
21 See the GNU Affero General Public License for more details.
22
23* You should have received a copy of the GNU Affero General Public
24 License along with Javascript Crypto Library. If not, see
25 <http://www.gnu.org/licenses/>.
26
27*/
28
29if (typeof(Clipperz) == 'undefined') { Clipperz = {}; }
30if (typeof(Clipperz.PM) == 'undefined') { Clipperz.PM = {}; }
31if (typeof(Clipperz.PM.DataModel) == 'undefined') { Clipperz.PM.DataModel = {}; }
32
33
34//#############################################################################
35
36Clipperz.PM.DataModel.OneTimePassword = function(args) {
37 args = args || {};
38
39//console.log("new OneTimePassword", args);
40//MochiKit.Logging.logDebug("---");
41 this._user = args['user'];
42 this._password = args['password'];
43 this._passwordValue = Clipperz.PM.DataModel.OneTimePassword.normalizedOneTimePassword(args['password']);
44 this._reference = args['reference'] || Clipperz.PM.Crypto.randomKey();
45 this._creationDate = args['created'] ? Clipperz.PM.Date.parseDateWithUTCFormat(args['created']) : new Date();
46 this._usageDate = args['used'] ? Clipperz.PM.Date.parseDateWithUTCFormat(args['used']) : null;
47
48 this._status = args['status'] || 'ACTIVE';
49 this._connectionInfo = null;
50
51 this._key = null;
52 this._keyChecksum = null;
53
54 return this;
55}
56
57Clipperz.PM.DataModel.OneTimePassword.prototype = MochiKit.Base.update(null, {
58
59 'toString': function() {
60 return "Clipperz.PM.DataModel.OneTimePassword";
61 },
62
63 //-------------------------------------------------------------------------
64
65 'user': function() {
66 return this._user;
67 },
68
69 //-------------------------------------------------------------------------
70
71 'password': function() {
72 return this._password;
73 },
74
75 //-------------------------------------------------------------------------
76
77 'passwordValue': function() {
78 return this._passwordValue;
79 },
80
81 //-------------------------------------------------------------------------
82
83 'creationDate': function() {
84 return this._creationDate;
85 },
86
87 //-------------------------------------------------------------------------
88
89 'reference': function() {
90 return this._reference;
91 },
92
93 //-------------------------------------------------------------------------
94
95 'key': function() {
96 if (this._key == null) {
97 this._key = Clipperz.PM.DataModel.OneTimePassword.computeKeyWithUsernameAndPassword(this.user().username(), this.passwordValue());
98 }
99
100 return this._key;
101 },
102
103 //-------------------------------------------------------------------------
104
105 'keyChecksum': function() {
106 if (this._keyChecksum == null) {
107 this._keyChecksum = Clipperz.PM.DataModel.OneTimePassword.computeKeyChecksumWithUsernameAndPassword(this.user().username(), this.passwordValue());
108 }
109
110 return this._keyChecksum;
111 },
112
113 //-------------------------------------------------------------------------
114
115 'status': function() {
116 return this._status;
117 },
118
119 'setStatus': function(aValue) {
120 this._status = aValue;
121 },
122
123 //-------------------------------------------------------------------------
124
125 'serializedData': function() {
126 var result;
127
128 result = {
129 'password': this.password(),
130 'created': this.creationDate() ? Clipperz.PM.Date.formatDateWithUTCFormat(this.creationDate()) : null,
131 'used': this.usageDate() ? Clipperz.PM.Date.formatDateWithUTCFormat(this.usageDate()) : null,
132 'status': this.status()
133 };
134
135 return result;
136 },
137
138 //-------------------------------------------------------------------------
139
140 'packedPassphrase': function() {
141 var result;
142 var packedPassphrase;
143 var encodedPassphrase;
144 varprefixPadding;
145 var suffixPadding;
146 var getRandomBytes;
147
148 getRandomBytes = MochiKit.Base.method(Clipperz.Crypto.PRNG.defaultRandomGenerator(), 'getRandomBytes');
149
150 encodedPassphrase = new Clipperz.ByteArray(this.user().passphrase()).toBase64String();
151//MochiKit.Logging.logDebug("--- encodedPassphrase.length: " + encodedPassphrase.length);
152 prefixPadding = getRandomBytes(getRandomBytes(1).byteAtIndex(0)).toBase64String();
153//MochiKit.Logging.logDebug("--- prefixPadding.length: " + prefixPadding.length);
154 suffixPadding = getRandomBytes((500 - prefixPadding.length - encodedPassphrase.length) * 6 / 8).toBase64String();
155//MochiKit.Logging.logDebug("--- suffixPadding.length: " + suffixPadding.length);
156//MochiKit.Logging.logDebug("--- total.length: " + (prefixPadding.length + encodedPassphrase.length + suffixPadding.length));
157
158 packedPassphrase = {
159 'prefix': prefixPadding,
160 'passphrase': encodedPassphrase,
161 'suffix': suffixPadding
162 };
163
164 // result = Clipperz.Base.serializeJSON(packedPassphrase);
165 result = packedPassphrase;
166//MochiKit.Logging.logDebug("===== OTP packedPassprase: [" + result.length + "]" + result);
167//MochiKit.Logging.logDebug("<<< OneTimePassword.packedPassphrase");
168
169 return result;
170 },
171
172 //-------------------------------------------------------------------------
173
174 'encryptedPackedPassphrase': function() {
175 return Clipperz.PM.Crypto.deferredEncryptWithCurrentVersion(this.passwordValue(), this.packedPassphrase())
176 },
177
178 //-------------------------------------------------------------------------
179
180 'encryptedData': function() {
181 var deferredResult;
182 varresult;
183
184//MochiKit.Logging.logDebug(">>> OneTimePassword.encryptedData");
185//MochiKit.Logging.logDebug("--- OneTimePassword.encryptedData - id: " + this.reference());
186 result = {
187 'reference': this.reference(),
188 'key': this.key(),
189 'keyChecksum': this.keyChecksum(),
190 'data': "",
191 'version': Clipperz.PM.Crypto.encryptingFunctions.currentVersion
192 }
193//MochiKit.Logging.logDebug("--- OneTimePassword.encryptedData - 2: " + Clipperz.Base.serializeJSON(result));
194 deferredResult = new MochiKit.Async.Deferred();
195//MochiKit.Logging.logDebug("--- OneTimePassword.encryptedData - 3");
196//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("OneTimePassword.encryptedData - 1: " + res); return res;});
197 //# deferredResult.addCallback(Clipperz.PM.Crypto.deferredEncryptWithCurrentVersion, this.passwordValue(), this.packedPassphrase());
198 deferredResult.addCallback(MochiKit.Base.method(this, 'encryptedPackedPassphrase'));
199//MochiKit.Logging.logDebug("--- OneTimePassword.encryptedData - 4");
200//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("OneTimePassword.encryptedData - 2: [" + res.length + "]" + res); return res;});
201 deferredResult.addCallback(function(aResult, res) {
202 aResult['data'] = res;
203 return aResult;
204 }, result);
205//MochiKit.Logging.logDebug("--- OneTimePassword.encryptedData - 5");
206//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("OneTimePassword.encryptedData - 3: " + Clipperz.Base.serializeJSON(res)); return res;});
207 deferredResult.callback();
208//MochiKit.Logging.logDebug("--- OneTimePassword.encryptedData - 6");
209
210 return deferredResult;
211 },
212
213 //-------------------------------------------------------------------------
214
215 'saveChanges': function() {
216 var deferredResult;
217 varresult;
218
219//MochiKit.Logging.logDebug(">>> OneTimePassword.saveChanges");
220 result = {};
221 deferredResult = new MochiKit.Async.Deferred();
222
223 deferredResult.addCallback(Clipperz.NotificationCenter.deferredNotification, this, 'updatedProgressState', 'saveOTP_encryptUserData');
224 deferredResult.addCallback(MochiKit.Base.method(this.user(), 'encryptedData'));
225 deferredResult.addCallback(function(aResult, res) {
226 aResult['user'] = res;
227 return aResult;
228 }, result);
229
230 deferredResult.addCallback(Clipperz.NotificationCenter.deferredNotification, this, 'updatedProgressState', 'saveOTP_encryptOTPData');
231 deferredResult.addCallback(MochiKit.Base.method(this, 'encryptedData'));
232 deferredResult.addCallback(function(aResult, res) {
233 aResult['oneTimePassword'] = res;
234 return aResult;
235 }, result);
236
237 deferredResult.addCallback(Clipperz.NotificationCenter.deferredNotification, this, 'updatedProgressState', 'saveOTP_sendingData');
238//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("OneTimePassword.saveChanges - 1: " + Clipperz.Base.serializeJSON(res)); return res;});
239 deferredResult.addCallback(MochiKit.Base.method(this.user().connection(), 'message'), 'addNewOneTimePassword');
240
241 deferredResult.addCallback(Clipperz.NotificationCenter.deferredNotification, this, 'updatedProgressState', 'saveOTP_updatingInterface');
242//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("OneTimePassword.saveChanges - 2: " + res); return res;});
243 deferredResult.addCallback(Clipperz.NotificationCenter.deferredNotification, this, 'notify', 'OTPUpdated');
244 deferredResult.addCallback(Clipperz.NotificationCenter.deferredNotification, this, 'oneTimePassword_saveChanges_done', null);
245//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("OneTimePassword.saveChanges - 2: " + res); return res;});
246 deferredResult.callback();
247//MochiKit.Logging.logDebug("<<< OneTimePassword.saveChanges");
248
249 return deferredResult;
250 },
251
252 //-------------------------------------------------------------------------
253
254 'usageDate': function() {
255 return this._usageDate;
256 },
257
258 'setUsageDate': function(aValue) {
259 this._usageDate = aValue;
260 },
261
262 //-------------------------------------------------------------------------
263
264 'connectionInfo': function() {
265 return this._connectionInfo;
266 },
267
268 'setConnectionInfo': function(aValue) {
269 this._connectionInfo = aValue;
270 },
271
272 //-------------------------------------------------------------------------
273
274 'isExpired': function() {
275 return (this.usageDate() != null);
276 },
277
278 //-------------------------------------------------------------------------
279
280 'updateStatusWithValues': function(someValues) {
281 var result;
282
283 result = false;
284
285 if (someValues['status'] != this.status()) {
286 result = true;
287 }
288
289 this.setStatus(someValues['status']);
290 this.setUsageDate(Clipperz.PM.Date.parseDateWithUTCFormat(someValues['requestDate']));
291 this.setConnectionInfo(someValues['connection']);
292
293 return result;
294 },
295
296 //-------------------------------------------------------------------------
297 __syntaxFix__: "syntax fix"
298});
299
300//=============================================================================
301
302Clipperz.PM.DataModel.OneTimePassword.computeKeyWithUsernameAndPassword = function(anUsername, aPassword) {
303 return Clipperz.Crypto.SHA.sha_d256(new Clipperz.ByteArray(aPassword)).toHexString().substring(2);
304}
305
306Clipperz.PM.DataModel.OneTimePassword.computeKeyChecksumWithUsernameAndPassword = function(anUsername, aPassword) {
307 return Clipperz.Crypto.SHA.sha_d256(new Clipperz.ByteArray(anUsername + aPassword)).toHexString().substring(2);
308}
309
310//=============================================================================
311
312Clipperz.PM.DataModel.OneTimePassword.normalizedOneTimePassword = function(aPassword) {
313 varresult;
314
315 if (aPassword.replace(/[\s\-]/g, '').length == 32) {
316 try {
317 var passwordByteArray;
318
319 passwordByteArray = new Clipperz.ByteArray();
320 passwordByteArray.appendBase32String(aPassword);
321
322 result = passwordByteArray.toBase64String();
323 } catch(exception) {
324 result = aPassword;
325 }
326 } else {
327 result = aPassword;
328 }
329
330 return result;
331}
332
333//=============================================================================
diff --git a/frontend/beta/js/Clipperz/PM/DataModel/OneTimePasswordManager.js b/frontend/beta/js/Clipperz/PM/DataModel/OneTimePasswordManager.js
new file mode 100644
index 0000000..d90100a
--- a/dev/null
+++ b/frontend/beta/js/Clipperz/PM/DataModel/OneTimePasswordManager.js
@@ -0,0 +1,280 @@
1/*
2
3Copyright 2008-2011 Clipperz Srl
4
5This file is part of Clipperz's Javascript Crypto Library.
6Javascript Crypto Library provides web developers with an extensive
7and efficient set of cryptographic functions. The library aims to
8obtain maximum execution speed while preserving modularity and
9reusability.
10For further information about its features and functionalities please
11refer to http://www.clipperz.com
12
13* Javascript Crypto Library is free software: you can redistribute
14 it and/or modify it under the terms of the GNU Affero General Public
15 License as published by the Free Software Foundation, either version
16 3 of the License, or (at your option) any later version.
17
18* Javascript Crypto Library is distributed in the hope that it will
19 be useful, but WITHOUT ANY WARRANTY; without even the implied
20 warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
21 See the GNU Affero General Public License for more details.
22
23* You should have received a copy of the GNU Affero General Public
24 License along with Javascript Crypto Library. If not, see
25 <http://www.gnu.org/licenses/>.
26
27*/
28
29if (typeof(Clipperz) == 'undefined') { Clipperz = {}; }
30if (typeof(Clipperz.PM) == 'undefined') { Clipperz.PM = {}; }
31if (typeof(Clipperz.PM.DataModel) == 'undefined') { Clipperz.PM.DataModel = {}; }
32
33
34//#############################################################################
35
36Clipperz.PM.DataModel.OneTimePasswordManager = function(anUser, args) {
37 args = args || {};
38
39 this._user = anUser;
40 this._oneTimePasswords = {};
41
42 this.updateWithData(args);
43
44 Clipperz.NotificationCenter.notify(null, 'oneTimePasswordAdded', null, true);
45
46 return this;
47}
48
49Clipperz.PM.DataModel.OneTimePasswordManager.prototype = MochiKit.Base.update(null, {
50
51 'toString': function() {
52 return "Clipperz.PM.DataModel.OneTimePasswordManager";
53 },
54
55 //-------------------------------------------------------------------------
56
57 'updateWithData': function(someValues) {
58 varotpReference;
59
60//console.log("OneTimePasswordManager.updateWithData", someValues);
61//MochiKit.Logging.logDebug("OneTimePasswordManager.updateWithData: " + Clipperz.Base.serializeJSON(someValues));
62 for (otpReference in someValues) {
63 var otp;
64 var otpConfiguration;
65
66 otpConfiguration = someValues[otpReference];
67 otpConfiguration['user'] = this.user();
68 otpConfiguration['reference'] = otpReference;
69 otp = new Clipperz.PM.DataModel.OneTimePassword(otpConfiguration);
70 this._oneTimePasswords[otpReference] = otp;
71 }
72
73 return this;
74 },
75
76 //-------------------------------------------------------------------------
77
78 'updateWithServerData': function(someValues) {
79 var deferredResult;
80 varoneTimePasswordReference;
81 var wereChangesApplied;
82
83//MochiKit.Logging.logDebug(">>> OneTimePasswordManager.updateWithServerData");
84 deferredResult = new MochiKit.Async.Deferred();
85 wereChangesApplied = false;
86
87 for (oneTimePasswordReference in someValues) {
88 var oneTimePassword;
89
90 oneTimePassword = this.oneTimePasswordWithReference(oneTimePasswordReference);
91 if (oneTimePassword != null) {
92 var oneTimePasswordHasBeenUpdated;
93
94 oneTimePasswordHasBeenUpdated = oneTimePassword.updateStatusWithValues(someValues[oneTimePasswordReference]);
95 wereChangesApplied = oneTimePasswordHasBeenUpdated || wereChangesApplied;
96 } else {
97
98 }
99 }
100
101 if (wereChangesApplied == true) {
102 this.user().header().markSectionAsUpdated('oneTimePasswords');
103 }
104
105 for (oneTimePasswordReference in this.oneTimePasswords()) {
106 if (typeof(someValues[oneTimePasswordReference]) == 'undefind') {
107 deferredResult.addCallback(MochiKit.Base.method(this.oneTimePasswordWithReference(oneTimePasswordReference), 'saveChanges'));
108 }
109 }
110
111 deferredResult.addCallback(MochiKit.Async.succeed, this);
112
113 deferredResult.callback();
114//MochiKit.Logging.logDebug("<<< OneTimePasswordManager.updateWithServerData");
115
116 return deferredResult;
117 },
118
119 //-------------------------------------------------------------------------
120
121 'user': function() {
122 return this._user;
123 },
124
125 //-------------------------------------------------------------------------
126
127 'addOneTimePassword': function(aOneTimePassword, isBatchUpdate) {
128 this.oneTimePasswords()[aOneTimePassword.reference()] = aOneTimePassword;
129
130 if (isBatchUpdate != true) {
131 Clipperz.NotificationCenter.notify(aOneTimePassword, 'oneTimePasswordAdded');
132 Clipperz.NotificationCenter.notify(this.user(), 'updatedSection', 'oneTimePasswords', true);
133 }
134 },
135
136 //-------------------------------------------------------------------------
137
138 'archiveOneTimePassword': function(aOneTimePasswordReference) {
139 var deferredResult;
140
141//MochiKit.Logging.logDebug(">>> OneTimePasswordManager.archiveOneTimePassword");
142//MochiKit.Logging.logDebug("--- OneTimePasswordManager.archiveOneTimePassword - 0 otp.reference: " + aOneTimePasswordReference);
143 deferredResult = new MochiKit.Async.Deferred();
144 deferredResult.addCallback(MochiKit.Base.method(this.user(), 'loadOneTimePasswords'));
145 deferredResult.addCallback(MochiKit.Base.bind(function(aOneTimePasswordReference) {
146 var oneTimePassword;
147
148//MochiKit.Logging.logDebug("--- OneTimePasswordManager.archiveOneTimePassword - 1 serializedData: " + Clipperz.Base.serializeJSON(this.serializedData()));
149 oneTimePassword = this.oneTimePasswords()[aOneTimePasswordReference];
150
151 if (oneTimePassword != null) {
152 oneTimePassword.setUsageDate(new Date());
153
154 // while (this.usedOneTimePasswords().length > 10) {
155 // var referenceOfOneTimePasswordToRemove;
156 //
157 // referenceOfOneTimePasswordToRemove = this.usedOneTimePasswords()[0];
158 // delete this.oneTimePasswords()[referenceOfOneTimePasswordToRemove];
159 // this.usedOneTimePasswords().shift();
160 // }
161
162 Clipperz.NotificationCenter.notify(this.user(), 'updatedSection', 'oneTimePasswords', true);
163 } else {
164 MochiKit.Logging.logError("### OneTimePasswordManager.archiveOneTimePassword - the used OneTimePassword has not been found on the index-card. :-(");
165 }
166
167//MochiKit.Logging.logDebug("--- OneTimePasswordManager.archiveOneTimePassword - 2 serializedData: " + Clipperz.Base.serializeJSON(this.serializedData()));
168 }, this), aOneTimePasswordReference);
169 deferredResult.addCallback(MochiKit.Base.method(this, 'saveChanges'));
170 deferredResult.callback();
171//MochiKit.Logging.logDebug("<<< OneTimePasswordManager.archiveOneTimePassword");
172
173 return deferredResult;
174 },
175
176 //-------------------------------------------------------------------------
177
178 'serializedData': function() {
179 var result;
180 varkey;
181
182 result = {};
183
184 for (key in this.oneTimePasswords()) {
185 result[key] = this.oneTimePasswords()[key].serializedData();
186 }
187
188 return result;
189 },
190
191 //-------------------------------------------------------------------------
192
193 'oneTimePasswords': function() {
194 return this._oneTimePasswords;
195 },
196
197 //-------------------------------------------------------------------------
198
199 'oneTimePasswordWithReference': function(aOneTimePasswordReference) {
200 return this.oneTimePasswords()[aOneTimePasswordReference];
201 },
202
203 //-------------------------------------------------------------------------
204
205 'deleteOneTimePasswordWithReference': function(aOneTimePasswordReference) {
206 delete(this.oneTimePasswords()[aOneTimePasswordReference]);
207 Clipperz.NotificationCenter.notify(this.user(), 'updatedSection', 'oneTimePasswords', true);
208 },
209
210 //-------------------------------------------------------------------------
211
212 'encryptedData': function() {
213 var deferredResult;
214 var oneTimePasswordReferences;
215 var result;
216 var i, c;
217
218 result = {};
219 deferredResult = new MochiKit.Async.Deferred();
220 deferredResult.addCallback(MochiKit.Async.succeed);
221
222 oneTimePasswordReferences = MochiKit.Base.keys(this.oneTimePasswords());
223 c = oneTimePasswordReferences.length;
224 for (i=0; i<c; i++) {
225 var currentOneTimePassword;
226
227 currentOneTimePassword = this.oneTimePasswords()[oneTimePasswordReferences[i]];
228 deferredResult.addCallback(MochiKit.Base.method(currentOneTimePassword, 'encryptedPackedPassphrase'));
229 deferredResult.addCallback(function(aResult, aOneTimePasswordReference, anEncryptedPackedPassphrase) {
230 aResult[aOneTimePasswordReference] = anEncryptedPackedPassphrase;
231 return aResult;
232 }, result, oneTimePasswordReferences[i]);
233 }
234//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("OneTimePasswordManager.encryptedData: " + res); return res;});
235
236 deferredResult.callback(result);
237
238 return deferredResult;
239 },
240
241 //-------------------------------------------------------------------------
242
243 'saveChanges': function() {
244 var deferredResult;
245 varresult;
246
247//MochiKit.Logging.logDebug(">>> OneTimePasswordManager.saveChanges");
248 result = {};
249 deferredResult = new MochiKit.Async.Deferred();
250 deferredResult.addCallback(Clipperz.NotificationCenter.deferredNotification, this, 'updatedProgressState', 'saveOTP_encryptUserData');
251 deferredResult.addCallback(MochiKit.Base.method(this.user(), 'encryptedData'));
252 deferredResult.addCallback(function(aResult, res) {
253 aResult['user'] = res;
254 return aResult;
255 }, result);
256
257 deferredResult.addCallback(Clipperz.NotificationCenter.deferredNotification, this, 'updatedProgressState', 'saveOTP_encryptOTPData');
258 deferredResult.addCallback(MochiKit.Base.bind(function(res) {
259 res['oneTimePasswords'] = MochiKit.Base.keys(this.oneTimePasswords());
260 return res;
261 }, this));
262
263 deferredResult.addCallback(Clipperz.NotificationCenter.deferredNotification, this, 'updatedProgressState', 'saveOTP_sendingData');
264//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("OneTimePasswordManager.saveChanges - 1: " + Clipperz.Base.serializeJSON(res)); return res;});
265 deferredResult.addCallback(MochiKit.Base.method(this.user().connection(), 'message'), 'updateOneTimePasswords');
266
267 deferredResult.addCallback(Clipperz.NotificationCenter.deferredNotification, this, 'updatedProgressState', 'saveOTP_updatingInterface');
268//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("OneTimePasswordManager.saveChanges - 2: " + res); return res;});
269 deferredResult.addCallback(Clipperz.NotificationCenter.deferredNotification, this, 'notify', 'OTPUpdated');
270//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("OneTimePasswordManager.saveChanges - 3: " + res); return res;});
271 deferredResult.callback();
272//MochiKit.Logging.logDebug("<<< OneTimePasswordManager.saveChanges");
273
274 return deferredResult;
275 },
276
277 //-------------------------------------------------------------------------
278 __syntaxFix__: "syntax fix"
279});
280
diff --git a/frontend/beta/js/Clipperz/PM/DataModel/Record.js b/frontend/beta/js/Clipperz/PM/DataModel/Record.js
new file mode 100644
index 0000000..b4b5023
--- a/dev/null
+++ b/frontend/beta/js/Clipperz/PM/DataModel/Record.js
@@ -0,0 +1,759 @@
1/*
2
3Copyright 2008-2011 Clipperz Srl
4
5This file is part of Clipperz's Javascript Crypto Library.
6Javascript Crypto Library provides web developers with an extensive
7and efficient set of cryptographic functions. The library aims to
8obtain maximum execution speed while preserving modularity and
9reusability.
10For further information about its features and functionalities please
11refer to http://www.clipperz.com
12
13* Javascript Crypto Library is free software: you can redistribute
14 it and/or modify it under the terms of the GNU Affero General Public
15 License as published by the Free Software Foundation, either version
16 3 of the License, or (at your option) any later version.
17
18* Javascript Crypto Library is distributed in the hope that it will
19 be useful, but WITHOUT ANY WARRANTY; without even the implied
20 warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
21 See the GNU Affero General Public License for more details.
22
23* You should have received a copy of the GNU Affero General Public
24 License along with Javascript Crypto Library. If not, see
25 <http://www.gnu.org/licenses/>.
26
27*/
28
29if (typeof(Clipperz) == 'undefined') { Clipperz = {}; }
30if (typeof(Clipperz.PM) == 'undefined') { Clipperz.PM = {}; }
31if (typeof(Clipperz.PM.DataModel) == 'undefined') { Clipperz.PM.DataModel = {}; }
32
33
34//#############################################################################
35
36Clipperz.PM.DataModel.Record = function(args) {
37 args = args || {};
38
39 this._user = args['user'] || null;
40 this._reference = args['reference'] || Clipperz.PM.Crypto.randomKey();
41 this._version = args['version'] || Clipperz.PM.Crypto.encryptingFunctions.currentVersion;
42 this._key = args['key'] || Clipperz.PM.Crypto.randomKey();
43
44 this.setLabel(args['label'] || Clipperz.PM.Strings['newRecordTitleLabel']);
45
46 this.setHeaderNotes(args['headerNotes'] || null);
47 this.setNotes(args['notes'] || args['headerNotes'] || "");
48//MochiKit.Logging.logDebug("--- new Record ('" + this._label + "')- _headerNotes: '" + this._headerNotes + "'");
49//MochiKit.Logging.logDebug("--- new Record ('" + this._label + "')- _notes: '" + this._notes + "'");
50 //this._notes = args.notes || "";
51
52 this._versions = {};
53 this._directLogins = {};
54 this._removedDirectLogins = [];
55
56 this.setIsBrandNew(args['reference'] == null);
57
58 this.setShouldLoadData(this.isBrandNew() ? false: true);
59 this.setShouldDecryptData(this.isBrandNew() ? false: true);
60 this.setShouldProcessData(this.isBrandNew() ? false: true);
61
62 this.setCurrentVersion(this.isBrandNew() ? new Clipperz.PM.DataModel.RecordVersion(this, null): null);
63 this.setCurrentVersionKey(null);
64
65 this._serverData = null;
66 this._decryptedData = null;
67 this._cachedData = null;
68
69 return this;
70}
71
72Clipperz.PM.DataModel.Record.prototype = MochiKit.Base.update(null, {
73
74 'toString': function() {
75 return "Record (" + this.label() + ")";
76 },
77
78 //-------------------------------------------------------------------------
79
80 'isBrandNew': function() {
81 return this._isBrandNew;
82 },
83
84 'setIsBrandNew': function(aValue) {
85 this._isBrandNew = aValue;
86 },
87
88 //-------------------------------------------------------------------------
89/*
90 'shouldRunTheRecordCreationWizard': function() {
91 return (this.isBrandNew() && (MochiKit.Base.keys(this.currentVersion().fields()).length == 0));
92 },
93 */
94 //-------------------------------------------------------------------------
95
96 'user': function() {
97 return this._user;
98 },
99
100 //-------------------------------------------------------------------------
101
102 'reference': function() {
103 return this._reference;
104 },
105
106 //-------------------------------------------------------------------------
107
108 'key': function() {
109 return this._key;
110 },
111
112 'updateKey': function() {
113 this._key = Clipperz.PM.Crypto.randomKey();
114 },
115
116 //-------------------------------------------------------------------------
117
118 'label': function() {
119 return this._label;
120 },
121
122 'setLabel': function(aValue) {
123 this._label = aValue;
124 },
125
126 'lowerCaseLabel': function() {
127 return this.label().toLowerCase();
128 },
129
130 //-------------------------------------------------------------------------
131
132 'versions': function() {
133 return this._versions;
134 },
135
136 //-------------------------------------------------------------------------
137
138 'currentVersion': function() {
139 return this._currentVersion;
140 },
141
142 'setCurrentVersion': function(aValue) {
143 this._currentVersion = aValue;
144 },
145
146 //-------------------------------------------------------------------------
147
148 'currentVersionKey': function() {
149 return this._currentVersionKey;
150 },
151
152 'setCurrentVersionKey': function(aValue) {
153 this._currentVersionKey = aValue;
154 },
155
156 //-------------------------------------------------------------------------
157
158 'deferredData': function() {
159 vardeferredResult;
160
161//MochiKit.Logging.logDebug(">>> [" + (new Date()).valueOf() + "] Record.deferredData - this: " + this);
162 deferredResult = new MochiKit.Async.Deferred();
163 deferredResult.addCallback(MochiKit.Base.method(this, 'loadData'));
164 deferredResult.addCallback(MochiKit.Base.method(this, 'decryptData'));
165 deferredResult.addCallback(MochiKit.Base.method(this, 'processData'));
166 deferredResult.addCallback(function(aRecord) {
167 return aRecord.currentVersion().deferredData();
168 });
169 deferredResult.addCallback(MochiKit.Base.method(this, 'takeSnapshotOfCurrentData'));
170 deferredResult.addCallback(MochiKit.Async.succeed, this);
171 deferredResult.callback();
172//MochiKit.Logging.logDebug("<<< [" + (new Date()).valueOf() + "] Record.deferredData");
173
174 return deferredResult;
175 },
176
177 //-------------------------------------------------------------------------
178
179 'exportedData': function() {
180 var result;
181
182 result = {};
183 result['label'] = this.label();
184 result['data'] = this.serializedData();
185 result['currentVersion'] = this.currentVersion().serializedData();
186 result['currentVersion']['reference'] = this.currentVersion().reference();
187 // result['versions'] = MochiKit.Base.map(MochiKit.Base.methodcaller("serializedData"), MochiKit.Base.values(this.versions()));
188
189 return Clipperz.Base.serializeJSON(result);
190 },
191
192 //-------------------------------------------------------------------------
193
194 'shouldLoadData': function() {
195 return this._shouldLoadData;
196 },
197
198 'setShouldLoadData': function(aValue) {
199 this._shouldLoadData = aValue;
200 },
201
202 //-------------------------------------------------------------------------
203
204 'shouldDecryptData': function() {
205 return this._shouldDecryptData;
206 },
207
208 'setShouldDecryptData': function(aValue) {
209 this._shouldDecryptData = aValue;
210 },
211
212 //-------------------------------------------------------------------------
213
214 'shouldProcessData': function() {
215 return this._shouldProcessData;
216 },
217
218 'setShouldProcessData': function(aValue) {
219 this._shouldProcessData = aValue;
220 },
221
222 //-------------------------------------------------------------------------
223
224 'loadData': function() {
225 var result;
226
227//MochiKit.Logging.logDebug(">>> [" + (new Date()).valueOf() + "] Record.loadData - this: " + this);
228 if (this.shouldLoadData()) {
229 var deferredResult;
230
231 deferredResult = new MochiKit.Async.Deferred();
232 deferredResult.addCallback(Clipperz.NotificationCenter.deferredNotification, this, 'notify', 'loadingRecordData');
233 deferredResult.addCallback(MochiKit.Base.method(this.user().connection(), 'message'), 'getRecordDetail', {reference: this.reference()});
234 deferredResult.addCallback(MochiKit.Base.method(this,'setServerData'));
235 deferredResult.callback();
236 result = deferredResult;
237 } else {
238 result = MochiKit.Async.succeed(this.serverData());
239 }
240//MochiKit.Logging.logDebug("<<< [" + (new Date()).valueOf() + "] Record.loadData");
241
242 return result;
243 },
244
245 //-------------------------------------------------------------------------
246
247 'decryptData': function(anEncryptedData) {
248 var result;
249
250//MochiKit.Logging.logDebug(">>> [" + (new Date()).valueOf() + "] Record.decryptData - this: " + this + " (" + anEncryptedData + ")");
251 if (this.shouldDecryptData()) {
252 var deferredResult;
253
254 deferredResult = new MochiKit.Async.Deferred();
255 deferredResult.addCallback(Clipperz.NotificationCenter.deferredNotification, this, 'notify', 'decryptingRecordData');
256 deferredResult.addCallback(Clipperz.PM.Crypto.deferredDecrypt, this.key(), anEncryptedData['data'], anEncryptedData['version']);
257 deferredResult.addCallback(function(anEncryptedData, someDecryptedValues) {
258 varresult;
259
260 result = anEncryptedData;
261 result['data'] = someDecryptedValues;
262
263 return result;
264 }, anEncryptedData);
265 deferredResult.addCallback(MochiKit.Base.method(this, 'setDecryptedData'));
266 deferredResult.callback();
267
268 result = deferredResult;
269 } else {
270 result = MochiKit.Async.succeed(this.decryptedData());
271 }
272//MochiKit.Logging.logDebug("<<< [" + (new Date()).valueOf() + "] Record.decryptData");
273
274 return result;
275 },
276
277 //-------------------------------------------------------------------------
278
279 'processData': function(someValues) {
280//MochiKit.Logging.logDebug(">>> [" + (new Date()).valueOf() + "] Record.processData");
281//MochiKit.Logging.logDebug("--- Record.processData: " + Clipperz.Base.serializeJSON(someValues));
282 if (this.shouldProcessData()) {
283 var currentVersionParameters;
284
285 this.processDataToExtractLegacyValues(someValues['data']);
286
287 if (typeof(someValues['data']['notes']) != 'undefined') {
288 this.setNotes(someValues['data']['notes']);
289 }
290 if (someValues['data']['currentVersionKey'] != null) {
291 this.setCurrentVersionKey(someValues['data']['currentVersionKey']);
292 } else {
293 this.setCurrentVersionKey(this.key());
294 }
295
296 currentVersionParameters = someValues['currentVersion'];
297 currentVersionParameters['key'] = this.currentVersionKey();
298 this.setCurrentVersion(new Clipperz.PM.DataModel.RecordVersion(this, currentVersionParameters));
299
300 if (someValues['data']['directLogins'] != null) {
301 vardirectLoginReference;
302
303 for (directLoginReference in someValues['data']['directLogins']) {
304 var directLogin;
305 var directLoginParameters;
306
307 directLoginParameters = someValues['data']['directLogins'][directLoginReference];
308 directLoginParameters.record = this;
309 directLoginParameters.reference = directLoginReference;
310
311 directLogin = new Clipperz.PM.DataModel.DirectLogin(directLoginParameters);
312 this.addDirectLogin(directLogin, true);
313 }
314 }
315 this.setShouldProcessData(false);
316 }
317
318 Clipperz.NotificationCenter.notify(this, 'recordDataReady');
319//MochiKit.Logging.logDebug("<<< [" + (new Date()).valueOf() + "] Record.processData");
320//MochiKit.Logging.logDebug("<<< Record.processData");
321
322 return this;
323 },
324
325 //-------------------------------------------------------------------------
326
327 'processDataToExtractLegacyValues': function(someValues) {
328//MochiKit.Logging.logDebug(">>> Record.processDataToExtractLegacyValues");
329 if (someValues['data'] != null) {
330 this.setNotes(someValues['data']);
331 }
332
333 if (
334 (typeof(someValues['loginFormData']) != "undefined")
335 &&(typeof(someValues['loginBindings'] != "undefined"))
336 &&(someValues['loginFormData'] != "")
337 &&(someValues['loginBindings'] != "")
338 ) {
339 vardirectLogin;
340
341 directLogin = new Clipperz.PM.DataModel.DirectLogin({
342 record:this,
343 label:this.label() + Clipperz.PM.Strings['newDirectLoginLabelSuffix'],
344 reference:Clipperz.Crypto.SHA.sha256(new Clipperz.ByteArray(this.label() +
345 someValues['loginFormData'] +
346 someValues['loginBindings'])).toHexString().substring(2),
347 formData:Clipperz.Base.evalJSON(someValues['loginFormData']),
348 legacyBindingData:Clipperz.Base.evalJSON(someValues['loginBindings']),
349 bookmarkletVersion:'0.1'
350 });
351 this.addDirectLogin(directLogin, true);
352 }
353//MochiKit.Logging.logDebug("<<< Record.processDataToExtractLegacyValues");
354 },
355
356 //-------------------------------------------------------------------------
357
358 'getReadyBeforeUpdatingVersionValues': function() {
359 },
360
361 //-------------------------------------------------------------------------
362
363 'addNewField': function() {
364 varnewField;
365
366//MochiKit.Logging.logDebug(">>> Record.addNewField - " + this);
367 this.getReadyBeforeUpdatingVersionValues();
368 newField = this.currentVersion().addNewField();
369 Clipperz.NotificationCenter.notify(this, 'recordUpdated');
370//MochiKit.Logging.logDebug("<<< Record.addNewField");
371
372 return newField;
373 },
374
375 //-------------------------------------------------------------------------
376
377 'removeField': function(aField) {
378 this.getReadyBeforeUpdatingVersionValues();
379 this.currentVersion().removeField(aField);
380 Clipperz.NotificationCenter.notify(this, 'recordUpdated');
381 },
382
383 'removeEmptyFields': function() {
384 MochiKit.Iter.forEach(MochiKit.Base.values(this.currentVersion().fields()), MochiKit.Base.bind(function(aField) {
385 if (aField.isEmpty()) {
386 this.removeField(aField);
387 // this.currentVersion().removeField(aField);
388 }
389 }, this));
390 },
391
392 //-------------------------------------------------------------------------
393
394 'notes': function() {
395 return this._notes;
396 },
397
398 'setNotes': function(aValue) {
399 this._notes = aValue;
400 this.setHeaderNotes(null);
401 },
402
403 //-------------------------------------------------------------------------
404
405 'headerNotes': function() {
406 return this._headerNotes;
407 },
408
409 'setHeaderNotes': function(aValue) {
410 this._headerNotes = aValue;
411 },
412
413 //-------------------------------------------------------------------------
414
415 'remove': function() {
416//MochiKit.Logging.logDebug(">>> Record.remove - " + this);
417 MochiKit.Iter.forEach(MochiKit.Base.values(this.directLogins()), MochiKit.Base.method(this, 'removeDirectLogin'));
418
419 this.syncDirectLoginReferenceValues();
420 this.user().removeRecord(this);
421//MochiKit.Logging.logDebug("<<< Record.remove");
422 },
423
424 //-------------------------------------------------------------------------
425
426 'directLogins': function() {
427 return this._directLogins;
428 },
429
430 'addDirectLogin': function(aDirectLogin, shouldUpdateUser) {
431 this.directLogins()[aDirectLogin.reference()] = aDirectLogin;
432 if (shouldUpdateUser == true) {
433 this.user().addDirectLogin(aDirectLogin);
434 }
435 },
436
437 'removeDirectLogin': function(aDirectLogin) {
438 this.removedDirectLogins().push(aDirectLogin);
439 delete this.directLogins()[aDirectLogin.reference()];
440 // this.user().removeDirectLogin(aDirectLogin);
441 },
442
443 'resetDirectLogins': function() {
444 this._directLogins = {};
445 },
446
447 'removedDirectLogins': function() {
448 return this._removedDirectLogins;
449 },
450
451 'resetRemovedDirectLogins': function() {
452 this._removedDirectLogins = [];
453 },
454
455 //-------------------------------------------------------------------------
456
457 'serverData': function() {
458 return this._serverData;
459 },
460
461 'setServerData': function(aValue) {
462 this._serverData = aValue;
463 this.setShouldLoadData(false);
464 return aValue;
465 },
466
467 //-------------------------------------------------------------------------
468
469 'decryptedData': function() {
470 return this._decryptedData;
471 },
472
473 'setDecryptedData': function(aValue) {
474 this._decryptedData = aValue;
475 this.setShouldDecryptData(false);
476 return aValue;
477 },
478
479 //-------------------------------------------------------------------------
480
481 'cachedData': function() {
482 return this._cachedData;
483 },
484
485 'setCachedData': function(aValue) {
486//MochiKit.Logging.logDebug(">>> Record.setCachedData");
487//MochiKit.Logging.logDebug("--- Record.setCachedData - aValue: " + Clipperz.Base.serializeJSON(aValue));
488 this._cachedData = aValue;
489 this.setShouldProcessData(false);
490//MochiKit.Logging.logDebug("<<< Record.setCachedData");
491
492 return aValue;
493 },
494
495 //-------------------------------------------------------------------------
496
497 'hasPendingChanges': function() {
498 var result;
499
500//MochiKit.Logging.logDebug(">>> [" + (new Date()).valueOf() + "] Record.hasPendingChanges");
501//MochiKit.Logging.logDebug(">>> Record.hasPendingChanges - cachedData: " + this.cachedData());
502//MochiKit.Logging.logDebug(">>> Record.hasPendingChanges - cachedData: " + Clipperz.Base.serializeJSON(this.cachedData()));
503//MochiKit.Logging.logDebug(">>> Record.hasPendingChanges - currentSnapshot: " + this.currentDataSnapshot());
504//MochiKit.Logging.logDebug(">>> Record.hasPendingChanges - currentSnapshot: " + Clipperz.Base.serializeJSON(this.currentDataSnapshot()));
505//console.log(">>> Record.hasPendingChanges - cachedData: %o", this.cachedData());
506//console.log(">>> Record.hasPendingChanges - currentSnapshot: %o", this.currentDataSnapshot());
507 result = (MochiKit.Base.compare(this.cachedData(), this.currentDataSnapshot()) != 0);
508//MochiKit.Logging.logDebug("<<< Record.hasPendingChanges - " + result);
509
510 if ((result == false) && this.isBrandNew() && (this.label() != Clipperz.PM.Strings['newRecordTitleLabel'])) {
511 result = true;
512 }
513//MochiKit.Logging.logDebug("<<< [" + (new Date()).valueOf() + "] Record.hasPendingChanges");
514
515 return result;
516 },
517
518 //-------------------------------------------------------------------------
519
520 'currentDataSnapshot': function() {
521 varresult;
522
523//MochiKit.Logging.logDebug(">>> [" + (new Date()).valueOf() + "] Record.currentDataSnapshot");
524 result = {
525 'label': this.label(),
526 'data': this.serializedData(),
527 'currentVersion': this.currentVersion().currentDataSnapshot()
528 };
529
530 // result['data']['data'] = this.notes();
531 result = Clipperz.Base.serializeJSON(result);
532
533//MochiKit.Logging.logDebug("<<< [" + (new Date()).valueOf() + "] Record.currentDataSnapshot");
534//MochiKit.Logging.logDebug("<<< Record.currentDataSnapshot");
535
536 return result;
537 },
538
539 //.........................................................................
540
541 'takeSnapshotOfCurrentData': function() {
542 this.setCachedData(this.currentDataSnapshot());
543 },
544
545 //-------------------------------------------------------------------------
546
547 'headerData': function() {
548 var result;
549
550 result = {
551 'label': this.label(),
552 'key': this.key()
553 };
554
555 if (this.headerNotes() != null) {
556 result['headerNotes'] = this.headerNotes();
557 }
558
559 return result;
560 },
561
562 //-------------------------------------------------------------------------
563
564 'serializedData': function() {
565 var result;
566 var directLoginReference;
567
568 result = {};
569 result['currentVersionKey'] = this.currentVersion().key();
570
571 result['directLogins'] = {};
572 for (directLoginReference in this.directLogins()) {
573 result['directLogins'][directLoginReference] = this.directLogins()[directLoginReference].serializedData();
574 }
575 result['notes'] = this.notes();
576
577 return result;
578 },
579
580 //-------------------------------------------------------------------------
581
582 'encryptedData': function() {
583 var deferredResult;
584 varresult;
585
586//MochiKit.Logging.logDebug(">>> [" + (new Date()).valueOf() + "] Record.encryptedData");
587 result = {}
588//MochiKit.Logging.logDebug("--- Record.encryptedData - 1");
589 deferredResult = new MochiKit.Async.Deferred();
590//MochiKit.Logging.logDebug("--- Record.encryptedData - 2");
591//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("Record.encryptedData - 1: " + res); return res;});
592 deferredResult.addCallback(function(aResult, aRecord) {
593 aResult['reference'] = aRecord.reference();
594 return aResult;
595 }, result, this);
596//MochiKit.Logging.logDebug("--- Record.encryptedData - 3");
597//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("Record.encryptedData - 2: " + res); return res;});
598 deferredResult.addCallback(Clipperz.PM.Crypto.deferredEncryptWithCurrentVersion, this.key(), this.serializedData());
599//MochiKit.Logging.logDebug("--- Record.encryptedData - 4");
600//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("Record.encryptedData - 3: " + res); return res;});
601 deferredResult.addCallback(function(aResult, res) {
602 aResult['data'] = res;
603 return aResult;
604 }, result);
605//MochiKit.Logging.logDebug("--- Record.encryptedData - 5");
606//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("Record.encryptedData - 4: " + res); return res;});
607 deferredResult.addCallback(function(aResult) {
608 aResult['version'] = Clipperz.PM.Crypto.encryptingFunctions.currentVersion;
609 return aResult;
610 }, result);
611//MochiKit.Logging.logDebug("--- Record.encryptedData - 6");
612//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("Record.encryptedData - 5: " + res); return res;});
613 deferredResult.callback();
614//MochiKit.Logging.logDebug("<<< [" + (new Date()).valueOf() + "] Record.encryptedData");
615
616 return deferredResult;
617 },
618
619 //-------------------------------------------------------------------------
620
621 'syncDirectLoginReferenceValues': function() {
622//MochiKit.Logging.logDebug(">>> Record.syncDirectLoginReferenceValues");
623 MochiKit.Iter.forEach(MochiKit.Base.values(this.directLogins()), function(aDirectLogin) {
624 aDirectLogin.record().user().synchronizeDirectLogin(aDirectLogin);
625 });
626
627 MochiKit.Iter.forEach(this.removedDirectLogins(), function(aDirectLogin) {
628 aDirectLogin.record().user().removeDirectLogin(aDirectLogin);
629 });
630
631 this.resetRemovedDirectLogins();
632//MochiKit.Logging.logDebug("<<< Record.syncDirectLoginReferenceValues");
633 },
634
635 //-------------------------------------------------------------------------
636
637 'saveChanges': function() {
638 var result;
639
640 if (this.isBrandNew() == false) {
641 result = this.user().saveRecords([this], 'updateData');
642 } else {
643 result = this.user().saveRecords([this], 'addNewRecords');
644 }
645
646 return result;
647 },
648
649/*
650 'saveChanges': function() {
651 var deferredResult;
652 varresult;
653
654 Clipperz.NotificationCenter.notify(this.user(), 'updatedSection', 'records', true);
655//MochiKit.Logging.logDebug(">>> Record.saveChanges");
656//MochiKit.Logging.logDebug(">>> [" + (new Date()).valueOf() + "] Record.saveChanges");
657 if (this.headerNotes() != null) {
658 this.setNotes(this.headerNotes());
659 }
660 this.syncDirectLoginReferenceValues();
661 this.currentVersion().createNewVersion();
662
663 result = {'records': [{}]};
664
665 deferredResult = new MochiKit.Async.Deferred();
666 deferredResult.addCallback(Clipperz.NotificationCenter.deferredNotification, this, 'updatedProgressState', 'saveCard_collectRecordInfo');
667 deferredResult.addCallback(MochiKit.Base.method(this, 'updateKey'));
668
669 deferredResult.addCallback(Clipperz.NotificationCenter.deferredNotification, this, 'updatedProgressState', 'saveCard_encryptUserData');
670 deferredResult.addCallback(MochiKit.Base.method(this.user(), 'encryptedData'));
671 deferredResult.addCallback(function(aResult, res) {
672 aResult['user'] = res;
673 return aResult;
674 }, result);
675
676 deferredResult.addCallback(Clipperz.NotificationCenter.deferredNotification, this, 'updatedProgressState', 'saveCard_encryptRecordData');
677 deferredResult.addCallback(MochiKit.Base.method(this, 'encryptedData'));
678 deferredResult.addCallback(function(aResult, res) {
679 //# aResult['record'] = res;
680 aResult['records'][0]['record'] = res;
681 return aResult;
682 }, result);
683
684 deferredResult.addCallback(Clipperz.NotificationCenter.deferredNotification, this, 'updatedProgressState', 'saveCard_encryptRecordVersions');
685 deferredResult.addCallback(MochiKit.Base.method(this.currentVersion(), 'encryptedData'));
686 deferredResult.addCallback(function(aResult, res) {
687 // aResult['currentRecordVersion'] = res;
688 aResult['records'][0]['currentRecordVersion'] = res;
689 return aResult;
690 }, result);
691
692 deferredResult.addCallback(Clipperz.NotificationCenter.deferredNotification, this, 'updatedProgressState', 'saveCard_sendingData');
693 if (this.isBrandNew() == false) {
694 deferredResult.addCallback(MochiKit.Base.method(this.user().connection(), 'message'), 'updateData');
695 } else {
696 //# deferredResult.addCallback(MochiKit.Base.method(this.user().connection(), 'message'), 'addNewRecord');
697 deferredResult.addCallback(MochiKit.Base.method(this.user().connection(), 'message'), 'addNewRecords');
698 }
699
700 deferredResult.addCallback(MochiKit.Base.method(this, 'takeSnapshotOfCurrentData'));
701 deferredResult.addCallback(Clipperz.NotificationCenter.deferredNotification, this, 'updatedProgressState', 'saveCard_updatingInterface');
702 deferredResult.addCallback(MochiKit.Base.method(this, 'setIsBrandNew'), false);
703 deferredResult.addCallback(Clipperz.NotificationCenter.deferredNotification, this, 'notify', 'recordUpdated');
704 deferredResult.addCallback(Clipperz.NotificationCenter.deferredNotification, this, 'notify', 'directLoginUpdated');
705 deferredResult.callback();
706
707 return deferredResult;
708 },
709 */
710 //-------------------------------------------------------------------------
711
712 'cancelChanges': function() {
713//MochiKit.Logging.logDebug(">>> Record.cancelChanges");
714//MochiKit.Logging.logDebug("--- Record.cancelChanges - cachedData: " + Clipperz.Base.serializeJSON(this.cachedData()));
715 if (this.isBrandNew()) {
716 this.user().removeRecord(this);
717 } else {
718 this.restoreValuesFromSnapshot(this.cachedData());
719 }
720//MochiKit.Logging.logDebug("<<< Record.cancelChanges");
721 },
722
723 //-------------------------------------------------------------------------
724
725 'restoreValuesFromSnapshot': function(someSnapshotData) {
726 varsnapshotData;
727
728//MochiKit.Logging.logDebug(">>> [" + (new Date()).valueOf() + "] Record.restoreValuesFromSnapshot");
729 snapshotData = Clipperz.Base.evalJSON(someSnapshotData);
730//MochiKit.Logging.logDebug("--- Record.restoreValuesFromSnapshot - someSnapshotData (1): " + Clipperz.Base.serializeJSON(someSnapshotData));
731 this.setLabel(snapshotData['label']);
732 this.resetDirectLogins();
733 this.setShouldProcessData(true);
734 this.processData(snapshotData);
735//MochiKit.Logging.logDebug("--- Record.restoreValuesFromSnapshot - snapshotData: (2)" + Clipperz.Base.serializeJSON(snapshotData));
736
737 this.resetRemovedDirectLogins();
738
739 {
740 var currentSnapshot;
741 varcomparisonResult;
742
743 currentSnapshot = this.currentDataSnapshot();
744//MochiKit.Logging.logDebug("--- Record.restoreValuesFromSnapshot - 1");
745//console.log("snapshot data: %o", someSnapshotData.currentVersion);
746//console.log("current data: %o", currentSnapshot.currentVersion);
747//MochiKit.Logging.logDebug("--- Record.restoreValuesFromSnapshot - someSnapshotData: " + Clipperz.Base.serializeJSON(someSnapshotData.currentVersion));
748//MochiKit.Logging.logDebug("--- Record.restoreValuesFromSnapshot - currentSnapshot: " + Clipperz.Base.serializeJSON(currentSnapshot.currentVersion));
749 comparisonResult = MochiKit.Base.compare(someSnapshotData.currentVersion, currentSnapshot.currentVersion);
750//MochiKit.Logging.logDebug("--- Record.restoreValuesFromSnapshot - " + comparisonResult);
751 }
752//MochiKit.Logging.logDebug("<<< [" + (new Date()).valueOf() + "] Record.restoreValuesFromSnapshot");
753 },
754
755 //-------------------------------------------------------------------------
756 __syntaxFix__: "syntax fix"
757});
758
759
diff --git a/frontend/beta/js/Clipperz/PM/DataModel/RecordField.js b/frontend/beta/js/Clipperz/PM/DataModel/RecordField.js
new file mode 100644
index 0000000..2063825
--- a/dev/null
+++ b/frontend/beta/js/Clipperz/PM/DataModel/RecordField.js
@@ -0,0 +1,220 @@
1/*
2
3Copyright 2008-2011 Clipperz Srl
4
5This file is part of Clipperz's Javascript Crypto Library.
6Javascript Crypto Library provides web developers with an extensive
7and efficient set of cryptographic functions. The library aims to
8obtain maximum execution speed while preserving modularity and
9reusability.
10For further information about its features and functionalities please
11refer to http://www.clipperz.com
12
13* Javascript Crypto Library is free software: you can redistribute
14 it and/or modify it under the terms of the GNU Affero General Public
15 License as published by the Free Software Foundation, either version
16 3 of the License, or (at your option) any later version.
17
18* Javascript Crypto Library is distributed in the hope that it will
19 be useful, but WITHOUT ANY WARRANTY; without even the implied
20 warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
21 See the GNU Affero General Public License for more details.
22
23* You should have received a copy of the GNU Affero General Public
24 License along with Javascript Crypto Library. If not, see
25 <http://www.gnu.org/licenses/>.
26
27*/
28
29if (typeof(Clipperz) == 'undefined') { Clipperz = {}; }
30if (typeof(Clipperz.PM) == 'undefined') { Clipperz.PM = {}; }
31if (typeof(Clipperz.PM.DataModel) == 'undefined') { Clipperz.PM.DataModel = {}; }
32
33//#############################################################################
34
35Clipperz.PM.DataModel.RecordField = function(args) {
36 args = args || {};
37
38 this._recordVersion = args.recordVersion || null;
39 this._key = args.key || Clipperz.PM.Crypto.randomKey();
40 this.setLabel(args.label || '');
41 this.setValue(args.value || '');
42 this.setType(args.type || 'TXT'); //valid types: 'TXT', 'PWD', 'URL', 'DATE', 'ADDR', 'CHECK', 'RADIO', ('NOTE' probably not), ...
43 this._hidden = args.hidden || (args.type == 'PWD') || false;
44
45 return this;
46}
47
48Clipperz.PM.DataModel.RecordField.prototype = MochiKit.Base.update(null, {
49
50 'toString': function() {
51 return "Clipperz.PM.DataModel.RecordField - " + this.label() + " (" + this.key() + ")";
52 },
53
54 //-------------------------------------------------------------------------
55
56 'recordVersion': function() {
57 return this._recordVersion;
58 },
59
60 //-------------------------------------------------------------------------
61
62 'key': function() {
63 return this._key;
64 },
65
66 //-------------------------------------------------------------------------
67
68 'label': function() {
69 return this._label;
70 },
71
72 'setLabel': function(aValue) {
73 this._label = aValue;
74 },
75
76 //-------------------------------------------------------------------------
77
78 'value': function() {
79 return this._value;
80 },
81
82 'setValue': function(aValue) {
83 this._value = aValue;
84 },
85
86 //-------------------------------------------------------------------------
87
88 'type': function() {
89 return this._type;
90 },
91
92 'setType': function(aValue) {
93 this._type = aValue;
94
95 if (aValue == 'PWD') {
96 this.setHidden(true);
97 } else {
98 this.setHidden(false);
99 }
100 },
101
102 //-------------------------------------------------------------------------
103
104 'serializeData': function() {
105 var result;
106
107//MochiKit.Logging.logDebug(">>> RecordField.serializeData - " + this);
108 result = {
109 label: this.label(),
110 value:this.value(),
111 type: this.type(),
112 hidden: this.hidden()
113 };
114//MochiKit.Logging.logDebug("<<< RecordField.serializeData");
115
116 return result;
117 },
118
119 //-------------------------------------------------------------------------
120
121 'typeShortDescription': function() {
122 // return Clipperz.PM.DataModel.RecordField.TypeDescriptions[this.type()]['shortDescription'];
123 return Clipperz.PM.Strings['recordFieldTypologies'][this.type()]['shortDescription'];
124 },
125
126 //-------------------------------------------------------------------------
127
128 'hidden': function() {
129 return this._hidden;
130 },
131
132 'setHidden': function(aValue) {
133 this._hidden = aValue;
134 },
135
136 //-------------------------------------------------------------------------
137
138 'clone': function(aRecordVersion) {
139 var result;
140
141 result = new Clipperz.PM.DataModel.RecordField({
142 recordVersion:aRecordVersion,
143 label:this.label(),
144 value:this.value(),
145 type:this.type(),
146 hidden:this.hidden()
147 });
148
149 return result;
150 },
151
152 //-------------------------------------------------------------------------
153
154 'isEmpty': function() {
155 var result;
156
157 if ((this.label() == "") && (this.value() == "") && (this.type() == 'TXT')) {
158 result = true;
159 } else {
160 result = false;
161 }
162
163 return result;
164 },
165
166 //-------------------------------------------------------------------------
167 __syntaxFix__: "syntax fix"
168
169});
170
171//#############################################################################
172/*
173Clipperz.PM.DataModel.RecordField.TypeDescriptions = {
174 'TXT': {
175 description: 'simple text field',
176 shortDescription: 'txt'
177 },
178 'PWD': {
179 description: 'simple text field, with default status set to hidden',
180 shortDescription: 'pwd'
181 },
182 'URL': {
183 description: 'simple text field in edit mode, that became an active url in view mode',
184 shortDescription: 'url'
185 },
186 'DATE': {
187 description: 'a value set with a calendar helper',
188 shortDescription: 'date'
189 },
190 'ADDR': {
191 description: 'just like the URL, but the active link points to Google Maps (or similar service) passing the address value as argument',
192 shortDescription: 'addr'
193 },
194 'CHECK': {
195 description: 'check description',
196 shortDescription: 'check'
197 },
198 'RADIO': {
199 description: 'radio description',
200 shortDescription: 'radio'
201 },
202 'SELECT': {
203 description: 'select description',
204 shortDescription: 'select'
205 }
206
207 //'NOTE': {
208 // description: 'a simple text field, but with a bigger component dimension; possibly with "smart edit components"',
209 // shortDescription: 'note'
210 //}
211};
212
213Clipperz.PM.DataModel.RecordField.InputTypeToRecordFieldType = {
214 'text': 'TXT',
215 'password': 'PWD',
216 'checkbox': 'CHECK',
217 'radio': 'RADIO',
218 'select': 'SELECT'
219};
220*/
diff --git a/frontend/beta/js/Clipperz/PM/DataModel/RecordVersion.js b/frontend/beta/js/Clipperz/PM/DataModel/RecordVersion.js
new file mode 100644
index 0000000..d2b3e12
--- a/dev/null
+++ b/frontend/beta/js/Clipperz/PM/DataModel/RecordVersion.js
@@ -0,0 +1,535 @@
1/*
2
3Copyright 2008-2011 Clipperz Srl
4
5This file is part of Clipperz's Javascript Crypto Library.
6Javascript Crypto Library provides web developers with an extensive
7and efficient set of cryptographic functions. The library aims to
8obtain maximum execution speed while preserving modularity and
9reusability.
10For further information about its features and functionalities please
11refer to http://www.clipperz.com
12
13* Javascript Crypto Library is free software: you can redistribute
14 it and/or modify it under the terms of the GNU Affero General Public
15 License as published by the Free Software Foundation, either version
16 3 of the License, or (at your option) any later version.
17
18* Javascript Crypto Library is distributed in the hope that it will
19 be useful, but WITHOUT ANY WARRANTY; without even the implied
20 warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
21 See the GNU Affero General Public License for more details.
22
23* You should have received a copy of the GNU Affero General Public
24 License along with Javascript Crypto Library. If not, see
25 <http://www.gnu.org/licenses/>.
26
27*/
28
29if (typeof(Clipperz) == 'undefined') { Clipperz = {}; }
30if (typeof(Clipperz.PM) == 'undefined') { Clipperz.PM = {}; }
31if (typeof(Clipperz.PM.DataModel) == 'undefined') { Clipperz.PM.DataModel = {}; }
32
33
34//#############################################################################
35
36Clipperz.PM.DataModel.RecordVersion = function(aRecord, args) {
37 args = args || {};
38
39 this._record = aRecord;
40
41 this._reference = args.reference || Clipperz.PM.Crypto.randomKey();
42 this._version = args.version || Clipperz.PM.Crypto.encryptingFunctions.currentVersion;
43 this._key = args.key || Clipperz.PM.Crypto.randomKey();;
44
45 this._previousVersion = args.previousVersion || null;
46 this._previousVersionKey = args.previousVersionKey || null;
47
48 this.setIsBrandNew(args.reference == null);
49
50 if (this.isBrandNew()) {
51 this._fields = {};
52
53 this.setShouldLoadData(false);
54 this.setShouldDecryptData(false);
55 this.setShouldProcessData(false);
56 } else {
57 if (typeof(args.fields) != 'undefined') {
58 this.processFieldData(args.fields);
59
60 this.setShouldLoadData(false);
61 this.setShouldDecryptData(false);
62 this.setShouldProcessData(false);
63 } else {
64 if (typeof(args.data) != 'undefined') {
65 this.setShouldLoadData(false);
66 } else {
67 this.setShouldLoadData(true);
68 }
69 this.setShouldDecryptData(true);
70 this.setShouldProcessData(true);
71 }
72 }
73
74 this._serverData = args.data;
75 this._decryptedData = null;
76
77 return this;
78}
79
80Clipperz.PM.DataModel.RecordVersion.prototype = MochiKit.Base.update(null, {
81
82 'toString': function() {
83 return "RecordVersion";
84 },
85
86 //-------------------------------------------------------------------------
87
88 'record': function() {
89 return this._record;
90 },
91
92 //-------------------------------------------------------------------------
93
94 'reference': function() {
95 return this._reference;
96 },
97
98 'setReference': function(aValue) {
99 this._reference = aValue;
100 },
101
102 //-------------------------------------------------------------------------
103
104 'key': function() {
105//MochiKit.Logging.logDebug(">>> RecordVersion.key");
106//MochiKit.Logging.logDebug("--- RecordVersion.key - " + this._key);
107 return this._key;
108 },
109
110 'setKey': function(aValue) {
111 this._key = aValue;
112 },
113
114 //-------------------------------------------------------------------------
115
116 'serverData': function() {
117 return this._serverData;
118 },
119
120 'setServerData': function(aValue) {
121 this._serverData = aValue;
122 this.setShouldLoadData(false);
123 return aValue;
124 },
125
126 //-------------------------------------------------------------------------
127
128 'decryptedData': function() {
129//MochiKit.Logging.logDebug(">>> RecordVersion.decryptedData: " + (this._decryptedData ? Clipperz.Base.serializeJSON(aValue) : "null"));
130 return this._decryptedData;
131 },
132
133 'setDecryptedData': function(aValue) {
134//MochiKit.Logging.logDebug(">>> RecordVersion.setDecryptedData: " + Clipperz.Base.serializeJSON(aValue));
135 this._decryptedData = aValue;
136 this.setShouldDecryptData(false);
137 return aValue;
138 },
139
140 //-------------------------------------------------------------------------
141
142 'version': function() {
143 return this._version;
144 },
145
146 //-------------------------------------------------------------------------
147
148 'isBrandNew': function() {
149 return this._isBrandNew;
150 },
151
152 'setIsBrandNew': function(aValue) {
153 this._isBrandNew = aValue;
154 },
155
156 //-------------------------------------------------------------------------
157
158 'fields': function() {
159 return this._fields;
160 },
161
162 'addField': function(aField) {
163 this.fields()[aField.key()] = aField;
164 },
165
166 'addNewField': function() {
167 varnewRecordField;
168
169 newRecordField = new Clipperz.PM.DataModel.RecordField({recordVersion:this});
170 this.addField(newRecordField);
171
172 return newRecordField;
173 },
174
175 'fieldWithName': function(aValue) {
176 varresult;
177 var fieldValues;
178 var i,c;
179
180 result = null;
181 fieldValues = MochiKit.Base.values(this.fields());
182 c = fieldValues.length;
183 for (i=0; (i<c) && (result == null); i++) {
184 varcurrentField;
185
186 currentField = fieldValues[i];
187 if (currentField.label() == aValue) {
188 result = currentField;
189 }
190 }
191
192 return result;
193 },
194
195 //-------------------------------------------------------------------------
196
197 'shouldLoadData': function() {
198 return this._shouldLoadData;
199 },
200
201 'setShouldLoadData': function(aValue) {
202 this._shouldLoadData = aValue;
203 },
204
205 //-------------------------------------------------------------------------
206
207 'shouldDecryptData': function() {
208 return this._shouldDecryptData;
209 },
210
211 'setShouldDecryptData': function(aValue) {
212 this._shouldDecryptData = aValue;
213 },
214
215 //-------------------------------------------------------------------------
216
217 'shouldProcessData': function() {
218 return this._shouldProcessData;
219 },
220
221 'setShouldProcessData': function(aValue) {
222 this._shouldProcessData = aValue;
223 },
224
225 //-------------------------------------------------------------------------
226
227 'deferredData': function() {
228 var deferredResult;
229
230//MochiKit.Logging.logDebug(">>> RecordVersion.deferredData - this: " + this);
231 deferredResult = new MochiKit.Async.Deferred();
232 deferredResult.addCallback(MochiKit.Base.method(this, 'loadData'));
233 deferredResult.addCallback(MochiKit.Base.method(this, 'decryptData'));
234 deferredResult.addCallback(MochiKit.Base.method(this, 'processData'));
235 deferredResult.callback();
236//MochiKit.Logging.logDebug("<<< RecordVersion.deferredData");
237
238 return deferredResult;
239 },
240
241 //-------------------------------------------------------------------------
242
243 'loadData': function() {
244 var result;
245
246//MochiKit.Logging.logDebug(">>> RecordVersion.loadData - this: " + this);
247 if (this.shouldLoadData()) {
248 var deferredResult;
249
250 alert("ERROR: this should have not happened yet!");
251//MochiKit.Logging.logDebug("--- RecordVersion.loadData - 1");
252 deferredResult = new MochiKit.Async.Deferred();
253//MochiKit.Logging.logDebug("--- RecordVersion.loadData - 2");
254 deferredResult.addCallback(MochiKit.Base.method(this, 'notify'), 'loadingRecordVersionData');
255//MochiKit.Logging.logDebug("--- RecordVersion.loadData - 3");
256 deferredResult.addCallback(MochiKit.Base.method(this.user().connection(), 'message'), 'getRecordVersionDetail', {reference: this.reference()});
257//MochiKit.Logging.logDebug("--- RecordVersion.loadData - 4");
258 deferredResult.addCallback(MochiKit.Base.method(this, 'setServerData'));
259//MochiKit.Logging.logDebug("--- RecordVersion.loadData - 5");
260 deferredResult.callback();
261//MochiKit.Logging.logDebug("--- RecordVersion.loadData - 6");
262 result = deferredResult;
263//MochiKit.Logging.logDebug("--- RecordVersion.loadData - 7");
264 } else {
265//MochiKit.Logging.logDebug("--- RecordVersion.loadData - 8");
266 result = MochiKit.Async.succeed(this.serverData());
267//MochiKit.Logging.logDebug("--- RecordVersion.loadData - 9");
268 }
269//MochiKit.Logging.logDebug("<<< RecordVersion.loadData");
270
271 return result;
272 },
273
274 //-------------------------------------------------------------------------
275
276 'decryptData': function(anEncryptedData) {
277 var result;
278
279//MochiKit.Logging.logDebug(">>> RecordVersion.decryptData - this: " + this + " (" + anEncryptedData + ")");
280 if (this.shouldDecryptData()) {
281 var deferredResult;
282
283//MochiKit.Logging.logDebug("--- RecordVersion.decryptData - 1");
284 deferredResult = new MochiKit.Async.Deferred();
285//MochiKit.Logging.logDebug("--- RecordVersion.decryptData - 2");
286//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("RecordVersion.decryptData 1: " + res); return res;});
287 deferredResult.addCallback(MochiKit.Base.method(this, 'notify'), 'decryptingRecordVersionData');
288//MochiKit.Logging.logDebug("--- RecordVersion.decryptData - 3");
289//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("RecordVersion.decryptData 2: " + res); return res;});
290 deferredResult.addCallback(Clipperz.PM.Crypto.deferredDecrypt, this.key(), anEncryptedData, this.version());
291//MochiKit.Logging.logDebug("--- RecordVersion.decryptData - 4");
292//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("RecordVersion.decryptData 3: " + res); return res;});
293//MochiKit.Logging.logDebug("--- RecordVersion.decryptData - 5");
294//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("RecordVersion.decryptData 4: " + res); return res;});
295 deferredResult.addCallback(MochiKit.Base.method(this, 'setDecryptedData'));
296//MochiKit.Logging.logDebug("--- RecordVersion.decryptData - 6");
297//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("RecordVersion.decryptData 5: " + res); return res;});
298 deferredResult.callback();
299//MochiKit.Logging.logDebug("--- RecordVersion.decryptData - 7");
300 result = deferredResult;
301//MochiKit.Logging.logDebug("--- RecordVersion.decryptData - 8");
302 } else {
303//MochiKit.Logging.logDebug("--- RecordVersion.decryptData - 9");
304 result = MochiKit.Async.succeed(this.decryptedData());
305//MochiKit.Logging.logDebug("--- RecordVersion.decryptData - 10");
306 }
307//MochiKit.Logging.logDebug("<<< RecordVersion.decryptData");
308
309 return result;
310 },
311
312 //-------------------------------------------------------------------------
313
314 'processFieldData': function(someValues) {
315 var fieldValues;
316
317 this._fields = {};
318
319 if (typeof(someValues) == 'undefined') {
320 fieldValues = {};
321 } else {
322 fieldValues = someValues;
323 }
324
325 if (fieldValues.constructor == Array) {
326 var i, c;
327 c = fieldValues.length;
328 for (i=0; i<c; i++) {
329 var newRecordField;
330 var currentFieldValues;
331
332 currentFieldValues = fieldValues[i];
333 currentFieldValues['recordVersion'] = this;
334 newRecordField = new Clipperz.PM.DataModel.RecordField(currentFieldValues);
335 this._fields[newRecordField.key()] = newRecordField;
336 }
337
338 } else {
339 var fieldKey;
340
341 for (fieldKey in fieldValues) {
342 var newRecordField;
343 var currentFieldValues;
344
345 currentFieldValues = fieldValues[fieldKey];
346 currentFieldValues['key'] = fieldKey;
347 currentFieldValues['recordVersion'] = this;
348 newRecordField = new Clipperz.PM.DataModel.RecordField(currentFieldValues);
349 this._fields[fieldKey] = newRecordField;
350 }
351 }
352
353 },
354
355 'processData': function(someValues) {
356 if (this.shouldProcessData()) {
357 this.processFieldData(someValues.fields);
358 this.setShouldProcessData(false);
359 }
360
361 this.notify('recordVersionDataReady');
362
363 return this;
364 },
365
366 //-------------------------------------------------------------------------
367
368 'notify': function(aValue) {
369 Clipperz.NotificationCenter.notify(this, aValue);
370 },
371
372 //-------------------------------------------------------------------------
373
374 'removeField': function(aField) {
375 delete this.fields()[aField.key()];
376 },
377
378 //-------------------------------------------------------------------------
379
380 'previousVersion': function() {
381 return this._previousVersion;
382 },
383
384 'setPreviousVersion': function(aValue) {
385 this._previousVersion = aValue;
386 },
387
388 //-------------------------------------------------------------------------
389
390 'previousVersionKey': function() {
391 return this._previousVersionKey;
392 },
393
394 'setPreviousVersionKey': function(aValue) {
395 this._previousVersionKey = aValue;
396 },
397
398 //-------------------------------------------------------------------------
399
400 'serializedData': function() {
401 var result;
402 varfieldKey;
403
404//MochiKit.Logging.logDebug(">>> RecordVersion.serializedData");
405 result = {
406 fields: {}
407 };
408//MochiKit.Logging.logDebug("--- RecordVersion.serializedData - 1");
409
410 for (fieldKey in this.fields()) {
411//MochiKit.Logging.logDebug("--- RecordVersion.serializedData - 2");
412 result.fields[fieldKey] = this.fields()[fieldKey].serializeData();
413//MochiKit.Logging.logDebug("--- RecordVersion.serializedData - 3");
414 }
415//MochiKit.Logging.logDebug("--- RecordVersion.serializedData - 4");
416//MochiKit.Logging.logDebug("<<< RecordVersion.serializedData: " + Clipperz.Base.serializeJSON(result));
417
418 return result;
419 },
420
421 'currentDataSnapshot': function() {
422 var result;
423
424 result = this.serializedData();
425 result['version'] = this.version();
426 result['reference'] = this.reference();
427 result['previousVersionKey'] = this.previousVersionKey();
428
429 return result;
430 },
431
432 //-------------------------------------------------------------------------
433
434 'encryptedData': function() {
435 var deferredResult;
436 var result;
437
438//MochiKit.Logging.logDebug(">>> RecordVersion.encryptedData - " + this);
439 result = {};
440 deferredResult = new MochiKit.Async.Deferred();
441//MochiKit.Logging.logDebug("--- RecordVersion.encryptedData - 1");
442//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("RecordVersion.encryptedData - 1: " + res); return res;});
443 deferredResult.addCallback(function(aResult, aRecordVersion) {
444 aResult['reference'] = aRecordVersion.reference();
445 aResult['recordReference'] = aRecordVersion.record().reference();// TODO - this seems to be completely useless
446 return aResult;
447 }, result, this);
448//MochiKit.Logging.logDebug("--- RecordVersion.encryptedData - 2");
449//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("RecordVersion.encryptedData - 2: " + res); return res;});
450 deferredResult.addCallback(Clipperz.PM.Crypto.deferredEncryptWithCurrentVersion, this.key(), this.serializedData());
451//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("RecordVersion.encryptedData - 3: " + res); return res;});
452 deferredResult.addCallback(function(aResult, res) {
453 aResult['data'] = res;
454 return aResult;
455 }, result);
456//MochiKit.Logging.logDebug("--- RecordVersion.encryptedData - 3");
457//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("RecordVersion.encryptedData - 4: " + res); return res;});
458 deferredResult.addCallback(function(aResult) {
459 aResult['version'] = Clipperz.PM.Crypto.encryptingFunctions.currentVersion;
460 return aResult;
461 }, result);
462//MochiKit.Logging.logDebug("--- RecordVersion.encryptedData - 4");
463 if (this.previousVersion() != null) {
464//MochiKit.Logging.logDebug("--- RecordVersion.encryptedData - 5");
465//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("RecordVersion.encryptedData - 5: " + res); return res;});
466 deferredResult.addCallback(function(aResult, aRecordVersion) {
467 aResult['previousVersion'] = aRecordVersion.previousVersion();
468 return aResult;
469 }, result, this);
470//MochiKit.Logging.logDebug("--- RecordVersion.encryptedData - 6");
471//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("RecordVersion.encryptedData - 6: " + res); return res;});
472 deferredResult.addCallback(Clipperz.PM.Crypto.deferredEncryptWithCurrentVersion, this.key(), this.previousVersionKey());
473//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("RecordVersion.encryptedData - 7: " + res); return res;});
474 deferredResult.addCallback(function(aResult, res) {
475 aResult['previousVersionKey'] = res;
476 return aResult;
477 }, result);
478//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("RecordVersion.encryptedData - 8: " + res); return res;});
479//MochiKit.Logging.logDebug("--- RecordVersion.encryptedData - 7");
480 } else {
481//MochiKit.Logging.logDebug("--- RecordVersion.encryptedData - 8");
482//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("RecordVersion.encryptedData - 9: " + res); return res;});
483 deferredResult.addCallback(function(aResult) {
484 aResult['previousVersionKey'] = Clipperz.PM.Crypto.nullValue;
485 return aResult;
486 }, result);
487//MochiKit.Logging.logDebug("--- RecordVersion.encryptedData - 9");
488//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("RecordVersion.encryptedData - 10: " + res); return res;});
489 };
490//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("RecordVersion.encryptedData - 11: " + res); return res;});
491 deferredResult.callback();
492//MochiKit.Logging.logDebug("<<< RecordVersion.encryptedData");
493
494 return deferredResult;
495 },
496
497 //-------------------------------------------------------------------------
498
499 'createNewVersion': function() {
500 if (this.record().isBrandNew() == false) {
501 this.setPreviousVersion(this.reference());
502 this.setPreviousVersionKey(this.key());
503
504 this.setReference(Clipperz.PM.Crypto.randomKey());
505 this.setKey(Clipperz.PM.Crypto.randomKey());
506 }
507 },
508
509 //-------------------------------------------------------------------------
510/*
511 'shouldLoadData': function() {
512 return ((this.data() == null) && (this.isBrandNew() === false));
513 },
514
515 'loadData': function() {
516//MochiKit.Logging.logDebug(">>> Record.loadData (" + this.label() + ")");
517 // if (this.shouldLoadData()) {
518 // this.user().connection().message('getRecordDetail',
519 // {recordReference: this.reference()},
520 // {callback:MochiKit.Base.bind(this.loadDataCallback, this),
521 // errorHandler:Clipperz.PM.defaultErrorHandler });
522 // } else {
523 // this.notify('loadDataDone');
524 // }
525 },
526
527 'loadDataCallback': function() {
528MochiKit.Logging.logDebug("RecordVersion.loadDataCallback: " + Clipperz.Base.serializeJSON(arguments));
529 },
530*/
531 //-------------------------------------------------------------------------
532 __syntaxFix__: "syntax fix"
533
534});
535
diff --git a/frontend/beta/js/Clipperz/PM/DataModel/Statistics.js b/frontend/beta/js/Clipperz/PM/DataModel/Statistics.js
new file mode 100644
index 0000000..fb5eb01
--- a/dev/null
+++ b/frontend/beta/js/Clipperz/PM/DataModel/Statistics.js
@@ -0,0 +1,133 @@
1/*
2
3Copyright 2008-2011 Clipperz Srl
4
5This file is part of Clipperz's Javascript Crypto Library.
6Javascript Crypto Library provides web developers with an extensive
7and efficient set of cryptographic functions. The library aims to
8obtain maximum execution speed while preserving modularity and
9reusability.
10For further information about its features and functionalities please
11refer to http://www.clipperz.com
12
13* Javascript Crypto Library is free software: you can redistribute
14 it and/or modify it under the terms of the GNU Affero General Public
15 License as published by the Free Software Foundation, either version
16 3 of the License, or (at your option) any later version.
17
18* Javascript Crypto Library is distributed in the hope that it will
19 be useful, but WITHOUT ANY WARRANTY; without even the implied
20 warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
21 See the GNU Affero General Public License for more details.
22
23* You should have received a copy of the GNU Affero General Public
24 License along with Javascript Crypto Library. If not, see
25 <http://www.gnu.org/licenses/>.
26
27*/
28
29if (typeof(Clipperz) == 'undefined') { Clipperz = {}; }
30if (typeof(Clipperz.PM) == 'undefined') { Clipperz.PM = {}; }
31if (typeof(Clipperz.PM.DataModel) == 'undefined') { Clipperz.PM.DataModel = {}; }
32
33
34//#############################################################################
35
36Clipperz.PM.DataModel.Statistics = function(args) {
37 args = args || {};
38
39 this._user = args.user;
40 this._data = args.data || null;
41
42 return this;
43}
44
45Clipperz.PM.DataModel.Statistics.prototype = MochiKit.Base.update(null, {
46
47 //-------------------------------------------------------------------------
48
49 'decrypt': function(aVersion, someEncryptedData) {
50 var deferredResult;
51
52//MochiKit.Logging.logDebug(">>> Statistics.decrypt");
53 if (someEncryptedData == Clipperz.PM.Crypto.nullValue) {
54 this.setData({});
55 deferredResult = MochiKit.Async.succeed(this.data());
56 } else {
57 varstatistic;
58 var user;
59
60 statistic = this;
61 user = this.user();
62 deferredResult = new MochiKit.Async.Deferred();
63//deferredResult.addCallback(function() { console.time("Statistics.decrypt.deferredDecrypt")});
64 deferredResult.addCallback(Clipperz.PM.Crypto.deferredDecrypt, user.passphrase(), someEncryptedData, aVersion);
65//deferredResult.addCallback(function() { console.timeEnd("Statistics.decrypt.deferredDecrypt")});
66//deferredResult.addCallback(function() { console.time("Statistics.decrypt.setup")});
67 deferredResult.addCallbacks(
68 MochiKit.Base.partial(function (aStatistic, someData) {
69 aStatistic.setData(someData);
70 return aStatistic.data();
71 }, statistic),
72 MochiKit.Base.partial(function (aStatistic) {
73 MochiKit.Logging.logWarning("resetting user statistics due to an error while decrypting stored data");
74 aStatistic.setData({});
75 return aStatistic.data();
76 }, statistic)
77 );
78//deferredResult.addCallback(function() { console.timeEnd("Statistics.decrypt.setup")});
79
80 deferredResult.callback();
81 }
82//MochiKit.Logging.logDebug("<<< Statistics.decrypt");
83
84 return deferredResult;
85 },
86
87 //-------------------------------------------------------------------------
88
89 'user': function() {
90 return this._user;
91 },
92
93 //-------------------------------------------------------------------------
94
95 'data': function() {
96 return this._data;
97 },
98
99 'setData': function(aValue) {
100 this._data = aValue;
101
102 this.extractInfoFromData(aValue);
103 },
104
105 //-------------------------------------------------------------------------
106
107 'extractInfoFromData': function(someValues) {
108
109 },
110
111 //-------------------------------------------------------------------------
112
113 'encryptedData': function() {
114 return Clipperz.PM.Crypto.deferredEncryptWithCurrentVersion(this.user().passphrase(), this.serializedData());
115 },
116
117 //-------------------------------------------------------------------------
118
119 'serializedData': function() {
120 var result;
121
122//MochiKit.Logging.logDebug(">>> Statistics.serializedData");
123 result = {};
124//MochiKit.Logging.logDebug("<<< Statistics.serializedData");
125
126 return result;
127 },
128
129 //-------------------------------------------------------------------------
130 __syntaxFix__: "syntax fix"
131
132});
133
diff --git a/frontend/beta/js/Clipperz/PM/DataModel/User.js b/frontend/beta/js/Clipperz/PM/DataModel/User.js
new file mode 100644
index 0000000..5aaaff7
--- a/dev/null
+++ b/frontend/beta/js/Clipperz/PM/DataModel/User.js
@@ -0,0 +1,904 @@
1/*
2
3Copyright 2008-2011 Clipperz Srl
4
5This file is part of Clipperz's Javascript Crypto Library.
6Javascript Crypto Library provides web developers with an extensive
7and efficient set of cryptographic functions. The library aims to
8obtain maximum execution speed while preserving modularity and
9reusability.
10For further information about its features and functionalities please
11refer to http://www.clipperz.com
12
13* Javascript Crypto Library is free software: you can redistribute
14 it and/or modify it under the terms of the GNU Affero General Public
15 License as published by the Free Software Foundation, either version
16 3 of the License, or (at your option) any later version.
17
18* Javascript Crypto Library is distributed in the hope that it will
19 be useful, but WITHOUT ANY WARRANTY; without even the implied
20 warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
21 See the GNU Affero General Public License for more details.
22
23* You should have received a copy of the GNU Affero General Public
24 License along with Javascript Crypto Library. If not, see
25 <http://www.gnu.org/licenses/>.
26
27*/
28
29if (typeof(Clipperz) == 'undefined') { Clipperz = {}; }
30if (typeof(Clipperz.PM) == 'undefined') { Clipperz.PM = {}; }
31if (typeof(Clipperz.PM.DataModel) == 'undefined') { Clipperz.PM.DataModel = {}; }
32
33
34//#############################################################################
35
36Clipperz.PM.DataModel.User = function(args) {
37//MochiKit.Logging.logDebug(">>> new User");
38 args = args || {};
39
40 this._username = args.username || null;
41 this._passphrase = args.passphrase || null;
42
43 this._connection = null;
44 this._connectionVersion = 'current';
45
46 this._header = null;
47 this._statistics = null;
48 this._lock = 'new lock';
49
50 this._preferences = null;
51 this._records = {};
52 this._directLoginReferences = {};
53 this._oneTimePasswordManager = null;
54
55 this._isLoadingUserDetails = false;
56 this._loadingUserDetailsPendingQueue = [];
57
58 this._maxNumberOfRecords = Number.MAX_VALUE;
59
60 this._shouldDownloadOfflineCopy = false;
61
62 this._loginInfo = null;
63 this._loginHistory = null;
64
65 this._serverData = null;
66//MochiKit.Logging.logDebug("<<< new User");
67
68 return this;
69}
70
71Clipperz.PM.DataModel.User.prototype = MochiKit.Base.update(null, {
72
73 'toString': function() {
74 return "Clipperz.PM.DataModel.User - " + this.username();
75 },
76
77 //-------------------------------------------------------------------------
78
79 'username': function() {
80 return this._username;
81 },
82
83 'setUsername': function(aValue) {
84 this._username = aValue;
85 },
86
87 //-------------------------------------------------------------------------
88
89 'passphrase': function() {
90 return this._passphrase;
91 },
92
93 'setPassphrase': function(aValue) {
94 this._passphrase = aValue;
95 },
96
97 //-------------------------------------------------------------------------
98
99 'maxNumberOfRecords': function() {
100 return this._maxNumberOfRecords;
101 },
102
103 'setMaxNumberOfRecords': function(aValue) {
104 this._maxNumberOfRecords = aValue;
105 },
106
107 //-------------------------------------------------------------------------
108
109 'errorHandler': function(anErrorString, anException) {
110MochiKit.Logging.logError("- User.errorHandler: " + anErrorString + " (" + anException + ")");
111 },
112
113 //-------------------------------------------------------------------------
114
115 'connectionVersion': function() {
116 return this._connectionVersion;
117 },
118
119 'setConnectionVersion': function(aValue) {
120 this._connectionVersion = aValue;
121 },
122
123 //-------------------------------------------------------------------------
124
125 'connection': function() {
126 if ((this._connection == null) && (this.connectionVersion() != null) ){
127 this._connection = new Clipperz.PM.Crypto.communicationProtocol.versions[this.connectionVersion()]({user:this});
128 }
129
130 return this._connection;
131 },
132
133 'resetConnection': function(aValue) {
134 this._connection = null;
135 },
136
137 //=========================================================================
138
139 'register': function(anInvitationCode) {
140 vardeferredResult;
141 var prng;
142
143//MochiKit.Logging.logError(">>> User.register: " + this);
144 prng = Clipperz.Crypto.PRNG.defaultRandomGenerator();
145
146 deferredResult = new MochiKit.Async.Deferred()
147//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("User.register - 1: " + res); return res;});
148 deferredResult.addCallback(MochiKit.Base.method(prng, 'deferredEntropyCollection'));
149//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("User.register - 2: " + res); return res;});
150 deferredResult.addCallback(MochiKit.Base.method(this.header(), 'updateAllSections'), anInvitationCode);
151//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("User.register - 2.1: " + res); return res;});
152 deferredResult.addCallback(MochiKit.Base.method(this.connection(), 'register'), anInvitationCode);
153//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("User.register - 3: " + res); return res;});
154 deferredResult.callback();
155//MochiKit.Logging.logError("<<< User.register");
156
157 return deferredResult;
158 },
159
160 //=========================================================================
161
162 'connect': function(aValue) {
163 vardeferredResult;
164 var prng;
165
166 prng = Clipperz.Crypto.PRNG.defaultRandomGenerator();
167
168//MochiKit.Logging.logDebug(">>> User.connect");
169 deferredResult = new MochiKit.Async.Deferred();
170//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("1.2.1 - User.connect - 1: "/* + res*/); return res;});
171//deferredResult.addErrback(function(res) {MochiKit.Logging.logDebug("ERROR: " + res); return res;});
172 deferredResult.addCallback(MochiKit.Base.method(prng, 'deferredEntropyCollection'));
173//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("1.2.2 - User.connect - 2: "/* + res*/); return res;});
174//deferredResult.addErrback(function(res) {MochiKit.Logging.logDebug("ERROR: " + res); return res;});
175 deferredResult.addCallback(MochiKit.Base.method(this.connection(), 'login'));
176//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("1.2.3 - User.connect - 3: "/* + res*/); return res;});
177//deferredResult.addErrback(function(res) {MochiKit.Logging.logDebug("ERROR: " + res); return res;});
178
179 // TODO:add an addErrback call here to manage a wrong login. Any error after this point is due to some other causes.
180 // possibly the same exact 'handleConnectionFallback use at the end of this same method.
181
182 if (this.connectionVersion() != 'current') {
183 varcurrentConnection;
184
185 currentVersionConnection = new Clipperz.PM.Crypto.communicationProtocol.versions['current']({user:this});
186
187//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("1.2.4 - User.connect - 4: "/* + res*/); return res;});
188//deferredResult.addErrback(function(res) {MochiKit.Logging.logDebug("ERROR: " + res); return res;});
189 deferredResult.addCallback(Clipperz.NotificationCenter.deferredNotification, this, 'updatedProgressState', 'connection_upgrading');
190//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("1.2.5 - User.connect - 5: "/* + res*/); return res;});
191//deferredResult.addErrback(function(res) {MochiKit.Logging.logDebug("ERROR: " + res); return res;});
192 deferredResult.addCallback(MochiKit.Base.method(this.connection(), 'message'), 'upgradeUserCredentials', currentVersionConnection.serverSideUserCredentials());
193//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("1.2.6 - User.connect - 6: "/* + res*/); return res;});
194//deferredResult.addErrback(function(res) {MochiKit.Logging.logDebug("ERROR: " + res); return res;});
195 }
196
197//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("1.2.7 - User.connect - 7: "/* + res*/); return res;});
198//deferredResult.addErrback(function(res) {MochiKit.Logging.logDebug("ERROR: " + res); return res;});
199 deferredResult.addCallback(Clipperz.NotificationCenter.deferredNotification, this, 'userConnected', null);
200//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("1.2.8 - User.connect - 8: "/* + res*/); return res;});
201//deferredResult.addErrback(function(res) {MochiKit.Logging.logDebug("ERROR: " + res); return res;});
202 deferredResult.addErrback(MochiKit.Base.method(this, 'handleConnectionFallback'));
203//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("1.2.9 - User.connect - 9: "/* + res*/); return res;});
204//deferredResult.addErrback(function(res) {MochiKit.Logging.logDebug("ERROR: " + res); return res;});
205
206 deferredResult.callback(aValue);
207//MochiKit.Logging.logDebug("<<< User.connect");
208
209 return deferredResult;
210 },
211
212 //.........................................................................
213
214 'handleConnectionFallback': function(aValue) {
215 var result;
216//MochiKit.Logging.logDebug(">>> User.handleConnectionFallback");
217 if (aValue instanceof MochiKit.Async.CancelledError) {
218//MochiKit.Logging.logDebug("--- User.handleConnectionFallback - operation cancelled");
219 result = aValue;
220 } else {
221
222//MochiKit.Logging.logDebug("--- User.handleConnectionFallback - an ERROR has occurred - " + aValue);
223 this.resetConnection();
224 this.setConnectionVersion(Clipperz.PM.Crypto.communicationProtocol.fallbackVersions[this.connectionVersion()]);
225
226 if (this.connectionVersion() != null) {
227 result = new MochiKit.Async.Deferred();
228
229 result.addCallback(Clipperz.NotificationCenter.deferredNotification, this, 'updatedProgressState', 'connection_tryOlderSchema');
230 result.addCallback(MochiKit.Base.method(this, 'connect'));
231 result.callback();
232 } else {
233 result = MochiKit.Async.fail(Clipperz.PM.DataModel.User.exception.LoginFailed);
234 }
235 }
236//MochiKit.Logging.logDebug("<<< User.handleConnectionFallback");
237 return result;
238 },
239
240 //=========================================================================
241
242 'header': function() {
243 if (this._header == null) {
244 this._header = new Clipperz.PM.DataModel.Header({user:this});
245 }
246 return this._header;
247 },
248
249 //-------------------------------------------------------------------------
250
251 'statistics': function() {
252 if (this._statistics == null) {
253 this._statistics = new Clipperz.PM.DataModel.Statistics({user:this});
254 }
255 return this._statistics;
256 },
257
258 //-------------------------------------------------------------------------
259
260 'records': function() {
261 return this._records;
262 },
263
264 //.........................................................................
265
266 'addRecord': function(aValue, isBatchUpdate) {
267 this.records()[aValue.reference()] = aValue;
268
269 if (isBatchUpdate != true) {
270 Clipperz.NotificationCenter.notify(aValue, 'recordAdded', null, true);
271 Clipperz.NotificationCenter.notify(this, 'updatedSection', 'records', true);
272 }
273 },
274
275 //-----------------------------------------------------------------------------
276
277 'addNewRecord': function() {
278 varrecord;
279
280//MochiKit.Logging.logDebug(">>> User.addNewRecord");
281 record = new Clipperz.PM.DataModel.Record({user:this});
282 this.addRecord(record);
283 Clipperz.NotificationCenter.notify(this, 'updatedSection', 'records', true);
284//MochiKit.Logging.logDebug("<<< User.addNewRecord");
285
286 return record;
287 },
288
289 //-------------------------------------------------------------------------
290
291 'saveRecords': function(someRecords, aMethodName) {
292 var deferredResult;
293 var methodName;
294 varresult;
295 var i,c;
296
297//console.log("User.saveRecords - someRecords", someRecords);
298 methodName = aMethodName || 'addNewRecords';
299
300 Clipperz.NotificationCenter.notify(this, 'updatedSection', 'records', true);
301//MochiKit.Logging.logDebug(">>> User.saveRecords");
302//MochiKit.Logging.logDebug(">>> [" + (new Date()).valueOf() + "] User.saveRecords");
303/*
304MochiKit.Logging.logDebug("--- User.saveRecords - 1");
305 MochiKit.Iter.forEach(someRecords, function(aRecord) {
306 if (aRecord.headerNotes() != null) {
307 aRecord.setNotes(aRecord.headerNotes());
308 }
309 aRecord.syncDirectLoginReferenceValues();
310 aRecord.currentVersion().createNewVersion();
311 aRecord.updateKey();
312 });
313MochiKit.Logging.logDebug("--- User.saveRecords - 2");
314*/
315
316 result = {'records': []};
317
318 deferredResult = new MochiKit.Async.Deferred();
319 c = someRecords.length;
320 for (i=0; i<c; i++) {
321 deferredResult.addCallback(function(aRecord) {
322 if (aRecord.headerNotes() != null) {
323 aRecord.setNotes(aRecord.headerNotes());
324 }
325 aRecord.syncDirectLoginReferenceValues();
326 aRecord.currentVersion().createNewVersion();
327 aRecord.updateKey();
328 }, someRecords[i]);
329 deferredResult.addCallback(MochiKit.Async.wait, 0.1);
330 }
331//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("User.saveRecords - 1 " + res); return res;});
332 deferredResult.addCallback(Clipperz.NotificationCenter.deferredNotification, this, 'updatedProgressState', 'saveCard_collectRecordInfo');
333//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("User.saveRecords - 2 " + res); return res;});
334
335 deferredResult.addCallback(Clipperz.NotificationCenter.deferredNotification, this, 'updatedProgressState', 'saveCard_encryptUserData');
336//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("User.saveRecords - 3 " + res); return res;});
337 deferredResult.addCallback(MochiKit.Base.method(this, 'encryptedData'));
338//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("User.saveRecords - 4 " + res); return res;});
339 deferredResult.addCallback(function(aResult, res) {
340 aResult['user'] = res;
341 return aResult;
342 }, result);
343//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("User.saveRecords - 5 " + res); return res;});
344
345 c = someRecords.length;
346 for (i=0; i<c; i++) {
347 var recordData;
348
349 recordData = {};
350
351//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("User.saveRecords - 6.1 " + res); return res;});
352 deferredResult.addCallback(Clipperz.NotificationCenter.deferredNotification, this, 'updatedProgressState', 'saveCard_encryptRecordData');
353//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("User.saveRecords - 6.2 " + res); return res;});
354 deferredResult.addCallback(MochiKit.Base.method(someRecords[i], 'encryptedData'));
355//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("User.saveRecords - 6.3 " + res); return res;});
356 deferredResult.addCallback(function(aResult, res) {
357 aResult['record'] = res;
358 return aResult;
359 }, recordData);
360//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("User.saveRecords - 6.4 " + res); return res;});
361
362 deferredResult.addCallback(Clipperz.NotificationCenter.deferredNotification, this, 'updatedProgressState', {} /*'saveCard_encryptRecordVersions'*/);
363//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("User.saveRecords - 6.5 " + res); return res;});
364 deferredResult.addCallback(MochiKit.Base.method(someRecords[i].currentVersion(), 'encryptedData'));
365//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("User.saveRecords - 6.6 " + res); return res;});
366 deferredResult.addCallback(function(aResult, res) {
367 aResult['currentRecordVersion'] = res;
368 return aResult;
369 }, recordData);
370//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("User.saveRecords - 6.7 " + res); return res;});
371
372 deferredResult.addCallback(function(aResult, res) {
373 aResult['records'].push(res);
374 return aResult;
375 }, result);
376//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("User.saveRecords - 6.8 " + res); return res;});
377 }
378
379//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("User.saveRecords - 7 " + res); return res;});
380 deferredResult.addCallback(Clipperz.NotificationCenter.deferredNotification, this, 'updatedProgressState', 'saveCard_sendingData');
381//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("User.saveRecords - 8 " + res); return res;});
382 deferredResult.addCallback(MochiKit.Base.method(this.connection(), 'message'), methodName);
383//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("User.saveRecords - 9 " + res); return res;});
384
385 for (i=0; i<c; i++) {
386//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("User.saveRecords - 9.1 " + res); return res;});
387 deferredResult.addCallback(MochiKit.Base.method(someRecords[i], 'takeSnapshotOfCurrentData'));
388//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("User.saveRecords - 9.2 " + res); return res;});
389 deferredResult.addCallback(MochiKit.Base.method(someRecords[i], 'setIsBrandNew'), false);
390//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("User.saveRecords - 9.3 " + res); return res;});
391 }
392
393//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("User.saveRecords - 10 " + res); return res;});
394 deferredResult.addCallback(Clipperz.NotificationCenter.deferredNotification, this, 'notify', 'recordUpdated');
395//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("User.saveRecords - 11 " + res); return res;});
396 deferredResult.addCallback(Clipperz.NotificationCenter.deferredNotification, this, 'notify', 'directLoginUpdated');
397//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("User.saveRecords - 12 " + res); return res;});
398 deferredResult.callback();
399
400 return deferredResult;
401 },
402
403 //-------------------------------------------------------------------------
404
405 'removeRecord': function(aRecord) {
406//MochiKit.Logging.logDebug(">>> User.removeRecord");
407 delete this.records()[aRecord.reference()];
408//MochiKit.Logging.logDebug("--- User.removeRecord - 1");
409 Clipperz.NotificationCenter.notify(aRecord, 'recordRemoved', null, false);
410 Clipperz.NotificationCenter.notify(this, 'updatedSection', 'records', true);
411//MochiKit.Logging.logDebug("<<< User.removeRecord");
412 },
413
414 //-------------------------------------------------------------------------
415
416 'deleteRecordsAction': function(someRecords) {
417 vardeferredResult;
418 var parameters;
419
420//MochiKit.Logging.logDebug(">>> User.deleteRecordsAction - someRecords.length: " + someRecords.length);
421 parameters = {};
422 deferredResult = new MochiKit.Async.Deferred();
423//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("User.deleteRecordsAction - 1 " + res); return res;});
424 deferredResult.addCallback(Clipperz.NotificationCenter.deferredNotification, this, 'updatedProgressState', 'deleteRecord_collectData');
425//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("User.deleteRecordsAction - 2 " + res); return res;});
426 deferredResult.addCallback(function(someParameters, someRecords) {
427 var recordReferences;
428
429 recordReferences = MochiKit.Base.map(function(aRecord) {
430 var result;
431
432 result = aRecord.reference();
433 aRecord.remove();
434
435 return result;
436 }, someRecords);
437 someParameters.recordReferences = recordReferences;
438
439 return someParameters;
440 }, parameters);
441//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("User.deleteRecordsAction - 3 " + res); return res;});
442 deferredResult.addCallback(Clipperz.NotificationCenter.deferredNotification, this, 'updatedProgressState', 'deleteRecord_encryptData');
443//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("User.deleteRecordsAction - 4 " + res); return res;});
444 deferredResult.addCallback(MochiKit.Base.method(this, 'encryptedData'));
445//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("User.deleteRecordsAction - 5 " + res); return res;});
446 deferredResult.addCallback(function(someParameters, anUserEncryptedData) {
447 someParameters.user = anUserEncryptedData;
448 return someParameters;
449 }, parameters);
450//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("User.deleteRecordsAction - 6 " + res); return res;});
451 deferredResult.addCallback(Clipperz.NotificationCenter.deferredNotification, this, 'updatedProgressState', 'deleteRecord_sendingData');
452//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("User.deleteRecords parameters: " + Clipperz.Base.serializeJSON(res)); return res;});
453//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("User.deleteRecordsAction - 7 " + res); return res;});
454 deferredResult.addCallback(MochiKit.Base.method(this.connection(), 'message'), 'deleteRecords');
455//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("User.deleteRecordsAction - 8 " + res); return res;});
456 deferredResult.addCallback(Clipperz.NotificationCenter.deferredNotification, this, 'updatedProgressState', 'deleteRecord_updatingInterface');
457//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("User.deleteRecordsAction - 9 " + res); return res;});
458 deferredResult.callback(someRecords);
459//MochiKit.Logging.logDebug("<<< User.deleteRecordsAction");
460
461 return deferredResult;
462 },
463
464 //-------------------------------------------------------------------------
465
466 'resetAllLocalData': function() {
467 this.resetConnection();
468
469 this.setUsername("");
470 this.setPassphrase("");
471
472 this._header = null;
473 this._statistics = null;
474 this._preferences = null;
475 this._records = {};
476 this._directLoginReferences = {};
477 },
478
479 //-------------------------------------------------------------------------
480
481 'deleteAccountAction': function() {
482 var deferredResult;
483
484//MochiKit.Logging.logDebug(">>> user.deleteAccountAction - " + this);
485 deferredResult = new MochiKit.Async.Deferred();
486 deferredResult.addCallback(MochiKit.Base.method(this.connection(), 'message'), 'deleteUser');
487 deferredResult.addCallback(MochiKit.Base.method(this, 'resetAllLocalData'));
488 deferredResult.callback();
489//MochiKit.Logging.logDebug("<<< user.deleteAccountAction - " + this);
490
491 return deferredResult;
492 },
493
494 //-------------------------------------------------------------------------
495
496 'encryptedData': function() {
497 var deferredResult;
498 varresult;
499
500 result = {};
501
502 deferredResult = new MochiKit.Async.Deferred();
503
504//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("User.encryptedData - 0: " + res); return res;});
505 deferredResult.addCallback(MochiKit.Base.method(this.header(), 'encryptedData'));
506//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("User.encryptedData - 1: " + res); return res;});
507 deferredResult.addCallback(function(aResult, aValue) {
508 aResult['header'] = aValue;
509 }, result);
510//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("User.encryptedData - 2: " + res); return res;});
511
512 deferredResult.addCallback(MochiKit.Base.method(this.statistics(), 'encryptedData'));
513//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("User.encryptedData - 3: " + res); return res;});
514 deferredResult.addCallback(function(aResult, aValue) {
515 aResult['statistics'] = aValue;
516 }, result);
517//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("User.encryptedData - 4: " + res); return res;});
518
519 deferredResult.addCallback(MochiKit.Base.bind(function(aResult, aValue) {
520 aResult['version'] = Clipperz.PM.Crypto.encryptingFunctions.currentVersion;
521 aResult['lock'] = this.lock();
522
523 return aResult;
524 }, this), result);
525//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("User.encryptedData - 5: " + res); return res;});
526 deferredResult.callback();
527
528 return deferredResult;
529 },
530
531 //-------------------------------------------------------------------------
532
533 'preferences': function() {
534 if (this._preferences == null) {
535 this._preferences = new Clipperz.PM.DataModel.UserPreferences({user:this});
536 }
537
538 return this._preferences;
539 },
540/*
541 'setPreferences': function(aValue) {
542 this._preferences = aValue;
543
544 if (this._preferences.preferredLanguage() != null) {
545 Clipperz.PM.Strings.Languages.setSelectedLanguage(this._preferences.preferredLanguage());
546 } else {
547//MochiKit.Logging.logDebug("### keepping the browser selected language: " + Clipperz.PM.Strings.selectedLanguage);
548 }
549 },
550*/
551 //-------------------------------------------------------------------------
552
553 'oneTimePasswordManager': function() {
554 if (this._oneTimePasswordManager == null) {
555 this._oneTimePasswordManager = new Clipperz.PM.DataModel.OneTimePasswordManager(this, null);
556 }
557
558 return this._oneTimePasswordManager;
559 },
560
561 //-------------------------------------------------------------------------
562
563 'directLoginReferences': function() {
564 return this._directLoginReferences;
565 },
566
567 'addDirectLoginReference': function(aDirectLoginReference, isBatchUpdate) {
568//MochiKit.Logging.logDebug(">>> User.addDirectLoginReference");
569 this.directLoginReferences()[aDirectLoginReference.reference()] = aDirectLoginReference;
570
571 if (isBatchUpdate != true) {
572 Clipperz.NotificationCenter.notify(aDirectLoginReference, 'directLoginAdded');
573 Clipperz.NotificationCenter.notify(this, 'updatedSection', 'directLogins', true);
574 }
575 },
576
577 'removeDirectLoginReference': function(aDirectLoginReference) {
578 delete this.directLoginReferences()[aDirectLoginReference.reference()];
579 Clipperz.NotificationCenter.notify(aDirectLoginReference, 'directLoginRemoved');
580 Clipperz.NotificationCenter.notify(this, 'updatedSection', 'directLogins', true);
581 },
582
583 //.........................................................................
584
585 'addDirectLogin': function(aDirectLogin) {
586 varnewDirectLoginReference;
587
588 newDirectLoginReference = new Clipperz.PM.DataModel.DirectLoginReference({user:this, directLogin:aDirectLogin})
589 this.addDirectLoginReference(newDirectLoginReference);
590 },
591
592 'synchronizeDirectLogin': function(aDirectLogin) {
593 var directLoginReference;
594
595 directLoginReference = this.directLoginReferences()[aDirectLogin.reference()];
596 if (typeof(directLoginReference) != 'undefined') {
597 directLoginReference.synchronizeValues(aDirectLogin);
598 } else {
599 this.addDirectLogin(aDirectLogin);
600 }
601 },
602
603 'removeDirectLogin': function(aDirectLogin) {
604 this.removeDirectLoginReference(aDirectLogin);
605 },
606
607 //-------------------------------------------------------------------------
608
609 'changeCredentials': function(aUsername, aPassphrase) {
610 vardeferredResult;
611 var result;
612
613 result = {};
614
615 deferredResult = new MochiKit.Async.Deferred();
616
617 deferredResult.addCallback(MochiKit.Base.method(this.header(), 'loadAllSections'));
618 deferredResult.addCallback(MochiKit.Base.method(this.header(), 'updateAllSections'));
619
620 deferredResult.addCallback(MochiKit.Base.bind(function(aUsername, aPssphrase) {
621 this.setUsername(aUsername);
622 this.setPassphrase(aPassphrase);
623 }, this), aUsername, aPassphrase)
624
625//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("User.changeCredentials - 1: " + res); return res;});
626 deferredResult.addCallback(Clipperz.NotificationCenter.deferredNotification, this, 'updatedProgressState', 'changeCredentials_encryptingData');
627//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("User.changeCredentials - 2: " + res); return res;});
628 deferredResult.addCallback(MochiKit.Base.method(this, 'encryptedData'));
629//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("User.changeCredentials - 3: " + res); return res;});
630 deferredResult.addCallback(function(aResult, anEncryptedData) {
631 aResult['user'] = anEncryptedData;
632
633 return aResult;
634 }, result);
635//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("User.changeCredentials - 4: " + res); return res;});
636 deferredResult.addCallback(Clipperz.NotificationCenter.deferredNotification, this, 'updatedProgressState', 'changeCredentials_creatingNewCredentials');
637//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("User.changeCredentials - 5: " + res); return res;});
638 deferredResult.addCallback(function(aResult, anUser) {
639 varnewConnection;
640
641 newConnection = new Clipperz.PM.Crypto.communicationProtocol.versions[Clipperz.PM.Crypto.communicationProtocol.currentVersion]({user:anUser})
642 aResult['credentials'] = newConnection.serverSideUserCredentials();
643
644 return aResult;
645 }, result, this);
646//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("User.changeCredentials - 6: " + res); return res;});
647 deferredResult.addCallback(MochiKit.Base.method(this.oneTimePasswordManager(), 'encryptedData'));
648//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("User.changeCredentials - 7: " + res); return res;});
649 deferredResult.addCallback(function(aResult, anEncryptedData) {
650 aResult['oneTimePasswords'] = anEncryptedData;
651
652 return aResult;
653 }, result);
654//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("User.changeCredentials - 8: " + res); return res;});
655 deferredResult.addCallback(Clipperz.NotificationCenter.deferredNotification, this, 'updatedProgressState', 'changeCredentials_sendingCredentials');
656//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("User.changeCredentials - 9: " + res); return res;});
657 deferredResult.addCallback(MochiKit.Base.method(this.connection(), 'message'), 'upgradeUserCredentials');
658//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("User.changeCredentials - 10: " + res); return res;});
659 deferredResult.addCallback(Clipperz.NotificationCenter.deferredNotification, this, 'updatedProgressState', 'changeCredentials_done');
660//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("User.changeCredentials - 11: " + res); return res;});
661 deferredResult.callback();
662
663 return deferredResult;
664 },
665
666 //-------------------------------------------------------------------------
667
668 'doLogout': function() {
669 var deferredResult;
670
671 deferredResult = new MochiKit.Async.Deferred();
672//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("User.doLogout - 1: " + res); return res;});
673 deferredResult.addCallback(MochiKit.Base.method(this.connection(), 'logout'));
674//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("User.doLogout - 2: " + res); return res;});
675 deferredResult.addCallback(MochiKit.Base.method(this, 'resetAllLocalData'));
676//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("User.doLogout - 3: " + res); return res;});
677
678 deferredResult.callback();
679
680 return deferredResult;
681 },
682
683 //-------------------------------------------------------------------------
684
685 'lock': function() {
686 this.setPassphrase("")
687 this.connection().logout();
688 this.connection().resetSrpConnection();
689 },
690
691 'unlockWithPassphrase': function(aValue) {
692 vardeferredResult;
693 // varconnection;
694
695 // connection = this.connection();
696
697 deferredResult = new MochiKit.Async.Deferred();
698//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("User.unlockWithPassphrase 1: " + res); return res;});
699 deferredResult.addCallback(MochiKit.Base.method(this, 'setPassphrase'));
700//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("User.unlockWithPassphrase 2: " + res); return res;});
701 // deferredResult.addCallback(MochiKit.Base.method(connection, 'message'), 'echo', {'echo':"echo"});
702 deferredResult.addCallback(MochiKit.Base.method(this.connection(), 'reestablishConnection'));
703//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("User.unlockWithPassphrase 3: " + res); return res;});
704 // deferredResult.addErrback(MochiKit.Base.method(this, 'setPassphrase', ""));
705 deferredResult.addErrback(MochiKit.Base.bind(function(anError) {
706 this.setPassphrase("");
707 this.connection().resetSrpConnection();
708
709 return anError;
710 }, this));
711//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("User.unlockWithPassphrase 4: " + res); return res;});
712 deferredResult.callback(aValue);
713
714 return deferredResult;
715 },
716
717 //-------------------------------------------------------------------------
718 //-------------------------------------------------------------------------
719 //-------------------------------------------------------------------------
720 //-------------------------------------------------------------------------
721 //-------------------------------------------------------------------------
722 //-------------------------------------------------------------------------
723 //-------------------------------------------------------------------------
724 //-------------------------------------------------------------------------
725 //-------------------------------------------------------------------------
726 //-------------------------------------------------------------------------
727 //-------------------------------------------------------------------------
728 //-------------------------------------------------------------------------
729
730 'serverData': function() {
731 return this._serverData;
732 },
733
734 'setServerData': function(aValue) {
735//MochiKit.Logging.logDebug(">>> User.setServerData");
736 this._serverData = aValue;
737
738 if (typeof(aValue.maxNumberOfRecords) != 'undefined') {
739 this.setMaxNumberOfRecords(aValue.maxNumberOfRecords);
740 }
741//MochiKit.Logging.logDebug("<<< User.setServerData");
742 },
743
744 //-------------------------------------------------------------------------
745
746 'isLoadingUserDetails': function() {
747 return this._isLoadingUserDetails;
748 },
749
750 'setIsLoadingUserDetails': function(aValue) {
751 this._isLoadingUserDetails = aValue;
752 },
753
754 //-------------------------------------------------------------------------
755
756 'loadingUserDetailsPendingQueue': function() {
757 return this._loadingUserDetailsPendingQueue;
758 },
759
760 'flushLoadingUserDetailsPendingQueue': function() {
761 var queue;
762
763//MochiKit.Logging.logDebug(">>> User.flushLoadingUserDetailsPendingQueue");
764 queue = this.loadingUserDetailsPendingQueue();
765
766 while(queue.length > 0) {
767//MochiKit.Logging.logDebug("--- User.flushLoadingUserDetailsPendingQueue - pop");
768 queue.pop().callback();
769 }
770//MochiKit.Logging.logDebug("<<< User.flushLoadingUserDetailsPendingQueue");
771 },
772
773 //-------------------------------------------------------------------------
774
775 'getUserDetails': function() {
776 var deferredResult;
777
778//MochiKit.Logging.logDebug(">>> User.getUserDetails");
779 deferredResult = new MochiKit.Async.Deferred();
780 if ((this.serverData() == null) && (this.isLoadingUserDetails() == false)) {
781 deferredResult.addCallback(MochiKit.Base.method(this, 'setIsLoadingUserDetails', true));
782 deferredResult.addCallback(MochiKit.Base.method(this.connection(), 'message'), 'getUserDetails');
783 deferredResult.addCallback(MochiKit.Base.method(this, 'setServerData'));
784 deferredResult.addCallback(MochiKit.Base.method(this, 'flushLoadingUserDetailsPendingQueue'));
785 deferredResult.addCallback(MochiKit.Base.method(this, 'setIsLoadingUserDetails', false));
786 }
787
788 deferredResult.addCallback(MochiKit.Base.method(this, 'serverData'));
789
790 if (this.isLoadingUserDetails() == false) {
791 deferredResult.callback();
792 } else {
793 this.loadingUserDetailsPendingQueue().push(deferredResult);
794 }
795//MochiKit.Logging.logDebug("<<< User.getUserDetails");
796
797 return deferredResult;
798 },
799
800 //-------------------------------------------------------------------------
801
802 'loadRecords': function() {
803 return this.header().loadRecords();
804 },
805
806 'loadDirectLogins': function() {
807 return this.header().loadDirectLogins();
808 },
809
810 'loadPreferences': function() {
811 return this.header().loadPreferences();
812 },
813
814 'loadOneTimePasswords': function() {
815 return this.header().loadOneTimePasswords();
816 },
817
818 //-------------------------------------------------------------------------
819
820 'loadLoginHistory': function() {
821 var deferredResult;
822
823 deferredResult = new MochiKit.Async.Deferred();
824 deferredResult.addCallback(MochiKit.Base.method(this.connection(), 'message'), 'getLoginHistory');
825 deferredResult.addCallback(function(aResult) {
826 return aResult['result'];
827 });
828 deferredResult.addCallback(MochiKit.Base.method(this, 'setLoginHistory'));
829 deferredResult.addCallback(MochiKit.Base.method(this, 'loginHistory'));
830 deferredResult.callback();
831
832 return deferredResult;
833 },
834
835 //-------------------------------------------------------------------------
836
837 'shouldDownloadOfflineCopy': function() {
838 return this._shouldDownloadOfflineCopy;
839 },
840
841 'setShouldDownloadOfflineCopy': function(aValue) {
842 this._shouldDownloadOfflineCopy = aValue;
843 },
844
845 //-------------------------------------------------------------------------
846
847 'loginInfo': function() {
848 return this._loginInfo;
849 },
850
851 'setLoginInfo': function(aValue) {
852 this._loginInfo = aValue;
853//MochiKit.Logging.logDebug("### LoginInfo: " + Clipperz.Base.serializeJSON(aValue));
854 },
855
856 //-------------------------------------------------------------------------
857
858 'loginHistory': function() {
859 return this._loginHistory;
860 },
861
862 'setLoginHistory': function(aValue) {
863 this._loginHistory = aValue;
864 },
865/*
866 'loginInfoWithOneTimePasswordReference': function(aOneTimePasswordReference) {
867 var result;
868 var i,c;
869
870 result = null;
871 c = this.loginHistory().length;
872 for (i=0; (i<c) && (result == null); i++) {
873 var currentLoginInfo;
874
875 currentLoginInfo = this.loginHistory()[i];
876 if (currentLoginInfo['oneTimePasswordReference'] == aOneTimePasswordReference) {
877 result = currentLoginInfo;
878 }
879 }
880
881 return result;
882 },
883 */
884 //-------------------------------------------------------------------------
885
886 'lock': function() {
887 return this._lock;
888 },
889
890 'setLock': function(aValue) {
891//MochiKit.Logging.logDebug("=== User.setLock: " + aValue);
892 this._lock = aValue;
893 },
894
895 //-------------------------------------------------------------------------
896 __syntaxFix__: "syntax fix"
897
898});
899
900
901Clipperz.PM.DataModel.User.exception = {
902 LoginFailed: new MochiKit.Base.NamedError("Clipperz.PM.DataModel.User.exception.LoginFailed")
903};
904
diff --git a/frontend/beta/js/Clipperz/PM/DataModel/UserPreferences.js b/frontend/beta/js/Clipperz/PM/DataModel/UserPreferences.js
new file mode 100644
index 0000000..dc73ce1
--- a/dev/null
+++ b/frontend/beta/js/Clipperz/PM/DataModel/UserPreferences.js
@@ -0,0 +1,197 @@
1/*
2
3Copyright 2008-2011 Clipperz Srl
4
5This file is part of Clipperz's Javascript Crypto Library.
6Javascript Crypto Library provides web developers with an extensive
7and efficient set of cryptographic functions. The library aims to
8obtain maximum execution speed while preserving modularity and
9reusability.
10For further information about its features and functionalities please
11refer to http://www.clipperz.com
12
13* Javascript Crypto Library is free software: you can redistribute
14 it and/or modify it under the terms of the GNU Affero General Public
15 License as published by the Free Software Foundation, either version
16 3 of the License, or (at your option) any later version.
17
18* Javascript Crypto Library is distributed in the hope that it will
19 be useful, but WITHOUT ANY WARRANTY; without even the implied
20 warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
21 See the GNU Affero General Public License for more details.
22
23* You should have received a copy of the GNU Affero General Public
24 License along with Javascript Crypto Library. If not, see
25 <http://www.gnu.org/licenses/>.
26
27*/
28
29if (typeof(Clipperz) == 'undefined') { Clipperz = {}; }
30if (typeof(Clipperz.PM) == 'undefined') { Clipperz.PM = {}; }
31if (typeof(Clipperz.PM.DataModel) == 'undefined') { Clipperz.PM.DataModel = {}; }
32
33
34//#############################################################################
35
36Clipperz.PM.DataModel.UserPreferences = function(args) {
37 args = args || {};
38
39 this._user = args['user']; delete args['user'];
40 this._config = args;
41
42 return this;
43}
44
45Clipperz.PM.DataModel.UserPreferences.prototype = MochiKit.Base.update(null, {
46
47 //-------------------------------------------------------------------------
48
49 'config': function() {
50 return this._config;
51 },
52
53 //-------------------------------------------------------------------------
54
55 'user': function() {
56 return this._user;
57 },
58
59 //-------------------------------------------------------------------------
60
61 'updateWithData': function(someValues) {
62 var currentLanguage;
63
64//MochiKit.Logging.logDebug(">>> Clipperz.PM.DataModel.UserPreferences.updateWithData: " + Clipperz.Base.serializeJSON(someValues));
65 currentLanguage = this.preferredLanguage();
66
67 MochiKit.Base.update(this._config, someValues);
68
69 if (this.preferredLanguage() != currentLanguage) {
70 Clipperz.PM.Strings.Languages.setSelectedLanguage(this.preferredLanguage());
71 } else {
72//MochiKit.Logging.logDebug("### keepping the browser selected language: " + Clipperz.PM.Strings.selectedLanguage);
73 }
74
75 return this;
76 },
77
78 //-------------------------------------------------------------------------
79
80 'configValue': function(aConfigName, aDefaultValue) {
81 var result;
82
83//MochiKit.Logging.logDebug(">>> UserPreferences.configValue - config: " + Clipperz.Base.serializeJSON(this.config()));
84 if (typeof(this.config()[aConfigName]) == 'undefined') {
85 result = aDefaultValue;
86 } else {
87 result = this.config()[aConfigName];
88 }
89//MochiKit.Logging.logDebug("<<< UserPreferences.configValue");
90
91 return result;
92 },
93
94 'setConfigValue': function(aConfigName, aValue) {
95 var result;
96
97 if (aValue != this.configValue(aConfigName)) {
98 if (aValue == null) {
99 delete this.config()[aConfigName]
100 } else {
101 this.config()[aConfigName] = aValue;
102 }
103
104 Clipperz.NotificationCenter.notify(this.user(), 'updatedSection', 'preferences', true);
105
106 result = true;
107 } else {
108 result = false;
109 }
110
111 return result;
112 },
113
114 //-------------------------------------------------------------------------
115
116 'useSafeEditMode': function() {
117 return this.configValue('useSafeEditMode', true);
118 },
119
120 'setUseSafeEditMode': function(aValue) {
121 this.setConfigValue('useSafeEditMode', aValue);
122 },
123
124 //-------------------------------------------------------------------------
125
126 'preferredLanguage': function() {
127 return this.configValue('preferredLanguage', null);
128 },
129
130 'setPreferredLanguage': function(aValue) {
131 if (this.setConfigValue('preferredLanguage', aValue)) {
132 Clipperz.PM.Strings.Languages.setSelectedLanguage(this.preferredLanguage());
133 }
134 },
135
136 //-------------------------------------------------------------------------
137
138 'shouldShowDonationPanel': function() {
139 return this.configValue('shouldShowDonationPanel', true);
140 },
141
142 'setShouldShowDonationPanel': function(aValue) {
143 this.setConfigValue('shouldShowDonationPanel', aValue);
144 },
145
146 //-------------------------------------------------------------------------
147
148 'disableUnsecureFaviconLoadingForIE': function() {
149 return this.configValue('disableUnsecureFaviconLoadingForIE', false);
150 },
151
152 'setDisableUnsecureFaviconLoadingForIE': function(aValue) {
153 this.setConfigValue('disableUnsecureFaviconLoadingForIE', aValue);
154 },
155
156 //-------------------------------------------------------------------------
157
158 'serializedData': function() {
159 return this.config();
160 },
161
162 //-------------------------------------------------------------------------
163
164 'saveChanges': function(aReferenceElement) {
165 vardeferredResult;
166
167 deferredResult = new MochiKit.Async.Deferred();
168
169 deferredResult.addCallback(MochiKit.Base.method(Clipperz.PM.Components.MessageBox(), 'deferredShow'),
170 {
171 title:"", //Clipperz.PM.Strings['accountPreferencesSavingPanelTitle_Step1'],
172 text:"", //Clipperz.PM.Strings['accountPreferencesSavingPanelText_Step1'],
173 width:240,
174 showProgressBar:true,
175 showCloseButton:false
176 },
177 aReferenceElement
178 );
179 deferredResult.addCallback(Clipperz.NotificationCenter.deferredNotification, this, 'updatedProgressState', 'account_savingPreferences_1');
180 deferredResult.addCallback(MochiKit.Base.method(this.user(), 'encryptedData'));
181 deferredResult.addCallback(function(res) {
182 return {user:res};
183 })
184 deferredResult.addCallback(Clipperz.NotificationCenter.deferredNotification, this, 'updatedProgressState', 'account_savingPreferences_2');
185 deferredResult.addCallback(MochiKit.Base.method(this.user().connection(), 'message'), 'updateData');
186 deferredResult.addCallback(Clipperz.PM.Components.MessageBox().hide, YAHOO.ext.Element.get('main'));
187 deferredResult.addCallback(Clipperz.NotificationCenter.deferredNotification, this, 'updatedPreferences', null);
188
189 deferredResult.callback();
190
191 return deferredResult;
192 },
193
194 //-------------------------------------------------------------------------
195 __syntaxFix__: "syntax fix"
196});
197
diff --git a/frontend/beta/js/Clipperz/PM/Date.js b/frontend/beta/js/Clipperz/PM/Date.js
new file mode 100644
index 0000000..5e21340
--- a/dev/null
+++ b/frontend/beta/js/Clipperz/PM/Date.js
@@ -0,0 +1,193 @@
1/*
2
3Copyright 2008-2011 Clipperz Srl
4
5This file is part of Clipperz's Javascript Crypto Library.
6Javascript Crypto Library provides web developers with an extensive
7and efficient set of cryptographic functions. The library aims to
8obtain maximum execution speed while preserving modularity and
9reusability.
10For further information about its features and functionalities please
11refer to http://www.clipperz.com
12
13* Javascript Crypto Library is free software: you can redistribute
14 it and/or modify it under the terms of the GNU Affero General Public
15 License as published by the Free Software Foundation, either version
16 3 of the License, or (at your option) any later version.
17
18* Javascript Crypto Library is distributed in the hope that it will
19 be useful, but WITHOUT ANY WARRANTY; without even the implied
20 warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
21 See the GNU Affero General Public License for more details.
22
23* You should have received a copy of the GNU Affero General Public
24 License along with Javascript Crypto Library. If not, see
25 <http://www.gnu.org/licenses/>.
26
27*/
28
29if (typeof(Clipperz) == 'undefined') { Clipperz = {}; }
30if (typeof(Clipperz.PM) == 'undefined') { Clipperz.PM = {}; }
31if (typeof(Clipperz.PM.Date) == 'undefined') { Clipperz.PM.Date = {}; }
32
33Clipperz.PM.Date.VERSION = "0.1";
34Clipperz.PM.Date.NAME = "Clipperz.PM.Date";
35
36MochiKit.Base.update(Clipperz.PM.Date, {
37
38 '__repr__': function () {
39 return "[" + this.NAME + " " + this.VERSION + "]";
40 },
41
42 //-------------------------------------------------------------------------
43
44 'toString': function () {
45 return this.__repr__();
46 },
47
48 //-------------------------------------------------------------------------
49
50 'locale': function() {
51 return {
52 'amDesignation':Clipperz.PM.Strings['calendarStrings']['amDesignation'],
53 'pmDesignation':Clipperz.PM.Strings['calendarStrings']['pmDesignation'],
54 'days': Clipperz.PM.Strings['calendarStrings']['days'],
55 'shortDays': Clipperz.PM.Strings['calendarStrings']['shortDays'],
56 'shortMonths': Clipperz.PM.Strings['calendarStrings']['shortMonths'],
57 'months': Clipperz.PM.Strings['calendarStrings']['months']
58 }
59 },
60
61 //=========================================================================
62/*
63 'formatDateWithPHPLikeTemplate': function(aDate, aTemplate) {
64 return Clipperz.Date.formatDateWithPHPLikeTemplateAndLocale(aDate, aTemplate, Clipperz.PM.Date.locale());
65 },
66
67 'parseDateWithPHPLikeTemplate': function(aDate, aTemplate) {
68 return Clipperz.Date.parseDateWithPHPTemplateAndLocale(aDate, aTemplate, Clipperz.PM.Date.locale());
69 },
70
71 //=========================================================================
72
73 'formatDateWithJavaLikeTemplate': function(aDate, aTemplate) {
74 return Clipperz.Date.formatDateWithJavaLikeTemplateAndLocale(aDate, aTemplate, Clipperz.PM.Date.locale());
75 },
76
77 'parseDateWithJavaLikeTemplate': function(aDate, aTemplate) {
78 return Clipperz.Date.parseDateWithJavaLikeTemplateAndLocale(aDate, aTemplate, Clipperz.PM.Date.locale());
79 },
80*/
81 //=========================================================================
82
83 'formatDateWithTemplate': function(aDate, aTemplate) {
84 var result;
85
86 if (aDate == null) {
87 result = ""
88 } else {
89 result = Clipperz.Date.formatDateWithPHPLikeTemplateAndLocale(aDate, aTemplate, Clipperz.PM.Date.locale());
90 };
91
92 return result;
93 },
94
95 'parseDateWithTemplate': function(aValue, aTemplate) {
96 return Clipperz.Date.parseDateWithPHPTemplateAndLocale(aValue, aTemplate, Clipperz.PM.Date.locale());
97 },
98
99 //=========================================================================
100
101 'formatDateWithUTCFormat': function(aDate) {
102 return Clipperz.Date.formatDateWithUTCFormatAndLocale(aDate, Clipperz.PM.Date.locale());
103 },
104
105 'parseDateWithUTCFormat': function(aValue) {
106 var result;
107
108 if (aValue == null) {
109 result = null;
110 } else {
111 result = Clipperz.Date.parseDateWithUTCFormatAndLocale(aValue, Clipperz.PM.Date.locale());
112 }
113
114 return result;
115 },
116
117 //=========================================================================
118
119 'getElapsedTimeDescription': function(aDate) {
120 var result;
121
122 result = ""
123
124 if (aDate != null) {
125 var now;
126 var elapsedTime;
127
128 var millisencondsInAMinute;
129 var millisencondsInAnHour;
130 var millisencondsInADay;
131 var millisencondsInAWeek;
132 var millisencondsInAMonth;
133
134 now = new Date();
135 elapsedTime = now.getTime() - aDate.getTime();
136
137 millisencondsInAMinute = 60 * 1000;
138 millisencondsInAnHour = millisencondsInAMinute * 60;
139 millisencondsInADay = millisencondsInAnHour * 24;
140 millisencondsInAWeek = millisencondsInADay * 7;
141 millisencondsInAMonth = millisencondsInAWeek * 5;
142
143 if ((elapsedTime / millisencondsInAMonth) > 1) {
144 result = Clipperz.PM.Strings['elapsedTimeDescriptions']['MORE_THAN_A_MONTH_AGO'];
145 } else if ((elapsedTime / millisencondsInAWeek) > 1) {
146 var elapsedWeeks;
147
148 elapsedWeeks = Math.floor((elapsedTime / millisencondsInAWeek));
149 if (elapsedWeeks == 1) {
150 result = Clipperz.PM.Strings['elapsedTimeDescriptions']['MORE_THAN_A_WEEK_AGO'];
151 } else {
152 result = Clipprez.PM.Strings['elapsedTimeDescriptions']['MORE_THAN_*_WEEKS_AGO'].replace(/__elapsed__/, elapsedWeeks);
153 }
154 } else if ((elapsedTime / millisencondsInADay) > 1) {
155 var elapsedDays;
156
157 elapsedDays = Math.floor((elapsedTime / millisencondsInADay));
158 if (elapsedDays == 1) {
159 result = Clipperz.PM.Strings['elapsedTimeDescriptions']['YESTERDAY'];
160 } else {
161 result = Clipperz.PM.Strings['elapsedTimeDescriptions']['*_DAYS_AGO'].replace(/__elapsed__/, elapsedDays);
162 }
163 } else if ((elapsedTime / millisencondsInAnHour) > 1) {
164 var elapsedHours;
165
166 elapsedHours = Math.floor((elapsedTime / millisencondsInAnHour));
167 if (elapsedHours == 1) {
168 result = Clipperz.PM.Strings['elapsedTimeDescriptions']['ABOUT_AN_HOUR_AGO'];
169 } else {
170 result = Clipperz.PM.Strings['elapsedTimeDescriptions']['*_HOURS_AGO'].replace(/__elapsed__/, elapsedHours);
171 }
172 } else {
173 var elapsed10Minutes;
174
175 elapsed10Minutes = (Math.floor((elapsedTime / millisencondsInAMinute) / 10)) * 10;
176 if (elapsed10Minutes == 0) {
177 result = Clipperz.PM.Strings['elapsedTimeDescriptions']['JUST_A_FEW_MINUTES_AGO'];
178 } else {
179 result = Clipperz.PM.Strings['elapsedTimeDescriptions']['ABOUT_*_MINUTES_AGO'].replace(/__elapsed__/, elapsed10Minutes+"");
180 }
181 }
182 }
183
184 return result;
185 },
186
187 //-------------------------------------------------------------------------
188
189 //-------------------------------------------------------------------------
190 __syntaxFix__: "syntax fix"
191
192});
193
diff --git a/frontend/beta/js/Clipperz/PM/Main.js b/frontend/beta/js/Clipperz/PM/Main.js
new file mode 100644
index 0000000..9a068e1
--- a/dev/null
+++ b/frontend/beta/js/Clipperz/PM/Main.js
@@ -0,0 +1,588 @@
1/*
2
3Copyright 2008-2011 Clipperz Srl
4
5This file is part of Clipperz's Javascript Crypto Library.
6Javascript Crypto Library provides web developers with an extensive
7and efficient set of cryptographic functions. The library aims to
8obtain maximum execution speed while preserving modularity and
9reusability.
10For further information about its features and functionalities please
11refer to http://www.clipperz.com
12
13* Javascript Crypto Library is free software: you can redistribute
14 it and/or modify it under the terms of the GNU Affero General Public
15 License as published by the Free Software Foundation, either version
16 3 of the License, or (at your option) any later version.
17
18* Javascript Crypto Library is distributed in the hope that it will
19 be useful, but WITHOUT ANY WARRANTY; without even the implied
20 warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
21 See the GNU Affero General Public License for more details.
22
23* You should have received a copy of the GNU Affero General Public
24 License along with Javascript Crypto Library. If not, see
25 <http://www.gnu.org/licenses/>.
26
27*/
28
29if (typeof(Clipperz.PM) == 'undefined') { Clipperz.PM = {}; }
30
31Clipperz.PM.VERSION = "0.1";
32Clipperz.PM.NAME = "Clipperz.PM";
33
34//#############################################################################
35
36Clipperz.PM.Main = function() {
37 this._loginPanel = null;
38 this._user = null;
39
40 this._isRunningCompact = false;
41
42 Clipperz.NotificationCenter.register(null, 'userConnected', this, 'userConnectedCallback');
43 Clipperz.NotificationCenter.register(null, 'switchLanguage', this, 'switchLanguageHandler');
44
45 Clipperz.NotificationCenter.register(null, 'EXCEPTION', this, 'reportException');
46
47 return this;
48}
49
50//=============================================================================
51
52MochiKit.Base.update(Clipperz.PM.Main.prototype, {
53 'toString': function() {
54 return "Clipperz.PM.Main";
55 },
56
57 'switchLanguageHandler': function() {
58//MochiKit.Logging.logDebug(">>> main.switchLanguageHandler");
59 YAHOO.ext.Element.get('donateHeaderIconLink').dom.href = Clipperz.PM.Strings['donateHeaderLinkUrl'];
60 YAHOO.ext.Element.get('donateHeaderLink').update(Clipperz.PM.Strings['donateHeaderLinkLabel']).dom.href = Clipperz.PM.Strings['donateHeaderLinkUrl'];
61 YAHOO.ext.Element.get('creditsHeaderLink').update(Clipperz.PM.Strings['creditsHeaderLinkLabel']).dom.href = Clipperz.PM.Strings['creditsHeaderLinkUrl'];
62 YAHOO.ext.Element.get('feedbackHeaderLink').update(Clipperz.PM.Strings['feedbackHeaderLinkLabel']).dom.href = Clipperz.PM.Strings['feedbackHeaderLinkUrl'];
63 YAHOO.ext.Element.get('helpHeaderLink').update(Clipperz.PM.Strings['helpHeaderLinkLabel']).dom.href = Clipperz.PM.Strings['helpHeaderLinkUrl'];
64 YAHOO.ext.Element.get('forumHeaderLink').update(Clipperz.PM.Strings['forumHeaderLinkLabel']).dom.href = Clipperz.PM.Strings['forumHeaderLinkUrl'];
65
66 if (YAHOO.ext.Element.get('logout') != null) {
67 YAHOO.ext.Element.get('logout').update(Clipperz.PM.Strings['logoutMenuLabel']);
68 YAHOO.ext.Element.get('lock').update(Clipperz.PM.Strings['lockMenuLabel']);
69
70 YAHOO.ext.Element.get('recordsTabAnchor').update(Clipperz.PM.Strings['recordMenuLabel']);
71 YAHOO.ext.Element.get('accountTabAnchor').update(Clipperz.PM.Strings['accountMenuLabel']);
72 YAHOO.ext.Element.get('dataTabAnchor').update(Clipperz.PM.Strings['dataMenuLabel']);
73 // YAHOO.ext.Element.get('contactsTabAnchor').update(Clipperz.PM.Strings['contactsMenuLabel']);
74 YAHOO.ext.Element.get('toolsTabAnchor').update(Clipperz.PM.Strings['toolsMenuLabel']);
75 }
76//MochiKit.Logging.logDebug("<<< main.switchLanguageHandler");
77 },
78
79 //-------------------------------------------------------------------------
80
81 'fixToDrawTheMainTabsCorrectlyOnSafari': function() {
82 this.switchLanguageHandler();
83 },
84
85 //-------------------------------------------------------------------------
86
87 'run': function(shouldShowRegistrationForm) {
88 varmainElement;
89
90 Clipperz.NotificationCenter.register(null, 'updatedProgressState', this, 'updateProgressDialogStatus');
91
92 YAHOO.ext.Element.get('recordDetailEditModeHeaderMask').setVisibilityMode(YAHOO.ext.Element.DISPLAY).hide().unmask();
93 YAHOO.ext.Element.get('recordDetailEditModeVerticalMask').setVisibilityMode(YAHOO.ext.Element.DISPLAY).hide().unmask();
94
95//MochiKit.Logging.logDebug(">>> Main.run");
96 mainElement = YAHOO.ext.Element.get('main');
97 if (Clipperz.PM.Proxy.defaultProxy.isReadOnly()) {
98 YAHOO.ext.Element.get('applicationVersionType').dom.className = "readOnly";
99 }
100 mainElement.update("");
101
102 Clipperz.YUI.DomHelper.append(mainElement.dom, {tag:'ul', cls:'clipperzTabPanels', children:[
103 {tag:'li', id:'loginPanel'}
104 ]})
105
106 this.setLoginPanel(new Clipperz.PM.Components.Panels.LoginPanel(YAHOO.ext.Element.get('loginPanel')));
107
108//MochiKit.Logging.logDebug("--- Main.run - selecting active form to show ...");
109 if (shouldShowRegistrationForm == true) {
110 this.loginPanel().showRegistrationForm(false);
111 } else {
112 this.loginPanel().showLoginForm(false);
113 }
114
115 this.switchLanguageHandler();
116//MochiKit.Logging.logDebug("--- Main.run - selecting active form to show. done.");
117//MochiKit.Logging.logDebug("<<< Main.run");
118 },
119
120 //-------------------------------------------------------------------------
121
122 'runCompact': function() {
123 this.setIsRunningCompact(true);
124 YAHOO.ext.Element.get(document.body).addClass("compact");
125 new Clipperz.PM.Components.Compact.LoginForm(YAHOO.ext.Element.get('mainDiv'));
126 },
127
128 'showCompactInterface': function() {
129//MochiKit.Logging.logDebug(">>> main.showCompactInterface");
130 new Clipperz.PM.Components.Compact.CompactInterface(YAHOO.ext.Element.get('compactBody'), {user:this.user()});
131//MochiKit.Logging.logDebug("<<< main.showCompactInterface");
132 },
133
134 //-------------------------------------------------------------------------
135
136 'mainPage': function() {
137 if (this._mainPage == null) {
138 this._mainPage = new Clipperz.PM.Components.MainPage();
139 }
140
141 return this._mainPage;
142 },
143
144 //-------------------------------------------------------------------------
145
146 'loginPanel': function() {
147 return this._loginPanel;
148 },
149
150 'setLoginPanel': function(aValue) {
151 this._loginPanel = aValue;
152 },
153
154 //-------------------------------------------------------------------------
155
156 'showMainPanels': function() {
157 varmainElement;
158 var logoutBlock;
159 var lockBlock;
160 var menusTRElement;
161
162 this.loginPanel().remove();
163 this.setLoginPanel(null);
164
165 logoutBlock = YAHOO.ext.Element.get('logoutLI');
166 Clipperz.YUI.DomHelper.append(logoutBlock.dom, {tag:'a', href:"#", id:'logout', htmlString:Clipperz.PM.Strings['logoutMenuLabel']});
167 MochiKit.Signal.connect('logout', 'onclick', this, 'doLogoutEventHandler');
168
169 lockBlock = YAHOO.ext.Element.get('lockLI');
170 Clipperz.YUI.DomHelper.append(lockBlock.dom, {tag:'a', href:"#", id:'lock', htmlString:Clipperz.PM.Strings['lockMenuLabel']});
171 MochiKit.Signal.connect('lock', 'onclick', this, 'doLockEventHandler');
172
173 menusTRElement = YAHOO.ext.Element.get('menusTR');
174 Clipperz.YUI.DomHelper.append(menusTRElement.dom, {tag:'td', id:'recordsTab', children:[{tag:'div', children:[{tag:'a', id:'recordsTabAnchor', htmlString:Clipperz.PM.Strings['recordMenuLabel']}]}]});
175 Clipperz.YUI.DomHelper.append(menusTRElement.dom, {tag:'td', id:'accountTab', children:[{tag:'div', children:[{tag:'a', id:'accountTabAnchor', htmlString:Clipperz.PM.Strings['accountMenuLabel']}]}]});
176 Clipperz.YUI.DomHelper.append(menusTRElement.dom, {tag:'td', id:'dataTab', children:[{tag:'div', children:[{tag:'a', id:'dataTabAnchor', htmlString:Clipperz.PM.Strings['dataMenuLabel']}]}]});
177 // Clipperz.YUI.DomHelper.append(menusTRElement.dom, {tag:'td', id:'contactsTab', children:[{tag:'div', children:[{tag:'a', id:'contactsTabAnchor', htmlString:Clipperz.PM.Strings['contactsMenuLabel']}]}]});
178 Clipperz.YUI.DomHelper.append(menusTRElement.dom, {tag:'td', id:'toolsTab', children:[{tag:'div', children:[{tag:'a', id:'toolsTabAnchor', htmlString:Clipperz.PM.Strings['toolsMenuLabel']}]}]});
179
180 mainElement = YAHOO.ext.Element.get('main');
181 mainElement.update("");
182 Clipperz.YUI.DomHelper.append(mainElement.dom, {tag:'ul', cls:'clipperzTabPanels', children:[
183 {tag:'li', id:'recordsPanel'},
184 {tag:'li', id:'accountPanel'},
185 {tag:'li', id:'dataPanel'},
186 // {tag:'li', id:'contactsPanel'},
187 {tag:'li', id:'toolsPanel'}
188 ]}, true)
189
190 new Clipperz.PM.Components.TabPanel.TabPanelController({
191 name: 'mainTabPanel',
192 config:{'recordsTab':'recordsPanel',
193 'accountTab':'accountPanel',
194 'dataTab':'dataPanel',
195 // 'contactsTab':'contactsPanel',
196 'toolsTab':'toolsPanel'},
197 selectedTab:'recordsTab'
198 }).setUp();
199
200 new Clipperz.PM.Components.Panels.MainPanel(YAHOO.ext.Element.get('recordsPanel'), {user:this.user()});
201 new Clipperz.PM.Components.Panels.AccountPanel(YAHOO.ext.Element.get('accountPanel'), {user:this.user()});
202 new Clipperz.PM.Components.Panels.DataPanel(YAHOO.ext.Element.get('dataPanel'), {user:this.user()});
203 // new Clipperz.PM.Components.Panels.ContactsPanel(YAHOO.ext.Element.get('contactsPanel'), {user:this.user()});
204 new Clipperz.PM.Components.Panels.ToolsPanel(YAHOO.ext.Element.get('toolsPanel'), {user:this.user()});
205
206 this.fixToDrawTheMainTabsCorrectlyOnSafari(); //fix to
207//MochiKit.Logging.logDebug("<<< Main.showMainPanels");
208 },
209
210 //-------------------------------------------------------------------------
211
212 'userConnectedCallback': function(anEvent) {
213//MochiKit.Logging.logDebug(">>> Main.userConnectedCallback");
214//MochiKit.Logging.logDebug(">>> doConnect - user: " + this.user());
215 this.setUser(anEvent.source());
216
217 if (this.isRunningCompact()) {
218 this.showCompactInterface();
219 } else {
220 this.showMainPanels();
221 }
222//MochiKit.Logging.logDebug("<<< Main.userConnectedCallback");
223 },
224
225 //-----------------------------------------------------------------------------
226
227 'user': function() {
228 return this._user;
229 },
230
231 'setUser': function(aValue) {
232 this._user = aValue;
233 },
234
235 //-----------------------------------------------------------------------------
236
237 'doLogoutEventHandler': function(anEvent) {
238 var deferred;
239
240 anEvent.stop();
241
242 deferred = new MochiKit.Async.Deferred();
243//deferred.addBoth(function(res) {MochiKit.Logging.logDebug("Main.doLogoutEventHandler - 1: " + res); return res;});
244 deferred.addCallback(MochiKit.Base.method(this.user(), 'doLogout'));
245//deferred.addBoth(function(res) {MochiKit.Logging.logDebug("Main.doLogoutEventHandler - 2: " + res); return res;});
246 deferred.addCallback(Clipperz.PM.exit, 'logout.html');
247//deferred.addBoth(function(res) {MochiKit.Logging.logDebug("Main.doLogoutEventHandler - 3: " + res); return res;});
248 deferred.callback();
249 },
250
251 //-----------------------------------------------------------------------------
252
253 'doLockEventHandler': function(anEvent) {
254 vardeferredResult;
255 varlockDialogElement;
256 var lockDialog;
257 var unlockButton;
258
259 anEvent.stop();
260
261 Clipperz.NotificationCenter.notify(this, 'accountLocked', null, true);
262
263 lockDialogElement = Clipperz.YUI.DomHelper.append(document.body, {tag:'div', id:'lockDialog', children:[
264 {tag:'div', cls:'ydlg-hd', htmlString:Clipperz.PM.Strings['lockTitle']},
265 {tag:'div', cls:'ydlg-bd', children:[
266 {tag:'div', cls:'alert-message', id:'lockMessage', children:[
267 {tag:'div', htmlString:Clipperz.PM.Strings['lockDescription']},
268 {tag:'form', id:'lockDialogForm', children:[
269 {tag:'input', type:'password', id:'lockPassphrase'}
270 ]}
271 ]}
272 ]},
273 {tag:'div', cls:'ydlg-ft'}
274 ]}, true);
275 new Clipperz.PM.Components.PasswordEntropyDisplay(YAHOO.ext.Element.get('lockPassphrase'));
276
277 lockDialog = new YAHOO.ext.BasicDialog(
278 lockDialogElement, {
279 closable:false,
280 modal:true,
281 autoTabs:false,
282 resizable:false,
283 fixedcenter:true,
284 constraintoviewport:false,
285 width:350,
286 height:130,
287 shadow:true
288 }
289 );
290
291 unlockButton = lockDialog.addButton(Clipperz.PM.Strings['unlockButtonLabel'], MochiKit.Base.method(this, 'exitLock', lockDialog));
292//MochiKit.Logging.logDebug("--- Main.showAlertDialog - 5");
293 lockDialog.setDefaultButton(unlockButton);
294
295 MochiKit.Signal.connect('lockDialogForm', 'onsubmit', MochiKit.Base.method(this, 'exitLock', lockDialog));
296 lockDialog.on('show', function() {YAHOO.ext.Element.get('lockPassphrase').focus();});
297 lockDialog.show('main');
298 // this.user().lock();
299 },
300
301 'exitLock': function(aLockDialog, anEvent) {
302 // var deferredResult;
303
304//MochiKit.Logging.logDebug(">>> Exiting lock");
305 if (typeof(anEvent.stop) != 'undefined') {
306 anEvent.stop();
307 }
308
309 if (this.user().passphrase() == YAHOO.ext.Element.get('lockPassphrase').dom.value) {
310 aLockDialog.hide(MochiKit.Base.method(aLockDialog, 'destroy', true));
311 Clipperz.NotificationCenter.notify(this, 'accountUnlocked', null, true);
312 } else {
313 YAHOO.ext.Element.get('lockPassphrase').dom.value = "";
314 YAHOO.ext.Element.get('lockPassphrase').focus();
315 }
316
317 // deferredResult = new MochiKit.Async.Deferred();
318 // deferredResult.addCallback(MochiKit.Base.method(this.user(), 'unlockWithPassphrase'));
319 // deferredResult.addCallback(MochiKit.Base.method(aLockDialog, 'hide', MochiKit.Base.method(aLockDialog, 'destroy', true)));
320 // deferredResult.addCallback(MochiKit.Base.method(Clipperz.NotificationCenter, 'notify', this, 'accountUnlocked', null, true));
321 // deferredResult.addErrback(function() {
322 // YAHOO.ext.Element.get('lockPassphrase').dom.value = "";
323 // YAHOO.ext.Element.get('lockPassphrase').focus();
324 // });
325 // deferredResult.callback(YAHOO.ext.Element.get('lockPassphrase').dom.value);
326
327 return false;
328 },
329
330 //-----------------------------------------------------------------------------
331
332 'updateProgressDialogStatus': function(anEvent) {
333//MochiKit.Logging.logDebug(">>> main.updateProgressDialogStatus - " + anEvent.parameters());
334//try {
335 if (Clipperz.Base.objectType(anEvent.parameters()) == 'string') {
336 Clipperz.PM.Components.MessageBox().update(Clipperz.PM.Strings.messagePanelConfigurations[anEvent.parameters()]());
337 } else {
338 Clipperz.PM.Components.MessageBox().update(anEvent.parameters());
339 }
340//} catch (exception) {
341//console.log("updateProgressDialogStatus - anEvent", anEvent);
342 //MochiKit.Logging.logError("Main.updateProgressDialogStatus: " + exception);
343 //throw exception;
344//}
345//MochiKit.Logging.logDebug("<<< main.updateProgressDialogStatus");
346 },
347
348 //-----------------------------------------------------------------------------
349
350 'defaultErrorHandler': function(anErrorString, anException) {
351MochiKit.Logging.logDebug(">>> DEFAULT ERROR HANDLER: " + anErrorString + " (exception: " + Clipperz.Base.serializeJSON(anException) + ")");
352 },
353
354 //-----------------------------------------------------------------------------
355
356 'isRunningCompact': function() {
357 return this._isRunningCompact;
358 },
359
360 'setIsRunningCompact': function(aValue) {
361 this._isRunningCompact = aValue;
362 },
363
364 //-----------------------------------------------------------------------------
365
366 'reportException': function(anError) {
367/*
368 var deferredResult;
369
370 deferredResult = new MochiKit.Async.Deferred();
371
372 Clipperz.PM.Components.MessageBox().show(
373 {
374 title:Clipperz.PM.Strings['fatalErrorMessageTitle'],
375 text:Clipperz.PM.Strings['fatalErrorMessageText'],
376 width:240,
377 showProgressBar:false,
378 showCloseButton:false,
379 fn:MochiKit.Base.method(deferredResult, 'callback'),
380 scope:this,
381 buttons:{
382 'ok':Clipperz.PM.Strings['fatalErrorMessageCloseButtonLabel']
383 }
384 }
385 );
386
387 deferredResult.addCallback(function() {
388 window.document.body.innerHTML = "";
389 window.location.reload(true);
390 });
391*/
392 Clipperz.PM.exit('error.html');
393 },
394
395 //-----------------------------------------------------------------------------
396 __syntaxFix__: "syntax fix"
397
398});
399
400
401
402//#############################################################################
403
404MochiKit.Base.update(Clipperz.PM, {
405
406 __repr__: function() {
407 return "[" + this.NAME + " " + this.VERSION + "]";
408 },
409
410 toString: function() {
411 return this.__repr__();
412 },
413
414 //-----------------------------------------------------------------------------
415
416 'initPage': function() {
417 varmain;
418 var shouldShowRegistrationForm;
419 var useCompactDesign;
420
421//MochiKit.Logging.logWarning("Just testing logging system");
422 Clipperz.PM.Strings.Languages.initSetup();
423 // DWRUtil.useLoadingMessage(Clipperz.PM.Strings['DWRUtilLoadingMessage']);
424
425 if (window.location.search.indexOf("registration") != -1) {
426 shouldShowRegistrationForm = true;
427 } else {
428 shouldShowRegistrationForm = false;
429 }
430
431 if (window.location.search.indexOf("compact") != -1) {
432 useCompactDesign = true;
433 } else {
434 useCompactDesign = false;
435 }
436
437 main = new Clipperz.PM.Main();
438
439 if (useCompactDesign == true) {
440 main.runCompact();
441 } else {
442 if (Clipperz_IEisBroken === true) {
443 if (Clipperz.PM.Proxy.defaultProxy.isReadOnly()) {
444 var logoParentNode;
445
446 YAHOO.ext.Element.get('donateHeaderIcon').remove();
447 logoParentNode = YAHOO.ext.Element.get('logo').dom.parentNode;
448 YAHOO.ext.Element.get('logo').remove();
449 Clipperz.YUI.DomHelper.append(logoParentNode, {tag:'span', children:[
450 {tag:'span', cls:'clipperzLogoSpan', html:'clipper'},
451 {tag:'span', cls:'clipperzLogoZSpan', html:'z'}
452 ]})
453 } else {
454 YAHOO.ext.Element.get('donateHeaderIcon').dom.src = "./images/smiles.gif";
455 YAHOO.ext.Element.get('logo').dom.src = "./images/logo.gif";
456 }
457 } else {
458 YAHOO.ext.Element.get('donateHeaderIcon').dom.src = "data:image/gif;charset=utf-8;base64,R0lGODlhEAAQAPf/ADMzZvrFL/KbGPrER3VXJeaJHvnGXNJ/KAEAAPnKefvJDamopMvLy8GZEfrTpvvgwGhVB0xKSO3BDUk+A/vYqnVgLcmndoRqM/exO3hrS3lmPYRsB39lDum9Dv3aCuebVPnIdP////3cCvewE07BafrQk/rHG1tYR5qZl7eUWZl7CfnGjdeuDPnCPpl4LDEoA5R2OP3XC/jBgfi2EvrXrvrRlWpYHgGtKdiqKPvfvu6nFzTNWfexFv7gCEc4GPrFDvaqFJmDB/euE/vYrJV5SfzUC7uTIuCxDf8AAPrHX519EbONGLubCvvYqzsxA/42AwaIGPzTC9u8CfTALlRUUomJiACWHaaMCsmeJFBFBZ5wUtaRVGlOVrySGLBvPNaBKsSGU9OOUbF7VPOycaRxUaFzWfGtaLZ6L+CaHcZ/Kt6YHVxJXfvXqaGhn0A8Z/i8c7JwM7d4MP6SBrJtM21MUDs4ZT84YmFhYaBnPqtyNM2QW6t2Va18XfvWsPvZsmVOXUQ7X86CJ1ZDWzo2Y6FoOfzSDBMPB/rTqW1OT0I5YEQ9ZnVTS1pEV9iCI7x+Ljw4ZvnJlqNnOfeyUfnMi/CkSfnKhAOmJ/WqU/ewJmVUO6qRB3ljHOGzFvauSfnFWveuI/esFK2JE5iVifrEEA+uJ/K+RayHMYVvTsyiE3NxbnBdQl5KG+cAAPnBIQYFA8GXN82hJbWXa6WDEQgGBFNBGMKeC4iFeZiiGdTZ1aqgd1dTPF9fX4R1BHReOOi9cdmsUn9xBKKFIWVPG5J0FLmzmcLCwtK5B6eQcnx5doZrFPnAH6eFP/fDL1RLBYVsQW5raMXGEFA5E+rLoUQEAG0kA8ONCteZId6wF86tCJ0AAGFQBurKn6mJHks/A2tZQOKfIHFua+29Wum1OOzv7LysCN3i3s/Rz/DDdeOyKCckHxQTEDsuEUIvEI1EBfP29KuIQbqUR9O7CbnCER8ZCSIeGDQJADQXAaCVaKeCGUNAPFRGMpmJS1xIF/rELPXARv///yH/C05FVFNDQVBFMi4wAwEAAAAh+QQFZAD/ACwAAAAAEAAQAAAI+AABCASwhkyYDx+27PkzcGCdMmZWOOjT5xCkMXwUDXwERgaNHA9CPsjhZ4UeNwK1vHEwpAmFlxSaDGEjQwwAQZQq1aihKlaJEhYylagx6RIXPJ1AJEjgSsNSIrOWJpDk5QAGT0mSIKiQFQaCrAYwfCnwqUWpAatMDRjwitYAfy0wFSgwQhksZgHy6mWGpRWPAgdGjEKlxIThw7IajBrRKBIQBQpUaGMiQUItbSogA5nDSMCPIlGudHPiZEKQKEV+CKADgJCQQh5iy44dZQQcgXbSzCjSo7fvGDMCJRo4KA8oBTFEiIihQEgcQA0FIjqjRocONI4WNQwIACH5BAVkAP8ALAEABAANAAkAAAhaAP8J1GehhMASBgUqREAExLkUEFMoFOgDXpJwFzLCUChuwL8BHj8O8OeRRxd0ASbiwBKgn8AjHK5N5AQB1bUjAmt128BCIIssL3gqlALBiUAnGyRMFChiqcKAACH5BAVkAP8ALAEABAANAAoAAAhzAP8JrKEqlkALmQQq/JfAlYYECYjMSrDwXxIEFZIkgYEgicIWAleZEviK1gCBI/7BqhggwD8cS/4tEVWBg5JQoZRwsGEr2D8JuUKYa1OlCopiIYgdEchEVIinUBdcWahJFwoGDNqcCFLxnxRezbIAM6YwIAAh+QQFZAD/ACwCAAMADAAMAAAIeQD//ZN2TOC/bQUN/st06pRAhg4NOuvlS+DEigZ/LbsgUCNHgwSEuRAYcuS/JUam4FCIg5kRfF3anNqUbNiwZJs0oOCmYN8/d+VwmcM17t89Cf+kaCCxo+kOEhmwGYwHxYpVK1DIKYR2o2tXS/IU3rpBqiwpS7cEBgQAIfkEBWQA/wAsAgADAAwADAAACH4A//0b0kTgPwoFDf6roSqWQAuZSihM4EqDQCKzEihMgqCCQBgIkhgsNWCVKYGvaA3w908Zln8BFMbE0moUKiUmcuqU1WDUPwUqtDHp0KEatXYKFPwrUkRTN3v1pmV7UsSgBw8x5CBhxeqJwiI9wsp58kSOQlAKYlyNoWCEwIAAIfkEBWQA/wAsAQAEAA4ACwAACIwACURIhQxcBG8a8j1DlooKAXpUdt3ZFUGdoQgS71BJFw2Bx38IYLxDANIju2/C5hla5+LfP1M+DM3jZ+1fF1gBXOr8FwDHEpdLRFXgoCRUKCUcbNgK5lJCrhDm2lSpgqJYCGJHdDIRFaKr1wVXdv7TpAsFAwZtTgQR61IKr2ZZgBmLwVanCBEuhegMCAA7Cg==";
459 YAHOO.ext.Element.get('logo').dom.src = "data:image/gif;charset=utf-8;base64,R0lGODlhgwAoAPf/AP////+SAIKCmV1df3l5jYmhef//9vr6+YSQrJSguNfk60xMZjw8bf+PAI2Zsq6ulTU1ZZqasrzE05Gdtf//90pHW6d4KuPj6cLCz6ampzw3Ymt9nXp6Z21tif+MAHV1mPaOBJGRrPLy8dPT21Zhifb2+H19j/z8+MmOG3V/n729zcnJ1jU1aLmKIsnb5M3O2Xe5y3JyjHZqRD1xlElJd7KyuPSSBGFhhPn59kFBcKiovIaGov+KAP7+/sDA0HZ2mKqtwV5fh6y1yMTM2X19nXuCoTg5al1MUdTV4O3u8jU8bTMzZv+OAIt6Nfz8/G5ukldTVF5egv///nFxlJ2eeFFRfPX18cN/HpOTanV1lLOzp3l5m1dXesXF1O7u7MOPHj4+YaWltdXV1WJqj4ODdU1NeZWVZNaSFff39WFmjEtQfP+GAPSGBenq77q6ym1thP//+3l5kX5+kIOiubx8IpyCMf3//8nJ0eHh20JMedHRwVJSeba2yEJyPsaDHVhYffT+/llag4uNqcTE0T4+bvDw7dra4v7///n//6GhuGZojTw8a/r6+/z89OLy9ZWVr8mMG9ra1t/f5zo6ZUNEcjs7bPHx9dzc34iVsE5Od319mZ2dbUZJd2hoh4xsOf398mBhiP39/ZmZkmtrkKOmvK7B0T9Bb77H1evr2c2PGX2Ipn1YQT9RbOrq56bR3Y2NgLrV35mZZ+yOCqmptZiYmN/fx7OzxTY+YFJXgVFchdnZvsLE08jI0ztcTeCLEPuVAv2QAIqSrZietlJUbGpqYYWFWWdlSKKlepajukJvQMbI1kZhiURukj09ZlNUf5mwxOHhxFxchVtehoaOqoqKZv39+HF5mnR6m5OZsj8/bDQ0ZzQzZuzs6vr67MDAyUhIdGpqj+np0IqZstfY4o+btI6dtv2NAPf353ibtGJcTtWJEDJIdrPD0u/9/ufo7ZWiuZWjulVVdeLi6Nvb5N3d4oiIcIyMecLC0XWAoGVlfpCQmGCctXR3mXh4W2lukv///yH5BAEAAP8ALAAAAACDACgAAAj/AP8JHEiwoMGDCBMqXMiwocOHECNKnEixosWLGDNq3Mixo8ePIEOKHEmypMmTKFOqXMmyZcktLwZ1wRBF4I+YM2+43IlRWI8eAKrFEIgNANBqcXgqpfgOgFMDBAROcAqAgpylWCEmoApVIDyqVrOKZbj1adR/RbqoHdRprFuEZQF0fes2yIcfH55QOhh37sMcU378eMLAIaEngp8QYhjt7gdFRh5W+fCBVUcWIVaUoCplnopoBfueLbKiNK8OAkmXngVhzjjOSIQtKnit9Ioa/9Ah4TwuUbaDLAQp20z1RYTIBP3Z9sbClBB3Tgs0gYSiuvXrKCCla6jmBdXvTp1Q/yEoWiAysCakOpXS5hQi8E51LSCIab0lCe/h15pPMI8r+OuNkAlBRVAlAi4ufEcFJGt44OCDEHqwhgwM0aBAD4cASNUrA5X3z1ROUZDePw5oCN8IhQmEwHeHZAigITkMtM4FJgIgRSR7CZQCVSW0YYeLACzYIIRMBGCkkR5QuBAQ35XABxHiwPJdEvEI5CGIVY1Y4nehuLHDIyOAJ8BAK4Knwg4heMfZDgMJ8Z0kiXyQCHRO9RDGQDtqeMgxTXzhp58tnNHAkQFMuBAngFDVyJgCKXHKd8VYydVZWIoo0JZOhaLJQEbA8F0kZH7XA5sCsQADUE7hIdAyB6CqxzdLxP+qhgJUWZFinpxh8MEoHwxzUAvmHOlBKhUoxEk5VMHxQEEzcPaIpGapF6KWVPWwLEFKtFGrTv+UaaMWBWlDo1M4tLXPeiIsEOu6G9hRZz06fgfHnQktYUGwSJ4BxkK5lEJVKFVi+8QUU3xQBbRyUYrepf9yYBApLkpBhorVOlyQMJzZo80QVBWywxZEhLwFOe5+Gy9VYsyWkCfAAGNkA74Uu1AaElDVzb5kTSptlgw7xc0eBinCmRkUO2XFHwYF8V0sRjhSo6hunOzUMQrJMOiRNhzRECg+UIUKzgtduTCJVF2QI0FCU0V0t1S1QYNBoHy3CQu0Pk2VClJLIUpCxoD/cHUAHqziEM1UnQO2QmJP2zMAPxuUxndreysCFwZJI3fTVJ3Aiwo+dO655/pIfQBqB/Viw98NePIQCexkzt9AlAChwuykJs4z2eQOVZC3AFBTNAAnJFWQKt9hoQ0SLuJRSUO4jn7QEWwQ6kEdEKnxDJARFDRGok7t/Y/tluLu1CwF0U0VI7rzjhtBLCQYXlJzKFpTQSCHPH/zpBNUgTrSUw+REYFAFQBEQIyBMIBjVOkHwuZSKWpRBQdZIMgjnEAVaEzidwA4wKYGIghGUCUcF2wWVXiRon9oAwE/AgAczoK/gtzCDx44UgMsAIGCbKMh/qLKJ0LwASIYgjOXSBH4/xz4Lx1QRgXgoUWo5AUEyvCBSxkYCAKdIo8dUGYXJQOAHvBEFecRpA88IFQA/ECHK5jxjHSQWULyIImnweENHdLZh8aGqaeJoYS8q9ElYiQQErTjaZ/IBxed4sWBgFGMf5PhL6DAEGeMI4vgScIWCNKUaH0PLFcRHxruoCF6IG2JAMDBHQT4HXnMbyDMkIeJLDGxgeBjPaHIn0AOKcZaBsAGjGQIJQThjlaFpwQ6+ORAglGCYlqBdNMoZgmsoDtMteIbH7iABwHgBGC+jSDeKkQZniCJaYaiBEAow0Fo8Igk+JKaViBFIApiDWWKoC0ESQYbQEDPetqznrLIZUOMQIEDcExhC9EoIfsYQFAGsKBUBTXo4gpBOSM4IzBBWIxBJDeAfxihCoEBBR8TUokyjKJggWgGcBJ6UIJAQAMoTalKV1pDlmDKC5RrCEXpwpOXxpQhM6WpS2zqkJzqlCVYOppD6kOuU/5UJfwYxOxs8Q2HTOEes+ODOI9K1apa9aoLCQgAOwo=";
460 }
461
462 main.run(shouldShowRegistrationForm);
463 }
464
465 Clipperz.PM.defaultErrorHandler = main.defaultErrorHandler;
466
467 //DEBUG
468 if ((typeof(_clipperz_pm_test_user) != 'undefined') && (typeof(_clipperz_pm_test_passphrase) != 'undefined')) {
469 //------- automatic login with test/test --------------
470 // Clipperz.PM.Proxy.defaultProxy = new Clipperz.PM.Proxy.Offline();
471//MochiKit.Logging.logWarning("activating AUTOLOGIN (" + _clipperz_pm_test_user + "/" + _clipperz_pm_test_passphrase + ")");
472 // MochiKit.Async.callLater(0.9, MochiKit.Base.bind(main.doLogin, main), _clipperz_pm_test_user, _clipperz_pm_test_passphrase, YAHOO.ext.Element.get('Clipperz_PM_Components_Panels_login_submit_9'));
473 MochiKit.Async.callLater(0.5, MochiKit.Base.bind(main.loginPanel().doLoginWithUsernameAndPassphrase, main.loginPanel()), _clipperz_pm_test_user, _clipperz_pm_test_passphrase);
474 //------- automatic registration --------------
475//MochiKit.Logging.logWarning("Testing registration (user,passwd)");
476//MochiKit.Logging.logDebug("mainPanel: " + main.mainPage().mainPanel().content());
477 // main.mainPage().getActivePanel().showRegistrationFormAnimator().play();
478 // MochiKit.Async.callLater(1.9, MochiKit.Base.bind(main.doRegistration, main), 'user', 'passwd');
479//-------------------------------------
480 // main.showMainPanels('ok');
481 };
482
483 if (/fastEntropyAccumulationForTestingPurpose/.test(window.location.search)) {
484 Clipperz.Crypto.PRNG.defaultRandomGenerator().fastEntropyAccumulationForTestingPurpose();
485 }
486
487 // Clipperz.PM.Proxy.defaultProxy.knock();
488 },
489
490 //-------------------------------------------------------------------------
491
492 'showDonationSplashScreen': function(aUser, aFocusElementId) {
493 var deferredResult;
494 var donateElement;
495 vardonateDialog;
496 var closeButton;
497 var closeFunction;
498 var donateButton;
499 var donateFunction;
500
501 deferredResult = new MochiKit.Async.Deferred();
502
503//MochiKit.Logging.logDebug(">>> Main.showRegistrationSplashScreen");
504 donateElement = Clipperz.YUI.DomHelper.append(document.body, {tag:'div', id:'donateSplash', children:[
505 {tag:'div', cls:'ydlg-hd', htmlString:Clipperz.PM.Strings['donateSplashPanelTitle']},
506 {tag:'div', cls:'ydlg-bd', children:[
507 {tag:'div', cls:'alert-message', id:'donateMessage', children:[
508 {tag:'div', cls:'donateSplashPanelIcon', children:[
509 {tag:'img', src:Clipperz.PM.Strings['donateSplashPanelIconUrl']}
510 ]},
511 {tag:'div', cls:'donateSplashPanelDescription', htmlString:Clipperz.PM.Strings['donateSplashPanelDescription']}
512 ]}
513 ]},
514 {tag:'div', cls:'ydlg-ft'}
515 ]}, true);
516
517 donateDialog = new YAHOO.ext.BasicDialog(
518 donateElement, {
519 closable:false,
520 modal:true,
521 autoTabs:false,
522 resizable:false,
523 fixedcenter:true,
524 constraintoviewport:false,
525 width:450,
526 height:220,
527 shadow:true,
528 minWidth:300,
529 minHeight:300
530 }
531 );
532
533 closeFunction = MochiKit.Base.partial(deferredResult.callback, false);
534 donateFunction = MochiKit.Base.partial(deferredResult.callback, true);
535 donateButton = donateDialog.addButton(Clipperz.PM.Strings['donateDonateButtonLabel'], donateFunction, deferredResult);
536
537 donateDialog.addKeyListener(27, closeFunction, deferredResult);
538 closeButton = donateDialog.addButton(Clipperz.PM.Strings['donateCloseButtonLabel'], closeFunction, deferredResult);
539
540 donateDialog.setDefaultButton(donateButton);
541 donateDialog.show(aFocusElementId /*'recordListAddRecordButton'*/);
542
543 deferredResult.addCallback(MochiKit.Base.bind(function(shouldOpenDonatePage) {
544 var result;
545
546 if (shouldOpenDonatePage) {
547 window.open(Clipperz.PM.Strings['donateHeaderLinkUrl'], "donate");
548 aUser.preferences().setShouldShowDonationPanel(false);
549 aUser.preferences().saveChanges();
550 }
551 }, this));
552 deferredResult.addBoth(MochiKit.Base.method(donateDialog, 'hide'));
553 deferredResult.addBoth(MochiKit.Base.method(donateElement, 'remove'));
554//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("Main.showDonationSplashScreen - 2: " + res); return res;});
555//MochiKit.Logging.logDebug("<<< Main.showRegistrationSplashScreen");
556
557 return deferredResult;
558 },
559
560 //-----------------------------------------------------------------------------
561
562 'exit': function(aPageName) {
563 // alert("ERROR: " + aPageName);
564
565 // YAHOO.ext.Element.get('menus').update("");
566 // YAHOO.ext.Element.get('logoutLI').update("");
567 // YAHOO.ext.Element.get('lockLI').update("");
568 // YAHOO.ext.Element.get('main').update("");
569 // Clipperz.YUI.DomHelper.append('main', {tag:'div', id:'exitBlock', children:Clipperz.PM.Strings['exitConfig']});
570
571 MochiKit.Async.wait(0).addCallback(function() {
572 // window.location.href = "http://www.google.com/search?hl=" + Clipperz.PM.Strings.preferredLanguage + "&q=phishing&btnI=Google+Search";
573 window.location.href = "./" + aPageName;
574 });
575 },
576
577 //-----------------------------------------------------------------------------
578 __syntaxFix__: "syntax fix"
579
580});
581
582//#############################################################################
583
584//Clipperz.PM.SerializeAsyncCalls = function(aDelay, aFunction) {
585 //aFunction.apply(extend(null, arguments, 1));
586//};
587
588MochiKit.DOM.addLoadEvent(Clipperz.PM.initPage);
diff --git a/frontend/beta/js/Clipperz/PM/Proxy.js b/frontend/beta/js/Clipperz/PM/Proxy.js
new file mode 100644
index 0000000..d05a5e0
--- a/dev/null
+++ b/frontend/beta/js/Clipperz/PM/Proxy.js
@@ -0,0 +1,173 @@
1/*
2
3Copyright 2008-2011 Clipperz Srl
4
5This file is part of Clipperz's Javascript Crypto Library.
6Javascript Crypto Library provides web developers with an extensive
7and efficient set of cryptographic functions. The library aims to
8obtain maximum execution speed while preserving modularity and
9reusability.
10For further information about its features and functionalities please
11refer to http://www.clipperz.com
12
13* Javascript Crypto Library is free software: you can redistribute
14 it and/or modify it under the terms of the GNU Affero General Public
15 License as published by the Free Software Foundation, either version
16 3 of the License, or (at your option) any later version.
17
18* Javascript Crypto Library is distributed in the hope that it will
19 be useful, but WITHOUT ANY WARRANTY; without even the implied
20 warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
21 See the GNU Affero General Public License for more details.
22
23* You should have received a copy of the GNU Affero General Public
24 License along with Javascript Crypto Library. If not, see
25 <http://www.gnu.org/licenses/>.
26
27*/
28
29if (typeof(Clipperz) == 'undefined') { Clipperz = {}; }
30if (typeof(Clipperz.PM) == 'undefined') { Clipperz.PM = {}; }
31
32//=============================================================================
33
34Clipperz.PM.Proxy = function(args) {
35 args = args || {};
36
37 this._shouldPayTolls = args.shouldPayTolls || false;
38
39 this._tolls = {
40 'CONNECT':[],
41 'REGISTER':[],
42 'MESSAGE':[]
43 };
44
45 if (args.isDefault === true) {
46 Clipperz.PM.Proxy.defaultProxy = this;
47 }
48
49 return this;
50}
51
52Clipperz.PM.Proxy.prototype = MochiKit.Base.update(null, {
53
54 'toString': function() {
55 return "Clipperz.PM.Proxy";
56 },
57
58 //=========================================================================
59
60 'shouldPayTolls': function() {
61 return this._shouldPayTolls;
62 },
63
64 //-------------------------------------------------------------------------
65
66 'tolls': function() {
67 return this._tolls;
68 },
69
70 //-------------------------------------------------------------------------
71
72 'payToll': function(aRequestType, someParameters) {
73 vardeferredResult;
74
75//console.log(">>> Proxy.payToll", aRequestType, someParameters);
76 if (this.shouldPayTolls()) {
77 deferredResult = new MochiKit.Async.Deferred();
78
79 if (this.tolls()[aRequestType].length == 0) {
80 deferredResult.addCallback(MochiKit.Base.method(this, 'sendMessage', 'knock', {requestType:aRequestType}));
81 deferredResult.addCallback(MochiKit.Base.method(this, 'setTollCallback'));
82 }
83 deferredResult.addCallback(MochiKit.Base.method(this.tolls()[aRequestType], 'pop'));
84 deferredResult.addCallback(MochiKit.Base.methodcaller('deferredPay'));
85 deferredResult.addCallback(function(aToll) {
86 var result;
87
88 result = {
89 parameters: someParameters,
90 toll: aToll
91 }
92
93 return result;
94 });
95
96 deferredResult.callback();
97 } else {
98 deferredResult = MochiKit.Async.succeed({parameters:someParameters});
99 }
100//console.log("<<< Proxy.payToll");
101
102 return deferredResult;
103 },
104
105 //-------------------------------------------------------------------------
106
107 'addToll': function(aToll) {
108//console.log(">>> Proxy.addToll", aToll);
109 this.tolls()[aToll.requestType()].push(aToll);
110//console.log("<<< Proxy.addToll");
111 },
112
113 //=========================================================================
114
115 'setTollCallback': function(someParameters) {
116//console.log(">>> Proxy.setTollCallback", someParameters);
117 if (typeof(someParameters['toll']) != 'undefined') {
118//console.log("added a new toll", someParameters['toll']);
119 this.addToll(new Clipperz.PM.Toll(someParameters['toll']));
120 }
121//console.log("<<< Proxy.setTallCallback", someParameters['result']);
122 //return someParameters['result'];
123 return someParameters;
124 },
125
126 //=========================================================================
127
128 'registration': function (someParameters) {
129 return this.processMessage('registration', someParameters, 'REGISTER');
130 },
131
132 'handshake': function (someParameters) {
133 return this.processMessage('handshake', someParameters, 'CONNECT');
134 },
135
136 'message': function (someParameters) {
137 return this.processMessage('message', someParameters, 'MESSAGE');
138 },
139
140 'logout': function (someParameters) {
141 return this.processMessage('logout', someParameters, 'MESSAGE');
142 },
143
144 //=========================================================================
145
146 'processMessage': function (aFunctionName, someParameters, aRequestType) {
147 vardeferredResult;
148
149 deferredResult = new MochiKit.Async.Deferred();
150 deferredResult.addCallback(MochiKit.Base.method(this, 'payToll', aRequestType));
151 deferredResult.addCallback(MochiKit.Base.method(this, 'sendMessage', aFunctionName));
152 deferredResult.addCallback(MochiKit.Base.method(this, 'setTollCallback'));
153 deferredResult.callback(someParameters);
154
155 return deferredResult;
156 },
157
158 //=========================================================================
159
160 'sendMessage': function () {
161 throw Clipperz.Base.exception.AbstractMethod;
162 },
163
164 //=========================================================================
165
166 'isReadOnly': function () {
167 return false;
168 },
169
170 //=========================================================================
171 __syntaxFix__: "syntax fix"
172
173});
diff --git a/frontend/beta/js/Clipperz/PM/Proxy/Proxy.JSON.js b/frontend/beta/js/Clipperz/PM/Proxy/Proxy.JSON.js
new file mode 100755
index 0000000..889e1f1
--- a/dev/null
+++ b/frontend/beta/js/Clipperz/PM/Proxy/Proxy.JSON.js
@@ -0,0 +1,100 @@
1/*
2
3Copyright 2008-2011 Clipperz Srl
4
5This file is part of Clipperz's Javascript Crypto Library.
6Javascript Crypto Library provides web developers with an extensive
7and efficient set of cryptographic functions. The library aims to
8obtain maximum execution speed while preserving modularity and
9reusability.
10For further information about its features and functionalities please
11refer to http://www.clipperz.com
12
13* Javascript Crypto Library is free software: you can redistribute
14 it and/or modify it under the terms of the GNU Affero General Public
15 License as published by the Free Software Foundation, either version
16 3 of the License, or (at your option) any later version.
17
18* Javascript Crypto Library is distributed in the hope that it will
19 be useful, but WITHOUT ANY WARRANTY; without even the implied
20 warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
21 See the GNU Affero General Public License for more details.
22
23* You should have received a copy of the GNU Affero General Public
24 License along with Javascript Crypto Library. If not, see
25 <http://www.gnu.org/licenses/>.
26
27*/
28
29if (typeof(Clipperz) == 'undefined') { Clipperz = {}; }
30if (typeof(Clipperz.PM) == 'undefined') { Clipperz.PM = {}; }
31
32//=============================================================================
33
34Clipperz.PM.Proxy.JSON = function(args) {
35 Clipperz.PM.Proxy.JSON.superclass.constructor.call(this, args);
36
37 this._url = args.url || Clipperz.Base.exception.raise('MandatoryParameter');
38
39 return this;
40}
41
42YAHOO.extendX(Clipperz.PM.Proxy.JSON, Clipperz.PM.Proxy, {
43
44 'toString': function() {
45 return "Clipperz.PM.Proxy.JSON";
46 },
47
48 //=========================================================================
49
50 'url': function () {
51 return this._url;
52 },
53
54 //=========================================================================
55
56 'sendMessage': function(aFunctionName, someParameters) {
57 vardeferredResult;
58 var parameters;
59
60 parameters = {
61 method: aFunctionName,
62 // version: someParameters['version'],
63 // message: someParameters['message'],
64 parameters: Clipperz.Base.serializeJSON(someParameters)
65 };
66
67 deferredResult = new MochiKit.Async.Deferred();
68 deferredResult.addCallback(function (aValue) {
69 MochiKit.Signal.signal(Clipperz.Signal.NotificationCenter, 'remoteRequestSent');
70 return aValue;
71 });
72 deferredResult.addCallback(MochiKit.Async.doXHR, this.url(), {
73 method:'POST',
74 sendContent:MochiKit.Base.queryString(parameters),
75 headers:{"Content-Type":"application/x-www-form-urlencoded"}
76 });
77 deferredResult.addCallback(function (aValue) {
78 MochiKit.Signal.signal(Clipperz.Signal.NotificationCenter, 'remoteRequestReceived');
79 return aValue;
80 });
81 // deferredResult.addCallback(MochiKit.Async.evalJSONRequest);
82 deferredResult.addCallback(MochiKit.Base.itemgetter('responseText'));
83 deferredResult.addCallback(Clipperz.Base.evalJSON);
84 deferredResult.addCallback(function (someValues) {
85 if (someValues['result'] == 'EXCEPTION') {
86 throw someValues['message'];
87 }
88
89 return someValues;
90 })
91 // return MochiKit.Base.evalJSON(req.responseText);
92 deferredResult.callback();
93
94 return deferredResult;
95 },
96
97 //=========================================================================
98 __syntaxFix__: "syntax fix"
99
100});
diff --git a/frontend/beta/js/Clipperz/PM/Proxy/Proxy.Offline.DataStore.js b/frontend/beta/js/Clipperz/PM/Proxy/Proxy.Offline.DataStore.js
new file mode 100644
index 0000000..4d3ba08
--- a/dev/null
+++ b/frontend/beta/js/Clipperz/PM/Proxy/Proxy.Offline.DataStore.js
@@ -0,0 +1,804 @@
1/*
2
3Copyright 2008-2011 Clipperz Srl
4
5This file is part of Clipperz's Javascript Crypto Library.
6Javascript Crypto Library provides web developers with an extensive
7and efficient set of cryptographic functions. The library aims to
8obtain maximum execution speed while preserving modularity and
9reusability.
10For further information about its features and functionalities please
11refer to http://www.clipperz.com
12
13* Javascript Crypto Library is free software: you can redistribute
14 it and/or modify it under the terms of the GNU Affero General Public
15 License as published by the Free Software Foundation, either version
16 3 of the License, or (at your option) any later version.
17
18* Javascript Crypto Library is distributed in the hope that it will
19 be useful, but WITHOUT ANY WARRANTY; without even the implied
20 warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
21 See the GNU Affero General Public License for more details.
22
23* You should have received a copy of the GNU Affero General Public
24 License along with Javascript Crypto Library. If not, see
25 <http://www.gnu.org/licenses/>.
26
27*/
28
29try { if (typeof(Clipperz.PM.Proxy.Offline) == 'undefined') { throw ""; }} catch (e) {
30 throw "Clipperz.PM.Proxy.Offline.DataStore depends on Clipperz.PM.Proxy.Offline!";
31}
32
33//=============================================================================
34
35Clipperz.PM.Proxy.Offline.DataStore = function(args) {
36 args = args || {};
37
38 this._data = args.data || (typeof(_clipperz_dump_data_) != 'undefined' ? _clipperz_dump_data_ : null);
39 this._isReadOnly = (typeof(args.readOnly) == 'undefined' ? true : args.readOnly);
40 this._shouldPayTolls = args.shouldPayTolls || false;
41
42 this._tolls = {};
43 this._connections = {};
44
45 this._b = null;
46 this._B = null;
47 this._A = null;
48 this._userData = null;
49
50 return this;
51}
52
53//Clipperz.Base.extend(Clipperz.PM.Proxy.Offline.DataStore, Object, {
54Clipperz.PM.Proxy.Offline.DataStore.prototype = MochiKit.Base.update(null, {
55
56 //-------------------------------------------------------------------------
57
58 'isReadOnly': function () {
59 return this._isReadOnly;
60 },
61
62 //-------------------------------------------------------------------------
63
64 'shouldPayTolls': function() {
65 return this._shouldPayTolls;
66 },
67
68 //-------------------------------------------------------------------------
69
70 'data': function () {
71 return this._data;
72 },
73
74 //-------------------------------------------------------------------------
75
76 'tolls': function () {
77 return this._tolls;
78 },
79
80 //-------------------------------------------------------------------------
81
82 'connections': function () {
83 return this._connections;
84 },
85
86 //=========================================================================
87
88 'resetData': function() {
89 this._data = {
90 'users': {
91 'catchAllUser': {
92 __masterkey_test_value__: 'masterkey',
93 s: '112233445566778899aabbccddeeff00112233445566778899aabbccddeeff00',
94 v: '112233445566778899aabbccddeeff00112233445566778899aabbccddeeff00'
95 }
96 }
97 };
98 },
99
100 //-------------------------------------------------------------------------
101
102 'setupWithEncryptedData': function(someData) {
103 this._data = Clipperz.Base.deepClone(someData);
104 },
105
106 //-------------------------------------------------------------------------
107
108 'setupWithData': function(someData) {
109 var deferredResult;
110 var resultData;
111 var i, c;
112
113//Clipperz.log(">>> Proxy.Test.setupWithData");
114 resultData = this._data;
115
116 deferredResult = new MochiKit.Async.Deferred();
117 c = someData['users'].length;
118
119 for (i=0; i<c; i++) {
120 varnewConnection;
121 varrecordConfiguration;
122
123 deferredResult.addCallback(MochiKit.Base.method(this, 'userSerializedEncryptedData', someData['users'][i]));
124 deferredResult.addCallback(MochiKit.Base.bind(function(aUserSerializationContext) {
125//console.log("SERIALIZED USER", aUserSerializationContext);
126 resultData['users'][aUserSerializationContext['credentials']['C']] = {
127 's': aUserSerializationContext['credentials']['s'],
128 'v': aUserSerializationContext['credentials']['v'],
129 'version': aUserSerializationContext['data']['connectionVersion'],
130 'userDetails': aUserSerializationContext['encryptedData']['user']['header'],
131 'userDetailsVersion':aUserSerializationContext['encryptedData']['user']['version'],
132 'statistics': aUserSerializationContext['encryptedData']['user']['statistics'],
133 'lock': aUserSerializationContext['encryptedData']['user']['lock'],
134 'records': this.rearrangeRecordsData(aUserSerializationContext['encryptedData']['records'])
135 }
136 }, this));
137 }
138
139 deferredResult.addCallback(MochiKit.Base.bind(function() {
140//console.log("this._data", resultData);
141 this._data = resultData;
142 }, this));
143
144 deferredResult.callback();
145//Clipperz.log("<<< Proxy.Test.setupWithData");
146
147 return deferredResult;
148 },
149
150 //=========================================================================
151
152 'b': function() {
153 return this._b;
154 },
155
156 'set_b': function(aValue) {
157 this._b = aValue;
158 },
159
160 //-------------------------------------------------------------------------
161
162 'B': function() {
163 return this._B;
164 },
165
166 'set_B': function(aValue) {
167 this._B = aValue;
168 },
169
170 //-------------------------------------------------------------------------
171
172 'A': function() {
173 return this._A;
174 },
175
176 'set_A': function(aValue) {
177 this._A = aValue;
178 },
179
180 //-------------------------------------------------------------------------
181
182 'userData': function() {
183 return this._userData;
184 },
185
186 'setUserData': function(aValue) {
187 this._userData = aValue;
188 },
189
190 //=========================================================================
191
192 'getTollForRequestType': function (aRequestType) {
193 varresult;
194 vartargetValue;
195 var cost;
196
197 targetValue = Clipperz.Crypto.PRNG.defaultRandomGenerator().getRandomBytes(32).toHexString().substring(2);
198 switch (aRequestType) {
199 case 'REGISTER':
200 cost = 5;
201 break;
202 case 'CONNECT':
203 cost = 5;
204 break;
205 case 'MESSAGE':
206 cost = 2;
207 break;
208 }
209
210 result = {
211 requestType: aRequestType,
212 targetValue: targetValue,
213 cost: cost
214 }
215
216 if (this.shouldPayTolls()) {
217 this.tolls()[targetValue] = result;
218 }
219
220 return result;
221 },
222
223 //-------------------------------------------------------------------------
224
225 'checkToll': function (aFunctionName, someParameters) {
226 if (this.shouldPayTolls()) {
227 var localToll;
228 vartollParameters;
229
230 tollParameters = someParameters['toll'];
231 localToll = this.tolls()[tollParameters['targetValue']];
232
233 if (localToll != null) {
234 if (! Clipperz.PM.Toll.validate(tollParameters['targetValue'], tollParameters['toll'], localToll['cost'])) {
235 throw "Toll value too low.";
236 };
237 } else {
238 throw "Missing toll";
239 }
240 }
241 },
242
243 //=========================================================================
244
245 'processMessage': function(aFunctionName, someParameters) {
246 var result;
247
248 switch(aFunctionName) {
249 case 'knock':
250 result = this._knock(someParameters);
251 break;
252 case 'registration':
253 this.checkToll(aFunctionName, someParameters);
254 result = this._registration(someParameters.parameters);
255 break;
256 case 'handshake':
257 this.checkToll(aFunctionName, someParameters);
258 result = this._handshake(someParameters.parameters);
259 break;
260 case 'message':
261 this.checkToll(aFunctionName, someParameters);
262 result = this._message(someParameters.parameters);
263 break;
264 case 'logout':
265 result = this._logout(someParameters.parameters);
266 break;
267 }
268
269 return result;
270 },
271
272 //=========================================================================
273
274 '_knock': function(someParameters) {
275 var result;
276
277 result = {
278 toll: this.getTollForRequestType(someParameters['requestType'])
279 // toll: {
280 // requestType: someParameters['requestType'],
281 // targetValue: "3a1ba0be23580f902885c6c8a6b035e228ed1ca74d77de5f9bb0e0c899f07cfe",
282 // cost:
283 // }
284 }
285
286 return result;
287 },
288
289 //-------------------------------------------------------------------------
290
291 '_registration': function(someParameters) {
292//console.log("_registration", someParameters);
293 if (this.isReadOnly() == false) {
294 if (typeof(this.data()['users'][someParameters['credentials']['C']]) == 'undefined') {
295 this.data()['users'][someParameters['credentials']['C']] = {
296 's': someParameters['credentials']['s'],
297 'v': someParameters['credentials']['v'],
298 'version':someParameters['credentials']['version'],
299 // 'lock': someParameters['user']['lock'],
300 'lock': Clipperz.Crypto.Base.generateRandomSeed(),
301 // 'maxNumberOfRecords':'100',
302 'userDetails': someParameters['user']['header'],
303 'statistics': someParameters['user']['statistics'],
304 'userDetailsVersion':someParameters['user']['version'],
305 'records':{}
306 }
307 } else {
308 throw "user already exists";
309 }
310 } else {
311 throw Clipperz.PM.Proxy.Offline.DataStore.exception.ReadOnly;
312 }
313
314 result = {
315 result: {
316 'lock': this.data()['users'][someParameters['credentials']['C']]['lock'],
317 'result':'done'
318 },
319 toll: this.getTollForRequestType('CONNECT')
320 }
321
322 return MochiKit.Async.succeed(result);
323 },
324
325 //-------------------------------------------------------------------------
326
327 '_handshake': function(someParameters) {
328 var result;
329 varnextTollRequestType;
330
331//Clipperz.log(">>> Proxy.Offline.DataStore._handshake");
332 result = {};
333 if (someParameters.message == "connect") {
334 var userData;
335 var randomBytes;
336 var b, B, v;
337
338//console.log(">>> Proxy.Offline.DataStore._handshake.connect", someParameters);
339 userData = this.data()['users'][someParameters.parameters.C];
340
341 if ((typeof(userData) != 'undefined') && (userData['version'] == someParameters.version)) {
342 this.setUserData(userData);
343 } else {
344 this.setUserData(this.data()['users']['catchAllUser']);
345 }
346
347 randomBytes = Clipperz.Crypto.Base.generateRandomSeed();
348 this.set_b(new Clipperz.Crypto.BigInt(randomBytes, 16));
349 v = new Clipperz.Crypto.BigInt(this.userData()['v'], 16);
350 this.set_B(v.add(Clipperz.Crypto.SRP.g().powerModule(this.b(), Clipperz.Crypto.SRP.n())));
351
352 this.set_A(someParameters.parameters.A);
353
354 result['s'] = this.userData()['s'];
355 result['B'] = this.B().asString(16);
356
357 nextTollRequestType = 'CONNECT';
358 } else if (someParameters.message == "credentialCheck") {
359 var v, u, S, A, K, M1;
360
361//console.log(">>> Proxy.Offline.DataStore._handshake.credentialCheck", someParameters);
362 v = new Clipperz.Crypto.BigInt(this.userData()['v'], 16);
363 u = new Clipperz.Crypto.BigInt(Clipperz.PM.Crypto.encryptingFunctions.versions[someParameters.version].hash(new Clipperz.ByteArray(this.B().asString(10))).toHexString(), 16);
364 A = new Clipperz.Crypto.BigInt(this.A(), 16);
365 S = (A.multiply(v.powerModule(u, Clipperz.Crypto.SRP.n()))).powerModule(this.b(), Clipperz.Crypto.SRP.n());
366
367 K = Clipperz.PM.Crypto.encryptingFunctions.versions[someParameters.version].hash(new Clipperz.ByteArray(S.asString(10))).toHexString().slice(2);
368
369 M1 = Clipperz.PM.Crypto.encryptingFunctions.versions[someParameters.version].hash(new Clipperz.ByteArray(A.asString(10) + this.B().asString(10) + K)).toHexString().slice(2);
370 if (someParameters.parameters.M1 == M1) {
371 var M2;
372
373 M2 = Clipperz.PM.Crypto.encryptingFunctions.versions[someParameters.version].hash(new Clipperz.ByteArray(A.asString(10) + someParameters.parameters.M1 + K)).toHexString().slice(2);
374 result['M2'] = M2;
375 } else {
376 throw new Error("Client checksum verification failed! Expected <" + M1 + ">, received <" + someParameters.parameters.M1 + ">.", "Error");
377 }
378
379 nextTollRequestType = 'MESSAGE';
380 } else if (someParameters.message == "oneTimePassword") {
381 var otpData;
382
383//console.log("HANDSHAKE WITH OTP", someParameters.parameters.oneTimePasswordKey);
384//console.log("someParameters", someParameters);
385//console.log("data.OTP", Clipperz.Base.serializeJSON(this.data()['onetimePasswords']));
386 otpData = this.data()['onetimePasswords'][someParameters.parameters.oneTimePasswordKey];
387
388 try {
389 if (typeof(otpData) != 'undefined') {
390 if (otpData['status'] == 'ACTIVE') {
391 if (otpData['key_checksum'] == someParameters.parameters.oneTimePasswordKeyChecksum) {
392 result = {
393 'data': otpData['data'],
394 'version':otpData['version']
395 }
396
397 otpData['status'] = 'REQUESTED';
398 } else {
399 otpData['status'] = 'DISABLED';
400 throw "The requested One Time Password has been disabled, due to a wrong keyChecksum";
401 }
402 } else {
403 throw "The requested One Time Password was not active";
404 }
405 } else {
406 throw "The requested One Time Password has not been found"
407 }
408 } catch (exception) {
409 result = {
410 'data': Clipperz.PM.Crypto.randomKey(),
411 'version':Clipperz.PM.Connection.communicationProtocol.currentVersion
412 }
413 }
414 nextTollRequestType = 'CONNECT';
415 } else {
416 MochiKit.Logging.logError("Clipperz.PM.Proxy.Test.handshake - unhandled message: " + someParameters.message);
417 }
418//console.log("<<< Proxy.Offline._handshake", result);
419
420 result = {
421 result: result,
422 toll: this.getTollForRequestType(nextTollRequestType)
423 }
424
425 return MochiKit.Async.succeed(result);
426 },
427
428 //-------------------------------------------------------------------------
429
430 '_message': function(someParameters) {
431 var result;
432
433 result = {};
434
435 //=====================================================================
436 //
437 // R E A D - O N L Y M e t h o d s
438 //
439 //=====================================================================
440 if (someParameters.message == 'getUserDetails') {
441 var recordsStats;
442 var recordReference;
443
444 //try {
445 recordsStats = {};
446 for (recordReference in this.userData()['records']) {
447 recordsStats[recordReference] = {
448 'updateDate': this.userData()['records'][recordReference]['updateDate']
449 }
450 }
451
452 result['header'] = this.userDetails();
453 result['statistics'] = this.statistics();
454 result['maxNumberOfRecords'] = this.userData()['maxNumberOfRecords'];
455 result['version'] = this.userData()['userDetailsVersion'];
456 result['recordsStats'] = recordsStats;
457
458 if (this.isReadOnly() == false) {
459 varlock;
460
461 if (typeof(this.userData()['lock']) == 'undefined') {
462 this.userData()['lock'] = "<<LOCK>>";
463 }
464
465 result['lock'] = this.userData()['lock'];
466 }
467//} catch (exception) {
468 //console.log("*#*#*#*#*#*#*", exception);
469 //throw exception;
470//}
471 //=====================================================================
472 } else if (someParameters.message == 'getRecordDetail') {
473 recordData = this.userData()['records'][someParameters['parameters']['reference']];
474
475 result['reference'] = someParameters['parameters']['reference'];
476 result['data'] = recordData['data'];
477 result['version'] = recordData['version'];
478 result['creationData'] = recordData['creationDate'];
479 result['updateDate'] = recordData['updateDate'];
480 result['accessDate'] = recordData['accessDate'];
481
482 currentVersionData = recordData['versions'][recordData['currentVersion']];
483
484 result['currentVersion'] = {};
485 result['currentVersion']['reference'] = recordData['currentVersion'];
486 result['currentVersion']['version'] = currentVersionData['version'];
487 result['currentVersion']['header'] = currentVersionData['header'];
488 result['currentVersion']['data'] = currentVersionData['data'];
489 result['currentVersion']['creationData'] = currentVersionData['creationDate'];
490 result['currentVersion']['updateDate'] = currentVersionData['updateDate'];
491 result['currentVersion']['accessDate'] = currentVersionData['accessDate'];
492 if (typeof(currentVersionData['previousVersion']) != 'undefined') {
493 result['currentVersion']['previousVersionKey'] = currentVersionData['previousVersionKey'];
494 result['currentVersion']['previousVersion'] = currentVersionData['previousVersion'];
495 }
496
497 //=====================================================================
498 //
499 // R E A D - W R I T E M e t h o d s
500 //
501 //=====================================================================
502 } else if (someParameters.message == 'upgradeUserCredentials') {
503 if (this.isReadOnly() == false) {
504 var parameters;
505 parameters = someParameters.parameters;
506
507 if (parameters['C'] == null) {
508 result = Clipperz.PM.DataModel.User.exception.CredentialUpgradeFailed;
509 } else if (parameters['s'] == null) {
510 result = Clipperz.PM.DataModel.User.exception.CredentialUpgradeFailed;
511 } else if (parameters['v'] == null) {
512 result = Clipperz.PM.DataModel.User.exception.CredentialUpgradeFailed;
513 } else if (parameters['version'] != Clipperz.PM.Connection.communicationProtocol.currentVersion) {
514 result = Clipperz.PM.DataModel.User.exception.CredentialUpgradeFailed;
515 } else {
516 result = {result:"done", parameters:parameters};
517 }
518 } else {
519 throw Clipperz.PM.Proxy.Offline.DataStore.exception.ReadOnly;
520 }
521 //=====================================================================
522 /* } else if (someParameters.message == 'updateData') {
523 if (this.isReadOnly() == false) {
524 var i, c;
525
526//console.log("###===============================================================");
527//console.log("###>>>", Clipperz.Base.serializeJSON(someParameters));
528//console.log("###--- userData", Clipperz.Base.serializeJSON(this.userData()));
529 if (this.userData()['lock']!= someParameters['parameters']['user']['lock']) {
530 throw "the lock attribute is not processed correctly"
531 }
532
533 this.userData()['userDetails'] = someParameters['parameters']['user']['header'];
534 this.userData()['statistics'] = someParameters['parameters']['user']['statistics'];
535 this.userData()['userDetailsVersions']= someParameters['parameters']['user']['version'];
536
537 c = someParameters['parameters']['records'].length;
538 for (i=0; i<c; i++) {
539 var currentRecord;
540 var currentRecordData;
541
542 currentRecordData = someParameters['parameters']['records'][i];
543 currentRecord = this.userData()['records'][currentRecordData['record']['reference']];
544
545 if (currentRecord == null) {
546 }
547
548 currentRecord['data'] = currentRecordData['record']['data'];
549 currentRecord['version'] = currentRecordData['record']['version'];
550 currentRecord['currentVersion'] = currentRecordData['currentRecordVersion']['reference'];
551
552 currentRecord['versions'][currentRecordData['currentRecordVersion']['reference']] = {
553 'data': currentRecordData['currentRecordVersion']['data'],
554 'version': currentRecordData['currentRecordVersion']['version'],
555 'previousVersion': currentRecordData['currentRecordVersion']['previousVersion'],
556 'previousVersionKey':currentRecordData['currentRecordVersion']['previousVersionKey']
557 }
558 }
559
560 this.userData()['lock'] = Clipperz.PM.Crypto.randomKey();
561 result['lock'] = this.userData()['lock'];
562 result['result'] = 'done';
563//console.log("###<<< userData", Clipperz.Base.serializeJSON(this.userData()));
564 } else {
565 throw Clipperz.PM.Proxy.Offline.DataStore.exception.ReadOnly;
566 }
567 */ //=====================================================================
568 } else if (someParameters.message == 'saveChanges') {
569 if (this.isReadOnly() == false) {
570 var i, c;
571
572//console.log("###===============================================================");
573//console.log("###>>>", someParameters);
574//console.log("###>>>", Clipperz.Base.serializeJSON(someParameters));
575//console.log("###--- userData", Clipperz.Base.serializeJSON(this.userData()));
576//console.log("###===============================================================");
577//console.log("--- userData.lock ", this.userData()['lock']);
578//console.log("--- parameters.lock", someParameters['parameters']['user']['lock']);
579 if (this.userData()['lock']!= someParameters['parameters']['user']['lock']) {
580 throw "the lock attribute is not processed correctly"
581 }
582
583 this.userData()['userDetails'] = someParameters['parameters']['user']['header'];
584 this.userData()['statistics'] = someParameters['parameters']['user']['statistics'];
585 this.userData()['userDetailsVersions']= someParameters['parameters']['user']['version'];
586
587 c = someParameters['parameters']['records']['updated'].length;
588 for (i=0; i<c; i++) {
589 var currentRecord;
590 var currentRecordData;
591
592 currentRecordData = someParameters['parameters']['records']['updated'][i];
593 currentRecord = this.userData()['records'][currentRecordData['record']['reference']];
594
595 if (
596 (typeof(this.userData()['records'][currentRecordData['record']['reference']]) == 'undefined')
597 &&
598 (typeof(currentRecordData['currentRecordVersion']) == 'undefined')
599 ) {
600//console.log("######## SHIT HAPPENS");
601 throw "Record added without a recordVersion";
602 }
603
604 if (currentRecord == null) {
605 currentRecord = {};
606 currentRecord['versions'] = {};
607 currentRecord['creationDate']= Clipperz.PM.Date.formatDateWithUTCFormat(new Date());
608 currentRecord['accessDate'] = Clipperz.PM.Date.formatDateWithUTCFormat(new Date());
609
610 this.userData()['records'][currentRecordData['record']['reference']] = currentRecord;
611 }
612
613 currentRecord['data'] = currentRecordData['record']['data'];
614 currentRecord['version']= currentRecordData['record']['version'];
615 currentRecord['updateDate']= Clipperz.PM.Date.formatDateWithUTCFormat(new Date());
616
617 if (typeof(currentRecordData['currentRecordVersion']) != 'undefined') {
618 currentRecord['currentVersion'] = currentRecordData['currentRecordVersion']['reference'];
619 currentRecord['versions'][currentRecordData['currentRecordVersion']['reference']] = {
620 'data': currentRecordData['currentRecordVersion']['data'],
621 'version': currentRecordData['currentRecordVersion']['version'],
622 'previousVersion': currentRecordData['currentRecordVersion']['previousVersion'],
623 'previousVersionKey':currentRecordData['currentRecordVersion']['previousVersionKey'],
624 'creationDate':Clipperz.PM.Date.formatDateWithUTCFormat(new Date()),
625 'updateDate':Clipperz.PM.Date.formatDateWithUTCFormat(new Date()),
626 'accessDate':Clipperz.PM.Date.formatDateWithUTCFormat(new Date())
627 }
628 }
629 }
630
631 c = someParameters['parameters']['records']['deleted'].length;
632 for (i=0; i<c; i++) {
633 var currentRecordReference;
634
635 currentRecordReference = someParameters['parameters']['records']['deleted'][i];
636//console.log("DELETING records", currentRecordReference);
637 delete this.userData()['records'][currentRecordReference];
638 }
639
640 this.userData()['lock'] = Clipperz.PM.Crypto.randomKey();
641 result['lock'] = this.userData()['lock'];
642 result['result'] = 'done';
643//console.log("###<<< userData", Clipperz.Base.serializeJSON(this.userData()));
644 } else {
645 throw Clipperz.PM.Proxy.Offline.DataStore.exception.ReadOnly;
646 }
647
648 //=====================================================================
649 //
650 // U N H A N D L E D M e t h o d
651 //
652 //=====================================================================
653 } else {
654 MochiKit.Logging.logError("Clipperz.PM.Proxy.Test.message - unhandled message: " + someParameters.message);
655 }
656
657 result = {
658 result: result,
659 toll: this.getTollForRequestType('MESSAGE')
660 }
661
662 return MochiKit.Async.succeed(result);
663 },
664
665 //-------------------------------------------------------------------------
666
667 '_logout': function(someParameters) {
668 return MochiKit.Async.succeed({result: 'done'});
669 },
670
671 //=========================================================================
672 //#########################################################################
673
674 'isTestData': function() {
675 return (typeof(this.userData()['__masterkey_test_value__']) != 'undefined');
676 },
677
678 'userDetails': function() {
679 var result;
680
681 if (this.isTestData()) {
682 var serializedHeader;
683 var version;
684
685//MochiKit.Logging.logDebug("### test data");
686 version = this.userData()['userDetailsVersion'];
687 serializedHeader = Clipperz.Base.serializeJSON(this.userData()['userDetails']);
688 result = Clipperz.PM.Crypto.encryptingFunctions.versions[version].encrypt(this.userData()['__masterkey_test_value__'], serializedHeader);
689 } else {
690//MochiKit.Logging.logDebug("### NOT test data");
691 result = this.userData()['userDetails'];
692 }
693
694 return result;
695 },
696
697 'statistics': function() {
698 var result;
699
700 if (this.userData()['statistics'] != null) {
701 if (this.isTestData()) {
702 var serializedStatistics;
703 var version;
704
705 version = this.userData()['userDetailsVersion'];
706 serializedStatistics = Clipperz.Base.serializeJSON(this.userData()['statistics']);
707 result = Clipperz.PM.Crypto.encryptingFunctions.versions[version].encrypt(this.userData()['__masterkey_test_value__'], serializedStatistics);
708 } else {
709 result = this.userData()['statistics'];
710 }
711 } else {
712 result = null;
713 }
714
715 return result;
716 },
717
718/*
719 'userSerializedEncryptedData': function(someData) {
720 var deferredResult;
721 var deferredContext;
722
723 deferredContext = { 'data': someData };
724
725 deferredResult = new Clipperz.Async.Deferred('Proxy.Test.serializeUserEncryptedData', {trace:false});
726 deferredResult.addCallback(MochiKit.Base.bind(function(aDeferredContext) {
727 aDeferredContext['user'] = this.createUserUsingConfigurationData(aDeferredContext['data']);
728 return aDeferredContext;
729 }, this));
730 deferredResult.addCallback(function(aDeferredContext) {
731 // return aDeferredContext['user'].encryptedDataUsingVersion(aDeferredContext['data']['version']);
732 return aDeferredContext['user'].serializedDataUsingVersion(MochiKit.Base.values(aDeferredContext['user'].records()), aDeferredContext['data']['version']);
733 });
734 deferredResult.addCallback(function(aUserEncryptedData) {
735 deferredContext['encryptedData'] = aUserEncryptedData;
736 return deferredContext;
737 });
738 deferredResult.addCallback(function(aDeferredContext) {
739 var connection;
740
741 connection = new Clipperz.PM.Connection.communicationProtocol.versions[aDeferredContext['data']['connectionVersion']]()
742 aDeferredContext['credentials'] = connection.serverSideUserCredentials(aDeferredContext['user'].username(),aDeferredContext['user'].passphrase());
743
744 return aDeferredContext;
745 });
746
747 // deferredResult.addCallback(function(aDeferredContext) {
748//console.log("#-#-#-#-#", aDeferredContext);
749 // return aDeferredContext['user'].serializedDataUsingVersion(MochiKit.Base.values(aDeferredContext['user'].records()), aDeferredContext['data']['version']);
750 // }, deferredContext);
751 // deferredResult.addCallback(function(aUserSerializedData) {
752//console.log("USER SERIALIZED DATA", aUserSerializedData);
753 // });
754//
755 // deferredResult.addCallback(MochiKit.Async.succeed, deferredContext);
756 deferredResult.callback(deferredContext);
757
758 return deferredResult;
759 },
760
761 'createUserUsingConfigurationData': function(someData) {
762 var result;
763 var user;
764 var recordLabel;
765
766 user = new Clipperz.PM.DataModel.User();
767 user.initForTests();
768 user.setUsername(someData['username']);
769 user.setPassphrase(someData['passphrase']);
770
771 for (recordLabel in someData['records']) {
772 var recordData;
773 var record;
774 var i, c;
775
776 recordData = someData['records'][recordLabel];
777 record = new Clipperz.PM.DataModel.Record({user:user, label:recordLabel});
778 record.setNotes(recordData['notes']);
779
780 c = recordData['fields'].length;
781 for (i=0; i<c; i++) {
782 var recordField;
783
784 recordField = new Clipperz.PM.DataModel.RecordField();
785 recordField.setLabel(recordData['fields'][i]['name']);
786 recordField.setValue(recordData['fields'][i]['value']);
787 recordField.setType(recordData['fields'][i]['type']);
788 record.addField(recordField);
789 }
790 user.addRecord(record, true);
791 }
792
793 result = user;
794
795 return result;
796 },
797*/
798 //=========================================================================
799 __syntaxFix__: "syntax fix"
800});
801
802Clipperz.PM.Proxy.Offline.DataStore['exception'] = {
803 'ReadOnly': new MochiKit.Base.NamedError("Clipperz.PM.Proxy.Offline.DataStore.exception.ReadOnly")
804}; \ No newline at end of file
diff --git a/frontend/beta/js/Clipperz/PM/Proxy/Proxy.Offline.js b/frontend/beta/js/Clipperz/PM/Proxy/Proxy.Offline.js
new file mode 100644
index 0000000..072f9bf
--- a/dev/null
+++ b/frontend/beta/js/Clipperz/PM/Proxy/Proxy.Offline.js
@@ -0,0 +1,73 @@
1/*
2
3Copyright 2008-2011 Clipperz Srl
4
5This file is part of Clipperz's Javascript Crypto Library.
6Javascript Crypto Library provides web developers with an extensive
7and efficient set of cryptographic functions. The library aims to
8obtain maximum execution speed while preserving modularity and
9reusability.
10For further information about its features and functionalities please
11refer to http://www.clipperz.com
12
13* Javascript Crypto Library is free software: you can redistribute
14 it and/or modify it under the terms of the GNU Affero General Public
15 License as published by the Free Software Foundation, either version
16 3 of the License, or (at your option) any later version.
17
18* Javascript Crypto Library is distributed in the hope that it will
19 be useful, but WITHOUT ANY WARRANTY; without even the implied
20 warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
21 See the GNU Affero General Public License for more details.
22
23* You should have received a copy of the GNU Affero General Public
24 License along with Javascript Crypto Library. If not, see
25 <http://www.gnu.org/licenses/>.
26
27*/
28
29if (typeof(Clipperz) == 'undefined') { Clipperz = {}; }
30if (typeof(Clipperz.PM) == 'undefined') { Clipperz.PM = {}; }
31
32//=============================================================================
33
34Clipperz.PM.Proxy.Offline = function(args) {
35 args = args || {};
36
37 Clipperz.PM.Proxy.Offline.superclass.constructor.call(this, args);
38
39 this._dataStore = args.dataStore || new Clipperz.PM.Proxy.Offline.DataStore(args);
40
41 return this;
42}
43
44YAHOO.extendX(Clipperz.PM.Proxy.Offline, Clipperz.PM.Proxy, {
45
46 'toString': function () {
47 return "Clipperz.PM.Proxy.Offline";
48 },
49
50 //-------------------------------------------------------------------------
51
52 'dataStore': function () {
53 return this._dataStore;
54 },
55
56 //-------------------------------------------------------------------------
57
58 'sendMessage': function(aFunctionName, someParameters) {
59 return this.dataStore().processMessage(aFunctionName, someParameters);
60 },
61
62 //-------------------------------------------------------------------------
63
64 'isReadOnly': function () {
65 return true;
66 },
67
68 //-------------------------------------------------------------------------
69
70 __syntaxFix__: "syntax fix"
71
72});
73
diff --git a/frontend/beta/js/Clipperz/PM/Proxy/Proxy.PHP.js b/frontend/beta/js/Clipperz/PM/Proxy/Proxy.PHP.js
new file mode 100755
index 0000000..e7c2bc1
--- a/dev/null
+++ b/frontend/beta/js/Clipperz/PM/Proxy/Proxy.PHP.js
@@ -0,0 +1,259 @@
1/*
2
3Copyright 2008-2011 Clipperz Srl
4
5This file is part of Clipperz's Javascript Crypto Library.
6Javascript Crypto Library provides web developers with an extensive
7and efficient set of cryptographic functions. The library aims to
8obtain maximum execution speed while preserving modularity and
9reusability.
10For further information about its features and functionalities please
11refer to http://www.clipperz.com
12
13* Javascript Crypto Library is free software: you can redistribute
14 it and/or modify it under the terms of the GNU Affero General Public
15 License as published by the Free Software Foundation, either version
16 3 of the License, or (at your option) any later version.
17
18* Javascript Crypto Library is distributed in the hope that it will
19 be useful, but WITHOUT ANY WARRANTY; without even the implied
20 warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
21 See the GNU Affero General Public License for more details.
22
23* You should have received a copy of the GNU Affero General Public
24 License along with Javascript Crypto Library. If not, see
25 <http://www.gnu.org/licenses/>.
26
27*/
28
29if (typeof(Clipperz) == 'undefined') { Clipperz = {}; }
30if (typeof(Clipperz.PM) == 'undefined') { Clipperz.PM = {}; }
31
32//=============================================================================
33
34Clipperz.PM.Proxy.PHP = function(args) {
35 Clipperz.PM.Proxy.PHP.superclass.constructor.call(this, args);
36/*
37 this._tolls = {
38 'CONNECT':[],
39 'REGISTER':[],
40 'MESSAGE':[]
41 };
42 */
43 return this;
44}
45
46YAHOO.extendX(Clipperz.PM.Proxy.PHP, Clipperz.PM.Proxy, {
47
48 'toString': function() {
49 return "Clipperz.PM.Proxy.PHP - " + this.args();
50 },
51
52 //=========================================================================
53/*
54 'tolls': function() {
55 return this._tolls;
56 },
57*/
58 //-------------------------------------------------------------------------
59/*
60 'payToll': function(aRequestType, someParameters) {
61 vardeferredResult;
62
63//MochiKit.Logging.logDebug(">>> Proxy.DWR.payToll: " + aRequestType);
64 if (this.tolls()[aRequestType].length > 0) {
65 deferredResult = MochiKit.Async.succeed(this.tolls()[aRequestType].pop());
66 } else {
67//MochiKit.Logging.logDebug("### " + aRequestType + " toll NOT immediately available; request queued.");
68 deferredResult = new MochiKit.Async.Deferred();
69 deferredResult.addCallback(function(someParameters) {
70 return new Clipperz.PM.Toll(someParameters['toll']);
71 })
72 com_clipperz_pm_Proxy.knock(Clipperz.Base.serializeJSON({requestType:aRequestType}), {
73 callback:MochiKit.Base.method(deferredResult, 'callback'),
74 errorHandler:MochiKit.Base.method(deferredResult, 'errback')
75 });
76 }
77
78 deferredResult.addCallback(function(aToll) {
79 return aToll.deferredPay();
80 });
81 deferredResult.addCallback(function(someParameters, aToll) {
82 var result;
83
84 result = {
85 parameters: someParameters,
86 toll: aToll
87 }
88
89 return result;
90 }, someParameters);
91
92 return deferredResult;
93 },
94*/
95 //-------------------------------------------------------------------------
96/*
97 'addToll': function(aToll) {
98 this.tolls()[aToll.requestType()].push(aToll);
99 },
100*/
101 //=========================================================================
102/*
103 'setTollCallback': function(someParameters) {
104//MochiKit.Logging.logDebug(">>> Proxy.DWR.setTollCallback");
105//MochiKit.Logging.logDebug("--- Proxy.DWR.setTollCallback - " + Clipperz.Base.serializeJSON(someParameters));
106 if (typeof(someParameters['toll']) != 'undefined') {
107 this.addToll(new Clipperz.PM.Toll(someParameters['toll']));
108 }
109 return someParameters['result'];
110 },
111*/
112 //=========================================================================
113
114 'registration': function(someParameters) {
115 return this.sendMessage('registration', someParameters, 'REGISTER');
116 },
117
118 //-------------------------------------------------------------------------
119
120 'handshake': function(someParameters) {
121/*
122 _s = "e8a2162f29aeaabb729f5625e9740edbf0cd80ac77c6b19ab951ed6c88443b8c";
123 _v = new Clipperz.Crypto.BigInt("955e2db0f7844aca372f5799e5f7e51b5866718493096908bd66abcf1d068108", 16);
124 _b = new Clipperz.Crypto.BigInt("5761e6c84d22ea3c5649de01702d60f674ccfe79238540eb34c61cd020230c53", 16);
125
126 _B = _v.add(Clipperz.Crypto.SRP.g().powerModule(_b, Clipperz.Crypto.SRP.n()));
127 _u = new Clipperz.Crypto.BigInt(Clipperz.PM.Crypto.encryptingFunctions.versions[someParameters.version].hash(new Clipperz.ByteArray(_B.asString(10))).toHexString(), 16);
128 _A = new Clipperz.Crypto.BigInt("3b3567ec33d73673552e960872eb154d091a2488915941038aef759236a27e64", 16);
129 _S = (_A.multiply(_v.powerModule(_u, Clipperz.Crypto.SRP.n()))).powerModule(_b, Clipperz.Crypto.SRP.n());
130 _K = Clipperz.PM.Crypto.encryptingFunctions.versions[someParameters.version].hash(new Clipperz.ByteArray(_S.asString(10))).toHexString().slice(2);
131 _M1 = Clipperz.PM.Crypto.encryptingFunctions.versions[someParameters.version].hash(new Clipperz.ByteArray(_A.asString(10) + _B.asString(10) + _K)).toHexString().slice(2);
132 _M2 = Clipperz.PM.Crypto.encryptingFunctions.versions[someParameters.version].hash(new Clipperz.ByteArray(_A.asString(10) + _M1 + _K)).toHexString().slice(2);
133
134 // MochiKit.Logging.logDebug("b = " + _b.asString(16));
135 // MochiKit.Logging.logDebug("v = " + _v.asString(16));
136 MochiKit.Logging.logDebug("B = " + _B.asString(16));
137 MochiKit.Logging.logDebug("u = " + _u.asString(16));
138 MochiKit.Logging.logDebug("S = " + _S.asString(16));
139 MochiKit.Logging.logDebug("K = " + _K);
140 MochiKit.Logging.logDebug("M1 = " + _M1);
141 MochiKit.Logging.logDebug("M2 = " + _M2);
142 // MochiKit.Logging.logDebug("someParameters.version: " + someParameters.version);
143 */
144 return this.sendMessage('handshake', someParameters, 'CONNECT');
145 },
146
147 //-------------------------------------------------------------------------
148
149 'message': function(someParameters) {
150 return this.sendMessage('message', someParameters, 'MESSAGE');
151 },
152
153 //-------------------------------------------------------------------------
154
155 'logout': function(someParameters) {
156//MochiKit.Logging.logDebug("=== Proxy.DWR.logout");
157 return this.sendMessage('logout', someParameters, 'MESSAGE');
158 },
159
160 //=========================================================================
161
162 'sendMessage': function(aFunctionName, someParameters, aRequestType) {
163/*
164 vardeferredResult;
165 var proxy;
166
167//MochiKit.Logging.logDebug(">>> Proxy.DWR.sendMessage - " + aFunctionName + " - " + aRequestType);
168 proxy = this;
169
170 deferredResult = new MochiKit.Async.Deferred();
171//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("x.1 Proxy.DWR.sendMessage - 1: " + res); return res;});
172 deferredResult.addCallback(MochiKit.Base.method(proxy, 'payToll'), aRequestType);
173//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("x.2 Proxy.DWR.sendMessage - 2: " + Clipperz.Base.serializeJSON(res)); return res;});
174 deferredResult.addCallback(MochiKit.Base.method(proxy, 'sendRemoteMessage'), aFunctionName);
175//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("x.3 Proxy.DWR.sendMessage - 3: " + res); return res;});
176//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("x.3 Proxy.DWR.sendMessage - 3: " + Clipperz.Base.serializeJSON(res)); return res;});
177 deferredResult.callback(someParameters);
178
179//MochiKit.Logging.logDebug("<<< Proxy.DWR.sendMessage");
180 return deferredResult;
181*/
182
183 // return this.sendRemoteMessage(aFunctionName, someParameters);
184
185
186 vardeferredResult;
187 var proxy;
188
189 proxy = this;
190
191 deferredResult = new MochiKit.Async.Deferred();
192 deferredResult.addCallback(MochiKit.Base.method(proxy, 'sendRemoteMessage'), aFunctionName);
193//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("x.3 Proxy.PHP.sendMessage - 3: " + res); return res;});
194//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("x.3 Proxy.PHP.sendMessage - 3.1: " + Clipperz.Base.serializeJSON(res)); return res;});
195
196 deferredResult.callback(someParameters);
197
198 return deferredResult;
199 },
200
201 //=========================================================================
202
203 'sendRemoteMessage': function(aFunctionName, someParameters) {
204/*
205 vardeferredResult;
206
207//MochiKit.Logging.logDebug(">>> Proxy.DWR.sendRemoteMessage('" + aFunctionName + "', " + Clipperz.Base.serializeJSON(someParameters) + ") - " + this);
208 deferredResult = new MochiKit.Async.Deferred();
209//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("Proxy.DWR.sendRemoteMessage - 1: " + res); return res;});
210 // deferredResult.addCallback(MochiKit.Base.method(this, 'setTollCallback'));
211//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("Proxy.DWR.sendRemoteMessage - 2: " + res); return res;});
212
213 com_clipperz_pm_Proxy[aFunctionName](Clipperz.Base.serializeJSON(someParameters), {
214 callback:MochiKit.Base.method(deferredResult, 'callback'),
215 errorHandler:MochiKit.Base.method(deferredResult, 'errback')
216 });
217//MochiKit.Logging.logDebug("<<< Proxy.PHP.sendRemoteMessage - result: " + deferredResult);
218
219 return deferredResult;
220*/
221
222 vardeferredResult;
223 var parameters;
224
225//MochiKit.Logging.logDebug(">>> Proxy.PHP.sendRemoteMessage('" + aFunctionName + "', " + Clipperz.Base.serializeJSON(someParameters) + ") - " + this);
226 parameters = {};
227 parameters['method'] = aFunctionName;
228 // parameters['version'] = someParameters['version'];
229 // parameters['message'] = someParameters['message'];
230 parameters['parameters'] = Clipperz.Base.serializeJSON(someParameters);
231//MochiKit.Logging.logDebug("--- Proxy.PHP.sendRemoteMessage('" + Clipperz.Base.serializeJSON(parameters) + ") - " + this);
232 deferredResult = new MochiKit.Async.Deferred();
233 deferredResult.addCallback(MochiKit.Async.doXHR, "./php/index.php", {
234 method:'POST',
235 sendContent:MochiKit.Base.queryString(parameters),
236 headers:{"Content-Type":"application/x-www-form-urlencoded"}
237 });
238//deferredResult.addCallback(function(res) {MochiKit.Logging.logDebug("Proxy.PHP.response - 2: " + res.responseText); return res;});
239//deferredResult.addErrback(function(res) {MochiKit.Logging.logDebug("Proxy.PHP.response - ERROR: " + res); return res;});
240 deferredResult.addCallback(MochiKit.Async.evalJSONRequest);
241 deferredResult.callback();
242
243 return deferredResult;
244 },
245
246 //=========================================================================
247
248 'isReadOnly': function() {
249 return false;
250 },
251
252 //=========================================================================
253 __syntaxFix__: "syntax fix"
254
255});
256
257//=============================================================================
258
259//Clipperz.PM.Proxy.defaultProxy = new Clipperz.PM.Proxy.PHP("Proxy.PHP - async test");
diff --git a/frontend/beta/js/Clipperz/PM/Proxy/Proxy.Test.js b/frontend/beta/js/Clipperz/PM/Proxy/Proxy.Test.js
new file mode 100644
index 0000000..fd5bf8a
--- a/dev/null
+++ b/frontend/beta/js/Clipperz/PM/Proxy/Proxy.Test.js
@@ -0,0 +1,94 @@
1/*
2
3Copyright 2008-2011 Clipperz Srl
4
5This file is part of Clipperz's Javascript Crypto Library.
6Javascript Crypto Library provides web developers with an extensive
7and efficient set of cryptographic functions. The library aims to
8obtain maximum execution speed while preserving modularity and
9reusability.
10For further information about its features and functionalities please
11refer to http://www.clipperz.com
12
13* Javascript Crypto Library is free software: you can redistribute
14 it and/or modify it under the terms of the GNU Affero General Public
15 License as published by the Free Software Foundation, either version
16 3 of the License, or (at your option) any later version.
17
18* Javascript Crypto Library is distributed in the hope that it will
19 be useful, but WITHOUT ANY WARRANTY; without even the implied
20 warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
21 See the GNU Affero General Public License for more details.
22
23* You should have received a copy of the GNU Affero General Public
24 License along with Javascript Crypto Library. If not, see
25 <http://www.gnu.org/licenses/>.
26
27*/
28
29if (typeof(Clipperz) == 'undefined') { Clipperz = {}; }
30if (typeof(Clipperz.PM) == 'undefined') { Clipperz.PM = {}; }
31if (typeof(Clipperz.PM.Proxy) == 'undefined') { Clipperz.PM.Proxy = {}; }
32
33//=============================================================================
34
35Clipperz.PM.Proxy.Test = function(args) {
36 args = args || {};
37
38 Clipperz.PM.Proxy.Offline.call(this, args);
39
40
41
42 return this;
43}
44
45Clipperz.PM.Proxy.Test.prototype = MochiKit.Base.update(new Clipperz.PM.Proxy.Offline(), {
46
47 'toString': function() {
48 return "Clipperz.PM.Proxy.Test";
49 },
50
51 //-------------------------------------------------------------------------
52
53 'isTestData': function() {
54 return typeof(this.userData()['__masterkey_test_value__'] != 'undefined');
55 },
56
57 //-------------------------------------------------------------------------
58
59 'userDetails': function() {
60 var result;
61
62 if (this.isTestData()) {
63 var serializedHeader;
64 var version;
65
66 version = this.userData()['version'];
67 serializedHeader = Clipperz.Base.serializeJSON(this.userData()['userDetails']);
68 result = Clipperz.PM.Crypto.encryptingFunctions.versions[version].encrypt(this.userData()['__masterkey_test_value__'], serializedHeader);
69 } else {
70 result = Clipperz.PM.Proxy.Offline.prototype.userDetails.call(this);
71 }
72
73 return result;
74 },
75
76 //-------------------------------------------------------------------------
77
78 'statistics': function() {
79 var result;
80 var serializedStatistics;
81 var version;
82
83 version = this.userData()['version'];
84 serializedStatistics = Clipperz.Base.serializeJSON(this.userData()['statistics']);
85 result = Clipperz.PM.Crypto.encryptingFunctions.versions[version].encrypt(this.userData()['__masterkey_test_value__'], serializedStatistics);
86
87 return result;
88 },
89
90 //-------------------------------------------------------------------------
91 __syntaxFix__: "syntax fix"
92
93});
94
diff --git a/frontend/beta/js/Clipperz/PM/Strings.js b/frontend/beta/js/Clipperz/PM/Strings.js
new file mode 100644
index 0000000..e9f5dbe
--- a/dev/null
+++ b/frontend/beta/js/Clipperz/PM/Strings.js
@@ -0,0 +1,231 @@
1/*
2
3Copyright 2008-2011 Clipperz Srl
4
5This file is part of Clipperz's Javascript Crypto Library.
6Javascript Crypto Library provides web developers with an extensive
7and efficient set of cryptographic functions. The library aims to
8obtain maximum execution speed while preserving modularity and
9reusability.
10For further information about its features and functionalities please
11refer to http://www.clipperz.com
12
13* Javascript Crypto Library is free software: you can redistribute
14 it and/or modify it under the terms of the GNU Affero General Public
15 License as published by the Free Software Foundation, either version
16 3 of the License, or (at your option) any later version.
17
18* Javascript Crypto Library is distributed in the hope that it will
19 be useful, but WITHOUT ANY WARRANTY; without even the implied
20 warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
21 See the GNU Affero General Public License for more details.
22
23* You should have received a copy of the GNU Affero General Public
24 License along with Javascript Crypto Library. If not, see
25 <http://www.gnu.org/licenses/>.
26
27*/
28
29if (typeof(Clipperz) == 'undefined') { Clipperz = {}; }
30if (typeof(Clipperz.PM) == 'undefined') { Clipperz.PM = {}; }
31if (typeof(Clipperz.PM.Strings) == 'undefined') { Clipperz.PM.Strings = {}; }
32if (typeof(Clipperz.PM.Strings.Languages) == 'undefined') { Clipperz.PM.Strings.Languages = {}; }
33
34Clipperz.PM.Strings.standardStrings = {
35
36 'loginPanelSwitchLanguageSelectOptions':[
37/*
38 {tag:'option', html:"Arabic (Oman) (العربية)", value:'ar-OM', disabled:true},
39 {tag:'option', html:"Arabic (Syria) (العربية)", value:'ar-SY', disabled:true},
40 {tag:'option', html:"Bahasa Indonesia", value:'id-ID', disabled:true},
41 {tag:'option', html:"Bulgarian (Български)", value:'bg-BG', disabled:true},
42 {tag:'option', html:"Català", value:'ca-ES', disabled:true},
43 {tag:'option', html:"Chinese (Simplified) (简体中文)", value:'zh-CN', disabled:true},
44 {tag:'option', html:"Chinese (Traditional) (正體中文)", value:'zh-TW', disabled:true},
45 {tag:'option', html:"Czech (Česky)", value:'cs-CZ', disabled:true},
46 {tag:'option', html:"Dansk", value:'da-DK', disabled:true},
47 {tag:'option', html:"Deutsch", value:'de-DE'/ *, disabled:true* /},
48 {tag:'option', html:"English (American)", value:'en-US'/ *, disabled:true* /},
49 {tag:'option', html:"English (British)", value:'en-GB'/ *, disabled:true* /},
50 {tag:'option', html:"English (Canadian)", value:'en-CA'/ *, disabled:true* /},
51 {tag:'option', html:"Español", value:'es-ES', disabled:true},
52 {tag:'option', html:"Eesti", value:'et-EE', disabled:true},
53 {tag:'option', html:"Français", value:'fr-FR', disabled:true},
54 {tag:'option', html:"Galego", value:'gl-ES', disabled:true},
55 {tag:'option', html:"Greek (Ελληνικά)", value:'el-GR', disabled:true},
56 {tag:'option', html:"Íslenska", value:'is-IS', disabled:true},
57 {tag:'option', html:"Italiano", value:'it-IT'/ *, disabled:true* /},
58 {tag:'option', html:"Japanese (日本語)", value:'ja-JP', disabled:true},
59 {tag:'option', html:"Korean (한국어)", value:'ko-KR', disabled:true},
60 {tag:'option', html:"Latviešu", value:'lv-LV', disabled:true},
61 {tag:'option', html:"Lietuvių", value:'lt-LT', disabled:true},
62 {tag:'option', html:"Macedonian (Македонски)", value:'mk-MK', disabled:true},
63 {tag:'option', html:"Magyar", value:'hu-HU', disabled:true},
64 {tag:'option', html:"Nederlands", value:'nl-NL', disabled:true},
65 {tag:'option', html:"Norsk bokmål", value:'nb-NO', disabled:true},
66 {tag:'option', html:"Norsk nynorsk", value:'nn-NO', disabled:true},
67 {tag:'option', html:"Persian (Western) (فارسى)", value:'fa-IR', disabled:true},
68 {tag:'option', html:"Polski", value:'pl-PL', disabled:true},
69 {tag:'option', html:"Português", value:'pt-PT'/ *, disabled:true* /},
70 {tag:'option', html:"Português Brasileiro", value:'pt-BR'/ *, disabled:true* /},
71 {tag:'option', html:"Românä", value:'ro-RO', disabled:true},
72 {tag:'option', html:"Russian (Русский)", value:'ru-RU', disabled:true},
73 {tag:'option', html:"Slovak (Slovenčina)", value:'sk-SK', disabled:true},
74 {tag:'option', html:"Slovenian (Slovenščina)", value:'sl-SI', disabled:true},
75 {tag:'option', html:"Suomi", value:'fi-FI', disabled:true},
76 {tag:'option', html:"Svenska", value:'sv-SE', disabled:true},
77 {tag:'option', html:"Thai (ไทย)", value:'th-TH', disabled:true},
78 {tag:'option', html:"Türkçe", value:'tr-TR', disabled:true},
79 {tag:'option', html:"Ukrainian (Українська)", value:'uk-UA', disabled:true}
80*/
81 {tag:'option', html:"Arabic (العربية)", value:"ar", disabled:true, cls:'disabledOption'},
82 // {tag:'option', html:"Chinese (中文)", value:"zh", disabled:true},
83 {tag:'option', html:"Chinese (Simplified) (简体中文)", value:'zh-CN'},
84 {tag:'option', html:"Dutch (Nederlands)", value:"nl-NL", disabled:true, cls:'disabledOption'},
85 {tag:'option', html:"English", value:"en-US"},
86 {tag:'option', html:"French (Français)", value:"fr-FR"},
87 {tag:'option', html:"German (Deutsch)", value:"de-DE"/* -- */, disabled:true, cls:'disabledOption' /* */},
88 {tag:'option', html:"Greek (Ελληνικά)", value:"el-GR"/* -- */, disabled:true, cls:'disabledOption' /* */},
89 {tag:'option', html:"Hebrew (עברית)", value:"he-IL"/* -- */, disabled:true, cls:'disabledOption' /* */},
90 {tag:'option', html:"Italian (Italiano)", value:"it-IT"},
91 {tag:'option', html:"Japanese (日本語)", value:"ja-JP"},
92 {tag:'option', html:"Korean (한국어)", value:"ko-KR", disabled:true, cls:'disabledOption'},
93 {tag:'option', html:"Norwegian (Norsk)", value:"no", disabled:true, cls:'disabledOption'},
94 {tag:'option', html:"Persian (فارسی)", value:"fa-IR", disabled:true, cls:'disabledOption'},
95 {tag:'option', html:"Polish (Polski)", value:"pl-PL", disabled:true, cls:'disabledOption'},
96 {tag:'option', html:"Portuguese (Português)", value:"pt-BR"},
97 {tag:'option', html:"Russian (Русский)", value:"ru-RU"/* -- */, disabled:true, cls:'disabledOption' /* */},
98 {tag:'option', html:"Spanish (Español)", value:"es-ES"},
99 {tag:'option', html:"Swedish (Svenska)", value:"sv-SE", disabled:true, cls:'disabledOption'},
100 {tag:'option', html:"Turkish (Türkçe)", value:"tr-TR", disabled:true, cls:'disabledOption'},
101 {tag:'option', html:"Vietnamese (Tiếng Việt)", value:"vi-VN", disabled:true, cls:'disabledOption'}
102 ]
103}
104
105Clipperz.PM.Strings.GeneralSettings = {
106 'en-us': {
107 'loginFormAarghThatsBadUrl':"http://www.clipperz.com/support/faq/account_faq",
108 'loginFormVerifyTheCodeUrl':"http://www.clipperz.com/learn_more/reviewing_the_code",
109
110 'donateHeaderLinkUrl': "http://www.clipperz.com/donations",
111 'creditsHeaderLinkUrl': "http://www.clipperz.com/credits",
112 'feedbackHeaderLinkUrl': "http://www.clipperz.com/contact",
113 'helpHeaderLinkUrl': "http://www.clipperz.com/support/user_guide",
114 'forumHeaderLinkUrl': "http://www.clipperz.com/forum",
115
116 'httpAuthBookmarkletConfiguration':{tag:'textarea', id:'httpAuthDefaultConfiguration', html:"" +
117 "{ \"page\":{\"title\":\"HTTP authentication\"}," + "\n" +
118 " \"form\":{\"attributes\": {" + "\n" +
119 " \"action\":\"\"," + "\n" +
120 " \"type\":\"http_auth\"" + "\n" +
121 " }, \"inputs\": [" + "\n" +
122 " {\"type\":\"text\",\"name\":\"url\",\"value\":\"\"}," + "\n" +
123 " {\"type\":\"text\",\"name\":\"username\",\"value\":\"\"}," + "\n" +
124 " {\"type\":\"password\",\"name\":\"password\",\"value\":\"\"}" + "\n" +
125 " ]}, \"version\":\"0.2.3\"}"
126 },
127
128 'directLoginJumpPageUrl':"",
129 'defaultFaviconUrl': "data:application/octet-stream;charset=utf-8;base64,AAABAAEAFxcAAAEAGAD8BgAAFgAAACgAAAAXAAAALgAAAAEAGAAAAAAAAAAAABIXAAASFwAAAAAAAAAAAAD///////////////////////////////////////////////////////////////////////////////////////////9zAC////////////////////////////////////////////////////////////////////////////////////////////9pAG////////////////////////////////////////////////////////////////////////////////////////////9rAC////////////////////////////////////////////////////////////////////////////////////////////9yAHP////////////////////////IyMizs7O6urrq6ur////////////Ozs6zs7Ozs7Pq6ur///////////////////////8AAAD////////////////////V1dWXl5eXl5eXl5elpaX4+Pj////Ozs6Xl5eXl5eXl5eenp7///////////////////////8AAAD////////////////////Ozs6Xl5eXl5eXl5eXl5fBwcHq6uqenp6Xl5eXl5eXl5eXl5f///////////////////////8AAAD////////////////////j4+OXl5eXl5eXl5eXl5eXl5elpaWXl5eXl5eXl5eXl5ezs7P///////////////////////8AAAD////////////////////////IyMiXl5eXl5eXl5eXl5eXl5eXl5eXl5eXl5eenp7x8fH////////////////////////////////////////////////////4+PilpaWXl5eXl5eXl5eXl5eXl5eXl5eXl5fOzs7////////////////////////////////////////////////////////q6uq6urqXl5eXl5eXl5eXl5eXl5eXl5eenp7V1dX4+Pj///////////////////////8AAAD////////////4+PjOzs6lpaWXl5eXl5eXl5eXl5eXl5eXl5eXl5eXl5eXl5eXl5eXl5e6urrj4+P///////////////8AAAD////////////BwcGXl5eXl5eXl5eXl5eXl5eXl5eXl5eXl5eXl5eXl5eXl5eXl5eXl5eXl5eXl5fx8fH///////////8AAAD///////////+zs7OXl5eXl5eXl5eXl5eXl5eXl5eXl5eXl5eXl5eXl5eXl5eXl5eXl5eXl5eXl5fj4+P///////////8AAAD////////////IyMiXl5eXl5eXl5eXl5e6urqXl5eXl5eXl5eXl5esrKylpaWXl5eXl5eXl5eenp7x8fH///////////8AAAD////////////////Ozs7Ozs7V1dX4+Pj///+Xl5eXl5eXl5eXl5fOzs7////q6urOzs7Ozs7q6ur///////////////8AAAD///////////////////////////////////+Xl5eXl5eXl5eXl5fOzs7///////////////////////////////////8AAAD///////////////////////////////////+Xl5eXl5eXl5eXl5fOzs7///////////////////////////////////8AAAD///////////////////////////////////+Xl5eXl5eXl5eXl5fOzs7///////////////////////////////////8AAAD////////////////////////////////////IyMiXl5eXl5eenp7x8fH///////////////////////////////////8AAAD////////////////////////////////////////j4+Pj4+Px8fH///////////////////////////////////////8AAAD///////////////////////////////////////////////////////////////////////////////////////////8AAAD///////////////////////////////////////////////////////////////////////////////////////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAo=",
130 'defaultFaviconUrl_IE': "https://www.clipperz.com/images/icons/misc/favicon.ico",
131
132 'donateSplashPanelIconUrl':"./images/smiles_big.gif",
133
134 'icons_baseUrl':"https://www.clipperz.com/images/icons",
135
136 'passwordGeneratorLowercaseCharset':"abcdefghijklmnopqrstuvwxyz",
137 'passwordGeneratorUppercaseCharset':"ABCDEFGHIJKLMNOPQRSTUVWXYZ",
138 'passwordGeneratorNumberCharset': "0123456789",
139 'passwordGeneratorSymbolCharset': "!@#$%^&*+?[]{}/|\\<>,.;:~=-_",
140
141 '_': ""
142 }
143}
144
145Clipperz.PM.Strings.defaultLanguages = {
146 'default':"en-us",
147
148 // 'de':"de-de",
149 // 'el':"el-gr",
150 // 'he':"he-il",
151 // 'ru':"ru-ru",
152
153
154 'fr':"fr-fr",
155 'es':"es-es",
156 'zh':"zh-cn",
157 'ja':"ja-jp",
158 'pt':"pt-br",
159 'it':"it-it",
160 'en': "en-us"
161}
162
163Clipperz.PM.Strings.inputTypeToRecordFieldType = {
164 'text': 'TXT',
165 'password': 'PWD',
166 'checkbox': 'CHECK',
167 'radio': 'RADIO',
168 'select': 'SELECT'
169};
170
171Clipperz.PM.Strings.Languages.setSelectedLanguage = function(aLanguage) {
172 var language;
173 varselectedLanguage;
174
175 language = (aLanguage || Clipperz.PM.Strings.preferredLanguage || 'default').toLowerCase();
176//MochiKit.Logging.logDebug("1 - language: " + language);
177 if (typeof(Clipperz.PM.Strings.defaultLanguages[language]) != 'undefined') {
178 language = Clipperz.PM.Strings.defaultLanguages[language];
179//MochiKit.Logging.logDebug("2 - language: " + language);
180 }
181
182 if (typeof(Clipperz.PM.Strings.Languages[language]) != 'undefined') {
183 selectedLanguage = language;
184//MochiKit.Logging.logDebug("### selectedLanguage full match: " + selectedLanguage);
185 } else if (typeof(Clipperz.PM.Strings.defaultLanguages[language.substr(0,2)]) != 'undefined') {
186 selectedLanguage = Clipperz.PM.Strings.defaultLanguages[language.substr(0,2)];
187//MochiKit.Logging.logDebug("### selectedLanguage partial match: " + selectedLanguage);
188 } else {
189 selectedLanguage = Clipperz.PM.Strings.defaultLanguages['default'];
190//MochiKit.Logging.logDebug("### selectedLanguage default match: " + selectedLanguage);
191 }
192
193//MochiKit.Logging.logDebug("### selectedLanguage: " + selectedLanguage);
194 if (selectedLanguage != Clipperz.PM.Strings.selectedLanguage) {
195//MochiKit.Logging.logDebug(">>> setting Clipperz.PM.Strings.selectedLanguage: " + selectedLanguage);
196 Clipperz.PM.Strings.selectedLanguage = selectedLanguage;
197
198 MochiKit.Base.update(Clipperz.PM.Strings, Clipperz.PM.Strings.standardStrings)
199//MochiKit.Logging.logDebug("=== 1: " + Clipperz.PM.Strings['bookmarkletTabInstructions']);
200 MochiKit.Base.updatetree(Clipperz.PM.Strings, Clipperz.PM.Strings.Languages[Clipperz.PM.Strings.defaultLanguages['default']]);
201//MochiKit.Logging.logDebug("=== 2: " + Clipperz.PM.Strings['bookmarkletTabInstructions']);
202 MochiKit.Base.updatetree(Clipperz.PM.Strings, Clipperz.PM.Strings.GeneralSettings[Clipperz.PM.Strings.defaultLanguages['default']]);
203//MochiKit.Logging.logDebug("=== 3: " + Clipperz.PM.Strings['bookmarkletTabInstructions']);
204 MochiKit.Base.updatetree(Clipperz.PM.Strings, Clipperz.PM.Strings.Languages[selectedLanguage]);
205//MochiKit.Logging.logDebug("=== 4: " + Clipperz.PM.Strings['bookmarkletTabInstructions']);
206 MochiKit.Base.updatetree(Clipperz.PM.Strings, Clipperz.PM.Strings.GeneralSettings[selectedLanguage]);
207//MochiKit.Logging.logDebug("=== 5: " + Clipperz.PM.Strings['bookmarkletTabInstructions']);
208
209 Clipperz.NotificationCenter.notify(Clipperz.PM.Strings.Languages, 'switchLanguage', selectedLanguage);
210//MochiKit.Logging.logDebug("<<< setting Clipperz.PM.Strings.selectedLanguage. Done");
211 }
212}
213
214Clipperz.PM.Strings.Languages.initSetup = function() {
215 varlanguage;
216 varlanguageParser;
217
218 language = navigator.language || navigator.userLanguage; //en, en-US, .... "de", "nb-no"
219 languageParser = new RegExp("language=([a-z]{2}(?:\-[a-z]{2})?)(\&|$)", "i");
220 if (languageParser.test(window.location.search)) {
221//MochiKit.Logging.logDebug("LANGUAGE specified in the query string");
222 language = RegExp.$1;
223 }
224
225//MochiKit.Logging.logDebug("+++ preferredLanguage: " + language);
226 Clipperz.PM.Strings.preferredLanguage = language.toLowerCase();
227//MochiKit.Logging.logDebug("## preferredLanguage: " + Clipperz.PM.Strings.preferredLanguage);
228 Clipperz.PM.Strings.Languages.setSelectedLanguage(Clipperz.PM.Strings.preferredLanguage);
229}
230
231//MochiKit.DOM.addLoadEvent(Clipperz.PM.Strings.Languages.initSetup);
diff --git a/frontend/beta/js/Clipperz/PM/Strings/MessagePanelConfigurations.js b/frontend/beta/js/Clipperz/PM/Strings/MessagePanelConfigurations.js
new file mode 100644
index 0000000..446e96c
--- a/dev/null
+++ b/frontend/beta/js/Clipperz/PM/Strings/MessagePanelConfigurations.js
@@ -0,0 +1,389 @@
1/*
2
3Copyright 2008-2011 Clipperz Srl
4
5This file is part of Clipperz's Javascript Crypto Library.
6Javascript Crypto Library provides web developers with an extensive
7and efficient set of cryptographic functions. The library aims to
8obtain maximum execution speed while preserving modularity and
9reusability.
10For further information about its features and functionalities please
11refer to http://www.clipperz.com
12
13* Javascript Crypto Library is free software: you can redistribute
14 it and/or modify it under the terms of the GNU Affero General Public
15 License as published by the Free Software Foundation, either version
16 3 of the License, or (at your option) any later version.
17
18* Javascript Crypto Library is distributed in the hope that it will
19 be useful, but WITHOUT ANY WARRANTY; without even the implied
20 warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
21 See the GNU Affero General Public License for more details.
22
23* You should have received a copy of the GNU Affero General Public
24 License along with Javascript Crypto Library. If not, see
25 <http://www.gnu.org/licenses/>.
26
27*/
28
29if (typeof(Clipperz) == 'undefined') { Clipperz = {}; }
30if (typeof(Clipperz.PM) == 'undefined') { Clipperz.PM = {}; }
31if (typeof(Clipperz.PM.Strings) == 'undefined') { Clipperz.PM.Strings = {}; }
32
33Clipperz.PM.Strings.messagePanelConfigurations = {
34
35
36 //-------------------------------------------------------------------------
37 //
38 // Registration - connection
39 //
40 'registration_verify': function() {
41 return {
42 'title': null,
43 'text': Clipperz.PM.Strings['connectionRegistrationSendingRequestMessageText']
44 }
45 },
46
47 'registration_sendingCredentials': function() {
48 return {
49 'title': null,
50 'text': Clipperz.PM.Strings['connectionRegistrationSendingCredentialsMessageText']
51 }
52 },
53
54 //-------------------------------------------------------------------------
55 //
56 // One Time Password login message panel
57 //
58
59 'OTP_login_start': function() {
60 return {
61 'title': Clipperz.PM.Strings['OTPloginMessagePanelInitialTitle'],
62 'text': Clipperz.PM.Strings['OTPloginMessagePanelInitialText'],
63 'steps': '+3',
64 'buttons': {}
65 }
66 },
67
68 'OTP_login_loadingOTP': function() {
69 return {
70 'title': Clipperz.PM.Strings['OTPloginMessagePanelLoadingTitle'],
71 'text': Clipperz.PM.Strings['OTPloginMessagePanelLoadingText']
72 }
73 },
74
75 'OTP_login_extractingPassphrase': function() {
76 return {
77 'title': Clipperz.PM.Strings['OTPloginMessagePanelProcessingTitle'],
78 'text': Clipperz.PM.Strings['OTPloginMessagePanelProcessingText']
79 }
80 },
81
82
83 //-------------------------------------------------------------------------
84 //
85 // Login message panel
86 //
87 'login_start': function() {
88 return {
89 'title': Clipperz.PM.Strings['loginMessagePanelInitialTitle'],
90 'text': Clipperz.PM.Strings['loginMessagePanelInitialText'],
91 'steps': '+7',
92 'buttons': {
93 'ok': Clipperz.PM.Strings['loginMessagePanelInitialButtonLabel']
94 }
95 }
96 },
97
98 'login_connected': function() {
99 return {
100 'title': Clipperz.PM.Strings['loginMessagePanelConnectedTitle'],
101 'text': Clipperz.PM.Strings['loginMessagePanelConnectedText'],
102 'buttons': {}
103 }
104 },
105
106 'login_failed':function() {
107 return {
108 'title': Clipperz.PM.Strings['loginMessagePanelFailureTitle'],
109 'text': Clipperz.PM.Strings['loginMessagePanelFailureText'],
110 'button': Clipperz.PM.Strings['loginMessagePanelFailureButtonLabel']
111 }
112 },
113
114 //-------------------------------------------------------------------------
115 //
116 // Login message panel - connection
117 //
118 'connection_sendingCredentials': function() {
119 return {
120 'title': Clipperz.PM.Strings['connectionLoginSendingCredentialsMessageTitle'],
121 'text': Clipperz.PM.Strings['connectionLoginSendingCredentialsMessageText']
122 }
123 },
124
125 'connection_credentialVerification': function() {
126 return {
127 'title': Clipperz.PM.Strings['connectionLoginCredentialsVerificationMessageTitle'],
128 'text': Clipperz.PM.Strings['connectionLoginCredentialsVerificationMessageText']
129 }
130 },
131
132 'connection_loggedIn': function() {
133 return {
134 'title': Clipperz.PM.Strings['connectionLoginDoneMessageTitle'],
135 'text': Clipperz.PM.Strings['connectionLoginDoneMessageText']
136 }
137 },
138
139 //-------------------------------------------------------------------------
140 //
141 //Login message panel - user
142 //
143 'connection_upgrading': function() {
144 return {
145 'title': Clipperz.PM.Strings['userLoginPanelUpgradingUserCredentialsMessageTitle'],
146 'text': Clipperz.PM.Strings['userLoginPanelUpgradingUserCredentialsMessageText'],
147 'steps': '+1'
148 }
149 },
150
151 'connection_done': function() {
152 return {
153 'title': Clipperz.PM.Strings['userLoginPanelConnectedMessageTitle'],
154 'text': Clipperz.PM.Strings['userLoginPanelConnectedMessageText']
155 }
156 },
157
158 'connection_tryOlderSchema': function() {
159 return {
160 'title': Clipperz.PM.Strings['userLoginPanelTryingAnOlderConnectionSchemaMessageTitle'],
161 'text': Clipperz.PM.Strings['userLoginPanelTryingAnOlderConnectionSchemaMessageText'],
162 'steps': '+4'
163 }
164 },
165
166 'connection_loadingUserData': function() {
167 return {
168 'title': Clipperz.PM.Strings['userLoginPanelLoadingUserDataMessageTitle'],
169 'text': Clipperz.PM.Strings['userLoginPanelLoadingUserDataMessageText']
170 }
171 },
172
173 'connection_decryptingUserData': function() {
174 return {
175 'title': Clipperz.PM.Strings['userLoginPanelDecryptingUserDataMessageTitle'],
176 'text': Clipperz.PM.Strings['userLoginPanelDecryptingUserDataMessageText'],
177 'steps': '+1'
178 }
179 },
180
181 'connection_decryptingUserStatistics': function() {
182 return {
183 'title': Clipperz.PM.Strings['userLoginPanelDecryptingUserStatisticsMessageTitle'],
184 'text': Clipperz.PM.Strings['userLoginPanelDecryptingUserStatisticsMessageText']
185 }
186 },
187
188 'collectingEntropy': function() {
189 return {
190 'text': Clipperz.PM.Strings['panelCollectingEntryopyMessageText'],
191 'steps': '+1'
192 }
193 },
194
195 //-------------------------------------------------------------------------
196 //
197 // Cards block - delete card panel
198 //
199 'deleteRecord_collectData': function() {
200 return {
201 'title': Clipperz.PM.Strings['deleteRecordPanelCollectRecordDataMessageTitle'],
202 'text': Clipperz.PM.Strings['deleteRecordPanelCollectRecordDataMessageText']
203 }
204 },
205
206 'deleteRecord_encryptData': function() {
207 return {
208 'title': Clipperz.PM.Strings['deleteRecordPanelEncryptUserDataMessageTitle'],
209 'text': Clipperz.PM.Strings['deleteRecordPanelEncryptUserDataMessageText']
210 }
211 },
212
213 'deleteRecord_sendingData': function() {
214 return {
215 'title': Clipperz.PM.Strings['deleteRecordPanelSendingDataToTheServerMessageTitle'],
216 'text': Clipperz.PM.Strings['deleteRecordPanelSendingDataToTheServerMessageText']
217 }
218 },
219
220 'deleteRecord_updatingInterface': function() {
221 return {
222 'title': Clipperz.PM.Strings['deleteRecordPanelUpdatingTheInterfaceMessageTitle'],
223 'text': Clipperz.PM.Strings['deleteRecordPanelUpdatingTheInterfaceMessageText']
224 }
225 },
226
227
228 //-------------------------------------------------------------------------
229 //
230 //Cards block - save card panel
231 //
232 'saveCard_collectRecordInfo': function() {
233 return {
234 'title': Clipperz.PM.Strings['recordSaveChangesPanelCollectRecordInfoMessageTitle'],
235 'text': Clipperz.PM.Strings['recordSaveChangesPanelCollectRecordInfoMessageText']
236 }
237 },
238
239 'saveCard_encryptUserData': function() {
240 return {
241 'title': Clipperz.PM.Strings['recordSaveChangesPanelEncryptUserDataMessageTitle'],
242 'text': Clipperz.PM.Strings['recordSaveChangesPanelEncryptUserDataMessageText']
243 }
244 },
245
246 'saveCard_encryptRecordData': function() {
247 return {
248 'title': Clipperz.PM.Strings['recordSaveChangesPanelEncryptRecordDataMessageTitle'],
249 'text': Clipperz.PM.Strings['recordSaveChangesPanelEncryptRecordDataMessageText']
250 }
251 },
252
253 'saveCard_encryptRecordVersions': function() {
254 return {
255 'title': Clipperz.PM.Strings['recordSaveChangesPanelEncryptRecordVersionDataMessageTitle'],
256 'text': Clipperz.PM.Strings['recordSaveChangesPanelEncryptRecordVersionDataMessageText']
257 }
258 },
259
260 'saveCard_sendingData': function() {
261 return {
262 'title': Clipperz.PM.Strings['recordSaveChangesPanelSendingDataToTheServerMessageTitle'],
263 'text': Clipperz.PM.Strings['recordSaveChangesPanelSendingDataToTheServerMessageText']
264 }
265 },
266
267 'saveCard_updatingInterface': function() {
268 return {
269 'title': Clipperz.PM.Strings['recordSaveChangesPanelUpdatingTheInterfaceMessageTitle'],
270 'text': Clipperz.PM.Strings['recordSaveChangesPanelUpdatingTheInterfaceMessageText']
271 }
272 },
273
274 //-------------------------------------------------------------------------
275 //
276 //Account panel - user preferences
277 //
278 'account_savingPreferences_1': function() {
279 return {
280 'title': Clipperz.PM.Strings['accountPreferencesSavingPanelTitle_Step1'],
281 'text': Clipperz.PM.Strings['accountPreferencesSavingPanelText_Step1'],
282 'steps': '+3'
283 }
284 },
285
286 'account_savingPreferences_2': function() {
287 return {
288 'title': Clipperz.PM.Strings['accountPreferencesSavingPanelTitle_Step2'],
289 'text': Clipperz.PM.Strings['accountPreferencesSavingPanelText_Step2']
290 }
291 },
292
293
294 //-------------------------------------------------------------------------
295 //
296 //Account panel - change credentials
297 //
298 'changeCredentials_encryptingData': function() {
299 return {
300 'title': Clipperz.PM.Strings['changeCredentialsPanelEncryptingDataMessageTitle'],
301 'text': Clipperz.PM.Strings['changeCredentialsPanelEncryptingDataMessageText']
302 }
303 },
304
305 'changeCredentials_creatingNewCredentials': function() {
306 return {
307 'title': Clipperz.PM.Strings['changeCredentialsPanelCreatingNewCredentialsMessageTitle'],
308 'text': Clipperz.PM.Strings['changeCredentialsPanelCreatingNewCredentialsMessageText']
309 }
310 },
311
312 'changeCredentials_sendingCredentials': function() {
313 return {
314 'title': Clipperz.PM.Strings['changeCredentialsPanelSendingNewCredentialsToTheServerMessageTitle'],
315 'text': Clipperz.PM.Strings['changeCredentialsPanelSendingNewCredentialsToTheServerMessageText']
316 }
317 },
318
319 'changeCredentials_done': function() {
320 return {
321 'title': Clipperz.PM.Strings['changeCredentialsPanelDoneMessageTitle'],
322 'text': Clipperz.PM.Strings['changeCredentialsPanelDoneMessageText']
323 }
324 },
325
326
327 //-------------------------------------------------------------------------
328 //
329 //Account panel - change credentials
330 //
331 'saveOTP_encryptUserData': function() {
332 return {
333 'title': Clipperz.PM.Strings['saveOTP_encryptUserDataTitle'],
334 'text': Clipperz.PM.Strings['saveOTP_encryptUserDataText'],
335 'steps': '+4'
336 }
337 },
338
339 'saveOTP_encryptOTPData': function() {
340 return {
341 'title': Clipperz.PM.Strings['saveOTP_encryptOTPDataTitle'],
342 'text': Clipperz.PM.Strings['saveOTP_encryptOTPDataText']
343 }
344 },
345
346 'saveOTP_sendingData': function() {
347 return {
348 'title': Clipperz.PM.Strings['saveOTP_sendingDataTitle'],
349 'text': Clipperz.PM.Strings['saveOTP_sendingDataText']
350 }
351 },
352
353 'saveOTP_updatingInterface': function() {
354 return {
355 'title': Clipperz.PM.Strings['saveOTP_updatingInterfaceTitle'],
356 'text': Clipperz.PM.Strings['saveOTP_updatingInterfaceText']
357 }
358 },
359
360
361 //-------------------------------------------------------------------------
362 //
363 //Data panel - processingImportData
364 //
365 'parseImportData': function() {
366 return {
367 'title': Clipperz.PM.Strings['importData_parsingDataTitle'],
368 'text': Clipperz.PM.Strings['importData_parsingDataText']
369 }
370 },
371
372 'previewImportData': function() {
373 return {
374 'title': Clipperz.PM.Strings['importData_previewingDataTitle'],
375 'text': Clipperz.PM.Strings['importData_previewingDataText']
376 }
377 },
378
379 'processingImportData': function() {
380 return {
381 'title': Clipperz.PM.Strings['importData_processingDataTitle'],
382 'text': Clipperz.PM.Strings['importData_processingDataText']
383 }
384 },
385
386 //-------------------------------------------------------------------------
387 __syntaxFix__: "syntax fix"
388
389}
diff --git a/frontend/beta/js/Clipperz/PM/Strings/Strings_de-DE.js b/frontend/beta/js/Clipperz/PM/Strings/Strings_de-DE.js
new file mode 100644
index 0000000..ecc8a36
--- a/dev/null
+++ b/frontend/beta/js/Clipperz/PM/Strings/Strings_de-DE.js
@@ -0,0 +1,352 @@
1/*
2
3Copyright 2008-2011 Clipperz Srl
4
5This file is part of Clipperz's Javascript Crypto Library.
6Javascript Crypto Library provides web developers with an extensive
7and efficient set of cryptographic functions. The library aims to
8obtain maximum execution speed while preserving modularity and
9reusability.
10For further information about its features and functionalities please
11refer to http://www.clipperz.com
12
13* Javascript Crypto Library is free software: you can redistribute
14 it and/or modify it under the terms of the GNU Affero General Public
15 License as published by the Free Software Foundation, either version
16 3 of the License, or (at your option) any later version.
17
18* Javascript Crypto Library is distributed in the hope that it will
19 be useful, but WITHOUT ANY WARRANTY; without even the implied
20 warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
21 See the GNU Affero General Public License for more details.
22
23* You should have received a copy of the GNU Affero General Public
24 License along with Javascript Crypto Library. If not, see
25 <http://www.gnu.org/licenses/>.
26
27*/
28
29Clipperz.PM.Strings.Languages['de-DE'.toLowerCase()] = MochiKit.Base.merge(Clipperz.PM.Strings.Languages['en-us'], {
30 'clipperzServiceDescription':"<h2>Privatsphäre für Deine Daten</h2> <ul> <li> <h3>Clipperz heißt:</h3> <ul> <li> <p>sichere und einfache zu bedienene Passwortverwaltung</p> </li> <li> <p>eine effektive Lösung des einmaligen Anmeldens</p> </li> <li> <p>eine digitale Brieftasche für Deine vertraulichen Daten</p> </li> </ul> </li> <li> <h3>Clipperz bietet Dir:</h3> <ul> <li> <p>einfaches Speichern und Verwalten von Passwörtern und Webzugangsdaten</p> </li> <li> <p>schnelles unkompliziertes einloggen, ohne Eingabe des Benutzernamen und Passworts, bei Webdiensten</p> </li> <li> <p>Schutz aller Deiner persönlichen Daten: Zutrittscodes, PINs, Benutzernamen, Passwörter, Kreditkartennummern, &hellip;</p> </li> <li> <p>Deine Geheimnisse mit Familienmitgliedern und Freunden zu teilen (mehr dazu in Kürze)</p> </li> </ul> </li> <li> <h3>Clipperz ist:</h3> <ul> <li> <p>kostenlos und absolut anonym</p> </li> <li> <p>unkomplizierter Zugriff zu jeder Zeit von jedem Rechner</p> </li> <li> <p>ohne Download und Installation verwendbar</p> </li> <li> <p>ein Schutz gegen das Speichern von Passwörtern auf Deinem PC oder das Notieren auf Papier</p> </li> </ul> </li> <li> <h3>Clipperz Sicherheit:</h3> <ul> <li> <p>Deine sensiblen persönlichen Informationen werden lokal durch Deinen Browser verschlüsselt, bevor sie an Clipperz über das Internet gesendet werden</p> </li> <li> <p>Der Schlüssel für diese Daten ist der Sicherheitssatz, den nur Du kennst</p> </li> <li> <p>Clipperz speichert Deine sensiblen Daten nur in verschlüsselter Form und kann zu keinem Zeitpunkt diese entschlüssel und in ihrer ursprünglichen Klartextform zugänglich machen</p> </li> <li> <p>Clipperz basiert auf standart Verschlüsselungsverfahren. Nichts ausergewöhnliches – oder hand gestricktes</p> </li> <li> <p>Du kannst den Quellcode zu jeder Zeit anschauen, aber Du brauchst nichts von Kryptographie zu verstehen um ein glücklicher Anwender zu sein!</p> </li> </ul> </li> <li> <a href=\"http://www.clipperz.com\" target=\"_blank\">Weitere Informationen</a> </li> </ul> ",
31 'loginFormTitle':"Login zu Deinem Clipperz Konto",
32 'loginFormUsernameLabel':"Benutzernamen",
33 'loginFormPassphraseLabel':"Sicherheitssatz",
34 'loginFormDontHaveAnAccountLabel':"Du hast noch kein Clipperz Konto?",
35 'loginFormCreateOneLabel':"Konto erstellen",
36 'loginFormForgotYourCredentialsLabel':"Zugangsdaten vergessen?",
37 'loginFormAarghThatsBadLabel':"Misst! Dass ist schlecht!",
38 'loginFormAfraidOfMaliciousScriptsLabel':"verängstigt von bösartigen Scripts?",
39 'loginFormVerifyTheCodeLabel':"begutachte den Quellcode",
40 'loginFormButtonLabel':"Einloggen",
41 'loginPanelSwithLanguageDescription':"<h5>Wechsel zu Deiner vervorzugten Sprache</h5> ",
42 'browserCompatibilityDescription':"<p>Bessere und sicherere Clipperz-Erfahrung mit Firefox. Clipperz funktioniert auch mit Safari, Opera und MS Internet Explorer!</p> ",
43 'loginMessagePanelInitialTitle':"Du wirst eingeloggt…",
44 'loginMessagePanelInitialButtonLabel':"Abbruch",
45 'loginMessagePanelConnectedTitle':"Verbunden",
46 'loginMessagePanelConnectedText':"Fertig",
47 'loginMessagePanelFailureTitle':"Fehler",
48 'loginMessagePanelFailureText':"Login fehlgeschlagen",
49 'loginMessagePanelFailureButtonLabel':"Schließen",
50 'connectionLoginSendingCredentialsMessageTitle':"Prüfe Zugangsdaten",
51 'connectionLoginSendingCredentialsMessageText':"Sende Zugangsdaten",
52 'connectionLoginCredentialsVerificationMessageTitle':"Prüfe Zugangsdaten",
53 'connectionLoginCredentialsVerificationMessageText':"Führe SRP Authentifizierung durch",
54 'connectionLoginDoneMessageTitle':"Prüfe Zugangsdaten",
55 'connectionLoginDoneMessageText':"Verbunden",
56 'userLoginPanelUpgradingUserCredentialsMessageTitle':"Prüfe Zugangsdaten",
57 'userLoginPanelUpgradingUserCredentialsMessageText':"Aktualisierung Deiner Zugangsdaten auf ein neues Authentifizierungsschema",
58 'userLoginPanelConnectedMessageTitle':"Benutzer authentifiziert",
59 'userLoginPanelConnectedMessageText':"Login erfolgreich",
60 'userLoginPanelTryingAnOlderConnectionSchemaMessageTitle':"Prüfe Zugangsdaten",
61 'userLoginPanelTryingAnOlderConnectionSchemaMessageText':"Probiere älteres Authentifizierungsschema",
62 'userLoginPanelLoadingUserDataMessageTitle':"Benutzer authentifiziert",
63 'userLoginPanelLoadingUserDataMessageText':"Lade verschlüsselte Kartendaten von Clipperz",
64 'userLoginPanelDecryptingUserDataMessageTitle':"Benutzer authentifiziert",
65 'userLoginPanelDecryptingUserDataMessageText':"Lokale Entschlüsselung der Kartendaten",
66 'userLoginPanelDecryptingUserStatisticsMessageTitle':"Benutzer authentifiziert",
67 'userLoginPanelDecryptingUserStatisticsMessageText':"Lokale Entschlüsselung der Benutzerstatisik",
68 'splashAlertTitle':"Willkommen bei Clipperz!",
69 'splashAlertText':"<p>Sicherheitshinweis</p> <ul> <li> <p>Die Speicherung von Informationen bei Clipperz ist so sicher, wie der Sicherheitssatz den Du zum Schutz gewählt hast. Ist der Sicherheitssatz nicht bekannt, können keine Informationen abgefragt werden.</p> </li> <li> <p>Solltest Du Clipperz nutzen, um sensible und kritische persönliche Daten abzuspeichern, so empfehlen wir in jedem Fall die Nutzung eines langen Sicherheitssatzes als Passwort und die Nutzung von Sonderzeichen, Zahlen, Groß- und Kleinbuchstaben.</p> </li> <li> <p>Clipperz kann einen verlorenen Sicherheitssatz nicht wiederherstellen!</p> </li> </ul> <p>Weitere Informationen findest Du bei <a href=\"http://www.clipperz.com\" target=\"_blank\">Clipperz</a>.</p> ",
70 'splashAlertCloseButtonLabel':"Ok",
71 'registrationFormTitle':"Erstelle Dein Konto",
72 'registrationFormUsernameLabel':"Benutzernamen",
73 'registrationFormPassphraseLabel':"Sicherheitssatz",
74 'registrationFormRetypePassphraseLabel':"Wiederhole Sicherheitssatz",
75 'registrationFormSafetyCheckLabel':"Ich akzeptiere dass es Clipperz nicht möglich ist, einen verlorenen Sicherheitssatz wiederherzustellen.",
76 'registrationFormTermsOfServiceCheckLabel':"Ich habe die <a href='http://www.clipperz.com/terms_of_service' target='_blank'>Nutzungsbedingungen</a> gelesen, verstanden und akzeptiere diese.",
77 'registrationFormDoYouAlreadyHaveAnAccountLabel':"Hast Du bereits einen Zugang?",
78 'registrationFormSimplyLoginLabel':"Einloggen",
79 'registrationFormButtonLabel':"Anmelden",
80 'registrationFormWarningMessageNotMatchingPassphrases':"Deine Sicherheitssätze stimmen nicht überein. Bitte erneut eingeben.",
81 'registrationFormWarningMessageSafetyCheckNotSelected':"Bitte lese die Bedingungen und akzeptiere die Auswahlboxen weiter unten.",
82 'registrationFormWarningMessageTermsOfServiceCheckNotSelected':"Du musst die Nutzungsbedingungen akzeptieren.",
83 'registrationMessagePanelInitialTitle':"Benutzer wird angelegt…",
84 'registrationMessagePanelInitialButtonLabel':"Abbruch",
85 'registrationMessagePanelRegistrationDoneTitle':"Anmeldung",
86 'registrationMessagePanelRegistrationDoneText':"Fertig",
87 'registrationMessagePanelFailureTitle':"Anmerldung fehlgeschlagen",
88 'registrationMessagePanelFailureButtonLabel':"Schließen",
89 'connectionRegistrationSendingRequestMessageText':"Zugangsdaten werden geprüft",
90 'connectionRegistrationSendingCredentialsMessageText':"Sende Zugangsdaten",
91 'registrationSplashPanelTitle':"Sicherheitshinweis",
92 'registrationSplashPanelDescription':"<p>Dies sind Deine Clipperz Zugangsdaten, pass sehr gut auf sie auf. Clipperz wird diese kein zweites und weiteres mal anzeigen!</p> ",
93 'registrationSplashPanelUsernameLabel':"Benutzernamen",
94 'registrationSplashPanelPassphraseLabel':"Schlüsselsatz",
95 'donateHeaderLinkLabel':"spende",
96 'creditsHeaderLinkLabel':"credits",
97 'feedbackHeaderLinkLabel':"feedback",
98 'helpHeaderLinkLabel':"hilfe",
99 'forumHeaderLinkLabel':"forum",
100 'recordMenuLabel':"Karten",
101 'accountMenuLabel':"Benutzer",
102 'dataMenuLabel':"Daten",
103 'contactsMenuLabel':"Kontakt",
104 'bookmarkletMenuLabel':"Bookmarklet",
105 'logoutMenuLabel':"Ausloggen",
106 'lockMenuLabel':"Sperren",
107 'lockTitle':"Dieses Konto ist gesperrt",
108 'lockDescription':"<p>Bitte gebe Deinen Sicherheitssatz ein, um das Clipperz-Konto zu entsperren.</p> ",
109 'unlockButtonLabel':"Entsperren",
110 'changePasswordTabLabel':"Sicherheitssatz ändern",
111 'changePasswordTabTitle':"Sicherheitssatz ändern",
112 'changePasswordFormUsernameLabel':"Benutzername",
113 'changePasswordFormOldPassphraseLabel':"Alter Sicherheitssatz",
114 'changePasswordFormNewPassphraseLabel':"Neuer Sicherheitssatz",
115 'changePasswordFormRetypePassphraseLabel':"Wiederholdung neuen Sicherheitssatz",
116 'changePasswordFormSafetyCheckboxLabel':"Ich akzeptiere dass es Clipperz nicht möglich ist, einen verlorenen Sicherheitssatz wiederherzustellen.",
117 'changePasswordFormSubmitLabel':"Sicherheitssatz ändern",
118 'changePasswordFormWrongUsernameWarning':"Falscher Benutzername",
119 'changePasswordFormWrongPassphraseWarning':"Falscher Sicherheitssatz",
120 'changePasswordFormWrongRetypePassphraseWarning':"Deine Sicherheitssätze stimmen nicht überein. Bitte erneut eingeben.",
121 'changePasswordFormSafetyCheckWarning':"Bitte ließ die folgenden Hinweise und akzeptiere diese.",
122 'changePasswordFormProgressDialogTitle':"Ändere Zugangsdaten",
123 'changePasswordFormProgressDialogConnectedMessageTitle':"Verbunden",
124 'changePasswordFormProgressDialogConnectedMessageText':"Fertig",
125 'changePasswordFormProgressDialogErrorMessageTitle':"Fehler",
126 'changePasswordFormProgressDialogErrorMessageText':"Ändern der Zugangsdaten fehlgeschlagen!",
127 'changeCredentialsPanelEncryptingDataMessageTitle':"Ändere Sicherheitssatz",
128 'changeCredentialsPanelEncryptingDataMessageText':"Lokale Verschlüsselung der Kartendaten",
129 'changeCredentialsPanelCreatingNewCredentialsMessageTitle':"Ändere Sicherheitssatz",
130 'changeCredentialsPanelCreatingNewCredentialsMessageText':"Aktualisiere Zugangsdaten",
131 'changeCredentialsPanelSendingNewCredentialsToTheServerMessageTitle':"Ändere Sicherheitssatz",
132 'changeCredentialsPanelSendingNewCredentialsToTheServerMessageText':"Sende verschlüsselte Zugangsdaten zu Clipperz",
133 'changeCredentialsPanelDoneMessageTitle':"Ändere Sicherheitssatz",
134 'changeCredentialsPanelDoneMessageText':"Fertig",
135 'manageOTPTabLabel':"Verwaltung des Sicheitssatzes für einmaliges Anmelden",
136 'manageOTPTabTitle':"Verwaltung des Sicheitssatzes für einmaliges Anmelden",
137 'manageOTPTabDescription':"<p>Der Sicherheitssatz für einmaliges Anmelden funktoniert wie Dein regulärer Sicherheitssatz, nur dass er nur einmal verwendet werden kann.</p> <p>Sollte der gleiche Sicherheitssatz zu einem späteren Zeitpunkt nocheinmal genutzt werden, wird dieser automatisch zurückgewießen und der Einlogvorgang scheitert.</p> <p>Sofort nach einem erfolgreichen Login wird der Sicherheitssatz für einmaliges Anmelden gelöscht und somit verhindert dass er ungewollt verwendet wird.</p> <p>Die Nutzung von Sicherheitssätzen für einmaliges Anmelden sind eine ideale Möglichkeit wenn Du verunsichert bist ob Trojaner, Spyware oder ähnliches auf Deinem Rechner vorhanden ist.</p> <p> <b>Es wird empfohlen Sicherheitssätze für einmaliges Anmelden beim Zugiff auf Clipperz zu verwenden, wenn man sich an öffentlichen Rechnern befindet, wie in Internet Cafes oder Bücherreien.</b> </p> <p> </p> <p> <b>Mehr dazu in Kürze ...</b> </p> ",
138 'accountPreferencesLabel':"Einstellungen",
139 'accountPreferencesTabTitle':"Einstellungen",
140 'accountPreferencesLanguageTitle':"Sprachenauswahl",
141 'accountPreferencesLanguageDescription':"<p>Wähle Deine bevorzugte Sprache, aus der unten stehenden Liste.</p> ",
142 'accountPreferencesInterfaceTitle':"Personalisiere Dein persönliches Clipperz-Erscheinungsbild",
143 'accountPreferencesInterfaceDescription':"<p>Passe dass Clipperz-Erscheinungsbild an Deine Wünsche an.</p> ",
144 'saveUserPreferencesFormSubmitLabel':"Speichern",
145 'cancelUserPreferencesFormSubmitLabel':"Abbruch",
146 'accountPreferencesSavingPanelTitle_Step1':"Speichere Einstellungen",
147 'accountPreferencesSavingPanelText_Step1':"Lokale Verschlüsselung der Einstellungen",
148 'accountPreferencesSavingPanelTitle_Step2':"Speichere Einstellungen",
149 'accountPreferencesSavingPanelText_Step2':"Sende verschlüsselte Einstellungen",
150 'deleteAccountTabLabel':"Konto löschen",
151 'deleteAccountTabTitle':"Konto löschen",
152 'deleteAccountFormUsernameLabel':"Benutzername",
153 'deleteAccountFormPassphraseLabel':"Sicherheitssatz",
154 'deleteAccountFormSafetyCheckboxLabel':"Ich bin mir bewusst, dass alle meine Daten gelöscht werden und dieser Vorgang in keinem Falle rückgängig gemacht werden kann.",
155 'deleteAccountFormSubmitLabel':"Konto löschens",
156 'deleteAccountFormWrongUsernameWarning':"Falscher Benutzername",
157 'deleteAccountFormWrongPassphraseWarning':"Falscher Sicherheitssatz",
158 'deleteAccountFormSafetyCheckWarning':"Bitte lese die Bedingungen und akzeptiere die Auswahlboxen weiter unten.",
159 'accountPanelDeletingAccountPanelConfirmationTitle':"ACHTUNG",
160 'accountPanelDeleteAccountPanelConfirmationText':"Bist Du sicher, dass Du den Zugang löschen möchtest?",
161 'accountPanelDeleteAccountPanelConfirmButtonLabel':"Ja",
162 'accountPanelDeleteAccountPanelDenyButtonLabel':"Nein",
163 'offlineCopyTabLabel':"Offline Kopie",
164 'offlineCopyTabTitle':"Offline Kopie",
165 'offlineCopyTabDescription':"<p>Mit nur einem Klick kannst Du alle Deine verschlüsselten Daten von dem Clipperz Server auf Deine Festplatte speichern und somit eine “nur lesbare” Offline Version anlegen. Diese Version ist auch dann verwendbar, wenn Du keine Verbindung ins Internet hast. (Zum Beispiel zum Speichern von Login-Informationen bei einem Hotspot)</p> <p>Die “nur lesbare” Version ist genauso sicher, wie die änderbare Version auf dem Server. Deine Daten werden niemals entschlüsselt gespeichert - beide Versionen verwenden die gleiche Art der Verschlüsselung und Entschlüsselung direkt im Browser.</p> <ol> <li> <p>Klicke auf den untenstehenden Link um die Offline Version herunterzuladen.</p> </li> <li> <p>Der Browser fragt Dich, was Du mit der Datei “Clipperz_YYYYMMDD.zip” machen möchtest. Speichere Sie auf Deine Festplatte.</p> </li> <li> <p>Unzip (dekomprimiere) die Datei. Du erhälst das Verzeichnis “Clipperz_YYYYMMDD”.</p> </li> <li> <p>Öffne das Verzeichnis “Clipperz_YYYYMMDD” und mache einen Doppelklick auf die Datei “index.html”.</p> </li> <li> <p>Gib Deinen Clipperz Benutzernamen und Sicherheitsschlüssel ein, um Zugriff auf Deine persönlichen Daten auch ohne Internetzugang zu erhalten.</p> </li> </ol> ",
166 'offlineCopyDownloadLinkLabel':"Download",
167 'sharingTabLabel':"Freigabe für gemeinsame Nutzung",
168 'sharingTabTitle':"Freigabe für gemeinsame Nutzung",
169 'sharingTabDescription':"<p>Häufig muss eine vertrauenswürdige Information mit mehreren Personen geteilt werden.</p> <p>Dies sollte so einfach sein, wie einem Kollegen die PIN für den Anrufbeantworter zu geben, wenn Du im Urlaub bist; jedoch so schwierig, wie berechtigten Erben Zugriff auf das Ersparte bei der Bank zu geben.</p> <p>Clipperz ermöglicht die einfache Freigabe für gemeinsam genutzte Informationen, an berechtigte Personen, durch einen einfachen Prozess.</p> <p> </p> <p> <b>Mehr dazu in Kürze ...</b> </p> ",
170 'importTabLabel':"Import",
171 'importTabTitle':"Import",
172 'importTabDescription':"<p> <b>In Kürze ...</b> </p> ",
173 'printingTabLabel':"Export",
174 'printingTabTitle':"Export",
175 'printingTabDescription':"<p> <b>Drucke deine Kartendaten</b> </p> <p>Klicke auf den untenstehenden Link. Es öffnet sich ein Fenster mit Deinen Kartendaten in einem druckerfreundlichen Format.</p> <p>Wenn Du den Ausdruck aus Absicherungsgründen nutzen möchtest, nutze lieber die Variante der sichereren “Offline Kopie”. Ein Ausdruck ist wie eine Notiz auf dem Scheibtisch und könnte von jedem ohne weiteres gelesen werden. Bewahre diesen an einem sicheren, für andere nicht zugänglichen Ort auf!</p> ",
176 'printingLinkLabel':"Druckerfreundliches Format",
177 'contactsTabLabel':"Kontakte",
178 'contactsTabTitle':"Kontakte",
179 'bookmarkletTabLabel':"Bookmarklet",
180 'bookmarkletTabTitle':"Bookmarklet",
181 'bookmarkletTabDescription':"<p>Ein Bookmarklet ist ein Werkezug, welches Dir mit einem Mausklick wichtige Funktionen ermöglicht. Es kann gespeichert und verwendet werden wie eine ganz normale Webseite, die Du in Deine Favoriten gespeichert hast.</p> <p>Das clipperz Bookmarklet ermöglicht Dir schnell und einfach neue Karten und Direkt-Logins für bestehende Karten anzulegen.</p> <p> <b>Bitte beachte: Das Bookmarklet enthält keine Informationen zu Deinem Zugang (wie Benutzernamen oder Passwort), das Bookmarklet ist ein generisches Werzeug, welches für jeden Clipperz Anwender den gleichen Code beinhaltet.</b> </p> <div> <p>Um das Bookmarklet zu installieren <b>ziehe</b> den unten stehenden Link in die Lesezeichen-Leiste Deines Browsers.</p> </div> ",
182 'bookmarkletTabBookmarkletTitle':"Zu Clipperz hinzufügen",
183 'bookmarkletTabInstructions':"<h3>Anlegen einer neuen Karte für das Direkt Login bei einem Webservice</h3> <ol> <li> <p>Öffne die Webseite, auf der das Anmeldeforumlar vorhanden ist. (Das ist die Seite, auf der Du normal Deine Zugangsdaten einträgst)</p> </li> <li> <p>Öffne das Boormarklet durch anklicken: ein Pop-Up Fenster erscheint und bietet Dir die Karteninformationen an.</p> </li> <li> <p>Kopiere von diesem Fenster den Inhalt des größten Textfeldes durch in die Zwischenablage (Makieren und STRG+C)</p> </li> <li> <p>Öffne Deinen Clipperz Zugang und wähle <b>Neue Karte anlegen</b>.</p> </li> <li> <p>Füge den Inhalt Deiner Zwischenablage in das Textfeld ein (STRG+V) und ergänze optional einen <b>Titel</b>.</p> </li> <li> <p>Drücke die <b>Anlegen</b> Schaltfläche, kontrolliere nocheinmal die Details, und wähle anschließend <b>Speichern<b>.</p> </li> </ol> <h3>Direkt Login Funktionalität zu einer bestehenden Karte ergänzen</h3> <ol> <li> <p>Gleich wie oben.</p> </li> <li> <p>Gleich wie oben.</p> </li> <li> <p>Gleich wie oben.</p> </li> <li> <p>Öffne Deinen Clipperz Zugang und wähle die Karte, die Du ändern möchtest. Klicke anschließend auf <b>Bearbeiten</b>.</p> </li> <li> <p>Füge den Inhalt Deiner Zwischenablage in das Textfeld für “Direkt Login” ein (STRG+V).</p> </li> <li> <p>Drücke auf <b>Direkt Login hinzufügen</b>, kontrolliere die Angabgen und wähle <b>Speichern</b>.</p> </li> </ol> <p> </p> <p>Weitere Informationen über das Bookmarklet findest Du <a href=\"http://www.clipperz.com/support/user_guide/bookmarklet\" target=\"_blank\">hier</a>.</p> ",
184 'mainPanelDirectLoginBlockLabel':"Direktes Login",
185 'directLinkReferenceShowButtonLabel':"zeigen",
186 'mainPanelDirectLoginBlockDescription':"<p>Add “direct logins” to sign in to your web accounts without typing usernames and passwords!</p> <p>“Direct logins” greatly enhance your password security since you can:</p> <ul> <li> <p>conveniently adopt and enter complex passwords;</p> </li> <li> <p>never re-use the same and easy-to-guess password.</p> </li> </ul> <p>Simple and quick configuration with the Clipperz <b>bookmarklet</b>.</p> <a href=\"http://www.clipperz.com/support/user_guide/direct_logins\" target=\"_blank\">Learn more about “direct logins”</a> ",
187 'mainPanelRecordsBlockLabel':"Karten",
188 'mainPanelAddRecordButtonLabel':"Neue Karte anlegen",
189 'mainPanelRemoveRecordButtonLabel':"Karte löschen",
190 'mainPanelRecordFilterBlockAllLabel':"all",
191 'mainPanelRecordFilterBlockTagsLabel':"tags",
192 'mainPanelRecordFilterBlockSearchLabel':"search",
193 'recordDetailNoRecordAtAllTitle':"Willkommen bei Clipperz!",
194 'recordDetailNoRecordAtAllDescription':"<h5>Beginne mit dem Hinzufügen von Karten zu Deinem Zugang.</h5> <p>Karten sind einfache und flexible Formulare, bei denen Du Deine Passwörter und andere vertrauenswürde Daten speichern kannst.</p> <p>Karten können Zugangsinformationen für eine WebSite, die Kombination Deines Fahrradschlosses, oder Daten Deiner Kreditkarte enthalten, ...</p> <h5>Vergiss nicht das Bookmarklet</h5> <p>Bevor Du beginnst, installiere Dir das “Add to Clipperz” Bookmarklet: Es vereinfacht Dir das anlegen von Karten und verbessert somit den Komfor.</p> <p>Gehe zum “Bookmarklet” Tabulator um herauszufinden, wie es installiert und verwendet werden kann.</p> <p> </p> <p>Dann klicke einfach auf den <b>Neue Karte anlegen</b> Button und genieße Deinen Clipperz Zugang.</p> <p> </p> <a href=\"http://www.clipperz.com/support/user_guide/managing_cards\" target=\"_blank\">Näheres zum Erstellen und Verwalten von Karten lernen</a> ",
195 'newRecordWizardTitleBox':"<h5>Bitte wähle eine Vorlage</h5> <p>Karten sind einfache und flexible Formulare, bei denen Du Passwörter oder jede Art von vertraulichen Informationen speichern kannst.</p> <p>Beginne mit der Auswahl einer der unten stehenden Vorlagen. Zu jeder Zeit kannst Du Deine Karten durch hinzufügen oder entfernen von Feldern verändern.</p> ",
196 'newRecordWizardBookmarkletConfigurationTitle':"Direktes Login",
197 'newRecordWizardBookmarkletConfigurationDescription':"<p>Füge bitte unten den Konfigurationscode ein, den das Clipperz Bookmarklet erzeugt hat.</p> <p>Eine neue Karte mit einem vollständigen Direkt Login zu dem gewählten Webzugang wird angelegt.</p> ",
198 'newRecordWizardCreateButtonLabel':"Anlegen",
199 'newRecordWizardCancelButtonLabel':"Abbruch",
200 'recordTemplates':{
201 'WebAccount':{
202 'title':"Web Zugangsdaten",
203 'description':"<p>Eine einfache Karte, die die Login Informationen für einen Online Service speichert.</p> ",
204 'fields':{
205 'URL':"Web Adresse",
206 'TXT':"Benutzername / E-Mail",
207 'PWD':"Passwort"
208 }
209 },
210 'BankAccount':{
211 'title':"Bank Zugangsdaten",
212 'description':"<p>Speichere geschützt Deine Online Banking Zugangsdaten.</p> ",
213 'fields':{
214 'TXT':"Bank",
215 'TXT':"Kontonummer",
216 'URL':"Web Adresse",
217 'TXT':"Online Zugangsdaten",
218 'PWD':"Online Passwort"
219 }
220 },
221 'CreditCard':{
222 'title':"Kreditkarte",
223 'description':"<p>Kartennummer, CVV2, Ablaufdatum und PIN zu jeder Zeit abrufbar bei Clipperz.</p> ",
224 'fields':{
225 'TXT':"Art (Visa, AmEx, ...)",
226 'TXT':"Nummer",
227 'TXT':"Inhaber",
228 'TXT':"Ablaufdatum",
229 'TXT':"CVV2",
230 'PWD':"PIN",
231 'URL':"Webseite",
232 'TXT':"Online Zugangsdaten",
233 'PWD':"Passwort"
234 }
235 },
236 'AddressBookEntry':{
237 'title':"Adressbuch Eintrag",
238 'description':"<p>Clipperz kann auch als Dein neues privates Adressbuch agieren. Nutze diese Vorlage um einfach eine neuen Eintrag anzulegen.</p> ",
239 'fields':{
240 'TXT':"Name",
241 'TXT':"Email",
242 'TXT':"Telefon",
243 'TXT':"Handy",
244 'ADDR':"Adresse"
245 }
246 },
247 'Custom':{
248 'title':"Benutzerdefinierte Karte",
249 'description':"<p>Egal welche Art von vertraulichen Informationen Du speichern musst, mit der benutzerdefinierten Karte kannst Du diese Informationen speichern.</p> ",
250 'fields':{
251 'TXT':"Feldname 1",
252 'TXT':"Feldname 2",
253 'TXT':"Feldname 3"
254 }
255 }
256},
257 'recordFieldTypologies':{
258 'TXT':{
259 'description':"simple text field",
260 'shortDescription':"Text"
261 },
262 'PWD':{
263 'description':"simple text field, with default status set to hidden",
264 'shortDescription':"Passwort"
265 },
266 'URL':{
267 'description':"simple text field in edit mode, that became an active url in view mode",
268 'shortDescription':"Webadresse"
269 },
270 'DATE':{
271 'description':"a value set with a calendar helper",
272 'shortDescription':"Datum"
273 },
274 'ADDR':{
275 'description':"just like the URL, but the active link points to Google Maps (or similar service) passing the address value as argument",
276 'shortDescription':"Postanschrift"
277 },
278 'CHECK':{
279 'description':"check description",
280 'shortDescription':"check"
281 },
282 'RADIO':{
283 'description':"radio description",
284 'shortDescription':"radio"
285 },
286 'SELECT':{
287 'description':"select description",
288 'shortDescription':"select"
289 }
290},
291 'newRecordPanelGeneralExceptionTitle':"Fehler",
292 'newRecordPanelGeneralExceptionMessage':"Der Konfigurationstext ist nicht gültig. Stelle sicher, dass Du den Text des Bookmarket Pop-Up eingefügt hast und versuch es nocheinmal.",
293 'newRecordPanelWrongBookmarkletVersionExceptionTitle':"Fehler",
294 'newRecordPanelWrongBookmarkletVersionExceptionMessage':"Der Konfigurationstext wurde von einer älteren Version des Bookmarklets erstellt. Bitte aktualisiere Dein Bookmarklet und probiere es erneut.",
295 'newRecordPanelExceptionPanelCloseButtonLabel':"Abbruch",
296 'mainPanelDeletingRecordPanelConfirmationTitle':"Lösche ausgewählte Karte",
297 'mainPanelDeleteRecordPanelConfirmationText':"Möschtest Du wirklich die ausgewählte Karte löschen?",
298 'mainPanelDeleteRecordPanelConfirmButtonLabel':"Ja",
299 'mainPanelDeleteRecordPanelDenyButtonLabel':"Nein",
300 'mainPanelDeletingRecordPanelInitialTitle':"Lösche ausgewählte Karte",
301 'mainPanelDeletingRecordPanelCompletedText':"Fertig",
302 'deleteRecordPanelCollectRecordDataMessageTitle':"Karte löschen",
303 'deleteRecordPanelCollectRecordDataMessageText':"Aktualisiere Kartenliste",
304 'deleteRecordPanelEncryptUserDataMessageTitle':"Karte löschen",
305 'deleteRecordPanelEncryptUserDataMessageText':"Lokale Verschlüsselung der Karten Kopfdaten",
306 'deleteRecordPanelSendingDataToTheServerMessageTitle':"Karte löschen",
307 'deleteRecordPanelSendingDataToTheServerMessageText':"Lade verschlüsselte Karten Kopfdaten zu Clipperz hoch",
308 'deleteRecordPanelUpdatingTheInterfaceMessageTitle':"Karte löschen",
309 'deleteRecordPanelUpdatingTheInterfaceMessageText':"Aktualisiere Benutzerschnittstelle",
310 'recordDetailNoRecordSelectedTitle':"Keine Karte ausgewählt",
311 'recordDetailNoRecordSelectedDescription':"<p>Bitte wähle aus der linken Liste eine Karte aus.</p> ",
312 'recordDetailLoadingRecordMessage':"Lade verschlüsselte Karte von Clipperz runter",
313 'recordDetailDecryptingRecordMessage':"Lokale entschlüsselung der Kartendaten",
314 'recordDetailLoadingRecordVersionMessage':"Herunterladen der aktuellsten Kartenversion",
315 'recordDetailDecryptingRecordVersionMessage':"Lokale Entschlüsselung der aktuellen Version",
316 'recordDetailLoadingErrorMessageTitle':"Fehler beim Herunterladen der Karte",
317 'recordDetailNotesLabel':"Notiz",
318 'recordDetailLabelFieldColumnLabel':"Feld Namen",
319 'recordDetailDataFieldColumnLabel':"Feld Daten",
320 'recordDetailTypeFieldColumnLabel':"Art",
321 'recordDetailSavingChangesMessagePanelInitialTitle':"Speichere Karte",
322 'recordDetailAddFieldButtonLabel':"Neues Feld hinzufügen",
323 'recordDetailDirectLoginBlockTitle':"Direkt Logins",
324 'recordDetailNewDirectLoginDescription':"<p>Direkt Login Konfiguration</p> ",
325 'recordDetailDirectLoginBlockNoDirectLoginConfiguredDescription':"<p>Enthält diese Karte Informationen um Zugriff auf ein Online Service zu erhalten?</p> <p>Verwende das Bookmarklet um ein “Direkt Login” mit nur einem Klick von Clipperz zu konfigurieren.</p> ",
326 'recordDetailAddNewDirectLoginButtonLabel':"Neues Direktlogin hinzufügen",
327 'recordDetailEditButtonLabel':"Bearbeiten",
328 'recordDetailSaveButtonLabel':"Speichern",
329 'recordDetailCancelButtonLabel':"Abbruch",
330 'newRecordTitleLabel':"_neue Karte_",
331 'newDirectLoginLabelSuffix':"",
332 'recordSaveChangesPanelCollectRecordInfoMessageTitle':"Karte speichern",
333 'recordSaveChangesPanelCollectRecordInfoMessageText':"Aktualisierung der Karten Kopfdaten",
334 'recordSaveChangesPanelEncryptUserDataMessageTitle':"Karte speichern",
335 'recordSaveChangesPanelEncryptUserDataMessageText':"Lokale Verschlüsselung der Karten Kopfdaten",
336 'recordSaveChangesPanelEncryptRecordDataMessageTitle':"Karte speichern",
337 'recordSaveChangesPanelEncryptRecordDataMessageText':"Lokale Verschlüsselung der Karten Informationen",
338 'recordSaveChangesPanelEncryptRecordVersionDataMessageTitle':"Karte speichern",
339 'recordSaveChangesPanelEncryptRecordVersionDataMessageText':"Lokale Verschlüsselung der Karten Versions Informationen",
340 'recordSaveChangesPanelSendingDataToTheServerMessageTitle':"Karte speichern",
341 'recordSaveChangesPanelSendingDataToTheServerMessageText':"Verschlüsselte Karten Kopfdaten auf Clipperz hochladen",
342 'recordSaveChangesPanelUpdatingTheInterfaceMessageTitle':"Karte speichern",
343 'recordSaveChangesPanelUpdatingTheInterfaceMessageText':"Aktualisierung der Benutzerschnittstelle",
344 'exit':"<h2> <b>Auf Wiedersehen! Danke, dass Du Clipperz verwendet hast.</b> </h2> <ul> <li> <h3>Hinweis:</h3> <ul> <li> <p>Speichere diese Seite in Deine Favoriten, damit Du auch in Zukunft dich sicher mit Clipperz verbinden kannst (solltest Du dies nicht bereits getan haben)</p> </li> <li> <p>Clipperz wird Dir niemals eine E-Mail senden, weil wir Dich niemals nach Deiner E-Mail Anschrift gefragt haben (und dies auch nie werden) – öffne daher niemals eine Mail, die wvon Clipperz zu sein scheint</p> </li> </ul> </li> </ul> <p> </p> <p>In 10 Sekunden wirdst Du auf eine Seite von Wikipedia umgeleitet, wo Du über eine herausragende Sicherheitslücke informiert wirst.</p> ",
345 //'DWRUtilLoadingMessage':"Lade Daten ...",
346 'comingSoon':"In Kürze ...",
347 'panelCollectingEntryopyMessageText':"Sammlung",
348 'directLoginConfigurationCheckBoxFieldSelectedValue':"Ja",
349 'directLoginConfigurationCheckBoxFieldNotSelectedValue':"Nein",
350
351__syntaxFix__: "syntax fix"
352});
diff --git a/frontend/beta/js/Clipperz/PM/Strings/Strings_el-GR.js b/frontend/beta/js/Clipperz/PM/Strings/Strings_el-GR.js
new file mode 100644
index 0000000..37e0a96
--- a/dev/null
+++ b/frontend/beta/js/Clipperz/PM/Strings/Strings_el-GR.js
@@ -0,0 +1,701 @@
1/*
2
3Copyright 2008-2011 Clipperz Srl
4
5This file is part of Clipperz's Javascript Crypto Library.
6Javascript Crypto Library provides web developers with an extensive
7and efficient set of cryptographic functions. The library aims to
8obtain maximum execution speed while preserving modularity and
9reusability.
10For further information about its features and functionalities please
11refer to http://www.clipperz.com
12
13* Javascript Crypto Library is free software: you can redistribute
14 it and/or modify it under the terms of the GNU Affero General Public
15 License as published by the Free Software Foundation, either version
16 3 of the License, or (at your option) any later version.
17
18* Javascript Crypto Library is distributed in the hope that it will
19 be useful, but WITHOUT ANY WARRANTY; without even the implied
20 warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
21 See the GNU Affero General Public License for more details.
22
23* You should have received a copy of the GNU Affero General Public
24 License along with Javascript Crypto Library. If not, see
25 <http://www.gnu.org/licenses/>.
26
27*/
28
29//=============================================================================
30//
31 // G R E E K (el_GR)
32//
33//=============================================================================
34
35Clipperz.PM.Strings.Languages['el-gr'] = MochiKit.Base.merge(Clipperz.PM.Strings.Languages['en-us'], {
36
37//-----------------------------------------------------
38 //Login page - description
39 'clipperzServiceDescriptionConfig': [
40 {tag:'h2', html:'Κρατήστε το για τον Εαυτό Σας'},
41 {tag:'ul', children:[
42 {tag:'li', children:[
43 {tag:'h3', html:'Το Clipperz είναι:'},
44 {tag:'ul', children:[
45 {tag:'li', children:[{tag:'span', html:'Ένας ασφαλής και απλός τρόπος διαχείρησης όλων των κωδικών πρόσβασης σας'}]},
46 {tag:'li', children:[{tag:'span', html:'Μια αποτελεσματική λύση πρόσβασης σε δεδομένα/εφαρμογές με μοναδικό κωδικό'}]},
47 {tag:'li', children:[{tag:'span', html:'Μια ψηφιακή θυρίδα για τα απόρρητα δεδομένα σας'}]}
48 ]}
49 ]},
50 {tag:'li', children:[
51 {tag:'h3', html:'Με το Clipperz μπορείτε:'},
52 {tag:'ul', children:[
53 {tag:'li', children:[{tag:'span', html:'Να αποθηκεύσετε και να διαχειριστείτε όλους τους κωδικούς πρόσβασης και τα online πιστοποιητικά/διαπιστευτήρια σας'}]},
54 {tag:'li', children:[{tag:'span', html:'Να έχετε πρόσβαση (login) στις υπηρεσίες διαδικτύου χωρίς την εισαγωγή oνομάτων λογαρισμών χρήστη (username),ή, κωδικών πρόσβασης (passwords)'}]},
55 {tag:'li', children:[{tag:'span', html:'Να προστατεύσετε όλα τα προσωπικά δεδομένα σας: κωδικούς συναγερμών, PINs, αριθμούς πιστωτικών καρτών, ...'}]},
56 {tag:'li', children:[{tag:'span', html:'Να μοιραστείτε δεδομένα με μέλη της οικογένεια σας και τους συνεργάτες σας (σύντομα στην διάθεση σας)'}]}
57 ]}
58 ]},
59 {tag:'li', children:[
60 {tag:'h3', html:'Τα πλεονεκτήματα του Clipperz είναι:'},
61 {tag:'ul', children:[
62 {tag:'li', children:[{tag:'span', html:'Είναι δωρεάν και προσφέρει πρόσβαση ανώνυμα'}]},
63 {tag:'li', children:[{tag:'span', html:'Μπορεί να χρησιμοποιηθεί οποαδήποτε ώρα και από οποιοδήποτε τερματικό'}]},
64 {tag:'li', children:[{tag:'span', html:'Δεν απαιτεί την φόρτωση και εγκατάσταση οποιουδήποτε λογισμικού'}]},
65 {tag:'li', children:[{tag:'span', html:'Αποφεύγετε την διατήριση απορρήτων στον υπολογιστή σας ή σε έντυπη μορφή'}]}
66 ]}
67 ]},
68 {tag:'li', children:[
69 {tag:'h3', html:'Η ασφάλεια που παρέχει το Clipperz:'},
70 {tag:'ul', children:[
71 {tag:'li', children:[{tag:'span', html:'Τα απόρρητα δεδομένα σας κωδικοποιούνται τοπικά από τον διακομιστή σας (browser) πρίν να φορτωθούν στο Clipperz'}]},
72 {tag:'li', children:[{tag:'span', html:'Το κλειδί της κωδικοποίησης είναι μία φράση-κωδικός γνωστή μόνο σε εσάς'}]},
73 {tag:'li', children:[{tag:'span', html:'Το Clipperz φυλάσσει τα προσωπικά σας δεδομένα σε κωδικοποιημένη μορφή, και δεν μπορεί να έχει πρόσβαση σε αυτά στην αρχική τους μορφή'}]},
74 {tag:'li', children:[{tag:'span', html:'Το Clipperz χρησιμοποιεί επίσημες /πρότυπες μεθόδους κωδικοποίησης, και όχι αόριστα και εφάνταστα μοντέλα'}]},
75 {tag:'li', children:[{tag:'span', html:'Έχετε πρόσβαση στον πηγαίο κώδικα οποτεδήποτε το θελήσετε, και δεν χρειάζετε να γνωρίζετε τίποτα από κρυπτογράφηση για να είστε ένας ευχαριστημένος χρήστης!'}]}
76 ]}
77 ]},
78 {tag:'li', children:[
79 {tag:'a', href:"http://www.clipperz.com", target:'_blank', html:'Μάθετε περισσότερα'}
80 ]}
81 ]}
82 ],
83
84 // Login page - form
85 'loginFormTitle': "Συνδεθείτε με τον Clipperz λογαριασμό σας",
86 'loginFormUsernameLabel': "Όνομα χρήστη",
87 'loginFormPassphraseLabel': "Κωδική φράση",
88 'loginFormDontHaveAnAccountLabel': "Δεν έχετε δημιουργήσει λογαριασμό?",
89 'loginFormCreateOneLabel': "Δημιουργήστε έναν",
90 'loginFormForgotYourCredentialsLabel': "Ξεχάσατε τα διαπιστευτήριά σας?",
91 'loginFormAarghThatsBadLabel': "Ααααργκ! Αυτό είναι κακό!",
92 'loginFormAfraidOfMaliciousScriptsLabel':"φοβάστε κακόβουλα προγράμματα (scripts)?",
93 'loginFormVerifyTheCodeLabel': "Επαληθεύστε τον κωδικό",
94 'loginFormButtonLabel': "Σύνδεση",
95
96// Login page - language selection
97 'loginPanelSwithLanguageDescriptionConfig':[
98 {tag:'h5', html:"Αλλάξτε στην γλώσσα προτήμησης σας"}
99 ],
100
101// Login page - browser compatibility
102 'browserCompatibilityDescriptionConfig':[
103 {tag:'p', html:"Έχετε μία καλύτερη και πιό ασφαλή Clipperz εμπειρία χρησιμοποιόντας τον Firefox. Ωστόσο το Clipperz συνεργάζετε άψογα με Opera και MS Internet Explorer!"}
104 ],
105
106// Login message panel
107 'loginMessagePanelInitialTitle': "Γίνεται σύνδεση ...",
108 'loginMessagePanelInitialButtonLabel': "Ακύρωση",
109 'loginMessagePanelConnectedTitle': "Συνδεθήκατε",
110 'loginMessagePanelConnectedText': "Ολοκληρώθηκε",
111 'loginMessagePanelFailureTitle': "Λάθος",
112 'loginMessagePanelFailureText': "Η σύνδεση χρήστη απέτυχε",
113 'loginMessagePanelFailureButtonLabel': "Κλείσιμο",
114
115// Login message panel - connection
116 'connectionLoginSendingCredentialsMessageTitle': "Γίνεται επαλήθευση διαπιστευτηρίων",
117 'connectionLoginSendingCredentialsMessageText': "Αποστέλλονται διαπιστευτήρια",
118 'connectionLoginCredentialsVerificationMessageTitle':"Γίνεται επαλήθευση διαπιστευτηρίων",
119 'connectionLoginCredentialsVerificationMessageText':"Εκτέλεση πιστοποίησης SRP ",
120 'connectionLoginDoneMessageTitle': "Γίνεται επαλήθευση διαπιστευτηρίων",
121 'connectionLoginDoneMessageText': "Συνδεδεμένος",
122
123 //Login message panel - user
124 'userLoginPanelUpgradingUserCredentialsMessageTitle': "Γίνεται επαλήθευση διαπιστευτηρίων",
125 'userLoginPanelUpgradingUserCredentialsMessageText': "Αναβάθμηση των διαπιστευτηρίων σας σε ένα νέο σζήμα πιστοποίησης",
126 'userLoginPanelConnectedMessageTitle': "Χρήστης πιστοποιήθηκε ",
127 'userLoginPanelConnectedMessageText': "Συνδεθήκατε με επιτυχία",
128 'userLoginPanelTryingAnOlderConnectionSchemaMessageTitle': "Γίνεται επαλήθευση διαπιστευτηρίων",
129 'userLoginPanelTryingAnOlderConnectionSchemaMessageText': "Trying an older authentication schema",
130 'userLoginPanelLoadingUserDataMessageTitle': "Χρήστης πιστοποιήθηκε ",
131 'userLoginPanelLoadingUserDataMessageText': "Downloading encrypted card headers from Clipperz",
132 'userLoginPanelDecryptingUserDataMessageTitle': "Χρήστης πιστοποιήθηκε ",
133 'userLoginPanelDecryptingUserDataMessageText': "Local decryption of card headers",
134 'userLoginPanelDecryptingUserStatisticsMessageTitle': "Χρήστης πιστοποιήθηκε ",
135 'userLoginPanelDecryptingUserStatisticsMessageText': "Local decryption of usage statistics",
136
137 //-----------------------------------------------------
138 //Registration page - splash alert
139 'splashAlertTitle':"Καλώς ήλθατε στο Clipperz!",
140 'splashAlertTextConfig': [
141 {tag:'p', html:'Μερικές συμβουλές ασφαλείας'},
142 {tag:'ul', children:[
143 {tag:'li', children:[{tag:'span', html:'Η αποθήκευση των δεδομένων σας στο Clipperz είναι τόσο ασφαλής, όσο η κωδική φράση που επιλέγετε για να τα προστατεύσετε. Κανένας δεν θα έχει πρόσβαση σε αυτά, εκτός αν γνωρίζει την κωδική φράση σας.'}]},
144 {tag:'li', children:[{tag:'span', html:'Αν πρόκειται να χρησιμοποιήσετε το Clipperz για ασφαλή προστασία ευαίσθητων ή σημαντικών πληροφοριών, βεβαιωθείτε ότι θα χρησιμοποιήσετε μία “γερή” κωδική φράση. Όσο μεγαλύτερη, τόσο καλύτερη!'}]},
145 {tag:'li', children:[{tag:'span', html:'Το Clipperz δεν θα έχει τη δυνατότητα να ανακτήσει μία χαμένη κωδική φράση!'}]}
146 ]},
147 {tag:'p', html:'Για περισσότερες πληροφορίες, παρακαλώ ανατρέξτε στο <a href=\"http://www.clipperz.com\" target=\"_blank\">Clipperz</a>.'}
148 ],
149 'splashAlertCloseButtonLabel':"Εντάξει",
150
151 // Registration page - form
152 'registrationFormTitle': "Δημιουργήστε λογαριασμό",
153 'registrationFormUsernameLabel': "Όνομα χρήστη",
154 'registrationFormPassphraseLabel': "Κωδική φράση",
155 'registrationFormRetypePassphraseLabel': "Εισάγετε ξανά την κωδική φράση",
156 'registrationFormSafetyCheckLabel': "Κατανοώ πως το Clipperz δεν θα μπορεί να ανακτήσει μία χαμένη κωδική φράση.",
157 'registrationFormTermsOfServiceCheckLabel': "Έχω διαβάσει και αποδέχομαι τους Όρους Χρήσης <a href='http://www.clipperz.com/terms_of_service' target='_blank'>Όρους Χρήσης</a>.",
158 'registrationFormDoYouAlreadyHaveAnAccountLabel': "Έχετε ήδη έναν λογαριασμό?",
159 'registrationFormSimplyLoginLabel': "απλώς συνδεθείτε",
160 'registrationFormButtonLabel': "Εγγραφείτε",
161
162// Registration page - warning messages
163 'registrationFormWarningMessageNotMatchingPassphrases':"Οι κωδικές φράσεις που εισάγατε δεν ταιριάζουν. Παρακαλώ ξαναπροσπαθήστε.",
164 'registrationFormWarningMessageSafetyCheckNotSelected':"Παρακαλώ διαβάστε και επιλέξτε όλες τις παρακάτω επιλογές.",
165 'registrationFormWarningMessageTermsOfServiceCheckNotSelected':"Πρέπει να αποδεχθείτε τους Όρους Χρήσης.",
166
167 // Registration message panel
168 'registrationMessagePanelInitialTitle': "Δημιουργία λογαριασμού ...",
169 'registrationMessagePanelInitialButtonLabel': "Ακύρωση",
170 'registrationMessagePanelRegistrationDoneTitle': "Εγγραφή",
171 'registrationMessagePanelRegistrationDoneText': "Ολοκληρώθηκε",
172 'registrationMessagePanelFailureTitle': "Η εγγραφή απέτυχε",
173 'registrationMessagePanelFailureButtonLabel': "Κλείσιμο",
174
175// Registration - connection
176 'connectionRegistrationSendingRequestMessageText': "Γίνεται επαλήθευση διαπιστευτηρίων",
177 'connectionRegistrationSendingCredentialsMessageText':"Αποστέλλονται διαπιστευτήρια",
178
179 //-----------------------------------------------------
180// Registration splash panel
181 'registrationSplashPanelTitle':"Συμβουλές Ασφαλείας",
182 'registrationSplashPanelDescriptionConfig': [
183 {tag:'p', html:'Αυτά είναι τα διαπιστευτήριά σας στο Clipperz, δείτε τα προσεκτικά. Το Clipperz δεν θα απεικονίσει το όνομα χρήστη και την κωδική σας φράση δεύτερη φορά!'}
184 ],
185 'registrationSplashPanelUsernameLabel': "όνομα χρήστη",
186 'registrationSplashPanelPassphraseLabel':"κωδική φράση",
187
188 //-----------------------------------------------------
189 //Header links
190 'donateHeaderLinkLabel':"donate",
191 'creditsHeaderLinkLabel':"credits",
192 'feedbackHeaderLinkLabel':"feedback",
193 'helpHeaderLinkLabel': "Βοήθεια",
194 'forumHeaderLinkLabel': "forum",
195
196 //-----------------------------------------------------
197 //Menu labels
198 'recordMenuLabel': "cards",
199 'accountMenuLabel': "Λογαριασμός",
200 'dataMenuLabel': "Δεδομένα",
201 'contactsMenuLabel':"Επαφές",
202 'bookmarkletMenuLabel':"bookmarklet",
203 'logoutMenuLabel': "Αποσύνδεση",
204 'lockMenuLabel': "lock",
205
206//-----------------------------------------------------
207 //Lock dialog
208 'lockTitle': "The account is locked",
209 'lockDescriptionConfig':[
210 {tag:'p', html:'To unlock your account, please insert your passphrase'}
211 ],
212 'unlockButtonLabel': "Unlock",
213
214//-----------------------------------------------------
215 //Account panel - change passphrase
216 'changePasswordTabLabel':"Αλλάξτε την κωδική φράση σας",
217 'changePasswordTabTitle':"Αλλάξτε την κωδική φράση σας",
218
219 //Account panel - change passphrase - form
220 'changePasswordFormUsernameLabel': "όνομα χρήστη",
221 'changePasswordFormOldPassphraseLabel': "παλαιά κωδική φράση",
222 'changePasswordFormNewPassphraseLabel': "νέα κωδική φράση",
223 'changePasswordFormRetypePassphraseLabel':"Εισάγετε ξανά τη νέα κωδική φράση",
224 'changePasswordFormSafetyCheckboxLabel':"Κατανοώ πως το Clipperz δεν θα μπορεί να ανακτήσει μία χαμένη κωδική φράση.",
225 'changePasswordFormSubmitLabel': "Αλλάξτε την κωδική φράση σας",
226
227 //Account panel - change passphrase - warnings
228 'changePasswordFormWrongUsernameWarning': "Λάθος όνομα χρήστη",
229 'changePasswordFormWrongPassphraseWarning': "Λάθος κωδική φράση",
230 'changePasswordFormWrongRetypePassphraseWarning':"Οι κωδικές φράσεις που εισάγατε δεν ταιριάζουν. Παρακαλώ ξαναπροσπαθήστε.",
231 'changePasswordFormSafetyCheckWarning': "Παρακαλώ διαβάστε και επιλέξτε όλες τις παρακάτω επιλογές.",
232
233 //Account panel - change passphrase - progress dialog
234 'changePasswordFormProgressDialogTitle': "Γίνεται αλλαγή διαπιστευτηρίων χρήστη",
235 'changePasswordFormProgressDialogConnectedMessageTitle': "Συνδεδεμένος",
236 'changePasswordFormProgressDialogConnectedMessageText': "Ολοκληρώθηκε",
237 'changePasswordFormProgressDialogErrorMessageTitle': "Σφάλμα",
238 'changePasswordFormProgressDialogErrorMessageText': "Απέτυχε η αλλαγή διαπιστευτηρίων!",
239
240 'changeCredentialsPanelEncryptingDataMessageTitle': "Γίνεται αλλαγή της κωδικής φράσης σας",
241 'changeCredentialsPanelEncryptingDataMessageText': "Local encryption of card headers",
242 'changeCredentialsPanelCreatingNewCredentialsMessageTitle': "Γίνεται αλλαγή της κωδικής φράσης σας",
243 'changeCredentialsPanelCreatingNewCredentialsMessageText': "Γίνεται ανανέωση των διαπιστευτηρίων σας",
244 'changeCredentialsPanelSendingNewCredentialsToTheServerMessageTitle':"Γίνεται αλλαγή της κωδικής φράσης σας",
245 'changeCredentialsPanelSendingNewCredentialsToTheServerMessageText':"Uploading your encrypted credentials to Clipperz",
246 'changeCredentialsPanelDoneMessageTitle': "Γίνεται αλλαγή της κωδικής φράσης σας",
247 'changeCredentialsPanelDoneMessageText': "Ολοκληρώθηκε",
248
249//-----------------------------------------------------
250 //Account panel - manage OTP
251 'manageOTPTabLabel': "Manage your one-time passphrases",
252 'manageOTPTabTitle': "Manage your one-time passphrases",
253
254 // Account panel - manage OTP - description
255 'manageOTPTabDescriptionConfig':[
256 {tag:'p', html:"A one-time passphrase works like your regular passphrase, but can be used only once."},
257 {tag:'p', html:"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."},
258 {tag:'p', html:"Immediately after a successful login, your one-time passphrase will be deleted preventing any fraudulent access."},
259 {tag:'p', html:"One-time passwords are an excellent choice if one is concerned about keyloggers or spyware infections that may be collecting data from compromised machines."},
260 {tag:'p', html:"<b>It's strongly advisable to use one-time passphrases when accessing Clipperz from public terminals, such as Internet cafes and libraries.</b>"},
261 {tag:'p', html:""},
262 {tag:'p', html:"<b>Coming soon ...</b>"}
263 ],
264
265//-----------------------------------------------------
266// Account panel - user preferences
267 'accountPreferencesLabel': "Προτιμήσεις",
268 'accountPreferencesTabTitle': "Προτιμήσεις",
269
270// Account panel - user preferences - description
271 'accountPreferencesLanguageTitle':"Επιλογή Γλώσσας",
272 'accountPreferencesLanguageDescriptionConfig': [
273 {tag:'p', html:"Choose your preferred language from the list below."}
274 ],
275
276 'accountPreferencesInterfaceTitle':"Interface customization",
277 'accountPreferencesInterfaceDescriptionConfig': [
278 {tag:'p', html:"Tune the Clipperz interface to your needs."}
279 ],
280
281// Account panel - user preferences - form
282 'saveUserPreferencesFormSubmitLabel': "Αποθήκευση",
283 'cancelUserPreferencesFormSubmitLabel': "Ακύρωση",
284
285// Account panel - user preferences - panel
286 'accountPreferencesSavingPanelTitle_Step1': "Saving preferences",
287 'accountPreferencesSavingPanelText_Step1': "Local encryption of your preferences",
288 'accountPreferencesSavingPanelTitle_Step2': "Saving preferences",
289 'accountPreferencesSavingPanelText_Step2': "Sending encrypted preferences to Clipperz",
290
291//-----------------------------------------------------
292 //Account panel - delete account
293 'deleteAccountTabLabel': "Διαγράψτε τον λογαριασμό σας",
294 'deleteAccountTabTitle':"Γίνεται διαγραφή του λογαριασμού σας",
295
296 //Account panel - delete account - form
297 'deleteAccountFormUsernameLabel': "όνομα χρήστη",
298 'deleteAccountFormPassphraseLabel': "κωδική φράση",
299 'deleteAccountFormSafetyCheckboxLabel':"Κατανοώ πως όλα τα δεδομένα μου θα διαγραφούν και πως αυτή η πράξη είναι μη αναστρέψιμη.",
300 'deleteAccountFormSubmitLabel': "Διαγράψτε τον λογαριασμό μου",
301
302 //Account panel - delete account - warnings
303 'deleteAccountFormWrongUsernameWarning':"λάθος όνομα χρήστη",
304 'deleteAccountFormWrongPassphraseWarning':"λάθος κωδική φράση",
305 'deleteAccountFormSafetyCheckWarning': "Παρακαλώ διαβάστε και επιλέξτε την παρακάτω επιλογή.",
306
307 //Account panel - delete account - confirmation
308 'accountPanelDeletingAccountPanelConfirmationTitle':"ΠΡΟΣΟΧΗ",
309 'accountPanelDeleteAccountPanelConfirmationText': "Είστε σίγουρος/η ότι θέλετε να διαγράψετε αυτόν τον λογαριασμό?",
310 'accountPanelDeleteAccountPanelConfirmButtonLabel': "Ναι",
311 'accountPanelDeleteAccountPanelDenyButtonLabel': "Όχι",
312
313//-----------------------------------------------------
314 //Data panel - offline copy
315 'offlineCopyTabLabel':"Offline copy",
316 'offlineCopyTabTitle':"Offline copy",
317
318 // Data panel - offline copy - description
319 'offlineCopyTabDescriptionConfig': [
320 {tag:'p', html:"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."},
321 {tag:'p', html:"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."},
322 {tag:'ol', children:[
323 {tag:'li', children:[{tag:'span', html:"Click the link below to download the offline copy."}]},
324 {tag:'li', children:[{tag:'span', html:"The browser will ask you what to do with the “Clipperz_YYYYMMDD.zip” file. Save it on your hard disk."}]},
325 {tag:'li', children:[{tag:'span', html:"Unzip the file to reveal the “Clipperz_YYYYMMDD” folder."}]},
326 {tag:'li', children:[{tag:'span', html:"Open the “Clipperz_YYYYMMDD” folder and double click on the “index.html” file."}]},
327 {tag:'li', children:[{tag:'span', html:"Enter the usual username and passphrase and access your private data without an Internet connection."}]}
328 ]}
329 ],
330 'offlineCopyDownloadLinkLabel':"Download",
331
332//-----------------------------------------------------
333 //Data panel - sharing
334 'sharingTabLabel':"Sharing",
335 'sharingTabTitle':"Sharing",
336
337 //Data panel - sharing - description
338 'sharingTabDescriptionConfig':[
339 {tag:'p', html:"Quite often a confidential piece of information needs to be shared with one or more persons."},
340 {tag:'p', html:"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."},
341 {tag:'p', html:"Clipperz can make sharing your secrets a secure and straightforward process."},
342 {tag:'p', html:""},
343 {tag:'p', html:"<b>Coming soon ...</b>"}
344 ],
345
346//-----------------------------------------------------
347 // Data panel - import
348 'importTabLabel':"Εισαγωγή",
349 'importTabTitle':"Εισαγωγή",
350
351 // Data panel - import - description
352 'importTabDescriptionConfig':[
353 {tag:'p', html:"<b>Σύντομα κοντά σας ...</b>"}
354 ],
355
356//-----------------------------------------------------
357 //Data panel - export
358 'printingTabLabel':"Εξαγωγή",
359 'printingTabTitle':"Εξαγωγή",
360
361 //Data panel - export - description “”
362 'printingTabDescriptionConfig':[
363 {tag:'p', html:"<b>Print your data</b>"},
364 {tag:'p', html:"Clicking on the link below will open a new window displaying all your cards in a printable format."},
365 {tag:'p', html:"If you are going to print for backup purposes, please consider the more safe option provided by the creating an “offline copy”."}
366 ],
367 'printingLinkLabel':"Έκδοση Εκτύπωσης",
368
369//-------------------------------------------------------------------
370 //Contacts panel
371 'contactsTabLabel':"Contacts",
372 'contactsTabTitle':"Contacts",
373
374//-------------------------------------------------------------------
375 //Bookmarklet panel
376 'bookmarkletTabLabel': "Bookmarklet",
377 'bookmarkletTabTitle': "Bookmarklet",
378
379 //Bookmarklet panel - description
380 'bookmarkletTabDescriptionConfig':[
381 {tag:'p', html:"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."},
382 {tag:'p', html:"The Clipperz bookmarklet will help you to quickly create new cards and new “direct logins” within existing cards."},
383 {tag:'p', html:"<b>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.</b>"},
384 {tag:'div', children:[
385 {tag:'p', html:"To install the bookmarklet <b>drag</b> the link below to the bookmark bar of your browser."}
386 ]}
387 ],
388 'bookmarkletTabBookmarkletTitle':"Προσθήκη στο Clipperz",
389
390 //Bookmarklet panel - instructions
391 'bookmarkletTabInstructionsConfig':[
392 {tag:'h3', html:"How to create a new card inclusive of a “direct login” link to an online service"},
393 {tag:'ol', children:[
394 {tag:'li', children:[{tag:'span', html:"Open the web page where the login form is hosted. (this is the page where you usually enter your sign-in credentials)"}]},
395 {tag:'li', children:[{tag:'span', html:"Launch the bookmarklet by clicking on it: a pop-up window will appear over the web page."}]},
396 {tag:'li', children:[{tag:'span', html:"Copy to the clipboard the content of the large text area within the pop-up. (ctrl-C)"}]},
397 {tag:'li', children:[{tag:'span', html:"Enter your Clipperz account and click on the <b>Add new card</b> button."}]},
398 {tag:'li', children:[{tag:'span', html:"Select the “Direct login” template and paste the content of the clipboard to the large text area in the form. (ctrl-V)"}]},
399 {tag:'li', children:[{tag:'span', html:"Press the <b>Create</b> button, complete and review the details, then click <b>Save</b>."}]}
400 ]},
401 {tag:'h3', html:"How to add a “direct login” link to an existing card"},
402 {tag:'ol', children:[
403 {tag:'li', children:[{tag:'span', html:"Same as above."}]},
404 {tag:'li', children:[{tag:'span', html:"Same as above."}]},
405 {tag:'li', children:[{tag:'span', html:"Same as above."}]},
406 {tag:'li', children:[{tag:'span', html:"Enter your Clipperz account and select the card containing the credentials for the web service you just visited and click the <b>Edit</b> button."}]},
407 {tag:'li', children:[{tag:'span', html:"Paste the content of the clipboard to the large text area in the “Direct logins” section. (ctrl-V)"}]},
408 {tag:'li', children:[{tag:'span', html:"Press the <b>Add direct login</b> button, review the details and then click <b>Save</b>."}]}
409 ]},
410 {tag:'p', html:""},
411 {tag:'p', html:"Further information about the bookmarklet are <a href=\"http://www.clipperz.com/support/user_guide/bookmarklet\" target=\"_blank\">available here</a>."}
412 ],
413
414//-------------------------------------------------------------------
415// Direct logins block
416 'mainPanelDirectLoginBlockLabel': "Απευθείας σύνδεση",
417 'directLinkReferenceShowButtonLabel':"Επίδειξη",
418
419 // Direct logins - blank slate“”
420 'mainPanelDirectLoginBlockDescriptionConfig': [
421 {tag:'p', html:"Add “direct logins” to sign in to your web accounts without typing usernames and passwords!"},
422 {tag:'p', html:"“Direct logins” greatly enhance your password security since you can:"},
423 {tag:'ul', children:[
424 {tag:'li', children:[{tag:'span', html:"conveniently adopt and enter complex passwords;"}]},
425 {tag:'li', children:[{tag:'span', html:"never re-use the same and easy-to-guess password."}]}
426 ]},
427 {tag:'p', html:"Simple and quick configuration with the Clipperz <b>bookmarklet</b>."},
428 {tag:'a', href:"http://www.clipperz.com/support/user_guide/direct_logins", target:'_blank', html:'Learn more about “direct logins”'}
429 ],
430
431//-------------------------------------------------------------------
432 // Cards block
433 'mainPanelRecordsBlockLabel': "Κάρτες",
434 'mainPanelAddRecordButtonLabel': "Προσθήκη νέας Κάρτας ",
435 'mainPanelRemoveRecordButtonLabel': "Διαγραφή κάρτας",
436
437// Cards block - filter tabs
438 'mainPanelRecordFilterBlockAllLabel': "Όλα",
439 'mainPanelRecordFilterBlockTagsLabel': "Επιλογές",
440 'mainPanelRecordFilterBlockSearchLabel':"Αναζήτηση",
441
442// Cards block - blank slate
443 'recordDetailNoRecordAtAllTitle': "Welcome to Clipperz!",
444 'recordDetailNoRecordAtAllDescriptionConfig':[
445 {tag:'h5', html:'Get started by adding cards to your account.'},
446 {tag:'p', html:'Cards are simple and flexible forms where you can store your passwords and any other confidential data.'},
447 {tag:'p', html:'Cards could contain credentials for accessing a web site, the combination of your bicycle lock, details of your credit card, ...'},
448 {tag:'h5', html:'Don\'t forget the bookmarklet!'},
449 {tag:'p', html:'Before you start, install the “Add to Clipperz” bookmarklet: it will make creating cards easier and more fun.'},
450 {tag:'p', html:'Go to the bookmarklet tab to discover how to install it and how it use it.'},
451 {tag:'p', html:''},
452 {tag:'p', html:'Then simply click the <b>"Add new card"</b> button and enjoy your Clipperz account.'},
453 {tag:'p', html:''},
454 {tag:'a', href:"http://www.clipperz.com/support/user_guide/managing_cards", target:'_blank', html:'Learn more about creating and managing cards'}
455 ],
456
457// Cards block - new card wizard - bookmarklet configuration
458 'newRecordWizardTitleBoxConfig': [
459 {tag:'h5', html:"Please select a template"},
460 {tag:'p', html:'Cards are simple and flexible forms where you can store passwords or any other confidential data.'},
461 {tag:'p', html:'Start choosing one of the template below. You can always customize your cards later by adding or removing fields.'}
462 ],
463
464 'newRecordWizardBookmarkletConfigurationTitle': "Απευθείας σύνδεση",
465 'newRecordWizardBookmarkletConfigurationDescriptionConfig': [
466 {tag:'p', html:"Paste below the configuration code generated by the Clipperz bookmarklet."},
467 {tag:'p', html:"A new card complete with a direct login to your web account will be created."}
468 ],
469
470 'newRecordWizardCreateButtonLabel':"Δημιουργία",
471 'newRecordWizardCancelButtonLabel':"Ακύρωση",
472
473//-------------------------------------------------------------------
474// Card templates
475//-------------------------------------------------------------------
476
477 'recordTemplates': {
478
479 //Web password
480 'WebAccount': {
481 'title': "Web password",
482 'description': [
483 {tag:'p', html:"A simple card to store login credentials for your online services."}
484 ],
485 'fields': [
486 {label:"Διεύθυνση δικτύου", type:'URL'},
487 {label:"Χρήστης ή διεύθυνση ηλεκτρονικού ταχυδρομείου", type:'TXT'},
488 {label:"Κωδικός Πράσβασης", type:'PWD'}
489 ]
490 },
491
492 // Bank account
493 'BankAccount': {
494 'title': "Bank account",
495 'description': [
496 {tag:'p', html:"Safely store your bank account number and online banking credentials."}
497 ],
498 'fields': [
499 {label:"Τράπεζα", type:'TXT'},
500 {label:"Αριθμός λογαριασμού", type:'TXT'},
501 {label:"Ιστοσελίδα τράπεζας", type:'URL'},
502 {label:"Αρ. Ηλεκτρονικής τράπεζας (ID)", type:'TXT'},
503 {label:"Κώδικος Ηλεκτρονικής τράπεζας", type:'PWD'}
504 ]
505 },
506
507 // Credit card
508 'CreditCard': {
509 'title': "Credit card",
510 'description': [
511 {tag:'p', html:"Card number, expire date, CVV2 and PIN always at hand with Clipperz."}
512 ],
513 'fields': [
514 {label:"Τύπος Κάρτας (Visa, AmEx,...)", type:'TXT'},
515 {label:"Αριθμός κάρτα", type:'TXT'},
516 {label:"Ονοματεπώνυμο κατόχου", type:'TXT'},
517 {label:"Ημερομηνία λήξης", type:'TXT'},
518 {label:"CVV2", type:'TXT'},
519 {label:"Κωδικός Αυτόματης ταμείακης μηχανης (ΑΤΜ)", type:'PWD'},
520 {label:"Ιστοσελίδα κάρτας", type:'URL'},
521 {label:"Χρήστης", type:'TXT'},
522 {label:"Κωδικός Πρόσβασης", type:'PWD'}
523 ]
524 },
525
526 // Address book entry
527 'AddressBookEntry': {
528 'title': "Address book entry",
529 'description': [
530 {tag:'p', html:"Clipperz could also work as your new private address book. Use this template to easily add a new entry."}
531 ],
532 'fields': [
533 {label:"Όνομα", type:'TXT'},
534 {label:"Ηλετρονικό ταχυδρομείο", type:'TXT'},
535 {label:"Τηλέφωνο", type:'TXT'},
536 {label:"Κινητο τηλέφωνο", type:'TXT'},
537 {label:"Διεύθυνση", type:'ADDR'},
538 ]
539 },
540
541 //Custom card
542 'Custom': {
543 'title': "Custom card",
544 'description': [
545 {tag:'p', html:"No matter which kind of confidential data you need to protect, create a custom card to match your needs."}
546 ],
547 'fields': [
548 {label:"Περιγραφή 1", type:'TXT'},
549 {label:"Περιγραφή 2", type:'TXT'},
550 {label:"Περιγραφή 3", type:'TXT'}
551 ]
552 }
553 },
554
555
556 'recordFieldTypologies': {
557 'TXT': {
558 description: 'simple text field',
559 shortDescription: '΄Κείμενο'
560 },
561 'PWD': {
562 description: 'simple text field, with default status set to hidden',
563 shortDescription: 'Κωδικός Πρόσβασης'
564 },
565 'URL': {
566 description: 'simple text field in edit mode, that became an active url in view mode',
567 shortDescription: 'Διεύθυνση ηλεκτρονικού ταχυδρομείου'
568 },
569 'DATE': {
570 description: 'a value set with a calendar helper',
571 shortDescription: 'Ημερομηνία'
572 },
573 'ADDR': {
574 description: 'just like the URL, but the active link points to Google Maps (or similar service) passing the address value as argument',
575 shortDescription: 'Διεύθυνση'
576 },
577 'CHECK': {
578 description: 'check description',
579 shortDescription: 'check'
580 },
581 'RADIO': {
582 description: 'radio description',
583 shortDescription: 'radio'
584 },
585 'SELECT': {
586 description: 'select description',
587 shortDescription: 'select'
588 }
589 },
590
591// Cards block - new card - warnings
592 'newRecordPanelGeneralExceptionTitle': "Σφάλμα",
593 'newRecordPanelGeneralExceptionMessage': "The configuration text is not valid. Make sure to get your text from the bookmarklet pop-up and retry.",
594 'newRecordPanelWrongBookmarkletVersionExceptionTitle': "Σφάλμα",
595 'newRecordPanelWrongBookmarkletVersionExceptionMessage':"The configuration text has been generated by an old version of the bookmarklet. Please update your bookmarklet and retry.",
596 'newRecordPanelExceptionPanelCloseButtonLabel': "Ακύρωση",
597
598// Cards block - delete card
599 'mainPanelDeletingRecordPanelConfirmationTitle':"Διαγραφή επιλεγμένης κάρτας",
600 'mainPanelDeleteRecordPanelConfirmationText': "Είστε σίγουρος ότι θέλετε να διαγράψετε την επιλεγμένη κάρτα?",
601 'mainPanelDeleteRecordPanelConfirmButtonLabel': "Ναι",
602 'mainPanelDeleteRecordPanelDenyButtonLabel': "Όχι",
603 'mainPanelDeletingRecordPanelInitialTitle': "Διαγραφή επιλεγμένης κάρτας ",
604 'mainPanelDeletingRecordPanelCompletedText': "Ολοκλήρωση",
605
606// Cards block - delete card panel
607 'deleteRecordPanelCollectRecordDataMessageTitle': "Διαγραφή κάρτας",
608 'deleteRecordPanelCollectRecordDataMessageText': "Φόρτωση λίστα κάρτας",
609 'deleteRecordPanelEncryptUserDataMessageTitle': "Διαγραφή κάρτας",
610 'deleteRecordPanelEncryptUserDataMessageText': "Local encryption of card headers",
611 'deleteRecordPanelSendingDataToTheServerMessageTitle': "Διαγραφή κάρτας",
612 'deleteRecordPanelSendingDataToTheServerMessageText': "Uploading encrypted card headers to Clipperz",
613 'deleteRecordPanelUpdatingTheInterfaceMessageTitle': "Διαγραφή κάρτας",
614 'deleteRecordPanelUpdatingTheInterfaceMessageText': "Φόρτωση επιφάνειας",
615
616// Cards block - no record selected
617 'recordDetailNoRecordSelectedTitle': "Δεν έχει επιλεγεί κάποια κάρτα",
618 'recordDetailNoRecordSelectedDescriptionConfig':[
619 {tag:'p', html:'Παρακαλώ επιλέξτε μια κάρτα από αυτές που βρίσκονται στα αριστερά σας'}
620 ],
621
622 // Cards block - loading messages
623 'recordDetailLoadingRecordMessage': "Downloading encrypted card from Clipperz",
624 'recordDetailDecryptingRecordMessage': "Τοπικη αποκωδικοποίηση αρχείων κάρτας",
625 'recordDetailLoadingRecordVersionMessage': "Φόρτωση τελευταίας έκδοσης κάρτας",
626 'recordDetailDecryptingRecordVersionMessage':"Τοπική αποκωδικοποίηση της τελευταίας έκδοσης",
627 'recordDetailLoadingErrorMessageTitle': "Σφάλμα στη φόρτωση της κάρτας",
628
629// Cards block - card details
630 'recordDetailNotesLabel': "Σημειώσης",
631 'recordDetailLabelFieldColumnLabel': "Περιγραφή πεδίου",
632 'recordDetailDataFieldColumnLabel': "Στοιχεία πεδίου",
633 'recordDetailTypeFieldColumnLabel': "Τύπος",
634
635 'recordDetailSavingChangesMessagePanelInitialTitle':"Αποθήκευση κάρτας",
636
637 'recordDetailAddFieldButtonLabel': "Προσθέστε νέο πεδίο",
638 'recordDetailPasswordFieldHelpLabel': "Για αντιγραφή του κωδικού στο clipboard επιλέξτε τα αστεράκια και μετα Ctrl-C",
639
640 'recordDetailDirectLoginBlockTitle': "Κωδικός Πρόσβασης",
641 'recordDetailNewDirectLoginDescriptionConfig': [
642 {tag:'p', html:'Επικύρωση κωδικου πρόσβασης'}
643 ],
644
645 'recordDetailDirectLoginBlockNoDirectLoginConfiguredDescriptionConfig':[
646 {tag:'p', html:"Does this card contain credentials to access an online service?"},
647 {tag:'p', html:"Use the bookmarklet to configure a “direct login” from Clipperz with just one click!"}
648 ],
649 'recordDetailAddNewDirectLoginButtonLabel': "Προσθέστε νέο κωδικό πρόσβασης",
650
651 'recordDetailEditButtonLabel': "Edit",
652 'recordDetailSaveButtonLabel': "Αποθήκευση",
653 'recordDetailCancelButtonLabel':"Ακύρωση",
654
655 'newRecordTitleLabel': "_Νέα κάρτα_",
656
657// Cards block - save card panel
658 'recordSaveChangesPanelCollectRecordInfoMessageTitle': "Αποθήκευση κάρτας",
659 'recordSaveChangesPanelCollectRecordInfoMessageText': "Updating card headers",
660 'recordSaveChangesPanelEncryptUserDataMessageTitle': "Αποθήκευση κάρτας",
661 'recordSaveChangesPanelEncryptUserDataMessageText': "Local encryption of card headers",
662 'recordSaveChangesPanelEncryptRecordDataMessageTitle': "Αποθήκευση κάρτας",
663 'recordSaveChangesPanelEncryptRecordDataMessageText': "Local encryption of card's data",
664 'recordSaveChangesPanelEncryptRecordVersionDataMessageTitle':"Αποθήκευση κάρτας",
665 'recordSaveChangesPanelEncryptRecordVersionDataMessageText':"Local encryption of card's version data",
666 'recordSaveChangesPanelSendingDataToTheServerMessageTitle': "Αποθήκευση κάρτας",
667 'recordSaveChangesPanelSendingDataToTheServerMessageText': "Uploading encrypted card's header to Clipperz",
668 'recordSaveChangesPanelUpdatingTheInterfaceMessageTitle': "Αποθήκευση κάρτας",
669 'recordSaveChangesPanelUpdatingTheInterfaceMessageText': "Φόρτωση επιφάνειας",
670
671 // Exit page
672 'exitConfig': [
673 {tag:'h2', html:'<b>Goodbye! Thanks for using Clipperz.</b>'},
674
675 {tag:'ul', children:[
676 {tag:'li', children:[
677 {tag:'h3', html:'Remember:'},
678 {tag:'ul', children:[
679 {tag:'li', children:[{tag:'span', html:'Bookmark this page to safely connect to Clipperz in the future (if you haven\'t already done it)'}]},
680 {tag:'li', children:[{tag:'span', html:'Clipperz will never send you an email, because we never asked your email address (and we never will), so never open an email that says it\'s from Clipperz'}]}
681 ]}
682 ]}
683 ]},
684 {tag:'p', html:""},
685 {tag:'p', html:"In 10 seconds you will be redirected to a Wikipedia page where you can read about a major security issue ..."}
686 ],
687
688//-------------------------------------------------------------------
689 // Miscellaneous strings
690 //-------------------------------------------------------------------
691
692 // 'DWRUtilLoadingMessage': "Φόρτωση δεδομένων ...",
693 'comingSoon': "Σύντομα κοντά σας ...",
694 'panelCollectingEntryopyMessageText': "Collecting entropy",
695 'directLoginConfigurationCheckBoxFieldSelectedValue': "Ναι",
696 'directLoginConfigurationCheckBoxFieldNotSelectedValue':"Όχι",
697
698 //-------------------------------------------------------------------------
699 __syntaxFix__: "syntax fix"
700});
701
diff --git a/frontend/beta/js/Clipperz/PM/Strings/Strings_en-CA.js b/frontend/beta/js/Clipperz/PM/Strings/Strings_en-CA.js
new file mode 100644
index 0000000..50fa7e5
--- a/dev/null
+++ b/frontend/beta/js/Clipperz/PM/Strings/Strings_en-CA.js
@@ -0,0 +1,43 @@
1/*
2
3Copyright 2008-2011 Clipperz Srl
4
5This file is part of Clipperz's Javascript Crypto Library.
6Javascript Crypto Library provides web developers with an extensive
7and efficient set of cryptographic functions. The library aims to
8obtain maximum execution speed while preserving modularity and
9reusability.
10For further information about its features and functionalities please
11refer to http://www.clipperz.com
12
13* Javascript Crypto Library is free software: you can redistribute
14 it and/or modify it under the terms of the GNU Affero General Public
15 License as published by the Free Software Foundation, either version
16 3 of the License, or (at your option) any later version.
17
18* Javascript Crypto Library is distributed in the hope that it will
19 be useful, but WITHOUT ANY WARRANTY; without even the implied
20 warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
21 See the GNU Affero General Public License for more details.
22
23* You should have received a copy of the GNU Affero General Public
24 License along with Javascript Crypto Library. If not, see
25 <http://www.gnu.org/licenses/>.
26
27*/
28
29//=============================================================================
30//
31 // E N G L I S H C A N A D I A N ( en_CA )
32//
33//=============================================================================
34
35Clipperz.PM.Strings.Languages['en-ca'] = MochiKit.Base.merge(Clipperz.PM.Strings.Languages['en-us'], {
36
37 // 'forumHeaderLinkLabel': "forum-CA",
38
39 // 'recordMenuLabel': "cards-CA",
40
41 //-------------------------------------------------------------------------
42 __syntaxFix__: "syntax fix"
43}); \ No newline at end of file
diff --git a/frontend/beta/js/Clipperz/PM/Strings/Strings_en-GB.js b/frontend/beta/js/Clipperz/PM/Strings/Strings_en-GB.js
new file mode 100644
index 0000000..ea55650
--- a/dev/null
+++ b/frontend/beta/js/Clipperz/PM/Strings/Strings_en-GB.js
@@ -0,0 +1,43 @@
1/*
2
3Copyright 2008-2011 Clipperz Srl
4
5This file is part of Clipperz's Javascript Crypto Library.
6Javascript Crypto Library provides web developers with an extensive
7and efficient set of cryptographic functions. The library aims to
8obtain maximum execution speed while preserving modularity and
9reusability.
10For further information about its features and functionalities please
11refer to http://www.clipperz.com
12
13* Javascript Crypto Library is free software: you can redistribute
14 it and/or modify it under the terms of the GNU Affero General Public
15 License as published by the Free Software Foundation, either version
16 3 of the License, or (at your option) any later version.
17
18* Javascript Crypto Library is distributed in the hope that it will
19 be useful, but WITHOUT ANY WARRANTY; without even the implied
20 warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
21 See the GNU Affero General Public License for more details.
22
23* You should have received a copy of the GNU Affero General Public
24 License along with Javascript Crypto Library. If not, see
25 <http://www.gnu.org/licenses/>.
26
27*/
28
29//=============================================================================
30//
31 // E N G L I S H B R I T I S H ( en_GB )
32//
33//=============================================================================
34
35Clipperz.PM.Strings.Languages['en-gb'] = MochiKit.Base.merge(Clipperz.PM.Strings.Languages['en-us'], {
36
37 // 'forumHeaderLinkLabel': "forum-GB",
38
39 // 'recordMenuLabel': "cards-GB",
40
41 //-------------------------------------------------------------------------
42 __syntaxFix__: "syntax fix"
43}); \ No newline at end of file
diff --git a/frontend/beta/js/Clipperz/PM/Strings/Strings_en-US.js b/frontend/beta/js/Clipperz/PM/Strings/Strings_en-US.js
new file mode 100644
index 0000000..c0dd6d0
--- a/dev/null
+++ b/frontend/beta/js/Clipperz/PM/Strings/Strings_en-US.js
@@ -0,0 +1,1259 @@
1/*
2
3Copyright 2008-2011 Clipperz Srl
4
5This file is part of Clipperz's Javascript Crypto Library.
6Javascript Crypto Library provides web developers with an extensive
7and efficient set of cryptographic functions. The library aims to
8obtain maximum execution speed while preserving modularity and
9reusability.
10For further information about its features and functionalities please
11refer to http://www.clipperz.com
12
13* Javascript Crypto Library is free software: you can redistribute
14 it and/or modify it under the terms of the GNU Affero General Public
15 License as published by the Free Software Foundation, either version
16 3 of the License, or (at your option) any later version.
17
18* Javascript Crypto Library is distributed in the hope that it will
19 be useful, but WITHOUT ANY WARRANTY; without even the implied
20 warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
21 See the GNU Affero General Public License for more details.
22
23* You should have received a copy of the GNU Affero General Public
24 License along with Javascript Crypto Library. If not, see
25 <http://www.gnu.org/licenses/>.
26
27*/
28
29if (typeof(Clipperz) == 'undefined') { Clipperz = {}; }
30if (typeof(Clipperz.PM) == 'undefined') { Clipperz.PM = {}; }
31if (typeof(Clipperz.PM.Strings) == 'undefined') { Clipperz.PM.Strings = {}; }
32if (typeof(Clipperz.PM.Strings.Languages) == 'undefined') { Clipperz.PM.Strings.Languages = {}; }
33
34//=============================================================================
35//
36 // E N G L I S H A M E R I C A N ( en_US )
37//
38//=============================================================================
39
40Clipperz.PM.Strings.Languages['en-us'] = {
41
42 //Login page - description
43'clipperzServiceDescription': "\
44 <!-- FIX CSS DONE -->\
45 <h2>Keep it to yourself!</h2>\
46 <ul>\
47 <li>\
48 <h3>Clipperz is:</h3>\
49 <ul>\
50 <li><p>a secure and simple password manager</p></li>\
51 <li><p>an effective single sign-on solution</p></li>\
52 <li><p>a digital vault for your personal data</p></li>\
53 </ul>\
54 </li>\
55 <li>\
56 <h3>With Clipperz you can:</h3>\
57 <ul>\
58 <li><p>store and manage your passwords and online credentials</p></li>\
59 <li><p>login to your web services without entering any username or password</p></li>\
60 <li><p>protect all your sensitive data: codes for burglar alarms, PINs, credit card numbers, …</p></li>\
61 <li><p>share secrets with family members and associates (coming soon)</p></li>\
62 </ul>\
63 </li>\
64 <li>\
65 <h3>Clipperz benefits:</h3>\
66 <ul>\
67 <li><p>free and completely anonymous</p></li>\
68 <li><p>access it any time from any computer</p></li>\
69 <li><p>no software to download and nothing to install</p></li>\
70 <li><p>avoid keeping secrets on your PC or on paper</p></li>\
71 </ul>\
72 </li>\
73 <li>\
74 <h3>Clipperz security:</h3>\
75 <ul>\
76 <li><p>your secrets are locally encrypted by your browser before being uploaded to Clipperz</p></li>\
77 <li><p>the encryption key is a passphrase known only to you</p></li>\
78 <li><p>Clipperz hosts your sensitive data in encrypted form and could never actually access the data in its plain form</p></li>\
79 <li><p>Clipperz is built upon standard encryption schemes, nothing fancies or homemade</p></li>\
80 <li><p>you can review the source code anytime you like, but you need to know nothing about cryptography to be an happy user!</p></li>\
81 </ul>\
82 </li>\
83 <li>\
84 <a href=\"http://www.clipperz.com\" target=\"_blank\">Learn more</a>\
85 </li>\
86 </ul>",
87
88
89 'loginFormTitle': "login with your Clipperz account",
90 'loginFormUsernameLabel': "username",
91 'loginFormPassphraseLabel': "passphrase",
92 'loginFormDontHaveAnAccountLabel': "don\'t have an account?",
93 'loginFormCreateOneLabel': "create one",
94 'loginFormForgotYourCredentialsLabel': "forgot your credentials?",
95 'loginFormAarghThatsBadLabel': "aargh! that\'s bad!",
96 'loginFormAfraidOfMaliciousScriptsLabel': "afraid of malicious scripts?",
97 'loginFormVerifyTheCodeLabel': "verify the code",
98 'loginFormButtonLabel': "Login",
99 'loginFormOneTimePasswordCheckboxLabel': "use a one-time passphrase",
100'loginFormOneTimePasswordCheckboxDescription': "",
101
102// Login page - language selection
103 'loginPanelSwithLanguageDescription': "<h5>Switch to your preferred language</h5>",
104
105// Login page - browser compatibility
106 'browserCompatibilityDescription': "<p>Have a better and safer Clipperz experience with Firefox. However Clipperz works just fine also with Opera, Safari and MS Internet Explorer!</p>",
107
108// Login with OTP - message panel
109 'OTPloginMessagePanelInitialTitle': "Logging in using a one-time passphrase",
110 'OTPloginMessagePanelInitialText': "Sending OTP credentials …",
111 'OTPloginMessagePanelLoadingTitle': "Logging in using a one-time passphrase",
112 'OTPloginMessagePanelLoadingText': "Fetching encrypted authentication data from the server …",
113 'OTPloginMessagePanelProcessingTitle': "Logging in using a one-time passphrase",
114 'OTPloginMessagePanelProcessingText': "Local decryption of authentication data",
115
116// Regular login - message panel
117 'loginMessagePanelInitialTitle': "Logging in …",
118 'loginMessagePanelInitialText': "---",
119 'loginMessagePanelInitialButtonLabel': "Cancel",
120 'loginMessagePanelConnectedTitle': "Connected",
121 'loginMessagePanelConnectedText': "Done",
122 'loginMessagePanelFailureTitle': "Error",
123 'loginMessagePanelFailureText': "Login failed",
124 'loginMessagePanelFailureButtonLabel': "Close",
125
126// Regular login - message panel - connection
127 'connectionLoginSendingCredentialsMessageTitle': "Verifying credentials",
128 'connectionLoginSendingCredentialsMessageText': "Sending credentials",
129 'connectionLoginCredentialsVerificationMessageTitle':"Verifying credentials",
130 'connectionLoginCredentialsVerificationMessageText':"Performing SRP authentication",
131 'connectionLoginDoneMessageTitle': "Verifying credentials",
132 'connectionLoginDoneMessageText': "Connected",
133
134 //Regular login - message panel - user
135 'userLoginPanelUpgradingUserCredentialsMessageTitle': "Verifying credentials",
136 'userLoginPanelUpgradingUserCredentialsMessageText': "Upgrading your credentials to a new authentication schema",
137 'userLoginPanelConnectedMessageTitle': "User authenticated",
138 'userLoginPanelConnectedMessageText': "Successfully logged in",
139 'userLoginPanelTryingAnOlderConnectionSchemaMessageTitle': "Verifying credentials",
140 'userLoginPanelTryingAnOlderConnectionSchemaMessageText': "Trying an older authentication schema",
141 'userLoginPanelLoadingUserDataMessageTitle': "User authenticated",
142 'userLoginPanelLoadingUserDataMessageText': "Downloading encrypted card headers from Clipperz",
143 'userLoginPanelDecryptingUserDataMessageTitle': "User authenticated",
144 'userLoginPanelDecryptingUserDataMessageText': "Local decryption of card headers",
145 'userLoginPanelDecryptingUserStatisticsMessageTitle': "User authenticated",
146 'userLoginPanelDecryptingUserStatisticsMessageText': "Local decryption of usage statistics",
147
148 //Registration page - splash alert
149 'splashAlertTitle':"Welcome to Clipperz!",
150'splashAlertText': "\
151 <!-- FIX CSS DONE! -->\
152 <p>Some security advice</p>\
153 <ul>\
154 <li><p>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.</p></li>\
155 <li><p>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!</p></li>\
156 <li><p>Clipperz will not be able to recover a lost passphrase!</p></li>\
157 </ul>\
158 <p>For any further information, please refer to <a href=\"http://www.clipperz.com\" target=\"_blank\">Clipperz</a> website.</p>",
159 'splashAlertCloseButtonLabel':"Ok",
160
161 // Registration page - form
162 'registrationFormTitle': "create your account",
163 'registrationFormUsernameLabel': "username",
164 'registrationFormPassphraseLabel': "passphrase",
165 'registrationFormRetypePassphraseLabel': "re-enter passphrase",
166 'registrationFormSafetyCheckLabel': "I understand that Clipperz will not be able to recover a lost passphrase.",
167 'registrationFormTermsOfServiceCheckLabel': "I have read and agreed to the <a href='http://www.clipperz.com/terms_of_service' target='_blank'>Terms of Service</a>.",
168 'registrationFormDoYouAlreadyHaveAnAccountLabel': "do you already have an account?",
169 'registrationFormSimplyLoginLabel': "simply login",
170 'registrationFormButtonLabel': "Register",
171
172// Registration page - warning messages
173 'registrationFormWarningMessageNotMatchingPassphrases':"Your passphrases don't match, please re-type them.",
174 'registrationFormWarningMessageSafetyCheckNotSelected':"Please read and check all the boxes below.",
175 'registrationFormWarningMessageTermsOfServiceCheckNotSelected':"You need to agree to the Terms of Service.",
176
177 // Registration page - message panel
178 'registrationMessagePanelInitialTitle': "Creating account …",
179 'registrationMessagePanelInitialText': "---",
180 'registrationMessagePanelInitialButtonLabel': "Cancel",
181 'registrationMessagePanelRegistrationDoneTitle': "Registration",
182 'registrationMessagePanelRegistrationDoneText': "Done",
183 'registrationMessagePanelFailureTitle': "Registration failed",
184 'registrationMessagePanelFailureButtonLabel': "Close",
185
186// Registration page - message panel - connection
187 'connectionRegistrationSendingRequestMessageText': "Verifying credentials",
188 'connectionRegistrationSendingCredentialsMessageText':"Sending credentials",
189
190// Registration page - splash panel
191 'registrationSplashPanelTitle': "Security advice",
192 'registrationSplashPanelDescription': "<p>These are your Clipperz credentials, take good care of them. Clipperz will never display your username and passphrase a second time!</p>",
193 'registrationSplashPanelUsernameLabel': "username",
194 'registrationSplashPanelPassphraseLabel':"passphrase",
195
196 'registrationSplashPanelShowPassphraseButtonLabel':"show passphrase",
197
198 //Header links
199 'donateHeaderLinkLabel': "donate",
200 'creditsHeaderLinkLabel': "credits",
201 'feedbackHeaderLinkLabel': "feedback",
202 'helpHeaderLinkLabel': "help",
203 'forumHeaderLinkLabel': "forum",
204
205 //Menu labels
206 'recordMenuLabel': "cards",
207 'accountMenuLabel': "account",
208 'dataMenuLabel': "data",
209 'contactsMenuLabel': "contacts",
210 'toolsMenuLabel': "tools",
211 'logoutMenuLabel': "logout",
212 'lockMenuLabel': "lock",
213
214 //Lock dialog
215 'lockTitle': "The account is locked",
216 'lockDescription': "<p>To unlock your account, please enter your passphrase.</p>",
217 'unlockButtonLabel': "Unlock",
218
219 //Account panel - change passphrase
220 'changePasswordTabLabel': "Change your passphrase",
221 'changePasswordTabTitle': "Change your passphrase",
222
223 'changePasswordFormUsernameLabel': "username",
224 'changePasswordFormOldPassphraseLabel': "old passphrase",
225 'changePasswordFormNewPassphraseLabel': "new passphrase",
226 'changePasswordFormRetypePassphraseLabel':"re-enter new passphrase",
227 'changePasswordFormSafetyCheckboxLabel':"I understand that Clipperz will not be able to recover a lost passphrase.",
228 'changePasswordFormSubmitLabel': "Change passphrase",
229
230 //Account panel - change passphrase - warning messages
231 'changePasswordFormWrongUsernameWarning': "Wrong username",
232 'changePasswordFormWrongPassphraseWarning': "Wrong passphrase",
233 'changePasswordFormWrongRetypePassphraseWarning':"Your passphrases don't match, please re-type them.",
234 'changePasswordFormSafetyCheckWarning': "Please read and check the box below.",
235
236 //Account panel - change passphrase - progress dialog
237 'changePasswordFormProgressDialogTitle': "Changing user credentials",
238 'changePasswordFormProgressDialogEmptyText': "---",
239 'changePasswordFormProgressDialogConnectedMessageTitle': "Connected",
240 'changePasswordFormProgressDialogConnectedMessageText': "Done",
241 'changePasswordFormProgressDialogErrorMessageTitle': "Error",
242 'changePasswordFormProgressDialogErrorMessageText': "Credentials change failed!",
243
244 'changeCredentialsPanelEncryptingDataMessageTitle': "Changing your passphrase",
245 'changeCredentialsPanelEncryptingDataMessageText': "Local encryption of card headers",
246 'changeCredentialsPanelCreatingNewCredentialsMessageTitle': "Changing your passphrase",
247 'changeCredentialsPanelCreatingNewCredentialsMessageText': "Updating your credentials",
248 'changeCredentialsPanelSendingNewCredentialsToTheServerMessageTitle':"Changing your passphrase",
249 'changeCredentialsPanelSendingNewCredentialsToTheServerMessageText':"Uploading your encrypted credentials to Clipperz",
250 'changeCredentialsPanelDoneMessageTitle': "Changing your passphrase",
251 'changeCredentialsPanelDoneMessageText': "Done",
252
253 //Account panel - OTP
254 'manageOTPTabLabel': "Manage your one-time passphrases",
255 'manageOTPTabTitle': "Manage your one-time passphrases",
256
257 'manageOTPTabDescription':"\
258 <p>A one-time passphrase works like your regular passphrase, but can be used only once.</p>\
259 <p>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.</p>\
260 <p>Immediately after a successful login, your one-time passphrase will be deleted preventing any fraudulent access.</p>\
261 <p>One-time passphrases are an excellent choice if one is concerned about keyloggers or spyware infections that may be collecting data from compromised machines.</p>\
262 <p><b>It's strongly advisable to use one-time passphrases when accessing Clipperz from public terminals, such as Internet cafes and libraries.</b></p>",
263
264 //Account panel - OTP - OTP table
265'oneTimePasswordReadOnlyMessage': "\
266 <h6>Sorry!</h6>\
267 <p>You cannot manage your one-time passphrases when using the offline version of Clipperz.</p>",
268
269 'oneTimePasswordLoadingMessage':"\
270 <h6>Loading data</h6>\
271 <p>Please wait …</p>",
272
273 'oneTimePasswordNoPasswordAvailable':"\
274 <h6>No one-time passphrase available</h6>\
275 <p>Click the “New” button above to add one-time passphrases to your account.</p>",
276
277 'createNewOTPButtonLabel': "New",
278 'deleteOTPButtonLabel': "Delete",
279 'printOTPButtonLabel': "Print",
280
281 'disabledOneTimePassword_warning': "disabled",
282
283 'oneTimePasswordSelectionLink_selectLabel':"Select:",
284 'oneTimePasswordSelectionLink_all': "all",
285 'oneTimePasswordSelectionLink_none': "none",
286 'oneTimePasswordSelectionLink_used': "used",
287 'oneTimePasswordSelectionLink_unused': "unused",
288
289//Account panel - OTP - saving new OTP dialog
290 'saveOTP_encryptUserDataTitle': "Saving one-time passphrase",
291 'saveOTP_encryptUserDataText': "Processing new OTP credentials …",
292 'saveOTP_encryptOTPDataTitle': "Saving one-time passphrase",
293 'saveOTP_encryptOTPDataText': "Local encryption of authentication data …",
294 'saveOTP_sendingDataTitle': "Saving one-time passphrase",
295 'saveOTP_sendingDataText': "Sending authentication data to the server …",
296 'saveOTP_updatingInterfaceTitle': "Saving one-time passphrase",
297 'saveOTP_updatingInterfaceText': "Updating interface",
298
299// Account panel - preferences
300 'accountPreferencesLabel': "Preferences",
301 'accountPreferencesTabTitle': "Preferences",
302
303 'accountPreferencesLanguageTitle': "Language",
304 'accountPreferencesLanguageDescription':"<p>Choose your preferred language from the list below.</p>",
305
306 'showDonationReminderPanelTitle': "Donation reminders",
307 'showDonationReminderPanelDescription': "<p>Show donation reminders</p>",
308
309 'saveUserPreferencesFormSubmitLabel': "Save",
310 'cancelUserPreferencesFormSubmitLabel': "Cancel",
311
312// Account panel - preferences - saving dialog
313 'accountPreferencesSavingPanelTitle_Step1': "Saving preferences",
314 'accountPreferencesSavingPanelText_Step1': "Local encryption of your preferences",
315 'accountPreferencesSavingPanelTitle_Step2': "Saving preferences",
316 'accountPreferencesSavingPanelText_Step2': "Sending encrypted preferences to Clipperz",
317
318 //Account panel - login history
319 'accountLoginHistoryLabel': "Login history",
320 'loginHistoryTabTitle': "Login history",
321
322 'loginHistoryReadOnlyMessage': "\
323 <h6>Sorry!</h6>\
324 <p>The login history is not available while using the offline version of Clipperz.</p>",
325
326 'loginHistoryLoadingMessage': "\
327 <h6>Loading data</h6>\
328 <p>Please wait …</p>",
329
330 'loginHistoryLoadedMessage': "\
331 <h6>Your latest 10 logins</h6>\
332 <p></p>",
333
334 'loginHistoryIPLabel': "IP",
335 'loginHistoryTimeLabel': "date",
336 'loginHistoryCurrentSessionText': "current session",
337 'loginHistoryReloadButtonLabel': "Reload login history",
338
339 //Account panel - delete account
340 'deleteAccountTabLabel': "Delete your account",
341 'deleteAccountTabTitle': "Delete your account",
342
343 'deleteAccountFormUsernameLabel': "username",
344 'deleteAccountFormPassphraseLabel': "passphrase",
345 'deleteAccountFormSafetyCheckboxLabel': "I understand that all my data will be deleted and that this action is irreversible.",
346 'deleteAccountFormSubmitLabel': "Delete my account",
347
348//Account panel - delete account - warnings
349 'deleteAccountFormWrongUsernameWarning':"Wrong username",
350 'deleteAccountFormWrongPassphraseWarning':"Wrong passphrase",
351 'deleteAccountFormSafetyCheckWarning': "Please read and check the box below.",
352
353//Account panel - delete account - confirmation
354 'accountPanelDeletingAccountPanelConfirmationTitle':"ATTENTION",
355 'accountPanelDeleteAccountPanelConfirmationText': "Are your sure you want to delete your account?",
356 'accountPanelDeleteAccountPanelConfirmButtonLabel': "Yes",
357 'accountPanelDeleteAccountPanelDenyButtonLabel': "No",
358
359//Account panel - delete account - confirmation
360 'accountPanelDeletingAccountPanelProgressTitle': "Deleting the account data",
361 'accountPanelDeletingAccountPanelProgressText': "The operation could take long, please be patient.",
362
363//Data panel - offline copy
364 'offlineCopyTabLabel': "Offline copy",
365 'offlineCopyTabTitle': "Offline copy",
366
367'offlineCopyTabDescription': "\
368 <!-- FIX CSS DONE! -->\
369 <p>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.</p>\
370 <p>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.</p>\
371 <ol>\
372 <li><p>Click the link below to start the download.</p></li>\
373 <li><p>The browser will ask you what to do with the “Clipperz_YYYYMMDD.html” file. Save it on your hard disk.</p></li>\
374 <li><p>Double click on the downloaded file to launch the offline version in your browser.</p></li>\
375 <li><p>Enter the usual username and passphrase.</p></li>\
376 </ol>",
377
378 'offlineCopyDownloadLinkLabel': "Download",
379
380 //Data panel - offline copy - not updated
381 'offlineCopyDownloadWarning': "\
382 <!-- FIX CSS DONE! -->\
383 <h4><a href=\"#\" id=\"offlineCopyDownloadWarningLink\">Update your “offline copy”!</a></h4>\
384 <p>You have recently created or modified one or more cards, it would be wise to download a new copy of the offline version.</p>",
385
386 'offlineCopyDownloadOk': "",
387
388 //Data panel - sharing
389 'sharingTabLabel': "Sharing",
390 'sharingTabTitle': "Sharing",
391
392 'sharingTabDescription': "\
393 <p>Quite often a confidential piece of information needs to be shared with one or more persons.</p>\
394 <p>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.</p>\
395 <p>Clipperz can make sharing your secrets a secure and straightforward process.</p>\
396 <p></p>\
397 <p><b>Coming soon …</b></p>",
398
399 // Data panel - import
400 'importTabLabel': "Import",
401 'importTabTitle': "Import",
402
403 'importTabDescription': "<p>You can bulk import data to your Clipperz account from several file formats.</p>",
404
405 //Data panel - export
406 'printingTabLabel': "Export",
407 'printingTabTitle': "Export",
408
409 'printingTabDescription': "\
410 <h5>Printing</h5>\
411 <p>Click on the link below to open a new window displaying all your cards in a printable format.</p>\
412 <p>If you are going to print for backup purposes, please consider the safer option provided by the “offline copy”.</p>",
413
414 'printingLinkLabel': "Printable version",
415
416 'exportTabDescription': "\
417 <h5>Exporting to JSON</h5>\
418 <p>JSON enables a “lossless” export of your cards. All the information will be preserved, including direct login configurations.</p>\
419 <p>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.</p>\
420 <p>Click on the link below to start the export process.</p>",
421
422 'exportLinkLabel': "Export to JSON",
423
424 'exportDataInProgressDescription':"<h4>Exporting, please wait while your data are being processed …</h4>",
425
426 'exportDataDescription': "\
427 <h4>Instructions</h4>\
428 <p>Copy the text below to your favorite editor and save it. (e.g. “clipperz_export_20071217.json”)</p>",
429
430 //Contacts panel
431 'contactsTabLabel': "Contacts",
432 'contactsTabTitle': "Contacts",
433
434//Tools panel - password generator
435 'passwordGeneratorTabLabel': "Password generator",
436 'bookmarkletTabLabel': "Bookmarklet",
437 'compactTabLabel': "Compact edition",
438 'httpAuthTabLabel': "HTTP authentication",
439
440 'passwordGeneratorTabTitle': "Password generator",
441 'bookmarkletTabTitle': "Bookmarklet",
442 'compactTabTitle': "Compact edition",
443 'httpAuthTabTitle': "HTTP authentication",
444
445
446 //Tools panel - password generator - description
447 'paswordGeneratorTabDescription':"<p></p>",
448 'passwordGeneratorTabButtonLabel':"Generate password",
449
450 //Tools panel - bookmarklet
451 'bookmarkletTabLabel': "Bookmarklet",
452 'bookmarkletTabTitle': "Bookmarklet",
453
454 'bookmarkletTabDescription': "\
455 <!-- FIX CSS DONE! -->\
456 <p>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.</p>\
457 <p>The Clipperz bookmarklet will help you to quickly create new cards and new “direct logins” within existing cards.</p>\
458 <p><b>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.</b></p>\
459 <h3>How to install the bookmarklet</h3>\
460 <h>Firefox, Camino, Opera, Safari</h5>\
461 <ol>\
462 <li><p>Make sure that the “Bookmarks Bar” is displayed by selecting “View > Toolbars > Bookmarks”, or similar menu items, from the browser menu.</p></li>\
463 <li><p>Drag and drop the “Add to Clipperz” link below to the bookmark bar.</p></li>\
464 </ol>\
465 \
466 <h5>Internet Explorer</h5>\
467 <ol>\
468 <li><p>Make sure that the “Links” toolbar is displayed by selecting “View > Toolbars > Links” from the browser menu.</p></li>\
469 <li><p>Right-click on the “Add to Clipperz” link below.</p></li>\
470 <li><p>Select “Add to favorites” from the contextual menu.</p></li>\
471 <li><p>Click “Yes” for any security message that pops up.</p></li>\
472 <li><p>Open the “Links” folder and click “OK”</p></li>\
473 </ol>",
474
475 'bookmarkletTabBookmarkletTitle':"Add to Clipperz",
476
477 //Tools panel - bookmarklet - instructions
478 'bookmarkletTabInstructions': "\
479 <!-- FIX CSS DONE! -->\
480 <h3>How to create a new card inclusive of a “direct login” link to an online service</h3>\
481 <ol>\
482 <li><p>Open the web page where the login form is hosted. (this is the page where you usually enter your sign-in credentials)</p></li>\
483 <li><p>Launch the bookmarklet by clicking on it: a pop-up window will appear over the web page.</p></li>\
484 <li><p>Copy to the clipboard the content of the large text area within the pop-up. (ctrl-C)</p></li>\
485 <li><p>Enter your Clipperz account and click on the <b>Add new card</b> button.</p></li>\
486 <li><p>Select the “Direct login” template and paste the content of the clipboard to the large text area in the form. (ctrl-V)</p></li>\
487 <li><p>Press the <b>Create</b> button, complete and review the details, then click <b>Save</b>.</p></li>\
488 </ol>\
489 \
490 <h3>How to add a “direct login” link to an existing card</h3>\
491 <ol>\
492 <li><p>Same as above.</p></li>\
493 <li><p>Same as above.</p></li>\
494 <li><p>Same as above.</p></li>\
495 <li><p>Enter your Clipperz account and select the card containing the credentials for the web service you just visited and click the <b>Edit</b> button.</p></li>\
496 <li><p>Paste the content of the clipboard to the large text area in the “Direct logins” section. (ctrl-V)</p></li>\
497 <li><p>Press the <b>Add direct login</b> button, review the details and then click <b>Save</b>.</p></li>\
498 </ol>\
499 \
500 <p></p>\
501 <p>Further information about the bookmarklet are <a href=\"http://www.clipperz.com/support/user_guide/bookmarklet\" target=\"_blank\">available here</a>.</p>",
502
503 //Tools panel - Compact - instructions
504 'compactTabDescription': "\
505 <!-- FIX CSS DONE! -->\
506 <p>Clipperz Compact is a special version of Clipperz designed to be opened in the Firefox sidebar.</p>\
507 <p>Its purpose is to keep your collection of “direct logins” always at hand. Read more <a href=\"http://www.clipperz.com/support/user_guide/clipperz_compact\", target=\"blank\">here</a></p>\
508 \
509 <h3>How to launch Clipperz Compact in the sidebar</h3>\
510 <ol>\
511 <li><p>Get Firefox! Sidebars are only available in Firefox and you need to switch to Firefox in order to enjoy the convenience of Clipperz Compact.</p></li>\
512 <li>\
513 <p>Add the following URL to Firefox bookmarks, or even better, drag it to the bookmark bar.</p>\
514 <div id=\"compactLinkBox\"><a href=\"https://www.clipperz.com/beta/index.html?compact\" target=\"_search\">Clipperz Compact</a></div>\
515 </li>\
516 <li><p>Change the properties of the bookmark so that “load this bookmark in the sidebar” is checked.</p></li>\
517 </ol>\
518 \
519 <h5>Added bonus: Clipperz Compact works also in Opera’s panel.</h5>",
520
521 //Tools panel - HTTP authentication - instructions
522 'httpAuthTabDescription': "\
523 <!-- FIX CSS DONE! -->\
524 <p>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).</p>\
525 <p>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.</p>\
526 <p>Unfortunately the Clipperz bookmarklet does not work on websites that use HTTP authentication. However you can still create a “direct login”.</p>\
527 \
528 <h3>How to create a “direct login” for a website that uses HTTP authentication</h3>\
529 <ol>\
530 <li><p>Store website URL, username and password in a new card.</p></li>\
531 <li><p>Copy the configuration below and paste it to the large text area in the “Direct logins” section of the new card.</p></li>\
532 <li><p>Press the <b>Add direct login</b> button, bind URL, username and password fields and then click <b>Save</b>.</p></li>\
533 </ol>\
534 \
535 <h5><a href=\"http://support.microsoft.com/kb/834489\" target=\"_blank\">Warning: Internet Explorer does not support HTTP authentication.</a></h5>",
536
537// Direct logins block
538 'mainPanelDirectLoginBlockLabel': "Direct logins",
539 'directLinkReferenceShowButtonLabel': "show",
540
541// Direct logins - blank slate
542 'mainPanelDirectLoginBlockDescription': "\
543 <!-- FIX CSS DONE! -->\
544 <p>Add “direct logins” to sign in to your web accounts without typing usernames and passwords!</p>\
545 <p>“Direct logins” greatly enhance your password security since you can:</p>\
546 <ul>\
547 <li><p>conveniently adopt and enter complex passwords;</p></li>\
548 <li><p>never re-use the same and easy-to-guess password.</p></li>\
549 </ul>\
550 <p>Simple and quick configuration with the <b>Clipperz bookmarklet</b>.</p>\
551 <a href=\"http://www.clipperz.com/support/user_guide/direct_logins\" target=\"_blank\">Learn more about “direct logins”</a>",
552
553 // Cards block
554 'mainPanelRecordsBlockLabel': "Cards",
555 'mainPanelAddRecordButtonLabel': "Add new card",
556 'mainPanelRemoveRecordButtonLabel': "Delete card",
557
558// Cards block - filter tabs
559 'mainPanelRecordFilterBlockAllLabel': "all",
560 'mainPanelRecordFilterBlockTagsLabel': "tags",
561 'mainPanelRecordFilterBlockSearchLabel':"search",
562
563// Cards block - blank slate
564 'recordDetailNoRecordAtAllTitle': "Welcome to Clipperz!",
565 'recordDetailNoRecordAtAllDescription': "\
566 <h5>Get started by adding cards to your account.</h5>\
567 <p>Cards are simple and flexible forms where you can store your passwords and any other confidential data.</p>\
568 <p>Cards could contain credentials for accessing a web site, the combination of your bicycle lock, details of your credit card, …</p>\
569 \
570 <h5>Don't forget the Clipperz bookmarklet!</h5>\
571 <p>Before you start, install the “Add to Clipperz” bookmarklet: it will make creating cards easier and more fun.</p>\
572 <p>Go to the “Tools” tab to discover how to install it and how it use it.</p>\
573 <p></p>\
574 <p>Then simply click the <b>\"Add new card\"</b> button and enjoy your Clipperz account.</p>\
575 <p></p>\
576 <a href=\"http://www.clipperz.com/support/user_guide/managing_cards\" target=\"_blank\">Learn more about creating and managing cards</a>",
577
578// Cards block - new card wizard - bookmarklet configuration
579 'newRecordWizardTitleBox': "\
580 <h5>Please select a template</h5>\
581 <p>Cards are simple and flexible forms where you can store passwords or any other confidential data.</p>\
582 <p>Start choosing one of the templates below. You can always customize your cards later by adding or removing fields.</p>",
583
584 'newRecordWizardBookmarkletConfigurationTitle': "Direct login",
585 'newRecordWizardBookmarkletConfigurationDescription':"\
586 <p>Paste below the configuration code generated by the Clipperz bookmarklet.</p>\
587 <p>A new card complete with a direct login to your web account will be created.</p>",
588
589 'newRecordWizardCreateButtonLabel': "Create",
590 'newRecordWizardCancelButtonLabel': "Cancel",
591
592 //Create new card - Donation splash
593 'donateSplashPanelTitle': "Support Clipperz, make a donation today!",
594 'donateSplashPanelDescription': "\
595 <!-- FIX CSS DONE! -->\
596 <p>A few good reasons to make a donation:</p>\
597 <ul>\
598 <li><p>support the development of new features</p></li>\
599 <li><p>keep Clipperz free</p></li>\
600 <li><p>show appreciation for our hard work</p></li>\
601 </ul>\
602 <p>For any further information, please visit our <a href=\"http://www.clipperz.com/donations\" target=\"_blank\">Donations page</a>.</p>\
603 <p><b>Ready to donate?</b></p>",
604
605 'donateCloseButtonLabel': "Not yet",
606 'donateDonateButtonLabel': "Yes",
607
608// Card templates
609'recordTemplates': {
610
611//Web password
612 'WebAccount': {
613 'title': "Web password",
614 'description':"<p>A simple card to store login credentials for your online services.</p>",
615 'fields': [
616 {label:"Web address", type:'URL'},
617 {label:"Username or email", type:'TXT'},
618 {label:"Password", type:'PWD'}
619 ]
620 },
621
622 //Bank account
623 'BankAccount': {
624 'title': "Bank account",
625 'description':"<p>Safely store your bank account number and online banking credentials.</p>",
626 'fields': [
627 {label:"Bank", type:'TXT'},
628 {label:"Account number", type:'TXT'},
629 {label:"Bank website", type:'URL'},
630 {label:"Online banking ID", type:'TXT'},
631 {label:"Online banking password", type:'PWD'}
632 ]
633 },
634
635 // Credit card
636 'CreditCard': {
637 'title': "Credit card",
638 'description':"<p>Card number, expire date, CVV2 and PIN always at hand with Clipperz.</p>",
639 'fields': [
640 {label:"Type (Visa, AmEx, …)", type:'TXT'},
641 {label:"Number", type:'TXT'},
642 {label:"Owner name", type:'TXT'},
643 {label:"Expiry date", type:'TXT'},
644 {label:"CVV2", type:'TXT'},
645 {label:"PIN", type:'PWD'},
646 {label:"Card website", type:'URL'},
647 {label:"Username", type:'TXT'},
648 {label:"Password", type:'PWD'}
649 ]
650 },
651
652 // Address book entry
653 'AddressBookEntry': {
654 'title': "Address book entry",
655 'description':"<p>Clipperz could also work as your new private address book. Use this template to easily add a new entry.</p>",
656 'fields': [
657 {label:"Name", type:'TXT'},
658 {label:"Email", type:'TXT'},
659 {label:"Phone", type:'TXT'},
660 {label:"Mobile", type:'TXT'},
661 {label:"Address", type:'ADDR'},
662 ]
663 },
664
665//Custom card
666 'Custom': {
667 'title': "Custom card",
668 'description':"<p>No matter which kind of confidential data you need to protect, create a custom card to match your needs.</p>",
669 'fields': [
670 {label:"Label 1", type:'TXT'},
671 {label:"Label 2", type:'TXT'},
672 {label:"Label 3", type:'TXT'}
673 ]
674 }
675},
676
677
678'recordFieldTypologies': {
679 'TXT': {
680 description: "simple text field",
681 shortDescription: "text"
682 },
683 'PWD': {
684 description: "simple text field, with default status set to hidden",
685 shortDescription: "password"
686 },
687 'URL': {
688 description: "simple text field in edit mode, that became an active url in view mode",
689 shortDescription: "web address"
690 },
691 'DATE': {
692 description: "a value set with a calendar helper",
693 shortDescription: "date"
694 },
695 'ADDR': {
696 description: "just like the URL, but the active link points to Google Maps (or similar service) passing the address value as argument",
697 shortDescription: "street address"
698 },
699 'CHECK': {
700 description: "check description",
701 shortDescription: "check"
702 },
703 'RADIO': {
704 description: "radio description",
705 shortDescription: "radio"
706 },
707 'SELECT': {
708 description: "select description",
709 shortDescription: "select"
710 }
711},
712
713// Cards block - new card - warnings
714 'newRecordPanelGeneralExceptionTitle': "Error",
715 'newRecordPanelGeneralExceptionMessage': "The configuration text is not valid. Make sure to get your text from the bookmarklet pop-up and retry.",
716 'newRecordPanelWrongBookmarkletVersionExceptionTitle': "Error",
717 'newRecordPanelWrongBookmarkletVersionExceptionMessage':"The configuration text has been generated by an old version of the bookmarklet. Please update your bookmarklet and retry.",
718 'newRecordPanelExceptionPanelCloseButtonLabel': "Cancel",
719
720// Cards block - delete card
721 'mainPanelDeletingRecordPanelConfirmationTitle': "Deleting selected card",
722 'mainPanelDeleteRecordPanelConfirmationText': "Do your really want to delete the selected card?",
723 'mainPanelDeleteRecordPanelConfirmButtonLabel': "Yes",
724 'mainPanelDeleteRecordPanelDenyButtonLabel': "No",
725 'mainPanelDeletingRecordPanelInitialTitle': "Deleting selected card",
726 'mainPanelDeletingRecordPanelInitialText': "---",
727 'mainPanelDeletingRecordPanelCompletedText': "Done",
728
729// Cards block - delete card panel
730 'deleteRecordPanelCollectRecordDataMessageTitle': "Delete card",
731 'deleteRecordPanelCollectRecordDataMessageText': "Updating card list",
732 'deleteRecordPanelEncryptUserDataMessageTitle': "Delete card",
733 'deleteRecordPanelEncryptUserDataMessageText': "Local encryption of card headers",
734 'deleteRecordPanelSendingDataToTheServerMessageTitle': "Delete card",
735 'deleteRecordPanelSendingDataToTheServerMessageText': "Uploading encrypted card headers to Clipperz",
736 'deleteRecordPanelUpdatingTheInterfaceMessageTitle': "Delete card",
737 'deleteRecordPanelUpdatingTheInterfaceMessageText': "Updating the interface",
738
739// Cards block - no record selected
740 'recordDetailNoRecordSelectedTitle': "No card selected",
741 'recordDetailNoRecordSelectedDescription': "<p>Please select a card from the list on the left.</p>",
742
743 // Cards block - loading messages
744 'recordDetailLoadingRecordMessage': "Downloading encrypted card from Clipperz",
745 'recordDetailDecryptingRecordMessage': "Local decryption of card\'s data",
746 'recordDetailLoadingRecordVersionMessage': "Downloading latest card version",
747 'recordDetailDecryptingRecordVersionMessage': "Local decryption of latest version",
748 'recordDetailLoadingErrorMessageTitle': "Error while downloading the card",
749
750// Cards block - card details
751 'recordDetailNotesLabel': "Notes",
752 'recordDetailLabelFieldColumnLabel': "Field label",
753 'recordDetailDataFieldColumnLabel': "Field data",
754 'recordDetailTypeFieldColumnLabel': "Type",
755
756 'recordDetailSavingChangesMessagePanelInitialTitle': "Saving card",
757 'recordDetailSavingChangesMessagePanelInitialText': "---",
758
759 'recordDetailRemoveFieldButtonLabel': "-",
760 'recordDetailAddFieldButtonLabel': "Add new field",
761 'recordDetailPasswordFieldHelpLabel': "click the stars to select the password and then Ctrl-C to copy",
762
763 'recordDetailPasswordFieldScrambleLabel': "scramble",
764 'recordDetailPasswordFieldUnscrambleLabel': "unscramble",
765
766 'recordDetailDirectLoginBlockTitle': "Direct logins",
767 'recordDetailNewDirectLoginDescription': "<p>Direct login configuration</p>",
768
769 'recordDetailDirectLoginBlockNoDirectLoginConfiguredDescription':"\
770 <p>Does this card contain credentials to access an online service?</p>\
771 <p>Use the bookmarklet to configure a “direct login” from Clipperz with just one click!</p>",
772
773 'recordDetailDeleteDirectLoginButtonLabel': "-",
774 'recordDetailAddNewDirectLoginButtonLabel': "Add new direct login",
775
776 'recordDetailEditButtonLabel': "Edit",
777 'recordDetailSaveButtonLabel': "Save",
778 'recordDetailCancelButtonLabel': "Cancel",
779
780 'newRecordTitleLabel': "_new card_",
781 'newDirectLoginLabelSuffix': "",
782
783// Cards block - save card panel
784 'recordSaveChangesPanelCollectRecordInfoMessageTitle': "Save card",
785 'recordSaveChangesPanelCollectRecordInfoMessageText': "Updating card headers",
786 'recordSaveChangesPanelEncryptUserDataMessageTitle': "Save card",
787 'recordSaveChangesPanelEncryptUserDataMessageText': "Local encryption of card headers",
788 'recordSaveChangesPanelEncryptRecordDataMessageTitle': "Save card",
789 'recordSaveChangesPanelEncryptRecordDataMessageText': "Local encryption of card's data",
790 'recordSaveChangesPanelEncryptRecordVersionDataMessageTitle':"Save card",
791 'recordSaveChangesPanelEncryptRecordVersionDataMessageText':"Local encryption of card's version data",
792 'recordSaveChangesPanelSendingDataToTheServerMessageTitle': "Save card",
793 'recordSaveChangesPanelSendingDataToTheServerMessageText': "Uploading encrypted card's header to Clipperz",
794 'recordSaveChangesPanelUpdatingTheInterfaceMessageTitle': "Save card",
795 'recordSaveChangesPanelUpdatingTheInterfaceMessageText': "Updating the interface",
796
797 //Password Generator strings
798 'passwordGeneratorPanelTitle': "Password generator",
799 'passwordGeneratorPanelOkLabel': "Ok",
800 'passwordGeneratorPanelCancelLabel': "Cancel",
801
802 'passwordGeneratorLowercaseLabel': "abc",
803 'passwordGeneratorUppercaseLabel': "ABC",
804 'passwordGeneratorNumberLabel': "012",
805 'passwordGeneratorSymbolLabel': "@#$",
806
807 'passwordGeneratorLengthLabel': "length:",
808
809
810 //Miscellaneous strings
811
812 //'DWRUtilLoadingMessage': "Loading data …",
813 'comingSoon': "coming soon …",
814 'panelCollectingEntryopyMessageText': "Collecting entropy",
815 'directLoginConfigurationCheckBoxFieldSelectedValue': "Yes",
816 'directLoginConfigurationCheckBoxFieldNotSelectedValue': "No",
817
818
819
820// NEW - Import panel
821 'importFormats':{
822 'CSV': {
823 'label': "CSV",
824 'description':"<p>A widely recognized file format that stores tabular data. Several password managers can export data to this format.</p>"
825 },
826 'Excel': {
827 'label': "Excel",
828 'description':"<p>The popular spreadsheet from Microsoft. Storing passwords in Excel files is very common but not advisable.</p>"
829 },
830 'KeePass': {
831 'label': "KeePass",
832 'description':"<p>The custom TXT file created by KeePass password manager.</p>"
833 },
834 'PasswordPlus': {
835 'label': "Password Plus",
836 'description':"<p>The custom CSV format produced by Password Plus, a password manager mostly used on mobile devices.</p>"
837 },
838 'Roboform': {
839 'label': "RoboForm",
840 'description':"<p>The special HTML file created by Roboform password manager when displaying Passcard and Safenotes for printing.</p>"
841 },
842 'ClipperzExport': {
843 'label': "JSON",
844 'description':"<p>The file created by Clipperz itself in JSON format. It preserves all information contained in your cards, even direct login configurations.</p>"
845 }
846},
847
848 //JSON
849 'Clipperz_ImportWizard_Title': "JSON import",
850 'importOptions_clipperz_description': "<p>Open the JSON file exported from Clipperz in a text editor. Then copy and paste its content to the text area below.</p>",
851
852 //CSV
853 'CSV_ImportWizard_Title': "CSV import",
854 'importOptions_csv_description_': "\
855 <p>Open the CSV file in a text editor. Then copy and paste its content to the text area below.</p>\
856 <p>Please select the special characters used within your file.</p>",
857
858 //Excel
859 'Excel_ImportWizard_Title': "Excel import",
860 'importOptions_excel_description_': "<p>Open the Excel file and select the cells you want to import. Then copy and paste them to the text area below.</p>",
861
862 //KeePass
863 'KeePass_ImportWizard_Title': "KeePass import",
864 'importOptions_keePass_description_': "<p>Open the TXT file created by Keepass in a text editor. Then copy and paste its content to the text area below.</p>",
865
866 //PasswordPlus
867 'PasswordPlus_ImportWizard_Title': "Password Plus import",
868 'importOptions_passwordPlus_description':"<p>Open the CSV file created by PasswordPlus in a text editor. Then copy and paste its content to the text area below.</p>",
869
870 //RoboForm
871 'RoboForm_ImportWizard_Title': "RoboForm import",
872 'importOptions_roboForm_description': "<p>Open the HTML file created by RoboForm in a text editor. Then copy and paste its content to the text area below.</p>",
873
874
875 'importData_parsingDataTitle': "Import",
876 'importData_parsingDataText': "Parsing data …",
877
878 'importData_previewingDataTitle': "Import",
879 'importData_previewingDataText': "Processing data …",
880
881 'importData_processingDataTitle': "Import",
882 'importData_processingDataText': "Creating new cards …",
883
884'ImportWizard': {
885 'EDIT': "edit",
886 'PREVIEW': "preview",
887 'IMPORT': "import",
888
889 'KEEPASS_SETTINGS': "settings",
890
891 'CSV_EDIT': "paste",
892 'CSV_COLUMNS': "columns",
893 'CSV_HEADER': "labels",
894 'CSV_TITLE': "titles",
895 'CSV_NOTES': "notes",
896 'CSV_FIELDS': "types",
897
898 'EXCEL_EDIT': "edit"
899},
900
901 'CSV_ImportWizard_Columns': "<p>Select the columns you want to import.</p>",
902 'CSV_ImportWizard_Header': "<p>If the first row of the CSV file contains field labels, tick off the checkbox below.</p>",
903 'CSV_ImportWizard_Header_Settings_firstRowHeaderLabel':"Use the first row as labels?",
904 'CSV_ImportWizard_Title': "<p>Select the column that contains titles of the cards you are importing. (mandatory)</p>",
905 'CSV_ImportWizard_Notes': "<p>Select the column that represents a \"notes\" field. (optional)</p>",
906 'CSV_ImportWizard_Notes_Settings_noSelectionLabel': "\"notes\" field not present",
907 'CSV_ImportWizard_Fields': "<p>Select the correct type for each column from the drop down lists.</p>",
908 'CSV_ImportWizard_Fields_MissingLabelWarning': "Missing label",
909
910 'importData_importConfirmation_title': "Import",
911 'importData_importConfirmation_text': "Do you want to import __numberOfRecords__ cards?",
912
913
914 //Vulnerability warning
915 'VulnerabilityWarning_Panel_title': "Vulnerability warning",
916 'VulnerabilityWarning_Panel_message': "The action as been aborted due to a catched vulnerability",
917 'VulnerabilityWarning_Panel_buttonLabel':"Close",
918
919
920
921 //All the loginInfo panel infos
922
923 'WELCOME_BACK': "Welcome back!",
924
925 'currentConnectionText': "You are connected from ip&nbsp;__ip__, apparently from __country__, using __browser__ on __operatingSystem__.",
926 'latestConnectionText': "Your latest connection was __elapsedTimeDescription__ (__time__) from ip&nbsp;__ip__, apparently from __country__, using __browser__ on __operatingSystem__.",
927
928 'fullLoginHistoryLinkLabel': "show login history",
929
930'elapsedTimeDescriptions': {
931 'MORE_THAN_A_MONTH_AGO': "more than a month ago",
932 'MORE_THAN_A_WEEK_AGO': "more than a week ago",
933 'MORE_THAN_*_WEEKS_AGO': "more than __elapsed__ weeks ago",
934 'YESTERDAY': "yesterday",
935 '*_DAYS_AGO': "__elapsed__ days ago",
936 'ABOUT_AN_HOUR_AGO': "about an hour ago",
937 '*_HOURS_AGO': "__elapsed__ hours ago",
938 'JUST_A_FEW_MINUTES_AGO': "just a few minutes ago",
939 'ABOUT_*_MINUTES_AGO': "about __elapsed__ minutes ago"
940},
941
942 'unknown_ip': "unknown",
943
944'countries': {
945 '--': "unknown",
946 'AD': "Andorra",
947 'AE': "United Arab Emirates",
948 'AF': "Afghanistan",
949 'AG': "Antigua and Barbuda",
950 'AI': "Anguilla",
951 'AL': "Albania",
952 'AM': "Armenia",
953 'AN': "Netherlands Antilles",
954 'AO': "Angola",
955 'AP': "Non-Spec Asia Pas Location",
956 'AR': "Argentina",
957 'AS': "American Samoa",
958 'AT': "Austria",
959 'AU': "Australia",
960 'AW': "Aruba",
961 'AX': "Aland Islands",
962 'AZ': "Azerbaijan",
963 'BA': "Bosnia and Herzegowina",
964 'BB': "Barbados",
965 'BD': "Bangladesh",
966 'BE': "Belgium",
967 'BF': "Burkina Faso",
968 'BG': "Bulgaria",
969 'BH': "Bahrain",
970 'BI': "Burundi",
971 'BJ': "Benin",
972 'BM': "Bermuda",
973 'BN': "Brunei Darussalam",
974 'BO': "Bolivia",
975 'BR': "Brazil",
976 'BS': "Bahamas",
977 'BT': "Bhutan",
978 'BW': "Botswana",
979 'BY': "Belarus",
980 'BZ': "Belize",
981 'CA': "Canada",
982 'CD': "Congo the Democratic Republic of the",
983 'CF': "Central African Republic",
984 'CH': "Switzerland",
985 'CI': "Cote D'ivoire",
986 'CK': "Cook Islands",
987 'CL': "Chile",
988 'CM': "Cameroon",
989 'CN': "China",
990 'CO': "Colombia",
991 'CR': "Costa Rica",
992 'CS': "Serbia and Montenegro",
993 'CU': "Cuba",
994 'CY': "Cyprus",
995 'CZ': "Czech Republic",
996 'DE': "Germany",
997 'DJ': "Djibouti",
998 'DK': "Denmark",
999 'DO': "Dominican Republic",
1000 'DZ': "Algeria",
1001 'EC': "Ecuador",
1002 'EE': "Estonia",
1003 'EG': "Egypt",
1004 'ER': "Eritrea",
1005 'ES': "Spain",
1006 'ET': "Ethiopia",
1007 'EU': "European Union",
1008 'FI': "Finland",
1009 'FJ': "Fiji",
1010 'FM': "Micronesia Federated States of",
1011 'FO': "Faroe Islands",
1012 'FR': "France",
1013 'GA': "Gabon",
1014 'GB': "United Kingdom",
1015 'GD': "Grenada",
1016 'GE': "Georgia",
1017 'GF': "French Guiana",
1018 'GG': "Guernsey",
1019 'GH': "Ghana",
1020 'GI': "Gibraltar",
1021 'GL': "Greenland",
1022 'GM': "Gambia",
1023 'GP': "Guadeloupe",
1024 'GR': "Greece",
1025 'GT': "Guatemala",
1026 'GU': "Guam",
1027 'GW': "Guinea-Bissau",
1028 'GY': "Guyana",
1029 'HK': "Hong Kong",
1030 'HN': "Honduras",
1031 'HR': "Croatia (Local Name: Hrvatska)",
1032 'HT': "Haiti",
1033 'HU': "Hungary",
1034 'ID': "Indonesia",
1035 'IE': "Ireland",
1036 'IL': "Israel",
1037 'IM': "Isle of Man",
1038 'IN': "India",
1039 'IO': "British Indian Ocean Territory",
1040 'IQ': "Iraq",
1041 'IR': "Iran (Islamic Republic of)",
1042 'IS': "Iceland",
1043 'IT': "Italy",
1044 'JE': "Jersey",
1045 'JM': "Jamaica",
1046 'JO': "Jordan",
1047 'JP': "Japan",
1048 'KE': "Kenya",
1049 'KG': "Kyrgyzstan",
1050 'KH': "Cambodia",
1051 'KI': "Kiribati",
1052 'KN': "Saint Kitts and Nevis",
1053 'KR': "Korea Republic of",
1054 'KW': "Kuwait",
1055 'KY': "Cayman Islands",
1056 'KZ': "Kazakhstan",
1057 'LA': "Lao People's Democratic Republic",
1058 'LB': "Lebanon",
1059 'LC': "Saint Lucia",
1060 'LI': "Liechtenstein",
1061 'LK': "Sri Lanka",
1062 'LR': "Liberia",
1063 'LS': "Lesotho",
1064 'LT': "Lithuania",
1065 'LU': "Luxembourg",
1066 'LV': "Latvia",
1067 'LY': "Libyan Arab Jamahiriya",
1068 'MA': "Morocco",
1069 'MC': "Monaco",
1070 'MD': "Moldova Republic of",
1071 'MG': "Madagascar",
1072 'MH': "Marshall Islands",
1073 'MK': "Macedonia the Former Yugoslav Republic of",
1074 'ML': "Mali",
1075 'MM': "Myanmar",
1076 'MN': "Mongolia",
1077 'MO': "Macau",
1078 'MP': "Northern Mariana Islands",
1079 'MR': "Mauritania",
1080 'MS': "Montserrat",
1081 'MT': "Malta",
1082 'MU': "Mauritius",
1083 'MV': "Maldives",
1084 'MW': "Malawi",
1085 'MX': "Mexico",
1086 'MY': "Malaysia",
1087 'MZ': "Mozambique",
1088 'NA': "Namibia",
1089 'NC': "New Caledonia",
1090 'NF': "Norfolk Island",
1091 'NG': "Nigeria",
1092 'NI': "Nicaragua",
1093 'NL': "Netherlands",
1094 'NO': "Norway",
1095 'NP': "Nepal",
1096 'NR': "Nauru",
1097 'NU': "Niue",
1098 'NZ': "New Zealand",
1099 'OM': "Oman",
1100 'PA': "Panama",
1101 'PE': "Peru",
1102 'PF': "French Polynesia",
1103 'PG': "Papua New Guinea",
1104 'PH': "Philippines",
1105 'PK': "Pakistan",
1106 'PL': "Poland",
1107 'PR': "Puerto Rico",
1108 'PS': "Palestinian Territory Occupied",
1109 'PT': "Portugal",
1110 'PW': "Palau",
1111 'PY': "Paraguay",
1112 'QA': "Qatar",
1113 'RO': "Romania",
1114 'RS': "Serbia",
1115 'RU': "Russian Federation",
1116 'RW': "Rwanda",
1117 'SA': "Saudi Arabia",
1118 'SB': "Solomon Islands",
1119 'SC': "Seychelles",
1120 'SD': "Sudan",
1121 'SE': "Sweden",
1122 'SG': "Singapore",
1123 'SI': "Slovenia",
1124 'SK': "Slovakia (Slovak Republic)",
1125 'SL': "Sierra Leone",
1126 'SM': "San Marino",
1127 'SN': "Senegal",
1128 'SR': "Suriname",
1129 'SV': "El Salvador",
1130 'SY': "Syrian Arab Republic",
1131 'SZ': "Swaziland",
1132 'TC': "Turks and Caicos Islands",
1133 'TG': "Togo",
1134 'TH': "Thailand",
1135 'TJ': "Tajikistan",
1136 'TM': "Turkmenistan",
1137 'TN': "Tunisia",
1138 'TO': "Tonga",
1139 'TR': "Turkey",
1140 'TT': "Trinidad and Tobago",
1141 'TV': "Tuvalu",
1142 'TW': "Taiwan Province of China",
1143 'TZ': "Tanzania United Republic of",
1144 'UA': "Ukraine",
1145 'UG': "Uganda",
1146 'US': "United States",
1147 'UY': "Uruguay",
1148 'UZ': "Uzbekistan",
1149 'VA': "Holy See (Vatican City State)",
1150 'VE': "Venezuela",
1151 'VG': "Virgin Islands (British)",
1152 'VI': "Virgin Islands (U.S.)",
1153 'VN': "Viet Nam",
1154 'VU': "Vanuatu",
1155 'WF': "Wallis and Futuna Islands",
1156 'WS': "Samoa",
1157 'YE': "Yemen",
1158 'ZA': "South Africa",
1159 'ZM': "Zambia",
1160 'ZW': "Zimbabwe",
1161 'ZZ': "Reserved"
1162},
1163
1164'browsers': {
1165 'UNKNOWN': "Unknown",
1166 'MSIE': "Internet Explorer",
1167 'FIREFOX': "Firefox",
1168 'OPERA': "Opera",
1169 'SAFARI': "Safari",
1170 'OMNIWEB': "OmniWeb",
1171 'CAMINO': "Camino",
1172 'CHROME': "Chrome"
1173},
1174
1175'operatingSystems': {
1176 'UNKNOWN': "Unknown",
1177 'WINDOWS': "Windows",
1178 'MAC': "Mac",
1179 'LINUX': "Linux",
1180 'IPHONE': "iPhone",
1181 'MOBILE': "Mobile",
1182 'OPENBSD': "OpenBSD",
1183 'FREEBSD': "FreeBSD",
1184 'NETBSD': "NetBSD"
1185},
1186
1187
1188 //Calendar texts
1189'calendarStrings': {
1190 'months': {
1191 '0':"January",
1192 '1':"February",
1193 '2':"March",
1194 '3':"April",
1195 '4':"May",
1196 '5':"June",
1197 '6':"July",
1198 '7':"August",
1199 '8':"September",
1200 '9':"October",
1201 '10':"November",
1202 '11':"December"
1203 },
1204 'shortMonths':{
1205 '0':"Jan",
1206 '1':"Feb",
1207 '2':"Mar",
1208 '3':"Apr",
1209 '4':"May",
1210 '5':"Jun",
1211 '6':"Jul",
1212 '7':"Aug",
1213 '8':"Sep",
1214 '9':"Oct",
1215 '10':"Nov",
1216 '11':"Dec"
1217 },
1218
1219 'days':{
1220 '0':"Sunday",
1221 '1':"Monday",
1222 '2':"Tuesday",
1223 '3':"Wednesday",
1224 '4':"Thursday",
1225 '5':"Friday",
1226 '6':"Saturday"
1227 },
1228
1229 'shortDays':{
1230 '0':"Sun",
1231 '1':"Mon",
1232 '2':"Tue",
1233 '3':"Wed",
1234 '4':"Thu",
1235 '5':"Fri",
1236 '6':"Sat"
1237 },
1238
1239 'veryShortDays':{
1240 '0':"Su",
1241 '1':"Mo",
1242 '2':"Tu",
1243 '3':"We",
1244 '4':"Th",
1245 '5':"Fr",
1246 '6':"Sa"
1247 },
1248
1249 'amDesignation':"am",
1250 'pmDesignation':"pm"
1251},
1252
1253
1254// Date format
1255 'fullDate_format':"l, F d, Y H:i:s",
1256
1257__syntaxFix__: "syntax fix"
1258
1259}
diff --git a/frontend/beta/js/Clipperz/PM/Strings/Strings_es-ES.js b/frontend/beta/js/Clipperz/PM/Strings/Strings_es-ES.js
new file mode 100644
index 0000000..1541d5f
--- a/dev/null
+++ b/frontend/beta/js/Clipperz/PM/Strings/Strings_es-ES.js
@@ -0,0 +1,480 @@
1/*
2
3Copyright 2008-2011 Clipperz Srl
4
5This file is part of Clipperz's Javascript Crypto Library.
6Javascript Crypto Library provides web developers with an extensive
7and efficient set of cryptographic functions. The library aims to
8obtain maximum execution speed while preserving modularity and
9reusability.
10For further information about its features and functionalities please
11refer to http://www.clipperz.com
12
13* Javascript Crypto Library is free software: you can redistribute
14 it and/or modify it under the terms of the GNU Affero General Public
15 License as published by the Free Software Foundation, either version
16 3 of the License, or (at your option) any later version.
17
18* Javascript Crypto Library is distributed in the hope that it will
19 be useful, but WITHOUT ANY WARRANTY; without even the implied
20 warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
21 See the GNU Affero General Public License for more details.
22
23* You should have received a copy of the GNU Affero General Public
24 License along with Javascript Crypto Library. If not, see
25 <http://www.gnu.org/licenses/>.
26
27*/
28
29Clipperz.PM.Strings.Languages['es-ES'.toLowerCase()] = MochiKit.Base.merge(Clipperz.PM.Strings.Languages['en-us'], {
30 'clipperzServiceDescription':"<h2>Guárdelo usted mismo!</h2> <ul> <li> <h3>Clipperz es:</h3> <ul> <li> <p>un simple y seguro administrador de contraseñas</p> </li> <li> <p>una efectiva y simple solución de logueo</p> </li> <li> <p>un maletín digital para sus datos confidenciales</p> </li> </ul> </li> <li> <h3>Con Clipperz usted puede:</h3> <ul> <li> <p>administrar y almacenar en línea sus contraseñas y credenciales digitales</p> </li> <li> <p>ingresar en sus servicios web sin ningún nombre de usuario o contraseña</p> </li> <li> <p>protejer todos sus datos sensibles: códigos de alarmas, PINs y números de tarjetas de crédito, &hellip;</p> </li> <li> <p>compartir secretos con sus familiares y socios</p> </li> </ul> </li> <li> <h3>Beneficios de Clipperz:</h3> <ul> <li> <p>es gratis y completamente anónimo</p> </li> <li> <p>con acceso en cualquier momento y desde cualquier ordenador</p> </li> <li> <p>no necesita instalar o descargar ningún programa</p> </li> <li> <p>no necesita guardar secretos en papel o en el ordenador</p> </li> </ul> </li> <li> <h3>Seguridad de Clipperz:</h3> <ul> <li> <p>sus secretos son localmente encriptados por su navegador antes de ser almacenados en Clipperz</p> </li> <li> <p>la llave de encriptación es una frase clave conocida solo por usted</p> </li> <li> <p>Clipperz almacena sus datos de manera encriptada y nunca accede a ellos en forma de texto plano</p> </li> <li> <p>Clipperz esta basado en esquemas estándares de encriptación, no hemos inventado nada</p> </li> <li> <p>usted puede revisar el código todas las veces que lo desee, ¡ pero no necesita conocer algo de encriptación para ser un usuario feliz!</p> </li> </ul> </li> <li> <a href=\"http://www.clipperz.com\" target=\"_blank\">Aprender más</a> </li> </ul> ",
31 'loginFormTitle':"ingrese con su usuario Clipperz",
32 'loginFormUsernameLabel':"usuario",
33 'loginFormPassphraseLabel':"frase clave",
34 'loginFormDontHaveAnAccountLabel':"¿no tiene una cuenta?",
35 'loginFormCreateOneLabel':"crear una",
36 'loginFormForgotYourCredentialsLabel':"¿perdió sus credenciales?",
37 'loginFormAarghThatsBadLabel':"¡Ahhh! ¡eso es malo!",
38 'loginFormAfraidOfMaliciousScriptsLabel':"¿evitar scripts maliciosos?",
39 'loginFormVerifyTheCodeLabel':"verificar el código",
40 'loginFormButtonLabel':"Ingresar",
41 'loginFormOneTimePasswordCheckboxLabel':"usar una frase clave desechable",
42 'loginPanelSwithLanguageDescription':"<h5>Cambiar a su lenguaje preferido</h5> ",
43 'browserCompatibilityDescription':"<p>Obtenga una mejor y más segura experiencia con Firefox. De todas maneras Clipperz funciona también con Opera y MS Explorer!</p> ",
44 'OTPloginMessagePanelInitialTitle':"Ingresar usando una frase clave desechable",
45 'OTPloginMessagePanelInitialText':"Enviando credenciales OTP ...",
46 'OTPloginMessagePanelLoadingTitle':"Ingresar usando una frase clave desechable",
47 'OTPloginMessagePanelLoadingText':"Descargando datos de autenticación encriptados desde el servidor ...",
48 'OTPloginMessagePanelProcessingTitle':"Ingresar usando una frase clave desechable",
49 'OTPloginMessagePanelProcessingText':"Desencriptación local de datos de autenticación ...",
50 'loginMessagePanelInitialTitle':"Ingresando ...",
51 'loginMessagePanelInitialButtonLabel':"Cancelar",
52 'loginMessagePanelConnectedTitle':"Conectado",
53 'loginMessagePanelConnectedText':"Hecho",
54 'loginMessagePanelFailureTitle':"Error",
55 'loginMessagePanelFailureText':"Ingreso fallido",
56 'loginMessagePanelFailureButtonLabel':"Cerrar",
57 'connectionLoginSendingCredentialsMessageTitle':"Verificando credenciales",
58 'connectionLoginSendingCredentialsMessageText':"Enviando credenciales",
59 'connectionLoginCredentialsVerificationMessageTitle':"Verificando credenciales",
60 'connectionLoginCredentialsVerificationMessageText':"Realizando una autenticación SRP",
61 'connectionLoginDoneMessageTitle':"Verificando credenciales",
62 'connectionLoginDoneMessageText':"Conectado",
63 'userLoginPanelUpgradingUserCredentialsMessageTitle':"Verificando credenciales",
64 'userLoginPanelUpgradingUserCredentialsMessageText':"Actualizando sus credenciales al nuevo esquema de autenticación",
65 'userLoginPanelConnectedMessageTitle':"Usuario autenticado",
66 'userLoginPanelConnectedMessageText':"Exitosamente logueado",
67 'userLoginPanelTryingAnOlderConnectionSchemaMessageTitle':"Verifying credentials",
68 'userLoginPanelTryingAnOlderConnectionSchemaMessageText':"Probando un esquema de autenticación antiguo",
69 'userLoginPanelLoadingUserDataMessageTitle':"Usuario autenticado",
70 'userLoginPanelLoadingUserDataMessageText':"Descargando encabezamientos encriptados desde Clipperz",
71 'userLoginPanelDecryptingUserDataMessageTitle':"Usuario autenticado",
72 'userLoginPanelDecryptingUserDataMessageText':"Desencriptación local de datos",
73 'userLoginPanelDecryptingUserStatisticsMessageTitle':"Usuario autenticado",
74 'userLoginPanelDecryptingUserStatisticsMessageText':"Desencriptación local de estadísticas de uso",
75 'splashAlertTitle':"¡Bienvenido a Clipperz!",
76 'splashAlertText':"<p>Algunas advertencias sobre seguridad</p> <ul> <li> <p>Almacenar sus datos en Clipperz es tan seguro como la frase clave que usted elija para protegerlos. Nadie puede acceder a ellos a no ser que conozca la frase clave.</p> </li> <li> <p>Si usted va a usar Clipperz para guardar información sensible y crítica, esté seguro de elegir una frase clave fuerte. ¡Cuanto más larga mejor!</p> </li> <li> <p>Clipperz no le permitirá recuperar una frase clave perdida.</p> </li> </ul> <p>Si necesita más información, por favor visite el sitio de <a href=\"http://www.clipperz.com\" target=\"_blank\">Clipperz</a>.</p> ",
77 'splashAlertCloseButtonLabel':"Aceptar",
78 'registrationFormTitle':"Abrir su cuenta",
79 'registrationFormUsernameLabel':"usuario",
80 'registrationFormPassphraseLabel':"frase clave",
81 'registrationFormRetypePassphraseLabel':"reingrese la frase clave",
82 'registrationFormSafetyCheckLabel':"Yo entiendo que Clipperz no me permite recuperar frases clave perdidas",
83 'registrationFormTermsOfServiceCheckLabel':"He leído y estoy de acuerdo con los <a href='http://www.clipperz.com/terms_of_service' target='_blank'>Términos de Servicio</a>.",
84 'registrationFormDoYouAlreadyHaveAnAccountLabel':"¿usted ya tiene una cuenta?",
85 'registrationFormSimplyLoginLabel':"ingreso simple",
86 'registrationFormButtonLabel':"Registrarse",
87 'registrationFormWarningMessageNotMatchingPassphrases':"Su frase clave no coincide, por favor reescríbala.",
88 'registrationFormWarningMessageSafetyCheckNotSelected':"Por favor, lea y chequee todas las casillas debajo.",
89 'registrationFormWarningMessageTermsOfServiceCheckNotSelected':"Usted necesita estar de acuerdo con los Términos de Servicio.",
90 'registrationMessagePanelInitialTitle':"Creando cuenta ...",
91 'registrationMessagePanelInitialButtonLabel':"Cancelar",
92 'registrationMessagePanelRegistrationDoneTitle':"Registración",
93 'registrationMessagePanelRegistrationDoneText':"Hecho",
94 'registrationMessagePanelFailureTitle':"Registración fallada",
95 'registrationMessagePanelFailureButtonLabel':"Cerrar",
96 'connectionRegistrationSendingRequestMessageText':"Verificando credenciales",
97 'connectionRegistrationSendingCredentialsMessageText':"Enviando credenciales",
98 'registrationSplashPanelTitle':"Aviso de seguridad",
99 'registrationSplashPanelDescriptionConfig':"<p>Estas son sus credenciales de Clipperz, cuídelas. ¡Clipperz nunca más le mostrará su cuenta y frase clave por segunda vez!</p> ",
100 'registrationSplashPanelUsernameLabel':"usuario",
101 'registrationSplashPanelPassphraseLabel':"frase clave",
102 'registrationSplashPanelShowPassphraseButtonLabel':" mostrar frase clave",
103 'donateHeaderLinkLabel':"donaciones",
104 'creditsHeaderLinkLabel':"créditos",
105 'feedbackHeaderLinkLabel':"contacto",
106 'helpHeaderLinkLabel':"ayuda",
107 'forumHeaderLinkLabel':"foro",
108 'recordMenuLabel':"tarjetas",
109 'accountMenuLabel':"cuenta",
110 'dataMenuLabel':"datos",
111 'contactsMenuLabel':"contactos",
112 'toolsMenuLabel':"herramientas",
113 'logoutMenuLabel':"salir",
114 'lockMenuLabel':"bloquear",
115 'lockTitle':"La cuenta está bloqueada",
116 'lockDescriptionConfig':"<p>Para desbloquear su cuenta, por favor ingrese su frase clave</p> ",
117 'unlockButtonLabel':"desbloquear",
118 'changePasswordTabLabel':"Cambiar su frase clave",
119 'changePasswordTabTitle':"Cambiar su frase clave",
120 'changePasswordFormUsernameLabel':"usuario",
121 'changePasswordFormOldPassphraseLabel':"frase clave anterior",
122 'changePasswordFormNewPassphraseLabel':"nueva frase clave",
123 'changePasswordFormRetypePassphraseLabel':"reingrese su nueva frase clave",
124 'changePasswordFormSafetyCheckboxLabel':"Yo entiendo que Clipperz no me permite recuperar una frase clave perdida.",
125 'changePasswordFormSubmitLabel':"Cambiar",
126 'changePasswordFormWrongUsernameWarning':"Usuario incorrecto",
127 'changePasswordFormWrongPassphraseWarning':"Frase clave incorrecta",
128 'changePasswordFormWrongRetypePassphraseWarning':"Sus frases claves no coinciden, por favor reescríbalas.",
129 'changePasswordFormSafetyCheckWarning':"Por favor lea y seleccione la casilla de abajo.",
130 'changePasswordFormProgressDialogTitle':"Cambiando credenciales de usuario",
131 'changePasswordFormProgressDialogConnectedMessageTitle':"Conectado",
132 'changePasswordFormProgressDialogConnectedMessageText':"Hecho",
133 'changePasswordFormProgressDialogErrorMessageTitle':"Error",
134 'changePasswordFormProgressDialogErrorMessageText':"¡Cambio de credenciales fallado!",
135 'changeCredentialsPanelEncryptingDataMessageTitle':"Cambiando su frase clave",
136 'changeCredentialsPanelEncryptingDataMessageText':"Encriptación local de encabezados de tarjetas",
137 'changeCredentialsPanelCreatingNewCredentialsMessageTitle':"Cambiando su frase clave",
138 'changeCredentialsPanelCreatingNewCredentialsMessageText':"Actualizando su credenciales",
139 'changeCredentialsPanelSendingNewCredentialsToTheServerMessageTitle':"Cambiando su frase clave",
140 'changeCredentialsPanelSendingNewCredentialsToTheServerMessageText':"Subiendo sus credenciales encriptadas a Clipperz",
141 'changeCredentialsPanelDoneMessageTitle':"Cambiando su frase clave",
142 'changeCredentialsPanelDoneMessageText':"Hecho",
143 'manageOTPTabLabel':"Administrar su frases clave desechables",
144 'manageOTPTabTitle':"Administrar su frases clave desechables",
145 'manageOTPTabDescription':"<p>Una frase clave desechable uso funciona como una frase clave regular, pero puede ser usada solo una vez.</p> <p>Si las misma frase clave es usada nuevamente en un segundo intento de acceso, esta será rechazada y el proceso de acceso fallará.</p> <p>Inmediatamente después de un acceso exitoso, su on-time frase clave será borrada previniendo accesos fraudulentos.</p> <p>Frases claves desechables son una excelente elección para protegerse de keyloggers y spywares, que pueden recolectar datos desde máquinas comprometidas.</p> <p> <b>Le recomendamos muy fuertemente que use frases claves desechables uso cuando acceda a Clipperz desde terminales públicas, como Internet Cafés, Cybercafés y bibliotecas.</b> </p> ",
146 'oneTimePasswordReadOnlyMessage':"<h6>¡Disculpe!</h6> <p>Usted no puede usar su frases clave desechables mientras usa la versión fuera de línea de Clipperz.</p> ",
147 'oneTimePasswordLoadingMessage':"<h6>Cargando datos</h6> <p>Por favor espere ...</p> ",
148 'oneTimePasswordNoPasswordAvailable':"<h6>No hay frase clave desechables disponible</h6> <p>Haga click en el botón “Nueva” para agregar una frase clave desechables a su cuenta.</p> ",
149 'createNewOTPButtonLabel':"Nueva",
150 'deleteOTPButtonLabel':"Borrar",
151 'printOTPButtonLabel':"Imprimir",
152 'disabledOneTimePassword_warning':"desabilitado",
153 'oneTimePasswordSelectionLink_selectLabel':"Seleccionar:",
154 'oneTimePasswordSelectionLink_all':"todo",
155 'oneTimePasswordSelectionLink_none':"ninguna",
156 'oneTimePasswordSelectionLink_used':"usada",
157 'oneTimePasswordSelectionLink_unused':"sin uso",
158 'saveOTP_encryptUserDataTitle':"Guardando frase clave desechable",
159 'saveOTP_encryptUserDataText':"Procesando nuevas credenciales OTP ...",
160 'saveOTP_encryptOTPDataTitle':"Guardando frase clave desechable",
161 'saveOTP_encryptOTPDataText':"Encriptación local de datos de autenticación ...",
162 'saveOTP_sendingDataTitle':"Guardando frase clave desechable",
163 'saveOTP_sendingDataText':"Enviando datos de autenticación al servidor ...",
164 'saveOTP_updatingInterfaceTitle':"Guardando frase clave desechable",
165 'saveOTP_updatingInterfaceText':"Actualizando interface ...",
166 'accountPreferencesLabel':"Preferencias",
167 'accountPreferencesTabTitle':"Preferencias",
168 'accountPreferencesLanguageTitle':"Seleccione el lenguaje",
169 'accountPreferencesLanguageDescription':"<p>Elija su lenguaje preferido de la siguiente lista.<p> ",
170 'showDonationReminderPanelTitle':"Recordatorios de donaciones",
171 'showDonationReminderPanelDescription':"<p>Mostrar recordatorios de donaciones</p> ",
172 'accountPreferencesInterfaceTitle':"Personalización de la interface",
173 'accountPreferencesInterfaceDescription':"<p>Ajuste Clipperz a sus necesidades.</p> ",
174 'saveUserPreferencesFormSubmitLabel':"Guardar",
175 'cancelUserPreferencesFormSubmitLabel':"Cancelar",
176 'accountPreferencesSavingPanelTitle_Step1':"Guardando preferencias",
177 'accountPreferencesSavingPanelText_Step1':"Encriptación local de sus preferencias",
178 'accountPreferencesSavingPanelTitle_Step2':"Guardando preferencias",
179 'accountPreferencesSavingPanelText_Step2':"Enviando preferencias encriptadas a Clipperz",
180 'accountLoginHistoryLabel':"Historial de accesos",
181 'loginHistoryTabTitle':"Historial de accesos",
182 'loginHistoryReadOnlyMessage':"<h6>¡Perdón!</h6> <p>El historial de acceso no está disponible mientras usa la versión fuera de línea de Clipperz.</p> ",
183 'loginHistoryLoadingMessage':"<h6>Cargando datos</h6> <p>Por favor espere ...</p> ",
184 'loginHistoryLoadedMessage':"<h6>Sus últimos 10 accesos</h6> <p> </p> ",
185 'loginHistoryIPLabel':"IP",
186 'loginHistoryTimeLabel':"fecha",
187 'loginHistoryCurrentSessionText':"sesión actual",
188 'loginHistoryReloadButtonLabel':"Refrescar historial de acceso",
189 'deleteAccountTabLabel':"Borrar su cuenta",
190 'deleteAccountTabTitle':"Borrar su cuenta",
191 'deleteAccountFormUsernameLabel':"usuario",
192 'deleteAccountFormPassphraseLabel':"frase clave",
193 'deleteAccountFormSafetyCheckboxLabel':"Yo entiendo que todos mis datos serán borrados y que esta acción es irreversible.",
194 'deleteAccountFormSubmitLabel':"Borrar mi cuenta",
195 'deleteAccountFormWrongUsernameWarning':"Usuario incorrecto",
196 'deleteAccountFormWrongPassphraseWarning':"Frase clave incorrecta",
197 'deleteAccountFormSafetyCheckWarning':"Por favor, léa y marque la opción debajo.",
198 'accountPanelDeletingAccountPanelConfirmationTitle':"ATENCIÓN",
199 'accountPanelDeleteAccountPanelConfirmationText':"¿Esta Ud. seguro que desea borrar esta cuenta?",
200 'accountPanelDeleteAccountPanelConfirmButtonLabel':"Sí",
201 'accountPanelDeleteAccountPanelDenyButtonLabel':"No",
202 'offlineCopyTabLabel':"Copia fuera de línea",
203 'offlineCopyTabTitle':"Copia fuera de línea",
204 'offlineCopyTabDescription':"<p>Con solo un clik usted puede descargar todos sus datos encriptados desde los servidores de Clipperz a su disco rígido y crear una versión solo-lectura fuera de línea para ser usada cuando usted no está conectado a Internet.</p> <p>La versión solo-lectura es tan segura como la lectura-escritura y no expondrá sus datos a mayores riegos desde el momento que ambas comparten el mismo código y arquitectura de seguridad.</p> <ol> <li> <p>Haga click en el link debajo para comenzar la descarga.</p> </li> <li> <p>El navegador le preguntará que hacer con el archivo “Clipperz_YYYYMMDD.html”. Guárdelo en su disco rígido.</p> </li> <li> <p>Haga doble click en el archivo descargado para ejecutar la versión fuera de línea en su navegador.</p> </li> <li> <p>Ingrese el usuario y la frase clave habitual.</p> </li> </ol> ",
205 'offlineCopyDownloadLinkLabel':"Descargar",
206 'offlineCopyDownloadWarning':"<h4> <a href=\"#\" id=\"offlineCopyDownloadWarningLink\">¡Actualize su “copia fuera de línea”!</a> </h4> <p>Usted ha recientemente creado o modificado una o más tarjetas, podría ser necesario que realize una nueva “copia fuera de línea”.</p> ",
207 'sharingTabLabel':"Compartir",
208 'sharingTabTitle':"Compartir",
209 'sharingTabDescription':"<p>Muy frecuentemente una pieza de información confidencial necesita ser compartida con una o más personas.</p> <p>Esto debería ser tan simple como darle a sus colegas el accese al código de su casilla de voz cuando está fuera de la oficina, o tan complicado con habilitarles a sus herederos el derecho de acceder a su caja de seguridad en su banco.</p> <p>Clipperz puede permitirle compartir sus secretos de una forma segura y directa.</p> <p> </p> <p> <b>Proximamente ...</b> </p> ",
210 'importTabLabel':"Importar",
211 'importTabTitle':"Importar",
212 'importTabDescription':"<p> <b>Proximamente ...</b> </p> ",
213 'printingTabLabel':"Exportar",
214 'printingTabTitle':"Exportar",
215 'printingTabDescription':"<p> <b>Imprima sus datos</b> </p> <p>Haciendo click en el enlace que sigue se abrirá una nueva ventana mostrando todas sus tarjetas en un formato imprimible.</p> <p>Si usted está imprimiendo con propósitos de respaldo, por favor considere la opción más segura provista por la creación de una “copia fuera de línea”.</p> ",
216 'printingLinkLabel':"Versión imprimible",
217 'contactsTabLabel':"Contactos",
218 'contactsTabTitle':"Contactos",
219 'passwordGeneratorTabLabel':"Generador de contraseñas",
220 'passwordGeneratorTabTitle':"Generador de contraseñas",
221 'paswordGeneratorTabDescriptionConfig':"<p> </p> ",
222 'passwordGeneratorTabButtonLabel':"Generar contraseña",
223 'bookmarkletTabLabel':"Bookmarklet",
224 'bookmarkletTabTitle':"Bookmarklet",
225 'bookmarkletTabDescription':"<p>Un bookmarklet es una simple herramienta de \"un click\" que puede realizar tareas muy útiles. Este puede ser grabado y usado como un marcador normal de una página web.</p> <p>El Clipperz bookmarklet le ayudará a usted a crear rapidamente tarjetas nuevas y accesos directos dentro de las tarjetas existentes.</p> <p> <b>Por favor tenga en cuenta que el bookmarklet no incluye ninguna información relacionadas con su cuenta (ej: su nombre de usuario o clave), el bookmarklet es una herramienta general que contiene el mismo código para todos los usuarios de Clipperz.</b> </p> <h3>How to install the bookmarklet</h3> <h5>Firefox, Camino, Opera, Safari</h5> <ol> <li> <p>Asegúrese que la “Barra de marcadores” está mostrada seleccionando “Ver > Barra de herramientas > Barra de marcadores”, menú similar, desde el menú del navegador.</p> </li> <li> <p>Arrastre el enlace “Agregar a Clipperz” sobre la barra de marcadores.</p> </li> </ol> <h5>Internet Explorer</h5> <ol> <li> <p>Asegúrese que la barra “Vínculos” es mostrada seleccionando “Ver > Barra de Herramientas > Herramientas > Vínculos” desde el menú del navegador.</p> </li> <li> <p>Haga click con el botón derecho del mouse en el link “Agregar a Clipperz”.</p> </li> <li> <p>Seleccione “Agregar a favoritos” desde el menú contextual.</p> </li> <li> <p>Haga click en “Si” o “Acepto” a cualquier advertencia de seguridad que le aparezca.</p> </li> <li> <p>Abra la carpeta “Vínculos” y haga click en “OK”</p> </li> </ol> ",
226 'bookmarkletTabBookmarkletTitle':"Agregar a Clipperz",
227 'bookmarkletTabInstructions':"<h3>Como crear una nueva tarjeta que incluya un enlace de “acceso directo” a un servicio en línea.</h3> <ol> <li> <p>Abra una página web dónde el formulario de logueo está almacenado (es la página donde usualmente ingresa sus credenciales firmadas)</p> </li> <li> <p>Ejecute el bookmarklet haciendo click en éste: una ventana emergente (pop-up) aparecerá sobre la página web.</p> </li> <li> <p>Copie al portapapeles el contenido de todo el texto dentro de la ventana emergente (pop-up) (Ctrl-C)</p> </li> <li> <p>Ingrese en su cuenta Clipperz y haga click en el botón <b>Agregar nueva tarjeta</b>.</p> </li> <li> <p>Seleccione la plantilla “Acceso directo” y pegue el contenido del portapapeles en el formulario (Ctrl-V)</p> </li> <li> <p>Haga click en el botón <b>Crear</b>, revise los datos y luego haga click en <b>Guardar</b>.</p> </li> </ol> <h3>Cómo agregar un enlace “acceso directo” a una tarjeta existente</h3> <ol> <li> <p>Igual que arriba.</p> </li> <li> <p>Igual que arriba.</p> </li> <li> <p>Igual que arriba.</p> </li> <li> <p>Ingrese en su cuenta Clipperz y seleccione una tarjeta conteniendo las credenciales de un servicio web que usted visitó y haga click en el botón <b>Editar</b>.</p> </li> <li> <p>Pegue el contenido del portapapeles en el área de texto de la sección “Acceso directo” (Ctrl-V)</p> </li> <li> <p>Haga click en el botón <b>Agregar acceso directo</b>, revise los detalles y luego haga click en <b>Guardar</b>.</p> </li> </ol> <p> </p> <p>Más información sobre bookmarklet está <a href=\"http://www.clipperz.com/support/user_guide/bookmarklet\" target=\"_blank\">disponible aquí</a>.</p> ",
228 'mainPanelDirectLoginBlockLabel':"Accesos directos",
229 'directLinkReferenceShowButtonLabel':"ver",
230 'mainPanelDirectLoginBlockDescription':"<p>¡ Agregar “accesos directos” para ingresar en sus cuentas de la web sin necesidad de escribir nombres de usuarios o claves!</p> <p>“Accesos directos” incrementa notablemente la seguridad de sus claves desde que ud. puede:</p> <ul> <li> <p>usar claves complejas con comodidad;</p> </li> <li> <p>nunca más reusar la misma clave simple.</p> </li> </ul> <p> </p> <a href=\"http://www.clipperz.com/support/user_guide/direct_logins\" target=\"_blank\">Apreender más sobre “accesos directos”</a> ",
231 'mainPanelRecordsBlockLabel':"Tarjetas",
232 'mainPanelAddRecordButtonLabel':"Agregar tarjeta nueva",
233 'mainPanelRemoveRecordButtonLabel':"Borrar tarjeta",
234 'mainPanelRecordFilterBlockAllLabel':"todo",
235 'mainPanelRecordFilterBlockTagsLabel':"tags",
236 'mainPanelRecordFilterBlockSearchLabel':"buscar",
237 'recordDetailNoRecordAtAllTitle':"¡Bienvenido a Clipperz!",
238 'recordDetailNoRecordAtAllDescription':"<h5>Comienze agregando tarjetas a su cuenta.</h5> <p>Tarjetas son formularios simples y flexibles donde Usted puede almacenar sus claves y cualquier otro dato confidencial.</p> <p>Tarjetas pueden contener credenciales para acceder a un sitio web, la conbinación del candado de su bicicleta, detalles de su tarjeta de crédito, ....</p> <h5>¡No olvide los bookmarklet!</h5> <p>Antes de comenzar, instale el “Agregar a Clipperz” bookmarklet: esta hará la creación de tarjetas más fácil y más divertida.</p> <p>Vaya al marcador “herramientas” para descubrir como instalar y usarlo.</p> <p> </p> <p>Luego simplemente haga click en el botón “Agregar nueva tarjeta” y disfrute su cuenta Clipperz.</p> <p> </p> <a href=\"http://www.clipperz.com/support/user_guide/managing_cards\" target=\"_blank\">Apreender más acerca de la creación y administración de las tarjetas</a> ",
239 'newRecordWizardTitleBox':"<h5>Por favor seleccione una plantilla</h5> <p>Tarjetas son formularios simples y flexibles donde usted puede almacenar claves y cualquier otro dato confidencial.</p> <p>Comienze eligiendo una de las plantillas que se encuentran debajo. Usted siempre puede personalizar sus tarjetas más tarde agregando o borrando campos.</p> ",
240 'newRecordWizardBookmarkletConfigurationTitle':"Acceso directo",
241 'newRecordWizardBookmarkletConfigurationDescription':"<p>Pegue debajo el código de configuración generado por el bookmarklet Clipperz.</p> <p>Una nueva tarjeta con un acceso directo a su cuenta web será creada.</p> ",
242 'newRecordWizardCreateButtonLabel':"Crear",
243 'newRecordWizardCancelButtonLabel':"Cancelar",
244 'donateSplashPanelTitle':"¡Apoye a Clipperz, haga una donación hoy!",
245 'donateSplashPanelDescription':"<p>Una pocas buenas razones para hacer una donación:</p> <ul> <li> <p>apoyar el desarrollo de nuevas utilidades</p> </li> <li> <p>mantener Clipperz gratuito</p> </li> <li> <p>mostrar su aprecio por nuestro duro trabajo</p> </li> </ul> <p>Por cualquier información adicional, por favor visite nuestra <a href=\"http://www.clipperz.com/donations\" target=\"_blank\">página de donaciones</a>.</p> <p> <b>¿Listo para hacer una donación?</b> </p> ",
246 'donateCloseButtonLabel':"No todavía",
247 'donateDonateButtonLabel':"Si",
248 'recordTemplates':{
249 'WebAccount':{
250 'title':"Contraseña web",
251 'description':"<p>Una simple tarjeta para almacenar sus credenciales de acceso a sus servicios online.</p> ",
252 'fields':{
253 'URL':"Dirección web",
254 'TXT':"Usuario o correo electrónico",
255 'PWD':"Contraseña"
256 }
257 },
258 'BankAccount':{
259 'title':"Cuenta bancaria",
260 'description':"<p>Almacene en forma segura su número de cuenta bancaria y credenciales de servicios bancarios en línea.</p> ",
261 'fields':{
262 'TXT':"Banco",
263 'TXT':"Número de cuenta",
264 'URL':"Sitio web del Banco",
265 'TXT':"ID del servicio bancario en línea",
266 'PWD':"Contraseña del servicio bancario en línea"
267 }
268 },
269 'CreditCard':{
270 'title':"Tarjeta de crédito",
271 'description':"<p>Número de tarjeta, fecha de vencimiento, CVV2 y PIN siempre a mano con Clipperz.</p> ",
272 'fields':{
273 'TXT':"Tipo (Visa, AmEx, ...)",
274 'TXT':"Número",
275 'TXT':"Nombre del propietario",
276 'TXT':"Fecha de vencimiento",
277 'TXT':"CVV2",
278 'PWD':"PIN cajero automático",
279 'URL':"Sitio web tarjeta",
280 'TXT':"Usuario",
281 'PWD':"Contraseña"
282 }
283 },
284 'AddressBookEntry':{
285 'title':"Libreta de direcciones",
286 'description':"<p>Clipperz puede también funcionar como su nueva libreta privada de direcciones. Use esta plantilla para crear fácilmente nuevas entradas.</p> ",
287 'fields':{
288 'TXT':"Nombre",
289 'TXT':"Correo electrónico",
290 'TXT':"Teléfono",
291 'TXT':"Móvil",
292 'ADDR':"Dirección"
293 }
294 },
295 'Custom':{
296 'title':" Tarjeta personalizada",
297 'description':"<p>No importa que tipo de dato confidencial usted necesita proteger, puede crear la tarjeta que necesite.</p> ",
298 'fields':{
299 'TXT':"Etiqueta 1",
300 'TXT':"Etiqueta 2",
301 'TXT':"Etiqueta 3"
302 }
303 }
304},
305 'recordFieldTypologies':{
306 'TXT':{
307 'description':"simple text field",
308 'shortDescription':"texto"
309 },
310 'PWD':{
311 'description':"simple text field, with default status set to hidden",
312 'shortDescription':"contraseña"
313 },
314 'URL':{
315 'description':"simple text field in edit mode, that became an active url in view mode",
316 'shortDescription':"dirección web"
317 },
318 'DATE':{
319 'description':"a value set with a calendar helper",
320 'shortDescription':"fecha"
321 },
322 'ADDR':{
323 'description':"just like the URL, but the active link points to Google Maps (or similar service) passing the address value as argument",
324 'shortDescription':"dirección postal"
325 },
326 'CHECK':{
327 'description':"check description",
328 'shortDescription':"check"
329 },
330 'RADIO':{
331 'description':"radio description",
332 'shortDescription':"radio"
333 },
334 'SELECT':{
335 'description':"select description",
336 'shortDescription':"select"
337 }
338},
339 'newRecordPanelGeneralExceptionTitle':"Error",
340 'newRecordPanelGeneralExceptionMessage':"El texto de configuración no es válido. Asegúrese que toma su texto desde la ventana emergente del bookmarklet.",
341 'newRecordPanelWrongBookmarkletVersionExceptionTitle':"Error",
342 'newRecordPanelWrongBookmarkletVersionExceptionMessage':"El texto de configuración ha sido generado por una versión anterior de bookmarklet. Por favor actualize su bookmarklet y pruebe nuevamente.",
343 'newRecordPanelExceptionPanelCloseButtonLabel':"Cancelar",
344 'mainPanelDeletingRecordPanelConfirmationTitle':"Eliminando tarjeta seleccionada",
345 'mainPanelDeleteRecordPanelConfirmationText':"¿Desea realmente eliminar la tarjeta seleccionada?",
346 'mainPanelDeleteRecordPanelConfirmButtonLabel':"Sí",
347 'mainPanelDeleteRecordPanelDenyButtonLabel':"No",
348 'mainPanelDeletingRecordPanelInitialTitle':"Eliminando tarjeta seleccionada",
349 'mainPanelDeletingRecordPanelCompletedText':"Hecho",
350 'deleteRecordPanelCollectRecordDataMessageTitle':"Eliminar tarjeta",
351 'deleteRecordPanelCollectRecordDataMessageText':"Actualizando lista de tarjetas",
352 'deleteRecordPanelEncryptUserDataMessageTitle':"Eliminar tarjeta",
353 'deleteRecordPanelEncryptUserDataMessageText':"Encriptación local de encabezamiento de tarjetas",
354 'deleteRecordPanelSendingDataToTheServerMessageTitle':"Eliminar tarjeta",
355 'deleteRecordPanelSendingDataToTheServerMessageText':"Subiendo encabezamiento de tarjetas encriptadas a Clipperz",
356 'deleteRecordPanelUpdatingTheInterfaceMessageTitle':"Eliminar tarjeta",
357 'deleteRecordPanelUpdatingTheInterfaceMessageText':"Actualizando interface",
358 'recordDetailNoRecordSelectedTitle':"No hay tarjetas seleccionadas",
359 'recordDetailNoRecordSelectedDescription':"<p>Por favor seleccione una tarjeta de la lista de la izquierda.</p> ",
360 'recordDetailLoadingRecordMessage':"Descargando tarjetas encriptadas desde Clipperz",
361 'recordDetailDecryptingRecordMessage':"Desencriptación local de los datos de las tarjetas",
362 'recordDetailLoadingRecordVersionMessage':"Descargando última versión de la tarjeta",
363 'recordDetailDecryptingRecordVersionMessage':"Desencriptación local de la última versión",
364 'recordDetailLoadingErrorMessageTitle':"Error mientras descargaba la tarjeta",
365 'recordDetailNotesLabel':"Notas",
366 'recordDetailLabelFieldColumnLabel':"Campo título",
367 'recordDetailDataFieldColumnLabel':"Campo de datos",
368 'recordDetailTypeFieldColumnLabel':"Tipo",
369 'recordDetailSavingChangesMessagePanelInitialTitle':"Guardando tarjeta",
370 'recordDetailAddFieldButtonLabel':"Agregar nuevo campo",
371 'recordDetailPasswordFieldHelpLabel':"para copiar la contraseña al portapapeles, haga click en la estrella y luego Ctrl-C",
372 'recordDetailPasswordFieldScrambleLabel':"ocultar",
373 'recordDetailPasswordFieldUnscrambleLabel':"mostrar",
374 'recordDetailDirectLoginBlockTitle':"Acceso directos",
375 'recordDetailNewDirectLoginDescription':"<p>Configuración de los accesos directos</p> ",
376 'recordDetailDirectLoginBlockNoDirectLoginConfiguredDescription':"<p>¿Esta tarjeta contiene credenciales para acceder a un servicio en línea?</p> <p>¡Use los bookmarklet para configurar un \"acceso directo\" desde Clpperz con solo un click!</p> ",
377 'recordDetailAddNewDirectLoginButtonLabel':"Agregar nuevo acceso directo",
378 'recordDetailEditButtonLabel':"Editar",
379 'recordDetailSaveButtonLabel':"Guardar",
380 'recordDetailCancelButtonLabel':"Cancelar",
381 'newRecordTitleLabel':"_nueva tarjeta_",
382 'recordSaveChangesPanelCollectRecordInfoMessageTitle':"Guardar tarjeta",
383 'recordSaveChangesPanelCollectRecordInfoMessageText':"Actualizando encabezamiento de tarjetas",
384 'recordSaveChangesPanelEncryptUserDataMessageTitle':"Guardar tarjeta",
385 'recordSaveChangesPanelEncryptUserDataMessageText':"Encriptación local de encabezamiento de tarjetas",
386 'recordSaveChangesPanelEncryptRecordDataMessageTitle':"Guardar tarjeta",
387 'recordSaveChangesPanelEncryptRecordDataMessageText':"Encriptación local de los datos de la tarjeta",
388 'recordSaveChangesPanelEncryptRecordVersionDataMessageTitle':"Guardar tarjeta",
389 'recordSaveChangesPanelEncryptRecordVersionDataMessageText':"Encriptación local de la versión de los datos de la tarjeta",
390 'recordSaveChangesPanelSendingDataToTheServerMessageTitle':"Guardar tarjeta",
391 'recordSaveChangesPanelSendingDataToTheServerMessageText':"Subiendo encabezamiento de tarjeta encriptada a Clipperz",
392 'recordSaveChangesPanelUpdatingTheInterfaceMessageTitle':"Guardar tarjeta",
393 'recordSaveChangesPanelUpdatingTheInterfaceMessageText':"Actualizando la interface",
394 'passwordGeneratorPanelTitle':"Generador de contraseñas",
395 'passwordGeneratorPanelOkLabel':"Ok",
396 'passwordGeneratorPanelCancelLabel':"Cancelar",
397 'passwordGeneratorLengthLabel':"longitud:",
398 //'DWRUtilLoadingMessage':"Cargando datos ...",
399 'comingSoon':"próximamente ...",
400 'panelCollectingEntryopyMessageText':"Recogiendo entropía",
401 'directLoginConfigurationCheckBoxFieldSelectedValue':"Sí",
402 'directLoginConfigurationCheckBoxFieldNotSelectedValue':"No",
403 'WELCOME_BACK':"¡Bienvenido!",
404 'currentConnectionText':"Usted está ahora conectado desde ip&nbsp;__ip__, aparentemente desde __country__, usando __browser__ en __operatingSystem__.",
405 'latestConnectionText':"Su última conexión fue __elapsedTimeDescription__ (__time__) desde ip&nbsp;__ip__, aparentemente desde __country__, usando __browser__ en __operatingSystem__.",
406 'fullLoginHistoryLinkLabel':"mostrar historial de acceso",
407 'elapsedTimeDescriptions':{
408 'MORE_THAN_A_MONTH_AGO':"más de un mes atrás",
409 'MORE_THAN_A_WEEK_AGO':"más de una semana atrás",
410 'MORE_THAN_*_WEEKS_AGO':"más de __elapsed__ semanas atrás",
411 'YESTERDAY':"ayer",
412 '*_DAYS_AGO':"__elapsed__ días atrás",
413 'ABOUT_AN_HOUR_AGO':"about an hour ago",
414 '*_HOURS_AGO':"__elapsed__ hours ago",
415 'JUST_A_FEW_MINUTES_AGO':"hace unos minutos",
416 'ABOUT_*_MINUTES_AGO':"hace __elapsed__ minutos atrás"
417},
418 'unknown_ip':"desconocida",
419 'calendarStrings':{
420 'months':{
421 '0':"Enero",
422 '1':"Febrero",
423 '2':"Marzo",
424 '3':"Abril",
425 '4':"Mayo",
426 '5':"Junio",
427 '6':"Julio",
428 '7':"Agosto",
429 '8':"Setiembre",
430 '9':"Octubre",
431 '10':"Noviembre",
432 '11':"Diciembre"
433 },
434 'shortMonths':{
435 '0':"Ene",
436 '1':"Feb",
437 '2':"Mar",
438 '3':"Abr",
439 '4':"May",
440 '5':"Jun",
441 '6':"Jul",
442 '7':"Ago",
443 '8':"Set",
444 '9':"Oct",
445 '10':"Nov",
446 '11':"Dic"
447 },
448 'days':{
449 '0':"Domingo",
450 '1':"Lunes",
451 '2':"Martes",
452 '3':"Miércoles",
453 '4':"Jueves",
454 '5':"Viernes",
455 '6':"Sábado"
456 },
457 'shortDays':{
458 '0':"Dom",
459 '1':"Lun",
460 '2':"Mar",
461 '3':"Mie",
462 '4':"Jue",
463 '5':"Vie",
464 '6':"Sab"
465 },
466 'veryShortDays':{
467 '0':"Do",
468 '1':"Lu",
469 '2':"Ma",
470 '3':"Mi",
471 '4':"Ju",
472 '5':"Vi",
473 '6':"Sa"
474 },
475 'amDesignation':"am",
476 'pmDesignation':"pm"
477},
478
479__syntaxFix__: "syntax fix"
480});
diff --git a/frontend/beta/js/Clipperz/PM/Strings/Strings_fr-FR.js b/frontend/beta/js/Clipperz/PM/Strings/Strings_fr-FR.js
new file mode 100644
index 0000000..c137fb8
--- a/dev/null
+++ b/frontend/beta/js/Clipperz/PM/Strings/Strings_fr-FR.js
@@ -0,0 +1,362 @@
1/*
2
3Copyright 2008-2011 Clipperz Srl
4
5This file is part of Clipperz's Javascript Crypto Library.
6Javascript Crypto Library provides web developers with an extensive
7and efficient set of cryptographic functions. The library aims to
8obtain maximum execution speed while preserving modularity and
9reusability.
10For further information about its features and functionalities please
11refer to http://www.clipperz.com
12
13* Javascript Crypto Library is free software: you can redistribute
14 it and/or modify it under the terms of the GNU Affero General Public
15 License as published by the Free Software Foundation, either version
16 3 of the License, or (at your option) any later version.
17
18* Javascript Crypto Library is distributed in the hope that it will
19 be useful, but WITHOUT ANY WARRANTY; without even the implied
20 warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
21 See the GNU Affero General Public License for more details.
22
23* You should have received a copy of the GNU Affero General Public
24 License along with Javascript Crypto Library. If not, see
25 <http://www.gnu.org/licenses/>.
26
27*/
28
29Clipperz.PM.Strings.Languages['fr-FR'.toLowerCase()] = MochiKit.Base.merge(Clipperz.PM.Strings.Languages['en-us'], {
30 'clipperzServiceDescription':"<h2>Gardez le pour vous!</h2> <ul> <li> <h3>Clipperz est:</h3> <ul> <li> <p>un gestionnaire de mots de passe sécurisé</p> </li> <li> <p>une solution fiable d’authentification unique</p> </li> <li> <p>une chambre forte numérique pour vos données confidentielles</p> </li> </ul> </li> <li> <h3>Avec Clipperz vous pouvez:</h3> <ul> <li> <p>enregistrer et gérer vos mots de passe et autres informations d'identification en ligne</p> </li> <li> <p>vous identifier sur vos sites web sans avoir besoin de saisir votre nom d’utilisateur ou votre mot de passe</p> </li> <li> <p>protéger toutes vos données sensibles: codes d’alarmes, PINs (téléphone portable), carte de crédits, &hellip;</p> </li> <li> <p>partager certaines données confidentielles avec vos proches et vos associés (bientôt disponible!)</p> </li> </ul> </li> <li> <h3>Les avantages de Clipperz:</h3> <ul> <li> <p>c'est gratuit et totalement anonyme</p> </li> <li> <p>accéder à vos données depuis n’importe quel ordinateur</p> </li> <li> <p>vous n'avez besoin d'aucun logiciel et rien n'est à installer sur votre poste</p> </li> <li> <p>cela vous évite de garder des mots de passe sur votre PC ou sur des bouts de papier</p> </li> </ul> </li> <li> <h3>La sécurité de Clipperz:</h3> <ul> <li> <p>vos mots de passe sont localement chiffrés par votre navigateur avant d’être téléchargé à Clipperz</p> </li> <li> <p>la clé de cryptage est une phrase secrète détenue uniquement par vous même</p> </li> <li> <p>héberge vos données sensibles dans des formulaires cryptés et ne peuvent être consultées directement en clair</p> </li> <li> <p>est développé sur des standard de cryptage réputé sans aucune fantaisie ni de bricolage fait maison</p> </li> <li> <p>vous pouvez consulter le code source autant que vous le souhaitez</p> </li> </ul> </li> <li> <a href=\"http://www.clipperz.com\" target=\"_blank\">Plus d’informations</a> </li> </ul> ",
31 'loginFormTitle':"identifiez-vous avec votre compte Clipperz",
32 'loginFormUsernameLabel':"nom d’utilisateur",
33 'loginFormPassphraseLabel':"phrase secrète",
34 'loginFormDontHaveAnAccountLabel':"vous n’avez pas de compte?",
35 'loginFormCreateOneLabel':"créez votre compte",
36 'loginFormForgotYourCredentialsLabel':"vous avez oublié votre certificat?",
37 'loginFormAarghThatsBadLabel':"c’est fort dommage pour vous!",
38 'loginFormAfraidOfMaliciousScriptsLabel':"vous avez peur des script malicieux?",
39 'loginFormVerifyTheCodeLabel':"vérifiez le code",
40 'loginFormButtonLabel':"S’identifer",
41 'loginPanelSwithLanguageDescription':"<p>Sélectionnez votre langue préféré</p> ",
42 'browserCompatibilityDescription':"<p>Have a better and safer Clipperz experience with Firefox. However Clipperz works just fine also with Opera and MS Internet Explorer!</p> ",
43 'loginMessagePanelInitialTitle':"En cours d’identification ...",
44 'loginMessagePanelInitialButtonLabel':"Annuler",
45 'loginMessagePanelConnectedTitle':"Connecté",
46 'loginMessagePanelConnectedText':"Terminé",
47 'loginMessagePanelFailureTitle':"Erreur",
48 'loginMessagePanelFailureText':"Identification échoué",
49 'loginMessagePanelFailureButtonLabel':"Fermer",
50 'connectionLoginSendingCredentialsMessageTitle':"Vérification des identifiants",
51 'connectionLoginSendingCredentialsMessageText':"Envoi des identifiants",
52 'connectionLoginCredentialsVerificationMessageTitle':"Vérification des identifiants",
53 'connectionLoginCredentialsVerificationMessageText':"Authentification SRP en cours",
54 'connectionLoginDoneMessageTitle':"Vérification des identifiants",
55 'connectionLoginDoneMessageText':"Connecté",
56 'userLoginPanelUpgradingUserCredentialsMessageTitle':"Vérification des identifiants",
57 'userLoginPanelUpgradingUserCredentialsMessageText':"Mise à jour de vos identifiants à un nouveau schéma d’authentification",
58 'userLoginPanelConnectedMessageTitle':"Utilisateur identifié",
59 'userLoginPanelConnectedMessageText':"Vous vous êtes identifié avec succès",
60 'userLoginPanelTryingAnOlderConnectionSchemaMessageTitle':"Vérification des identifiants",
61 'userLoginPanelTryingAnOlderConnectionSchemaMessageText':"Nous essayons un ancien schéma d’authentification",
62 'userLoginPanelLoadingUserDataMessageTitle':"Utilisateur identifié",
63 'userLoginPanelLoadingUserDataMessageText':"Téléchargement des cartes d’en-têtes chiffrés depuis Clipperz",
64 'userLoginPanelDecryptingUserDataMessageTitle':"Utilisateur identifié",
65 'userLoginPanelDecryptingUserDataMessageText':"Décryptage local des en-têtes chiffrés",
66 'userLoginPanelDecryptingUserStatisticsMessageTitle':"Utilisateur identifié",
67 'userLoginPanelDecryptingUserStatisticsMessageText':"Décryptage local des statistiques",
68 'splashAlertTitle':"Bienvenue sur Clipperz!",
69 'splashAlertText':"<p>Conseils de sécurité</p> <ul> <li> <p>Le stockage de vos mots de passe sur Clipperz est aussi sécurisé que la phrase que vous avez sélectionnée pour les protéger. Personne ne peux y accéder tant que personne ne connait votre phrase secrète.</p> </li> <li> <p>Si vous allez utiliser Clipperz pour sauvegarder des informations sensibles et critiques assurez-vous d’utiliser une phrase secrète compliquée. Plus elle sera longue mieux ce sera!</p> </li> <li> <p>Clipperz ne sera pas capable de récupérer votre phrase secrète!</p> </li> </ul> <p>Pour toute autre information, veuillez vous référer au site <a href=\"http://www.clipperz.com\" target=\"_blank\">Clipperz</a>.</p> ",
70 'splashAlertCloseButtonLabel':"Ok",
71 'registrationFormTitle':"créer votre compte",
72 'registrationFormUsernameLabel':"nom d’utilisateur",
73 'registrationFormPassphraseLabel':"phrase secrète",
74 'registrationFormRetypePassphraseLabel':"re-saisissez votre phrase secrète",
75 'registrationFormSafetyCheckLabel':"J’accepte que Clipperz ne pourra pas récupérer ma phrase secrète.",
76 'registrationFormTermsOfServiceCheckLabel':"J’ai lu et j’accepte les <a href='http://www.clipperz.com/terms_of_service' target='_blank'>Conditions d’Utilisation du Service</a>.",
77 'registrationFormDoYouAlreadyHaveAnAccountLabel':"avez-vous déjà un compte?",
78 'registrationFormSimplyLoginLabel':"identifiez-vous",
79 'registrationFormButtonLabel':"S’inscrire",
80 'registrationFormWarningMessageNotMatchingPassphrases':"Vos phrases secrètes ne correspondent pas, veuillez les saisir à nouveau.",
81 'registrationFormWarningMessageSafetyCheckNotSelected':"Veuillez lire et cocher les cases-à-cocher ci-dessous.",
82 'registrationFormWarningMessageTermsOfServiceCheckNotSelected':"Vous devez accepter les “Conditions d’Utilisation du Service”.",
83 'registrationMessagePanelInitialTitle':"Création du compte en cours ...",
84 'registrationMessagePanelInitialButtonLabel':"Annuler",
85 'registrationMessagePanelRegistrationDoneTitle':"Enregistrement",
86 'registrationMessagePanelRegistrationDoneText':"Terminé",
87 'registrationMessagePanelFailureTitle':"Enregistrement échoué",
88 'registrationMessagePanelFailureButtonLabel':"Fermer",
89 'connectionRegistrationSendingRequestMessageText':"Vérification en cours des identifiants",
90 'connectionRegistrationSendingCredentialsMessageText':"Envoi des identifiants",
91 'registrationSplashPanelTitle':"Conseils de sécurité",
92 'registrationSplashPanelDescription':"<p>Ce sont vos identifiants Clipperz, gardez les biens. Clipperz ne va plus jamais vous montrer votre nom d’utilisateur et votre phrase secrète!</p> ",
93 'registrationSplashPanelUsernameLabel':"nom d’utilisateur",
94 'registrationSplashPanelPassphraseLabel':"phrase secrète",
95 'registrationSplashPanelShowPassphraseButtonLabel':"afficher la phrase secrète",
96 'donateHeaderLinkLabel':"faites un don",
97 'creditsHeaderLinkLabel':"crédits",
98 'feedbackHeaderLinkLabel':"votre avis",
99 'helpHeaderLinkLabel':"aide",
100 'forumHeaderLinkLabel':"forum",
101 'recordMenuLabel':"cartes",
102 'accountMenuLabel':"compte",
103 'dataMenuLabel':"données",
104 'contactsMenuLabel':"contacts",
105 'toolsMenuLabel':"outils",
106 'logoutMenuLabel':"déconnexion",
107 'lockMenuLabel':"verrouiller",
108 'lockTitle':"Le compte est verrouillé",
109 'lockDescription':"<p>Pour déverrouiller votre compte, veuillez saisir votre phrase secrète</p> ",
110 'unlockButtonLabel':"Déverrouiller",
111 'changePasswordTabLabel':"Changer votre phrase secrète",
112 'changePasswordTabTitle':"Changer votre phrase secrète",
113 'changePasswordFormUsernameLabel':"nom d’utilisateur",
114 'changePasswordFormOldPassphraseLabel':"ancienne phrase secrète",
115 'changePasswordFormNewPassphraseLabel':"nouvelle phrase secrète",
116 'changePasswordFormRetypePassphraseLabel':"re-saisissez phrase secrète",
117 'changePasswordFormSafetyCheckboxLabel':"Je sais que Clipperz ne pourra pas récupérer ma phrase secrète.",
118 'changePasswordFormSubmitLabel':"Changer ma phrase secrète",
119 'changePasswordFormWrongUsernameWarning':"Nom d’utilisateur incorrect",
120 'changePasswordFormWrongPassphraseWarning':"Phrase secrète incorrect",
121 'changePasswordFormWrongRetypePassphraseWarning':"Votre phrase secrète ne correspond pas, veuillez la saisir à nouveau",
122 'changePasswordFormSafetyCheckWarning':"Veuillez lire et cocher la case-à-cocher ci-dessous",
123 'changePasswordFormProgressDialogTitle':"Changement des identifiants utilisateurs",
124 'changePasswordFormProgressDialogConnectedMessageTitle':"Connecté",
125 'changePasswordFormProgressDialogConnectedMessageText':"Terminé",
126 'changePasswordFormProgressDialogErrorMessageTitle':"Erreur",
127 'changePasswordFormProgressDialogErrorMessageText':"Changement de identifiants échoué!",
128 'changeCredentialsPanelEncryptingDataMessageTitle':"Changement de votre phrase secrète",
129 'changeCredentialsPanelEncryptingDataMessageText':"Cryptage local des identifiants",
130 'changeCredentialsPanelCreatingNewCredentialsMessageTitle':"Modifier votre phrase secrète",
131 'changeCredentialsPanelCreatingNewCredentialsMessageText':"Mettre à jour vos identifiants",
132 'changeCredentialsPanelSendingNewCredentialsToTheServerMessageTitle':"Modifier votre phrase secrète",
133 'changeCredentialsPanelSendingNewCredentialsToTheServerMessageText':"Téléchargement de vos identifiants sur Clipperz.com",
134 'changeCredentialsPanelDoneMessageTitle':"Modifier votre phrase secrète",
135 'changeCredentialsPanelDoneMessageText':"Terminé",
136 'manageOTPTabLabel':"Mettre à jour votre phrase secrète à usage unique",
137 'manageOTPTabTitle':"Mettre à jour votre phrase secrète à usage unique",
138 'manageOTPTabDescription':"<p>Une phrase secrète à usage unique fonctionne comme votre phrase secrète habituelle, mais elle ne peut être utilisé qu'une seule fois.</p> <p>Si la phrase secrète est utilisé de nouveau et que vous tenté de vous identifier à nouveau, vous serez rejeté et le processus d'identification échouera.</p> <p>Juste après une identification correcte, votre phrase secrète à usage unique sera effacée pour interdire tout accès frauduleux.</p> <p>Les phrases secrètes à usage unique sont un excellent choix si vous craignez qu'un logiciel espion ne vole vos données après avoir infecté votre machine.</p> <p> <b>Il est fortement recommandé d'utiliser des phrases secrètes à usage unique lorsque vous accédez à Clipperz depuis un terminal public, comme un cybercafé ou une borne Internet.</b> </p> ",
139 'accountPreferencesLabel':"Préférences",
140 'accountPreferencesTabTitle':"Préférences",
141 'accountPreferencesLanguageTitle':"Choix de la langue",
142 'accountPreferencesLanguageDescription':"<p>Choisissez la langue d'affichage de Clipperz dans la liste suivante.</p> ",
143 'accountPreferencesInterfaceTitle':"Personnalisation de l'interface",
144 'accountPreferencesInterfaceDescription':"<p>Ajustez l'interface de Clipperz à vos besoins.</p> ",
145 'saveUserPreferencesFormSubmitLabel':"Enregistrer",
146 'cancelUserPreferencesFormSubmitLabel':"Annuler",
147 'accountPreferencesSavingPanelTitle_Step1':"Enregistrement des préférences",
148 'accountPreferencesSavingPanelText_Step1':"Chiffrement local de vos préférences",
149 'accountPreferencesSavingPanelTitle_Step2':"Enregistrement des préférences",
150 'accountPreferencesSavingPanelText_Step2':"Transmission des préférences chiffrées au serveur",
151 'deleteAccountTabLabel':"Supprimer votre compte",
152 'deleteAccountTabTitle':"Supprimer votre compte",
153 'deleteAccountFormUsernameLabel':"nom d’utilisateur",
154 'deleteAccountFormPassphraseLabel':"phrase secrète",
155 'deleteAccountFormSafetyCheckboxLabel':"Je sais que toute mes données seront supprimés et que cette action sera irréversible.",
156 'deleteAccountFormSubmitLabel':"Supprimer mon compte",
157 'deleteAccountFormWrongUsernameWarning':"Nom d’utilisateur incorrect",
158 'deleteAccountFormWrongPassphraseWarning':"Phrase secrète incorrect",
159 'deleteAccountFormSafetyCheckWarning':"Veuillez lire et cocher la case-à-cocher ci-dessous.",
160 'accountPanelDeletingAccountPanelConfirmationTitle':"ATTENTION",
161 'accountPanelDeleteAccountPanelConfirmationText':"Êtes-vous sûr de vouloir supprimer ce compte?",
162 'accountPanelDeleteAccountPanelConfirmButtonLabel':"Oui",
163 'accountPanelDeleteAccountPanelDenyButtonLabel':"Non",
164 'offlineCopyTabLabel':"Copie locale",
165 'offlineCopyTabTitle':"Copie locale",
166 'offlineCopyTabDescription':"<p>D'un seul click, vous pouvez télécharger toutes vos données chiffrées des serveurs Clipperz sur votre disque dur, créant ainsi une version déconnecté de Clipperz utilisable lorsque vous n'êtes pas connectés à Internet.</p> <p>Cette version en lecture seule est aussi sécurisée que la version en lecture-écriture, et n'expose pas vos données à un risque plus élevé. Elles partagent en effet le même code et la même architecture de sécurité.</p> <ol> <li> <p>Cliquez sur le liens ci-dessous pour lancer le téléchargement.</p> </li> <li> <p>Votre navigateur vous demandera que faire du fichier “Clipperz_YYYYMMDD.html”. Sauvez le sur votre disque dur.</p> </li> <li> <p>Puis double-cliquez sur le fichier téléchargé pour lancer la version déconnectée dans votre navigateur.</p> </li> <li> <p>Utilisez vos nom d’utilisateur et phrase secrète habituels.</p> </li> </ol> ",
167 'offlineCopyDownloadLinkLabel':"Télécharger",
168 'sharingTabLabel':"Partager",
169 'sharingTabTitle':"Partager",
170 'sharingTabDescription':"<p>De temps en temps il est nécessaire de partager des parties de vos informations confidentiels avec une ou plusieurs personnes.</p> <p>Cela pourrait être aussi simple que l’octroi à un collègue de votre code d’accès à votre messagerie vocale quand vous êtes hors du bureau, ou aussi compliqués que la permission d’ayant droit aux héritiers pour avoir accès à votre boîte de coffre-fort à la banque locale.</p> <p>Clipperz vous permez donc de partager vos mots de passe grâce à un processe sûr et direct.</p> <p> </p> <p> <b>Prochainement disponible ...</b> </p> ",
171 'importTabLabel':"Importer",
172 'importTabTitle':"Importer",
173 'importTabDescription':"<p> <b>Prochainement disponible ...</b> </p> ",
174 'printingTabLabel':"Exporter",
175 'printingTabTitle':"Exporter",
176 'printingTabDescription':"<p> <b>Version d’impression</b> </p> <p>En cliquant sur ce bouton vous ouvrirez une fenêtre contenant vos en-têtes cryptés dans un format d’impression.</p> <p>Si vous imprimez pour des raisons de sauvegarde personnel, veuillez vous tourner vers une solution plus sécurisé comme la version “Copie locale”.</p> ",
177 'printingLinkLabel':"Version imprimable",
178 'contactsTabLabel':"Contacts",
179 'contactsTabTitle':"Contacts",
180 'passwordGeneratorTabLabel':"Générateur de mot de passe",
181 'bookmarkletTabLabel':"Bookmarklet",
182 'passwordGeneratorTabTitle':"Générateur de mot de passe",
183 'bookmarkletTabTitle':"Bookmarklet",
184 'paswordGeneratorTabDescription':"<p> </p> ",
185 'passwordGeneratorTabButtonLabel':" Générer un mot de passe",
186 'bookmarkletTabDescription':"<p>Un bookmarklet est un outil “clique unique” simple qui peut exécuter des tâches très utiles. Il peut être sauvegardé et utilisé comme un signet de page Web normal.</p> <p>Le bookmarklet Clipperz vous aidera à rapidement créer de nouvelles cartes et des nouveaux “accès directs” avec vos cartes existantes.</p> <p> <b>Notez s’il vous plaît que le bookmarklet n’inclut pas d’informations liées à votre compte (par exemple votre nom d’utilisateur ou votre phrase secrète), le bookmarklet est un outil général contenant le même code pour chaque utilisateur Clipperz.</b> </p> <div> <p>Pour installer le bookmarklet <b>glissez & déposez</b> le lien ci-dessous dans votre bar de navigation.</p> </div> ",
187 'bookmarkletTabBookmarkletTitle':"Ajouter à Clipperz",
188 'bookmarkletTabInstructions':"<h3>Comment créer une carte comprenant un lien de “accès direct” à un service en ligne</h3> <ol> <li> <p>Ouvrir la page Web où le site affiche un formulaire d’identification. (C’est la page où vous entrez d’habitude vos informations d'identification)</p> </li> <li> <p>Lancer le bookmarklet en cliquant dessus : une fenêtre contextuelle apparait alors sur la page Web.</p> </li> <li> <p>Copier dans le presse-papiers le contenu du grand secteur de texte dans le menu contextuel. (Ctrl-C)</p> </li> <li> <p>Entrer dans votre compte Clipperz et cliquer sur <b>“Ajouter une nouvelle carte”</b>.</p> </li> <li> <p>Coller le presse-papiers dans la zone de texte et rajouter un titre (facultatif). (Ctrl-V)</p> </li> <li> <p>Cliquer sur le bouton <b>“Créer”</b>, repassez en revu les détails et cliquer <b>“Sauver”</b>. De plus amples informations sont disponibles <a href=\"http://www.clipperz.com/support/user_guide/bookmarklet\" target=\"_blank\">ici</a>.</p> </li> </ol> <h3>Comment ajouter un lien de “accès direct” à une carte existante</h3> <ol> <li> <p>Idem que précédemment.</p> </li> <li> <p>Idem que précédemment..</p> </li> <li> <p>Idem que précédemment.</p> </li> <li> <p>Entrer dans votre compte Clipperz et sélectionner la carte crypté qui contient les identifiants pour le service web que vous venez tout juste de visiter et cliquer sur <b>“Modifier”</b>.</p> </li> <li> <p>Coller le presse-papier dans la zone de texte <b>“Accès directs”</b>. (ctrl-V)</p> </li> <li> <p>Cliquer sur <b>“Ajouter un accès direct”</b>, repassez en revu les détails et cliquer <b>“Sauver”</b>.</p> </li> </ol> ",
189 'mainPanelDirectLoginBlockLabel':"Accès directs",
190 'directLinkReferenceShowButtonLabel':"voir",
191 'mainPanelDirectLoginBlockDescription':"<p>Ajouter une “accès direct” pour vous identifier sans avoir besoin de taper vos identifiants de connexions!</p> <p>Les “accès directs” augmente considérablement la sécurité de vos mots passes dans la mesure où vous pouvez:</p> <ul> <li> <p>adopter et saisir des mots de passe complexes;</p> </li> <li> <p>ne réutilisez le même mot de passe et ne mettez plus de mots de passe facile à deviner.</p> </li> </ul> <p>Simple et rapide à configurer avec le Clipperz <b>bookmarklet</b>.</p> <a href=\"http://www.clipperz.com/support/user_guide/direct_logins\" target=\"_blank\">Pour en savoir plus sur les “accès directs”</a> ",
192 'mainPanelRecordsBlockLabel':"Cartes",
193 'mainPanelAddRecordButtonLabel':"Ajouter une nouvelle carte",
194 'mainPanelRemoveRecordButtonLabel':"Supprimer une carte",
195 'mainPanelRecordFilterBlockAllLabel':"tous",
196 'mainPanelRecordFilterBlockTagsLabel':"tags",
197 'mainPanelRecordFilterBlockSearchLabel':"chercher",
198 'recordDetailNoRecordAtAllTitle':"Bienvenue sur Clipperz!",
199 'recordDetailNoRecordAtAllDescription':"<h5>Commencez par ajouter des cartes à votre compte.</h5> <p>Les cartes sont des formulaires flexibles ou vous pouvez enregistrer vos mots de passe et autres informations confidentielles.</p> <p>Par exemple, une carte peut contenir les informations d\"identification pour un site web, la combinaison de votre antivol de bicyclette, les détails de votre carte bancaire, ...</p> <h5>N'oubliez pas le bookmarklet!</h5> <p>Avant de commencer, installez le bookmarklet “Ajouter à Clipperz”: il rends la création de carte plus facile et amusante.</p> <p>Allez à l'onglet “outils” pour découvrir comment l'installer et l'utiliser.</p> <p> </p> <p>Ensuite, cliquez tout simplement sur le bouton “Ajouter une nouvelle carte” et profitez de votre compte Clipperz.</p> <p> </p> <a href=\"http://www.clipperz.com/support/user_guide/managing_cards\" target=\"_blank\">En savoir plus sur la création et la gestion des cartes.</a> ",
200 'newRecordWizardTitleBox':"<h5>Choisissez un modèle</h5> <p>Les cartes sont des formulaires flexibles ou vous pouvez enregistrer vos mots de passe et autres informations confidentielles.</p> <p>Commencez par choisir un des modèles ci-dessous. Vous pourrez toujours adapter vos cartes plus tard en ajoutant ou supprimant des champs.</p> ",
201 'newRecordWizardBookmarkletConfigurationTitle':"Accès directs",
202 'newRecordWizardBookmarkletConfigurationDescriptionConfig':"<p>Collez ici le code de configuration généré par le bookmarlet Clipperz.</p> <p>Cela créera une nouvelle carte avec un accès direct à votre site web.</p> ",
203 'newRecordWizardCreateButtonLabel':"Créer",
204 'newRecordWizardCancelButtonLabel':"Annuler",
205 'recordTemplates':{
206 'WebAccount':{
207 'title':"Mot de passe web",
208 'description':"<p>Une carte toute simple pour enregistrer les informations d'identification de vos services en ligne.</p> ",
209 'fields':{
210 'URL':"Adresse web",
211 'TXT':"Nom d'utilisateur ou email",
212 'PWD':"Mot de passe"
213 }
214 },
215 'BankAccount':{
216 'title':"Compte bancaire",
217 'description':"<p>Enregistrer de façon sécurisée vos numéros de compte bancaire et vos identifiants de service bancaire en ligne.</p> ",
218 'fields':{
219 'TXT':"Banque",
220 'TXT':"N° de compte",
221 'URL':"Adresse web du site",
222 'TXT':"Identifiant",
223 'PWD':"Mot de passe"
224 }
225 },
226 'CreditCard':{
227 'title':"Carte bancaire",
228 'description':"<p>Ayez toujours sous la main votre numéro de carte, la date d'expiration, le code de contrôle et le code secret avec Clipperz</p> ",
229 'fields':{
230 'TXT':"Type (Visa, AmEx, ...)",
231 'TXT':"Numéro",
232 'TXT':"Nom du porteur",
233 'TXT':"Date de validité",
234 'TXT':"Code de contrôle",
235 'PWD':"Code secret",
236 'URL':"Site web",
237 'TXT':"Identifiant",
238 'PWD':"Mot de passe"
239 }
240 },
241 'AddressBookEntry':{
242 'title':"Carnet d'adresse",
243 'description':"<p>Clipperz peux aussi être utilisé comme un nouveau carnet d'adresse privé. Utilisez ce modèle pour ajouter des contacts facilement.</p> ",
244 'fields':{
245 'TXT':"Nom",
246 'TXT':"Adresse eMail",
247 'TXT':"Téléphone",
248 'TXT':"Mobile",
249 'ADDR':"Adresse"
250 }
251 },
252 'Custom':{
253 'title':"Carte personnalisée",
254 'description':"<p>Quelles que soient les données confidentielles que vous souhaitez protéger, créez une carte personnalisée adaptée à vos besoins.</p> ",
255 'fields':{
256 'TXT':"Titre du champ 1",
257 'TXT':"Titre du champ 2",
258 'TXT':"Titre du champ 3"
259 }
260 }
261},
262 'recordFieldTypologies':{
263 'TXT':{
264 'description':"simple text field",
265 'shortDescription':"texte"
266 },
267 'PWD':{
268 'description':"simple text field, with default status set to hidden",
269 'shortDescription':"mot de passe"
270 },
271 'URL':{
272 'description':"simple text field in edit mode, that became an active url in view mode",
273 'shortDescription':"adresse de site web"
274 },
275 'DATE':{
276 'description':"a value set with a calendar helper",
277 'shortDescription':"date"
278 },
279 'ADDR':{
280 'description':"just like the URL, but the active link points to Google Maps (or similar service) passing the address value as argument",
281 'shortDescription':"adresse"
282 },
283 'CHECK':{
284 'description':"check description",
285 'shortDescription':"check"
286 },
287 'RADIO':{
288 'description':"radio description",
289 'shortDescription':"radio"
290 },
291 'SELECT':{
292 'description':"select description",
293 'shortDescription':"select"
294 }
295},
296 'newRecordPanelGeneralExceptionTitle':"Erreur",
297 'newRecordPanelGeneralExceptionMessage':"Le code de configuration n'est pas valide. Copiez le depuis la fenêtre du bookmarklet, et essayez à nouveau.",
298 'newRecordPanelWrongBookmarkletVersionExceptionTitle':"Erreur",
299 'newRecordPanelWrongBookmarkletVersionExceptionMessage':"Ce code de configuration provient d'un ancien bookmarklet. Mettez votre bookmarklet à jour, puis essayez de nouveau.",
300 'newRecordPanelExceptionPanelCloseButtonLabel':"Annuler",
301 'mainPanelDeletingRecordPanelConfirmationTitle':"Suppression de la carte sélectionnée",
302 'mainPanelDeleteRecordPanelConfirmationText':"Voulez vous vraiment supprimer la carte sélectionnée?",
303 'mainPanelDeleteRecordPanelConfirmButtonLabel':"Oui",
304 'mainPanelDeleteRecordPanelDenyButtonLabel':"Non",
305 'mainPanelDeletingRecordPanelInitialTitle':"Suppression de la carte",
306 'mainPanelDeletingRecordPanelCompletedText':"Terminé",
307 'deleteRecordPanelCollectRecordDataMessageTitle':"Supprimer la carte",
308 'deleteRecordPanelCollectRecordDataMessageText':"Mise à jour de la liste des cartes",
309 'deleteRecordPanelEncryptUserDataMessageTitle':"Supprimer la carte",
310 'deleteRecordPanelEncryptUserDataMessageText':"Chiffrement local des en-têtes de carte",
311 'deleteRecordPanelSendingDataToTheServerMessageTitle':"Supprimer la carteDelete card",
312 'deleteRecordPanelSendingDataToTheServerMessageText':"Transmission des en-têtes chiffrées à Clipperz",
313 'deleteRecordPanelUpdatingTheInterfaceMessageTitle':"Supprimer la carte",
314 'deleteRecordPanelUpdatingTheInterfaceMessageText':"Mise à jour de l'interface",
315 'recordDetailNoRecordSelectedTitle':"Aucune carte sélectionnée",
316 'recordDetailNoRecordSelectedDescription':"<p>Veuillez selectionner une carte dans la liste de gauche.</p> ",
317 'recordDetailLoadingRecordMessage':"Téléchargement de la carte chiffrée depuis Clipperz",
318 'recordDetailDecryptingRecordMessage':"Déchiffrement local des informations de la carte",
319 'recordDetailLoadingRecordVersionMessage':"Téléchargement de la dernière version de la carte",
320 'recordDetailDecryptingRecordVersionMessage':"Déchiffrement local de la dernière version",
321 'recordDetailLoadingErrorMessageTitle':"Erreur lors du téléchargement de la carte",
322 'recordDetailNotesLabel':"Notes",
323 'recordDetailLabelFieldColumnLabel':"Titre du champ",
324 'recordDetailDataFieldColumnLabel':"Données du champ",
325 'recordDetailTypeFieldColumnLabel':"Type",
326 'recordDetailSavingChangesMessagePanelInitialTitle':"Enregistrement de la carte",
327 'recordDetailAddFieldButtonLabel':"Ajouter un champ",
328 'recordDetailPasswordFieldHelpLabel':"pour copier le mot de passe, cliquez sur les étoiles, puis Ctrl-C",
329 'recordDetailPasswordFieldScrambleLabel':"dissimuler",
330 'recordDetailPasswordFieldUnscrambleLabel':"en clair",
331 'recordDetailDirectLoginBlockTitle':"Accès directs",
332 'recordDetailNewDirectLoginDescription':"<p>Configuration de l'accès direct</p> ",
333 'recordDetailDirectLoginBlockNoDirectLoginConfiguredDescription':"<p>Cette carte contient-elle des informations d'identification pour un service en ligne?</p> <p>Utilisez le bookmarklet pour configurer un “accès direct” depuis Clipperz en un seul click!</p> ",
334 'recordDetailAddNewDirectLoginButtonLabel':"Ajouter un accès direct",
335 'recordDetailEditButtonLabel':"Modifier",
336 'recordDetailSaveButtonLabel':"Sauver",
337 'recordDetailCancelButtonLabel':"Annuler",
338 'newRecordTitleLabel':"_nouvelle carte_",
339 'recordSaveChangesPanelCollectRecordInfoMessageTitle':"Enregistrement de la carte",
340 'recordSaveChangesPanelCollectRecordInfoMessageText':"Updating card headers",
341 'recordSaveChangesPanelEncryptUserDataMessageTitle':"Sauvegarde de la carte",
342 'recordSaveChangesPanelEncryptUserDataMessageText':"Cryptage local des en-têtes chiffrés",
343 'recordSaveChangesPanelEncryptRecordDataMessageTitle':"Sauvegarde de la carte",
344 'recordSaveChangesPanelEncryptRecordDataMessageText':"Cryptage local des en-têtes chiffrés",
345 'recordSaveChangesPanelEncryptRecordVersionDataMessageTitle':"Sauvegarde de la carte",
346 'recordSaveChangesPanelEncryptRecordVersionDataMessageText':"Cryptage local des données de version de la carte",
347 'recordSaveChangesPanelSendingDataToTheServerMessageTitle':"Sauvegarde de la carte",
348 'recordSaveChangesPanelSendingDataToTheServerMessageText':"Téléchargement des cartes d’en-têtes chiffrés depuis Clipperz",
349 'recordSaveChangesPanelUpdatingTheInterfaceMessageTitle':"Sauvegarde de la carte",
350 'recordSaveChangesPanelUpdatingTheInterfaceMessageText':"Mise à jour de l'interface",
351 'passwordGeneratorPanelTitle':"Générateur de mot de passe",
352 'passwordGeneratorPanelOkLabel':"Ok",
353 'passwordGeneratorPanelCancelLabel':"Annuler",
354 'passwordGeneratorLengthLabel':"longueur:",
355 //'DWRUtilLoadingMessage':"Chargement des données ...",
356 'comingSoon':"Bientôt en ligne ...",
357 'panelCollectingEntryopyMessageText':"Rassemblement d'entropie",
358 'directLoginConfigurationCheckBoxFieldSelectedValue':"Oui",
359 'directLoginConfigurationCheckBoxFieldNotSelectedValue':"Non",
360
361__syntaxFix__: "syntax fix"
362});
diff --git a/frontend/beta/js/Clipperz/PM/Strings/Strings_he-IL.js b/frontend/beta/js/Clipperz/PM/Strings/Strings_he-IL.js
new file mode 100644
index 0000000..3bdfe19
--- a/dev/null
+++ b/frontend/beta/js/Clipperz/PM/Strings/Strings_he-IL.js
@@ -0,0 +1,40 @@
1/*
2
3Copyright 2008-2011 Clipperz Srl
4
5This file is part of Clipperz's Javascript Crypto Library.
6Javascript Crypto Library provides web developers with an extensive
7and efficient set of cryptographic functions. The library aims to
8obtain maximum execution speed while preserving modularity and
9reusability.
10For further information about its features and functionalities please
11refer to http://www.clipperz.com
12
13* Javascript Crypto Library is free software: you can redistribute
14 it and/or modify it under the terms of the GNU Affero General Public
15 License as published by the Free Software Foundation, either version
16 3 of the License, or (at your option) any later version.
17
18* Javascript Crypto Library is distributed in the hope that it will
19 be useful, but WITHOUT ANY WARRANTY; without even the implied
20 warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
21 See the GNU Affero General Public License for more details.
22
23* You should have received a copy of the GNU Affero General Public
24 License along with Javascript Crypto Library. If not, see
25 <http://www.gnu.org/licenses/>.
26
27*/
28
29//=============================================================================
30//
31 // H E B R E W (he_IL)
32//
33//=============================================================================
34
35Clipperz.PM.Strings.Languages['he-il'] = MochiKit.Base.merge(Clipperz.PM.Strings.Languages['en-us'], {
36
37 //-------------------------------------------------------------------------
38 __syntaxFix__: "syntax fix"
39});
40
diff --git a/frontend/beta/js/Clipperz/PM/Strings/Strings_it-IT.js b/frontend/beta/js/Clipperz/PM/Strings/Strings_it-IT.js
new file mode 100644
index 0000000..51c0d03
--- a/dev/null
+++ b/frontend/beta/js/Clipperz/PM/Strings/Strings_it-IT.js
@@ -0,0 +1,694 @@
1/*
2
3Copyright 2008-2011 Clipperz Srl
4
5This file is part of Clipperz's Javascript Crypto Library.
6Javascript Crypto Library provides web developers with an extensive
7and efficient set of cryptographic functions. The library aims to
8obtain maximum execution speed while preserving modularity and
9reusability.
10For further information about its features and functionalities please
11refer to http://www.clipperz.com
12
13* Javascript Crypto Library is free software: you can redistribute
14 it and/or modify it under the terms of the GNU Affero General Public
15 License as published by the Free Software Foundation, either version
16 3 of the License, or (at your option) any later version.
17
18* Javascript Crypto Library is distributed in the hope that it will
19 be useful, but WITHOUT ANY WARRANTY; without even the implied
20 warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
21 See the GNU Affero General Public License for more details.
22
23* You should have received a copy of the GNU Affero General Public
24 License along with Javascript Crypto Library. If not, see
25 <http://www.gnu.org/licenses/>.
26
27*/
28
29Clipperz.PM.Strings.Languages['it-IT'.toLowerCase()] = MochiKit.Base.merge(Clipperz.PM.Strings.Languages['en-us'], {
30 'clipperzServiceDescription':"<h2>Tienilo per te!</h2> <ul> <li> <h3>Clipperz è:</h3> <ul> <li> <p>un archivio semplice e sicuro per le tue password</p> </li> <li> <p>un canale di accesso unificato a tutti i tuoi servizi online</p> </li> <li> <p>una cassaforte digitale per tutti i tuoi dati riservati</p> </li> </ul> </li> <li> <h3>Con Clipperz puoi:</h3> <ul> <li> <p>memorizzare e gestire le password e le credenziali di accesso dei tuoi servizi online</p> </li> <li> <p>accedere ai tuoi servizi online con un solo click senza bisogno di inserire username o password</p> </li> <li> <p>proteggere tutte le tue informazioni confidenziali: codice dell&#x27;allarme di casa, dati delle carte di credito, …</p> </li> <li> <p>condividere dati riservati con i tuoi familiari o colleghi (disponibile a breve)</p> </li> </ul> </li> <li> <h3>I vantaggi di Clipperz:</h3> <ul> <li> <p>gratuito e completamente anonimo</p> </li> <li> <p>accessibile da qualsiasi computer</p> </li> <li> <p>nessun software da scaricare e niente da installare</p> </li> <li> <p>mai più informazioni riservate sul tuo PC o sulla carta!</p> </li> </ul> </li> <li> <h3>La sicurezza di Clipperz:</h3> <ul> <li> <p>i dati sono criptati dal tuo browser prima di essere inviati a Clipperz</p> </li> <li> <p>la chiave per decriptare i dati è conosciuta soltanto da te</p> </li> <li> <p>Clipperz riceve e memorizza solo i tuoi dati criptati e non ha nessuna possibilità di accedere alla versione in chiaro</p> </li> <li> <p>Clipperz utilizza solo sistemi crittografici standard, senza nessuna velleità di inventare e proporre nuovi algoritmi non validati dalla comunità scientifica</p> </li> <li> <p>tutto il codice di Clipperz è disponibile e può essere analizzato in qualsiasi momento, ma non serve essere un esperto di crittografia per apprezzare la sicurezza e la comodità di Clipperz!</p> </li> </ul> </li> <li><a href=\"http://www.clipperz.com\" target=\"_blank\">Maggiori informazioni su Clipperz (in inglese)</a> </li> </ul> ",
31 'loginFormTitle':"accedi a Clipperz",
32 'loginFormUsernameLabel':"Utente",
33 'loginFormPassphraseLabel':"frase segreta",
34 'loginFormDontHaveAnAccountLabel':"non ti sei ancora registrato?",
35 'loginFormCreateOneLabel':"registrati adesso",
36 'loginFormForgotYourCredentialsLabel':"hai perso i dati di accesso?",
37 'loginFormAarghThatsBadLabel':"aargh! questo non è bello!",
38 'loginFormAfraidOfMaliciousScriptsLabel':"non ti fidi?",
39 'loginFormVerifyTheCodeLabel':"controlla il codice",
40 'loginFormButtonLabel':"Accedi",
41 'loginFormOneTimePasswordCheckboxLabel':"usa un codice “usa e getta”",
42 'loginFormOneTimePasswordCheckboxDescription':"",
43 'loginPanelSwithLanguageDescription':"<h5>Seleziona la tua lingua preferita</h5> ",
44 'browserCompatibilityDescription':"<p>Clipperz consiglia Firefox per una maggiore sicurezza. Clipperz supporta anche Opera ed Internet Explorer.</p> ",
45 'OTPloginMessagePanelInitialTitle':"Accesso con codice “usa e getta”",
46 'OTPloginMessagePanelInitialText':"Invio delle credenziali OTP ...",
47 'OTPloginMessagePanelLoadingTitle':"Accesso con codice “usa e getta”",
48 'OTPloginMessagePanelLoadingText':"Caricamento dei dati di autenticazione criptati ...",
49 'OTPloginMessagePanelProcessingTitle':"Accesso con codice “usa e getta”",
50 'OTPloginMessagePanelProcessingText':"Decodifica locale dei dati di autenticazione ...",
51 'loginMessagePanelInitialTitle':"Connessione in corso ...",
52 'loginMessagePanelInitialText':"---",
53 'loginMessagePanelInitialButtonLabel':"Annulla",
54 'loginMessagePanelConnectedTitle':"Connesso",
55 'loginMessagePanelConnectedText':"Fatto",
56 'loginMessagePanelFailureTitle':"Errore",
57 'loginMessagePanelFailureText':"Connessione fallita",
58 'loginMessagePanelFailureButtonLabel':"Chiudi",
59 'connectionLoginSendingCredentialsMessageTitle':"Verifica delle credenziali",
60 'connectionLoginSendingCredentialsMessageText':"Invio delle credenziali",
61 'connectionLoginCredentialsVerificationMessageTitle':"Verifica delle credenziali",
62 'connectionLoginCredentialsVerificationMessageText':"Esecuzione dell&#x27;autenticazione SRP ...",
63 'connectionLoginDoneMessageTitle':"Verifica delle credenziali",
64 'connectionLoginDoneMessageText':"Connesso",
65 'userLoginPanelUpgradingUserCredentialsMessageTitle':"Verifica delle credenziali",
66 'userLoginPanelUpgradingUserCredentialsMessageText':"Aggiornamento delle credenziali ad un nuovo schema di autenticazione",
67 'userLoginPanelConnectedMessageTitle':"Utente autenticato",
68 'userLoginPanelConnectedMessageText':"Autenticazione eseguita con successo",
69 'userLoginPanelTryingAnOlderConnectionSchemaMessageTitle':"Verifica delle credenziali",
70 'userLoginPanelTryingAnOlderConnectionSchemaMessageText':"Tentativo con vecchio schema di autenticazione",
71 'userLoginPanelLoadingUserDataMessageTitle':"Utente autenticato",
72 'userLoginPanelLoadingUserDataMessageText':"Scarica le intestazioni criptate delle schede da Clipperz",
73 'userLoginPanelDecryptingUserDataMessageTitle':"Utente autenticato",
74 'userLoginPanelDecryptingUserDataMessageText':"Decodifica locale dell&#x27;intestazione delle schede",
75 'userLoginPanelDecryptingUserStatisticsMessageTitle':"Utente autenticato",
76 'userLoginPanelDecryptingUserStatisticsMessageText':"Decodifica locale delle statistiche d&#x27;uso",
77 'splashAlertTitle':"Benvenuto a Clipperz!",
78 'splashAlertText':"<p>Alcuni consigli per la sicurezza</p> <ul> <li> <p>La sicurezza dei tuoi dati dipende da quanto è sicura la frase segreta che usi per proteggerli. Nessuno può accedervi a meno che non conosca la frase segreta.</p> </li> <li> <p>Se hai intenzione di usare Clipperz per conservare informazioni sensibili e riservate, scegli attentamente una frase segreta complessa. Più è lunga, maggiore è la sicurezza!</p> </li> <li> <p>E non dimenticare che Clipperz non è in grado di recuperare la tua frase segreta in caso di smarrimento!</p> </li> </ul> <p>Per maggiori informazioni sulla sicurezza, consulta il sito <a href=\"http://www.clipperz.com\" target=\"_blank\">Clipperz</a> (in lingua inglese).</p> ",
79 'splashAlertCloseButtonLabel':"Ok",
80 'registrationFormTitle':"crea il tuo utente",
81 'registrationFormUsernameLabel':"Utente",
82 'registrationFormPassphraseLabel':"frase segreta",
83 'registrationFormRetypePassphraseLabel':"ripeti frase segreta",
84 'registrationFormSafetyCheckLabel':"Sono consapevole che Clipperz non è in grado di recuperare una frase segreta dimenticata.",
85 'registrationFormTermsOfServiceCheckLabel':"Dichiaro di aver letto e di accettare i <a href=\"http://www.clipperz.com/terms_of_service\" target=\"_blank\">Termini del Servizio</a> .",
86 'registrationFormDoYouAlreadyHaveAnAccountLabel':"sei già un utente registrato?",
87 'registrationFormSimplyLoginLabel':"accedi subito",
88 'registrationFormButtonLabel':"Registrati",
89 'registrationFormWarningMessageNotMatchingPassphrases':"Le frasi segrete non corrispondono, ripeti l&#x27;inserimento.",
90 'registrationFormWarningMessageSafetyCheckNotSelected':"Leggi e spunta le condizioni sotto riportate.",
91 'registrationFormWarningMessageTermsOfServiceCheckNotSelected':"Per procedere devi accettare i Termini del Servizio.",
92 'registrationMessagePanelInitialTitle':"Registrazione in corso ...",
93 'registrationMessagePanelInitialText':"---",
94 'registrationMessagePanelInitialButtonLabel':"Annulla",
95 'registrationMessagePanelRegistrationDoneTitle':"Registrazione",
96 'registrationMessagePanelRegistrationDoneText':"Fatto",
97 'registrationMessagePanelFailureTitle':"Registrazione fallita",
98 'registrationMessagePanelFailureButtonLabel':"Chiudi",
99 'connectionRegistrationSendingRequestMessageText':"Verifica delle credenziali",
100 'connectionRegistrationSendingCredentialsMessageText':"Invio delle credenziali",
101 'registrationSplashPanelTitle':"Avviso di sicurezza",
102 'registrationSplashPanelDescription':"<p>Queste sono le tue credenziali di accesso a Clipperz, conservale con cura. Il tuo utente ed la tua frase segreta non ti verranno mostrati una seconda volta!</p> ",
103 'registrationSplashPanelUsernameLabel':"Utente",
104 'registrationSplashPanelPassphraseLabel':"frase segreta",
105 'registrationSplashPanelShowPassphraseButtonLabel':"mostra la frase segreta",
106 'donateHeaderLinkLabel':"donazioni",
107 'creditsHeaderLinkLabel':"credits",
108 'feedbackHeaderLinkLabel':"scrivici",
109 'helpHeaderLinkLabel':"aiuto",
110 'forumHeaderLinkLabel':"forum",
111 'recordMenuLabel':"Schede",
112 'accountMenuLabel':"profilo",
113 'dataMenuLabel':"dati",
114 'contactsMenuLabel':"Contatti",
115 'toolsMenuLabel':"strumenti",
116 'logoutMenuLabel':"esci",
117 'lockMenuLabel':"blocca",
118 'lockTitle':"Utente bloccato",
119 'lockDescription':"<p>Per sbloccare il tuo utente inserisci la frase segreta</p> ",
120 'unlockButtonLabel':"Sblocca",
121 'changePasswordTabLabel':"Cambia la tua frase segreta",
122 'changePasswordTabTitle':"Cambia la tua frase segreta",
123 'changePasswordFormUsernameLabel':"Utente",
124 'changePasswordFormOldPassphraseLabel':"attuale frase segreta",
125 'changePasswordFormNewPassphraseLabel':"nuova frase segreta",
126 'changePasswordFormRetypePassphraseLabel':"ripeti nuova frase segreta",
127 'changePasswordFormSafetyCheckboxLabel':"Sono consapevole che Clipperz non è in grado di recuperare una frase segreta dimenticata.",
128 'changePasswordFormSubmitLabel':"Cambia frase segreta",
129 'changePasswordFormWrongUsernameWarning':"Utente errato",
130 'changePasswordFormWrongPassphraseWarning':"Frase segreta errata",
131 'changePasswordFormWrongRetypePassphraseWarning':"Le frasi segrete non corrispondono, ripeti l&#x27;inserimento.",
132 'changePasswordFormSafetyCheckWarning':"Leggi e spunta le condizioni sotto riportate.",
133 'changePasswordFormProgressDialogTitle':"Aggiornamento credenziali",
134 'changePasswordFormProgressDialogEmptyText':"---",
135 'changePasswordFormProgressDialogConnectedMessageTitle':"Connesso",
136 'changePasswordFormProgressDialogConnectedMessageText':"Fatto",
137 'changePasswordFormProgressDialogErrorMessageTitle':"Errore",
138 'changePasswordFormProgressDialogErrorMessageText':"Aggiornamento credenziali fallito!",
139 'changeCredentialsPanelEncryptingDataMessageTitle':"Cambio della frase segreta",
140 'changeCredentialsPanelEncryptingDataMessageText':"Cripta localmente l&#x27;intestazione delle schede",
141 'changeCredentialsPanelCreatingNewCredentialsMessageTitle':"Cambio della frase segreta",
142 'changeCredentialsPanelCreatingNewCredentialsMessageText':"Aggiornamento delle credenziali",
143 'changeCredentialsPanelSendingNewCredentialsToTheServerMessageTitle':"Cambio della frase segreta",
144 'changeCredentialsPanelSendingNewCredentialsToTheServerMessageText':"Carica le intestazioni criptate delle schede su Clipperz",
145 'changeCredentialsPanelDoneMessageTitle':"Cambio della frase segreta",
146 'changeCredentialsPanelDoneMessageText':"Fatto",
147 'manageOTPTabLabel':"Codici di accesso “usa e getta”",
148 'manageOTPTabTitle':"Codici di accesso “usa e getta”",
149 'manageOTPTabDescription':"<p>I codici di accesso e “usa e getta” funzionano come la tua normale frase segreta, ma possono essere utilizzate una sola volta.</p> <p>Se lo stesso codice “usa e getta” viene utilizzato per tentare ulteriori accessi il processo di autenticazione fallirà.</p> <p>Infatti, dopo il primo utilizzo, il codice “usa e getta” verrà immediatamente disattivato e cancellato prevenendo così eventuali accessi non autorizzati.</p> <p>L&#x27;utilizzo di codici “usa e getta” è una scelta consigliata per chi teme che il computer dal quale sta accedendo a Clipperz non sia sicuro a causa di software quali keyloggers e spyware che potrebbero registrare le proprie credenziali di accesso.</p> <p><b>E&#x27; caldamente consigliato l&#x27;utilizzo di codici “usa e getta” quando ci si collega a Clipperz da terminali pubblici quali Internet Cafe e biblioteche.</b> </p> ",
150 'oneTimePasswordReadOnlyMessage':"<h6>Attenzione!</h6> <p>Non è possibilie accedere ai propri codici “usa e getta” quando si utilizza la versione offline di Clipperz.</p> ",
151 'oneTimePasswordLoadingMessage':"<h6>Caricamento dati</h6> <p>Si prega di attendere ...</p> ",
152 'oneTimePasswordNoPasswordAvailable':"<h6>Nessun codice “usa e getta” disponibile</h6> <p>Per creare codici “usa e getta” clicca sul pulsante “Nuovo” che trovi qui sopra.</p> ",
153 'deleteOTPButtonLabel':"Elimina",
154 'printOTPButtonLabel':"Stampa",
155 'disabledOneTimePassword_warning':"disabilitato",
156 'oneTimePasswordSelectionLink_selectLabel':"Seleziona:",
157 'oneTimePasswordSelectionLink_none':"nessuno",
158 'oneTimePasswordSelectionLink_used':"utilizzati",
159 'oneTimePasswordSelectionLink_unused':"disponibili",
160 'saveOTP_encryptUserDataTitle':"Registrazione del nuovo codice “usa e getta”",
161 'saveOTP_encryptUserDataText':"Elaborazione delle credenziali OTP ...",
162 'saveOTP_encryptOTPDataTitle':"Registrazione del nuovo codice “usa e getta”",
163 'saveOTP_encryptOTPDataText':"Codifica locale dei dati di autenticazione ...",
164 'saveOTP_sendingDataTitle':"Registrazione del nuovo codice “usa e getta”",
165 'saveOTP_sendingDataText':"Invio dei dati di autenticazione criptati ...",
166 'saveOTP_updatingInterfaceTitle':"Registrazione del nuovo codice “usa e getta”",
167 'saveOTP_updatingInterfaceText':"Aggiornamento dell&#x27;interfaccia",
168 'accountPreferencesLabel':"Preferenze",
169 'accountPreferencesTabTitle':"Preferenze",
170 'accountPreferencesLanguageTitle':"Selezione della lingua",
171 'accountPreferencesLanguageDescription':"<p>Scegli la lingua preferita dall&#x27;elenco sottostante.</p> ",
172 'showDonationReminderPanelTitle':"Promemoria donazioni",
173 'showDonationReminderPanelDescription':"<p>Mostra i promemopria per le donazioni</p> ",
174 'saveUserPreferencesFormSubmitLabel':"Salva",
175 'cancelUserPreferencesFormSubmitLabel':"Annulla",
176 'accountPreferencesSavingPanelTitle_Step1':"Salvataggio preferenze",
177 'accountPreferencesSavingPanelText_Step1':"Cripta localmente le preferenze",
178 'accountPreferencesSavingPanelTitle_Step2':"Salvataggio preferenze",
179 'accountPreferencesSavingPanelText_Step2':"Carica preferenze criptate su Clipperz",
180 'accountLoginHistoryLabel':"Registro degli accessi",
181 'loginHistoryTabTitle':"Registro degli accessi",
182 'loginHistoryReadOnlyMessage':"<h6>Attenzione!</h6> <p>Il registro degli accessi non è disponibile quando si utilizza la versione offline di Clipperz</p> ",
183 'loginHistoryLoadingMessage':"<h6>Caricamento dati</h6> <p>Si prega di attendere ...</p> ",
184 'loginHistoryLoadedMessage':"<h6>I tuoi ultimi 10 accessi</h6> <p> </p> ",
185 'loginHistoryIPLabel':"IP",
186 'loginHistoryTimeLabel':"data",
187 'loginHistoryCurrentSessionText':"sessione corrente",
188 'loginHistoryReloadButtonLabel':"Aggiorna il registro degli accessi",
189 'deleteAccountTabLabel':"Cancella il tuo utente",
190 'deleteAccountTabTitle':"Cancella il tuo utente",
191 'deleteAccountFormUsernameLabel':"Utente",
192 'deleteAccountFormPassphraseLabel':"frase segreta",
193 'deleteAccountFormSafetyCheckboxLabel':"Sono consapevole che tutti miei dati verranno cancellati e che questa azione è irreversibile.",
194 'deleteAccountFormSubmitLabel':"Cancella il mio utente",
195 'deleteAccountFormWrongUsernameWarning':"Utente errato",
196 'deleteAccountFormWrongPassphraseWarning':"Frase segreta errata",
197 'deleteAccountFormSafetyCheckWarning':"Leggi e spunta le condizioni sotto riportate.",
198 'accountPanelDeletingAccountPanelConfirmationTitle':"ATTENZIONE",
199 'accountPanelDeleteAccountPanelConfirmationText':"Sei sicuro di voler cancellare il tuo utente?",
200 'offlineCopyTabLabel':"Copia offline",
201 'offlineCopyTabTitle':"Copia offline",
202 'offlineCopyTabDescription':"<p>Con un solo clic puoi trasferire tutti i tuoi dati dai server di Clipperz al tuo PC, creando una versione offline di Clipperz a cui potrai accedere quando non è disponibile un collegamento ad Internet.</p> <p>La versione offline in sola lettura è sicura quanto quella online e non espone i tuoi dati a livelli di rischio superiore in quanto entrambe condividono la medesima architettura di sicurezza.</p> <ol> <li> <p>Clicca sul link sottostante per scaricare la copia offline dei tuoi dati.</p> </li> <li> <p>Il browser ti chiederà cosa fare del file “Clipperz_YYYYMMDD.html”. Scegli di salvarlo su un disco locale.</p> </li> <li> <p>Basta un doppio click sul file appena scaricato per lanciare la versione offline di Clipperz.</p> </li> <li> <p>Accedi utilizzando le normali credenziali di accesso.</p> </li> </ol> ",
203 'offlineCopyDownloadLinkLabel':"Scarica copia offline",
204 'offlineCopyDownloadWarning':"<h4><a href=\"#\" id=\"offlineCopyDownloadWarningLink\">Aggiorna la tua “copia offline”!</a> </h4> <p>Una o più schede sono state recentemente create o modificate, ti consigliamo di scaricare nuovamente la tua “copia offline”.</p> ",
205 'offlineCopyDownloadOk':"",
206 'sharingTabLabel':"Condividi",
207 'sharingTabTitle':"Condividi",
208 'sharingTabDescription':"<p>Spesso è necessario condividere alcune delle proprie informazioni riservate con una o più persone.</p> <p>Può trattarsi di situazioni semplici come dare ad un collega il codice di accesso alla propria segreteria telefonica quando si va in vacanza, oppure complesse come regolare l&#x27;accesso dei legittimi eredi ai servizi di online banking utilizzati dal defunto.</p> <p>Con Clipperz la condivisione di segreti diviene un processo semplice e sicuro.</p> <p> </p> <p><b>Presto disponibile ...</b> </p> ",
209 'importTabLabel':"Importa",
210 'importTabTitle':"Importa",
211 'importTabDescription':"<p>Presto disponibile ...</p> ",
212 'printingTabLabel':"Esporta",
213 'printingTabTitle':"Esporta",
214 'printingTabDescription':"<h5>Stampa i tuoi dati</h5> <p>Cliccando sul link sottostante si aprirà una nuova finestra in cui verranno visualizzate tutte le tue schede in un formato idoneo alla stampa.</p> <p>Se intendi utilizzare la stampa per creare una copia di sicurezza dei tuoi dati, ti suggeriamo di considerare l&#x27;opzione più sicura fornita della “copia offline”.</p> ",
215 'printingLinkLabel':"Versione stampabile",
216 'contactsTabLabel':"Contatti",
217 'contactsTabTitle':"Contatti",
218 'passwordGeneratorTabLabel':"Generatore di password",
219 'bookmarkletTabLabel':"Bookmarklet",
220 'passwordGeneratorTabTitle':"Generatore di password",
221 'bookmarkletTabTitle':"Bookmarklet",
222 'paswordGeneratorTabDescription':"<p> </p> ",
223 'passwordGeneratorTabButtonLabel':"Genera password",
224 'bookmarkletTabLabel':"Bookmarklet",
225 'bookmarkletTabTitle':"Bookmarklet",
226 'bookmarkletTabBookmarkletTitle':"Aggiungi a Clipperz",
227 'bookmarkletTabInstructions':"<h3>Come creare una scheda con “login diretto” ad un servizio online</h3> <ol> <li> <p>Aprire la pagina web che contiene la maschera di login. (ovvero la pagina dove usualmente si inseriscono nome utente e password)</p> </li> <li> <p>Cliccare sulla bookmarklet: una nuova finestrella si visualizzerà sopra la pagina.</p> </li> <li> <p>Copiare il testo di configurazione del “login diretto” contenuto nella finestrella. (ctrl-C)</p> </li> <li> <p>Accedere a Clipperz e cliccare sul pulsante <b>Aggiungi nuova scheda</b> .</p> </li> <li> <p>Selezionare il modello “Login diretto” ed incollare il testo precedentemente copiato. (ctrl-V)</p> </li> <li> <p>Cliccare sul pulsante <b>Crea</b> , completare e verificare i dettagli della scheda, quindi cliccare su <b>Salva</b> .</p> </li> </ol> <h3>Come aggiungere un “login diretto” ad una scheda esistente</h3> <ol> <li> <p>Come sopra.</p> </li> <li> <p>Come sopra.</p> </li> <li> <p>Come sopra.</p> </li> <li> <p>Accedere a Clipperz e selezionare la scheda contenente le credenziali del servizio a cui si vuole accedere con il “login diretto” e cliccare su <b>Modifica</b> .</p> </li> <li> <p>Incollare il testo precedentemente copiato nell&#x27;apposito campo presente nella sezione “Login diretti”. (ctrl-V)</p> </li> <li> <p>Cliccare il pulsante <b>Aggiungi nuovo login diretto</b> , completare e verificare i dettagli della scheda, quindi cliccare su <b>Salva</b> .</p> </li> </ol> <p> </p> <p>Ulteriori informazioni sull&#x27;utilizzo della bookmarklet sono <a href=\"http://www.clipperz.com/support/user_guide/bookmarklet\" target=\"_blank\">disponibili qui</a> .</p> ",
228 'mainPanelDirectLoginBlockLabel':"Login diretti",
229 'directLinkReferenceShowButtonLabel':"mostra",
230 'mainPanelDirectLoginBlockDescription':"<p>Crea “login diretti” per accedere ai tuoi servizi web senza bisogno di inserire username e password!</p> <p>I “login diretti” migliorano la tua sicurezza permettendoti di:</p> <ul> <li> <p>adottare comodamente password complesse;</p> </li> <li> <p>non riutilizzare mai la stessa password.</p> </li> </ul> <p>Semplice e rapido grazie alla <b>Clipperz bookmarklet</b> .</p><a href=\"http://www.clipperz.com/support/user_guide/direct_logins\" target=\"_blank\">Ulteriori informazioni</a> ",
231 'mainPanelRecordsBlockLabel':"Schede",
232 'mainPanelAddRecordButtonLabel':"Aggiungi nuova scheda",
233 'mainPanelRemoveRecordButtonLabel':"Elimina scheda",
234 'mainPanelRecordFilterBlockTagsLabel':"tags",
235 'recordDetailNoRecordAtAllTitle':"Benvenuto a Clipperz!",
236 'recordDetailNoRecordAtAllDescription':"<h5>Ora puoi iniziare ad aggiungere schede con le tue informazioni riservate.</h5> <p>Le schede sono semplici moduli in cui organizzare le tue password ed ogni altro tipo di dato confidenziale.</p> <p>Le schede hanno una struttura flessibile e si adattano a contenere le informazioni più diverse: dalle password ai dettagli delle tue carte di credito!</p> <h5>Non dimenticarti di installare la bookmarklet!</h5> <p>Prima di iniziare ti consigliamo di installare la bookmarklet “Aggiungi a Clipperz”: creare nuove schede diventerà più rapido e divertente.</p> <p>Vai alla sezione “bookmarklet” per scoprire come installarla ed utilizzarla.</p> <p> </p> <p>Quando sei pronto, clicca sul pulsante <b>Aggiungi nuova scheda</b> e metti al sicuro tutte le tue informazioni più preziose.</p> <p> </p><a href=\"http://www.clipperz.com/support/user_guide/managing_cards\" target=\"_blank\">Maggiori informazioni sulla creazione e gestione delle schede (in inglese)</a> ",
237 'newRecordWizardTitleBox':"<h5>Seleziona un modello di scheda</h5> <p>Le schede sono semplici moduli in cui organizzare le tue password ed ogni altro tipo di dato confidenziale.</p> <p>Scegli un modello dall&#x27;elenco sottostante. In seguito potrai sempre modificare la tua scheda aggiungendo o rimuovendo campi.</p> ",
238 'newRecordWizardBookmarkletConfigurationTitle':"Login diretto",
239 'newRecordWizardBookmarkletConfigurationDescription':"<p>Incolla qui sotto il codice generato dalla bookmarklet di Clipperz.</p> <p>Verrà creata una nuova scheda già completa con le informazioni per il “login diretto” al tuo servizio web.</p> ",
240 'newRecordWizardCreateButtonLabel':"Crea",
241 'newRecordWizardCancelButtonLabel':"Annulla",
242 'donateSplashPanelTitle':"Supporta Clipperz, fai una donazione oggi!",
243 'donateSplashPanelDescription':"<p>Alcune buone ragioni per fare una donazione:</p> <ul> <li> <p>supportare lo sviluppo di nuove funzionalità</p> </li> <li> <p>mantenere il servizio gratuito per tutti</p> </li> <li> <p>mostrare la tua gratitudine per il nostro duro lavoro</p> </li> </ul> <p>Per qualunque ulteriore informazione visita la <a href=\"http://www.clipperz.com/donations\" target=\"_blank\">pagina delle donazioni</a> .</p> <p><b>Pronto a donare?</b> </p> ",
244 'donateCloseButtonLabel':"Non ancora",
245 'recordTemplates':{
246 'WebAccount':{
247 'title':"Password",
248 'description':"<p>Una scheda molto semplice per conservare le credenziali di accesso ai tuoi servizi web.</p> ",
249 'fields':{
250 'URL':"Indirizzo web",
251 'TXT':"Utente o email",
252 'PWD':"Password"
253 }
254 },
255 'BankAccount':{
256 'title':"Conto corrente bancario",
257 'description':"<p>Proteggi il tuo numero di conto corrente ed i codici di accesso ai servizi di online banking.</p> ",
258 'fields':{
259 'TXT':"Banca",
260 'TXT':"Conto corrente n.",
261 'URL':"Sito web della banca",
262 'TXT':"Online banking ID",
263 'PWD':"Online banking password"
264 }
265 },
266 'CreditCard':{
267 'title':"Carta di credito",
268 'description':"<p>Numero della carta, data di scadenza, codici CVV2 e PIN sempre a portata di mano con Clipperz.</p> ",
269 'fields':{
270 'TXT':"Tipo (Visa, AmEx, ...)",
271 'TXT':"Numero",
272 'TXT':"Titolare",
273 'TXT':"Data di scadenza",
274 'TXT':"CVV2",
275 'PWD':"PIN",
276 'URL':"Sito web della carta",
277 'TXT':"Utente",
278 'PWD':"Password"
279 }
280 },
281 'AddressBookEntry':{
282 'title':"Voce della rubrica",
283 'description':"<p>Fai di Clipperz la tua rubrica segreta. Usa questo modello per creare una nuova voce.</p> ",
284 'fields':{
285 'TXT':"Nome",
286 'TXT':"Email",
287 'TXT':"Telefono",
288 'TXT':"Cellulare",
289 'ADDR':"Indirizzo"
290 }
291 },
292 'Custom':{
293 'title':"Scheda personalizzata",
294 'description':"<p>Qualunque sia il tipo di informazione che desideri proteggere, Clipperz ti consente di creare una scheda su misura per i tuoi bisogni.</p> ",
295 'fields':{
296 'TXT':"Nome del campo 1",
297 'TXT':"Nome del campo 2",
298 'TXT':"Nome del campo 3"
299 }
300 }
301},
302 'recordFieldTypologies':{
303 'TXT':{
304 'description':"simple text field"
305 },
306 'PWD':{
307 'description':"simple text field, with default status set to hidden",
308 'shortDescription':"Password"
309 },
310 'URL':{
311 'description':"simple text field in edit mode, that became an active url in view mode",
312 'shortDescription':"Indirizzo web"
313 },
314 'DATE':{
315 'description':"a value set with a calendar helper",
316 'shortDescription':"data"
317 },
318 'ADDR':{
319 'description':"just like the URL, but the active link points to Google Maps (or similar service) passing the address value as argument",
320 'shortDescription':"indirizzo stradale"
321 },
322 'CHECK':{
323 'description':"check description",
324 'shortDescription':"check"
325 },
326 'RADIO':{
327 'description':"radio description",
328 'shortDescription':"radio"
329 },
330 'SELECT':{
331 'description':"select description",
332 'shortDescription':"Seleziona:"
333 }
334},
335 'newRecordPanelGeneralExceptionTitle':"Errore",
336 'newRecordPanelGeneralExceptionMessage':"Configurazione non valida. Accertati di aver utilizzato il codice quello generato dalla bookmarklet.",
337 'newRecordPanelWrongBookmarkletVersionExceptionTitle':"Errore",
338 'newRecordPanelWrongBookmarkletVersionExceptionMessage':"La configurazione è stato generata da una vecchia versione della bookmarklet. Sei pregato di aggiornare subito la tua bookmarklet.",
339 'newRecordPanelExceptionPanelCloseButtonLabel':"Annulla",
340 'mainPanelDeletingRecordPanelConfirmationTitle':"Eliminazione della scheda in corso",
341 'mainPanelDeleteRecordPanelConfirmationText':"Vuoi veramente eliminare la scheda selezionata?",
342 'mainPanelDeletingRecordPanelInitialTitle':"Eliminazione della scheda in corso",
343 'mainPanelDeletingRecordPanelInitialText':"---",
344 'mainPanelDeletingRecordPanelCompletedText':"Fatto",
345 'deleteRecordPanelCollectRecordDataMessageTitle':"Elimina scheda",
346 'deleteRecordPanelCollectRecordDataMessageText':"Aggiorna elenco delle schede",
347 'deleteRecordPanelEncryptUserDataMessageTitle':"Elimina scheda",
348 'deleteRecordPanelEncryptUserDataMessageText':"Cripta localmente l&#x27;intestazione delle schede",
349 'deleteRecordPanelSendingDataToTheServerMessageTitle':"Elimina scheda",
350 'deleteRecordPanelSendingDataToTheServerMessageText':"Carica le intestazioni criptate delle schede su Clipperz",
351 'deleteRecordPanelUpdatingTheInterfaceMessageTitle':"Elimina scheda",
352 'deleteRecordPanelUpdatingTheInterfaceMessageText':"Aggiornamento dell&#x27;interfaccia",
353 'recordDetailNoRecordSelectedTitle':"Nessuna scheda selezionata",
354 'recordDetailNoRecordSelectedDescription':"<p>Selezionare una scheda dall&#x27;elenco a sinistra.</p> ",
355 'recordDetailLoadingRecordMessage':"Scarica scheda criptata da Clipperz",
356 'recordDetailDecryptingRecordMessage':"Decodifica locale dei dati della scheda",
357 'recordDetailLoadingRecordVersionMessage':"Scarica l&#x27;ultima versione della scheda",
358 'recordDetailDecryptingRecordVersionMessage':"Decodifica locale dell&#x27;ultima versione",
359 'recordDetailLoadingErrorMessageTitle':"Errore nello scaricamento della scheda",
360 'recordDetailNotesLabel':"Note",
361 'recordDetailLabelFieldColumnLabel':"Nome del campo",
362 'recordDetailDataFieldColumnLabel':"Dati del campo",
363 'recordDetailTypeFieldColumnLabel':"Tipo",
364 'recordDetailSavingChangesMessagePanelInitialTitle':"Salvataggio scheda",
365 'recordDetailSavingChangesMessagePanelInitialText':"---",
366 'recordDetailRemoveFieldButtonLabel':"-",
367 'recordDetailAddFieldButtonLabel':"Aggiungi nuovo campo",
368 'recordDetailPasswordFieldHelpLabel':"clicca le stelline per copiare la password e poi Ctrl-C",
369 'recordDetailPasswordFieldScrambleLabel':"nascondi",
370 'recordDetailPasswordFieldUnscrambleLabel':"mostra",
371 'recordDetailDirectLoginBlockTitle':"Login diretti",
372 'recordDetailNewDirectLoginDescription':"<p>Configurazione del login diretto</p> ",
373 'recordDetailDirectLoginBlockNoDirectLoginConfiguredDescription':"<p>Questa scheda contiene credenziali di accesso ad un servizio online?</p> <p>In tal caso puoi utilizzare la bookmarklet per configurare un “login diretto” da Clipperz con un solo clic!</p> ",
374 'recordDetailDeleteDirectLoginButtonLabel':"-",
375 'recordDetailAddNewDirectLoginButtonLabel':"Aggiungi nuovo login diretto",
376 'recordDetailEditButtonLabel':"Modifica",
377 'recordDetailSaveButtonLabel':"Salva",
378 'recordDetailCancelButtonLabel':"Annulla",
379 'newRecordTitleLabel':"_nuova scheda_",
380 'newDirectLoginLabelSuffix':"",
381 'recordSaveChangesPanelCollectRecordInfoMessageTitle':"Salva scheda",
382 'recordSaveChangesPanelCollectRecordInfoMessageText':"Aggiorna elenco delle schede",
383 'recordSaveChangesPanelEncryptUserDataMessageTitle':"Salva scheda",
384 'recordSaveChangesPanelEncryptUserDataMessageText':"Cripta localmente l&#x27;intestazione delle schede",
385 'recordSaveChangesPanelEncryptRecordDataMessageTitle':"Salva scheda",
386 'recordSaveChangesPanelEncryptRecordDataMessageText':"Cripta localmente i dati della scheda",
387 'recordSaveChangesPanelEncryptRecordVersionDataMessageTitle':"Salva scheda",
388 'recordSaveChangesPanelEncryptRecordVersionDataMessageText':"Cripta localmente la versione della scheda",
389 'recordSaveChangesPanelSendingDataToTheServerMessageTitle':"Salva scheda",
390 'recordSaveChangesPanelSendingDataToTheServerMessageText':"Carica le intestazioni criptate delle schede su Clipperz",
391 'recordSaveChangesPanelUpdatingTheInterfaceMessageTitle':"Salva scheda",
392 'recordSaveChangesPanelUpdatingTheInterfaceMessageText':"Aggiornamento dell&#x27;interfaccia",
393 'passwordGeneratorPanelTitle':"Generatore di password",
394 'passwordGeneratorPanelOkLabel':"Ok",
395 'passwordGeneratorPanelCancelLabel':"Annulla",
396 'passwordGeneratorLengthLabel':"lung . :",
397 //'DWRUtilLoadingMessage':"Caricamento dati",
398 'comingSoon':"Presto disponibile ...",
399 'panelCollectingEntryopyMessageText':"Raccolta entropia",
400 'importData_parsingDataTitle':"Importa",
401 'importData_previewingDataTitle':"Importa",
402 'importData_processingDataTitle':"Importa",
403 'ImportWizard':{
404 'EDIT':"Modifica",
405 'IMPORT':"Importa",
406 'CSV_NOTES':"Note",
407 'EXCEL_EDIT':"Modifica"
408},
409 'importData_importConfirmation_title':"Importa",
410 'WELCOME_BACK':"Bentornato!",
411 'currentConnectionText':"Sei collegato da ip __ip__; probabilmente in __country__, utilizzando __browser__ con __operatingSystem__.",
412 'latestConnectionText':"Il tuo ultimo accesso è stato __elapsedTimeDescription__ (__time__) da ip __ip__; probabilmente in __country__, utilizzando __browser__ con __operatingSystem__.",
413 'fullLoginHistoryLinkLabel':"vai al registro degli accessi",
414 'elapsedTimeDescriptions':{
415 'MORE_THAN_A_MONTH_AGO':"più di un mese fa",
416 'MORE_THAN_A_WEEK_AGO':"più di una settimana fa",
417 'MORE_THAN_*_WEEKS_AGO':"più di __elapsed__ settimane fa",
418 'YESTERDAY':"ieri",
419 '*_DAYS_AGO':"__elapsed__ giorni fa",
420 'ABOUT_AN_HOUR_AGO':"circa un&#x27;ora fa",
421 '*_HOURS_AGO':"__elapsed__ ore fa",
422 'JUST_A_FEW_MINUTES_AGO':"pochi minuti fa",
423 'ABOUT_*_MINUTES_AGO':"circa __elapsed__ minuti fa"
424},
425 'unknown_ip':"sconosciuto",
426 'countries':{
427 '--':"sconosciuto",
428 'AD':"Andorra",
429 'AE':"Emirati arabi uniti",
430 'AF':"Afghanistan",
431 'AG':"Antigua e Barbuda",
432 'AI':"Anguilla",
433 'AL':"Albania",
434 'AM':"Armenia",
435 'AN':"Antille olandesi",
436 'AO':"Angola",
437 'AR':"Argentina",
438 'AS':"Samoa americane",
439 'AT':"Austria",
440 'AU':"Australia",
441 'AW':"Aruba",
442 'AZ':"Azerbaigian",
443 'BB':"Barbados",
444 'BD':"Bangladesh",
445 'BE':"Belgio",
446 'BF':"Burkina-Faso",
447 'BG':"Bulgaria",
448 'BH':"Bahrein",
449 'BI':"Burundi",
450 'BJ':"Benin",
451 'BM':"Bermuda",
452 'BN':"Brunei",
453 'BO':"Bolivia",
454 'BR':"Brasile",
455 'BS':"Bahamas",
456 'BT':"Bhutan",
457 'BW':"Botswana",
458 'BY':"Bielorussia",
459 'BZ':"Belize",
460 'CA':"Canada",
461 'CD':"Repubblica democratica del Congo",
462 'CF':"Repubblica centrafricana",
463 'CH':"Svizzera",
464 'CK':"Isole Cook",
465 'CL':"Cile",
466 'CM':"Camerun",
467 'CN':"Cina",
468 'CO':"Colombia",
469 'CR':"Costa Rica",
470 'CS':"Repubblica del Montenegro",
471 'CU':"Cuba",
472 'CY':"Cipro",
473 'CZ':"Repubblica ceca",
474 'DE':"Germania",
475 'DJ':"Gibuti",
476 'DK':"Danimarca",
477 'DO':"Repubblica dominicana",
478 'DZ':"Algeria",
479 'EC':"Ecuador",
480 'EE':"Estonia",
481 'EG':"Egitto",
482 'ER':"Eritrea",
483 'ES':"Spagna",
484 'ET':"Etiopia",
485 'FI':"Finlandia",
486 'FJ':"Figi",
487 'FM':"Micronesia",
488 'FO':"Isole Fær Øer",
489 'FR':"Francia",
490 'GA':"Gabon",
491 'GB':"Regno Unito",
492 'GD':"Grenada",
493 'GE':"Georgia",
494 'GF':"Guyana francese",
495 'GG':"Guernsey",
496 'GH':"Ghana",
497 'GI':"Gibilterra",
498 'GL':"Groenlandia",
499 'GM':"Gambia",
500 'GP':"Guadalupa",
501 'GR':"Grecia",
502 'GT':"Guatemala",
503 'GU':"Guam",
504 'GW':"Guinea-Bissau",
505 'GY':"Guyana",
506 'HK':"Hong Kong",
507 'HN':"Honduras",
508 'HT':"Haiti",
509 'HU':"Ungheria",
510 'ID':"Indonesia",
511 'IE':"Irlanda",
512 'IL':"Israele",
513 'IM':"Isola di Man",
514 'IN':"India",
515 'IO':"Territorio britannico dell&#x27;Oceano Indiano",
516 'IQ':"Iraq",
517 'IR':"Iran",
518 'IS':"Islanda",
519 'IT':"Italia",
520 'JE':"Jersey",
521 'JM':"Giamaica",
522 'JO':"Giordania",
523 'JP':"Giappone",
524 'KE':"Kenya",
525 'KG':"Kirghizistan",
526 'KH':"Cambogia",
527 'KI':"Kiribati",
528 'KN':"Saint Kitts e Nevis",
529 'KR':"Corea del Sud",
530 'KW':"Kuwait",
531 'KY':"Isole Cayman",
532 'KZ':"Kazakistan",
533 'LA':"Laos",
534 'LB':"Libano",
535 'LC':"Saint Lucia",
536 'LI':"Liechtenstein",
537 'LK':"Sri Lanka",
538 'LR':"Liberia",
539 'LS':"Lesotho",
540 'LT':"Lituania",
541 'LU':"Lussemburgo",
542 'LV':"Lettonia",
543 'LY':"Libia",
544 'MA':"Marocco",
545 'MC':"Monaco",
546 'MD':"Moldova",
547 'MG':"Madagascar",
548 'MH':"Isole Marshall",
549 'ML':"Mali",
550 'MM':"Myanmar",
551 'MN':"Mongolia",
552 'MP':"Marianne settentrionali",
553 'MR':"Mauritania",
554 'MS':"Montserrat",
555 'MT':"Malta",
556 'MU':"Maurizio",
557 'MV':"Maldive",
558 'MW':"Malawi",
559 'MX':"Messico",
560 'MY':"Malaysia",
561 'MZ':"Mozambico",
562 'NA':"Namibia",
563 'NC':"Nuova Caledonia",
564 'NF':"Isola Norfolk",
565 'NG':"Nigeria",
566 'NI':"Nicaragua",
567 'NL':"Paesi Bassi",
568 'NO':"Norvegia",
569 'NP':"Nepal",
570 'NR':"Nauru",
571 'NU':"Niue",
572 'NZ':"Nuova Zelanda",
573 'OM':"Oman",
574 'PA':"Panama",
575 'PE':"Perù",
576 'PF':"Polinesia francese",
577 'PG':"Papua Nuova Guinea",
578 'PH':"Filippine",
579 'PK':"Pakistan",
580 'PL':"Polonia",
581 'PR':"Puerto Rico",
582 'PS':"Territori palestinesi",
583 'PT':"Portogallo",
584 'PW':"Palau",
585 'PY':"Paraguay",
586 'QA':"Qatar",
587 'RO':"Romania",
588 'RS':"Serbia",
589 'RU':"Russia",
590 'RW':"Ruanda",
591 'SA':"Arabia Saudita",
592 'SB':"Isole Salomone",
593 'SC':"Seicelle",
594 'SD':"Sudan",
595 'SE':"Svezia",
596 'SG':"Singapore",
597 'SI':"Slovenia",
598 'SL':"Sierra Leone",
599 'SM':"San Marino",
600 'SN':"Senegal",
601 'SR':"Suriname",
602 'SV':"El Salvador",
603 'SY':"Siria",
604 'SZ':"Swaziland",
605 'TC':"Turks e Caicos",
606 'TG':"Togo",
607 'TH':"Thailandia",
608 'TJ':"Tagikistan",
609 'TM':"Turkmenistan",
610 'TN':"Tunisia",
611 'TO':"Tonga",
612 'TR':"Turchia",
613 'TV':"Tuvalu",
614 'TW':"Taiwan",
615 'TZ':"Tanzania",
616 'UA':"Ucraina",
617 'UG':"Uganda",
618 'US':"Stati Uniti",
619 'UY':"Uruguay",
620 'UZ':"Uzbekistan",
621 'VA':"Santa Sede (Stato della Città del Vaticano)",
622 'VE':"Venezuela",
623 'VG':"Isole Vergini britanniche",
624 'VI':"Isole Vergini statunitensi",
625 'VN':"Vietnam",
626 'VU':"Vanuatu",
627 'WS':"Samoa",
628 'YE':"Yemen",
629 'ZA':"Sud Africa",
630 'ZM':"Zambia",
631 'ZW':"Zimbabwe"
632},
633 'browsers':{
634 'UNKNOWN':"sconosciuto"
635},
636 'operatingSystems':{
637 'UNKNOWN':"sconosciuto",
638 'MOBILE':"Cellulare"
639},
640 'calendarStrings':{
641 'months':{
642 '0':"Gennaio",
643 '1':"Febbraio",
644 '2':"Marzo",
645 '3':"Aprile",
646 '4':"Mag",
647 '5':"Giugno",
648 '6':"Luglio",
649 '7':"Agosto",
650 '8':"Settembre",
651 '9':"Ottobre",
652 '10':"Novembre",
653 '11':"Dicembre"
654 },
655 'shortMonths':{
656 '0':"Gen",
657 '1':"Feb",
658 '2':"Mar",
659 '3':"Apr",
660 '4':"Mag",
661 '5':"Giu",
662 '6':"Lug",
663 '7':"Ago",
664 '8':"Set",
665 '9':"Ott",
666 '10':"Nov",
667 '11':"Dic"
668 },
669 'days':{
670 '0':"Domenica",
671 '1':"Lunedì",
672 '2':"Martedì",
673 '3':"Mercoledì",
674 '4':"Giovedì",
675 '5':"Venerdì",
676 '6':"Sabato"
677 },
678 'shortDays':{
679 '0':"Dom",
680 '2':"Mar",
681 '3':"Mer",
682 '4':"Gio",
683 '5':"Ven",
684 '6':"Sab"
685 },
686 'veryShortDays':{
687 '1':"Lu",
688 '4':"Gi",
689 '5':"Ve"
690 }
691},
692
693__syntaxFix__: "syntax fix"
694});
diff --git a/frontend/beta/js/Clipperz/PM/Strings/Strings_ja-JP.js b/frontend/beta/js/Clipperz/PM/Strings/Strings_ja-JP.js
new file mode 100644
index 0000000..2b571b7
--- a/dev/null
+++ b/frontend/beta/js/Clipperz/PM/Strings/Strings_ja-JP.js
@@ -0,0 +1,808 @@
1/*
2
3Copyright 2008-2011 Clipperz Srl
4
5This file is part of Clipperz's Javascript Crypto Library.
6Javascript Crypto Library provides web developers with an extensive
7and efficient set of cryptographic functions. The library aims to
8obtain maximum execution speed while preserving modularity and
9reusability.
10For further information about its features and functionalities please
11refer to http://www.clipperz.com
12
13* Javascript Crypto Library is free software: you can redistribute
14 it and/or modify it under the terms of the GNU Affero General Public
15 License as published by the Free Software Foundation, either version
16 3 of the License, or (at your option) any later version.
17
18* Javascript Crypto Library is distributed in the hope that it will
19 be useful, but WITHOUT ANY WARRANTY; without even the implied
20 warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
21 See the GNU Affero General Public License for more details.
22
23* You should have received a copy of the GNU Affero General Public
24 License along with Javascript Crypto Library. If not, see
25 <http://www.gnu.org/licenses/>.
26
27*/
28
29Clipperz.PM.Strings.Languages['ja-JP'.toLowerCase()] = MochiKit.Base.merge(Clipperz.PM.Strings.Languages['en-us'], {
30 'clipperzServiceDescription':"<h2>自分で管理しよう!</h2> <ul> <li> <h3>Clipperz は</h3> <ul> <li> <p>安全でシンプルなパスワードマネージャです</p> </li> <li> <p>シングルサインオンを提供します</p> </li> <li> <p>機密情報のデジタル格納庫です</p> </li> </ul> </li> <li> <h3>Clipperz でできること</h3> <ul> <li> <p>パスワードを保管して管理できます</p> </li> <li> <p>ユーザー名やパスワードを入力せずに登録したウェブサービスにログインできます</p> </li> <li> <p>暗証番号やクレジットカード番号などあらゆる機密情報を守ります</p> </li> <li> <p>家族や信用できる相手と機密情報を共有できます(提供予定)</p> </li> </ul> </li> <li> <h3>Clipperz のよいところ</h3> <ul> <li> <p>無料で匿名利用できます</p> </li> <li> <p>いつでもどのコンピュータからでもアクセスできます</p> </li> <li> <p>ソフトウェアのダウンロードやインストールは不要です</p> </li> <li> <p>PC や紙に機密情報を残す必要がありません</p> </li> </ul> </li> <li> <h3>Clipperz のセキュリティ</h3> <ul> <li> <p>データはブラウザで暗号化されてから Clipprez に送信されます</p> </li> <li> <p>暗号化のキーはあなただけが知っているパスフレーズです</p> </li> <li> <p>保管したデータは暗号化されていて、保管中には決して中身を見ることができません</p> </li> <li> <p>標準が確立された暗号化手順を採用しています</p> </li> <li> <p>ソースコードはいつでも参照できますが、暗号化について何も知らなくても使えます</p> </li> </ul> </li> <li><a href=\"http://www.clipperz.com\" target=\"_blank\">もっと見る</a> </li> </ul> ",
31 'loginFormTitle':"Clipperz のアカウントでログイン",
32 'loginFormUsernameLabel':"ユーザー名",
33 'loginFormPassphraseLabel':"パスフレーズ",
34 'loginFormDontHaveAnAccountLabel':"アカウントを持っていない?",
35 'loginFormCreateOneLabel':"新規作成",
36 'loginFormForgotYourCredentialsLabel':"パスフレーズを忘れた?",
37 'loginFormAarghThatsBadLabel':"それは困った!",
38 'loginFormAfraidOfMaliciousScriptsLabel':"偽サイトかも?",
39 'loginFormVerifyTheCodeLabel':"確認する",
40 'loginFormButtonLabel':"ログイン",
41 'loginFormOneTimePasswordCheckboxLabel':"ワンタイムパスフレーズ使用",
42 'loginFormOneTimePasswordCheckboxDescription':"",
43 'loginPanelSwithLanguageDescription':"<h5>言語設定の変更</h5> ",
44 'browserCompatibilityDescription':"<p>Clipperz は Firefox に最適化されています。 しかし Clipperz は Opera や Safari そしてインターネットエクスプローラでも十分動作します。</p> ",
45 'OTPloginMessagePanelInitialTitle':"ワンタイムパスフレーズでログイン中",
46 'OTPloginMessagePanelInitialText':"OTP 情報送信中 ...",
47 'OTPloginMessagePanelLoadingTitle':"ワンタイムパスフレーズでログイン中",
48 'OTPloginMessagePanelLoadingText':"認証情報を取得中 ...",
49 'OTPloginMessagePanelProcessingTitle':"ワンタイムパスフレーズでログイン中",
50 'OTPloginMessagePanelProcessingText':"認証情報を復号中 ...",
51 'loginMessagePanelInitialTitle':"ログイン中 ...",
52 'loginMessagePanelInitialText':"---",
53 'loginMessagePanelInitialButtonLabel':"キャンセル",
54 'loginMessagePanelConnectedTitle':"接続完了",
55 'loginMessagePanelConnectedText':"完了",
56 'loginMessagePanelFailureTitle':"エラー",
57 'loginMessagePanelFailureText':"ログインに失敗しました",
58 'loginMessagePanelFailureButtonLabel':"閉じる",
59 'connectionLoginSendingCredentialsMessageTitle':"認証確認中",
60 'connectionLoginSendingCredentialsMessageText':"認証送信中",
61 'connectionLoginCredentialsVerificationMessageTitle':"認証確認中",
62 'connectionLoginCredentialsVerificationMessageText':"SRP 認証中",
63 'connectionLoginDoneMessageTitle':"認証確認中",
64 'connectionLoginDoneMessageText':"接続完了",
65 'userLoginPanelUpgradingUserCredentialsMessageTitle':"認証確認中",
66 'userLoginPanelUpgradingUserCredentialsMessageText':"認証更新中",
67 'userLoginPanelConnectedMessageTitle':"認証完了",
68 'userLoginPanelConnectedMessageText':"ログイン完了",
69 'userLoginPanelTryingAnOlderConnectionSchemaMessageTitle':"認証確認中",
70 'userLoginPanelTryingAnOlderConnectionSchemaMessageText':"認証復元中",
71 'userLoginPanelLoadingUserDataMessageTitle':"認証完了",
72 'userLoginPanelLoadingUserDataMessageText':"暗号化データを受信中",
73 'userLoginPanelDecryptingUserDataMessageTitle':"認証完了",
74 'userLoginPanelDecryptingUserDataMessageText':"復号中",
75 'userLoginPanelDecryptingUserStatisticsMessageTitle':"認証完了",
76 'userLoginPanelDecryptingUserStatisticsMessageText':"復号中",
77 'splashAlertTitle':"Clipperz へようこそ",
78 'splashAlertText':"<p>セキュリティアドバイス</p> <ul> <li> <p>Clipperz に保管したデータはパスフレーズによって保護されます。 パスフレーズを知らない人はデータにアクセスできません。</p> </li> <li> <p>Clipperz に重要なデータを保管するためにパスフレーズを類推されにくいものにしてください。 長いほど安全です。</p> </li> <li> <p>パスフレーズを忘れてしまったら Clipperz ではデータを復元できません。</p> </li> </ul> <p>さらに詳しくは Clipperz のサイトをごらんください。</p> ",
79 'splashAlertCloseButtonLabel':"OK",
80 'registrationFormTitle':"新規アカウント作成",
81 'registrationFormUsernameLabel':"ユーザー名",
82 'registrationFormPassphraseLabel':"パスフレーズ",
83 'registrationFormRetypePassphraseLabel':"パスフレーズをもう一度",
84 'registrationFormSafetyCheckLabel':"パスフレーズを忘れたら復活できないことを了承します。",
85 'registrationFormTermsOfServiceCheckLabel':"利用許諾に同意します 。",
86 'registrationFormDoYouAlreadyHaveAnAccountLabel':"アカウントを持っている?",
87 'registrationFormSimplyLoginLabel':"すぐにログイン",
88 'registrationFormButtonLabel':"登録",
89 'registrationFormWarningMessageNotMatchingPassphrases':"パスフレーズの入力に誤りがあります。 再入力してください。",
90 'registrationFormWarningMessageSafetyCheckNotSelected':"説明を読んで下のボックスを全てチェックしてください。",
91 'registrationFormWarningMessageTermsOfServiceCheckNotSelected':"利用許諾に同意してください。",
92 'registrationMessagePanelInitialTitle':"アカウント作成中 ...",
93 'registrationMessagePanelInitialText':"---",
94 'registrationMessagePanelInitialButtonLabel':"キャンセル",
95 'registrationMessagePanelRegistrationDoneTitle':"登録",
96 'registrationMessagePanelRegistrationDoneText':"完了",
97 'registrationMessagePanelFailureTitle':"登録失敗",
98 'registrationMessagePanelFailureButtonLabel':"閉じる",
99 'connectionRegistrationSendingRequestMessageText':"認証確認中",
100 'connectionRegistrationSendingCredentialsMessageText':"認証送信中",
101 'registrationSplashPanelTitle':"セキュリティアドバイス",
102 'registrationSplashPanelDescription':"<p>Clipperz の認証情報です。 大切に保管してください。 ユーザー名とパスフレーズは二度と表示されません。</p> ",
103 'registrationSplashPanelUsernameLabel':"ユーザー名",
104 'registrationSplashPanelPassphraseLabel':"パスフレーズ",
105 'registrationSplashPanelShowPassphraseButtonLabel':"パスフレーズを表示",
106 'donateHeaderLinkLabel':"寄付",
107 'creditsHeaderLinkLabel':"クレジット",
108 'feedbackHeaderLinkLabel':"フィードバック",
109 'helpHeaderLinkLabel':"ヘルプ",
110 'forumHeaderLinkLabel':"フォーラム",
111 'recordMenuLabel':"カード",
112 'accountMenuLabel':"アカウント",
113 'dataMenuLabel':"データ",
114 'contactsMenuLabel':"コンタクト",
115 'toolsMenuLabel':"ツール",
116 'logoutMenuLabel':"ログアウト",
117 'lockMenuLabel':"ロック",
118 'lockTitle':"アカウントはロックされました",
119 'lockDescription':"<p>ロックを解除するにはパスフレーズを入力してください。</p> ",
120 'unlockButtonLabel':"解除",
121 'changePasswordTabLabel':"パスフレーズの変更",
122 'changePasswordTabTitle':"パスフレーズの変更",
123 'changePasswordFormUsernameLabel':"ユーザー名",
124 'changePasswordFormOldPassphraseLabel':"今のパスフレーズ",
125 'changePasswordFormNewPassphraseLabel':"新しいパスフレーズ",
126 'changePasswordFormRetypePassphraseLabel':"パスフレーズをもう一度",
127 'changePasswordFormSafetyCheckboxLabel':"パスフレーズを忘れたら復活できないことを了承します。",
128 'changePasswordFormSubmitLabel':"変更",
129 'changePasswordFormWrongUsernameWarning':"ユーザー名が違います",
130 'changePasswordFormWrongPassphraseWarning':"パスフレーズが違います",
131 'changePasswordFormWrongRetypePassphraseWarning':"パスフレーズの入力に誤りがあります。 再入力してください。",
132 'changePasswordFormSafetyCheckWarning':"説明を読んでボックスをチェックしてください。",
133 'changePasswordFormProgressDialogTitle':"認証情報を変更中",
134 'changePasswordFormProgressDialogEmptyText':"---",
135 'changePasswordFormProgressDialogConnectedMessageTitle':"接続完了",
136 'changePasswordFormProgressDialogConnectedMessageText':"完了",
137 'changePasswordFormProgressDialogErrorMessageTitle':"エラー",
138 'changePasswordFormProgressDialogErrorMessageText':"変更に失敗しました",
139 'changeCredentialsPanelEncryptingDataMessageTitle':"パスフレーズを変更中",
140 'changeCredentialsPanelEncryptingDataMessageText':"カードヘッダ暗号化",
141 'changeCredentialsPanelCreatingNewCredentialsMessageTitle':"パスフレーズを変更中",
142 'changeCredentialsPanelCreatingNewCredentialsMessageText':"認証情報を送信中",
143 'changeCredentialsPanelSendingNewCredentialsToTheServerMessageTitle':"パスフレーズを変更中",
144 'changeCredentialsPanelSendingNewCredentialsToTheServerMessageText':"暗号化データを送信中",
145 'changeCredentialsPanelDoneMessageTitle':"パスフレーズを変更中",
146 'changeCredentialsPanelDoneMessageText':"完了",
147 'manageOTPTabLabel':"ワンタイムパスフレーズ管理",
148 'manageOTPTabTitle':"ワンタイムパスフレーズ管理",
149 'manageOTPTabDescription':"<p>ワンタイムパスフレーズは通常のパスフレームと同様に機能しますが、一回限りの使い捨てパスフレーズです。</p> <p>同じパスフレーズで再度ログインすることはできません。</p> <p>不正アクセス防止のためにログインに成功したら直ちにワンタイムパスフレーズは削除されます</p> <p>ワンタイムパスフレーズはキーロガーやスパイウェアからパスフレーズを守るすばらしい機能です</p> <p><b>インターネットカフェや図書館などから Clipperz にアクセする場合にはワンタイムパスフレーズを利用することを強くお薦めします。</b> </p> ",
150 'oneTimePasswordReadOnlyMessage':"<h6>ごめんなさい</h6> <p>ローカルコピー使用中はワンタイムパスフレーズを利用できません。</p> ",
151 'oneTimePasswordLoadingMessage':"<h6>ロード中</h6> <p>お待ちください ...</p> ",
152 'oneTimePasswordNoPasswordAvailable':"<h6>有効なワンタイムパスフレーズがありません</h6> <p>「新規」ボタンをクリックしてワンタイムパスフレーズを作成してください。</p> ",
153 'createNewOTPButtonLabel':"新規",
154 'deleteOTPButtonLabel':"削除",
155 'printOTPButtonLabel':"印刷",
156 'disabledOneTimePassword_warning':"無効",
157 'oneTimePasswordSelectionLink_selectLabel':"選択:",
158 'oneTimePasswordSelectionLink_all':"すべて",
159 'oneTimePasswordSelectionLink_none':"解除",
160 'oneTimePasswordSelectionLink_used':"使用済",
161 'oneTimePasswordSelectionLink_unused':"未使用",
162 'saveOTP_encryptUserDataTitle':"ワンタイムパスフレーズを保存中",
163 'saveOTP_encryptUserDataText':"OTP 認証譲歩を作成中 ...",
164 'saveOTP_encryptOTPDataTitle':"ワンタイムパスフレーズを保存中",
165 'saveOTP_encryptOTPDataText':"暗号化データを作成中 ...",
166 'saveOTP_sendingDataTitle':"ワンタイムパスフレーズを保存中",
167 'saveOTP_sendingDataText':"暗号化データを送信中 ...",
168 'saveOTP_updatingInterfaceTitle':"ワンタイムパスフレーズを保存中",
169 'saveOTP_updatingInterfaceText':"インターフェイスを更新中 ...",
170 'accountPreferencesLabel':"設定",
171 'accountPreferencesTabTitle':"設定",
172 'accountPreferencesLanguageTitle':"言語設定",
173 'accountPreferencesLanguageDescription':"<p>リストから使用する言語を選択してください。</p> ",
174 'showDonationReminderPanelTitle':"ドネーションリマインダ",
175 'showDonationReminderPanelDescription':"<p>ドネーションリマインダを表示</p> ",
176 'saveUserPreferencesFormSubmitLabel':"保存",
177 'cancelUserPreferencesFormSubmitLabel':"キャンセル",
178 'accountPreferencesSavingPanelTitle_Step1':"保存中",
179 'accountPreferencesSavingPanelText_Step1':"暗号化中",
180 'accountPreferencesSavingPanelTitle_Step2':"保存中",
181 'accountPreferencesSavingPanelText_Step2':"送信中",
182 'accountLoginHistoryLabel':"ログイン履歴",
183 'loginHistoryTabTitle':"ログイン履歴",
184 'loginHistoryReadOnlyMessage':"<h6>ごめんなさい</h6> <p>ローカルコピー使用中はログイン履歴を利用できません。</p> ",
185 'loginHistoryLoadingMessage':"<h6>ロード中</h6> <p>お待ちください ...</p> ",
186 'loginHistoryLoadedMessage':"<h6>最近 10 回のログイン</h6> <p> </p> ",
187 'loginHistoryIPLabel':"IP",
188 'loginHistoryTimeLabel':"日付",
189 'loginHistoryCurrentSessionText':"現在のログイン",
190 'loginHistoryReloadButtonLabel':"ログイン履歴を更新",
191 'deleteAccountTabLabel':"アカウント削除",
192 'deleteAccountTabTitle':"アカウント削除",
193 'deleteAccountFormUsernameLabel':"ユーザー名",
194 'deleteAccountFormPassphraseLabel':"パスフレーズ",
195 'deleteAccountFormSafetyCheckboxLabel':"全てのデータが消去されて復元不可能になることを了承します。",
196 'deleteAccountFormSubmitLabel':"アカウント削除",
197 'deleteAccountFormWrongUsernameWarning':"ユーザー名が違います",
198 'deleteAccountFormWrongPassphraseWarning':"パスフレーズが違います",
199 'deleteAccountFormSafetyCheckWarning':"説明を読んでボックスをチェックしてください。",
200 'accountPanelDeletingAccountPanelConfirmationTitle':"確認",
201 'accountPanelDeleteAccountPanelConfirmationText':"本当にアカウントを削除しますか?",
202 'accountPanelDeleteAccountPanelConfirmButtonLabel':"はい",
203 'accountPanelDeleteAccountPanelDenyButtonLabel':"いいえ",
204 'accountPanelDeletingAccountPanelProgressTitle':"アカウント情報削除中",
205 'accountPanelDeletingAccountPanelProgressText':"しばらくお待ちください",
206 'offlineCopyTabLabel':"ローカルコピー",
207 'offlineCopyTabTitle':"ローカルコピー",
208 'offlineCopyTabDescription':"<p>ダウンロードのリンクをクリクするとインターネットに接続していないときでも利用できる読み取り専用のローカル版をダウンロードできます。</p> <p>ローカル版はオンライン版と同じ暗号化処理がされているため、編集可能なオンライン版と同じ安全性があります。</p> <ol> <li> <p>下の「ダウンロード」をクリックします。</p> </li> <li> <p>ブラウザーが &quot;Clipperz_YYYYMMDD.html&quot; をダウンロードするか確認します。 ファイルをハードディスクに保存してください。</p> </li> <li> <p>ローカルコピーをダブルクリックして起動してください。</p> </li> <li> <p>オンライン版と同じユーザー名とパスフレーズを入力してください。</p> </li> </ol> ",
209 'offlineCopyDownloadLinkLabel':"ダウンロード",
210 'offlineCopyDownloadWarning':"<h4><a href=\"#\" id=\"offlineCopyDownloadWarningLink\">ローカルコピーを更新してください</a> </h4> <p>ローカルコピーを作成後に新しいカードを追加または編集しています。 最新の情報を保つためローカルコピーを更新してください。</p> ",
211 'offlineCopyDownloadOk':"",
212 'sharingTabLabel':"共有",
213 'sharingTabTitle':"共有",
214 'sharingTabDescription':"<p>暗証番号などを他人に教える必要があることは日常生活で往々にして発生します。</p> <p>同僚に留守番電話のメッセージを代わりに聞いてもらうために暗証番号を教えたり、秘書に代わりに銀行に行ってもらうために暗証番号を教えたりということはよくあることです。</p> <p>Clipperz では機密情報を安全に、そして簡単に共有できます。</p> <p> </p> <p><b>近日登場 ...</b> </p> ",
215 'importTabLabel':"インポート",
216 'importTabTitle':"インポート",
217 'importTabDescription':"<p>コンピュータから Clipperz にデータを一括インポートできます。</p> ",
218 'printingTabLabel':"エクスポート",
219 'printingTabTitle':"エクスポート",
220 'printingTabDescription':"<h5>印刷</h5> <p>「印刷用データ」のリンクをクリックするとウィンドウが開いて全てのデータが印刷可能な状態で表示されます。</p> <p>バックアップが目的なら、誰でも見ることができる印刷版よりは安全なローカルコピーをお薦めします。</p> ",
221 'printingLinkLabel':"印刷用データ",
222 'exportTabDescription':"<h5>JSON エクスポート</h5> <p>JSON はすべてのデータをエクスポートできます。 ダイレクトログインを含むすべての情報が保存されます。</p> <p>このフォーマットはすべてのデータを別の Clipperz アカウントに移動するときに便利です。 トラブルが発生したときにデータを復旧するのにも役立ちます。</p> <p>「JSON 出力」のリンクをクリックするとエクスポートが開始されます。</p> ",
223 'exportLinkLabel':"JSON 出力",
224 'exportDataInProgressDescription':"<h4>出力中。しばらくお待ちください ...</h4> ",
225 'exportDataDescription':"<h4>利用法</h4> <p>下のテキストを任意のエディターにコピーして保存します。 (例: 「clipperz_export_20071217.json」)</p> ",
226 'contactsTabLabel':"コンタクト",
227 'contactsTabTitle':"コンタクト",
228 'passwordGeneratorTabLabel':"パスワードジェネレータ",
229 'bookmarkletTabLabel':"ブックマークレット",
230 'compactTabLabel':"コンパクト版",
231 'httpAuthTabLabel':"HTTP 認証",
232 'passwordGeneratorTabTitle':"パスワードジェネレータ",
233 'bookmarkletTabTitle':"ブックマークレット",
234 'compactTabTitle':"コンパクト版",
235 'httpAuthTabTitle':"HTTP 認証",
236 'paswordGeneratorTabDescription':"<p> </p> ",
237 'passwordGeneratorTabButtonLabel':"パスワード生成",
238 'bookmarkletTabLabel':"ブックマークレット",
239 'bookmarkletTabTitle':"ブックマークレット",
240 'bookmarkletTabDescription':"<p>ブックマークレットはブラウザのブックマークに登録して使う小さなプログラムです。 通常のウェブページのブックマークと同じようにブラウザに登録できます。</p> <p>Clipperz のブックマークレットを使えば簡単に新規カードを追加したり、既存のカードにダイレクトログインを追加したりできます。</p> <p><b>Clipperz のブックマークレットにはユーザー名やパスフレーズなどの個人情報は含まれていません。ブックマークレットは全ユーザー共通のものです。</b> </p> <h3>ブックマークレットの登録方法</h3> <h>Firefox, Camino, Opera, Safari <ol> <li> <p>ブックマークバー(パーソナルバー)が表示されていることを確認します。 (「表示」メニュー(「表示>ツールバー」サブメニューの場合もあり)から変更できます。)</p> </li> <li> <p>下の「Clipperz に追加」をブックマークバー(パーソナルバー)にドラッグします。</p> </li> </ol> <h5>インターネットエクスプローラー</h5> <ol> <li> <p>アドレスバーが表示されていることを確認します。 (「表示>ツールバー>アドレスバー」メニューから変更できます。)</p> </li> <li> <p>下の「Clipperz に追加」を右クリックします。</p> </li> <li> <p>コンテキストメニューから「お気に入りに追加」を選択します。</p> </li> <li> <p>セキュリティ警告が表示されますので「はい」をクリックします。</p> </li> <li> <p>保存先の「リンク」フォルダーを開き「OK」をクリックします。</p> </li> </ol> ",
241 'bookmarkletTabBookmarkletTitle':"Clipperz に追加",
242 'bookmarkletTabInstructions':"<h3>ダイレクトログイン用の新規カードの作成方法</h3> <ol> <li> <p>保存したいサービスのログインページを開きます。 (パスワードなどを入力する画面があるところです)</p> </li> <li> <p>ブックマークレットをクリックします。 画面上にウィンドウがポップアップします。</p> </li> <li> <p>ポップアップしたウィンドウに表示された登録用コードをコピーします。 (ctrl-C)</p> </li> <li> <p>Clipperz にログインして 「新規カード追加」のボタンをクリックします。</p> </li> <li> <p>「ダイレクトログイン」のテンプレートを選んでコード入力用のスペースに先ほどコピーしたコードを貼り付けます。 (ctrl-V)</p> </li> <li> <p>「作成」ボタンをクリックして、内容を確認して「保存」ボタンをクリックします。</p> </li> </ol> <h3>既存カードへのダイレクトログインの追加方法</h3> <ol> <li> <p>上記と同じです。</p> </li> <li> <p>上記と同じです。</p> </li> <li> <p>上記と同じです。</p> </li> <li> <p>Clipperz にログインして変更したいカードを選択後「編集」ボタンをクリックします。</p> </li> <li> <p>ダイレクトログインコード用のスペースに先ほどコピーしたコードを貼り付けます。 (ctrl-V)</p> </li> <li> <p>「ダイレクトログイン追加」ボタンをクリックして、内容を確認して「保存」ボタンをクリックします。</p> </li> </ol> <p> </p> <p>ブックマークレットに関する詳しい情報はこちら。</p> ",
243 'compactTabDescription':"<p>Clipprez Compact は Firefox のサイドバーで利用するようデザインされた Clipperz の特別版です。</p> <p>ダイレクトログインを常時アクセス可能にします。 さらに詳しく </p> <h3>Clipperz Compact の利用法</h3> <ol> <li> <p>Firefox を入手します。 サイドバーは Firefox だけで利用できるため、 Clipperz Compact を利用するには Firefox が必須です。</p> </li> <li> <p>下の「Clipperz Compact」 URL を Firefox のブックマークに登録します。ブックマークバーにドラッグするのが簡単です。</p> <div id=\"compactLinkBox\"><a href=\"https://www.clipperz.com/beta/index.html?compact\" target=\"_search\">Clipperz Compact</a> </div> </li> <li> <p>ブックマークを右クリックして「情報を見る」を選択後、「このブックマークをサイドバーに読み込む」にチェックを入れます。</p> </li> </ol> <h5>追加情報:Clipperz Compact は Opera のパネルでも操作します。</h5> ",
244 'httpAuthTabDescription':"<p>HTTP 認証は HTML の基本機能を使ってブラウザからユーザー名とパスワードでログインする方式です。</p> <p>すでに主流ではありませんが、またプライベートなサイトなどで使われています。 HTTP 認証が必要なサイトにアクセスしようとすると、ブラウザがポップアップウィンドウを開いてユーザー名とパスワードの入力を要求してきます。</p> <p>残念ながら、 Clipperz のブックマークレットは HTTP 認証には対応していません。 しかし、ダイレクトログインを設定する方法はあります。</p> <h3>HTTP 認証サイトでのダイレクトログイン設定方法</h3> <ol> <li> <p>サイトの URL とユーザー名、パスワードを新規カードに登録します。</p> </li> <li> <p>下記の設定をコピーして、カード編集画面の「ダイレクトログイン設定」のセクションに貼り付けます。</p> </li> <li> <p>「新規ダイレクトログイン追加」ボタンをクリックして、 URL とユーザー名、パスワードを入力して保存します。</p> </li> </ol> <h5><a href=\"http://support.microsoft.com/kb/834489\" target=\"_blank\">警告:インターネットエクスプローラは HTTP 認証に対応していません。</a> </h5> ",
245 'mainPanelDirectLoginBlockLabel':"ダイレクトログイン",
246 'directLinkReferenceShowButtonLabel':"表示",
247 'mainPanelDirectLoginBlockDescription':"<p>ダイレクトログインを設定してユーザー名やパスワードを入力することなくログインできるようにしましょう。</p> <p>ダイレクトログインでさらにセキュリティを強化するために:</p> <ul> <li> <p>より複雑なパスワードを設定しましょう</p> </li> <li> <p>推測されやすい同じパスワードを複数のサイトで使わないようにしましょう。</p> </li> </ul> <p>ブックマークレットを使うと簡単に設定できます。</p><a href=\"http://www.clipperz.com/support/user_guide/direct_logins\" target=\"_blank\">ダイレクトログインに関する詳しい情報</a> ",
248 'mainPanelRecordsBlockLabel':"カード",
249 'mainPanelAddRecordButtonLabel':"新規カード追加",
250 'mainPanelRemoveRecordButtonLabel':"カード削除",
251 'mainPanelRecordFilterBlockAllLabel':"すべて",
252 'mainPanelRecordFilterBlockTagsLabel':"タグ",
253 'mainPanelRecordFilterBlockSearchLabel':"検索",
254 'recordDetailNoRecordAtAllTitle':"Clipperz へようこそ",
255 'recordDetailNoRecordAtAllDescription':"<h5>まず最初にカードを追加しましょう。</h5> <p>カードはパスワードやその他の重要な情報を保管するためのシンプルでフレキシブルなフォームです。</p> <p>カードにはウェブサイトのログインパスワード、自転車の鍵の番号、クレジットカードの番号など何でも記入できます。</p> <h5>ブックマークレットを活用しましょう。</h5> <p>まずは簡単にカードを追加できるブックマークレットをインストールしましょう。</p> <p>ブックマークレットのタブをクリックしてインストール方法と利用方法を確認しましょう。</p> <p> </p> <p>ブックマークレットをインストールしたら Clipperz を活用しましょう。</p> <p> </p><a href=\"http://www.clipperz.com/support/user_guide/managing_cards\" target=\"_blank\">カードに関する詳しい情報</a> ",
256 'newRecordWizardTitleBox':"<h5>テンプレート選択</h5> <p>カードはシンプルでパスワードや重要な情報を何でも保存できる柔軟性があります。</p> <p>まずはテンプレートを選んでください。  カードはいつでも自由に変更できます。</p> ",
257 'newRecordWizardBookmarkletConfigurationTitle':"ダイレクトログイン",
258 'newRecordWizardBookmarkletConfigurationDescription':"<p>ブックマークレットが生成したコードを下に貼り付けてください。</p> <p>ダイレクトログイン情報を含む新しいカードが作成されます。</p> ",
259 'newRecordWizardCreateButtonLabel':"作成",
260 'newRecordWizardCancelButtonLabel':"キャンセル",
261 'donateSplashPanelTitle':"Clipperz のために今すぐ寄付しよう",
262 'donateSplashPanelDescription':"<p>寄付する理由:</p> <ul> <li> <p>新機能追加をサポートします</p> </li> <li> <p>Clipperz を無料に保ちます</p> </li> <li> <p>開発陣の仕事に感謝します</p> </li> </ul> <p>詳しくは寄付のページをごらんください .</p> <p><b>寄付しますか?</b> </p> ",
263 'donateCloseButtonLabel':"あとでする",
264 'donateDonateButtonLabel':"はい",
265 'recordTemplates':{
266 'WebAccount':{
267 'title':"ウェブパスワード",
268 'description':"<p>ログイン情報用のシンプルなカードです。</p> ",
269 'fields':{
270 'URL':"ウェブアドレス",
271 'TXT':"ユーザー名またはメールアドレス",
272 'PWD':"パスワード"
273 }
274 },
275 'BankAccount':{
276 'title':"銀行口座",
277 'description':"<p>口座番号とオンラインバンキング情報用のカードです。</p> ",
278 'fields':{
279 'TXT':"銀行",
280 'TXT':"口座番号",
281 'URL':"銀行サイト",
282 'TXT':"オンラインバンキング ID",
283 'PWD':"オンラインバンキングパスワード"
284 }
285 },
286 'CreditCard':{
287 'title':"クレジットカード",
288 'description':"<p>クレジットカードに関するあらゆる情報を保管できます。</p> ",
289 'fields':{
290 'TXT':"種類(Visa 、 AMEX など)",
291 'TXT':"番号",
292 'TXT':"所有者名",
293 'TXT':"有効期限",
294 'TXT':"CVV2 番号",
295 'PWD':"暗証番号",
296 'URL':"カード会社サイト",
297 'TXT':"ユーザー名",
298 'PWD':"パスワード"
299 }
300 },
301 'AddressBookEntry':{
302 'title':"アドレス帳",
303 'description':"<p>Clipperz はプライベートなアドレス帳としても機能します。 このテンプレートを利用して簡単に新しい住所を追加できます。</p> ",
304 'fields':{
305 'TXT':"名前",
306 'TXT':"メールアドレス",
307 'TXT':"電話番号",
308 'TXT':"携帯電話",
309 'ADDR':"住所"
310 }
311 },
312 'Custom':{
313 'title':"カスタムカード",
314 'description':"<p>カスタムカードを使えばどんな情報でも保管できます。</p> ",
315 'fields':{
316 'TXT':"ラベル 1",
317 'TXT':"ラベル 2",
318 'TXT':"ラベル 3"
319 }
320 }
321},
322 'recordFieldTypologies':{
323 'TXT':{
324 'description':"テキスト入力欄",
325 'shortDescription':"テキスト"
326 },
327 'PWD':{
328 'description':"通常は非表示になるテキスト入力欄",
329 'shortDescription':"パスワード"
330 },
331 'URL':{
332 'description':"表示モードではクリックできる URL 入力欄",
333 'shortDescription':"ウェブアドレス"
334 },
335 'DATE':{
336 'description':"日付入力欄",
337 'shortDescription':"日付"
338 },
339 'ADDR':{
340 'description':"Google マップ用の URL に似た文字列",
341 'shortDescription':"住所"
342 },
343 'CHECK':{
344 'description':"チェックボックスの詳細",
345 'shortDescription':"チェックボックス"
346 },
347 'RADIO':{
348 'description':"ラジオボタンの詳細",
349 'shortDescription':"ラジオボタン"
350 },
351 'SELECT':{
352 'description':"セレクトリストの詳細",
353 'shortDescription':"セレクトリスト"
354 }
355},
356 'newRecordPanelGeneralExceptionTitle':"エラー",
357 'newRecordPanelGeneralExceptionMessage':"コードが不正です。 ブックマークレットを確認してもう一度やり直してください。",
358 'newRecordPanelWrongBookmarkletVersionExceptionTitle':"エラー",
359 'newRecordPanelWrongBookmarkletVersionExceptionMessage':"古いバージョンのブックマークレットで生成されたコードです。 ブックマークレットを更新してやり直してください。",
360 'newRecordPanelExceptionPanelCloseButtonLabel':"キャンセル",
361 'mainPanelDeletingRecordPanelConfirmationTitle':"カード削除中",
362 'mainPanelDeleteRecordPanelConfirmationText':"本当に削除しますか?",
363 'mainPanelDeleteRecordPanelConfirmButtonLabel':"はい",
364 'mainPanelDeleteRecordPanelDenyButtonLabel':"いいえ",
365 'mainPanelDeletingRecordPanelInitialTitle':"カード削除中",
366 'mainPanelDeletingRecordPanelInitialText':"---",
367 'mainPanelDeletingRecordPanelCompletedText':"完了",
368 'deleteRecordPanelCollectRecordDataMessageTitle':"カード削除",
369 'deleteRecordPanelCollectRecordDataMessageText':"カードリスト更新中",
370 'deleteRecordPanelEncryptUserDataMessageTitle':"カード削除",
371 'deleteRecordPanelEncryptUserDataMessageText':"カードヘッダ暗号化",
372 'deleteRecordPanelSendingDataToTheServerMessageTitle':"カード削除",
373 'deleteRecordPanelSendingDataToTheServerMessageText':"送信中",
374 'deleteRecordPanelUpdatingTheInterfaceMessageTitle':"カード削除",
375 'deleteRecordPanelUpdatingTheInterfaceMessageText':"更新中",
376 'recordDetailNoRecordSelectedTitle':"カードが選択されていません",
377 'recordDetailNoRecordSelectedDescription':"<p>左のリストからカードを選択してください。</p> ",
378 'recordDetailLoadingRecordMessage':"データ受信中",
379 'recordDetailDecryptingRecordMessage':"データ復元中",
380 'recordDetailLoadingRecordVersionMessage':"最新情報を受信中",
381 'recordDetailDecryptingRecordVersionMessage':"最新情報を復元中",
382 'recordDetailLoadingErrorMessageTitle':"受信エラー",
383 'recordDetailNotesLabel':"ノート",
384 'recordDetailLabelFieldColumnLabel':"ラベル",
385 'recordDetailDataFieldColumnLabel':"データ",
386 'recordDetailTypeFieldColumnLabel':"タイプ",
387 'recordDetailSavingChangesMessagePanelInitialTitle':"保存中",
388 'recordDetailSavingChangesMessagePanelInitialText':"---",
389 'recordDetailRemoveFieldButtonLabel':"-",
390 'recordDetailAddFieldButtonLabel':"フィールド追加",
391 'recordDetailPasswordFieldHelpLabel':"パスワードをコピーするには星マークをクリックして ctrl-C をタイプします",
392 'recordDetailPasswordFieldScrambleLabel':"隠す",
393 'recordDetailPasswordFieldUnscrambleLabel':"可視化",
394 'recordDetailDirectLoginBlockTitle':"ダイレクトログイン",
395 'recordDetailNewDirectLoginDescription':"<p>ダイレクトログイン設定</p> ",
396 'recordDetailDirectLoginBlockNoDirectLoginConfiguredDescription':"<p>オンラインサービスのログイン情報を含んでいますか?</p> <p>ブックマークレットを使ってダイレクトログインを設定しましょう!</p> ",
397 'recordDetailDeleteDirectLoginButtonLabel':"-",
398 'recordDetailAddNewDirectLoginButtonLabel':"新規ダイレクトログイン追加",
399 'recordDetailEditButtonLabel':"編集",
400 'recordDetailSaveButtonLabel':"保存",
401 'recordDetailCancelButtonLabel':"キャンセル",
402 'newRecordTitleLabel':"_新規カード_",
403 'newDirectLoginLabelSuffix':"",
404 'recordSaveChangesPanelCollectRecordInfoMessageTitle':"カード保存",
405 'recordSaveChangesPanelCollectRecordInfoMessageText':"更新中",
406 'recordSaveChangesPanelEncryptUserDataMessageTitle':"カード保存",
407 'recordSaveChangesPanelEncryptUserDataMessageText':"カードヘッダ暗号化",
408 'recordSaveChangesPanelEncryptRecordDataMessageTitle':"カード保存",
409 'recordSaveChangesPanelEncryptRecordDataMessageText':"カードデータ暗号化",
410 'recordSaveChangesPanelEncryptRecordVersionDataMessageTitle':"カード保存",
411 'recordSaveChangesPanelEncryptRecordVersionDataMessageText':"バージョンデータ暗号化",
412 'recordSaveChangesPanelSendingDataToTheServerMessageTitle':"カード保存",
413 'recordSaveChangesPanelSendingDataToTheServerMessageText':"カード送信中",
414 'recordSaveChangesPanelUpdatingTheInterfaceMessageTitle':"カード保存",
415 'recordSaveChangesPanelUpdatingTheInterfaceMessageText':"更新中",
416 'passwordGeneratorPanelTitle':"パスワードジェネレータ",
417 'passwordGeneratorPanelOkLabel':"OK",
418 'passwordGeneratorPanelCancelLabel':"キャンセル",
419 'passwordGeneratorLowercaseLabel':"abc",
420 'passwordGeneratorUppercaseLabel':"ABC",
421 'passwordGeneratorNumberLabel':"012",
422 'passwordGeneratorSymbolLabel':"@#$",
423 'passwordGeneratorLengthLabel':"文字数:",
424 //'DWRUtilLoadingMessage':"ロード中 ...",
425 'comingSoon':"近日登場 ...",
426 'panelCollectingEntryopyMessageText':"整頓中",
427 'directLoginConfigurationCheckBoxFieldSelectedValue':"はい",
428 'directLoginConfigurationCheckBoxFieldNotSelectedValue':"いいえ",
429 'importFormats':{
430 'CSV':{
431 'label':"CSV",
432 'description':"<p>広く普及しているフォーマットです。 いくつかのパスワードマネージャは CSV でのエクスポートに対応しています。</p>"
433 },
434 'Excel':{
435 'label':"エクセル",
436 'description':"<p>マイクロソフトの有名な表計算ソフトです。 エクセルのファイルでパスワードを保存することは広く行われていますがおすすめできません。</p>"
437 },
438 'KeePass':{
439 'label':"KeePass",
440 'description':"<p>パスワードマネージャ KeePass で生成されるテキストファイルです。</p>"
441 },
442 'PasswordPlus':{
443 'label':"Password Plus",
444 'description':"<p>パスワードマネージャ Password Plus で生成される CSV ファイルです。</p>"
445 },
446 'Roboform':{
447 'label':"RoboForm",
448 'description':"<p>パスワードマネージャ Roboform で印刷用に表示される HTML ファイルです。</p>"
449 },
450 'ClipperzExport':{
451 'label':"JSON",
452 'description':"<p>Clipperz で生成されるフォーマットです。 ダイレクトログインを含むすべての情報が含まれます。</p>"
453 }
454},
455 'Clipperz_ImportWizard_Title':"JSON インポート",
456 'importOptions_clipperz_description':"<p>Clipperz で生成された JSON ファイルをテキストエディタで開きます。 次に下のテキストエリアにファイルの内容をコピーします。</p> ",
457 'CSV_ImportWizard_Title':"CSV インポート",
458 'importOptions_csv_description_':"<p>CSV ファイルをテキストエディタで開きます。 下のテキストエリアにファイルの内容をコピーします。</p> <p>区切り記号などを選択します。</p> ",
459 'Excel_ImportWizard_Title':"エクセルインポート",
460 'importOptions_excel_description_':"<p>エクセルでファイルを開いてインポートしたいセルを選択します。 次に下のテキストエリアに選択したセルをコピーします。</p> ",
461 'KeePass_ImportWizard_Title':"KeePass インポート",
462 'importOptions_keePass_description_':"<p>KeePas で生成されたファイルをテキストエディタで開きます。 次に下のテキストエリアにファイルの内容をコピーします。</p> ",
463 'PasswordPlus_ImportWizard_Title':"Password Plus インポート",
464 'importOptions_passwordPlus_description':"<p>Password Plus で生成された CSV ファイルをテキストエディタで開きます。 下のテキストエリアにファイルの内容をコピーします。</p> ",
465 'RoboForm_ImportWizard_Title':"RoboForm インポート",
466 'importOptions_roboForm_description':"<p>RoboForm で生成された HTML ファイルをテキストエディタで開きます。 次に下のテキストエリアにファイルの内容をコピーします。</p> ",
467 'importData_parsingDataTitle':"インポート",
468 'importData_parsingDataText':"分析中 ...",
469 'importData_previewingDataTitle':"インポート",
470 'importData_previewingDataText':"変換中 ...",
471 'importData_processingDataTitle':"インポート",
472 'importData_processingDataText':"カード作成中 ...",
473 'ImportWizard':{
474 'EDIT':"編集",
475 'PREVIEW':"プレビュー",
476 'IMPORT':"インポート",
477 'KEEPASS_SETTINGS':"設定",
478 'CSV_EDIT':"貼り付け",
479 'CSV_COLUMNS':"列",
480 'CSV_HEADER':"ラベル",
481 'CSV_TITLE':"タイトル",
482 'CSV_NOTES':"ノート",
483 'CSV_FIELDS':"タイプ",
484 'EXCEL_EDIT':"編集"
485},
486 'CSV_ImportWizard_Columns':"<p>インポートする列を選択してください。</p> ",
487 'CSV_ImportWizard_Header':"<p>最初の行にラベルが含まれている場合、下のチェックボックスをチェックしてください。</p> ",
488 'CSV_ImportWizard_Header_Settings_firstRowHeaderLabel':"先頭行をラベルとして利用する",
489 'CSV_ImportWizard_Title':"<p>カードのタイトルになる列を選択してください。 (必須)</p>",
490 'CSV_ImportWizard_Notes':"<p>ノートに相当する列を選択してください。 (オプション)</p> ",
491 'CSV_ImportWizard_Notes_Settings_noSelectionLabel':"ノートは利用できません",
492 'CSV_ImportWizard_Fields':"<p>それぞれの列のデータタイプをドロップダウンリストから選択してください。</p> ",
493 'CSV_ImportWizard_Fields_MissingLabelWarning':"ラベルがありません",
494 'importData_importConfirmation_title':"インポート",
495 'importData_importConfirmation_text':"__numberOfRecords__ 枚のカードをインポートしますか?",
496 'WELCOME_BACK':"おかえりなさい",
497 'currentConnectionText':"あなたの利用 IP アドレスは __ip__, です。 country__, から __operatingSystem__ 版 __browser__ を利用しています。",
498 'latestConnectionText':"前回の利用は __elapsedTimeDescription__ (__time__)、IP アドレスは __ip__, でした。 country__ から __operatingSystem__ 版 __browser__ を利用しました。",
499 'fullLoginHistoryLinkLabel':"ログイン履歴を詳しく見る",
500 'elapsedTimeDescriptions':{
501 'MORE_THAN_A_MONTH_AGO':"1 か月以上前",
502 'MORE_THAN_A_WEEK_AGO':"1 週間以上前",
503 'MORE_THAN_*_WEEKS_AGO':"elapsed__ 週間以上前",
504 'YESTERDAY':"昨日",
505 '*_DAYS_AGO':"__elapsed__ 日前",
506 'ABOUT_AN_HOUR_AGO':"約 1 時間前",
507 '*_HOURS_AGO':"__elapsed__ 時間前",
508 'JUST_A_FEW_MINUTES_AGO':"直前",
509 'ABOUT_*_MINUTES_AGO':"約 __elapsed__ 分前"
510},
511 'unknown_ip':"不明",
512 'countries':{
513 '--':"不明",
514 'AD':"アンドラ",
515 'AE':"アラブ首長国連邦",
516 'AF':"アフガニスタン",
517 'AG':"アンティグアバーブーダ",
518 'AI':"アングイラ",
519 'AL':"アルバニア",
520 'AM':"アルメニア",
521 'AN':"オランダ アンティル諸島",
522 'AO':"アンゴラ",
523 'AP':"その他のアジアパシフィック地域",
524 'AR':"アルゼンチン",
525 'AS':"米国領サモア",
526 'AT':"オーストリア",
527 'AU':"オーストラリア",
528 'AW':"アルーバ",
529 'AX':"アーラント諸島",
530 'AZ':"アゼルバイジャン",
531 'BA':"ボスニア・ヘルツェゴビナ",
532 'BB':"バルバドス",
533 'BD':"バングラデシュ",
534 'BE':"ベルギー",
535 'BF':"ブルキナファソ",
536 'BG':"ブルガリア",
537 'BH':"バーレーン",
538 'BI':"ブルンジ",
539 'BJ':"ベナン",
540 'BN':"ブルネイダルサラーム",
541 'BO':"ボリビア",
542 'BR':"ブラジル",
543 'BS':"バハマ",
544 'BT':"ブータン",
545 'BW':"ボツワナ",
546 'BY':"ベラルーシ",
547 'BZ':"ベリーズ",
548 'CA':"カナダ",
549 'CD':"コンゴ民主共和国",
550 'CF':"中央アフリカ共和国",
551 'CH':"スイス",
552 'CI':"コートジボワール",
553 'CK':"クック諸島",
554 'CL':"チリ",
555 'CM':"カメルーン",
556 'CN':"中国",
557 'CO':"コロンビア",
558 'CR':"コスタリカ",
559 'CS':"セルビア・モンテネグロ",
560 'CU':"キューバ",
561 'CY':"キプロス",
562 'CZ':"チェコ共和国",
563 'DE':"ドイツ",
564 'DJ':"ジブチ",
565 'DK':"デンマーク",
566 'DO':"ドミニカ共和国",
567 'DZ':"アルジェリア",
568 'EC':"エクアドル",
569 'EE':"エストニア",
570 'EG':"エジプト",
571 'ER':"エリトリア",
572 'ES':"スペイン",
573 'ET':"エチオピア",
574 'EU':"欧州連合",
575 'FI':"フィンランド",
576 'FJ':"フィジー",
577 'FM':"ミクロネシア連邦邦国",
578 'FR':"フランス",
579 'GA':"ガボン",
580 'GB':"英国",
581 'GD':"グラナダ",
582 'GE':"グルジア",
583 'GF':"仏領ギアナ",
584 'GG':"ガーンジー",
585 'GH':"ガーナ",
586 'GI':"ジブラルタル",
587 'GL':"グリーンランド",
588 'GP':"グアドロープ",
589 'GR':"ギリシャ",
590 'GT':"カタロニア",
591 'GU':"グアム",
592 'GW':"ギニアビサウ",
593 'GY':"ガイアナ",
594 'HK':"香港",
595 'HN':"ホンデュラス",
596 'HR':"クロアチア",
597 'HT':"ハイチ",
598 'HU':"ハンガリー",
599 'ID':"インドネシア",
600 'IE':"アイルランド",
601 'IL':"イスラエル",
602 'IM':"マン島",
603 'IN':"インド",
604 'IO':"英領インド洋植民地",
605 'IQ':"イラク",
606 'IR':"イラン・イスラム共和国",
607 'IS':"アイスランド",
608 'IT':"イタリア",
609 'JE':"ジャージー",
610 'JO':"ヨルダン",
611 'JP':"日本",
612 'KE':"ケニア",
613 'KG':"キルギスタン",
614 'KH':"カンボジア",
615 'KI':"キリバス",
616 'KN':"セントキッツネヴィス",
617 'KR':"大韓民国 (韓国)",
618 'KW':"クウェート",
619 'KY':"カイマン諸島",
620 'KZ':"カザフスタン",
621 'LA':"ラオス人民民主共和国",
622 'LB':"レバノン",
623 'LC':"セントルシア",
624 'LI':"リヒテンシュタイン",
625 'LK':"スリランカ",
626 'LR':"リベリア",
627 'LS':"レソト",
628 'LT':"リトアニア",
629 'LU':"ルクセンブルグ",
630 'LV':"ラトビア",
631 'LY':"リビア・アラブ・Jamahiriya",
632 'MA':"モロッコ",
633 'MC':"モナコ",
634 'MD':"モルドバ共和国",
635 'MG':"マダガスカル",
636 'MH':"マーシャル諸島",
637 'MK':"マケドニア共和国",
638 'ML':"マリ",
639 'MM':"ミャンマー",
640 'MN':"モンゴル",
641 'MO':"マカオ",
642 'MP':"北マリアナ諸島",
643 'MR':"モーリタニア",
644 'MT':"マルタ",
645 'MU':"モーリシャス",
646 'MV':"モルジヴ",
647 'MW':"マラウイ",
648 'MX':"メキシコ",
649 'MY':"マレーシア",
650 'MZ':"モザンビーク",
651 'NA':"ナミビア",
652 'NC':"ニューカレドニア",
653 'NF':"ノーフォーク諸島",
654 'NG':"ナイジェリア",
655 'NI':"ニカラグア",
656 'NL':"オランダ",
657 'NO':"ノルウェー",
658 'NP':"ネパール",
659 'NR':"ナウル",
660 'NU':"ニウエ",
661 'NZ':"ニュージーランド",
662 'OM':"オマーン",
663 'PA':"パナマ",
664 'PE':"ペルー",
665 'PF':"仏領ポリネシア",
666 'PG':"パプアニューギニア",
667 'PH':"フィリピン",
668 'PK':"パキスタン",
669 'PL':"ポーランド",
670 'PR':"プエルトリコ",
671 'PS':"パレスチナ占領地区",
672 'PT':"ポルトガル",
673 'PW':"パラオ",
674 'PY':"パラグアイ",
675 'QA':"カタール",
676 'RO':"ルーマニア",
677 'RS':"セルビア",
678 'RU':"ロシア連邦",
679 'RW':"ルワンダ",
680 'SA':"サウジアラビア",
681 'SB':"ソロモン諸島",
682 'SC':"セイシェル",
683 'SD':"スーダン",
684 'SE':"スウェーデン",
685 'SG':"シンガポール",
686 'SI':"スロベニア",
687 'SK':"スロバキア",
688 'SL':"シエラレオネ",
689 'SM':"サンマリノ",
690 'SN':"セネガル",
691 'SR':"スリナム",
692 'SV':"エルサルバドル",
693 'SY':"シリアアラブ共和国",
694 'SZ':"スワジランド",
695 'TC':"タークスアンドケーコス諸島",
696 'TG':"トーゴ",
697 'TH':"タイ",
698 'TJ':"タジキスタン",
699 'TM':"トルクメニスタン",
700 'TN':"チュニジア",
701 'TO':"トンガ",
702 'TR':"トルコ",
703 'TT':"トリニダードトバコ",
704 'TV':"ツヴァル",
705 'TW':"中国領・台湾",
706 'TZ':"タニザニア連合共和国",
707 'UA':"ウクライナ",
708 'UG':"ウガンダ",
709 'US':"アメリカ合衆国",
710 'UY':"ウルグアイ",
711 'UZ':"ウズベキスタン",
712 'VA':"聖庁 (バチカン市国)",
713 'VE':"ベネズェラ",
714 'VG':"英国ヴァージン諸島",
715 'VI':"米国ヴァージン諸島",
716 'VN':"ベトナム",
717 'VU':"バヌアツ",
718 'WF':"ワリーエフトゥーナ諸島",
719 'WS':"サモア",
720 'YE':"イエメン",
721 'ZA':"南アフリカ",
722 'ZM':"ザンビア",
723 'ZW':"ジンバブエ",
724 'ZZ':"Reserved"
725},
726 'browsers':{
727 'UNKNOWN':"不明",
728 'MSIE':"インターネットエクスプローラー",
729 'FIREFOX':"Firefox",
730 'OPERA':"Opera",
731 'SAFARI':"Safari",
732 'OMNIWEB':"OmniWeb",
733 'CAMINO':"Camino"
734},
735 'operatingSystems':{
736 'UNKNOWN':"不明",
737 'WINDOWS':"ウィンドウズ",
738 'MAC':"Mac",
739 'LINUX':"Linux",
740 'IPHONE':"iPhone",
741 'MOBILE':"携帯電話",
742 'OPENBSD':"OpenBSD",
743 'FREEBSD':"FreeBSD",
744 'NETBSD':"NetBSD"
745},
746 'calendarStrings':{
747 'months':{
748 '0':"1 月",
749 '1':"2 月",
750 '2':"3 月",
751 '3':"4 月",
752 '4':"5",
753 '5':"6 月",
754 '6':"7 月",
755 '7':"8 月",
756 '8':"9 月",
757 '9':"10 月",
758 '10':"11 月",
759 '11':"12 月"
760 },
761 'shortMonths':{
762 '0':"1",
763 '1':"2",
764 '2':"3",
765 '3':"4",
766 '4':"5",
767 '5':"6",
768 '6':"7",
769 '7':"8",
770 '8':"9",
771 '9':"10",
772 '10':"11",
773 '11':"12"
774 },
775 'days':{
776 '0':"日曜日",
777 '1':"月曜日",
778 '2':"火曜日",
779 '3':"水曜日",
780 '4':"木曜日",
781 '5':"金曜日",
782 '6':"土曜日"
783 },
784 'shortDays':{
785 '0':"日",
786 '1':"月",
787 '2':"火",
788 '3':"水",
789 '4':"木",
790 '5':"金",
791 '6':"土"
792 },
793 'veryShortDays':{
794 '0':"月",
795 '1':"月",
796 '2':"日",
797 '3':"金",
798 '4':"木",
799 '5':"金",
800 '6':"水"
801 },
802 'amDesignation':"土",
803 'pmDesignation':"午後"
804},
805 'fullDate_format':"l, F d, Y H:i:s",
806
807__syntaxFix__: "syntax fix"
808});
diff --git a/frontend/beta/js/Clipperz/PM/Strings/Strings_pt-BR.js b/frontend/beta/js/Clipperz/PM/Strings/Strings_pt-BR.js
new file mode 100644
index 0000000..db6c2f6
--- a/dev/null
+++ b/frontend/beta/js/Clipperz/PM/Strings/Strings_pt-BR.js
@@ -0,0 +1,478 @@
1/*
2
3Copyright 2008-2011 Clipperz Srl
4
5This file is part of Clipperz's Javascript Crypto Library.
6Javascript Crypto Library provides web developers with an extensive
7and efficient set of cryptographic functions. The library aims to
8obtain maximum execution speed while preserving modularity and
9reusability.
10For further information about its features and functionalities please
11refer to http://www.clipperz.com
12
13* Javascript Crypto Library is free software: you can redistribute
14 it and/or modify it under the terms of the GNU Affero General Public
15 License as published by the Free Software Foundation, either version
16 3 of the License, or (at your option) any later version.
17
18* Javascript Crypto Library is distributed in the hope that it will
19 be useful, but WITHOUT ANY WARRANTY; without even the implied
20 warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
21 See the GNU Affero General Public License for more details.
22
23* You should have received a copy of the GNU Affero General Public
24 License along with Javascript Crypto Library. If not, see
25 <http://www.gnu.org/licenses/>.
26
27*/
28
29Clipperz.PM.Strings.Languages['pt-BR'.toLowerCase()] = MochiKit.Base.merge(Clipperz.PM.Strings.Languages['en-us'], {
30 'clipperzServiceDescriptionConfig':"<h2>Guarde com você!</h2> <ul> <li> <h3>Clipperz é:</h3> <ul> <li> <p>um simples e seguro gerenciador de senhas</p> </li> <li> <p>uma efetiva solução com uma única assinatura</p> </li> <li> <p>um cofre digital para suas informações confidenciais</p> </li> </ul> </li> <li> <h3>Com Clipperz você pode:</h3> <ul> <li> <p>guardar e gerenciar suas senhas e credenciais online</p> </li> <li> <p>logar em seus serviços web sem precisar entrar com nenhum nome de usuário ou senha</p> </li> <li> <p>proteger todos os seus dados sensíveis: códigos de alarme, PINs, números de cartão de crédito, &hellip;</p> </li> <li> <p>compartilhar segredos com membros da família e associados (em breve)</p> </li> </ul> </li> <li> <h3>Clipperz proporciona:</h3> <ul> <li> <p>anonimato completo e gratuito</p> </li> <li> <p>acesso a qualquer hora em qualquer computador</p> </li> <li> <p>sem software ou download e nada que instalar</p> </li> <li> <p>evite guardar seus segredos em seu PC ou papel</p> </li> </ul> </li> <li> <h3>Segurança Clipperz:</h3> <ul> <li> <p>seus segredos são codificados localmente por seu navegador antes de ser enviado para Clipperz</p> </li> <li> <p>a chave de codificação é uma senha que só você conhece</p> </li> <li> <p>Clipperz armazena apenas seus dados confidenciais codificados, nunca acessando os dados originais</p> </li> <li> <p>Clipperz é construído a partir de esquemas de codificação padrão, ou seja, nada é exclusivo ou caseiro</p> </li> <li> <p>você pode revisar o código a qualquer momento, mas você não precisa conhecer nada sobre criptograia para ser um usuário feliz!</p> </li> </ul> </li> <li> <a href=\"http://www.clipperz.com\" target=\"_blank\">Saiba mais</a> </li> </ul> ",
31 'loginFormTitle':"entre sua conta Clipperz",
32 'loginFormUsernameLabel':"nome do usuário",
33 'loginFormPassphraseLabel':"frase chave",
34 'loginFormDontHaveAnAccountLabel':"não tem uma conta?",
35 'loginFormCreateOneLabel':"criar uma",
36 'loginFormForgotYourCredentialsLabel':"esqueceu suas credenciais?",
37 'loginFormAarghThatsBadLabel':"xiiiii! isso é não é bom!",
38 'loginFormAfraidOfMaliciousScriptsLabel':"medo de scripts maliciosos?",
39 'loginFormVerifyTheCodeLabel':"verifique o código",
40 'loginFormButtonLabel':"Entrar",
41 'loginFormOneTimePasswordCheckboxLabel':"use uma frase chave descartável",
42 'loginPanelSwithLanguageDescription':"<h5>Mudar para sua linguagem preferida</h5> ",
43 'browserCompatibilityDescription':"<p>Tenha uma experiência melhor e mais segura com Clipperz, utilizando o Firefox. No entanto, Clipperz funciona bem também em Opera e MS Internet Explorer!</p> ",
44 'OTPloginMessagePanelInitialTitle':"Acessando usando a frase chave descartável",
45 'OTPloginMessagePanelInitialText':"Enviando credenciais descartáveis ...",
46 'OTPloginMessagePanelLoadingTitle':"Acessando usando a frase chave descartável",
47 'OTPloginMessagePanelLoadingText':"Buscando informação de autenticação codificada no servidor ...",
48 'OTPloginMessagePanelProcessingTitle':"Acessando usando a frase chave descartável",
49 'OTPloginMessagePanelProcessingText':"Decodificação local da informação de autenticação ...",
50 'loginMessagePanelInitialTitle':"Entrando ...",
51 'loginMessagePanelInitialButtonLabel':"Cancelar",
52 'loginMessagePanelConnectedTitle':"Conectado",
53 'loginMessagePanelConnectedText':"Concluído",
54 'loginMessagePanelFailureTitle':"Erro",
55 'loginMessagePanelFailureText':"Ocorreu uma falha",
56 'loginMessagePanelFailureButtonLabel':"Fechar",
57 'connectionLoginSendingCredentialsMessageTitle':"Verificando credenciais",
58 'connectionLoginSendingCredentialsMessageText':"Enviando credenciais",
59 'connectionLoginCredentialsVerificationMessageTitle':"Verificando credenciais",
60 'connectionLoginCredentialsVerificationMessageText':"Realizando autenticação SRP",
61 'connectionLoginDoneMessageTitle':"Verificando credenciais",
62 'connectionLoginDoneMessageText':"Conectado",
63 'userLoginPanelUpgradingUserCredentialsMessageTitle':"Verificando credenciais",
64 'userLoginPanelUpgradingUserCredentialsMessageText':"Upgrade de suas credenciais para um novo esquema de autenticação",
65 'userLoginPanelConnectedMessageTitle':"Usuário autenticado",
66 'userLoginPanelConnectedMessageText':"Logado com sucesso em",
67 'userLoginPanelTryingAnOlderConnectionSchemaMessageTitle':"Verificando credenciais",
68 'userLoginPanelTryingAnOlderConnectionSchemaMessageText':"Tentando esquema antigo de autenticação",
69 'userLoginPanelLoadingUserDataMessageTitle':"Usuário autenticado",
70 'userLoginPanelLoadingUserDataMessageText':"Baixando cabeçalhos de cartão codificados de Clipperz",
71 'userLoginPanelDecryptingUserDataMessageTitle':"Usuário autenticado",
72 'userLoginPanelDecryptingUserDataMessageText':"Descrição local de cabeçalhos dos cartões",
73 'userLoginPanelDecryptingUserStatisticsMessageTitle':"Usuário autenticado",
74 'userLoginPanelDecryptingUserStatisticsMessageText':"Descrição local de estatísticas de uso",
75 'splashAlertTitle':"Bem-vindo ao Clipperz!",
76 'splashAlertText':"<p>Alguns avisos de segurança</p> <ul> <li> <p>Guardar suas informações no Clipperz é tão seguro quanto a frase chave que você escolher para protege-los. Ninguém pode acessá-los sem essa frase chave.</p> </li> <li> <p>Se você vai utlizar Clipperz para armazenar suas informações confidenciais e críticas, escolha uma frase chave difícil de ser descoberta. Quanto mais longa, melhor!</p> </li> <li> <p>Clipperz não será capaz de recuperar frase chave perdidas!</p> </li> </ul> <p>Para mais informações, por favor vá até <a href=\"http://www.clipperz.com\" target=\"_blank\">Clipperz</a> website.</p> ",
77 'splashAlertCloseButtonLabel':"Ok",
78 'registrationFormTitle':"crie sua conta",
79 'registrationFormUsernameLabel':"nome do usuário",
80 'registrationFormPassphraseLabel':"frase chave",
81 'registrationFormRetypePassphraseLabel':"entre novamente sua frase chave",
82 'registrationFormSafetyCheckLabel':"Eu compreendo que Clipperz não será capaz de recuperar senhas perdidas.",
83 'registrationFormTermsOfServiceCheckLabel':"Eu li e concordo com os <a href='http://www.clipperz.com/terms_of_service' target='_blank'>Termos do Serviço</a>.",
84 'registrationFormDoYouAlreadyHaveAnAccountLabel':"você já tem uma conta?",
85 'registrationFormSimplyLoginLabel':"login simples",
86 'registrationFormButtonLabel':"Registrar",
87 'registrationFormWarningMessageNotMatchingPassphrases':"Suas frases chaves não conferem, por favor tente novamente.",
88 'registrationFormWarningMessageSafetyCheckNotSelected':"Por favor leia e confira todos os campos abaixo.",
89 'registrationFormWarningMessageTermsOfServiceCheckNotSelected':"Você precisa concordar com os Termos do Serviço.",
90 'registrationMessagePanelInitialTitle':"Criando conta ...",
91 'registrationMessagePanelInitialText':"---",
92 'registrationMessagePanelInitialButtonLabel':"Cancelar",
93 'registrationMessagePanelRegistrationDoneTitle':"Registro",
94 'registrationMessagePanelRegistrationDoneText':"Concluído",
95 'registrationMessagePanelFailureTitle':"Registrou falhou",
96 'registrationMessagePanelFailureButtonLabel':"Fechar",
97 'connectionRegistrationSendingRequestMessageText':"Verificando credenciais",
98 'connectionRegistrationSendingCredentialsMessageText':"Enviando credenciais",
99 'registrationSplashPanelTitle':"Informe de segurança",
100 'registrationSplashPanelDescription':"<p>Essas são suas credenciais Clipperz, cuide delas com cuidado. Clipperz nunca vai mostrar seu nome de usuário e frase chave uma outra vez!</p> ",
101 'registrationSplashPanelUsernameLabel':"nome de usuário",
102 'registrationSplashPanelPassphraseLabel':"frase chave",
103 'registrationSplashPanelShowPassphraseButtonLabel':"mostrar frase chave",
104 'donateHeaderLinkLabel':"doar",
105 'creditsHeaderLinkLabel':"créditos",
106 'feedbackHeaderLinkLabel':"feedback",
107 'helpHeaderLinkLabel':"ajuda",
108 'forumHeaderLinkLabel':"fórum",
109 'recordMenuLabel':"cartões",
110 'accountMenuLabel':"conta",
111 'dataMenuLabel':"dados",
112 'contactsMenuLabel':"contatos",
113 'toolsMenuLabel':"ferramentas",
114 'logoutMenuLabel':"sair",
115 'lockMenuLabel':"bloquear",
116 'lockTitle':"A conta está bloqueada",
117 'lockDescription':"<p>Para desbloquear sua conta, por favor, entre com a frase chave</p> ",
118 'unlockButtonLabel':"desbloquear",
119 'changePasswordTabLabel':"Alterar sua frase chave",
120 'changePasswordTabTitle':"Alterar sua frase chave",
121 'changePasswordFormUsernameLabel':"nome de usuário",
122 'changePasswordFormOldPassphraseLabel':"frase chave antiga",
123 'changePasswordFormNewPassphraseLabel':"frase chave nova",
124 'changePasswordFormRetypePassphraseLabel':"re-inserir frase chave nova",
125 'changePasswordFormSafetyCheckboxLabel':"Eu compreendo que Clipperz não poderá recuperar a frase chave perdida.",
126 'changePasswordFormSubmitLabel':"Alterar frase chave",
127 'changePasswordFormWrongUsernameWarning':"Nome de usuário errado",
128 'changePasswordFormWrongPassphraseWarning':"Frase chave errada",
129 'changePasswordFormWrongRetypePassphraseWarning':"Suas frases chaves não conferem, por favor tente novamente.",
130 'changePasswordFormSafetyCheckWarning':"Por favor leia e confira todos os campos abaixo.",
131 'changePasswordFormProgressDialogTitle':"Alterando credenciais do usuário",
132 'changePasswordFormProgressDialogConnectedMessageTitle':"Conectado",
133 'changePasswordFormProgressDialogConnectedMessageText':"Concluído",
134 'changePasswordFormProgressDialogErrorMessageTitle':"Erro",
135 'changePasswordFormProgressDialogErrorMessageText':"Mudança de credenciais falhou!",
136 'changeCredentialsPanelEncryptingDataMessageTitle':"Alterando sua frase chave",
137 'changeCredentialsPanelEncryptingDataMessageText':"Codificação local de cabeçalho de cartões",
138 'changeCredentialsPanelCreatingNewCredentialsMessageTitle':"Alterando sua frase chave",
139 'changeCredentialsPanelCreatingNewCredentialsMessageText':"Atualizando suas credenciais",
140 'changeCredentialsPanelSendingNewCredentialsToTheServerMessageTitle':"Alterando sua frase chave",
141 'changeCredentialsPanelSendingNewCredentialsToTheServerMessageText':"Enviando suas credenciais codificadas para Clipperz",
142 'changeCredentialsPanelDoneMessageTitle':"Alterando sua frase chave",
143 'changeCredentialsPanelDoneMessageText':"Concluído",
144 'manageOTPTabLabel':"Gerenciar suas frases chaves descartáveis",
145 'manageOTPTabTitle':"Gerenciar suas frases chaves descartáveis",
146 'manageOTPTabDescription':"<p>Uma frase chave descartável funciona como uma frase chave normal, mas só pode ser utilizada uma única vez.</p> <p>Se a mesma frase chave for utilizada novamente num próximo login, ela será rejeitada e o login não irá ocorrer.</p> <p>Imediatamente após um login com sucesso, sua frase chave descartável será apagada para evitar logins fraudulentos.</p> <p>Frases chaves descartáveis são uma excelente opção se você está preocupado com keyloggers ou spywares que podem estar coletando seus dados em determinadas máquinas.</p> <p> <b>É recomendável que você utilize frases chaves descartáveis sempre que utilizar terminais públicos como Internet cafés e bibliotecas.</b> </p> ",
147 'oneTimePasswordReadOnlyMessage':"<h6>Desculpe!</h6> <p>Você não pode gerenciar sua frase chave descartável quando usando a versão offline do Clipperz.</p> ",
148 'oneTimePasswordLoadingMessage':"<h6>Carregando informação</h6> <p>Por favor, aguarde ...</p> ",
149 'oneTimePasswordNoPasswordAvailable':"<h6>Nenhuma frase chave descartável disponível</h6> <p>Clique o botão “Novo” acima para adicionar uma frase chave descartável em sua conta.</p> ",
150 'createNewOTPButtonLabel':"Novo",
151 'deleteOTPButtonLabel':"Apagar",
152 'printOTPButtonLabel':"Imprimir",
153 'disabledOneTimePassword_warning':"desativada",
154 'oneTimePasswordSelectionLink_selectLabel':"Selecionar:",
155 'oneTimePasswordSelectionLink_all':"tudo",
156 'oneTimePasswordSelectionLink_none':"nenhum",
157 'oneTimePasswordSelectionLink_used':"usado",
158 'oneTimePasswordSelectionLink_unused':"não usado",
159 'saveOTP_encryptUserDataTitle':"Salvando a frase chave descartável",
160 'saveOTP_encryptUserDataText':"Processando novas credenciais descartáveis ...",
161 'saveOTP_encryptOTPDataTitle':"Salvando a frase chave descartável",
162 'saveOTP_encryptOTPDataText':"Codificação local da informação de autenticação ...",
163 'saveOTP_sendingDataTitle':"Salvando a frase chave descartável",
164 'saveOTP_sendingDataText':"Enviando informação de autenticação para o servidor ...",
165 'saveOTP_updatingInterfaceTitle':"Salvando a frase chave descartável",
166 'saveOTP_updatingInterfaceText':"Atualizando interface ...",
167 'accountPreferencesLabel':"Preferências",
168 'accountPreferencesTabTitle':"Preferências",
169 'accountPreferencesLanguageTitle':"Seleção de idioma",
170 'accountPreferencesLanguageDescription':"<p>Escolha seu idioma preferido da lista abaixo.</p> ",
171 'showDonationReminderPanelTitle':"Lembretes de doação",
172 'showDonationReminderPanelDescription':"<p>Mostrar lembretes de doação</p> ",
173 'saveUserPreferencesFormSubmitLabel':"Salvar",
174 'cancelUserPreferencesFormSubmitLabel':"Cancelar",
175 'accountPreferencesSavingPanelTitle_Step1':"Salvando preferências",
176 'accountPreferencesSavingPanelText_Step1':"Codificação local de suas preferências",
177 'accountPreferencesSavingPanelTitle_Step2':"Salvando preferências",
178 'accountPreferencesSavingPanelText_Step2':"Enviando informação codificada para o servidor",
179 'accountLoginHistoryLabel':"Histórico de conexão",
180 'loginHistoryTabTitle':"Histórico de conexão",
181 'loginHistoryReadOnlyMessage':"<h6>Desculpe!</h6> <p>Seu histórico de conexão não está disponível quando usando uma versão offline do Clipperz.</p> ",
182 'loginHistoryLoadingMessage':"<h6>Carregando informação</h6> <p>Por favor, aguarde ...</p> ",
183 'loginHistoryLoadedMessageConfig':"<h6>Suas 10 últimas conexões</h6> <p> </p> ",
184 'loginHistoryIPLabel':"IP",
185 'loginHistoryTimeLabel':"data",
186 'loginHistoryCurrentSessionText':"sessão atual",
187 'loginHistoryReloadButtonLabel':"Recarregar histórico de conexão",
188 'deleteAccountTabLabel':"Apagar sua conta",
189 'deleteAccountTabTitle':"Apagar sua conta",
190 'deleteAccountFormUsernameLabel':"nome de usuário",
191 'deleteAccountFormPassphraseLabel':"frase chave",
192 'deleteAccountFormSafetyCheckboxLabel':"Eu compreendo que toda minha informação será apagada e que esta ação é irreversível.",
193 'deleteAccountFormSubmitLabel':"Apagar minha conta",
194 'deleteAccountFormWrongUsernameWarning':"Nome de usuário errado",
195 'deleteAccountFormWrongPassphraseWarning':"Frase chave errada",
196 'deleteAccountFormSafetyCheckWarning':"Por favor leia e confira os campos abaixo.",
197 'accountPanelDeletingAccountPanelConfirmationTitle':"ATENÇÃO",
198 'accountPanelDeleteAccountPanelConfirmationText':"Você tem certeza que quer apagar esta conta?",
199 'accountPanelDeleteAccountPanelConfirmButtonLabel':"Sim",
200 'accountPanelDeleteAccountPanelDenyButtonLabel':"Não",
201 'offlineCopyTabLabel':"Cópia offline",
202 'offlineCopyTabTitle':"Cópia offline",
203 'offlineCopyTabDescription':"<p>Com apenas um click você pode passar toda sua informação codificada dos servidores Clipperz para seu hard disk e criar uma versão read-only offline do Clipperz para ser utilizada quando você não estiver conectado na Internet.</p> <p>Essa versão read-only é tão segura quanto a versão online e não vai expor suas informações a riscos maiores já que ambas tem a mesma arquitetura de código e segurança.</p> <ol> <li> <p>Clique no link abaixo para iniciar o download.</p> </li> <li> <p>O navegador vai perguntar o que fazer com o arquivo “Clipperz_YYYYMMDD.html”. Grave-o em seu hard disk.</p> </li> <li> <p>Clique duas vezes no arquivo baixado para abrir a versão offline em seu navegador.</p> </li> <li> <p>Entre sua frase chave e nome de usuário como sempre faz.</p> </li> </ol> ",
204 'offlineCopyDownloadLinkLabel':"Baixar",
205 'offlineCopyDownloadWarningConfig':"<h4> <a href=\"#\" id=\"offlineCopyDownloadWarningLink\">Atualize sua “cópia offline”!</a> </h4> <p>Vocie recentemente criou ou modificou um ou mais cartões, seria inteligente baixar uma nova “cópia offline”.</p> ",
206 'sharingTabLabel':"Compartilhar",
207 'sharingTabTitle':"Compartilhar",
208 'sharingTabDescriptionConfig':"<p>Frequentemente uma informação confidencial precisa ser compartilhada com uma ou mais pessoas.</p> <p>Isso pode ser tão simples quanto permitir o acesso de seus colegas ao seu voice mail quando você está fora do escritório, ou tão complicado quanto permitir que seus herdeiros acessem seu caixa num banco quando você morrer.</p> <p>Clipperz pode fazer o processo de compartilhamento simples e seguro.</p> <p> </p> <p> <b>Em breve ...</b> </p> ",
209 'importTabLabel':"Importar",
210 'importTabTitle':"Importar",
211 'importTabDescription':"<p> <b>Em breve ...</b> <p> ",
212 'printingTabLabel':"Exportar",
213 'printingTabTitle':"Exportar",
214 'printingTabDescription':"<p> <b>Versão para impressão</b> </p> <p>Clicando no link abaixo você abre uma nova janela contendo todos os seus cartões em formato de impressão.</p> <p>Se você vai impriir para backup, considere a opção mais segura criando uma “cópia offline”.</p> ",
215 'printingLinkLabel':"Versão para impressão",
216 'contactsTabLabel':"Contatos",
217 'contactsTabTitle':"Contatos",
218 'passwordGeneratorTabLabel':"Gerador de senhas",
219 'passwordGeneratorTabTitle':"Gerador de senhas",
220 'passwordGeneratorTabButtonLabel':"Gerar senha",
221 'bookmarkletTabLabel':"Bookmarklet",
222 'bookmarkletTabTitle':"Bookmarklet",
223 'bookmarkletTabDescription':"<p>Um bookmarklet é uma ferramenta “one-click” que pode executar diversas tarefas úteis. Pode ser salva e utilizada como uma página web preferida normal.</p> <p>Os bookmarklet Clipperz vão ajudar você a a rapidamente criar novos cartões e novos logins diretos a partir dos cartões existentes.</p> <p> <b>Por favor, note que o bookmarklet não inclui nenhuma informação relacionada à sua conta (e.g. seu nome de usuário ou frase chave), o bookmarklet é um ferramenta contendo o mesmo código para todos ois usuários Clipperz.</b> </p> <h3>Como instalar o bookmarlet</h3> <h5>Firefox, Camino, Opera, Safari</h5> <ol> <li> <p>Assegure-se que a “Barra de Bookmarks” está visível, selecionando “View > Toolbars > Bookmarks”, ou menu similar no menu do navegador</p> </li> <li> <p>Arraste o link “Adicionar ao Clipperz” abaixo para a barra de bookmark.</p> </li> </ol> <h5>Internet Explorer</h5> <ol> <li> <p>Assegure-se que o barra de “Links” está visível selecionando “View > Toolbar > Links” no menu do navegador.</p> </li> <li> <p>Clique com o botão direito no link “Adicionar ao Clipperz” abaixo.</p> </li> <li> <p>Select “Selecione “Add to favorites” no menu contextual.</p> </li> <li> <p>Clique “Yes” para qualquer mensagem de segurança que surgir em pop-up.</p> </li> <li> <p>Abra o folder “Links” e clique “OK”.</p> </li> </ol> ",
224 'bookmarkletTabBookmarkletTitle':"Adicionar ao Clipperz",
225 'bookmarkletTabInstructions':"<h3>Como criar um novo cartão para acessar diretamente um serviço online</h3> <ol> <li> <p>Abra a página web onde o formulário de login está. (é a página onde você usualmente entra com suas credenciais)</p> </li> <li> <p>Dispare a preferência clicando nela: um pop-up vai aparecer sobre a página.</p> </li> <li> <p>Copie para o clipboard o conteúdo da área de texto do pop-up. (ctrl-C)</p> </li> <li> <p>Entre em sua conta Clipperz e clique no botão <b>Adicionar novo cartão</b>.</p> </li> <li> <p>Selecione o template de \"Login Direto\" e cole o conteúdo do clipboard para a grande área de texto do formulário. (ctrl-V)</p> </li> <li> <p>Pressione o botão <b>Criar</b>, reveja os detalhes e clique <b>Save</b>.</p> </li> </ol> <h3>Como adicionar login direto a um cartão existente</h3> <ol> <li> <p>Idem acima.</p> </li> <li> <p>Idem acima.</p> </li> <li> <p>Idem acima.</p> </li> <li> <p>Entre em sua conta Clipperz e selecione o cartão contendo as credenciais para o serviço web que você visitou e clique no botão <b>Editar</b>.</p> </li> <li> <p>Cole o conteúdo do clipboard para a grande área de texto da sessão “Logins diretos”. (ctrl-V)</p> </li> <li> <p>Pressione o botão <b>Adicionar login direto</b>, reveja os detalhes e clique <b>Salvar</b>.</p> </li> </ol> <p> </p> <p>Mais informações sobre as preferências estão <a href=\"http://www.clipperz.com/support/user_guide/bookmarklet\" target=\"_blank\">disponíveis aqui</a>.</p> ",
226 'mainPanelDirectLoginBlockLabel':"Logins diretos",
227 'directLinkReferenceShowButtonLabel':"mostrar",
228 'mainPanelDirectLoginBlockDescription':"<p>Adicionar “logins diretos” para entrar em páginas web sem ter que digitar nome de usuário e senhas!</p> <p>“Logins diretos” ampliam a segurança de sus senha já que você pode:</p> <ul> <li> <p>utilizar senhas mais complexas;</p> </li> <li> <p>nunca re-utilizar a mesma senha fácil-de-lembrar.</p> </li> </ul> <p>Configuração simples e rápida com os <b>bookmarklet</b> Clipperz.</p> <a href=\"http://www.clipperz.com/support/user_guide/direct_logins\" target=\"_blank\">Saiba mais sobre “logins diretos”</a> ",
229 'mainPanelRecordsBlockLabel':"Cartões",
230 'mainPanelAddRecordButtonLabel':"Adicionar novo cartão",
231 'mainPanelRemoveRecordButtonLabel':"Apagar cartão",
232 'mainPanelRecordFilterBlockAllLabel':"todos",
233 'mainPanelRecordFilterBlockTagsLabel':"tags",
234 'mainPanelRecordFilterBlockSearchLabel':"buscar",
235 'recordDetailNoRecordAtAllTitle':"Bem-vindo ao Clipperz!",
236 'recordDetailNoRecordAtAllDescription':"<h5>Inicie criando cartões para sua conta.</h5> <p>Cartões são formulários simples e flexíveis onde você guarda senhas e outras informações confidenciais.</p> <p>Cartões podem conter credenciais de login a sites, a combinação do seu cadeado da bicicleta, detalhes do seu cartão de crédito, ...</p> <h5>Não esqueça o bookmarklet</h5> <p>Antes de começar, instale o bookmarklet “Adicionar ao Clipperz”: ele vai tornar o processo de criar cartões mais fácil e divertido.</p> <p> </p> <p>Depois, apenas click no botão <b>Adicionar novo cartão</b> e aproveite sua conta Clipperz.</p> <p> </p> <a href=\"http://www.clipperz.com/support/user_guide/managing_cards\" target=\"_blank\">Saiba mais sobre criar e gerenciar cartões</a> ",
237 'newRecordWizardTitleBox':"<h5>Por favor selecione um template</h5> <p>Cartões são formulários simples e flexíveis onde você pode arquivar suas senhas ou outras informações confidenciais.</p> <p>Comece escolhendo um dos templates abaixo. Você poderá customizar seus cartões mais tarde, adicionando e removendo campos.</p> ",
238 'newRecordWizardBookmarkletConfigurationTitle':"Login direto",
239 'newRecordWizardBookmarkletConfigurationDescription':"<p>Coloque abaixo o código de configuração gerado pelo bookmarklet Clipperz.</p> <p>Um novo cartão completo com login direto para sua conta web será criado.</p> ",
240 'newRecordWizardCreateButtonLabel':"Criar",
241 'newRecordWizardCancelButtonLabel':"Cancelar",
242 'donateSplashPanelTitle':"Apoie Clipperz, faça uma doação hoje!",
243 'donateSplashPanelDescription':"<p>Algumas boas razões para doar:</p> <ul> <li> <p>apoie o desenvolvimento de novas funcionalidades</p> </li> <li> <p>mantenha Clipperz gratuito</p> </li> <li> <p>mostrar apreciação por trabalho duro</p> </li> </ul> <p>Para qualquer informação adicional, por favor visite nossa <a href=\"http://www.clipperz.com/donations\" target=\"_blank\">página de Doações</a>.</p> <p> <b>Pronto para doar?</b> </p> ",
244 'donateCloseButtonLabel':"Não ainda",
245 'donateDonateButtonLabel':"Sim",
246 'recordTemplates':{
247 'WebAccount':{
248 'title':"Senha web",
249 'description':"<p>Um cartão simples para arquivar credenciais de login para seus serviços online.</p> ",
250 'fields':{
251 'URL':"Endereço web",
252 'TXT':"Nome de usuário ou email",
253 'PWD':"Senha"
254 }
255 },
256 'BankAccount':{
257 'title':"Conta bancária",
258 'description':"<p>Arquive com segurança o número de sua conta corrente e suas credenciais de online banking.</p> ",
259 'fields':{
260 'TXT':"Banco",
261 'TXT':"Número da conta",
262 'URL':"Website do banco",
263 'TXT':"ID de online banking",
264 'PWD':"Senha de online banking"
265 }
266 },
267 'CreditCard':{
268 'title':"Cartão de crédito",
269 'description':"<p>Número do cartão, validade, CVV2 e PIN sempre disponíveis no Clipperz</p> ",
270 'fields':{
271 'TXT':"Tipo (Visa, AmEx, ...)",
272 'TXT':"Número",
273 'TXT':"Nome do proprietário",
274 'TXT':"Prazo de validade",
275 'TXT':"CVV2",
276 'PWD':"PIN",
277 'URL':"Website do cartão",
278 'TXT':"Nome do usuário",
279 'PWD':"Senha"
280 }
281 },
282 'AddressBookEntry':{
283 'title':"Agenda de endereços",
284 'description':"<p>Clipperz pode também funcionar como sua agenda de endereços particular. Use esse template para facilmente adicionar novas entradas.</p> ",
285 'fields':{
286 'TXT':"Nome",
287 'TXT':"Email",
288 'TXT':"Fone",
289 'TXT':"Mobile",
290 'ADDR':"Endereço"
291 }
292 },
293 'Custom':{
294 'title':"Cartão customizado",
295 'description':"<p>Não importa o tipo de informação confidencial você precisa proteger, crie um cartão customizado para sua necessidade.</p> ",
296 'fields':{
297 'TXT':"Label 1",
298 'TXT':"Label 2",
299 'TXT':"Label 3"
300 }
301 }
302},
303 'recordFieldTypologies':{
304 'TXT':{
305 'description':"simple text field",
306 'shortDescription':"texto"
307 },
308 'PWD':{
309 'description':"simple text field, with default status set to hidden",
310 'shortDescription':"senha"
311 },
312 'URL':{
313 'description':"simple text field in edit mode, that became an active url in view mode",
314 'shortDescription':"endereço web"
315 },
316 'DATE':{
317 'description':"a value set with a calendar helper",
318 'shortDescription':"data"
319 },
320 'ADDR':{
321 'description':"just like the URL, but the active link points to Google Maps (or similar service) passing the address value as argument",
322 'shortDescription':"endereço"
323 },
324 'CHECK':{
325 'description':"check description",
326 'shortDescription':"check"
327 },
328 'RADIO':{
329 'description':"radio description",
330 'shortDescription':"radio"
331 },
332 'SELECT':{
333 'description':"select description",
334 'shortDescription':"select"
335 }
336},
337 'newRecordPanelGeneralExceptionTitle':"Erro",
338 'newRecordPanelGeneralExceptionMessage':"O texto de configuração não é válido. Certifique-se do texto no pop-up de bookmarklet e tente novamente.",
339 'newRecordPanelWrongBookmarkletVersionExceptionTitle':"Erro",
340 'newRecordPanelWrongBookmarkletVersionExceptionMessage':"O texto de configuração foi gerado por uma velha versão de bookmarklet. Por favor, atualize seus preferidos e tente novamente.",
341 'newRecordPanelExceptionPanelCloseButtonLabel':"Cancelar",
342 'mainPanelDeletingRecordPanelConfirmationTitle':"Apagando o cartão selecionado",
343 'mainPanelDeleteRecordPanelConfirmationText':"Você quer mesmo apagar o cartão selecionado?",
344 'mainPanelDeleteRecordPanelConfirmButtonLabel':"Sim",
345 'mainPanelDeleteRecordPanelDenyButtonLabel':"Não",
346 'mainPanelDeletingRecordPanelInitialTitle':"Apagando o cartão selecionado",
347 'mainPanelDeletingRecordPanelCompletedText':"Concluído",
348 'deleteRecordPanelCollectRecordDataMessageTitle':"Apagar cartão",
349 'deleteRecordPanelCollectRecordDataMessageText':"Atualizando lista de cartões",
350 'deleteRecordPanelEncryptUserDataMessageTitle':"Apagar cartão",
351 'deleteRecordPanelEncryptUserDataMessageText':"Codificação local de cabeçalhos de cartão",
352 'deleteRecordPanelSendingDataToTheServerMessageTitle':"Apagar cartão",
353 'deleteRecordPanelSendingDataToTheServerMessageText':"Enviando os cabeçalhos de cartão codificados para Clipperz",
354 'deleteRecordPanelUpdatingTheInterfaceMessageTitle':"Apagar cartão",
355 'deleteRecordPanelUpdatingTheInterfaceMessageText':"Atualizando a interface",
356 'recordDetailNoRecordSelectedTitle':"Nenhum cartão selecionado",
357 'recordDetailNoRecordSelectedDescription':"<p>Por favor selecione um cartão da lista na esquerda.</p> ",
358 'recordDetailLoadingRecordMessage':"Baixando cartão codificados do Clipperz",
359 'recordDetailDecryptingRecordMessage':"Descrição local dos dados do cartão",
360 'recordDetailLoadingRecordVersionMessage':"Baixando a versão mais recente do cartão",
361 'recordDetailDecryptingRecordVersionMessage':"Descrição local da versão mais recente",
362 'recordDetailLoadingErrorMessageTitle':"Erro enquanto baixando o cartão",
363 'recordDetailNotesLabel':"Notas",
364 'recordDetailLabelFieldColumnLabel':"Legenda do campo",
365 'recordDetailDataFieldColumnLabel':"Dados do campo",
366 'recordDetailTypeFieldColumnLabel':"Tipo",
367 'recordDetailSavingChangesMessagePanelInitialTitle':"Salvando cartão",
368 'recordDetailAddFieldButtonLabel':"Adicionar novo campo",
369 'recordDetailPasswordFieldHelpLabel':"para copiar a senha para o clipboard clique nas estrelas e em seguida Ctrl-C",
370 'recordDetailPasswordFieldScrambleLabel':"misturar",
371 'recordDetailPasswordFieldUnscrambleLabel':"mostrar",
372 'recordDetailDirectLoginBlockTitle':"Logins diretos",
373 'recordDetailNewDirectLoginDescription':"<p>Configuração de login direto</p> ",
374 'recordDetailDirectLoginBlockNoDirectLoginConfiguredDescriptionConfig':"<p>Este cartão contém credenciais para acessar um serviço online?</p> <p>Use o bookmarklet para configurar um “login direto” desde o Clipperz com apenas um click!</p> ",
375 'recordDetailAddNewDirectLoginButtonLabel':"Adicionar novo login direto",
376 'recordDetailEditButtonLabel':"Editar",
377 'recordDetailSaveButtonLabel':"Salvar",
378 'recordDetailCancelButtonLabel':"Cancelar",
379 'newRecordTitleLabel':"_novo cartão_",
380 'recordSaveChangesPanelCollectRecordInfoMessageTitle':"Salvar cartão",
381 'recordSaveChangesPanelCollectRecordInfoMessageText':"Subindo cabeçalhos de cartão",
382 'recordSaveChangesPanelEncryptUserDataMessageTitle':"Salvar cartão",
383 'recordSaveChangesPanelEncryptUserDataMessageText':"Codificação local do cabeçalho do cartão",
384 'recordSaveChangesPanelEncryptRecordDataMessageTitle':"Salvar cartão",
385 'recordSaveChangesPanelEncryptRecordDataMessageText':"Codificação local da informação do cartão",
386 'recordSaveChangesPanelEncryptRecordVersionDataMessageTitle':"Salvar cartão",
387 'recordSaveChangesPanelEncryptRecordVersionDataMessageText':"Codificação local da informação de versão do cartão",
388 'recordSaveChangesPanelSendingDataToTheServerMessageTitle':"Salvar cartão",
389 'recordSaveChangesPanelSendingDataToTheServerMessageText':"Subindo o cabeçalho do cartão codificado para Clipperz",
390 'recordSaveChangesPanelUpdatingTheInterfaceMessageTitle':"Salvar cartão",
391 'recordSaveChangesPanelUpdatingTheInterfaceMessageText':"Atualizando a interface",
392 'passwordGeneratorPanelTitle':"Gerador de senhas",
393 'passwordGeneratorPanelOkLabel':"Ok",
394 'passwordGeneratorPanelCancelLabel':"Cancelar",
395 'passwordGeneratorLengthLabel':"compr.:",
396 //'DWRUtilLoadingMessage':"Carregando ...",
397 'comingSoon':"em breve ...",
398 'panelCollectingEntryopyMessageText':"Coletando entropia",
399 'directLoginConfigurationCheckBoxFieldSelectedValue':"Sim",
400 'directLoginConfigurationCheckBoxFieldNotSelectedValue':"Não",
401 'WELCOME_BACK':"Welcome back!",
402 'currentConnectionText':"Você está conectado do ip&nbsp;__ip__, aparentemente desde __country__, usando __browser__ num __operatingSystem__.",
403 'latestConnectionText':"Sua úlitima conexão foi __elapsedTimeDescription__ (__time__) do ip&nbsp;__ip__, aparentemente desde __country__, usando __browser__ num __operatingSystem__.",
404 'fullLoginHistoryLinkLabel':"mostrar o histórico de logins completos",
405 'elapsedTimeDescriptions':{
406 'MORE_THAN_A_MONTH_AGO':"mais de um mês atrás",
407 'MORE_THAN_A_WEEK_AGO':"mais de uma semana atrás",
408 'MORE_THAN_*_WEEKS_AGO':"mais de __elapsed__ semanas atrás",
409 'YESTERDAY':"ontem",
410 '*_DAYS_AGO':"__elapsed__ dias atrás",
411 'ABOUT_AN_HOUR_AGO':"cerca de uma hora atrás",
412 '*_HOURS_AGO':"__elapsed__ horas atrás",
413 'JUST_A_FEW_MINUTES_AGO':"apenas alguns minutos atrás",
414 'ABOUT_*_MINUTES_AGO':"cerca de __elapsed__ minutos atrás"
415},
416 'unknown_ip':"desconhecido",
417 'calendarStrings':{
418 'months':{
419 '0':"Janeiro",
420 '1':"Fevereiro",
421 '2':"Março",
422 '3':"Abril",
423 '4':"Maio",
424 '5':"Junho",
425 '6':"Julho",
426 '7':"Agosto",
427 '8':"Setembro",
428 '9':"Outubro",
429 '10':"Novembro",
430 '11':"Dezembro"
431 },
432 'shortMonths':{
433 '0':"Jan",
434 '1':"Fev",
435 '2':"Mar",
436 '3':"Abr",
437 '4':"Mai",
438 '5':"Jun",
439 '6':"Jul",
440 '7':"Ago",
441 '8':"Set",
442 '9':"Out",
443 '10':"Nov",
444 '11':"Dez"
445 },
446 'days':{
447 '0':"Domingo",
448 '1':"Segunda-feira",
449 '2':"Terça-feira",
450 '3':"Quarta-feira",
451 '4':"Quinta-feira",
452 '5':"Sexta-feira",
453 '6':"Sábado"
454 },
455 'shortDays':{
456 '0':"Dom",
457 '1':"Seg",
458 '2':"Ter",
459 '3':"Qua",
460 '4':"Quin",
461 '5':"Sex",
462 '6':"Sab"
463 },
464 'veryShortDays':{
465 '0':"Do",
466 '1':"Se",
467 '2':"Te",
468 '3':"Qa",
469 '4':"Qi",
470 '5':"Se",
471 '6':"Sa"
472 },
473 'amDesignation':"am",
474 'pmDesignation':"pm"
475},
476
477__syntaxFix__: "syntax fix"
478});
diff --git a/frontend/beta/js/Clipperz/PM/Strings/Strings_pt-PT.js b/frontend/beta/js/Clipperz/PM/Strings/Strings_pt-PT.js
new file mode 100644
index 0000000..5284683
--- a/dev/null
+++ b/frontend/beta/js/Clipperz/PM/Strings/Strings_pt-PT.js
@@ -0,0 +1,42 @@
1/*
2
3Copyright 2008-2011 Clipperz Srl
4
5This file is part of Clipperz's Javascript Crypto Library.
6Javascript Crypto Library provides web developers with an extensive
7and efficient set of cryptographic functions. The library aims to
8obtain maximum execution speed while preserving modularity and
9reusability.
10For further information about its features and functionalities please
11refer to http://www.clipperz.com
12
13* Javascript Crypto Library is free software: you can redistribute
14 it and/or modify it under the terms of the GNU Affero General Public
15 License as published by the Free Software Foundation, either version
16 3 of the License, or (at your option) any later version.
17
18* Javascript Crypto Library is distributed in the hope that it will
19 be useful, but WITHOUT ANY WARRANTY; without even the implied
20 warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
21 See the GNU Affero General Public License for more details.
22
23* You should have received a copy of the GNU Affero General Public
24 License along with Javascript Crypto Library. If not, see
25 <http://www.gnu.org/licenses/>.
26
27*/
28
29//=============================================================================
30//
31 // P O R T U G U Ê S ( pt_PT )
32//
33//=============================================================================
34
35Clipperz.PM.Strings.Languages['pt-pt'] = MochiKit.Base.merge(Clipperz.PM.Strings.Languages['pt-br'], {
36
37
38
39 //-------------------------------------------------------------------------
40 __syntaxFix__: "syntax fix"
41});
42
diff --git a/frontend/beta/js/Clipperz/PM/Strings/Strings_ru-RU.js b/frontend/beta/js/Clipperz/PM/Strings/Strings_ru-RU.js
new file mode 100644
index 0000000..41c904f
--- a/dev/null
+++ b/frontend/beta/js/Clipperz/PM/Strings/Strings_ru-RU.js
@@ -0,0 +1,440 @@
1/*
2
3Copyright 2008-2011 Clipperz Srl
4
5This file is part of Clipperz's Javascript Crypto Library.
6Javascript Crypto Library provides web developers with an extensive
7and efficient set of cryptographic functions. The library aims to
8obtain maximum execution speed while preserving modularity and
9reusability.
10For further information about its features and functionalities please
11refer to http://www.clipperz.com
12
13* Javascript Crypto Library is free software: you can redistribute
14 it and/or modify it under the terms of the GNU Affero General Public
15 License as published by the Free Software Foundation, either version
16 3 of the License, or (at your option) any later version.
17
18* Javascript Crypto Library is distributed in the hope that it will
19 be useful, but WITHOUT ANY WARRANTY; without even the implied
20 warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
21 See the GNU Affero General Public License for more details.
22
23* You should have received a copy of the GNU Affero General Public
24 License along with Javascript Crypto Library. If not, see
25 <http://www.gnu.org/licenses/>.
26
27*/
28
29Clipperz.PM.Strings.Languages['ru-RU'.toLowerCase()] = MochiKit.Base.merge(Clipperz.PM.Strings.Languages['en-us'], {
30 'clipperzServiceDescription':"<h2>Держи при себе!</h2> <ul> <li> <h3>Clipperz - это:</h3> <ul> <li> <p>безопасный и простой менеджер паролей</p> </li> <li> <p>эффективное решение для единой регистрации</p> </li> <li> <p>цифровое хранилище Ваших конфидециальных данных</p> </li> </ul> </li> <li>
31 <h3>C помошью Clipperz Вы можете:</h3> <ul>
32 <li> <p>хранить и управлять Вашими паролями</p> </li> <li> <p>входить в любые веб-сервисы без ввода логина и пароля</p> </li> <li> <p>защитить все важные данные: коды охранной сигнализации, ПИНы, номера кредитных кард, ...</p> </li> <li> <p>открыть доступ Вашим членам семьи, друзьям, коллегам</p> </li> </ul> </li> <li>
33 <h3>Преимущества Clipperz:</h3> <ul>
34 <li> <p>бесплатный и абсолютно анонимный</p> </li> <li> <p>доступен в любое время и с любого компьютера</p> </li> <li> <p>не нужно ничего устанавливать</p> </li> <li> <p>не надо хранить секреты на компьютере или бумаге</p> </li> </ul> </li> <li>
35 <h3>Безопасность Clipperz:</h3> <ul>
36 <li> <p>все данные перед отправкой в Clipperz шифруются в браузере</p> </li> <li> <p>секретный ключ - это фраза, которую знаете только Вы</p> </li> <li> <p>Clipperz управляет важными данными в зашифрованном виде и никогда не получит доступ к ним в открытом виде</p> </li> <li> <p>Clipperz основан на стандартных криптографических протоколах: без каких-либо самоделок</p> </li> <li> <p>Вы можете просмотреть исходный код, но Вам ничего не надо знать о криптографии, чтобы быть просто пользоваться</p> </li> </ul> </li> <li>
37 <a href=\"http://www.clipperz.com\" target=\"_blank\">Подробнее</a> </li> </ul> ",
38 'loginFormTitle':"войти под Вашим аккаунтом Clipperz",
39 'loginFormUsernameLabel':"имя пользователя",
40 'loginFormPassphraseLabel':"ключевая фраза",
41 'loginFormDontHaveAnAccountLabel':"у вас еще нет аккаунта?",
42 'loginFormCreateOneLabel':"создать",
43 'loginFormForgotYourCredentialsLabel':"забыли пароль?",
44 'loginFormAarghThatsBadLabel':"о! это плохо!",
45 'loginFormAfraidOfMaliciousScriptsLabel':"опасаетесь вредоносных скриптов?",
46 'loginFormVerifyTheCodeLabel':"проверить код",
47 'loginFormButtonLabel':"Войти",
48 'loginFormOneTimePasswordCheckboxLabel':"использовать одноразовую ключевую фразу",
49 'loginPanelSwithLanguageDescription':"<h5>Переключиться на Ваш язык</h5> ",
50 'browserCompatibilityDescription':"<p>Лучше работать с Clipperz в Firefox. Однако Clipperz хорошо совместим с Opera и MS Internet Explorer!</p> ",
51 'OTPloginMessagePanelInitialTitle':"Вход",
52 'OTPloginMessagePanelInitialText':"Передача данных учетной записи ...",
53 'OTPloginMessagePanelLoadingTitle':"Вход",
54 'OTPloginMessagePanelLoadingText':"Запрос аутентификационных данных с сервера ...",
55 'OTPloginMessagePanelProcessingTitle':"Вход",
56 'OTPloginMessagePanelProcessingText':"Расшифровка аутентификационных данных",
57 'loginMessagePanelInitialTitle':"Вход ...",
58 'loginMessagePanelInitialButtonLabel':"Отмена",
59 'loginMessagePanelConnectedTitle':"Соединен",
60 'loginMessagePanelConnectedText':"Выполнен",
61 'loginMessagePanelFailureTitle':"Ошибка",
62 'loginMessagePanelFailureText':"Ошибка при попытке входа",
63 'loginMessagePanelFailureButtonLabel':"Закрыть",
64 'connectionLoginSendingCredentialsMessageTitle':"Проверка учетной записи",
65 'connectionLoginSendingCredentialsMessageText':"Передача данных ...",
66 'connectionLoginCredentialsVerificationMessageTitle':"Проверка учетной записи",
67 'connectionLoginCredentialsVerificationMessageText':"Выполняем SRP-аутентификацию ...",
68 'connectionLoginDoneMessageTitle':"Проверка учетной записи",
69 'connectionLoginDoneMessageText':"Соединено",
70 'userLoginPanelUpgradingUserCredentialsMessageTitle':"Проверка учетной записи",
71 'userLoginPanelUpgradingUserCredentialsMessageText':"Обновляем полномочия к новой схеме аутентификации",
72 'userLoginPanelConnectedMessageTitle':"Пользователь аутентифицирован",
73 'userLoginPanelConnectedMessageText':"Успешный вход",
74 'userLoginPanelTryingAnOlderConnectionSchemaMessageTitle':"Проверка учетной записи",
75 'userLoginPanelTryingAnOlderConnectionSchemaMessageText':"Пробуем войти по старой схеме",
76 'userLoginPanelLoadingUserDataMessageTitle':"Пользователь аутентифицирован",
77 'userLoginPanelLoadingUserDataMessageText':"Загрузка зашифрованных заголовков карточек",
78 'userLoginPanelDecryptingUserDataMessageTitle':"Пользователь аутентифицирован",
79 'userLoginPanelDecryptingUserDataMessageText':"Расшифровка заголовков карточек",
80 'userLoginPanelDecryptingUserStatisticsMessageTitle':"Пользователь аутентифицирован",
81 'userLoginPanelDecryptingUserStatisticsMessageText':"Расшифровка статистики",
82 'splashAlertTitle':"Добро пожаловать в Clipperz!",
83 'splashAlertText':"<p>Несколько советов по безопасности:</p> <ul> <li> <p>Хранение данных в Clipperz зависит от того, насколько безопасна выбранная Вами ключевая фраза</p> </li> <li> <p>Если собираетесь использовать Clipperz для защиты важных или критических данных, то убедитесь, что выбрали сложный пароль</p> </li> <li> <p>Clipperz не может восстановить забытую ключевую фразу</p> </li> </ul> <p>За дополнительной информацией обратитесь на <a href=\"http://www.clipperz.com\" target=\"_blank\">сайт</a> Clipperz.</p> ",
84 'splashAlertCloseButtonLabel':"OK",
85 'registrationFormTitle':"создать аккаунт",
86 'registrationFormUsernameLabel':"имя пользователя",
87 'registrationFormPassphraseLabel':"ключевая фраза",
88 'registrationFormRetypePassphraseLabel':"повторите ключевую фразу",
89 'registrationFormSafetyCheckLabel':"Я понимаю, что Clipperz не может восстановить забытую ключевую фразу",
90 'registrationFormTermsOfServiceCheckLabel':"Я прочитал и согласен с <a href='http://www.clipperz.com/terms_of_service' target='_blank'>Условиями предоставления услуг</a>.",
91 'registrationFormDoYouAlreadyHaveAnAccountLabel':"у вас уже есть аккаунт?",
92 'registrationFormSimplyLoginLabel':"просто ввойдите",
93 'registrationFormButtonLabel':"Зарегистрировать",
94 'registrationFormWarningMessageNotMatchingPassphrases':"Ключевые фразы не совпадают, пожайлуста, повторите ввод",
95 'registrationFormWarningMessageSafetyCheckNotSelected':"Прочитайте и проверьте все поля ниже",
96 'registrationFormWarningMessageTermsOfServiceCheckNotSelected':"Вы должны принять Условия предоставления услуг",
97 'registrationMessagePanelInitialTitle':"Создание аккаунта",
98 'registrationMessagePanelInitialButtonLabel':"Отмена",
99 'registrationMessagePanelRegistrationDoneTitle':"Регистрация",
100 'registrationMessagePanelRegistrationDoneText':"Выполнено",
101 'registrationMessagePanelFailureTitle':"Ошибка регистрации",
102 'registrationMessagePanelFailureButtonLabel':"Закрыть",
103 'connectionRegistrationSendingRequestMessageText':"Проверка учетной записи",
104 'connectionRegistrationSendingCredentialsMessageText':"Передача данных",
105 'registrationSplashPanelTitle':"Совет",
106 'registrationSplashPanelDescription':"<p>Это Ваши данные учетной записи, позаботесь об их безопасности. Clipperz никогда больше не покажет Ваше имя пользователя и ключевую фразу!</p> ",
107 'registrationSplashPanelUsernameLabel':"имя пользователя",
108 'registrationSplashPanelPassphraseLabel':"ключевая фраза",
109 'registrationSplashPanelShowPassphraseButtonLabel':"показать ключевую фразу",
110 'donateHeaderLinkLabel':"пожертвования",
111 'creditsHeaderLinkLabel':"список разработчиков",
112 'feedbackHeaderLinkLabel':"обратная связь",
113 'helpHeaderLinkLabel':"помощь",
114 'forumHeaderLinkLabel':"форум",
115 'recordMenuLabel':"карточки",
116 'accountMenuLabel':"аккаунт",
117 'dataMenuLabel':"данные",
118 'contactsMenuLabel':"контакты",
119 'toolsMenuLabel':"инструменты",
120 'logoutMenuLabel':"выйти",
121 'lockMenuLabel':"заблокировать",
122 'lockTitle':"Аккаунт заблокирован",
123 'lockDescription':"<p>Введите ключевую фразу для разблокировки</p> ",
124 'unlockButtonLabel':"разблокировать",
125 'changePasswordTabLabel':"Изменить ключевую фразу",
126 'changePasswordTabTitle':"Изменить ключевую фразу",
127 'changePasswordFormUsernameLabel':"имя пользователя",
128 'changePasswordFormOldPassphraseLabel':"старая ключевая фраза",
129 'changePasswordFormNewPassphraseLabel':"новая ключевая фраза",
130 'changePasswordFormRetypePassphraseLabel':"повторить ключевую фразу",
131 'changePasswordFormSafetyCheckboxLabel':"Я понимаю, что Clipperz не может восстановить забытую ключевую фразу.",
132 'changePasswordFormSubmitLabel':"Изменить",
133 'changePasswordFormWrongUsernameWarning':"Неправильное имя пользователя",
134 'changePasswordFormWrongPassphraseWarning':"Неверная ключевая фраза",
135 'changePasswordFormWrongRetypePassphraseWarning':"Ключевые фразы не совпадают, пожайлуста, повторите ввод.",
136 'changePasswordFormSafetyCheckWarning':"Прочитайте и проверьте все поля ниже.",
137 'changePasswordFormProgressDialogTitle':"Изменение учетной записи",
138 'changePasswordFormProgressDialogConnectedMessageTitle':"Соединено",
139 'changePasswordFormProgressDialogConnectedMessageText':"Выполнено",
140 'changePasswordFormProgressDialogErrorMessageTitle':"Ошибка",
141 'changePasswordFormProgressDialogErrorMessageText':"Ошибка изменения учетной записи!",
142 'changeCredentialsPanelEncryptingDataMessageTitle':"Изменение ключевой фразы",
143 'changeCredentialsPanelEncryptingDataMessageText':"Шифрование заголовков карточек",
144 'changeCredentialsPanelCreatingNewCredentialsMessageTitle':"Изменение ключевой фразы",
145 'changeCredentialsPanelCreatingNewCredentialsMessageText':"Обновление учетной записи",
146 'changeCredentialsPanelSendingNewCredentialsToTheServerMessageTitle':"Изменение ключевой фразы",
147 'changeCredentialsPanelSendingNewCredentialsToTheServerMessageText':"Загрузка данных учетной записи в Clipperz",
148 'changeCredentialsPanelDoneMessageTitle':"Изменение ключевой фразы",
149 'changeCredentialsPanelDoneMessageText':"Выполнено",
150 'manageOTPTabLabel':"Управление одноразовыми ключевыми фразами",
151 'manageOTPTabTitle':"Управление одноразовыми ключевыми фразами",
152 'manageOTPTabDescription':"<p>Одноразовый пароль работает, как Ваша обычная ключевая фраза, но может быть использована только один раз.</p> <p>Если один и тот же пароль будет использоваться снова на следующих этапах, она будет отклонен и процедура входа завершится неудачно.</p> <p>Сразу после входа одноразовый пароль будет удален, чтобы предовратить любую несанкционированную попытку доступа.</p> <p>Одноразовые пароли - удачный выбор для тех, кто обеспокоен кейлоггерами или spyware, которые могут собирать информ.</p> <p> <b>Строго рекомендуется использовать одноразовые пароли для доступа к Clipperz с чужих компьютеров, из интернет-кафе и библиотек.</b> </p> ",
153 'oneTimePasswordReadOnlyMessage':"<h6>Извините!</h6> <p>Вы не можете управлять одноразовыми ключевыми фразами в оффлайновой версии Clipperz.</p> ",
154 'oneTimePasswordLoadingMessage':"<h6>Загрузка данных</h6> <p>Подождите, пожайлуста ...</p> ",
155 'oneTimePasswordNoPasswordAvailable':"<h6>Нет свободных для использования одноразовых ключевых фраз.</h6> <p>Нажмите кнопку “Новая”, чтобы добавить еще одноразовые ключевые фразы в аккаунт.</p> ",
156 'createNewOTPButtonLabel':"новая",
157 'deleteOTPButtonLabel':"удалить",
158 'printOTPButtonLabel':"печать",
159 'disabledOneTimePassword_warning':"запрещено",
160 'oneTimePasswordSelectionLink_selectLabel':"Выбрать:",
161 'oneTimePasswordSelectionLink_all':"все",
162 'oneTimePasswordSelectionLink_none':"ни одного",
163 'oneTimePasswordSelectionLink_used':"использованные",
164 'oneTimePasswordSelectionLink_unused':"неиспользованные",
165 'saveOTP_encryptUserDataTitle':"Сохранение одноразовых ключевых фраз",
166 'saveOTP_encryptUserDataText':"Обработка новых данных учетной записи ...",
167 'saveOTP_encryptOTPDataTitle':"одноразовыми ключевыми фразами",
168 'saveOTP_encryptOTPDataText':"Шифрование аутентификационных данных ...",
169 'saveOTP_sendingDataTitle':"одноразовыми ключевыми фразами",
170 'saveOTP_sendingDataText':"Передача аутентификационных данных на сервер ...",
171 'saveOTP_updatingInterfaceTitle':"одноразовыми ключевыми фразами",
172 'saveOTP_updatingInterfaceText':"Обновление интерфейса ...",
173 'accountPreferencesLabel':"Настройки",
174 'accountPreferencesTabTitle':"Настройки",
175 'accountPreferencesLanguageTitle':"Выбор языка",
176 'accountPreferencesLanguageDescription':"<p>Выберите Ваш язык из списка.</p> ",
177 'showDonationReminderPanelTitle':"Напоминания о пожертвованиях",
178 'showDonationReminderPanelDescription':"<p>Показать напоминания о пожертвованиях</p> ",
179 'saveUserPreferencesFormSubmitLabel':"Сохранить",
180 'cancelUserPreferencesFormSubmitLabel':"Отмена",
181 'accountPreferencesSavingPanelTitle_Step1':"Сохранение настроек",
182 'accountPreferencesSavingPanelText_Step1':"Шифрование настроек",
183 'accountPreferencesSavingPanelTitle_Step2':"Сохранение настроек",
184 'accountPreferencesSavingPanelText_Step2':"Передача зашифрованных настроек в Clipperz",
185 'accountLoginHistoryLabel':"История входов",
186 'loginHistoryTabTitle':"История входов",
187 'loginHistoryReadOnlyMessage':"<h6>Извините!</h6> <p>История входов не доступна в оффлайновой версии Clipperz.</p> ",
188 'loginHistoryLoadingMessage':"<h6>Загрузка данных</h6> <p>Подождите, пожайлуста ...</p> ",
189 'loginHistoryLoadedMessage':"<h6>Десять Ваших последних входов</h6> <p> </p> ",
190 'loginHistoryIPLabel':"IP",
191 'loginHistoryTimeLabel':"дата",
192 'loginHistoryCurrentSessionText':"текущая сессия",
193 'loginHistoryReloadButtonLabel':"Обновить историю",
194 'deleteAccountTabLabel':"Удалить аккаунт",
195 'deleteAccountTabTitle':"Удалить аккаунт",
196 'deleteAccountFormUsernameLabel':"имя пользователя",
197 'deleteAccountFormPassphraseLabel':"ключевая фраза",
198 'deleteAccountFormSafetyCheckboxLabel':"Я понимаю, что все мои данные будут удалены и это действие необратимо.",
199 'deleteAccountFormSubmitLabel':"Удалить мой аккаунт",
200 'deleteAccountFormWrongUsernameWarning':"Неверное имя пользователя",
201 'deleteAccountFormWrongPassphraseWarning':"Неверная ключевая фраза",
202 'deleteAccountFormSafetyCheckWarning':"Прочтите и отметьте все поля ниже.",
203 'accountPanelDeletingAccountPanelConfirmationTitle':"ВНИМАНИЕ",
204 'accountPanelDeleteAccountPanelConfirmationText':"Вы уверены, что хотите удалить аккаунт?",
205 'accountPanelDeleteAccountPanelConfirmButtonLabel':"Да",
206 'accountPanelDeleteAccountPanelDenyButtonLabel':"Нет",
207 'offlineCopyTabLabel':"Оффлайновая копия",
208 'offlineCopyTabTitle':"Оффлайновая копия",
209 'offlineCopyTabDescription':"<p>Одним кликом Вы можете сохранить все зашифрованные данные с серверов Clipperz на жесткий диск и создать оффлайновую версию, которую будете использовать при отсутствии подключения к Интернету.</p> <p>Версия только для чтения безопасна также, как и полная, и не подвергает Ваши данные большим рискам, так как использует тот же код и архитектуру.</p> <ol> <li> <p>Нажмите на ссылку, чтобы начать скачивание.</p> </li> <li> <p>Браузер спросит, что сделать с файлом “Clipperz_YYYYMMDD.html”. Сохраните его на Ваш жесткий диск.</p> </li> <li> <p>Double click on the downloaded file to launch the offline version in your browser.</p> </li> <li> <p>Как обычно, введите имя пользователя и ключевую фразу.</p> </li> </ol> ",
210 'offlineCopyDownloadLinkLabel':"Скачать",
211 'offlineCopyDownloadWarning':"<h4> <a href=\"#\" id=\"offlineCopyDownloadWarningLink\">Обновите Вашу “оффлайновую копию”!</a> </h4> <p>Вы недавно создали или изменили одну или более карточек: было бы разумным скачать новую оффлайновую копию.</p> ",
212 'sharingTabLabel':"Совместное использование",
213 'sharingTabTitle':"Совместное использование",
214 'sharingTabDescription':"<p>Достаточно часто конфидециальную информацию нужно открыть одному или нескольким людям.</p> <p>Это может быть просто, как дать коллеге ключ доступа к Вашей голосовой почте, когда Вас нет в офисе, или сложно, как открыть доступ наследникам к Вашему счету в местном банке, когда Вы скончаетесь.</p> <p>Clipperz поможет сделать совместное использование Ваших секретов безопасным и простым процессом.</p> <p> </p> <p> <b>Скоро ...</b> </p> ",
215 'importTabLabel':"Импорт",
216 'importTabTitle':"Импорт",
217 'importTabDescription':"<p> <b>Скоро ...</b> </p> ",
218 'printingTabLabel':"Экспорт",
219 'printingTabTitle':"Экспорт",
220 'printingTabDescription':"<p> <b>Печать Ваших данных</b> </p> <p>Нажмите по ссылке, чтобы открыть новое окно со всеми Вашими карточками для печати.</p> <p>Если вы собираетесь распечатать в резервных целях, пожайлуста, рассмотрите более безопасный вариант, как создание “оффлайновой копии”.</p> ",
221 'printingLinkLabel':"Версия для печати",
222 'contactsTabLabel':"Контакты",
223 'contactsTabTitle':"Контакты",
224 'passwordGeneratorTabLabel':"Генератор паролей",
225 'passwordGeneratorTabTitle':"Генератор паролей",
226 'passwordGeneratorTabButtonLabel':"Генератор паролей",
227 'bookmarkletTabLabel':"Закладка",
228 'bookmarkletTabTitle':"Закладка",
229 'bookmarkletTabDescription':"<p>Закладка - это простой инструмент, который может решать очень полезные задачи. Ее можно сохранить и использовать как обычную веб-страницу.</p> <p>Закладки помогут Вам быстро создать новые карточки и новые логины внутри существующих карточек.</p> <p> <b>Пожайлуста, учтите, что закладки действительно не включают какой-либо информации, связанной с аккаунтом (например, имя или ключевая фраза), закладки содержат один и тот же код для каждого пользователя.</b> </p> <h3>Как установить закладку</h3> <h5>Firefox, Camino, Opera, Safari</h5> <ol> <li> <p>Убедитесь, что панель закладок отображается выбором “View > Toolbars > Bookmarks” или похожими пунктами из меню браузера.</p> </li> <li> <p>Нажмите и перетащите ссылку “Добавить в Clipperz” на панель закладок.</p> </li> </ol> <h5>Internet Explorer</h5> <ol> <li> <p>Убедитесь, что отображается панель “Ссылки” выбором “View > Toolbars > Links” из меню браузера.</p> </li> <li> <p>Нажмите правой кнопкой на ссылку “Добавить в Clipperz”.</p> </li> <li> <p>Выберите “Add to favorites” из контекстного меню.</p> </li> <li> <p>Нажмите “Yes” для любых сообщений, которые появятся.</p> </li> <li> <p>Откройте папку “Links” и нажмите “OK”.</p> </li> </ol> ",
230 'bookmarkletTabBookmarkletTitle':"Добавить в Clipperz",
231 'bookmarkletTabInstructions':"<h3>Как создать новую карточку с ссылками “прямого подключения” в онлайновый сервис</h3> <ol> <li> <p>Откройте веб-страницу с формой входа. (обычно на этой страницы Вы вводите данные вашей учетной записи)</p> </li> <li> <p>Запустите закладку, нажав на нее: появится всплывающее окно.</p> </li> <li> <p>Скопируйте в буфер обмена содержимое текстового поля из всплывающего окна. (ctrl-C)</p> </li> <li> <p>Ввойдите в Ваш аккаунт и нажмите “Добавить новую карточку”.</p> </li> <li> <p>Выберите шаблон “Прямого подключения” и вставьте в текстовое поле содержимое буфера обмена. (ctrl-V)</p> </li> <li> <p>Нажмите кнопку “Создать”, проверьте правильность и нажмите “Сохранить”.</p> </li> </ol> <h3>Как создать ссылку “Прямого подключения” в существующей карточке</h3> <ol> <li> <p>Тоже самое, как и выше.</p> </li> <li> <p>Тоже самое, как и выше.</p> </li> <li> <p>Тоже самое, как и выше.</p> </li> <li> <p>Ввойдите в Ваш аккаунт и выберите карточку с данными учетной записи для только что посещенного веб-сервиса и нажмите “Редактировать”.</p> </li> <li> <p>Вставьте содержимое буфера обмена в текстовое поле в разделе “Прямого подключения”. (ctrl-V)</p> </li> <li> <p>Нажмите “Добавить новое прямое подключение”, проверьте правильность и нажмите “Сохранить”.</p> </li> </ol> <p> </p> <p>Подробнее о закладках <a href=\"http://www.clipperz.com/support/user_guide/bookmarklet\" target=\"_blank\">здесь</a>.</p> ",
232 'mainPanelDirectLoginBlockLabel':"Прямые подключения",
233 'directLinkReferenceShowButtonLabel':"показать",
234 'mainPanelDirectLoginBlockDescription':"<p>Добавьте “Прямые подключения”, чтобы срау входить в веб-сервисы без ввода имени и пароля!</p> <p>“Прямые подключения” значительно усиливают безопасность, так как:</p> <ul> <li> <p>удобно принимать и вводить сложные пароли;</p> </li> <li> <p>никогда не надо использовать простой и один и тот же пароль.</p> </li> </ul> <p>Простая и быстрая конфигурация с помощью закладок.</p> <a href=\"http://www.clipperz.com/support/user_guide/direct_logins\" target=\"_blank\">Подробнее о прямых подключениях</a> ",
235 'mainPanelRecordsBlockLabel':"Карточки",
236 'mainPanelAddRecordButtonLabel':"Добавить новую карточку",
237 'mainPanelRemoveRecordButtonLabel':"Удалить карточку",
238 'mainPanelRecordFilterBlockAllLabel':"все",
239 'mainPanelRecordFilterBlockTagsLabel':"теги",
240 'mainPanelRecordFilterBlockSearchLabel':"поиск",
241 'recordDetailNoRecordAtAllTitle':"Добро пожаловать в Clipperz!",
242 'recordDetailNoRecordAtAllDescription':"<h5>Начните, добавив карточку.</h5> <p>Карточки - это простой и гибкий инструмент, с помощью которого Вы можете хранить пароли и любую другую информацию.</p> <p>Карточки могут содержать учетные записи для доступа к веб-сайтам, код для замка от велосипеда, данные кредитной карточки, ...</p> <h5>Не забывай о закладках!</h5> <p>Перед началом работы установите закладку “Добавить в Clipperz”: создание карточек будет простым и забавным.</p> <p>Перейдите на панель закладок, чтобы изучить, как установить и использовать их.</p> <p> </p> <a href=\"http://www.clipperz.com/support/user_guide/managing_cards\" target=\"_blank\">Подробнее об создании и управлениями закладками</a> ",
243 'newRecordWizardTitleBox':"<h5>Пожайлуста, выберите шаблон</h5> <p>Карточки - это простой и гибкий инструмент, с помощью которого Вы можете хранить пароли и любую другую информацию.</p> <p>Выберите один из шаблонов. Вы всегда сможете настроить ваши карточки, добавляя или удаляя поля.</p> ",
244 'newRecordWizardBookmarkletConfigurationTitle':"Прямое подключение",
245 'newRecordWizardBookmarkletConfigurationDescription':"<p>Вставьте конфигурационный код, сгенерированный с помощью закладки</p> <p>Будет создана новая карточка с поддержкой прямого подключения.</p> ",
246 'newRecordWizardCreateButtonLabel':"Создать",
247 'newRecordWizardCancelButtonLabel':"Отмена",
248 'donateSplashPanelTitle':"Поддержите Clipperz, сделайте пожертвование сегодня!",
249 'donateSplashPanelDescription':"<p>Несколько причин сделать пожертвование:</p> <ul> <li> <p>поддержка развития новых функций</p> </li> <li> <p>оставить Clipperz бесплатным</p> </li> <li> <p>показать признательность нашей упорной работе</p> </li> </ul> <p>Для дополнительной информации посетите нашу <a href=\"http://www.clipperz.com/donations\" target=\"_blank\">страницу пожертвований</a>.</p> <p> <b>Готовы пожертвовать?</b> </p> ",
250 'donateCloseButtonLabel':"Еще нет",
251 'donateDonateButtonLabel':"Да",
252 'recordTemplates':{
253 'WebAccount':{
254 'title':"Интернет Пароль",
255 'description':"Простая форма для хранения учетной записи в онлайновый сервис."
256 },
257 'BankAccount':{
258 'title':"Банковский аккаунт",
259 'description':"Безопасное хранение номера Вашей банковской карты и учетной записи для онлайнового банкинга."
260 },
261 'CreditCard':{
262 'title':"Кредитная карта",
263 'description':"Номер карты, срок действия, CCV2 и ПИН всегда в Ваших руках."
264 },
265 'AddressBookEntry':{
266 'title':"Запись адресной книги",
267 'description':"Clipperz может также работать, как новая частная адресная книга. Используйте этот шаблон, чтобы легко добавить новую запись."
268 },
269 'Custom':{
270 'title':"Пользовательская карточка",
271 'description':"Не важно, какие данные нужно защитить, просто создайте карточку."
272 }
273 },
274 'recordFieldTypologies':{
275 'TXT':{
276 'description':"simple text field",
277 'shortDescription':"текст"
278 },
279 'PWD':{
280 'description':"simple text field, with default status set to hidden",
281 'shortDescription':"пароль"
282 },
283 'URL':{
284 'description':"simple text field in edit mode, that became an active url in view mode",
285 'shortDescription':"веб-адрес"
286 },
287 'DATE':{
288 'description':"a value set with a calendar helper",
289 'shortDescription':"дата"
290 },
291 'ADDR':{
292 'description':"just like the URL, but the active link points to Google Maps (or similar service) passing the address value as argument",
293 'shortDescription':"почтовый адрес"
294 },
295 'CHECK':{
296 'description':"check description",
297 'shortDescription':"check"
298 },
299 'RADIO':{
300 'description':"radio description",
301 'shortDescription':"radio"
302 },
303 'SELECT':{
304 'description':"select description",
305 'shortDescription':"select"
306 }
307 },
308 'newRecordPanelGeneralExceptionTitle':"Ошибка",
309 'newRecordPanelGeneralExceptionMessage':"Конфигурационный текст неверен. Убедитесь, что Вы взяли его из окна закладки и попробуйте снова.",
310 'newRecordPanelWrongBookmarkletVersionExceptionTitle':"Ошибка",
311 'newRecordPanelWrongBookmarkletVersionExceptionMessage':"Конфигурационный текст был сгенерирован с помощью старой весии закладок. Пожайлуста, обновите Вашу закладку и попробуйте снова.",
312 'newRecordPanelExceptionPanelCloseButtonLabel':"Отмена",
313 'mainPanelDeletingRecordPanelConfirmationTitle':"Удаление выбранной карточки",
314 'mainPanelDeleteRecordPanelConfirmationText':"Вы действительно хотите удалить эту карточку?",
315 'mainPanelDeleteRecordPanelConfirmButtonLabel':"Ага",
316 'mainPanelDeleteRecordPanelDenyButtonLabel':"Не-а",
317 'mainPanelDeletingRecordPanelInitialTitle':"Удаление выбранной карточки",
318 'mainPanelDeletingRecordPanelCompletedText':"Выполнено",
319 'deleteRecordPanelCollectRecordDataMessageTitle':"Удаление карточки",
320 'deleteRecordPanelCollectRecordDataMessageText':"Обновление списка карточек",
321 'deleteRecordPanelEncryptUserDataMessageTitle':"Удаление карточки",
322 'deleteRecordPanelEncryptUserDataMessageText':"Шифрование заголовков карточек",
323 'deleteRecordPanelSendingDataToTheServerMessageTitle':"Удаление карточки",
324 'deleteRecordPanelSendingDataToTheServerMessageText':"Передача зашифрованных заголовков карчточек в Clipperz",
325 'deleteRecordPanelUpdatingTheInterfaceMessageTitle':"Удаление карточки",
326 'deleteRecordPanelUpdatingTheInterfaceMessageText':"Обновление интерфейса",
327 'recordDetailNoRecordSelectedTitle':"Не выбрана карточка",
328 'recordDetailNoRecordSelectedDescription':"<p>Пожайлуста, выберите карточку из списка слева.</p> ",
329 'recordDetailLoadingRecordMessage':"Загрузка зашифрованных карточек из Clipperz",
330 'recordDetailDecryptingRecordMessage':"Расшифровка данных карточек",
331 'recordDetailLoadingRecordVersionMessage':"Загрузка последней версии карточкиn",
332 'recordDetailDecryptingRecordVersionMessage':"Расшифровка",
333 'recordDetailLoadingErrorMessageTitle':"Ошибка при загрузку",
334 'recordDetailNotesLabel':"Примечания",
335 'recordDetailLabelFieldColumnLabel':"Метка поля",
336 'recordDetailDataFieldColumnLabel':"Данные поля",
337 'recordDetailTypeFieldColumnLabel':"Тип",
338 'recordDetailSavingChangesMessagePanelInitialTitle':"Сохранение карточки",
339 'recordDetailAddFieldButtonLabel':"Добавить новое поле",
340 'recordDetailPasswordFieldHelpLabel':"чтобы скопировать пароль в буфер обмена, нажмите на звездочку, затем Ctrl-C",
341 'recordDetailPasswordFieldScrambleLabel':"спрятать",
342 'recordDetailPasswordFieldUnscrambleLabel':"показать",
343 'recordDetailDirectLoginBlockTitle':"Прямые подключения",
344 'recordDetailNewDirectLoginDescription':"<p>Настройка прямых подключений</p> ",
345 'recordDetailDirectLoginBlockNoDirectLoginConfiguredDescription':"<p>В этой карточке есть данные для доступа в онлайновый сервис?</p> <p>Используйте закладки, чтобы настроить “прямые подключения”!</p> ",
346 'recordDetailAddNewDirectLoginButtonLabel':"Добавить новое прямое подключение",
347 'recordDetailEditButtonLabel':"Редактировать",
348 'recordDetailSaveButtonLabel':"Сохранить",
349 'recordDetailCancelButtonLabel':"Отмена",
350 'newRecordTitleLabel':"_новую карточку_",
351 'recordSaveChangesPanelCollectRecordInfoMessageTitle':"Сохранение карточки",
352 'recordSaveChangesPanelCollectRecordInfoMessageText':"Обновление заголовков карточек",
353 'recordSaveChangesPanelEncryptUserDataMessageTitle':"Сохранение карточки",
354 'recordSaveChangesPanelEncryptUserDataMessageText':"Шифрование заголовков карточки",
355 'recordSaveChangesPanelEncryptRecordDataMessageTitle':"Сохранение карточки",
356 'recordSaveChangesPanelEncryptRecordDataMessageText':"Шифровани данных карточки",
357 'recordSaveChangesPanelEncryptRecordVersionDataMessageTitle':"Сохранение карточки",
358 'recordSaveChangesPanelEncryptRecordVersionDataMessageText':"Шифрование данных версии карточки",
359 'recordSaveChangesPanelSendingDataToTheServerMessageTitle':"Сохранение карточки",
360 'recordSaveChangesPanelSendingDataToTheServerMessageText':"Передача зашифрованного заголовка карточки в Clipperz",
361 'recordSaveChangesPanelUpdatingTheInterfaceMessageTitle':"Сохранение карточки",
362 'recordSaveChangesPanelUpdatingTheInterfaceMessageText':"Обновление интерфейса",
363 'passwordGeneratorPanelTitle':"Генератор паролей",
364 'passwordGeneratorPanelOkLabel':"OK",
365 'passwordGeneratorPanelCancelLabel':"Отмена",
366 'passwordGeneratorLengthLabel':"длина:",
367 //'DWRUtilLoadingMessage':"Загрузка данных ...",
368 'comingSoon':"вскоре ...",
369 'panelCollectingEntryopyMessageText':"Определение энтропии",
370 'directLoginConfigurationCheckBoxFieldSelectedValue':"Да",
371 'directLoginConfigurationCheckBoxFieldNotSelectedValue':"Нет",
372 'WELCOME_BACK':"Добро пожаловать снова!",
373 'currentConnectionText':"Сейчас вы подключились с ip&nbsp;__ip__, очевидно __country__, используя __browser__ на __operatingSystem__.",
374 'latestConnectionText':"Последнее соединение было __elapsedTimeDescription__ (__time__) с ip&nbsp;__ip__, очевидно __country__, используя __browser__ на __operatingSystem__.",
375 'fullLoginHistoryLinkLabel':"показать полную историю входов",
376 'elapsedTimeDescriptions':{
377 'MORE_THAN_A_MONTH_AGO':"за месяц",
378 'MORE_THAN_A_WEEK_AGO':"за неделю",
379 'MORE_THAN_*_WEEKS_AGO':"за несколько __elapsed__ недель",
380 'YESTERDAY':"вчера",
381 '*_DAYS_AGO':"__elapsed__ дней(-я)",
382 'ABOUT_AN_HOUR_AGO':"за час",
383 '*_HOURS_AGO':"__elapsed__ часов(-а)",
384 'JUST_A_FEW_MINUTES_AGO':"несколько минут",
385 'ABOUT_*_MINUTES_AGO':"около __elapsed__ минут"
386},
387 'unknown_ip':"неизвестный",
388 'calendarStrings':{
389 'months':{
390 '0':"Январь",
391 '1':"Февраль",
392 '2':"Март",
393 '3':"Апрель",
394 '4':"Май",
395 '5':"Июнь",
396 '6':"Июль",
397 '7':"Август",
398 '8':"Сентябрь",
399 '9':"Октябрь",
400 '10':"Ноябрь",
401 '11':"Декабрь"
402 },
403 'shortMonths':{
404 '0':"Янв",
405 '1':"Фев",
406 '2':"Мар",
407 '3':"Апр",
408 '4':"Май",
409 '5':"Июн",
410 '6':"Июл",
411 '7':"Авг",
412 '8':"Сен",
413 '9':"Окт",
414 '10':"Ноя",
415 '11':"Дек"
416 },
417 'days':{
418 '0':"Воскресенье",
419 '1':"Понедельник",
420 '2':"Вторник",
421 '3':"Среда",
422 '4':"Четверг",
423 '5':"Пятница",
424 '6':"Суббота"
425 },
426 'shortDays':{
427 '0':"Вск",
428 '1':"Пон",
429 '2':"Втр",
430 '3':"Сре",
431 '4':"Чет",
432 '5':"Пят",
433 '6':"Суб"
434 },
435 'amDesignation':"am",
436 'pmDesignation':"pm"
437},
438
439__syntaxFix__: "syntax fix"
440});
diff --git a/frontend/beta/js/Clipperz/PM/Strings/Strings_zh-CN.js b/frontend/beta/js/Clipperz/PM/Strings/Strings_zh-CN.js
new file mode 100644
index 0000000..a1d09f1
--- a/dev/null
+++ b/frontend/beta/js/Clipperz/PM/Strings/Strings_zh-CN.js
@@ -0,0 +1,477 @@
1/*
2
3Copyright 2008-2011 Clipperz Srl
4
5This file is part of Clipperz's Javascript Crypto Library.
6Javascript Crypto Library provides web developers with an extensive
7and efficient set of cryptographic functions. The library aims to
8obtain maximum execution speed while preserving modularity and
9reusability.
10For further information about its features and functionalities please
11refer to http://www.clipperz.com
12
13* Javascript Crypto Library is free software: you can redistribute
14 it and/or modify it under the terms of the GNU Affero General Public
15 License as published by the Free Software Foundation, either version
16 3 of the License, or (at your option) any later version.
17
18* Javascript Crypto Library is distributed in the hope that it will
19 be useful, but WITHOUT ANY WARRANTY; without even the implied
20 warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
21 See the GNU Affero General Public License for more details.
22
23* You should have received a copy of the GNU Affero General Public
24 License along with Javascript Crypto Library. If not, see
25 <http://www.gnu.org/licenses/>.
26
27*/
28
29Clipperz.PM.Strings.Languages['zh-CN'.toLowerCase()] = MochiKit.Base.merge(Clipperz.PM.Strings.Languages['en-us'], {
30 'clipperzServiceDescription':"<h2>只有你知道</h2> <ul> <li> <h3>Clipperz 是:</h3> <ul> <li> <p>一个简单而又安全的密码管理员</p> </li> <li> <p>一个有效的单一登录解决方案</p> </li> <li> <p>一个您保密的资料数据库</p> </li> </ul> </li> <li> <h3> 使用 Clipperz 你能:</h3> <ul> <li> <p>储存和管理你的密码和网上证书</p> </li> <li> <p>无需输入密码自动帮助你登录网站服务</p> </li> <li> <p>保护你的敏感数据:通讯录,口令,信用卡号码, ...</p> </li> <li> <p>与家人和伙伴分享秘密(将要上线)</p> </li> </ul> </li> <li> <h3>Clipperz 的特点:</h3> <ul> <li> <p>免费,彻底匿名</p> </li> <li> <p>在任何时间 任何电脑都可以轻松获取你的密码</p> </li> <li> <p>无需下载和安装任何软件</p> </li> <li> <p>再也无需在电脑或者纸上记录密码了</p> </li> </ul> </li> <li> <h3>Clipperz 的安全性:</h3> <ul> <li> <p>密码将在本地浏览器加密,然后上传至 Clipperz</p> </li> <li> <p>加密密钥是一个只有你知道的密码短语</p> </li> <li> <p>Clipperz 服务会加密你的敏感数据,并不会出现数据的原始形式</p> </li> <li> <p>Clipperz 基于加密标准,没有任何的花哨</p> </li> <li> <p>只要你愿意,你随时都可以查看源代码,但是做为一个使用者来说完全没有去必要去了解那些繁琐的加密原理</p> </li> </ul> </li> <li> <a href=\"http://www.clipperz.com\" target=\"_blank\">更多</a> </li> </ul> ",
31 'loginFormTitle':"用你的 Clipperz 帐户登录",
32 'loginFormUsernameLabel':"用户名",
33 'loginFormPassphraseLabel':"密码短语",
34 'loginFormDontHaveAnAccountLabel':"还未建立帐户?",
35 'loginFormCreateOneLabel':"创建一个新帐户",
36 'loginFormForgotYourCredentialsLabel':"忘记你的证书?",
37 'loginFormAarghThatsBadLabel':"呃?这下糟糕了",
38 'loginFormAfraidOfMaliciousScriptsLabel':"害怕有恶意脚本?",
39 'loginFormVerifyTheCodeLabel':"验证代码",
40 'loginFormButtonLabel':"登录",
41 'loginFormOneTimePasswordCheckboxLabel':"使用一次性密码短语",
42 'loginPanelSwithLanguageDescription':"<h5>选择你的第一语言</h5> ",
43 'browserCompatibilityDescription':"<p>使用 Firefox 将得到更快更安全的 Clipperz 服务。不过 Clipperz 同样可以很好的工作在 Opera 和 微软的 IE 中。</p> ",
44 'OTPloginMessagePanelInitialTitle':"用一次性密码短语登录",
45 'OTPloginMessagePanelInitialText':"发送 OTP 证书 ...",
46 'OTPloginMessagePanelLoadingTitle':"用一次性密码短语登录",
47 'OTPloginMessagePanelLoadingText':"从服务器读取加密认证数据 ...",
48 'OTPloginMessagePanelProcessingTitle':"用一次性密码短语登录",
49 'OTPloginMessagePanelProcessingText':"本地解密认证数据",
50 'loginMessagePanelInitialTitle':"登录中...",
51 'loginMessagePanelInitialButtonLabel':"取消",
52 'loginMessagePanelConnectedTitle':"连接成功",
53 'loginMessagePanelConnectedText':"完成",
54 'loginMessagePanelFailureTitle':"错误",
55 'loginMessagePanelFailureText':"登录失败",
56 'loginMessagePanelFailureButtonLabel':"取消",
57 'connectionLoginSendingCredentialsMessageTitle':"验证证书",
58 'connectionLoginSendingCredentialsMessageText':"传送证书",
59 'connectionLoginCredentialsVerificationMessageTitle':"验证证书",
60 'connectionLoginCredentialsVerificationMessageText':"进行 SRP 认证",
61 'connectionLoginDoneMessageTitle':"验证证书",
62 'connectionLoginDoneMessageText':"已连接",
63 'userLoginPanelUpgradingUserCredentialsMessageTitle':"验证证书",
64 'userLoginPanelUpgradingUserCredentialsMessageText':"升级证书到新的认证模式",
65 'userLoginPanelConnectedMessageTitle':"用户识别",
66 'userLoginPanelConnectedMessageText':"成功登录",
67 'userLoginPanelTryingAnOlderConnectionSchemaMessageTitle':"验证证书",
68 'userLoginPanelTryingAnOlderConnectionSchemaMessageText':"旧认证模式失效",
69 'userLoginPanelLoadingUserDataMessageTitle':"用户识别",
70 'userLoginPanelLoadingUserDataMessageText':"正在从 Clipperz 下载加密卡报头",
71 'userLoginPanelDecryptingUserDataMessageTitle':"用户识别",
72 'userLoginPanelDecryptingUserDataMessageText':"加密卡报头本地解密",
73 'userLoginPanelDecryptingUserStatisticsMessageTitle':"用户识别",
74 'userLoginPanelDecryptingUserStatisticsMessageText':"本地解密使用统计",
75 'splashAlertTitle':"Clipperz 欢迎您",
76 'splashAlertText':"<p>安全忠告</p> <ul> <li> <p>在 Clipperz ,用你选择的密码短语保存数据是安全的。没有人能够得到这些数据,除非他们有你的密码。</p> </li> <li> <p> 如果你决定使用 Clipperz 保护敏感数据和关键资料,请务必选用一个复杂的密码短语。越长越好</p> </li> <li> <p>注意:Clipperz将无法找回忘记的密码码短语!</p> </li> </ul> <p>获得更多的说明,请前往 <a href=\"http://www.clipperz.com\" target=\"_blank\">Clipperz</a> 网站.</p> ",
77 'splashAlertCloseButtonLabel':"确定",
78 'registrationFormTitle':"创建你的帐户",
79 'registrationFormUsernameLabel':"用户名",
80 'registrationFormPassphraseLabel':"密码短语",
81 'registrationFormRetypePassphraseLabel':"确认密码短语",
82 'registrationFormSafetyCheckLabel':"我明白 Clipperz 无法找回忘记的密码短语.",
83 'registrationFormTermsOfServiceCheckLabel':"我同意接受 <a href='http://www.clipperz.com/terms_of_service' target='_blank'>服务条款</a> 款.",
84 'registrationFormDoYouAlreadyHaveAnAccountLabel':"如果已有一个 Clipperz 帐户",
85 'registrationFormSimplyLoginLabel':"在此登录",
86 'registrationFormButtonLabel':"注册",
87 'registrationFormWarningMessageNotMatchingPassphrases':"两次密码短语不同,请重新输入",
88 'registrationFormWarningMessageSafetyCheckNotSelected':"请阅读并检查下面的选项框",
89 'registrationFormWarningMessageTermsOfServiceCheckNotSelected':"您需要同意服务条款",
90 'registrationMessagePanelInitialTitle':"创建账户...",
91 'registrationMessagePanelInitialButtonLabel':"取消",
92 'registrationMessagePanelRegistrationDoneTitle':"注册",
93 'registrationMessagePanelRegistrationDoneText':"完成",
94 'registrationMessagePanelFailureTitle':"注册失败",
95 'registrationMessagePanelFailureButtonLabel':"关闭",
96 'connectionRegistrationSendingRequestMessageText':"验证证书",
97 'connectionRegistrationSendingCredentialsMessageText':"传送证书",
98 'registrationSplashPanelTitle':"安全忠告",
99 'registrationSplashPanelDescription':"<p>这是你的 Clipperz 证书,请保存好。Clipperz 永远不会第二次显示你的用户名和密码短语</p> ",
100 'registrationSplashPanelUsernameLabel':"用户名",
101 'registrationSplashPanelPassphraseLabel':"密码短语",
102 'registrationSplashPanelShowPassphraseButtonLabel':"显示密码短语",
103 'donateHeaderLinkLabel':"捐赠",
104 'creditsHeaderLinkLabel':"致谢",
105 'feedbackHeaderLinkLabel':"反馈",
106 'helpHeaderLinkLabel':"帮助",
107 'forumHeaderLinkLabel':"论坛",
108 'recordMenuLabel':"密码卡片",
109 'accountMenuLabel':"账户",
110 'dataMenuLabel':"资料",
111 'contactsMenuLabel':"联系",
112 'toolsMenuLabel':"工具",
113 'logoutMenuLabel':"暂时离开",
114 'lockMenuLabel':"安全锁",
115 'lockTitle':"账户被锁定",
116 'lockDescription':"<p>请输入你的密码短语解开账户</p> ",
117 'unlockButtonLabel':"解锁",
118 'changePasswordTabLabel':"修改密码短语",
119 'changePasswordTabTitle':"修改密码短语",
120 'changePasswordFormUsernameLabel':"用户名",
121 'changePasswordFormOldPassphraseLabel':"旧密码短语",
122 'changePasswordFormNewPassphraseLabel':"新密码短语",
123 'changePasswordFormRetypePassphraseLabel':"确认密码短语",
124 'changePasswordFormSafetyCheckboxLabel':"我知道 Clipperz 不能找回丢失的密码短语",
125 'changePasswordFormSubmitLabel':"修改密码短语",
126 'changePasswordFormWrongUsernameWarning':"用户名错误",
127 'changePasswordFormWrongPassphraseWarning':"旧密码短语错误",
128 'changePasswordFormWrongRetypePassphraseWarning':"两次密码短语不同,请重新输入",
129 'changePasswordFormSafetyCheckWarning':"请阅读并检查下面的选项框",
130 'changePasswordFormProgressDialogTitle':"正在修改密码短语",
131 'changePasswordFormProgressDialogConnectedMessageTitle':"连接",
132 'changePasswordFormProgressDialogConnectedMessageText':"完成",
133 'changePasswordFormProgressDialogErrorMessageTitle':"错误",
134 'changePasswordFormProgressDialogErrorMessageText':"证书修改失败",
135 'changeCredentialsPanelEncryptingDataMessageTitle':"正在修改你的密码短语",
136 'changeCredentialsPanelEncryptingDataMessageText':"加密卡报头本地解密",
137 'changeCredentialsPanelCreatingNewCredentialsMessageTitle':"正在修改你的密码短语",
138 'changeCredentialsPanelCreatingNewCredentialsMessageText':"更新你的证书",
139 'changeCredentialsPanelSendingNewCredentialsToTheServerMessageTitle':"正在修改你的密码短语",
140 'changeCredentialsPanelSendingNewCredentialsToTheServerMessageText':"正在上传本地证书到 Clipperz",
141 'changeCredentialsPanelDoneMessageTitle':"正在修改你的密码短语",
142 'changeCredentialsPanelDoneMessageText':"完成",
143 'manageOTPTabLabel':"管理你的一次性密码短语",
144 'manageOTPTabTitle':"管理你的一次性密码短语",
145 'manageOTPTabDescription':"<p>一次性密码短语工作起来和一般的密码短语一样,但是只可以使用一次</p> <p>如果同样的密码短语在一段时间以内再次登录,会被拒绝。登录进程将会失败。</p> <p>为了防止任何欺诈登录,在成功登陆之后,你的一次性密码将会立即被删除,</p> <p>如果一次性密码被键盘记录程序或者间谍软件得到,可能会从被感染的机器上收集数据,这样的话,一次性密码绝对是个很好的选择。</p> <p> <b>强烈建议在公共场合登录 Clipperz 时,使用一次性密码。比如公关计算机,网吧,图书馆等</b> </p> ",
146 'oneTimePasswordReadOnlyMessage':"<h6>对不起!</h6> <p>你不能从离线版本管理你的一次性密码短语</p> ",
147 'oneTimePasswordLoadingMessage':"<h6>加载数据</h6> <p>请等待 ...</p> ",
148 'oneTimePasswordNoPasswordAvailable':"<h6>一次性密码短语没有激活</h6> <p>点击“新建”按钮添加一次性密码短语到你的帐户</p> ",
149 'createNewOTPButtonLabel':"新建",
150 'deleteOTPButtonLabel':"删除",
151 'printOTPButtonLabel':"打印",
152 'disabledOneTimePassword_warning':"禁用",
153 'oneTimePasswordSelectionLink_selectLabel':"选择:",
154 'oneTimePasswordSelectionLink_all':"所有",
155 'oneTimePasswordSelectionLink_none':"没有",
156 'oneTimePasswordSelectionLink_used':"被使用",
157 'oneTimePasswordSelectionLink_unused':"未使用",
158 'saveOTP_encryptUserDataTitle':"保存一次性密码短语",
159 'saveOTP_encryptUserDataText':"处理新的 OTP 证书 ...",
160 'saveOTP_encryptOTPDataTitle':"保存一次性密码短语",
161 'saveOTP_encryptOTPDataText':"本地解密认证数据 ...",
162 'saveOTP_sendingDataTitle':"保存一次性密码短语",
163 'saveOTP_sendingDataText':"发送信任数据到服务器 ...",
164 'saveOTP_updatingInterfaceTitle':"保存一次性密码短语",
165 'saveOTP_updatingInterfaceText':"更新界面...",
166 'accountPreferencesLabel':"使用偏好",
167 'accountPreferencesTabTitle':"使用偏好",
168 'accountPreferencesLanguageTitle':"界面语言选择",
169 'accountPreferencesLanguageDescription':"<p>在下拉菜单中选择你的首选语言</p> ",
170 'showDonationReminderPanelTitle':"捐赠提示",
171 'showDonationReminderPanelDescription':"<p>显示捐赠提示</p> ",
172 'saveUserPreferencesFormSubmitLabel':"保存",
173 'cancelUserPreferencesFormSubmitLabel':"取消",
174 'accountPreferencesSavingPanelTitle_Step1':"保存使用偏好",
175 'accountPreferencesSavingPanelText_Step1':"本地加密你的使用偏好",
176 'accountPreferencesSavingPanelTitle_Step2':"保存使用偏好",
177 'accountPreferencesSavingPanelText_Step2':"正在向 Clipperz 传送加密后的使用偏好",
178 'accountLoginHistoryLabel':"登录历史",
179 'loginHistoryTabTitle':"登录历史",
180 'loginHistoryReadOnlyMessage':"<h6>对不起!</h6> <p>当你使用离线版本时登录历史是无法显示的</p> ",
181 'loginHistoryLoadingMessage':"<h6>加载数据</h6> <p>请等待 ...</p> ",
182 'loginHistoryLoadedMessage':"<h6>您的最近 10 次登陆</h6> <p> </p> ",
183 'loginHistoryIPLabel':"IP",
184 'loginHistoryTimeLabel':"时间",
185 'loginHistoryCurrentSessionText':"当前登录信息",
186 'loginHistoryReloadButtonLabel':"刷新登录历史",
187 'deleteAccountTabLabel':"删除你的账户",
188 'deleteAccountTabTitle':"删除你的账户",
189 'deleteAccountFormUsernameLabel':"用户名",
190 'deleteAccountFormPassphraseLabel':"密码短语",
191 'deleteAccountFormSafetyCheckboxLabel':"我知道我的所有数据将被删除,并且是不可回复的.",
192 'deleteAccountFormSubmitLabel':"删除我的账户",
193 'deleteAccountFormWrongUsernameWarning':"用户名错误",
194 'deleteAccountFormWrongPassphraseWarning':"密码短语错误",
195 'deleteAccountFormSafetyCheckWarning':"请阅读并检查下面的选项框",
196 'accountPanelDeletingAccountPanelConfirmationTitle':"注意",
197 'accountPanelDeleteAccountPanelConfirmationText':"你确认要删除你的帐户",
198 'accountPanelDeleteAccountPanelConfirmButtonLabel':"是",
199 'accountPanelDeleteAccountPanelDenyButtonLabel':"否",
200 'offlineCopyTabLabel':"离线拷贝",
201 'offlineCopyTabTitle':"离线拷贝",
202 'offlineCopyTabDescription':"<p>只需点击一次就可以从 Clipperz 服务器下载所有加密数据到你的硬盘,让你在不能连接互联网的时候使用离线只读版本的 Clipperz。</p> <p>你下载的离线数据和登陆我们网站在线使用是一样安全的,它们使用了同样的密码和安全体系,都不会有暴露数据的风险。</p> <ol> <li> <p>点击链接后开始下载。</p> </li> <li> <p>浏览器会问你如何处理 “Clipperz_YYYYMMDD.html” 文件。保存这个文件到你的硬盘。</p> </li> <li> <p>双击下载的文件在浏览器运行离线版本。</p> </li> <li> <p>输入你的用户名和密码短语。</p> </li> </ol> ",
203 'offlineCopyDownloadLinkLabel':"下载",
204 'offlineCopyDownloadWarning':"<h4> <a href=\"#\" id=\"offlineCopyDownloadWarningLink\">更新你的“离线版本”!</a> </h4> <p>你最近创建或修改了卡片,需要下载新的“离线版本”</p> ",
205 'sharingTabLabel':"共享",
206 'sharingTabTitle':"共享",
207 'sharingTabDescription':"<p>往往一个机密的资料需要另外一个人或者多人共同使用</p> <p>你可以在这里设置一个简单的授权码,以便在离开办公室的时候你的同事可以访问你的邮箱,或者设置一个复杂的,当你去世后子孙可以在这里找到取得银行保险箱的方法。</p> <p>Clipperz 可以安全并且简单的分享你的密码</p> <p> </p> <p> <b>即将发布...</b> </p> ",
208 'importTabLabel':"导入",
209 'importTabTitle':"导入",
210 'importTabDescription':"<p> <b>即将发布 ...</b> </p> ",
211 'printingTabLabel':"导出",
212 'printingTabTitle':"导出",
213 'printingTabDescription':"<p> <b>打印你的数据</b> </p> <p>点击下面的链接,将会打开一个新窗口,以打印格式显示你的密码卡片</p> <p>如果你打印下来是为了备份,请考虑使用我们提供的\"离线版本\",这比打印更安全。</p> ",
214 'printingLinkLabel':"打印版本",
215 'contactsTabLabel':"联系",
216 'contactsTabTitle':"联系",
217 'passwordGeneratorTabLabel':"随机密码生成器",
218 'passwordGeneratorTabTitle':"随机密码生成器",
219 'passwordGeneratorTabButtonLabel':"生成随机密码",
220 'bookmarkletTabLabel':"书签按钮",
221 'bookmarkletTabTitle':"书签按钮",
222 'bookmarkletTabDescription':"<p>这个书签按钮是一个简单的非常有用的“一键”工具,它能像一般网站一样储存并且使用</p> <p>Clipperz 按钮书签可以帮助你快速建立密码卡片并且用存在的密码卡片直接登录</p> <p> <b>请注意,这个书签按钮不包含你账户中的任何信息(例如你的用户名和密码),对所有的 Clipperz 使用者,这个书签按钮是大家的工具,代码都是相同的。</b> </p> <h3>怎样安装书签按钮</h3> <h5>Firefox, Camino, Opera, Safari</h5> <ol> <li> <p>选择 “查看 > 工具栏 > 书签工具栏” 确认 “书签工具栏” 显示在浏览器菜单上。</p> </li> <li> <p>拖动 “添加到 Clipperz” 链接到书签工具栏。</p> </li> </ol> <h5>Internet Explorer</h5> <ol> <li> <p>选择 “查看 > 工具栏 > 链接” 确认 “链接” 显示在浏览器菜单上。</p> </li> <li> <p>右键 “添加到 Clipperz”</p> </li> <li> <p>选择 “添加到收藏夹”</p> </li> <li> <p>如果弹出安全提示选择 “是”</p> </li> <li> <p>打开 “链接” 文件夹后单击 “添加”</p> </li> </ol> ",
223 'bookmarkletTabBookmarkletTitle':"添加到 Clipperz",
224 'bookmarkletTabInstructions':"<h3>如何在一个在线服务中创建可以直接登录的新的密码卡片</h3> <ol> <li> <p>打开你要登录的页面(这个页面通常就是你输入登录信息的页面)</p> </li> <li> <p>点击书签按钮,会出现一个新的弹出窗口</p> </li> <li> <p>复制弹出窗口中的所有文本到剪贴板(ctrl+c)</p> </li> <li> <p>登录你的 Clipperz 账户,然后点击 <b>新建密码卡片</b> 按钮</p> </li> <li> <p>选择“直接登录”模板,之后粘贴剪贴板中的内容到大文本框(ctrl+v)</p> </li> <li> <p>按下 <b>创建</b> 按钮,检查细节并且点击 <b>保存</b>.</p> </li> </ol> <h3>对于已经存在的密码卡片如何添加直接登陆</h3> <ol> <li> <p>与上面的步骤相同</p> </li> <li> <p>与上面的步骤相同</p> </li> <li> <p>与上面的步骤相同</p> </li> <li> <p>输入你的 Clipperz 帐号,选择你刚刚访问的网络服务的密码卡片然后点击 <b>编辑</b> 按钮.</p> </li> <li> <p>将剪贴板中的内容粘贴到“直接登录”区域的大文本框中 (ctrl-V)</p> </li> <li> <p>点击添加 <b>自动登录</b> 按钮,检查细节并且点击k <b>保存</b>.</p> </li> </ol> <p> </p> <p>如果需要关于书签按钮的进一步资料可以在 <a href=\"http://www.clipperz.com/support/user_guide/bookmarklet\" target=\"_blank\">这里获得</a>.</p> ",
225 'mainPanelDirectLoginBlockLabel':"直接登录",
226 'directLinkReferenceShowButtonLabel':"显示",
227 'mainPanelDirectLoginBlockDescription':"<p>添加 “直接登录” 可以让你不用输入用户名和密码即可登录网络账户</p> <p>“直接登录” 可以大大提高你的密码安全性,因为你可以:</p> <ul> <li> <p>方便选择和输入复杂的密码</p> </li> <li> <p>永远不再使用相同的,容易猜测的密码</p> </li> </ul> <p>用 Clipperz 书签按钮简单快速的配置</p> <a href=\"http://www.clipperz.com/support/user_guide/direct_logins\" target=\"_blank\">关于 “直接登录” 的更多信息</a> ",
228 'mainPanelRecordsBlockLabel':"密码卡片",
229 'mainPanelAddRecordButtonLabel':"添加新密码卡片",
230 'mainPanelRemoveRecordButtonLabel':"删除密码卡片",
231 'mainPanelRecordFilterBlockAllLabel':"所有",
232 'mainPanelRecordFilterBlockTagsLabel':"标签",
233 'mainPanelRecordFilterBlockSearchLabel':"搜索",
234 'recordDetailNoRecordAtAllTitle':"欢迎来到 Clipperz!",
235 'recordDetailNoRecordAtAllDescription':"<h5>从你的账户添加密码卡片开始</h5> <p>密码卡片是简单灵活的方式,在这里你可以保存你的密码和其他机密资料.</p> <p>密码卡片含有一个全权访问网站的证书,你的通讯录,你的信用卡信息,……</p> <h5>不要忘记书签按钮</h5> <p>在你开始前,安装 “添加到 Clipperz” 书签按钮:它将使创建密码卡片变得简单并且有趣</p> <p>去书签按钮标签了解如何安装并使用它</p> <p> </p> <p>然后只需单击 “添加密码卡片” 按钮,即可尽情享受 Clipperz 帐户.</p> <p> <a href=\"http://www.clipperz.com/support/user_guide/managing_cards\" target=\"_blank\">关于创建和管理密码卡片的更多信息</a> </p> ",
236 'newRecordWizardTitleBox':"<h5>请选择一个模板</h5> <p>密码卡片是简单灵活的方式,在这里你可以保存你的密码和其他机密资料.</p> <p>首先选择下面的一个模板。在添加或者删除以后,可以随时定制你的密码卡片.</p> ",
237 'newRecordWizardBookmarkletConfigurationTitle':"直接登陆",
238 'newRecordWizardBookmarkletConfigurationDescription':"<p>将从 Clipperz 书签按钮得到的代码粘贴到下面的文本框中</p> <p>一个直接登陆你的网络账户的新密码卡片将要被创建完成</p> ",
239 'newRecordWizardCreateButtonLabel':"创建",
240 'newRecordWizardCancelButtonLabel':"取消",
241 'donateSplashPanelTitle':"今天就捐赠支持 Clipperz!",
242 'donateSplashPanelDescription':"<p>捐赠我们的原因:</p> <ul> <li> <p>支持新特性的开发</p> </li> <li> <p>保持 Clipperz 的免费</p> </li> <li> <p>对我们的辛勤工作表示感谢</p> </li> </ul> <p> <a href=\"http://www.clipperz.com/donations\" target=\"_blank\">进一步资料,请浏览我们的捐款页</a>.</p> <p> <b>愿意捐款?</b> </p> ",
243 'donateCloseButtonLabel':"不必了",
244 'donateDonateButtonLabel':"是",
245 'recordTemplates':{
246 'WebAccount':{
247 'title':"网站密码",
248 'description':"<p>为您的网上服务提供简单的密码储存,自动登录服务.</p> ",
249 'fields':{
250 'URL':"网址",
251 'TXT':"用户名或者电子邮件地址",
252 'PWD':"密码"
253 }
254 },
255 'BankAccount':{
256 'title':"银行帐户",
257 'description':"<p>安全储存你的银行账号和网上银行证书.</p> ",
258 'fields':{
259 'TXT':"银行",
260 'TXT':"帐号",
261 'URL':"银行网站",
262 'TXT':"在线银行 ID",
263 'PWD':"在线银行密码"
264 }
265 },
266 'CreditCard':{
267 'title':"信用卡",
268 'description':"<p>信用卡号码,有效日期,CVV2和PIN 都由 Clipperz 管理</p> ",
269 'fields':{
270 'TXT':"类型(VISA, AmEx, ...)",
271 'TXT':"号码",
272 'TXT':"持卡人姓名",
273 'TXT':"有效日期",
274 'TXT':"CVV2",
275 'PWD':"PIN",
276 'URL':"信用卡网站",
277 'TXT':"用户名",
278 'PWD':"密码"
279 }
280 },
281 'AddressBookEntry':{
282 'title':"通讯录条目",
283 'description':"<p>Clipperz 同样可以为你的私人通讯录服务. 使用这个模板,轻易添加新的条目.</p> ",
284 'fields':{
285 'TXT':"姓名",
286 'TXT':"电子邮件",
287 'TXT':"电话",
288 'TXT':"手机",
289 'ADDR':"地址"
290 }
291 },
292 'Custom':{
293 'title':"定制密码卡片",
294 'description':"<p>无论你需要保护哪种类型的机密数据,创建定制密码卡片便可满足你的需求</p> ",
295 'fields':{
296 'TXT':"标签 1",
297 'TXT':"标签 2",
298 'TXT':"标签 3"
299 }
300 }
301},
302 'recordFieldTypologies':{
303 'TXT':{
304 'description':"simple text field",
305 'shortDescription':"文字"
306 },
307 'PWD':{
308 'description':"simple text field, with default status set to hidden",
309 'shortDescription':"密码"
310 },
311 'URL':{
312 'description':"simple text field in edit mode, that became an active url in view mode",
313 'shortDescription':"网址"
314 },
315 'DATE':{
316 'description':"a value set with a calendar helper",
317 'shortDescription':"数据"
318 },
319 'ADDR':{
320 'description':"just like the URL, but the active link points to Google Maps (or similar service) passing the address value as argument",
321 'shortDescription':"地址"
322 },
323 'CHECK':{
324 'description':"check description",
325 'shortDescription':"check"
326 },
327 'RADIO':{
328 'description':"radio description",
329 'shortDescription':"radio"
330 },
331 'SELECT':{
332 'description':"select description",
333 'shortDescription':"select"
334 }
335},
336 'newRecordPanelGeneralExceptionTitle':"错误",
337 'newRecordPanelGeneralExceptionMessage':"配置文本不正确,请从书签中确认你的文本并且再试一次",
338 'newRecordPanelWrongBookmarkletVersionExceptionTitle':"错误",
339 'newRecordPanelWrongBookmarkletVersionExceptionMessage':"配置文本已经产生了一个旧版本书签,请更新你的书签然后再试试。",
340 'newRecordPanelExceptionPanelCloseButtonLabel':"取消",
341 'mainPanelDeletingRecordPanelConfirmationTitle':"删除所选密码卡片",
342 'mainPanelDeleteRecordPanelConfirmationText':"确认要删除选定的密码卡片?",
343 'mainPanelDeleteRecordPanelConfirmButtonLabel':"是",
344 'mainPanelDeleteRecordPanelDenyButtonLabel':"否",
345 'mainPanelDeletingRecordPanelInitialTitle':"删除选定的密码卡片",
346 'mainPanelDeletingRecordPanelCompletedText':"完成",
347 'deleteRecordPanelCollectRecordDataMessageTitle':"删除密码卡片",
348 'deleteRecordPanelCollectRecordDataMessageText':"更新密码卡片列表",
349 'deleteRecordPanelEncryptUserDataMessageTitle':"删除密码卡片",
350 'deleteRecordPanelEncryptUserDataMessageText':"加密卡报头本地解密",
351 'deleteRecordPanelSendingDataToTheServerMessageTitle':"删除密码卡片",
352 'deleteRecordPanelSendingDataToTheServerMessageText':"从 Clipperz 更新加密卡报头",
353 'deleteRecordPanelUpdatingTheInterfaceMessageTitle':"删除密码卡片",
354 'deleteRecordPanelUpdatingTheInterfaceMessageText':"更新界面",
355 'recordDetailNoRecordSelectedTitle':"未选择密码卡片",
356 'recordDetailNoRecordSelectedDescription':"<p>从左边的列表中选择一个密码卡片</p> ",
357 'recordDetailLoadingRecordMessage':"正在从 Clipperz 下载加密卡片",
358 'recordDetailDecryptingRecordMessage':"密码卡片数据本地解密",
359 'recordDetailLoadingRecordVersionMessage':"下载最新版本的密码卡片",
360 'recordDetailDecryptingRecordVersionMessage':"本地解密最新版本密码卡片",
361 'recordDetailLoadingErrorMessageTitle':"密码卡片下载错误",
362 'recordDetailNotesLabel':"注释",
363 'recordDetailLabelFieldColumnLabel':"标签区域",
364 'recordDetailDataFieldColumnLabel':"数据区域",
365 'recordDetailTypeFieldColumnLabel':"类型",
366 'recordDetailSavingChangesMessagePanelInitialTitle':"保存密码卡片",
367 'recordDetailAddFieldButtonLabel':"添加新区域",
368 'recordDetailPasswordFieldHelpLabel':"点击星星复制密码到剪贴板,然后用 Ctrl+V 使用",
369 'recordDetailPasswordFieldScrambleLabel':"隐藏密码",
370 'recordDetailPasswordFieldUnscrambleLabel':"显示密码",
371 'recordDetailDirectLoginBlockTitle':"直接登录",
372 'recordDetailNewDirectLoginDescription':"<p>直接登录配置</p> ",
373 'recordDetailDirectLoginBlockNoDirectLoginConfiguredDescription':"<p>这个密码卡片包含在线服务证书吗?</p> <p>仅仅单击就可以从 Clipperz 使用书签配置 “直接登录”</p> ",
374 'recordDetailAddNewDirectLoginButtonLabel':"添加新的直接登录",
375 'recordDetailEditButtonLabel':"编辑",
376 'recordDetailSaveButtonLabel':"保存",
377 'recordDetailCancelButtonLabel':"取消",
378 'newRecordTitleLabel':"_新密码卡片_",
379 'recordSaveChangesPanelCollectRecordInfoMessageTitle':"保存密码卡片",
380 'recordSaveChangesPanelCollectRecordInfoMessageText':"更新密码卡片报头",
381 'recordSaveChangesPanelEncryptUserDataMessageTitle':"保存密码卡片",
382 'recordSaveChangesPanelEncryptUserDataMessageText':"本地加密卡片报头",
383 'recordSaveChangesPanelEncryptRecordDataMessageTitle':"保存密码卡片",
384 'recordSaveChangesPanelEncryptRecordDataMessageText':"本地加密卡片数据",
385 'recordSaveChangesPanelEncryptRecordVersionDataMessageTitle':"保存密码卡片",
386 'recordSaveChangesPanelEncryptRecordVersionDataMessageText':"本地加密密码卡片版本数据",
387 'recordSaveChangesPanelSendingDataToTheServerMessageTitle':"保存密码卡片",
388 'recordSaveChangesPanelSendingDataToTheServerMessageText':"从 Clipperz 更新加密卡报头",
389 'recordSaveChangesPanelUpdatingTheInterfaceMessageTitle':"保存密码卡片",
390 'recordSaveChangesPanelUpdatingTheInterfaceMessageText':"更新界面",
391 'passwordGeneratorPanelTitle':"密码生成器",
392 'passwordGeneratorPanelOkLabel':"确认",
393 'passwordGeneratorPanelCancelLabel':"取消",
394 'passwordGeneratorLengthLabel':"长度:",
395 //'DWRUtilLoadingMessage':"加载数据。。。",
396 'comingSoon':"即将到来。。。",
397 'panelCollectingEntryopyMessageText':"收集平均信息",
398 'directLoginConfigurationCheckBoxFieldSelectedValue':"是",
399 'directLoginConfigurationCheckBoxFieldNotSelectedValue':"否",
400 'WELCOME_BACK':"欢迎回来!",
401 'currentConnectionText':"你的连接 IP 地址是&nbsp;__ip__; 来自 __country__, 在 __browser__ 上使用 __operatingSystem__。",
402 'latestConnectionText':"你上次的登录 IP 是&nbsp;__ip__ 在 __elapsedTimeDescription__ (__time__); 来自 __country__, 在 __browser__ 上使用 __operatingSystem__。",
403 'fullLoginHistoryLinkLabel':"显示所有登录历史",
404 'elapsedTimeDescriptions':{
405 'MORE_THAN_A_MONTH_AGO':"一个月之前",
406 'MORE_THAN_A_WEEK_AGO':"一周之前",
407 'MORE_THAN_*_WEEKS_AGO':"__elapsed__ 周以前",
408 'YESTERDAY':"昨天",
409 '*_DAYS_AGO':"__elapsed__ 天之前",
410 'ABOUT_AN_HOUR_AGO':"大约一个小时前",
411 '*_HOURS_AGO':"__elapsed__ 小时前",
412 'JUST_A_FEW_MINUTES_AGO':"仅仅几分钟之前",
413 'ABOUT_*_MINUTES_AGO':"大约 __elapsed__ 几分钟前"
414},
415 'unknown_ip':"未知",
416 'calendarStrings':{
417 'months':{
418 '0':"一月",
419 '1':"二月",
420 '2':"三月",
421 '3':"四月",
422 '4':"五月",
423 '5':"六月",
424 '6':"七月",
425 '7':"八月",
426 '8':"九月",
427 '9':"十月",
428 '10':"十一月",
429 '11':"十二月"
430 },
431 'shortMonths':{
432 '0':"一月",
433 '1':"二月",
434 '2':"三月",
435 '3':"四月",
436 '4':"五月",
437 '5':"六月",
438 '6':"七月",
439 '7':"八月",
440 '8':"九月",
441 '9':"十月",
442 '10':"十一月",
443 '11':"十二月"
444 },
445 'days':{
446 '0':"星期日",
447 '1':"星期一",
448 '2':"星期二",
449 '3':"星期三",
450 '4':"星期四",
451 '5':"星期五",
452 '6':"星期六"
453 },
454 'shortDays':{
455 '0':"日",
456 '1':"一",
457 '2':"二",
458 '3':"三",
459 '4':"四",
460 '5':"五",
461 '6':"六"
462 },
463 'veryShortDays':{
464 '0':"日",
465 '1':"一",
466 '2':"二",
467 '3':"三",
468 '4':"四",
469 '5':"五",
470 '6':"六"
471 },
472 'amDesignation':"上午",
473 'pmDesignation':"下午"
474},
475
476__syntaxFix__: "syntax fix"
477});
diff --git a/frontend/beta/js/Clipperz/PM/Toll.js b/frontend/beta/js/Clipperz/PM/Toll.js
new file mode 100644
index 0000000..6d412c1
--- a/dev/null
+++ b/frontend/beta/js/Clipperz/PM/Toll.js
@@ -0,0 +1,193 @@
1/*
2
3Copyright 2008-2011 Clipperz Srl
4
5This file is part of Clipperz's Javascript Crypto Library.
6Javascript Crypto Library provides web developers with an extensive
7and efficient set of cryptographic functions. The library aims to
8obtain maximum execution speed while preserving modularity and
9reusability.
10For further information about its features and functionalities please
11refer to http://www.clipperz.com
12
13* Javascript Crypto Library is free software: you can redistribute
14 it and/or modify it under the terms of the GNU Affero General Public
15 License as published by the Free Software Foundation, either version
16 3 of the License, or (at your option) any later version.
17
18* Javascript Crypto Library is distributed in the hope that it will
19 be useful, but WITHOUT ANY WARRANTY; without even the implied
20 warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
21 See the GNU Affero General Public License for more details.
22
23* You should have received a copy of the GNU Affero General Public
24 License along with Javascript Crypto Library. If not, see
25 <http://www.gnu.org/licenses/>.
26
27*/
28
29if (typeof(Clipperz) == 'undefined') { Clipperz = {}; }
30if (typeof(Clipperz.PM) == 'undefined') { Clipperz.PM = {}; }
31
32//=============================================================================
33
34Clipperz.PM.Toll = function(args) {
35 this._requestType = args.requestType;
36 this._targetValue = args.targetValue;
37 this._cost = args.cost;
38 this._toll = null;
39
40 return this;
41}
42
43Clipperz.PM.Toll.prototype = MochiKit.Base.update(null, {
44
45 'toString': function() {
46 return "Clipperz.PM.Toll (" + this.requestType() + ": " + this.cost() + " - " + ((this.toll() == null)? 'UNPAID' : 'PAID') + ")";
47 },
48
49 //-------------------------------------------------------------------------
50
51 'requestType': function() {
52 return this._requestType;
53 },
54
55 //-------------------------------------------------------------------------
56
57 'targetValue': function() {
58 return this._targetValue;
59 },
60
61 //-------------------------------------------------------------------------
62
63 'cost': function() {
64 return this._cost;
65 },
66
67 //-------------------------------------------------------------------------
68
69 'toll': function() {
70 return this._toll;
71 },
72
73 //=========================================================================
74
75 'prefixMatchingBits': function(aValue1, aValue2) {
76 varresult;
77 var i,c;
78
79 result = 0;
80
81 c = Math.min(aValue1.length(), aValue2.length());
82 i = 0;
83 while (i<c && (aValue1.byteAtIndex(i) == aValue2.byteAtIndex(i))) {
84 result += 8;
85 i++;
86 }
87
88 if (i<c) {
89 varxorValue;
90
91 xorValue = (aValue1.byteAtIndex(i) ^ aValue2.byteAtIndex(i));
92
93 if (xorValue >= 128) {
94 result += 0;
95 } else if (xorValue >= 64) {
96 result += 1;
97 } else if (xorValue >= 32) {
98 result += 2;
99 } else if (xorValue >= 16) {
100 result += 3;
101 } else if (xorValue >= 8) {
102 result += 4;
103 } else if (xorValue >= 4) {
104 result += 5;
105 } else if (xorValue >= 2) {
106 result += 6;
107 } else if (xorValue >= 1) {
108 result += 7;
109 }
110 }
111
112 return result;
113 },
114
115 //=========================================================================
116
117 'pay': function() {
118 varresult;
119 vartargetData;
120 vartargetMatchSize;
121 var prefixMatchingBits;
122 varpayment;
123 var i;
124
125//MochiKit.Logging.logDebug(">>> Toll.pay");
126 if (this.toll() == null) {
127 i = 0;
128//MochiKit.Logging.logDebug("--- Proxy.payToll - 1");
129 targetData = new Clipperz.ByteArray("0x" + this.targetValue());
130//MochiKit.Logging.logDebug("--- Proxy.payToll - 2");
131 targetMatchSize = this.cost();
132//MochiKit.Logging.logDebug("--- Proxy.payToll - 3");
133
134 payment = Clipperz.Crypto.PRNG.defaultRandomGenerator().getRandomBytes(32);
135//MochiKit.Logging.logDebug("--- Proxy.payToll - 4");
136
137 do {
138 varpaymentData;
139
140//MochiKit.Logging.logDebug("--- Proxy.payToll - 5");
141 //payment = Clipperz.Crypto.PRNG.defaultRandomGenerator().getRandomBytes(32);
142 payment.increment();
143//MochiKit.Logging.logDebug("--- Proxy.payToll - 6");
144 paymentData = Clipperz.Crypto.SHA.sha256(payment);
145//MochiKit.Logging.logDebug("--- Proxy.payToll - 7");
146 prefixMatchingBits = this.prefixMatchingBits(targetData, paymentData);
147//MochiKit.Logging.logDebug("--- Proxy.payToll - 8");
148 i++;
149//MochiKit.Logging.logDebug("--- Proxy.payToll - 9");
150 } while (prefixMatchingBits < targetMatchSize);
151//MochiKit.Logging.logDebug("--- Proxy.payToll - 10");
152
153 this._toll = payment.toHexString().substring(2)
154 }
155//MochiKit.Logging.logDebug("<<< Toll.pay");
156
157 return this;
158 },
159
160 //-------------------------------------------------------------------------
161
162 'deferredPay': function() {
163 vardeferredResult;
164 vartoll;
165
166//MochiKit.Logging.logDebug(">>> Toll.deferredPay");
167 toll = this;
168 deferredResult = new MochiKit.Async.Deferred();
169//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("y.1 - Proxy.deferredPayToll - 1: " + res); return res;});
170 deferredResult.addCallback(MochiKit.Base.method(toll, 'pay'));
171//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("y.2 - Proxy.deferredPayToll - 2: " + res); return res;});
172 deferredResult.addCallback(function(aToll) {
173 var result;
174
175 result = {
176 targetValue:aToll.targetValue(),
177 toll:aToll.toll()
178 };
179
180 return result;
181 });
182//deferredResult.addBoth(function(res) {MochiKit.Logging.logDebug("y.3 - Proxy.deferredPayToll - 3: " + res); return res;});
183 deferredResult.callback();
184//MochiKit.Logging.logDebug("<<< Toll.deferredPay");
185
186 return deferredResult;
187 },
188
189 //=========================================================================
190 __syntaxFix__: "syntax fix"
191
192});
193
diff --git a/frontend/beta/js/Clipperz/Profile.js b/frontend/beta/js/Clipperz/Profile.js
new file mode 100644
index 0000000..31888a9
--- a/dev/null
+++ b/frontend/beta/js/Clipperz/Profile.js
@@ -0,0 +1,485 @@
1/*
2
3Copyright 2008-2011 Clipperz Srl
4
5This file is part of Clipperz's Javascript Crypto Library.
6Javascript Crypto Library provides web developers with an extensive
7and efficient set of cryptographic functions. The library aims to
8obtain maximum execution speed while preserving modularity and
9reusability.
10For further information about its features and functionalities please
11refer to http://www.clipperz.com
12
13* Javascript Crypto Library is free software: you can redistribute
14 it and/or modify it under the terms of the GNU Affero General Public
15 License as published by the Free Software Foundation, either version
16 3 of the License, or (at your option) any later version.
17
18* Javascript Crypto Library is distributed in the hope that it will
19 be useful, but WITHOUT ANY WARRANTY; without even the implied
20 warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
21 See the GNU Affero General Public License for more details.
22
23* You should have received a copy of the GNU Affero General Public
24 License along with Javascript Crypto Library. If not, see
25 <http://www.gnu.org/licenses/>.
26
27*/
28
29addEvent(window, "load", sortables_init);
30
31var SORT_COLUMN_INDEX;
32
33function sortables_init() {
34 // Find all tables with class sortable and make them sortable
35 if (!document.getElementsByTagName) return;
36 tbls = document.getElementsByTagName("table");
37 for (ti=0;ti<tbls.length;ti++) {
38 thisTbl = tbls[ti];
39 if (((' '+thisTbl.className+' ').indexOf("sortable") != -1) && (thisTbl.id)) {
40 //initTable(thisTbl.id);
41 ts_makeSortable(thisTbl);
42 }
43 }
44}
45
46function ts_makeSortable(table) {
47 if (table.rows && table.rows.length > 0) {
48 var firstRow = table.rows[0];
49 }
50 if (!firstRow) return;
51
52 // We have a first row: assume it's the header, and make its contents clickable links
53 for (var i=0;i<firstRow.cells.length;i++) {
54 var cell = firstRow.cells[i];
55 var txt = ts_getInnerText(cell);
56 cell.innerHTML = '<a href="#" class="sortheader" '+
57 'onclick="ts_resortTable(this, '+i+');return false;">' +
58 txt+'<span class="sortarrow">&nbsp;&nbsp;&nbsp;</span></a>';
59 }
60}
61
62function ts_getInnerText(el) {
63 if (typeof el == "string") return el;
64 if (typeof el == "undefined") { return el };
65 if (el.innerText) return el.innerText;//Not needed but it is faster
66 var str = "";
67
68 var cs = el.childNodes;
69 var l = cs.length;
70 for (var i = 0; i < l; i++) {
71 switch (cs[i].nodeType) {
72 case 1: //ELEMENT_NODE
73 str += ts_getInnerText(cs[i]);
74 break;
75 case 3://TEXT_NODE
76 str += cs[i].nodeValue;
77 break;
78 }
79 }
80 return str;
81}
82
83function ts_resortTable(lnk,clid) {
84 // get the span
85 var span;
86 for (var ci=0;ci<lnk.childNodes.length;ci++) {
87 if (lnk.childNodes[ci].tagName && lnk.childNodes[ci].tagName.toLowerCase() == 'span') span = lnk.childNodes[ci];
88 }
89 var spantext = ts_getInnerText(span);
90 var td = lnk.parentNode;
91 var column = clid || td.cellIndex;
92 var table = getParent(td,'TABLE');
93
94 // Work out a type for the column
95 if (table.rows.length <= 1) return;
96 var itm = ts_getInnerText(table.rows[1].cells[column]);
97 sortfn = ts_sort_caseinsensitive;
98 if (itm.match(/^\d\d[\/-]\d\d[\/-]\d\d\d\d$/)) {
99 sortfn = ts_sort_date;
100 }
101 if (itm.match(/^\d\d[\/-]\d\d[\/-]\d\d$/)) {
102 sortfn = ts_sort_date;
103 }
104 if (itm.match(/^[£$]/)) {
105 sortfn = ts_sort_currency;
106 }
107 if (itm.match(/^[\d\.]+$/)) {
108 sortfn = ts_sort_numeric;
109 }
110 SORT_COLUMN_INDEX = column;
111 var firstRow = new Array();
112 var newRows = new Array();
113 for (i=0;i<table.rows[0].length;i++) {
114 firstRow[i] = table.rows[0][i];
115 }
116
117 for (j=1;j<table.rows.length;j++) {
118 newRows[j-1] = table.rows[j];
119 }
120 newRows.sort(sortfn);
121
122 if (span.getAttribute("sortdir") == 'down') {
123 ARROW = '&nbsp;&nbsp;&uarr;';
124 newRows.reverse();
125 span.setAttribute('sortdir','up');
126 } else {
127 ARROW = '&nbsp;&nbsp;&darr;';
128 span.setAttribute('sortdir','down');
129 }
130
131 // We appendChild rows that already exist to the tbody, so it moves them rather than creating new ones
132 // don't do sortbottom rows
133 for (i=0;i<newRows.length;i++) {
134 if (!newRows[i].className || (newRows[i].className && (newRows[i].className.indexOf('sortbottom') == -1))) {
135 table.tBodies[0].appendChild(newRows[i]);
136 }
137 }
138 // do sortbottom rows only
139 for (i=0;i<newRows.length;i++) {
140 if (newRows[i].className && (newRows[i].className.indexOf('sortbottom') != -1)) {
141 table.tBodies[0].appendChild(newRows[i]);
142 }
143 }
144
145 // Delete any other arrows there may be showing
146 var allspans = document.getElementsByTagName("span");
147 for (var ci=0;ci<allspans.length;ci++) {
148 if (allspans[ci].className == 'sortarrow') {
149 if (getParent(allspans[ci],"table") == getParent(lnk,"table")) { // in the same table as us?
150 allspans[ci].innerHTML = '&nbsp;&nbsp;&nbsp;';
151 }
152 }
153 }
154
155 span.innerHTML = ARROW;
156}
157
158function getParent(el, pTagName) {
159 if (el == null) return null;
160 else if (el.nodeType == 1 && el.tagName.toLowerCase() == pTagName.toLowerCase())// Gecko bug, supposed to be uppercase
161 return el;
162 else
163 return getParent(el.parentNode, pTagName);
164}
165function ts_sort_date(a,b) {
166 // y2k notes: two digit years less than 50 are treated as 20XX, greater than 50 are treated as 19XX
167 aa = ts_getInnerText(a.cells[SORT_COLUMN_INDEX]);
168 bb = ts_getInnerText(b.cells[SORT_COLUMN_INDEX]);
169 if (aa.length == 10) {
170 dt1 = aa.substr(6,4)+aa.substr(3,2)+aa.substr(0,2);
171 } else {
172 yr = aa.substr(6,2);
173 if (parseInt(yr) < 50) { yr = '20'+yr; } else { yr = '19'+yr; }
174 dt1 = yr+aa.substr(3,2)+aa.substr(0,2);
175 }
176 if (bb.length == 10) {
177 dt2 = bb.substr(6,4)+bb.substr(3,2)+bb.substr(0,2);
178 } else {
179 yr = bb.substr(6,2);
180 if (parseInt(yr) < 50) { yr = '20'+yr; } else { yr = '19'+yr; }
181 dt2 = yr+bb.substr(3,2)+bb.substr(0,2);
182 }
183 if (dt1==dt2) return 0;
184 if (dt1<dt2) return -1;
185 return 1;
186}
187
188function ts_sort_currency(a,b) {
189 aa = ts_getInnerText(a.cells[SORT_COLUMN_INDEX]).replace(/[^0-9.]/g,'');
190 bb = ts_getInnerText(b.cells[SORT_COLUMN_INDEX]).replace(/[^0-9.]/g,'');
191 return parseFloat(aa) - parseFloat(bb);
192}
193
194function ts_sort_numeric(a,b) {
195 aa = parseFloat(ts_getInnerText(a.cells[SORT_COLUMN_INDEX]));
196 if (isNaN(aa)) aa = 0;
197 bb = parseFloat(ts_getInnerText(b.cells[SORT_COLUMN_INDEX]));
198 if (isNaN(bb)) bb = 0;
199 return aa-bb;
200}
201
202function ts_sort_caseinsensitive(a,b) {
203 aa = ts_getInnerText(a.cells[SORT_COLUMN_INDEX]).toLowerCase();
204 bb = ts_getInnerText(b.cells[SORT_COLUMN_INDEX]).toLowerCase();
205 if (aa==bb) return 0;
206 if (aa<bb) return -1;
207 return 1;
208}
209
210function ts_sort_default(a,b) {
211 aa = ts_getInnerText(a.cells[SORT_COLUMN_INDEX]);
212 bb = ts_getInnerText(b.cells[SORT_COLUMN_INDEX]);
213 if (aa==bb) return 0;
214 if (aa<bb) return -1;
215 return 1;
216}
217
218
219function addEvent(elm, evType, fn, useCapture)
220// addEvent and removeEvent
221// cross-browser event handling for IE5+, NS6 and Mozilla
222// By Scott Andrew
223{
224 if (elm.addEventListener){
225 elm.addEventListener(evType, fn, useCapture);
226 return true;
227 } else if (elm.attachEvent){
228 var r = elm.attachEvent("on"+evType, fn);
229 return r;
230 } else {
231 alert("Handler could not be removed");
232 }
233}
234
235
236
237
238if (typeof(Clipperz) == 'undefined') { Clipperz = {}; }
239if (typeof(Clipperz.Profile) == 'undefined') { Clipperz.Profile = {}; }
240
241Clipperz.Profile.VERSION = "0.1";
242Clipperz.Profile.NAME = "Clipperz.Profile";
243
244MochiKit.Base.update(Clipperz.Profile, {
245
246 //-------------------------------------------------------------------------
247
248 '__repr__': function () {
249 varstatus;
250
251 if (Clipperz.Profile.isEnabled == true) {
252 status = ENABLED;
253 } else {
254 status = DISABLED;
255 }
256
257 return "[" + this.NAME + " " + this.VERSION + " - " + status + "]";
258 },
259
260 //-------------------------------------------------------------------------
261
262 'toString': function () {
263 return this.__repr__();
264 },
265
266 //-------------------------------------------------------------------------
267
268 'isEnabled': function() {
269 return false;
270 },
271
272 //-------------------------------------------------------------------------
273
274 'initialValues': function() {
275 return {iters:0, total:0, min:Number.MAX_VALUE, max:0}
276 },
277
278 //-------------------------------------------------------------------------
279
280 'start': function(aName) {},
281 'stop': function(aName) {},
282 'dump': function(aName) {},
283 'profileData': function(aName, aKey) {
284 varresult;
285
286 if (typeof(aName) != 'undefined') {
287 result = this.initialValues();
288
289 if (typeof(aKey) != 'undefined') {
290 result = result[aKey];
291 }
292 } else {
293 result = null;
294 }
295
296 return result;
297
298 },
299 'resetProfileData': function() {},
300 //-------------------------------------------------------------------------
301
302 'end': function(aName) {
303 Clipperz.Profile.stop(aName);
304 },
305
306 //-------------------------------------------------------------------------
307
308 __syntaxFix__: "syntax fix"
309});
310
311
312
313if ((typeof(clipperz_profiling_enabled) != 'undefined') && (clipperz_profiling_enabled == true)) {
314
315var _clipperz_profile_profiles = {};
316var _clipperz_profile_pns = [];
317
318
319MochiKit.Base.update(Clipperz.Profile, {
320
321 //-------------------------------------------------------------------------
322
323 'isEnabled': function() {
324 return true;
325 },
326
327 //-------------------------------------------------------------------------
328
329 'start': function(aName) {
330 if (!_clipperz_profile_profiles[aName]) {
331 _clipperz_profile_profiles[aName] = this.initialValues();
332 _clipperz_profile_pns[_clipperz_profile_pns.length] = aName;
333 } else {
334 if (_clipperz_profile_profiles[aName]["start"]) {
335 Clipperz.Profile.stop(aName);
336 }
337 }
338
339 _clipperz_profile_profiles[aName].end = null;
340 _clipperz_profile_profiles[aName].start = new Date();
341 },
342
343 //-------------------------------------------------------------------------
344
345 'stop': function(aName) {
346 if ((_clipperz_profile_profiles[aName]) && (_clipperz_profile_profiles[aName]["start"])) {
347 with(_clipperz_profile_profiles[aName]) {
348 var now;
349 varelapsedTime;
350
351 now = new Date();
352 elapsedTime = (now - start);
353
354 end = now;
355 min = Math.min(min, elapsedTime);
356 max = Math.max(max, elapsedTime);
357 total += elapsedTime;
358 start = null;
359 iters++;
360 }
361 } else {
362 // oops! bad call to end(), what should we do here?
363 return true;
364 }
365 },
366
367 //-------------------------------------------------------------------------
368
369 'dump': function(appendToDoc) {
370 // var tbl = document.createElement("table");
371 var tbl = MochiKit.DOM.TABLE(null, MochiKit.DOM.TBODY());
372 tbl.className = 'sortable';
373 tbl.id = "profileOutputTable_table";
374 with(tbl.style){
375 border = "1px solid black";
376 borderCollapse = "collapse";
377 }
378 var hdr = tbl.createTHead();
379 var hdrtr = hdr.insertRow(0);
380 // document.createElement("tr");
381 var cols = ["Identifier","#","Min", "Avg","Max","Total"];
382 for(var x=0; x<cols.length; x++){
383 var ntd = hdrtr.insertCell(x);
384 with(ntd.style){
385 backgroundColor = "#225d94";
386 color = "white";
387 borderBottom = "1px solid black";
388 borderRight = "1px solid black";
389 fontFamily = "tahoma";
390 fontWeight = "bolder";
391 paddingLeft = paddingRight = "5px";
392 }
393 ntd.appendChild(document.createTextNode(cols[x]));
394 }
395
396 for(var x=0; x < _clipperz_profile_pns.length; x++){
397 var prf = _clipperz_profile_profiles[_clipperz_profile_pns[x]];
398 this.end(_clipperz_profile_pns[x]);
399 if(prf.iters>0){
400 var bdytr = tbl.insertRow(true);
401 var vals = [_clipperz_profile_pns[x], prf.iters, prf.min, parseInt(Math.round(prf.total/prf.iters)), prf.max, prf.total];
402 for(var y=0; y<vals.length; y++){
403 var cc = bdytr.insertCell(y);
404 cc.appendChild(document.createTextNode(vals[y]));
405 with(cc.style){
406 borderBottom = "1px solid gray";
407 paddingLeft = paddingRight = "5px";
408 if(x%2){
409 backgroundColor = "#e1f1ff";
410 }
411 if(y>0){
412 textAlign = "right";
413 borderRight = "1px solid gray";
414 }else{
415 borderRight = "1px solid black";
416 }
417 }
418 }
419 }
420 }
421
422 if(appendToDoc){
423 var ne = document.createElement("div");
424 ne.id = "profileOutputTable";
425 with(ne.style){
426 fontFamily = "Courier New, monospace";
427 fontSize = "12px";
428 lineHeight = "16px";
429 borderTop = "1px solid black";
430 padding = "10px";
431 }
432 if(document.getElementById("profileOutputTable")){
433 MochiKit.DOM.swapDOM("profileOutputTable", ne);
434 }else{
435 document.body.appendChild(ne);
436 }
437 ne.appendChild(tbl);
438 }
439
440 return tbl;
441 },
442
443 //-------------------------------------------------------------------------
444
445 'profileData': function(aName, aKey) {
446 varresult;
447
448 if (typeof(aName) == 'undefined') {
449 result = _clipperz_profile_profiles;
450 } else {
451 if (typeof(_clipperz_profile_profiles[aName]) != 'undefined') {
452 result = _clipperz_profile_profiles[aName];
453 } else {
454 result = {};
455 }
456 }
457
458 if (typeof(aKey) != 'undefined') {
459 if (aKey == "average") {
460 result = Math.round(Clipperz.Profile.profileData(aName, 'total')/Clipperz.Profile.profileData(aName, 'iters'));
461 } else {
462 if (typeof(result[aKey]) != 'undefined') {
463 result = result[aKey];
464 } else {
465 result = 0;
466 }
467 }
468 }
469
470 return result;
471 },
472
473 //-------------------------------------------------------------------------
474
475 'resetProfileData': function() {
476 _clipperz_profile_profiles = {};
477 _clipperz_profile_pns = [];
478 },
479
480 //-------------------------------------------------------------------------
481
482 __syntaxFix__: "syntax fix"
483});
484
485}
diff --git a/frontend/beta/js/Clipperz/Set.js b/frontend/beta/js/Clipperz/Set.js
new file mode 100644
index 0000000..61e0769
--- a/dev/null
+++ b/frontend/beta/js/Clipperz/Set.js
@@ -0,0 +1,167 @@
1/*
2
3Copyright 2008-2011 Clipperz Srl
4
5This file is part of Clipperz's Javascript Crypto Library.
6Javascript Crypto Library provides web developers with an extensive
7and efficient set of cryptographic functions. The library aims to
8obtain maximum execution speed while preserving modularity and
9reusability.
10For further information about its features and functionalities please
11refer to http://www.clipperz.com
12
13* Javascript Crypto Library is free software: you can redistribute
14 it and/or modify it under the terms of the GNU Affero General Public
15 License as published by the Free Software Foundation, either version
16 3 of the License, or (at your option) any later version.
17
18* Javascript Crypto Library is distributed in the hope that it will
19 be useful, but WITHOUT ANY WARRANTY; without even the implied
20 warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
21 See the GNU Affero General Public License for more details.
22
23* You should have received a copy of the GNU Affero General Public
24 License along with Javascript Crypto Library. If not, see
25 <http://www.gnu.org/licenses/>.
26
27*/
28
29
30if (typeof(Clipperz) == 'undefined') {
31 Clipperz = {};
32}
33
34//#############################################################################
35
36Clipperz.Set = function(args) {
37 args = args || {};
38 //MochiKit.Base.bindMethods(this);
39
40 if (args.items != null) {
41 this._items = args.items.slice();
42 } else {
43 this._items = [];
44 }
45
46 return this;
47}
48
49//=============================================================================
50
51Clipperz.Set.prototype = MochiKit.Base.update(null, {
52
53 //-------------------------------------------------------------------------
54
55 'toString': function() {
56 return "Clipperz.Set";
57 },
58
59 //-------------------------------------------------------------------------
60
61 'items': function() {
62 return this._items;
63 },
64
65 //-------------------------------------------------------------------------
66
67 'popAnItem': function() {
68 var result;
69
70 if (this.size() > 0) {
71 result = this.items().pop();
72 } else {
73 result = null;
74 }
75
76 return result;
77 },
78
79 //-------------------------------------------------------------------------
80
81 'allItems': function() {
82 return this.items();
83 },
84
85 //-------------------------------------------------------------------------
86
87 'contains': function(anItem) {
88 return (this.indexOf(anItem) != -1);
89 },
90
91 //-------------------------------------------------------------------------
92
93 'indexOf': function(anItem) {
94 varresult;
95 vari, c;
96
97 result = -1;
98
99 c = this.items().length;
100 for (i=0; (i<c) && (result == -1); i++) {
101 if (this.items()[i] === anItem) {
102 result = i;
103 }
104 }
105
106 return result;
107 },
108
109 //-------------------------------------------------------------------------
110
111 'add': function(anItem) {
112 if (anItem.constructor == Array) {
113 MochiKit.Base.map(MochiKit.Base.bind(this,add, this), anItem);
114 } else {
115 if (! this.contains(anItem)) {
116 this.items().push(anItem);
117 }
118 }
119 },
120
121 //-------------------------------------------------------------------------
122
123 'debug': function() {
124 vari, c;
125
126 result = -1;
127
128 c = this.items().length;
129 for (i=0; i<c; i++) {
130 alert("[" + i + "] " + this.items()[i].label);
131 }
132 },
133
134 //-------------------------------------------------------------------------
135
136 'remove': function(anItem) {
137 if (anItem.constructor == Array) {
138 MochiKit.Base.map(MochiKit.Base.bind(this.remove, this), anItem);
139 } else {
140 varitemIndex;
141
142 itemIndex = this.indexOf(anItem);
143 if (itemIndex != -1) {
144 this.items().splice(itemIndex, 1);
145 }
146 }
147 },
148
149 //-------------------------------------------------------------------------
150
151 'size': function() {
152 return this.items().length;
153 },
154
155 //-------------------------------------------------------------------------
156
157 'empty': function() {
158 this.items().splice(0, this.items().length);
159 },
160
161 //-------------------------------------------------------------------------
162
163 __syntaxFix__: "syntax fix"
164
165 //-------------------------------------------------------------------------
166});
167
diff --git a/frontend/beta/js/Clipperz/Signal.js b/frontend/beta/js/Clipperz/Signal.js
new file mode 100644
index 0000000..1d3c9eb
--- a/dev/null
+++ b/frontend/beta/js/Clipperz/Signal.js
@@ -0,0 +1,71 @@
1/*
2
3Copyright 2008-2011 Clipperz Srl
4
5This file is part of Clipperz's Javascript Crypto Library.
6Javascript Crypto Library provides web developers with an extensive
7and efficient set of cryptographic functions. The library aims to
8obtain maximum execution speed while preserving modularity and
9reusability.
10For further information about its features and functionalities please
11refer to http://www.clipperz.com
12
13* Javascript Crypto Library is free software: you can redistribute
14 it and/or modify it under the terms of the GNU Affero General Public
15 License as published by the Free Software Foundation, either version
16 3 of the License, or (at your option) any later version.
17
18* Javascript Crypto Library is distributed in the hope that it will
19 be useful, but WITHOUT ANY WARRANTY; without even the implied
20 warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
21 See the GNU Affero General Public License for more details.
22
23* You should have received a copy of the GNU Affero General Public
24 License along with Javascript Crypto Library. If not, see
25 <http://www.gnu.org/licenses/>.
26
27*/
28
29if (typeof(Clipperz) == 'undefined') { Clipperz = {}; }
30if (typeof(Clipperz.Signal) == 'undefined') { Clipperz.Signal = {}; }
31
32Clipperz.Signal.VERSION = "0.1";
33Clipperz.Signal.NAME = "Clipperz.Signal";
34
35MochiKit.Base.update(Clipperz.Signal, {
36
37 //-------------------------------------------------------------------------
38
39 '__repr__': function () {
40 return "[" + this.NAME + " " + this.VERSION + "]";
41 },
42
43 //-------------------------------------------------------------------------
44
45 'toString': function () {
46 return this.__repr__();
47 },
48
49 //-------------------------------------------------------------------------
50
51 'fireNativeEvent': function(element, eventName) {
52 if (element.fireEvent) {
53 // MSIE
54 element.fireEvent(eventName);
55 } else {
56 // W3C
57 var event;
58
59 event = document.createEvent("HTMLEvents");
60 event.initEvent(eventName.replace(/^on/, ""), true, true);
61 element.dispatchEvent(event);
62 }
63 },
64
65 //-------------------------------------------------------------------------
66 __syntaxFix__: "syntax fix"
67
68});
69
70
71
diff --git a/frontend/beta/js/Clipperz/Style.js b/frontend/beta/js/Clipperz/Style.js
new file mode 100644
index 0000000..9762b1c
--- a/dev/null
+++ b/frontend/beta/js/Clipperz/Style.js
@@ -0,0 +1,73 @@
1/*
2
3Copyright 2008-2011 Clipperz Srl
4
5This file is part of Clipperz's Javascript Crypto Library.
6Javascript Crypto Library provides web developers with an extensive
7and efficient set of cryptographic functions. The library aims to
8obtain maximum execution speed while preserving modularity and
9reusability.
10For further information about its features and functionalities please
11refer to http://www.clipperz.com
12
13* Javascript Crypto Library is free software: you can redistribute
14 it and/or modify it under the terms of the GNU Affero General Public
15 License as published by the Free Software Foundation, either version
16 3 of the License, or (at your option) any later version.
17
18* Javascript Crypto Library is distributed in the hope that it will
19 be useful, but WITHOUT ANY WARRANTY; without even the implied
20 warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
21 See the GNU Affero General Public License for more details.
22
23* You should have received a copy of the GNU Affero General Public
24 License along with Javascript Crypto Library. If not, see
25 <http://www.gnu.org/licenses/>.
26
27*/
28
29if (typeof(Clipperz) == 'undefined') { Clipperz = {}; }
30if (typeof(Clipperz.Style) == 'undefined') { Clipperz.Style = {}; }
31
32Clipperz.Style.VERSION = "0.1";
33Clipperz.Style.NAME = "Clipperz.DOM";
34
35MochiKit.Base.update(Clipperz.Style, {
36
37 //-------------------------------------------------------------------------
38
39 '__repr__': function () {
40 return "[" + this.NAME + " " + this.VERSION + "]";
41 },
42
43 //-------------------------------------------------------------------------
44
45 'toString': function () {
46 return this.__repr__();
47 },
48
49 //-------------------------------------------------------------------------
50
51 'applyZebraStylesToTable': function(aTable) {
52 var tbody;
53 var tbodyRows;
54 var i,c;
55
56 tbody = MochiKit.DOM.getFirstElementByTagAndClassName('tbody', null, aTable);
57 tbodyRows = tbody.childNodes;
58 // tbodyRows = MochiKit.DOM.getElementsByTagAndClassName('tr', null, tbody)
59 c = tbodyRows.length;
60 for (i=0; i<c; i++) {
61 var element;
62
63 element = YAHOO.ext.Element.get(tbodyRows[i]);
64 element.addClass(((i%2 == 0) ? "zebra_odd": "zebra_even"));
65 element.removeClass(((i%2 == 1) ? "zebra_odd": "zebra_even"));
66 }
67 },
68
69 //-------------------------------------------------------------------------
70 __syntaxFix__: "syntax fix"
71
72});
73
diff --git a/frontend/beta/js/Clipperz/YUI/Collapser.js b/frontend/beta/js/Clipperz/YUI/Collapser.js
new file mode 100644
index 0000000..5c0ac0f
--- a/dev/null
+++ b/frontend/beta/js/Clipperz/YUI/Collapser.js
@@ -0,0 +1,73 @@
1/*
2
3Copyright 2008-2011 Clipperz Srl
4
5This file is part of Clipperz's Javascript Crypto Library.
6Javascript Crypto Library provides web developers with an extensive
7and efficient set of cryptographic functions. The library aims to
8obtain maximum execution speed while preserving modularity and
9reusability.
10For further information about its features and functionalities please
11refer to http://www.clipperz.com
12
13* Javascript Crypto Library is free software: you can redistribute
14 it and/or modify it under the terms of the GNU Affero General Public
15 License as published by the Free Software Foundation, either version
16 3 of the License, or (at your option) any later version.
17
18* Javascript Crypto Library is distributed in the hope that it will
19 be useful, but WITHOUT ANY WARRANTY; without even the implied
20 warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
21 See the GNU Affero General Public License for more details.
22
23* You should have received a copy of the GNU Affero General Public
24 License along with Javascript Crypto Library. If not, see
25 <http://www.gnu.org/licenses/>.
26
27*/
28
29if (typeof(Clipperz) == 'undefined') { Clipperz = {}; }
30if (typeof(Clipperz.YUI) == 'undefined') { Clipperz.YUI = {}; }
31
32 //found on YUI-EXT forum (http://www.yui-ext.com/forum/viewtopic.php?t=683&highlight=accordion)
33Clipperz.YUI.Collapser = function(clickEl, collapseEl, initiallyCollapsed) {
34 this.clickEl = getEl(clickEl);
35 this.collapseEl = getEl(collapseEl);
36 this.clickEl.addClass('collapser-expanded');
37 if (initiallyCollapsed == true) {
38 this.afterCollapse();
39 }
40 this.clickEl.mon('click', function(){
41 this.collapsed === true ? this.expand() : this.collapse();
42 }, this, true);
43};
44
45Clipperz.YUI.Collapser.prototype = {
46 'collapse': function(){
47 this.collapseEl.clip();
48 this.collapseEl.setHeight(1, true, .35, this.afterCollapse.createDelegate(this), YAHOO.util.Easing.easeOut);
49 this.clickEl.replaceClass('collapser-expanded','collapser-collapsed');
50 },
51
52 'afterCollapse': function(){
53 this.collapsed = true;
54 this.collapseEl.setDisplayed(false);
55 this.clickEl.replaceClass('collapser-expanded','collapser-collapsed');
56 },
57
58 'expand': function(){
59 this.collapseEl.setDisplayed(true);
60 this.collapseEl.autoHeight(true, .35, this.afterExpand.createDelegate(this), YAHOO.util.Easing.easeOut);
61 this.clickEl.replaceClass('collapser-collapsed','collapser-expanded');
62 },
63
64 'afterExpand': function(){
65 this.collapsed = false;
66 this.collapseEl.unclip();
67 this.collapseEl.setStyle('height', '');
68 this.clickEl.replaceClass('collapser-collapsed','collapser-expanded');
69 },
70
71 //-----------------------------------------------------
72 __syntaxFix__: '__syntaxFix__'
73};
diff --git a/frontend/beta/js/Clipperz/YUI/DomHelper.js b/frontend/beta/js/Clipperz/YUI/DomHelper.js
new file mode 100644
index 0000000..4f8acde
--- a/dev/null
+++ b/frontend/beta/js/Clipperz/YUI/DomHelper.js
@@ -0,0 +1,465 @@
1/*
2
3Copyright 2008-2011 Clipperz Srl
4
5This file is part of Clipperz's Javascript Crypto Library.
6Javascript Crypto Library provides web developers with an extensive
7and efficient set of cryptographic functions. The library aims to
8obtain maximum execution speed while preserving modularity and
9reusability.
10For further information about its features and functionalities please
11refer to http://www.clipperz.com
12
13* Javascript Crypto Library is free software: you can redistribute
14 it and/or modify it under the terms of the GNU Affero General Public
15 License as published by the Free Software Foundation, either version
16 3 of the License, or (at your option) any later version.
17
18* Javascript Crypto Library is distributed in the hope that it will
19 be useful, but WITHOUT ANY WARRANTY; without even the implied
20 warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
21 See the GNU Affero General Public License for more details.
22
23* You should have received a copy of the GNU Affero General Public
24 License along with Javascript Crypto Library. If not, see
25 <http://www.gnu.org/licenses/>.
26
27*/
28
29if (typeof(Clipperz) == 'undefined') { Clipperz = {}; }
30if (typeof(Clipperz.ext) == 'undefined') { Clipperz.ext = {}; }
31
32/**
33 * @class Clipperz.YUI.DomHelper
34 * Utility class for working with DOM and/or Templates. It transparently supports using HTML fragments or DOM.
35 * For more information see <a href="http://www.jackslocum.com/yui/2006/10/06/domhelper-create-elements-using-dom-html-fragments-or-templates/">this blog post with examples</a>.
36 * @singleton
37 */
38Clipperz.YUI.DomHelper = new function(){
39 /**@private*/
40 var d = document;
41 var tempTableEl = null;
42 /** True to force the use of DOM instead of html fragments @type Boolean */
43 this.useDom = false;
44 var emptyTags = /^(?:base|basefont|br|frame|hr|img|input|isindex|link|meta|nextid|range|spacer|wbr|audioscope|area|param|keygen|col|limittext|spot|tab|over|right|left|choose|atop|of)$/i;
45 /**
46 * Applies a style specification to an element
47 * @param {String/HTMLElement} el The element to apply styles to
48 * @param {String/Object/Function} styles A style specification string eg "width:100px", or object in the form {width:"100px"}, or
49 * a function which returns such a specification.
50 */
51 this.applyStyles = function(el, styles){
52 if(styles){
53 var D = YAHOO.util.Dom;
54 if (typeof styles == "string"){
55 var re = /\s?([a-z\-]*)\:([^;]*);?/gi;
56 var matches;
57 while ((matches = re.exec(styles)) != null){
58 D.setStyle(el, matches[1], matches[2]);
59 }
60 }else if (typeof styles == "object"){
61 for (var style in styles){
62 D.setStyle(el, style, styles[style]);
63 }
64 }else if (typeof styles == "function"){
65 Clipperz.YUI.DomHelper.applyStyles(el, styles.call());
66 }
67 }
68 };
69
70 // build as innerHTML where available
71 /** @ignore */
72 var createHtml = function(o){
73 var b = '';
74
75 if(typeof(o['html']) != 'undefined') {
76 o['html'] = Clipperz.Base.sanitizeString(o['html']);
77 } else if (typeof(o['htmlString']) != 'undefined') {
78 o['html'] = o['htmlString'];
79 delete o.htmlString;
80 }
81
82 b += '<' + o.tag;
83 for(var attr in o){
84 if(attr == 'tag' || attr == 'children' || attr == 'html' || typeof o[attr] == 'function') continue;
85 if(attr == 'style'){
86 var s = o['style'];
87 if(typeof s == 'function'){
88 s = s.call();
89 }
90 if(typeof s == 'string'){
91 b += ' style="' + s + '"';
92 }else if(typeof s == 'object'){
93 b += ' style="';
94 for(var key in s){
95 if(typeof s[key] != 'function'){
96 b += key + ':' + s[key] + ';';
97 }
98 }
99 b += '"';
100 }
101 }else{
102 if(attr == 'cls'){
103 b += ' class="' + o['cls'] + '"';
104 }else if(attr == 'htmlFor'){
105 b += ' for="' + o['htmlFor'] + '"';
106 }else{
107 b += ' ' + attr + '="' + o[attr] + '"';
108 }
109 }
110 }
111 if(emptyTags.test(o.tag)){
112 b += ' />';
113 }else{
114 b += '>';
115 if(o.children){
116 for(var i = 0, len = o.children.length; i < len; i++) {
117 b += createHtml(o.children[i], b);
118 }
119 }
120 if(o.html){
121 b += o.html;
122 }
123 b += '</' + o.tag + '>';
124 }
125 return b;
126 }
127
128 // build as dom
129 /** @ignore */
130 var createDom = function(o, parentNode){
131 var el = d.createElement(o.tag);
132 var useSet = el.setAttribute ? true : false; // In IE some elements don't have setAttribute
133 for(var attr in o){
134 if(attr == 'tag' || attr == 'children' || attr == 'html' || attr == 'style' || typeof o[attr] == 'function') continue;
135 if(attr=='cls'){
136 el.className = o['cls'];
137 }else{
138 if(useSet) el.setAttribute(attr, o[attr]);
139 else el[attr] = o[attr];
140 }
141 }
142 Clipperz.YUI.DomHelper.applyStyles(el, o.style);
143 if(o.children){
144 for(var i = 0, len = o.children.length; i < len; i++) {
145 createDom(o.children[i], el);
146 }
147 }
148 if(o.html){
149 el.innerHTML = o.html;
150 }
151 if(parentNode){
152 parentNode.appendChild(el);
153 }
154 return el;
155 };
156
157 /**
158 * @ignore
159 * Nasty code for IE's broken table implementation
160 */
161 var insertIntoTable = function(tag, where, el, html){
162 if(!tempTableEl){
163 tempTableEl = document.createElement('div');
164 }
165 var node;
166 if(tag == 'table' || tag == 'tbody'){
167 tempTableEl.innerHTML = '<table><tbody>'+html+'</tbody></table>';
168 node = tempTableEl.firstChild.firstChild.firstChild;
169 }else{
170 tempTableEl.innerHTML = '<table><tbody><tr>'+html+'</tr></tbody></table>';
171 node = tempTableEl.firstChild.firstChild.firstChild.firstChild;
172 }
173 if(where == 'beforebegin'){
174 el.parentNode.insertBefore(node, el);
175 return node;
176 }else if(where == 'afterbegin'){
177 el.insertBefore(node, el.firstChild);
178 return node;
179 }else if(where == 'beforeend'){
180 el.appendChild(node);
181 return node;
182 }else if(where == 'afterend'){
183 el.parentNode.insertBefore(node, el.nextSibling);
184 return node;
185 }
186 }
187
188 /**
189 * Inserts an HTML fragment into the Dom
190 * @param {String} where Where to insert the html in relation to el - beforeBegin, afterBegin, beforeEnd, afterEnd.
191 * @param {HTMLElement} el The context element
192 * @param {String} html The HTML fragmenet
193 * @return {HTMLElement} The new node
194 */
195 this.insertHtml = function(where, el, html){
196 where = where.toLowerCase();
197 if(el.insertAdjacentHTML){
198 var tag = el.tagName.toLowerCase();
199 if(tag == 'table' || tag == 'tbody' || tag == 'tr'){
200 return insertIntoTable(tag, where, el, html);
201 }
202 switch(where){
203 case 'beforebegin':
204 el.insertAdjacentHTML(where, html);
205 return el.previousSibling;
206 case 'afterbegin':
207 el.insertAdjacentHTML(where, html);
208 return el.firstChild;
209 case 'beforeend':
210 el.insertAdjacentHTML(where, html);
211 return el.lastChild;
212 case 'afterend':
213 el.insertAdjacentHTML(where, html);
214 return el.nextSibling;
215 }
216 throw 'Illegal insertion point -> "' + where + '"';
217 }
218 var range = el.ownerDocument.createRange();
219 var frag;
220 switch(where){
221 case 'beforebegin':
222 range.setStartBefore(el);
223 frag = range.createContextualFragment(html);
224 el.parentNode.insertBefore(frag, el);
225 return el.previousSibling;
226 case 'afterbegin':
227 if(el.firstChild){ // faster
228 range.setStartBefore(el.firstChild);
229 }else{
230 range.selectNodeContents(el);
231 range.collapse(true);
232 }
233 frag = range.createContextualFragment(html);
234 el.insertBefore(frag, el.firstChild);
235 return el.firstChild;
236 case 'beforeend':
237 if(el.lastChild){
238 range.setStartAfter(el.lastChild); // faster
239 }else{
240 range.selectNodeContents(el);
241 range.collapse(false);
242 }
243 frag = range.createContextualFragment(html);
244 el.appendChild(frag);
245 return el.lastChild;
246 case 'afterend':
247 range.setStartAfter(el);
248 frag = range.createContextualFragment(html);
249 el.parentNode.insertBefore(frag, el.nextSibling);
250 return el.nextSibling;
251 }
252 throw 'Illegal insertion point -> "' + where + '"';
253 };
254
255 /**
256 * Creates new Dom element(s) and inserts them before el
257 * @param {String/HTMLElement/Element} el The context element
258 * @param {Object} o The Dom object spec (and children)
259 * @param {<i>Boolean</i>} returnElement (optional) true to return a YAHOO.ext.Element
260 * @return {HTMLElement} The new node
261 */
262 this.insertBefore = function(el, o, returnElement){
263 el = el.dom ? el.dom : YAHOO.util.Dom.get(el);
264 var newNode;
265 if(this.useDom){
266 newNode = createDom(o, null);
267 el.parentNode.insertBefore(newNode, el);
268 }else{
269 var html = createHtml(o);
270 newNode = this.insertHtml('beforeBegin', el, html);
271 }
272 return returnElement ? YAHOO.ext.Element.get(newNode, true) : newNode;
273 };
274
275 /**
276 * Creates new Dom element(s) and inserts them after el
277 * @param {String/HTMLElement/Element} el The context element
278 * @param {Object} o The Dom object spec (and children)
279 * @param {<i>Boolean</i>} returnElement (optional) true to return a YAHOO.ext.Element
280 * @return {HTMLElement} The new node
281 */
282 this.insertAfter = function(el, o, returnElement){
283 el = el.dom ? el.dom : YAHOO.util.Dom.get(el);
284 var newNode;
285 if(this.useDom){
286 newNode = createDom(o, null);
287 el.parentNode.insertBefore(newNode, el.nextSibling);
288 }else{
289 var html = createHtml(o);
290 newNode = this.insertHtml('afterEnd', el, html);
291 }
292 return returnElement ? YAHOO.ext.Element.get(newNode, true) : newNode;
293 };
294
295 /**
296 * Creates new Dom element(s) and appends them to el
297 * @param {String/HTMLElement/Element} el The context element
298 * @param {Object} o The Dom object spec (and children)
299 * @param {<i>Boolean</i>} returnElement (optional) true to return a YAHOO.ext.Element
300 * @return {HTMLElement} The new node
301 */
302 this.append = function(el, o, returnElement){
303 el = el.dom ? el.dom : YAHOO.util.Dom.get(el);
304 var newNode;
305 if(this.useDom){
306 newNode = createDom(o, null);
307 el.appendChild(newNode);
308 }else{
309 var html = createHtml(o);
310 newNode = this.insertHtml('beforeEnd', el, html);
311 }
312 return returnElement ? YAHOO.ext.Element.get(newNode, true) : newNode;
313 };
314
315 /**
316 * Creates new Dom element(s) and overwrites the contents of el with them
317 * @param {String/HTMLElement/Element} el The context element
318 * @param {Object} o The Dom object spec (and children)
319 * @param {<i>Boolean</i>} returnElement (optional) true to return a YAHOO.ext.Element
320 * @return {HTMLElement} The new node
321 */
322 this.overwrite = function(el, o, returnElement){
323 el = el.dom ? el.dom : YAHOO.util.Dom.get(el);
324 el.innerHTML = createHtml(o);
325 return returnElement ? YAHOO.ext.Element.get(el.firstChild, true) : el.firstChild;
326 };
327
328 /**
329 * Creates a new Clipperz.YUI.DomHelper.Template from the Dom object spec
330 * @param {Object} o The Dom object spec (and children)
331 * @return {Clipperz.YUI.DomHelper.Template} The new template
332 */
333 this.createTemplate = function(o){
334 var html = createHtml(o);
335 return new Clipperz.YUI.DomHelper.Template(html);
336 };
337}();
338
339/**
340* @class Clipperz.YUI.DomHelper.Template
341* Represents an HTML fragment template.
342* For more information see <a href="http://www.jackslocum.com/yui/2006/10/06/domhelper-create-elements-using-dom-html-fragments-or-templates/">this blog post with examples</a>.
343* <br>
344* <b>This class is also available as YAHOO.ext.Template</b>.
345* @constructor
346* @param {String/Array} html The HTML fragment or an array of fragments to join('') or multiple arguments to join('')
347*/
348Clipperz.YUI.DomHelper.Template = function(html){
349 if(html instanceof Array){
350 html = html.join('');
351 }else if(arguments.length > 1){
352 html = Array.prototype.join.call(arguments, '');
353 }
354 /**@private*/
355 this.html = html;
356};
357Clipperz.YUI.DomHelper.Template.prototype = {
358 /**
359 * Returns an HTML fragment of this template with the specified values applied
360 * @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'})
361 * @return {String}
362 */
363 applyTemplate : function(values){
364 if(this.compiled){
365 return this.compiled(values);
366 }
367 var empty = '';
368 var fn = function(match, index){
369 if(typeof values[index] != 'undefined'){
370 return values[index];
371 }else{
372 return empty;
373 }
374 }
375 return this.html.replace(this.re, fn);
376 },
377
378 /**
379 * The regular expression used to match template variables
380 * @type RegExp
381 * @property
382 */
383 re : /\{([\w|-]+)\}/g,
384
385 /**
386 * Compiles the template into an internal function, eliminating the RegEx overhead
387 */
388 compile : function(){
389 var body = ["this.compiled = function(values){ return ['"];
390 body.push(this.html.replace(this.re, "', values['$1'], '"));
391 body.push("'].join('');};");
392 eval(body.join(''));
393 return this;
394 },
395
396 /**
397 * Applies the supplied values to the template and inserts the new node(s) before el
398 * @param {String/HTMLElement/Element} el The context element
399 * @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'})
400 * @param {<i>Boolean</i>} returnElement (optional) true to return a YAHOO.ext.Element
401 * @return {HTMLElement} The new node
402 */
403 insertBefore: function(el, values, returnElement){
404 el = el.dom ? el.dom : YAHOO.util.Dom.get(el);
405 var newNode = Clipperz.YUI.DomHelper.insertHtml('beforeBegin', el, this.applyTemplate(values));
406 return returnElement ? YAHOO.ext.Element.get(newNode, true) : newNode;
407 },
408
409 /**
410 * Applies the supplied values to the template and inserts the new node(s) after el
411 * @param {String/HTMLElement/Element} el The context element
412 * @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'})
413 * @param {<i>Boolean</i>} returnElement (optional) true to return a YAHOO.ext.Element
414 * @return {HTMLElement} The new node
415 */
416 insertAfter : function(el, values, returnElement){
417 el = el.dom ? el.dom : YAHOO.util.Dom.get(el);
418 var newNode = Clipperz.YUI.DomHelper.insertHtml('afterEnd', el, this.applyTemplate(values));
419 return returnElement ? YAHOO.ext.Element.get(newNode, true) : newNode;
420 },
421
422 /**
423 * Applies the supplied values to the template and append the new node(s) to el
424 * @param {String/HTMLElement/Element} el The context element
425 * @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'})
426 * @param {<i>Boolean</i>} returnElement (optional) true to return a YAHOO.ext.Element
427 * @return {HTMLElement} The new node
428 */
429 append : function(el, values, returnElement){
430 var sanitizedValues;
431 var key;
432
433 // sanitizedValues = MochiKit.Base.map(sanitizedValues)
434//console.log("values", values);
435 sanitizedValues = {};
436 for (key in values) {
437 sanitizedValues[key] = Clipperz.Base.sanitizeString(values[key]);
438 }
439//console.log("sanitizedValues", sanitizedValues);
440 el = el.dom ? el.dom : YAHOO.util.Dom.get(el);
441 var newNode = Clipperz.YUI.DomHelper.insertHtml('beforeEnd', el, this.applyTemplate(sanitizedValues));
442 return returnElement ? YAHOO.ext.Element.get(newNode, true) : newNode;
443 },
444
445 /**
446 * Applies the supplied values to the template and overwrites the content of el with the new node(s)
447 * @param {String/HTMLElement/Element} el The context element
448 * @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'})
449 * @param {<i>Boolean</i>} returnElement (optional) true to return a YAHOO.ext.Element
450 * @return {HTMLElement} The new node
451 */
452 overwrite : function(el, values, returnElement){
453 el = el.dom ? el.dom : YAHOO.util.Dom.get(el);
454 el.innerHTML = '';
455 var newNode = Clipperz.YUI.DomHelper.insertHtml('beforeEnd', el, this.applyTemplate(values));
456 return returnElement ? YAHOO.ext.Element.get(newNode, true) : newNode;
457 }
458};
459/**
460 * Alias for applyTemplate
461 * @method
462 */
463Clipperz.YUI.DomHelper.Template.prototype.apply = Clipperz.YUI.DomHelper.Template.prototype.applyTemplate;
464
465YAHOO.ext.Template = Clipperz.YUI.DomHelper.Template;
diff --git a/frontend/beta/js/Clipperz/YUI/DomQuery.js b/frontend/beta/js/Clipperz/YUI/DomQuery.js
new file mode 100644
index 0000000..84aac08
--- a/dev/null
+++ b/frontend/beta/js/Clipperz/YUI/DomQuery.js
@@ -0,0 +1,710 @@
1/*
2
3Copyright 2008-2011 Clipperz Srl
4
5This file is part of Clipperz's Javascript Crypto Library.
6Javascript Crypto Library provides web developers with an extensive
7and efficient set of cryptographic functions. The library aims to
8obtain maximum execution speed while preserving modularity and
9reusability.
10For further information about its features and functionalities please
11refer to http://www.clipperz.com
12
13* Javascript Crypto Library is free software: you can redistribute
14 it and/or modify it under the terms of the GNU Affero General Public
15 License as published by the Free Software Foundation, either version
16 3 of the License, or (at your option) any later version.
17
18* Javascript Crypto Library is distributed in the hope that it will
19 be useful, but WITHOUT ANY WARRANTY; without even the implied
20 warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
21 See the GNU Affero General Public License for more details.
22
23* You should have received a copy of the GNU Affero General Public
24 License along with Javascript Crypto Library. If not, see
25 <http://www.gnu.org/licenses/>.
26
27*/
28
29/*
30 * yui-ext 0.40
31 * Copyright(c) 2006, Jack Slocum.
32 */
33
34/**
35 * @class Ext.DomQuery
36 * Provides high performance selector/xpath processing by compiling queries into reusable functions.
37 * New pseudo classes and matchers can be plugged. It works on HTML and XML documents (if a content node is passed in).
38 * @singleton
39 */
40Ext.DomQuery = function(){
41 var cache = {}, simpleCache = {}, valueCache = {};
42 var nonSpace = /\S/;
43 var trimRe = /^\s*(.*?)\s*$/;
44 var tplRe = /\{(\d+)\}/g;
45 var modeRe = /^(\s?[\/>]\s?|\s|$)/;
46 var clsRes = {};
47
48 function child(p, index){
49 var i = 0;
50 var n = p.firstChild;
51 while(n){
52 if(n.nodeType == 1){
53 i++;
54 if(i == index){
55 return n;
56 }
57 }
58 n = n.nextSibling;
59 }
60 return null;
61 };
62
63 function next(d){
64 var n = d.nextSibling;
65 while(n && n.nodeType != 1){
66 n = n.nextSibling;
67 }
68 return n;
69 };
70
71 function prev(d){
72 var n = d.previousSibling;
73 while(n && n.nodeType != 1){
74 n = n.previousSibling;
75 }
76 return n;
77 };
78
79 function clean(d){
80 var n = d.firstChild, ni = -1;
81 while(n){
82 var nx = n.nextSibling;
83 if(n.nodeType == 3 && !nonSpace.test(n.nodeValue)){
84 d.removeChild(n);
85 }else{
86 n.nodeIndex = ++ni;
87 }
88 n = nx;
89 }
90 return this;
91 };
92
93 function byClassName(c, a, v){
94 if(!v){
95 return c;
96 }
97 var re = clsRes[v];
98 if(!re){
99 re = new RegExp('(?:^|\\s)(?:' + v + ')(?:\\s|$)');
100 clsRes[v] = re;
101 }
102 var r = [];
103 for(var i = 0, ci; ci = c[i]; i++){
104 if(re.test(ci.className)){
105 r[r.length] = ci;
106 }
107 }
108 return r;
109 };
110
111 function convert(c){
112 if(c.slice){
113 return c;
114 }
115 var r = [];
116 for(var i = 0, l = c.length; i < l; i++){
117 r[r.length] = c[i];
118 }
119 return r;
120 };
121
122 function attrValue(n, attr){
123 if(!n.tagName && typeof n.length != 'undefined'){
124 n = n[0];
125 }
126 if(!n){
127 return null;
128 }
129 if(attr == 'for'){
130 return n.htmlFor;
131 }
132 if(attr == 'class' || attr == 'className'){
133 return n.className;
134 }
135 return n.getAttribute(attr) || n[attr];
136
137 };
138
139 function getNodes(ns, mode, tagName){
140 var result = [], cs;
141 if(!ns){
142 return result;
143 }
144 mode = mode ? mode.replace(trimRe, '$1') : '';
145 tagName = tagName || '*';
146 if(ns.tagName || ns == document){
147 ns = [ns];
148 }
149 if(mode != '/' && mode != '>'){
150 for(var i = 0, ni; ni = ns[i]; i++){
151 cs = ni.getElementsByTagName(tagName);
152 result = concat(result, cs);
153 }
154 }else{
155 for(var i = 0, ni; ni = ns[i]; i++){
156 var cn = ni.getElementsByTagName(tagName);
157 for(var j = 0, cj; cj = cn[j]; j++){
158 if(cj.parentNode == ni){
159 result[result.length] = cj;
160 }
161 }
162 }
163
164 }
165 return result;
166 };
167
168 function concat(a, b){
169 if(b.slice){
170 return a.concat(b);
171 }
172 for(var i = 0, l = b.length; i < l; i++){
173 a[a.length] = b[i];
174 }
175 return a;
176 }
177
178 function byTag(cs, tagName){
179 if(cs.tagName || cs == document){
180 cs = [cs];
181 }
182 if(!tagName){
183 return cs;
184 }
185 var r = []; tagName = tagName.toLowerCase();
186 for(var i = 0, ci; ci = cs[i]; i++){
187 if(ci.nodeType == 1 && ci.tagName.toLowerCase()==tagName){
188 r[r.length] = ci;
189 }
190 }
191 return r;
192 };
193
194 function byId(cs, attr, id){
195 if(cs.tagName || cs == document){
196 cs = [cs];
197 }
198 if(!id){
199 return cs;
200 }
201 var r = [];
202 for(var i = 0, l = cs.length; i < l; i++){
203 var ci = cs[i];
204 if(ci && ci.id == id){
205 r[r.length] = ci;
206 }
207 }
208 return r;
209 };
210
211 function byAttribute(cs, attr, value, op, custom){
212 var r = [], st = custom=='{';
213 var f = Ext.DomQuery.operators[op];
214 for(var i = 0, l = cs.length; i < l; i++){
215 var a;
216 if(st){
217 a = Ext.DomQuery.getStyle(cs[i], attr);
218 }
219 else if(attr == 'class' || attr == 'className'){
220 a = cs[i].className;
221 }else if(attr == 'for'){
222 a = cs[i].htmlFor;
223 }else{
224 a = cs[i].getAttribute(attr);
225 }
226 if((f && f(a, value)) || (!f && a)){
227 r[r.length] = cs[i];
228 }
229 }
230 return r;
231 };
232
233 function byPseudo(cs, name, value){
234 return Ext.DomQuery.pseudos[name](cs, value);
235 };
236
237 // This is for IE MSXML which does not support expandos.
238 // IE runs the same speed using setAttribute, however FF slows way down
239 // and Safari completely fails so they need to continue to use expandos.
240 // Branched at load time for faster execution.
241 var isIE = window.ActiveXObject;
242 var addAttr = isIE ?
243 function(n, a, v){
244 n.setAttribute(a, v);
245 } :
246 function(n, a, v){
247 n[a] = v;
248 };
249 var getAttr = isIE ?
250 function(n, a){
251 return n.getAttribute(a);
252 } :
253 function(n, a){
254 return n[a];
255 };
256 var clearAttr = isIE ?
257 function(n, a){
258 n.removeAttribute(a);
259 } :
260 function(n, a, v){
261 delete n[a];
262 };
263
264 function nodup(cs){
265 if(!cs.length){
266 return cs;
267 }
268 addAttr(cs[0], '_nodup', true);
269 var r = [cs[0]];
270 for(var i = 1, len = cs.length; i < len; i++){
271 var c = cs[i];
272 if(!getAttr(c, '_nodup')){
273 addAttr(c, '_nodup', true);
274 r[r.length] = c;
275 }
276 }
277 for(var i = 0, len = cs.length; i < len; i++){
278 clearAttr(cs[i], '_nodup');
279 }
280 return r;
281 }
282
283 function quickDiff(c1, c2){
284 if(!c1.length){
285 return c2;
286 }
287 for(var i = 0, len = c1.length; i < len; i++){
288 addAttr(c1[i], '_qdiff', true);
289 }
290 var r = [];
291 for(var i = 0, len = c2.length; i < len; i++){
292 if(!getAttr(c2[i], '_qdiff')){
293 r[r.length] = c2[i];
294 }
295 }
296 for(var i = 0, len = c1.length; i < len; i++){
297 clearAttr(c1[i], '_qdiff');
298 }
299 return r;
300 }
301
302 function quickId(ns, mode, root, id){
303 if(ns == root){
304 var d = root.ownerDocument || root;
305 return d.getElementById(id);
306 }
307 ns = getNodes(ns, mode, '*');
308 return byId(ns, null, id);
309 }
310
311 return {
312 getStyle : function(el, name){
313 return YAHOO.util.Dom.getStyle(el, name);
314 },
315 /**
316 * Compiles a selector/xpath query into a reusable function. The returned function
317 * takes one parameter "root" (optional), which is the context node from where the query should start.
318 * @param {String} selector The selector/xpath query
319 * @param {String} type (optional) Either 'select' (the default) or 'simple' for a simple selector match
320 * @return {Function}
321 */
322 compile : function(path, type){
323 // strip leading slashes
324 while(path.substr(0, 1)=='/'){
325 path = path.substr(1);
326 }
327 type = type || 'select';
328
329 var fn = ['var f = function(root){\n var mode; var n = root || document;\n'];
330 var q = path, mode, lq;
331 var tk = Ext.DomQuery.matchers;
332 var tklen = tk.length;
333 var mm;
334 while(q && lq != q){
335 lq = q;
336 var tm = q.match(/^(#)?([\w-\*]+)/);
337 if(type == 'select'){
338 if(tm){
339 if(tm[1] == '#'){
340 fn[fn.length] = 'n = quickId(n, mode, root, "'+tm[2]+'");';
341 }else{
342 fn[fn.length] = 'n = getNodes(n, mode, "'+tm[2]+'");';
343 }
344 q = q.replace(tm[0], '');
345 }else{
346 fn[fn.length] = 'n = getNodes(n, mode, "*");';
347 }
348 }else{
349 if(tm){
350 if(tm[1] == '#'){
351 fn[fn.length] = 'n = byId(n, null, "'+tm[2]+'");';
352 }else{
353 fn[fn.length] = 'n = byTag(n, "'+tm[2]+'");';
354 }
355 q = q.replace(tm[0], '');
356 }
357 }
358 while(!(mm = q.match(modeRe))){
359 var matched = false;
360 for(var j = 0; j < tklen; j++){
361 var t = tk[j];
362 var m = q.match(t.re);
363 if(m){
364 fn[fn.length] = t.select.replace(tplRe, function(x, i){
365 return m[i];
366 });
367 q = q.replace(m[0], '');
368 matched = true;
369 break;
370 }
371 }
372 // prevent infinite loop on bad selector
373 if(!matched){
374 throw 'Error parsing selector, parsing failed at "' + q + '"';
375 }
376 }
377 if(mm[1]){
378 fn[fn.length] = 'mode="'+mm[1]+'";';
379 q = q.replace(mm[1], '');
380 }
381 }
382 fn[fn.length] = 'return nodup(n);\n}';
383 eval(fn.join(''));
384 return f;
385 },
386
387 /**
388 * Selects a group of elements.
389 * @param {String} selector The selector/xpath query
390 * @param {Node} root (optional) The start of the query (defaults to document).
391 * @return {Array}
392 */
393 select : function(path, root, type){
394 if(!root || root == document){
395 root = document;
396 }
397 if(typeof root == 'string'){
398 root = document.getElementById(root);
399 }
400 var paths = path.split(',');
401 var results = [];
402 for(var i = 0, len = paths.length; i < len; i++){
403 var p = paths[i].replace(trimRe, '$1');
404 if(!cache[p]){
405 cache[p] = Ext.DomQuery.compile(p);
406 if(!cache[p]){
407 throw p + ' is not a valid selector';
408 }
409 }
410 var result = cache[p](root);
411 if(result && result != document){
412 results = results.concat(result);
413 }
414 }
415 return results;
416 },
417
418 /**
419 * Selects a single element.
420 * @param {String} selector The selector/xpath query
421 * @param {Node} root (optional) The start of the query (defaults to document).
422 * @return {Element}
423 */
424 selectNode : function(path, root){
425 return Ext.DomQuery.select(path, root)[0];
426 },
427
428 /**
429 * Selects the value of a node, optionally replacing null with the defaultValue.
430 * @param {String} selector The selector/xpath query
431 * @param {Node} root (optional) The start of the query (defaults to document).
432 * @param {String} defaultValue
433 */
434 selectValue : function(path, root, defaultValue){
435 path = path.replace(trimRe, '$1');
436 if(!valueCache[path]){
437 valueCache[path] = Ext.DomQuery.compile(path, 'simple');
438 }
439 var n = valueCache[path](root);
440 n = n[0] ? n[0] : n;
441 var v = (n && n.firstChild ? n.firstChild.nodeValue : null);
442 return (v === null ? defaultValue : v);
443 },
444
445 /**
446 * Selects the value of a node, parsing integers and floats.
447 * @param {String} selector The selector/xpath query
448 * @param {Node} root (optional) The start of the query (defaults to document).
449 * @param {Number} defaultValue
450 * @return {Number}
451 */
452 selectNumber : function(path, root, defaultValue){
453 var v = Ext.DomQuery.selectValue(path, root, defaultValue || 0);
454 return parseFloat(v);
455 },
456
457 /**
458 * Returns true if the passed element(s) match the passed simple selector (e.g. div.some-class or span:first-child)
459 * @param {String/HTMLElement/Array} el An element id, element or array of elements
460 * @param {String} selector The simple selector to test
461 * @return {Boolean}
462 */
463 is : function(el, ss){
464 if(typeof el == 'string'){
465 el = document.getElementById(el);
466 }
467 var isArray = (el instanceof Array);
468 var result = Ext.DomQuery.filter(isArray ? el : [el], ss);
469 return isArray ? (result.length == el.length) : (result.length > 0);
470 },
471
472 /**
473 * Filters an array of elements to only include matches of a simple selector (e.g. div.some-class or span:first-child)
474 * @param {Array} el An array of elements to filter
475 * @param {String} selector The simple selector to test
476 * @param {Boolean} nonMatches If true, it returns the elements that DON'T match
477 * the selector instead of the ones that match
478 * @return {Array}
479 */
480 filter : function(els, ss, nonMatches){
481 ss = ss.replace(trimRe, '$1');
482 if(!simpleCache[ss]){
483 simpleCache[ss] = Ext.DomQuery.compile(ss, 'simple');
484 }
485 var result = simpleCache[ss](els);
486 return nonMatches ? quickDiff(result, els) : result;
487 },
488
489 /**
490 * Collection of matching regular expressions and code snippets.
491 */
492 matchers : [{
493 re: /^\.([\w-]+)/,
494 select: 'n = byClassName(n, null, "{1}");'
495 }, {
496 re: /^\:([\w-]+)(?:\(((?:[^\s>\/]*|.*?))\))?/,
497 select: 'n = byPseudo(n, "{1}", "{2}");'
498 },{
499 re: /^(?:([\[\{])(?:@)?([\w-]+)\s?(?:(=|.=)\s?['"]?(.*?)["']?)?[\]\}])/,
500 select: 'n = byAttribute(n, "{2}", "{4}", "{3}", "{1}");'
501 }, {
502 re: /^#([\w-]+)/,
503 select: 'n = byId(n, null, "{1}");'
504 },{
505 re: /^@([\w-]+)/,
506 select: 'return {firstChild:{nodeValue:attrValue(n, "{1}")}};'
507 }
508 ],
509
510 /**
511 * Collection of operator comparison functions. The default operators are =, !=, ^=, $=, *= and %=.
512 * New operators can be added as long as the match the format <i>c</i>= where <i>c<i> is any character other than space, &gt; &lt;.
513 */
514 operators : {
515 '=' : function(a, v){
516 return a == v;
517 },
518 '!=' : function(a, v){
519 return a != v;
520 },
521 '^=' : function(a, v){
522 return a && a.substr(0, v.length) == v;
523 },
524 '$=' : function(a, v){
525 return a && a.substr(a.length-v.length) == v;
526 },
527 '*=' : function(a, v){
528 return a && a.indexOf(v) !== -1;
529 },
530 '%=' : function(a, v){
531 return (a % v) == 0;
532 }
533 },
534
535 /**
536 * Collection of "pseudo class" processors. Each processor is passed the current nodeset (array)
537 * and the argument (if any) supplied in the selector.
538 */
539 pseudos : {
540 'first-child' : function(c){
541 var r = [];
542 for(var i = 0, l = c.length; i < l; i++){
543 var ci = c[i];
544 if(!prev(ci)){
545 r[r.length] = ci;
546 }
547 }
548 return r;
549 },
550
551 'last-child' : function(c){
552 var r = [];
553 for(var i = 0, l = c.length; i < l; i++){
554 var ci = c[i];
555 if(!next(ci)){
556 r[r.length] = ci;
557 }
558 }
559 return r;
560 },
561
562 'nth-child' : function(c, a){
563 var r = [];
564 if(a != 'odd' && a != 'even'){
565 for(var i = 0, ci; ci = c[i]; i++){
566 var m = child(ci.parentNode, a);
567 if(m == ci){
568 r[r.length] = m;
569 }
570 }
571 return r;
572 }
573 var p;
574 // first let's clean up the parent nodes
575 for(var i = 0, l = c.length; i < l; i++){
576 var cp = c[i].parentNode;
577 if(cp != p){
578 clean(cp);
579 p = cp;
580 }
581 }
582 // then lets see if we match
583 for(var i = 0, l = c.length; i < l; i++){
584 var ci = c[i], m = false;
585 if(a == 'odd'){
586 m = ((ci.nodeIndex+1) % 2 == 1);
587 }else if(a == 'even'){
588 m = ((ci.nodeIndex+1) % 2 == 0);
589 }
590 if(m){
591 r[r.length] = ci;
592 }
593 }
594 return r;
595 },
596
597 'only-child' : function(c){
598 var r = [];
599 for(var i = 0, l = c.length; i < l; i++){
600 var ci = c[i];
601 if(!prev(ci) && !next(ci)){
602 r[r.length] = ci;
603 }
604 }
605 return r;
606 },
607
608 'empty' : function(c){
609 var r = [];
610 for(var i = 0, l = c.length; i < l; i++){
611 var ci = c[i];
612 if(!ci.firstChild){
613 r[r.length] = ci;
614 }
615 }
616 return r;
617 },
618
619 'contains' : function(c, v){
620 var r = [];
621 for(var i = 0, l = c.length; i < l; i++){
622 var ci = c[i];
623 if(ci.innerHTML.indexOf(v) !== -1){
624 r[r.length] = ci;
625 }
626 }
627 return r;
628 },
629
630 'checked' : function(c){
631 var r = [];
632 for(var i = 0, l = c.length; i < l; i++){
633 if(c[i].checked == 'checked'){
634 r[r.length] = c[i];
635 }
636 }
637 return r;
638 },
639
640 'not' : function(c, ss){
641 return Ext.DomQuery.filter(c, ss, true);
642 },
643
644 'odd' : function(c){
645 return this['nth-child'](c, 'odd');
646 },
647
648 'even' : function(c){
649 return this['nth-child'](c, 'even');
650 },
651
652 'nth' : function(c, a){
653 return c[a-1];
654 },
655
656 'first' : function(c){
657 return c[0];
658 },
659
660 'last' : function(c){
661 return c[c.length-1];
662 },
663
664 'has' : function(c, ss){
665 var s = Ext.DomQuery.select;
666 var r = [];
667 for(var i = 0, ci; ci = c[i]; i++){
668 if(s(ss, ci).length > 0){
669 r[r.length] = ci;
670 }
671 }
672 return r;
673 },
674
675 'next' : function(c, ss){
676 var is = Ext.DomQuery.is;
677 var r = [];
678 for(var i = 0, ci; ci = c[i]; i++){
679 var n = next(ci);
680 if(n && is(n, ss)){
681 r[r.length] = ci;
682 }
683 }
684 return r;
685 },
686
687 'prev' : function(c, ss){
688 var is = Ext.DomQuery.is;
689 var r = [];
690 for(var i = 0, ci; ci = c[i]; i++){
691 var n = prev(ci);
692 if(n && is(n, ss)){
693 r[r.length] = ci;
694 }
695 }
696 return r;
697 }
698 }
699 };
700}();
701
702/**
703 * Selects an array of DOM nodes by CSS/XPath selector. Shorthand of {@link Ext.DomQuery#select}
704 * @param {String} path The selector/xpath query
705 * @param {Node} root (optional) The start of the query (defaults to document).
706 * @return {Array}
707 * @member Ext
708 * @method query
709 */
710Ext.query = Ext.DomQuery.select;
diff --git a/frontend/beta/js/Clipperz/YUI/Drawer.js b/frontend/beta/js/Clipperz/YUI/Drawer.js
new file mode 100644
index 0000000..394912e
--- a/dev/null
+++ b/frontend/beta/js/Clipperz/YUI/Drawer.js
@@ -0,0 +1,238 @@
1/*
2
3Copyright 2008-2011 Clipperz Srl
4
5This file is part of Clipperz's Javascript Crypto Library.
6Javascript Crypto Library provides web developers with an extensive
7and efficient set of cryptographic functions. The library aims to
8obtain maximum execution speed while preserving modularity and
9reusability.
10For further information about its features and functionalities please
11refer to http://www.clipperz.com
12
13* Javascript Crypto Library is free software: you can redistribute
14 it and/or modify it under the terms of the GNU Affero General Public
15 License as published by the Free Software Foundation, either version
16 3 of the License, or (at your option) any later version.
17
18* Javascript Crypto Library is distributed in the hope that it will
19 be useful, but WITHOUT ANY WARRANTY; without even the implied
20 warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
21 See the GNU Affero General Public License for more details.
22
23* You should have received a copy of the GNU Affero General Public
24 License along with Javascript Crypto Library. If not, see
25 <http://www.gnu.org/licenses/>.
26
27*/
28
29if (typeof(Clipperz) == 'undefined') { Clipperz = {}; }
30if (typeof(Clipperz.YUI) == 'undefined') { Clipperz.YUI = {}; }
31
32
33Clipperz.YUI.Drawer = function(anElement, aRegion) {
34 this._status = 'slideIn';
35
36 this._element = YAHOO.ext.Element.get(anElement);
37 this._region = aRegion || null;
38
39 this._collapsedElement = this.element().getChildrenByClassName("drawer-collapsed")[0];
40 this._contentElement = this.element().getChildrenByClassName("drawer-content")[0];
41
42
43 this._wholeCollapedElement = this.enhanceCollapsedElement();
44 this._wholeCollapedElement.setWidth(this.region().element().getWidth());
45 this._wholeCollapedElement.setHeight(this.region().element().getHeight());
46
47 this._contentWrapper = this.enhanceContentElement();
48 this._contentElementActor = new YAHOO.ext.Actor(this.contentWrapper().dom);
49 this.contentElementActor().hide();
50
51 this._contentWidth = 200;
52};
53
54YAHOO.extendX(Clipperz.YUI.Drawer, YAHOO.ext.util.Observable, {
55
56 'element': function() {
57 return this._element;
58 },
59
60 //-----------------------------------------------------
61
62 'status': function() {
63 return this._status;
64 },
65
66 'setStatus': function(aValue) {
67 this._status = aValue;
68 },
69
70 //-----------------------------------------------------
71
72 'collapsedElement': function() {
73 return this._collapsedElement;
74 },
75
76 //-----------------------------------------------------
77
78 'contentElement': function() {
79 return this._contentElement;
80 },
81
82 //-----------------------------------------------------
83
84 'contentElementActor': function() {
85 return this._contentElementActor;
86 },
87
88 //-----------------------------------------------------
89
90 'contentWrapper': function() {
91 return this._contentWrapper;
92 },
93
94 //-----------------------------------------------------
95
96 'contentWidth': function() {
97 return this._contentWidth;
98 },
99
100 //-----------------------------------------------------
101
102 'region': function() {
103 return this._region;
104 },
105
106 //-----------------------------------------------------
107
108 'enhanceCollapsedElement': function() {
109 varwrapper;
110 var link;
111
112 wrapper = this.collapsedElement().wrap({tag:'div', cls:'drawer-collapsedElement-wrapper', children:[
113 {tag:'div', cls:'drawer-pin-button', children:[
114 {tag:'a', cls:'drawer-pin-button', href:"#", children:[
115 {tag:'img', src:'./images/directLogins/drawer/mm-expand.gif'}
116 ]}
117 ]}
118 ]});
119
120 link = wrapper.getChildrenByClassName('drawer-pin-button', 'a')[0];
121 MochiKit.Signal.connect(link.dom, 'onclick', this, 'pinDrawer');
122
123 this.collapsedElement().setHeight('100%');
124 this.collapsedElement().setStyle('cursor', 'pointer');
125 MochiKit.Signal.connect(this.collapsedElement().dom, 'onclick', this, 'showDrawer');
126
127 return wrapper;
128 },
129
130 //-----------------------------------------------------
131
132 'enhanceContentElement': function() {
133 var wrapper;
134
135 wrapper = this.contentElement().wrap({tag:'div', cls:'drawer-content-wrapper', children:[
136 {tag:'div', cls:'drawer-content-header', html:'direct login', style:'width:100%;'}
137 ]});
138
139 MochiKit.Signal.connect(wrapper.dom, 'onclick', this, 'hideDrawer');
140 return wrapper;
141 },
142
143 //-----------------------------------------------------
144
145 'pinDrawer': function() {
146 alert("pin drawer");
147 },
148
149 //-----------------------------------------------------
150
151 'showDrawer': function() {
152 if (this.status() == 'slideIn') {
153 var actor;
154
155 this.setStatus('slidingOut');
156 actor = this.contentElementActor();
157 actor.setHeight(this.region().element().getHeight());
158
159 actor.startCapture(true);
160 actor.alignTo(this.element(), 'tr');
161 actor.blindShow('left', this.contentWidth(), .35);
162 actor.play(this.onSlideOut.createDelegate(this));
163 }
164 },
165
166 //-----------------------------------------------------
167
168 'onSlideOut': function() {
169 this.setStatus('slideOut');
170MochiKit.Logging.logDebug(">>> onSlideOut");
171 // alert("done");
172 },
173
174 //-----------------------------------------------------
175/*
176 'showContentElement': function() {
177 var top, left, width, height;
178
179MochiKit.Logging.logDebug(">>> showContentElement");
180
181
182 top = this.element().getTop(true);
183 left = this.element().getRight();
184 width = this.contentWidth();
185 height = this.element().getHeight();
186
187 this.contentWrapper().setStyle('position', 'absolute');
188 this.contentWrapper().setStyle('overflow', 'none');
189 this.contentWrapper().setStyle('visibility', 'visible');
190 this.contentWrapper().setStyle('z-index', '10');
191
192 this.contentWrapper().setLeft(left);
193 this.contentWrapper().setTop(top);
194 this.contentWrapper().setHeight(height);
195 this.contentWrapper().setWidth(width);
196
197 this.contentWrapper().show();
198 },
199 */
200 //-----------------------------------------------------
201
202 'hideDrawer': function() {
203 if (this.status() == 'slideOut') {
204 var actor;
205
206 this.setStatus('slidingIn');
207
208 actor = this.contentElementActor();
209 actor.setHeight(this.region().element().getHeight());
210
211 actor.startCapture(true);
212 actor.alignTo(this.element(), 'tr');
213 actor.blindHide('left', .35);
214 actor.setVisible(false);
215 actor.play(this.onSlideIn.createDelegate(this));
216 }
217 },
218
219 //-----------------------------------------------------
220
221 'onSlideIn': function() {
222 this.setStatus('slideIn');
223MochiKit.Logging.logDebug(">>> onSlideIn");
224 // alert("done");
225 },
226
227 //-----------------------------------------------------
228
229 'hideContentElement': function() {
230 this.contentWrapper().hide();
231 },
232
233 //-----------------------------------------------------
234 //-----------------------------------------------------
235
236 //-----------------------------------------------------
237 __syntaxFix__: '__syntaxFix__'
238}); \ No newline at end of file
diff --git a/frontend/beta/js/Clipperz/YUI/IBLayoutManager.js b/frontend/beta/js/Clipperz/YUI/IBLayoutManager.js
new file mode 100644
index 0000000..626b699
--- a/dev/null
+++ b/frontend/beta/js/Clipperz/YUI/IBLayoutManager.js
@@ -0,0 +1,114 @@
1/*
2
3Copyright 2008-2011 Clipperz Srl
4
5This file is part of Clipperz's Javascript Crypto Library.
6Javascript Crypto Library provides web developers with an extensive
7and efficient set of cryptographic functions. The library aims to
8obtain maximum execution speed while preserving modularity and
9reusability.
10For further information about its features and functionalities please
11refer to http://www.clipperz.com
12
13* Javascript Crypto Library is free software: you can redistribute
14 it and/or modify it under the terms of the GNU Affero General Public
15 License as published by the Free Software Foundation, either version
16 3 of the License, or (at your option) any later version.
17
18* Javascript Crypto Library is distributed in the hope that it will
19 be useful, but WITHOUT ANY WARRANTY; without even the implied
20 warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
21 See the GNU Affero General Public License for more details.
22
23* You should have received a copy of the GNU Affero General Public
24 License along with Javascript Crypto Library. If not, see
25 <http://www.gnu.org/licenses/>.
26
27*/
28
29if (typeof(Clipperz) == 'undefined') { Clipperz = {}; }
30if (typeof(Clipperz.YUI) == 'undefined') { Clipperz.YUI = {}; }
31
32
33Clipperz.YUI.IBLayoutManager = function(container, config) {
34 var regionName;
35 varelement;
36
37 config = config || {};
38
39 Clipperz.YUI.IBLayoutManager.superclass.constructor.call(this, container);
40 this.hideOnLayout = config.hideOnLayout || false;
41
42 element = YAHOO.ext.Element.get(container);
43 element.setStyle('position', 'absolute');
44 element.setStyle('overflow', 'hidden');
45
46 for (regionName in config.regions) {
47 var newRegion;
48
49 newRegion = new new Clipperz.YUI.IBLayoutRegion(this, regionName, config.regions[regionName]);
50 this.addRegion(regionName, newRegion);
51 }
52
53 this.layout();
54};
55
56YAHOO.extendX(Clipperz.YUI.IBLayoutManager, YAHOO.ext.LayoutManager, {
57
58 'toString': function() {
59 return "IBLayoutManager (" + this.el.id + ")";
60 },
61
62 //-----------------------------------------------------
63
64 'add': function(aName, aPanel) {
65 var regionName;
66
67 regionName = aName.toLowerCase();
68 return this.regions[regionName].add(aPanel);
69 },
70
71 //-----------------------------------------------------
72
73 'addRegion': function(aRegion) {
74 var regionName;
75
76 regionName = aRegion.name().toLowerCase();
77 if (!this.regions[regionName]) {
78//MochiKit.Logging.logDebug("--- adding region with name: " + aRegion.name());
79 this.regions[regionName] = aRegion;
80 } else {
81 // ????
82 }
83
84 return aRegion;
85 },
86
87 //-----------------------------------------------------
88
89 'getRegion': function(target){
90 return this.regions[target.toLowerCase()];
91 },
92
93 //-----------------------------------------------------
94
95 'layout': function(){
96 varregion;
97
98//MochiKit.Logging.logDebug(">>> IBLayoutManager.layout - regions: " + Clipperz.Base.serializeJSON(MochiKit.Base.keys(this.regions)));
99 for (region in this.regions) {
100//MochiKit.Logging.logDebug("--- IBLayoutManager.layout - region: " + region);
101 this.regions[region].layout();
102 }
103//MochiKit.Logging.logDebug("<<< IBLayoutManager.layout");
104 },
105
106 //-----------------------------------------------------
107
108 'getSize': function() {
109 return this.el.getSize();
110 },
111
112 //-----------------------------------------------------
113 __syntaxFix__: '__syntaxFix__'
114});
diff --git a/frontend/beta/js/Clipperz/YUI/IBLayoutRegion.js b/frontend/beta/js/Clipperz/YUI/IBLayoutRegion.js
new file mode 100644
index 0000000..2fd4377
--- a/dev/null
+++ b/frontend/beta/js/Clipperz/YUI/IBLayoutRegion.js
@@ -0,0 +1,249 @@
1/*
2
3Copyright 2008-2011 Clipperz Srl
4
5This file is part of Clipperz's Javascript Crypto Library.
6Javascript Crypto Library provides web developers with an extensive
7and efficient set of cryptographic functions. The library aims to
8obtain maximum execution speed while preserving modularity and
9reusability.
10For further information about its features and functionalities please
11refer to http://www.clipperz.com
12
13* Javascript Crypto Library is free software: you can redistribute
14 it and/or modify it under the terms of the GNU Affero General Public
15 License as published by the Free Software Foundation, either version
16 3 of the License, or (at your option) any later version.
17
18* Javascript Crypto Library is distributed in the hope that it will
19 be useful, but WITHOUT ANY WARRANTY; without even the implied
20 warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
21 See the GNU Affero General Public License for more details.
22
23* You should have received a copy of the GNU Affero General Public
24 License along with Javascript Crypto Library. If not, see
25 <http://www.gnu.org/licenses/>.
26
27*/
28
29if (typeof(Clipperz) == 'undefined') { Clipperz = {}; }
30if (typeof(Clipperz.YUI) == 'undefined') { Clipperz.YUI = {}; }
31
32
33Clipperz.YUI.IBLayoutRegion = function(aManager, aName, aConfig) {
34 this._configuration = aConfig;
35
36 //Clipperz.YUI.IBLayoutRegion.superclass.constructor.call();
37 Clipperz.YUI.IBLayoutRegion.superclass.constructor.call(this, aManager, aConfig, aName);
38};
39
40YAHOO.extendX(Clipperz.YUI.IBLayoutRegion, YAHOO.ext.LayoutRegion, {
41
42 'toString': function() {
43 return "IBLayoutRegion (" + this.name() + ")";
44 },
45
46 //-----------------------------------------------------
47
48 'name': function() {
49 return this.position;
50 },
51
52 //-----------------------------------------------------
53
54 'manager': function() {
55 return this.mgr;
56 },
57
58 'configuration': function() {
59 return this._configuration;
60 },
61
62 //-----------------------------------------------------
63
64 'getAttributeValue': function(anAttribute) {
65 var result;
66
67 switch(anAttribute) {
68 case "top":
69 result = this.element().getTop();
70 break;
71 case "left":
72 result = this.element().getLeft();
73 break;
74 case "bottom":
75 result = this.element().getBottom();
76 break;
77 case "right":
78 result = this.element().getRight();
79 break;
80 case "height":
81 result = this.element().getHeight();
82 break;
83 case "width":
84 result = this.element().getWidth();
85 break;
86 }
87//MochiKit.Logging.logDebug("--- " + this.name() + " [" + anAttribute + "] = " + result);
88
89 return result;
90 },
91
92 //-----------------------------------------------------
93
94 'normalizeConfigureValue': function(aConfigurationValue) {
95 var result;
96
97//MochiKit.Logging.logDebug("--- normalizeConfigureValue - " + aConfigurationValue);
98 if (typeof(aConfigurationValue) == 'number') {
99 result = aConfigurationValue;
100 } else if (aConfigurationValue == 'auto') {
101 result = aConfigurationValue;
102 } else {
103 var splitValues;
104 var referenceValue;
105 var deltaValue;
106 var targetRegion;
107 var targetAttribute;
108
109 splitValues = aConfigurationValue.split('+');
110 referenceValue = Clipperz.Base.trim(splitValues[0]);
111 deltaValue = Clipperz.Base.trim(splitValues[1] || "");
112
113 splitValues = referenceValue.split('.');
114 targetRegion = splitValues[0];
115 targetAttribute = splitValues[1];
116
117//MochiKit.Logging.logDebug("> " + aConfigurationValue);
118//MochiKit.Logging.logDebug(">> manager: " + this.manager());
119//MochiKit.Logging.logDebug(">> targetRegion: " + targetRegion);
120//MochiKit.Logging.logDebug(">>> " + this.manager().getRegion(targetRegion));
121 targetValue = this.manager().getRegion(targetRegion).getAttributeValue(targetAttribute);
122//MochiKit.Logging.logDebug(">>>> " + targetRegion + "." + targetAttribute + " + " + deltaValue + " = " + targetValue);
123
124 result = targetValue + (deltaValue - 0);
125
126//MochiKit.Logging.logDebug("<<< " + aConfigurationValue + " = " + result);
127 }
128
129 return result;
130 },
131
132 'normalizedConfiguration': function(aConfiguration) {
133 varresult;
134 varkey;
135
136 result = {};
137
138//MochiKit.Logging.logDebug("--- normalizedConfiguration - keys: " + Clipperz.Base.serializeJSON(MochiKit.Base.keys(aConfiguration)));
139 for (key in aConfiguration) {
140 if ((key == 'top') || (key == 'bottom') || (key == 'left') || (key == 'rigth') || (key == 'width') || (key == 'height')) {
141 result[key] = this.normalizeConfigureValue(aConfiguration[key]);
142 } else {
143 result[key] = aConfiguration[key];
144 }
145 }
146
147 return result;
148 },
149
150 //-----------------------------------------------------
151
152 'element': function() {
153 return this.el;
154 },
155
156 //-----------------------------------------------------
157/*
158 'hide': function() {
159MochiKit.Logging.logDebug(">>> IBLayoutManager.hide()")
160 Clipperz.YUI.IBLayoutRegion.superclass.hide.call(this);
161 },
162*/
163 //-----------------------------------------------------
164/*
165 'add': function(aPanel) {
166 Clipperz.YUI.IBLayoutRegion.superclass.add.call(this, aPanel);
167 aPanel.el.fitToParent(true);
168 },
169*/
170 //-----------------------------------------------------
171
172 'updateBox': function(aBox) {
173//MochiKit.Logging.logDebug(">>> IBLayoutRegion.updateBox - " + aBox);
174 Clipperz.YUI.IBLayoutRegion.superclass.updateBox.call(this, aBox);
175 },
176
177 //-----------------------------------------------------
178
179 'layout': function() {
180 vartop, left, bottom, right, width, height;
181 varelement;
182 var config;
183 var windowSize;
184 var containerSize;
185
186//MochiKit.Logging.logDebug(">>> IBLayoutRegion.layout - " + this);
187 config = this.normalizedConfiguration(this.configuration());
188 element = this.element();
189 // containerSize = this.manager().getSize(true);
190 containerSize = this.manager().getSize(false);
191 windowSize = {width: YAHOO.util.Dom.getViewportWidth(), height: YAHOO.util.Dom.getViewportHeight()};
192
193 // element.setStyle("position", "absolute");
194 // element.setStyle("overflow", "none");
195
196 if (typeof(config.top) == 'number') {
197 top = config.top;
198
199 if (typeof(config.bottom) == 'number') {
200 height = containerSize.height - top - config.bottom;
201 } else if (typeof(config.height) == 'number') {
202 height = config.height;
203 } else {
204 //???
205 }
206 } else {
207 if ((typeof(config.bottom) == 'number') && (typeof(config.height) == 'number')) {
208 top = containerSize.height - (config.height + config.bottom);
209 height = config.height;
210 } else if ((config.bottom == 'auto') && (typeof(config.height) == 'number')) {
211 top = ((containerSize.height - config.height) / 2);
212 height = config.height;
213 }
214 }
215
216 if (typeof(config.left) == 'number') {
217 left = config.left;
218
219 if (typeof(config.right) == 'number') {
220 width = (containerSize.width - left - config.right);
221 } else if (typeof(config.width) == 'number') {
222 width = config.width;
223 } else {
224 //???
225 }
226 } else {
227 if ((typeof(config.right) == 'number') && (typeof(config.width) == 'number')) {
228 left = containerSize.width - (config.width + config.right);
229 width = config.width;
230 } else if ((config.right == 'auto') && (typeof(config.width) == 'number')) {
231 left = ((containerSize.width - config.width) / 2);
232 width = config.width;
233 }
234 }
235//MochiKit.Logging.logDebug("--- setting position (top: " + top + ", left: " + left + ", width: " + width + ", height: " + height + ")");
236 element.setTop(top);
237 element.setLeft(left);
238 element.setWidth(width);
239 element.setHeight(height);
240
241 if (this.activePanel != null) {
242 this.activePanel.setSize(width, height);
243 }
244//MochiKit.Logging.logDebug("<<< IBLayoutRegion.layout");
245 },
246
247 //-----------------------------------------------------
248 __syntaxFix__: '__syntaxFix__'
249});
diff --git a/frontend/beta/js/Clipperz/YUI/MessageBox.js b/frontend/beta/js/Clipperz/YUI/MessageBox.js
new file mode 100644
index 0000000..ec33d7d
--- a/dev/null
+++ b/frontend/beta/js/Clipperz/YUI/MessageBox.js
@@ -0,0 +1,265 @@
1/*
2
3Copyright 2008-2011 Clipperz Srl
4
5This file is part of Clipperz's Javascript Crypto Library.
6Javascript Crypto Library provides web developers with an extensive
7and efficient set of cryptographic functions. The library aims to
8obtain maximum execution speed while preserving modularity and
9reusability.
10For further information about its features and functionalities please
11refer to http://www.clipperz.com
12
13* Javascript Crypto Library is free software: you can redistribute
14 it and/or modify it under the terms of the GNU Affero General Public
15 License as published by the Free Software Foundation, either version
16 3 of the License, or (at your option) any later version.
17
18* Javascript Crypto Library is distributed in the hope that it will
19 be useful, but WITHOUT ANY WARRANTY; without even the implied
20 warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
21 See the GNU Affero General Public License for more details.
22
23* You should have received a copy of the GNU Affero General Public
24 License along with Javascript Crypto Library. If not, see
25 <http://www.gnu.org/licenses/>.
26
27*/
28
29Clipperz.YUI.MessageBox = function(){
30 var dlg, opt, mask;
31 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
32 var buttons, activeTextEl, bwidth;
33
34 var handleButton = function(button){
35 if(typeof opt.fn == 'function'){
36 if(opt.fn.call(opt.scope||window, button, activeTextEl.dom.value) !== false){
37 dlg.hide();
38 }
39 }else{
40 dlg.hide();
41 }
42 };
43
44 return {
45 updateButtons: function(b){
46 var width = 0;
47 if(!b){
48 buttons['ok'].hide();
49 buttons['cancel'].hide();
50 buttons['yes'].hide();
51 buttons['no'].hide();
52 return width;
53 }
54 for(var k in buttons){
55 if(typeof buttons[k] != 'function'){
56 if(b[k]){
57 buttons[k].show();
58 buttons[k].setText(typeof b[k] == 'string' ? b[k] : YAHOO.ext.MessageBox.buttonText[k]);
59 width += buttons[k].el.getWidth()+15;
60 }else{
61 buttons[k].hide();
62 }
63 }
64 }
65 return width;
66 },
67
68 getDialog : function(){
69 if(!dlg){
70 dlg = new YAHOO.ext.BasicDialog('mb-dlg', {
71 autoCreate:true,
72 shadow:true,
73 draggable:true,
74 resizable:false,
75 constraintoviewport:true,
76 fixedcenter:true,
77 shim:true,
78 modal:true,
79 width:400, height:100,
80 buttonAlign:'center',
81 closeClick : function(){
82 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
83 handleButton('no');
84 }else{
85 handleButton('cancel');
86 }
87 }
88 });
89 dlg.closeClick = function(){
90 alert('wtf');
91 };
92 mask = dlg.mask;
93 dlg.addKeyListener(27, dlg.hide, dlg);
94 buttons = {};
95 buttons['ok'] = dlg.addButton(this.buttonText['ok'], handleButton.createCallback('ok'));
96 buttons['yes'] = dlg.addButton(this.buttonText['yes'], handleButton.createCallback('yes'));
97 buttons['no'] = dlg.addButton(this.buttonText['no'], handleButton.createCallback('no'));
98 buttons['cancel'] = dlg.addButton(this.buttonText['cancel'], handleButton.createCallback('cancel'));
99 bodyEl = dlg.body.createChild({
100 tag:'div',
101 html:'<span class="ext-mb-text"></span><br /><input type="text" class="ext-mb-input"><textarea class="ext-mb-textarea"></textarea><div class="ext-mb-progress-wrap"><div class="ext-mb-progress"><div class="ext-mb-progress-bar">&#160;</div></div></div>'
102 });
103 msgEl = bodyEl.dom.firstChild;
104 textboxEl = getEl(bodyEl.dom.childNodes[2]);
105 textboxEl.enableDisplayMode();
106 textboxEl.addKeyListener([10,13], function(){
107 if(dlg.isVisible() && opt && opt.buttons){
108 if(opt.buttons.ok){
109 handleButton('ok');
110 }else if(opt.buttons.yes){
111 handleButton('yes');
112 }
113 }
114 });
115 textareaEl = getEl(bodyEl.dom.childNodes[3]);
116 textareaEl.enableDisplayMode();
117 progressEl = getEl(bodyEl.dom.childNodes[4]);
118 progressEl.enableDisplayMode();
119 pp = getEl(progressEl.dom.firstChild.firstChild);
120 }
121 return dlg;
122 },
123
124 updateText : function(text){
125 if(!dlg.isVisible() && !opt.width){
126 dlg.resizeTo(this.maxWidth, 100); // resize first so content is never clipped from previous shows
127 }
128 msgEl.innerHTML = text;
129 var w = Math.max(Math.min(opt.width || msgEl.offsetWidth, this.maxWidth),
130 Math.max(opt.minWidth || this.minWidth, bwidth));
131 if(opt.prompt){
132 activeTextEl.setWidth(w);
133 }
134 dlg.setContentSize(w, bodyEl.getHeight());
135 },
136
137 updateProgress : function(value, text){
138 if(text){
139 this.updateText(text);
140 }
141 pp.setWidth(value*progressEl.dom.firstChild.offsetWidth);
142 },
143
144 isVisible : function(){
145 return dlg && dlg.isVisible();
146 },
147
148 hide : function(){
149 if(this.isVisible()){
150 dlg.hide();
151 }
152 },
153
154 show : function(options){
155 var d = this.getDialog();
156 opt = options;
157 d.setTitle(opt.title || '&#160;');
158 d.close.setDisplayed(opt.closable !== false);
159 activeTextEl = textboxEl;
160 opt.prompt = opt.prompt || (opt.multiline ? true : false)
161 if(opt.prompt){
162 if(opt.multiline){
163 textboxEl.hide();
164 textareaEl.show();
165 textareaEl.setHeight(typeof opt.multiline == 'number' ?
166 opt.multiline : this.defaultTextHeight);
167 activeTextEl = textareaEl;
168 }else{
169 textboxEl.show();
170 textareaEl.hide();
171 }
172 }else{
173 textboxEl.hide();
174 textareaEl.hide();
175 }
176 progressEl.setDisplayed(opt.progress === true);
177 this.updateProgress(0);
178 activeTextEl.dom.value = opt.value || '';
179 if(opt.prompt){
180 dlg.setDefaultButton(activeTextEl);
181 }else{
182 var bs = opt.buttons;
183 var db = null;
184 if(bs && bs.ok){
185 db = buttons['ok'];
186 }else if(bs && bs.yes){
187 db = buttons['yes'];
188 }
189 dlg.setDefaultButton(db);
190 }
191 bwidth = this.updateButtons(opt.buttons);
192 this.updateText(opt.msg);
193 d.modal = opt.modal !== false;
194 d.mask = opt.modal !== false ? mask : false;
195 d.animateTarget = null;
196 d.show(options.animEl);
197 },
198
199 progress : function(title, msg){
200 this.show({
201 title : title,
202 msg : msg,
203 buttons: false,
204 progress:true,
205 closable:false
206 });
207 },
208
209 progressElement : function() {
210 return progressEl;
211 },
212
213 opt: function() {
214 return opt;
215 },
216
217 alert : function(title, msg, fn, scope){
218 this.show({
219 title : title,
220 msg : msg,
221 buttons: this.OK,
222 fn: fn,
223 scope : scope
224 });
225 },
226
227 confirm : function(title, msg, fn, scope){
228 this.show({
229 title : title,
230 msg : msg,
231 buttons: this.YESNO,
232 fn: fn,
233 scope : scope
234 });
235 },
236
237 prompt : function(title, msg, fn, scope, multiline){
238 this.show({
239 title : title,
240 msg : msg,
241 buttons: this.OKCANCEL,
242 fn: fn,
243 minWidth:250,
244 scope : scope,
245 prompt:true,
246 multiline: multiline
247 });
248 },
249
250 OK : {ok:true},
251 YESNO : {yes:true, no:true},
252 OKCANCEL : {ok:true, cancel:true},
253 YESNOCANCEL : {yes:true, no:true, cancel:true},
254
255 defaultTextHeight:75,
256 maxWidth : 500,
257 minWidth : 100,
258 buttonText : {
259 ok : 'OK',
260 cancel : 'Cancel',
261 yes : 'Yes',
262 no : 'No'
263 }
264 };
265}();
diff --git a/frontend/beta/js/JSON/json2.js b/frontend/beta/js/JSON/json2.js
new file mode 100644
index 0000000..bbeeca9
--- a/dev/null
+++ b/frontend/beta/js/JSON/json2.js
@@ -0,0 +1,481 @@
1/*
2 http://www.JSON.org/json2.js
3 2008-09-01
4
5 Public Domain.
6
7 NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.
8
9 See http://www.JSON.org/js.html
10
11 This file creates a global JSON object containing two methods: stringify
12 and parse.
13
14 JSON2.stringify(value, replacer, space)
15 value any JavaScript value, usually an object or array.
16
17 replacer an optional parameter that determines how object
18 values are stringified for objects. It can be a
19 function or an array of strings.
20
21 space an optional parameter that specifies the indentation
22 of nested structures. If it is omitted, the text will
23 be packed without extra whitespace. If it is a number,
24 it will specify the number of spaces to indent at each
25 level. If it is a string (such as '\t' or '&nbsp;'),
26 it contains the characters used to indent at each level.
27
28 This method produces a JSON text from a JavaScript value.
29
30 When an object value is found, if the object contains a toJSON
31 method, its toJSON method will be called and the result will be
32 stringified. A toJSON method does not serialize: it returns the
33 value represented by the name/value pair that should be serialized,
34 or undefined if nothing should be serialized. The toJSON method
35 will be passed the key associated with the value, and this will be
36 bound to the object holding the key.
37
38 For example, this would serialize Dates as ISO strings.
39
40 Date.prototype.toJSON = function (key) {
41 function f(n) {
42 // Format integers to have at least two digits.
43 return n < 10 ? '0' + n : n;
44 }
45
46 return this.getUTCFullYear() + '-' +
47 f(this.getUTCMonth() + 1) + '-' +
48 f(this.getUTCDate()) + 'T' +
49 f(this.getUTCHours()) + ':' +
50 f(this.getUTCMinutes()) + ':' +
51 f(this.getUTCSeconds()) + 'Z';
52 };
53
54 You can provide an optional replacer method. It will be passed the
55 key and value of each member, with this bound to the containing
56 object. The value that is returned from your method will be
57 serialized. If your method returns undefined, then the member will
58 be excluded from the serialization.
59
60 If the replacer parameter is an array of strings, then it will be used to
61 select the members to be serialized. It filters the results such
62 that only members with keys listed in the replacer array are
63 stringified.
64
65 Values that do not have JSON representations, such as undefined or
66 functions, will not be serialized. Such values in objects will be
67 dropped; in arrays they will be replaced with null. You can use
68 a replacer function to replace those with JSON values.
69 JSON.stringify(undefined) returns undefined.
70
71 The optional space parameter produces a stringification of the
72 value that is filled with line breaks and indentation to make it
73 easier to read.
74
75 If the space parameter is a non-empty string, then that string will
76 be used for indentation. If the space parameter is a number, then
77 the indentation will be that many spaces.
78
79 Example:
80
81 text = JSON2.stringify(['e', {pluribus: 'unum'}]);
82 // text is '["e",{"pluribus":"unum"}]'
83
84
85 text = JSON2.stringify(['e', {pluribus: 'unum'}], null, '\t');
86 // text is '[\n\t"e",\n\t{\n\t\t"pluribus": "unum"\n\t}\n]'
87
88 text = JSON2.stringify([new Date()], function (key, value) {
89 return this[key] instanceof Date ?
90 'Date(' + this[key] + ')' : value;
91 });
92 // text is '["Date(---current time---)"]'
93
94
95 JSON2.parse(text, reviver)
96 This method parses a JSON text to produce an object or array.
97 It can throw a SyntaxError exception.
98
99 The optional reviver parameter is a function that can filter and
100 transform the results. It receives each of the keys and values,
101 and its return value is used instead of the original value.
102 If it returns what it received, then the structure is not modified.
103 If it returns undefined then the member is deleted.
104
105 Example:
106
107 // Parse the text. Values that look like ISO date strings will
108 // be converted to Date objects.
109
110 myData = JSON2.parse(text, function (key, value) {
111 var a;
112 if (typeof value === 'string') {
113 a =
114/^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d*)?)Z$/.exec(value);
115 if (a) {
116 return new Date(Date.UTC(+a[1], +a[2] - 1, +a[3], +a[4],
117 +a[5], +a[6]));
118 }
119 }
120 return value;
121 });
122
123 myData = JSON2.parse('["Date(09/09/2001)"]', function (key, value) {
124 var d;
125 if (typeof value === 'string' &&
126 value.slice(0, 5) === 'Date(' &&
127 value.slice(-1) === ')') {
128 d = new Date(value.slice(5, -1));
129 if (d) {
130 return d;
131 }
132 }
133 return value;
134 });
135
136
137 This is a reference implementation. You are free to copy, modify, or
138 redistribute.
139
140 This code should be minified before deployment.
141 See http://javascript.crockford.com/jsmin.html
142
143 USE YOUR OWN COPY. IT IS EXTREMELY UNWISE TO LOAD CODE FROM SERVERS YOU DO
144 NOT CONTROL.
145*/
146
147/*jslint evil: true */
148
149/*global JSON2 */
150
151/*members "", "\b", "\t", "\n", "\f", "\r", "\"", JSON, "\\", call,
152 charCodeAt, getUTCDate, getUTCFullYear, getUTCHours, getUTCMinutes,
153 getUTCMonth, getUTCSeconds, hasOwnProperty, join, lastIndex, length,
154 parse, propertyIsEnumerable, prototype, push, replace, slice, stringify,
155 test, toJSON, toString, valueOf
156*/
157
158// Create a JSON object only if one does not already exist. We create the
159// methods in a closure to avoid creating global variables.
160
161if (!this.JSON2) {
162 JSON2 = {};
163}
164(function () {
165
166 function f(n) {
167 // Format integers to have at least two digits.
168 return n < 10 ? '0' + n : n;
169 }
170
171 if (typeof Date.prototype.toJSON !== 'function') {
172
173 Date.prototype.toJSON = function (key) {
174
175 return this.getUTCFullYear() + '-' +
176 f(this.getUTCMonth() + 1) + '-' +
177 f(this.getUTCDate()) + 'T' +
178 f(this.getUTCHours()) + ':' +
179 f(this.getUTCMinutes()) + ':' +
180 f(this.getUTCSeconds()) + 'Z';
181 };
182
183 String.prototype.toJSON =
184 Number.prototype.toJSON =
185 Boolean.prototype.toJSON = function (key) {
186 return this.valueOf();
187 };
188 }
189
190 var cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
191 escapeable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
192 gap,
193 indent,
194 meta = { // table of character substitutions
195 '\b': '\\b',
196 '\t': '\\t',
197 '\n': '\\n',
198 '\f': '\\f',
199 '\r': '\\r',
200 '"' : '\\"',
201 '\\': '\\\\'
202 },
203 rep;
204
205
206 function quote(string) {
207
208// If the string contains no control characters, no quote characters, and no
209// backslash characters, then we can safely slap some quotes around it.
210// Otherwise we must also replace the offending characters with safe escape
211// sequences.
212
213 escapeable.lastIndex = 0;
214 return escapeable.test(string) ?
215 '"' + string.replace(escapeable, function (a) {
216 var c = meta[a];
217 if (typeof c === 'string') {
218 return c;
219 }
220 return '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
221 }) + '"' :
222 '"' + string + '"';
223 }
224
225
226 function str(key, holder) {
227
228// Produce a string from holder[key].
229
230 var i, // The loop counter.
231 k, // The member key.
232 v, // The member value.
233 length,
234 mind = gap,
235 partial,
236 value = holder[key];
237
238// If the value has a toJSON method, call it to obtain a replacement value.
239
240 if (value && typeof value === 'object' &&
241 typeof value.toJSON === 'function') {
242 value = value.toJSON(key);
243 }
244
245// If we were called with a replacer function, then call the replacer to
246// obtain a replacement value.
247
248 if (typeof rep === 'function') {
249 value = rep.call(holder, key, value);
250 }
251
252// What happens next depends on the value's type.
253
254 switch (typeof value) {
255 case 'string':
256 return quote(value);
257
258 case 'number':
259
260// JSON numbers must be finite. Encode non-finite numbers as null.
261
262 return isFinite(value) ? String(value) : 'null';
263
264 case 'boolean':
265 case 'null':
266
267// If the value is a boolean or null, convert it to a string. Note:
268// typeof null does not produce 'null'. The case is included here in
269// the remote chance that this gets fixed someday.
270
271 return String(value);
272
273// If the type is 'object', we might be dealing with an object or an array or
274// null.
275
276 case 'object':
277
278// Due to a specification blunder in ECMAScript, typeof null is 'object',
279// so watch out for that case.
280
281 if (!value) {
282 return 'null';
283 }
284
285// Make an array to hold the partial results of stringifying this object value.
286
287 gap += indent;
288 partial = [];
289
290// If the object has a dontEnum length property, we'll treat it as an array.
291
292 if (typeof value.length === 'number' &&
293 !value.propertyIsEnumerable('length')) {
294
295// The object is an array. Stringify every element. Use null as a placeholder
296// for non-JSON values.
297
298 length = value.length;
299 for (i = 0; i < length; i += 1) {
300 partial[i] = str(i, value) || 'null';
301 }
302
303// Join all of the elements together, separated with commas, and wrap them in
304// brackets.
305
306 v = partial.length === 0 ? '[]' :
307 gap ? '[\n' + gap +
308 partial.join(',\n' + gap) + '\n' +
309 mind + ']' :
310 '[' + partial.join(',') + ']';
311 gap = mind;
312 return v;
313 }
314
315// If the replacer is an array, use it to select the members to be stringified.
316
317 if (rep && typeof rep === 'object') {
318 length = rep.length;
319 for (i = 0; i < length; i += 1) {
320 k = rep[i];
321 if (typeof k === 'string') {
322 v = str(k, value);
323 if (v) {
324 partial.push(quote(k) + (gap ? ': ' : ':') + v);
325 }
326 }
327 }
328 } else {
329
330// Otherwise, iterate through all of the keys in the object.
331
332 for (k in value) {
333 if (Object.hasOwnProperty.call(value, k)) {
334 v = str(k, value);
335 if (v) {
336 partial.push(quote(k) + (gap ? ': ' : ':') + v);
337 }
338 }
339 }
340 }
341
342// Join all of the member texts together, separated with commas,
343// and wrap them in braces.
344
345 v = partial.length === 0 ? '{}' :
346 gap ? '{\n' + gap + partial.join(',\n' + gap) + '\n' +
347 mind + '}' : '{' + partial.join(',') + '}';
348 gap = mind;
349 return v;
350 }
351 }
352
353// If the JSON object does not yet have a stringify method, give it one.
354
355 if (typeof JSON2.stringify !== 'function') {
356 JSON2.stringify = function (value, replacer, space) {
357
358// The stringify method takes a value and an optional replacer, and an optional
359// space parameter, and returns a JSON text. The replacer can be a function
360// that can replace values, or an array of strings that will select the keys.
361// A default replacer method can be provided. Use of the space parameter can
362// produce text that is more easily readable.
363
364 var i;
365 gap = '';
366 indent = '';
367
368// If the space parameter is a number, make an indent string containing that
369// many spaces.
370
371 if (typeof space === 'number') {
372 for (i = 0; i < space; i += 1) {
373 indent += ' ';
374 }
375
376// If the space parameter is a string, it will be used as the indent string.
377
378 } else if (typeof space === 'string') {
379 indent = space;
380 }
381
382// If there is a replacer, it must be a function or an array.
383// Otherwise, throw an error.
384
385 rep = replacer;
386 if (replacer && typeof replacer !== 'function' &&
387 (typeof replacer !== 'object' ||
388 typeof replacer.length !== 'number')) {
389 throw new Error('JSON2.stringify');
390 }
391
392// Make a fake root object containing our value under the key of ''.
393// Return the result of stringifying the value.
394
395 return str('', {'': value});
396 };
397 }
398
399
400// If the JSON object does not yet have a parse method, give it one.
401
402 if (typeof JSON2.parse !== 'function') {
403 JSON2.parse = function (text, reviver) {
404
405// The parse method takes a text and an optional reviver function, and returns
406// a JavaScript value if the text is a valid JSON text.
407
408 var j;
409
410 function walk(holder, key) {
411
412// The walk method is used to recursively walk the resulting structure so
413// that modifications can be made.
414
415 var k, v, value = holder[key];
416 if (value && typeof value === 'object') {
417 for (k in value) {
418 if (Object.hasOwnProperty.call(value, k)) {
419 v = walk(value, k);
420 if (v !== undefined) {
421 value[k] = v;
422 } else {
423 delete value[k];
424 }
425 }
426 }
427 }
428 return reviver.call(holder, key, value);
429 }
430
431
432// Parsing happens in four stages. In the first stage, we replace certain
433// Unicode characters with escape sequences. JavaScript handles many characters
434// incorrectly, either silently deleting them, or treating them as line endings.
435
436 cx.lastIndex = 0;
437 if (cx.test(text)) {
438 text = text.replace(cx, function (a) {
439 return '\\u' +
440 ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
441 });
442 }
443
444// In the second stage, we run the text against regular expressions that look
445// for non-JSON patterns. We are especially concerned with '()' and 'new'
446// because they can cause invocation, and '=' because it can cause mutation.
447// But just to be safe, we want to reject all unexpected forms.
448
449// We split the second stage into 4 regexp operations in order to work around
450// crippling inefficiencies in IE's and Safari's regexp engines. First we
451// replace the JSON backslash pairs with '@' (a non-JSON character). Second, we
452// replace all simple value tokens with ']' characters. Third, we delete all
453// open brackets that follow a colon or comma or that begin the text. Finally,
454// we look to see that the remaining characters are only whitespace or ']' or
455// ',' or ':' or '{' or '}'. If that is so, then the text is safe for eval.
456
457 if (/^[\],:{}\s]*$/.
458test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@').
459replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']').
460replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) {
461
462// In the third stage we use the eval function to compile the text into a
463// JavaScript structure. The '{' operator is subject to a syntactic ambiguity
464// in JavaScript: it can begin a block or an object literal. We wrap the text
465// in parens to eliminate the ambiguity.
466
467 j = eval('(' + text + ')');
468
469// In the optional fourth stage, we recursively walk the new structure, passing
470// each name/value pair to a reviver function for possible transformation.
471
472 return typeof reviver === 'function' ?
473 walk({'': j}, '') : j;
474 }
475
476// If the text is not JSON parseable, then a SyntaxError is thrown.
477
478 throw new SyntaxError('JSON2.parse');
479 };
480 }
481})(); \ No newline at end of file
diff --git a/frontend/beta/js/MochiKit/Async.js b/frontend/beta/js/MochiKit/Async.js
new file mode 100644
index 0000000..7f575aa
--- a/dev/null
+++ b/frontend/beta/js/MochiKit/Async.js
@@ -0,0 +1,683 @@
1/***
2
3MochiKit.Async 1.4
4
5See <http://mochikit.com/> for documentation, downloads, license, etc.
6
7(c) 2005 Bob Ippolito. All rights Reserved.
8
9***/
10
11if (typeof(dojo) != 'undefined') {
12 dojo.provide("MochiKit.Async");
13 dojo.require("MochiKit.Base");
14}
15if (typeof(JSAN) != 'undefined') {
16 JSAN.use("MochiKit.Base", []);
17}
18
19try {
20 if (typeof(MochiKit.Base) == 'undefined') {
21 throw "";
22 }
23} catch (e) {
24 throw "MochiKit.Async depends on MochiKit.Base!";
25}
26
27if (typeof(MochiKit.Async) == 'undefined') {
28 MochiKit.Async = {};
29}
30
31MochiKit.Async.NAME = "MochiKit.Async";
32MochiKit.Async.VERSION = "1.4";
33MochiKit.Async.__repr__ = function () {
34 return "[" + this.NAME + " " + this.VERSION + "]";
35};
36MochiKit.Async.toString = function () {
37 return this.__repr__();
38};
39
40/** @id MochiKit.Async.Deferred */
41MochiKit.Async.Deferred = function (/* optional */ canceller) {
42 this.chain = [];
43 this.id = this._nextId();
44 this.fired = -1;
45 this.paused = 0;
46 this.results = [null, null];
47 this.canceller = canceller;
48 this.silentlyCancelled = false;
49 this.chained = false;
50};
51
52MochiKit.Async.Deferred.prototype = {
53 /** @id MochiKit.Async.Deferred.prototype.repr */
54 repr: function () {
55 var state;
56 if (this.fired == -1) {
57 state = 'unfired';
58 } else if (this.fired === 0) {
59 state = 'success';
60 } else {
61 state = 'error';
62 }
63 return 'Deferred(' + this.id + ', ' + state + ')';
64 },
65
66 toString: MochiKit.Base.forwardCall("repr"),
67
68 _nextId: MochiKit.Base.counter(),
69
70 /** @id MochiKit.Async.Deferred.prototype.cancel */
71 cancel: function () {
72 var self = MochiKit.Async;
73 if (this.fired == -1) {
74 if (this.canceller) {
75 this.canceller(this);
76 } else {
77 this.silentlyCancelled = true;
78 }
79 if (this.fired == -1) {
80 this.errback(new self.CancelledError(this));
81 }
82 } else if ((this.fired === 0) && (this.results[0] instanceof self.Deferred)) {
83 this.results[0].cancel();
84 }
85 },
86
87 _resback: function (res) {
88 /***
89
90 The primitive that means either callback or errback
91
92 ***/
93 this.fired = ((res instanceof Error) ? 1 : 0);
94 this.results[this.fired] = res;
95 this._fire();
96 },
97
98 _check: function () {
99 if (this.fired != -1) {
100 if (!this.silentlyCancelled) {
101 throw new MochiKit.Async.AlreadyCalledError(this);
102 }
103 this.silentlyCancelled = false;
104 return;
105 }
106 },
107
108 /** @id MochiKit.Async.Deferred.prototype.callback */
109 callback: function (res) {
110 this._check();
111 if (res instanceof MochiKit.Async.Deferred) {
112 throw new Error("Deferred instances can only be chained if they are the result of a callback");
113 }
114 this._resback(res);
115 },
116
117 /** @id MochiKit.Async.Deferred.prototype.errback */
118 errback: function (res) {
119 this._check();
120 var self = MochiKit.Async;
121 if (res instanceof self.Deferred) {
122 throw new Error("Deferred instances can only be chained if they are the result of a callback");
123 }
124 if (!(res instanceof Error)) {
125 res = new self.GenericError(res);
126 }
127 this._resback(res);
128 },
129
130 /** @id MochiKit.Async.Deferred.prototype.addBoth */
131 addBoth: function (fn) {
132 if (arguments.length > 1) {
133 fn = MochiKit.Base.partial.apply(null, arguments);
134 }
135 return this.addCallbacks(fn, fn);
136 },
137
138 /** @id MochiKit.Async.Deferred.prototype.addCallback */
139 addCallback: function (fn) {
140 if (arguments.length > 1) {
141 fn = MochiKit.Base.partial.apply(null, arguments);
142 }
143 return this.addCallbacks(fn, null);
144 },
145
146 /** @id MochiKit.Async.Deferred.prototype.addErrback */
147 addErrback: function (fn) {
148 if (arguments.length > 1) {
149 fn = MochiKit.Base.partial.apply(null, arguments);
150 }
151 return this.addCallbacks(null, fn);
152 },
153
154 /** @id MochiKit.Async.Deferred.prototype.addCallbacks */
155 addCallbacks: function (cb, eb) {
156 if (this.chained) {
157 throw new Error("Chained Deferreds can not be re-used");
158 }
159 this.chain.push([cb, eb]);
160 if (this.fired >= 0) {
161 this._fire();
162 }
163 return this;
164 },
165
166 _fire: function () {
167 /***
168
169 Used internally to exhaust the callback sequence when a result
170 is available.
171
172 ***/
173 var chain = this.chain;
174 var fired = this.fired;
175 var res = this.results[fired];
176 var self = this;
177 var cb = null;
178 while (chain.length > 0 && this.paused === 0) {
179 // Array
180 var pair = chain.shift();
181 var f = pair[fired];
182 if (f === null) {
183 continue;
184 }
185 try {
186 res = f(res);
187 fired = ((res instanceof Error) ? 1 : 0);
188 if (res instanceof MochiKit.Async.Deferred) {
189 cb = function (res) {
190 self._resback(res);
191 self.paused--;
192 if ((self.paused === 0) && (self.fired >= 0)) {
193 self._fire();
194 }
195 };
196 this.paused++;
197 }
198 } catch (err) {
199 fired = 1;
200 if (!(err instanceof Error)) {
201 err = new MochiKit.Async.GenericError(err);
202 }
203 res = err;
204 }
205 }
206 this.fired = fired;
207 this.results[fired] = res;
208 if (cb && this.paused) {
209 // this is for "tail recursion" in case the dependent deferred
210 // is already fired
211 res.addBoth(cb);
212 res.chained = true;
213 }
214 }
215};
216
217MochiKit.Base.update(MochiKit.Async, {
218 /** @id MochiKit.Async.evalJSONRequest */
219 evalJSONRequest: function (/* req */) {
220 return eval('(' + arguments[0].responseText + ')');
221 },
222
223 /** @id MochiKit.Async.succeed */
224 succeed: function (/* optional */result) {
225 var d = new MochiKit.Async.Deferred();
226 d.callback.apply(d, arguments);
227 return d;
228 },
229
230 /** @id MochiKit.Async.fail */
231 fail: function (/* optional */result) {
232 var d = new MochiKit.Async.Deferred();
233 d.errback.apply(d, arguments);
234 return d;
235 },
236
237 /** @id MochiKit.Async.getXMLHttpRequest */
238 getXMLHttpRequest: function () {
239 var self = arguments.callee;
240 if (!self.XMLHttpRequest) {
241 var tryThese = [
242 function () { return new XMLHttpRequest(); },
243 function () { return new ActiveXObject('Msxml2.XMLHTTP'); },
244 function () { return new ActiveXObject('Microsoft.XMLHTTP'); },
245 function () { return new ActiveXObject('Msxml2.XMLHTTP.4.0'); },
246 function () {
247 throw new MochiKit.Async.BrowserComplianceError("Browser does not support XMLHttpRequest");
248 }
249 ];
250 for (var i = 0; i < tryThese.length; i++) {
251 var func = tryThese[i];
252 try {
253 self.XMLHttpRequest = func;
254 return func();
255 } catch (e) {
256 // pass
257 }
258 }
259 }
260 return self.XMLHttpRequest();
261 },
262
263 _xhr_onreadystatechange: function (d) {
264 // MochiKit.Logging.logDebug('this.readyState', this.readyState);
265 var m = MochiKit.Base;
266 if (this.readyState == 4) {
267 // IE SUCKS
268 try {
269 this.onreadystatechange = null;
270 } catch (e) {
271 try {
272 this.onreadystatechange = m.noop;
273 } catch (e) {
274 }
275 }
276 var status = null;
277 try {
278 status = this.status;
279 if (!status && m.isNotEmpty(this.responseText)) {
280 // 0 or undefined seems to mean cached or local
281 status = 304;
282 }
283 } catch (e) {
284 // pass
285 // MochiKit.Logging.logDebug('error getting status?', repr(items(e)));
286 }
287 // 200 is OK, 201 is CREATED, 204 is NO CONTENT
288 // 304 is NOT MODIFIED, 1223 is apparently a bug in IE
289 if (status == 200 || status == 201 || status == 204 ||
290 status == 304 || status == 1223) {
291 d.callback(this);
292 } else {
293 var err = new MochiKit.Async.XMLHttpRequestError(this, "Request failed");
294 if (err.number) {
295 // XXX: This seems to happen on page change
296 d.errback(err);
297 } else {
298 // XXX: this seems to happen when the server is unreachable
299 d.errback(err);
300 }
301 }
302 }
303 },
304
305 _xhr_canceller: function (req) {
306 // IE SUCKS
307 try {
308 req.onreadystatechange = null;
309 } catch (e) {
310 try {
311 req.onreadystatechange = MochiKit.Base.noop;
312 } catch (e) {
313 }
314 }
315 req.abort();
316 },
317
318
319 /** @id MochiKit.Async.sendXMLHttpRequest */
320 sendXMLHttpRequest: function (req, /* optional */ sendContent) {
321 if (typeof(sendContent) == "undefined" || sendContent === null) {
322 sendContent = "";
323 }
324
325 var m = MochiKit.Base;
326 var self = MochiKit.Async;
327 var d = new self.Deferred(m.partial(self._xhr_canceller, req));
328
329 try {
330 req.onreadystatechange = m.bind(self._xhr_onreadystatechange,
331 req, d);
332 req.send(sendContent);
333 } catch (e) {
334 try {
335 req.onreadystatechange = null;
336 } catch (ignore) {
337 // pass
338 }
339 d.errback(e);
340 }
341
342 return d;
343
344 },
345
346 /** @id MochiKit.Async.doXHR */
347 doXHR: function (url, opts) {
348 var m = MochiKit.Base;
349 opts = m.update({
350 method: 'GET',
351 sendContent: ''
352 /*
353 queryString: undefined,
354 username: undefined,
355 password: undefined,
356 headers: undefined,
357 mimeType: undefined
358 */
359 }, opts);
360 var self = MochiKit.Async;
361 var req = self.getXMLHttpRequest();
362 if (opts.queryString) {
363 var qs = m.queryString(opts.queryString);
364 if (qs) {
365 url += "?" + qs;
366 }
367 }
368 req.open(opts.method, url, true, opts.username, opts.password);
369 if (req.overrideMimeType && opts.mimeType) {
370 req.overrideMimeType(opts.mimeType);
371 }
372 if (opts.headers) {
373 var headers = opts.headers;
374 if (!m.isArrayLike(headers)) {
375 headers = m.items(headers);
376 }
377 for (var i = 0; i < headers.length; i++) {
378 var header = headers[i];
379 var name = header[0];
380 var value = header[1];
381 req.setRequestHeader(name, value);
382 }
383 }
384 return self.sendXMLHttpRequest(req, opts.sendContent);
385 },
386
387 _buildURL: function (url/*, ...*/) {
388 if (arguments.length > 1) {
389 var m = MochiKit.Base;
390 var qs = m.queryString.apply(null, m.extend(null, arguments, 1));
391 if (qs) {
392 return url + "?" + qs;
393 }
394 }
395 return url;
396 },
397
398 /** @id MochiKit.Async.doSimpleXMLHttpRequest */
399 doSimpleXMLHttpRequest: function (url/*, ...*/) {
400 var self = MochiKit.Async;
401 url = self._buildURL.apply(self, arguments);
402 return self.doXHR(url);
403 },
404
405 /** @id MochiKit.Async.loadJSONDoc */
406 loadJSONDoc: function (url/*, ...*/) {
407 var self = MochiKit.Async;
408 url = self._buildURL.apply(self, arguments);
409 var d = self.doXHR(url, {
410 'mimeType': 'text/plain',
411 'headers': [['Accept', 'application/json']]
412 });
413 d = d.addCallback(self.evalJSONRequest);
414 return d;
415 },
416
417 /** @id MochiKit.Async.wait */
418 wait: function (seconds, /* optional */value) {
419 var d = new MochiKit.Async.Deferred();
420 var m = MochiKit.Base;
421 if (typeof(value) != 'undefined') {
422 d.addCallback(function () { return value; });
423 }
424 var timeout = setTimeout(
425 m.bind("callback", d),
426 Math.floor(seconds * 1000));
427 d.canceller = function () {
428 try {
429 clearTimeout(timeout);
430 } catch (e) {
431 // pass
432 }
433 };
434 return d;
435 },
436
437 /** @id MochiKit.Async.callLater */
438 callLater: function (seconds, func) {
439 var m = MochiKit.Base;
440 var pfunc = m.partial.apply(m, m.extend(null, arguments, 1));
441 return MochiKit.Async.wait(seconds).addCallback(
442 function (res) { return pfunc(); }
443 );
444 }
445});
446
447
448/** @id MochiKit.Async.DeferredLock */
449MochiKit.Async.DeferredLock = function () {
450 this.waiting = [];
451 this.locked = false;
452 this.id = this._nextId();
453};
454
455MochiKit.Async.DeferredLock.prototype = {
456 __class__: MochiKit.Async.DeferredLock,
457 /** @id MochiKit.Async.DeferredLock.prototype.acquire */
458 acquire: function () {
459 var d = new MochiKit.Async.Deferred();
460 if (this.locked) {
461 this.waiting.push(d);
462 } else {
463 this.locked = true;
464 d.callback(this);
465 }
466 return d;
467 },
468 /** @id MochiKit.Async.DeferredLock.prototype.release */
469 release: function () {
470 if (!this.locked) {
471 throw TypeError("Tried to release an unlocked DeferredLock");
472 }
473 this.locked = false;
474 if (this.waiting.length > 0) {
475 this.locked = true;
476 this.waiting.shift().callback(this);
477 }
478 },
479 _nextId: MochiKit.Base.counter(),
480 repr: function () {
481 var state;
482 if (this.locked) {
483 state = 'locked, ' + this.waiting.length + ' waiting';
484 } else {
485 state = 'unlocked';
486 }
487 return 'DeferredLock(' + this.id + ', ' + state + ')';
488 },
489 toString: MochiKit.Base.forwardCall("repr")
490
491};
492
493/** @id MochiKit.Async.DeferredList */
494MochiKit.Async.DeferredList = function (list, /* optional */fireOnOneCallback, fireOnOneErrback, consumeErrors, canceller) {
495
496 // call parent constructor
497 MochiKit.Async.Deferred.apply(this, [canceller]);
498
499 this.list = list;
500 var resultList = [];
501 this.resultList = resultList;
502
503 this.finishedCount = 0;
504 this.fireOnOneCallback = fireOnOneCallback;
505 this.fireOnOneErrback = fireOnOneErrback;
506 this.consumeErrors = consumeErrors;
507
508 var cb = MochiKit.Base.bind(this._cbDeferred, this);
509 for (var i = 0; i < list.length; i++) {
510 var d = list[i];
511 resultList.push(undefined);
512 d.addCallback(cb, i, true);
513 d.addErrback(cb, i, false);
514 }
515
516 if (list.length === 0 && !fireOnOneCallback) {
517 this.callback(this.resultList);
518 }
519
520};
521
522MochiKit.Async.DeferredList.prototype = new MochiKit.Async.Deferred();
523
524MochiKit.Async.DeferredList.prototype._cbDeferred = function (index, succeeded, result) {
525 this.resultList[index] = [succeeded, result];
526 this.finishedCount += 1;
527 if (this.fired == -1) {
528 if (succeeded && this.fireOnOneCallback) {
529 this.callback([index, result]);
530 } else if (!succeeded && this.fireOnOneErrback) {
531 this.errback(result);
532 } else if (this.finishedCount == this.list.length) {
533 this.callback(this.resultList);
534 }
535 }
536 if (!succeeded && this.consumeErrors) {
537 result = null;
538 }
539 return result;
540};
541
542/** @id MochiKit.Async.gatherResults */
543MochiKit.Async.gatherResults = function (deferredList) {
544 var d = new MochiKit.Async.DeferredList(deferredList, false, true, false);
545 d.addCallback(function (results) {
546 var ret = [];
547 for (var i = 0; i < results.length; i++) {
548 ret.push(results[i][1]);
549 }
550 return ret;
551 });
552 return d;
553};
554
555/** @id MochiKit.Async.maybeDeferred */
556MochiKit.Async.maybeDeferred = function (func) {
557 var self = MochiKit.Async;
558 var result;
559 try {
560 var r = func.apply(null, MochiKit.Base.extend([], arguments, 1));
561 if (r instanceof self.Deferred) {
562 result = r;
563 } else if (r instanceof Error) {
564 result = self.fail(r);
565 } else {
566 result = self.succeed(r);
567 }
568 } catch (e) {
569 result = self.fail(e);
570 }
571 return result;
572};
573
574
575MochiKit.Async.EXPORT = [
576 "AlreadyCalledError",
577 "CancelledError",
578 "BrowserComplianceError",
579 "GenericError",
580 "XMLHttpRequestError",
581 "Deferred",
582 "succeed",
583 "fail",
584 "getXMLHttpRequest",
585 "doSimpleXMLHttpRequest",
586 "loadJSONDoc",
587 "wait",
588 "callLater",
589 "sendXMLHttpRequest",
590 "DeferredLock",
591 "DeferredList",
592 "gatherResults",
593 "maybeDeferred",
594 "doXHR"
595];
596
597MochiKit.Async.EXPORT_OK = [
598 "evalJSONRequest"
599];
600
601MochiKit.Async.__new__ = function () {
602 var m = MochiKit.Base;
603 var ne = m.partial(m._newNamedError, this);
604
605 ne("AlreadyCalledError",
606 /** @id MochiKit.Async.AlreadyCalledError */
607 function (deferred) {
608 /***
609
610 Raised by the Deferred if callback or errback happens
611 after it was already fired.
612
613 ***/
614 this.deferred = deferred;
615 }
616 );
617
618 ne("CancelledError",
619 /** @id MochiKit.Async.CancelledError */
620 function (deferred) {
621 /***
622
623 Raised by the Deferred cancellation mechanism.
624
625 ***/
626 this.deferred = deferred;
627 }
628 );
629
630 ne("BrowserComplianceError",
631 /** @id MochiKit.Async.BrowserComplianceError */
632 function (msg) {
633 /***
634
635 Raised when the JavaScript runtime is not capable of performing
636 the given function. Technically, this should really never be
637 raised because a non-conforming JavaScript runtime probably
638 isn't going to support exceptions in the first place.
639
640 ***/
641 this.message = msg;
642 }
643 );
644
645 ne("GenericError",
646 /** @id MochiKit.Async.GenericError */
647 function (msg) {
648 this.message = msg;
649 }
650 );
651
652 ne("XMLHttpRequestError",
653 /** @id MochiKit.Async.XMLHttpRequestError */
654 function (req, msg) {
655 /***
656
657 Raised when an XMLHttpRequest does not complete for any reason.
658
659 ***/
660 this.req = req;
661 this.message = msg;
662 try {
663 // Strange but true that this can raise in some cases.
664 this.number = req.status;
665 } catch (e) {
666 // pass
667 }
668 }
669 );
670
671
672 this.EXPORT_TAGS = {
673 ":common": this.EXPORT,
674 ":all": m.concat(this.EXPORT, this.EXPORT_OK)
675 };
676
677 m.nameFunctions(this);
678
679};
680
681MochiKit.Async.__new__();
682
683MochiKit.Base._exportSymbols(this, MochiKit.Async);
diff --git a/frontend/beta/js/MochiKit/Base.js b/frontend/beta/js/MochiKit/Base.js
new file mode 100644
index 0000000..67f4499
--- a/dev/null
+++ b/frontend/beta/js/MochiKit/Base.js
@@ -0,0 +1,1403 @@
1/***
2
3MochiKit.Base 1.4
4
5See <http://mochikit.com/> for documentation, downloads, license, etc.
6
7(c) 2005 Bob Ippolito. All rights Reserved.
8
9***/
10
11if (typeof(dojo) != 'undefined') {
12 dojo.provide("MochiKit.Base");
13}
14if (typeof(MochiKit) == 'undefined') {
15 MochiKit = {};
16}
17if (typeof(MochiKit.Base) == 'undefined') {
18 MochiKit.Base = {};
19}
20if (typeof(MochiKit.__export__) == "undefined") {
21 MochiKit.__export__ = (MochiKit.__compat__ ||
22 (typeof(JSAN) == 'undefined' && typeof(dojo) == 'undefined')
23 );
24}
25
26MochiKit.Base.VERSION = "1.4";
27MochiKit.Base.NAME = "MochiKit.Base";
28/** @id MochiKit.Base.update */
29MochiKit.Base.update = function (self, obj/*, ... */) {
30 if (self === null) {
31 self = {};
32 }
33 for (var i = 1; i < arguments.length; i++) {
34 var o = arguments[i];
35 if (typeof(o) != 'undefined' && o !== null) {
36 for (var k in o) {
37 self[k] = o[k];
38 }
39 }
40 }
41 return self;
42};
43
44MochiKit.Base.update(MochiKit.Base, {
45 __repr__: function () {
46 return "[" + this.NAME + " " + this.VERSION + "]";
47 },
48
49 toString: function () {
50 return this.__repr__();
51 },
52
53 /** @id MochiKit.Base.camelize */
54 camelize: function (selector) {
55 /* from dojo.style.toCamelCase */
56 var arr = selector.split('-');
57 var cc = arr[0];
58 for (var i = 1; i < arr.length; i++) {
59 cc += arr[i].charAt(0).toUpperCase() + arr[i].substring(1);
60 }
61 return cc;
62 },
63
64 /** @id MochiKit.Base.counter */
65 counter: function (n/* = 1 */) {
66 if (arguments.length === 0) {
67 n = 1;
68 }
69 return function () {
70 return n++;
71 };
72 },
73
74 /** @id MochiKit.Base.clone */
75 clone: function (obj) {
76 var me = arguments.callee;
77 if (arguments.length == 1) {
78 me.prototype = obj;
79 return new me();
80 }
81 },
82
83 _flattenArray: function (res, lst) {
84 for (var i = 0; i < lst.length; i++) {
85 var o = lst[i];
86 if (o instanceof Array) {
87 arguments.callee(res, o);
88 } else {
89 res.push(o);
90 }
91 }
92 return res;
93 },
94
95 /** @id MochiKit.Base.flattenArray */
96 flattenArray: function (lst) {
97 return MochiKit.Base._flattenArray([], lst);
98 },
99
100 /** @id MochiKit.Base.flattenArguments */
101 flattenArguments: function (lst/* ...*/) {
102 var res = [];
103 var m = MochiKit.Base;
104 var args = m.extend(null, arguments);
105 while (args.length) {
106 var o = args.shift();
107 if (o && typeof(o) == "object" && typeof(o.length) == "number") {
108 for (var i = o.length - 1; i >= 0; i--) {
109 args.unshift(o[i]);
110 }
111 } else {
112 res.push(o);
113 }
114 }
115 return res;
116 },
117
118 /** @id MochiKit.Base.extend */
119 extend: function (self, obj, /* optional */skip) {
120 // Extend an array with an array-like object starting
121 // from the skip index
122 if (!skip) {
123 skip = 0;
124 }
125 if (obj) {
126 // allow iterable fall-through, but skip the full isArrayLike
127 // check for speed, this is called often.
128 var l = obj.length;
129 if (typeof(l) != 'number' /* !isArrayLike(obj) */) {
130 if (typeof(MochiKit.Iter) != "undefined") {
131 obj = MochiKit.Iter.list(obj);
132 l = obj.length;
133 } else {
134 throw new TypeError("Argument not an array-like and MochiKit.Iter not present");
135 }
136 }
137 if (!self) {
138 self = [];
139 }
140 for (var i = skip; i < l; i++) {
141 self.push(obj[i]);
142 }
143 }
144 // This mutates, but it's convenient to return because
145 // it's often used like a constructor when turning some
146 // ghetto array-like to a real array
147 return self;
148 },
149
150
151 /** @id MochiKit.Base.updatetree */
152 updatetree: function (self, obj/*, ...*/) {
153 if (self === null) {
154 self = {};
155 }
156 for (var i = 1; i < arguments.length; i++) {
157 var o = arguments[i];
158 if (typeof(o) != 'undefined' && o !== null) {
159 for (var k in o) {
160 var v = o[k];
161 if (typeof(self[k]) == 'object' && typeof(v) == 'object') {
162 arguments.callee(self[k], v);
163 } else {
164 self[k] = v;
165 }
166 }
167 }
168 }
169 return self;
170 },
171
172 /** @id MochiKit.Base.setdefault */
173 setdefault: function (self, obj/*, ...*/) {
174 if (self === null) {
175 self = {};
176 }
177 for (var i = 1; i < arguments.length; i++) {
178 var o = arguments[i];
179 for (var k in o) {
180 if (!(k in self)) {
181 self[k] = o[k];
182 }
183 }
184 }
185 return self;
186 },
187
188 /** @id MochiKit.Base.keys */
189 keys: function (obj) {
190 var rval = [];
191 for (var prop in obj) {
192 rval.push(prop);
193 }
194 return rval;
195 },
196
197 /** @id MochiKit.Base.values */
198 values: function (obj) {
199 var rval = [];
200 for (var prop in obj) {
201 rval.push(obj[prop]);
202 }
203 return rval;
204 },
205
206 /** @id MochiKit.Base.items */
207 items: function (obj) {
208 var rval = [];
209 var e;
210 for (var prop in obj) {
211 var v;
212 try {
213 v = obj[prop];
214 } catch (e) {
215 continue;
216 }
217 rval.push([prop, v]);
218 }
219 return rval;
220 },
221
222
223 _newNamedError: function (module, name, func) {
224 func.prototype = new MochiKit.Base.NamedError(module.NAME + "." + name);
225 module[name] = func;
226 },
227
228
229 /** @id MochiKit.Base.operator */
230 operator: {
231 // unary logic operators
232 /** @id MochiKit.Base.truth */
233 truth: function (a) { return !!a; },
234 /** @id MochiKit.Base.lognot */
235 lognot: function (a) { return !a; },
236 /** @id MochiKit.Base.identity */
237 identity: function (a) { return a; },
238
239 // bitwise unary operators
240 /** @id MochiKit.Base.not */
241 not: function (a) { return ~a; },
242 /** @id MochiKit.Base.neg */
243 neg: function (a) { return -a; },
244
245 // binary operators
246 /** @id MochiKit.Base.add */
247 add: function (a, b) { return a + b; },
248 /** @id MochiKit.Base.sub */
249 sub: function (a, b) { return a - b; },
250 /** @id MochiKit.Base.div */
251 div: function (a, b) { return a / b; },
252 /** @id MochiKit.Base.mod */
253 mod: function (a, b) { return a % b; },
254 /** @id MochiKit.Base.mul */
255 mul: function (a, b) { return a * b; },
256
257 // bitwise binary operators
258 /** @id MochiKit.Base.and */
259 and: function (a, b) { return a & b; },
260 /** @id MochiKit.Base.or */
261 or: function (a, b) { return a | b; },
262 /** @id MochiKit.Base.xor */
263 xor: function (a, b) { return a ^ b; },
264 /** @id MochiKit.Base.lshift */
265 lshift: function (a, b) { return a << b; },
266 /** @id MochiKit.Base.rshift */
267 rshift: function (a, b) { return a >> b; },
268 /** @id MochiKit.Base.zrshift */
269 zrshift: function (a, b) { return a >>> b; },
270
271 // near-worthless built-in comparators
272 /** @id MochiKit.Base.eq */
273 eq: function (a, b) { return a == b; },
274 /** @id MochiKit.Base.ne */
275 ne: function (a, b) { return a != b; },
276 /** @id MochiKit.Base.gt */
277 gt: function (a, b) { return a > b; },
278 /** @id MochiKit.Base.ge */
279 ge: function (a, b) { return a >= b; },
280 /** @id MochiKit.Base.lt */
281 lt: function (a, b) { return a < b; },
282 /** @id MochiKit.Base.le */
283 le: function (a, b) { return a <= b; },
284
285 // strict built-in comparators
286 seq: function (a, b) { return a === b; },
287 sne: function (a, b) { return a !== b; },
288
289 // compare comparators
290 /** @id MochiKit.Base.ceq */
291 ceq: function (a, b) { return MochiKit.Base.compare(a, b) === 0; },
292 /** @id MochiKit.Base.cne */
293 cne: function (a, b) { return MochiKit.Base.compare(a, b) !== 0; },
294 /** @id MochiKit.Base.cgt */
295 cgt: function (a, b) { return MochiKit.Base.compare(a, b) == 1; },
296 /** @id MochiKit.Base.cge */
297 cge: function (a, b) { return MochiKit.Base.compare(a, b) != -1; },
298 /** @id MochiKit.Base.clt */
299 clt: function (a, b) { return MochiKit.Base.compare(a, b) == -1; },
300 /** @id MochiKit.Base.cle */
301 cle: function (a, b) { return MochiKit.Base.compare(a, b) != 1; },
302
303 // binary logical operators
304 /** @id MochiKit.Base.logand */
305 logand: function (a, b) { return a && b; },
306 /** @id MochiKit.Base.logor */
307 logor: function (a, b) { return a || b; },
308 /** @id MochiKit.Base.contains */
309 contains: function (a, b) { return b in a; }
310 },
311
312 /** @id MochiKit.Base.forwardCall */
313 forwardCall: function (func) {
314 return function () {
315 return this[func].apply(this, arguments);
316 };
317 },
318
319 /** @id MochiKit.Base.itemgetter */
320 itemgetter: function (func) {
321 return function (arg) {
322 return arg[func];
323 };
324 },
325
326 /** @id MochiKit.Base.typeMatcher */
327 typeMatcher: function (/* typ */) {
328 var types = {};
329 for (var i = 0; i < arguments.length; i++) {
330 var typ = arguments[i];
331 types[typ] = typ;
332 }
333 return function () {
334 for (var i = 0; i < arguments.length; i++) {
335 if (!(typeof(arguments[i]) in types)) {
336 return false;
337 }
338 }
339 return true;
340 };
341 },
342
343 /** @id MochiKit.Base.isNull */
344 isNull: function (/* ... */) {
345 for (var i = 0; i < arguments.length; i++) {
346 if (arguments[i] !== null) {
347 return false;
348 }
349 }
350 return true;
351 },
352
353 /** @id MochiKit.Base.isUndefinedOrNull */
354 isUndefinedOrNull: function (/* ... */) {
355 for (var i = 0; i < arguments.length; i++) {
356 var o = arguments[i];
357 if (!(typeof(o) == 'undefined' || o === null)) {
358 return false;
359 }
360 }
361 return true;
362 },
363
364 /** @id MochiKit.Base.isEmpty */
365 isEmpty: function (obj) {
366 return !MochiKit.Base.isNotEmpty.apply(this, arguments);
367 },
368
369 /** @id MochiKit.Base.isNotEmpty */
370 isNotEmpty: function (obj) {
371 for (var i = 0; i < arguments.length; i++) {
372 var o = arguments[i];
373 if (!(o && o.length)) {
374 return false;
375 }
376 }
377 return true;
378 },
379
380 /** @id MochiKit.Base.isArrayLike */
381 isArrayLike: function () {
382 for (var i = 0; i < arguments.length; i++) {
383 var o = arguments[i];
384 var typ = typeof(o);
385 if (
386 (typ != 'object' && !(typ == 'function' && typeof(o.item) == 'function')) ||
387 o === null ||
388 typeof(o.length) != 'number' ||
389 o.nodeType === 3
390 ) {
391 return false;
392 }
393 }
394 return true;
395 },
396
397 /** @id MochiKit.Base.isDateLike */
398 isDateLike: function () {
399 for (var i = 0; i < arguments.length; i++) {
400 var o = arguments[i];
401 if (typeof(o) != "object" || o === null
402 || typeof(o.getTime) != 'function') {
403 return false;
404 }
405 }
406 return true;
407 },
408
409
410 /** @id MochiKit.Base.xmap */
411 xmap: function (fn/*, obj... */) {
412 if (fn === null) {
413 return MochiKit.Base.extend(null, arguments, 1);
414 }
415 var rval = [];
416 for (var i = 1; i < arguments.length; i++) {
417 rval.push(fn(arguments[i]));
418 }
419 return rval;
420 },
421
422 /** @id MochiKit.Base.map */
423 map: function (fn, lst/*, lst... */) {
424 var m = MochiKit.Base;
425 var itr = MochiKit.Iter;
426 var isArrayLike = m.isArrayLike;
427 if (arguments.length <= 2) {
428 // allow an iterable to be passed
429 if (!isArrayLike(lst)) {
430 if (itr) {
431 // fast path for map(null, iterable)
432 lst = itr.list(lst);
433 if (fn === null) {
434 return lst;
435 }
436 } else {
437 throw new TypeError("Argument not an array-like and MochiKit.Iter not present");
438 }
439 }
440 // fast path for map(null, lst)
441 if (fn === null) {
442 return m.extend(null, lst);
443 }
444 // disabled fast path for map(fn, lst)
445 /*
446 if (false && typeof(Array.prototype.map) == 'function') {
447 // Mozilla fast-path
448 return Array.prototype.map.call(lst, fn);
449 }
450 */
451 var rval = [];
452 for (var i = 0; i < lst.length; i++) {
453 rval.push(fn(lst[i]));
454 }
455 return rval;
456 } else {
457 // default for map(null, ...) is zip(...)
458 if (fn === null) {
459 fn = Array;
460 }
461 var length = null;
462 for (i = 1; i < arguments.length; i++) {
463 // allow iterables to be passed
464 if (!isArrayLike(arguments[i])) {
465 if (itr) {
466 return itr.list(itr.imap.apply(null, arguments));
467 } else {
468 throw new TypeError("Argument not an array-like and MochiKit.Iter not present");
469 }
470 }
471 // find the minimum length
472 var l = arguments[i].length;
473 if (length === null || length > l) {
474 length = l;
475 }
476 }
477 rval = [];
478 for (i = 0; i < length; i++) {
479 var args = [];
480 for (var j = 1; j < arguments.length; j++) {
481 args.push(arguments[j][i]);
482 }
483 rval.push(fn.apply(this, args));
484 }
485 return rval;
486 }
487 },
488
489 /** @id MochiKit.Base.xfilter */
490 xfilter: function (fn/*, obj... */) {
491 var rval = [];
492 if (fn === null) {
493 fn = MochiKit.Base.operator.truth;
494 }
495 for (var i = 1; i < arguments.length; i++) {
496 var o = arguments[i];
497 if (fn(o)) {
498 rval.push(o);
499 }
500 }
501 return rval;
502 },
503
504 /** @id MochiKit.Base.filter */
505 filter: function (fn, lst, self) {
506 var rval = [];
507 // allow an iterable to be passed
508 var m = MochiKit.Base;
509 if (!m.isArrayLike(lst)) {
510 if (MochiKit.Iter) {
511 lst = MochiKit.Iter.list(lst);
512 } else {
513 throw new TypeError("Argument not an array-like and MochiKit.Iter not present");
514 }
515 }
516 if (fn === null) {
517 fn = m.operator.truth;
518 }
519 if (typeof(Array.prototype.filter) == 'function') {
520 // Mozilla fast-path
521 return Array.prototype.filter.call(lst, fn, self);
522 } else if (typeof(self) == 'undefined' || self === null) {
523 for (var i = 0; i < lst.length; i++) {
524 var o = lst[i];
525 if (fn(o)) {
526 rval.push(o);
527 }
528 }
529 } else {
530 for (i = 0; i < lst.length; i++) {
531 o = lst[i];
532 if (fn.call(self, o)) {
533 rval.push(o);
534 }
535 }
536 }
537 return rval;
538 },
539
540
541 _wrapDumbFunction: function (func) {
542 return function () {
543 // fast path!
544 switch (arguments.length) {
545 case 0: return func();
546 case 1: return func(arguments[0]);
547 case 2: return func(arguments[0], arguments[1]);
548 case 3: return func(arguments[0], arguments[1], arguments[2]);
549 }
550 var args = [];
551 for (var i = 0; i < arguments.length; i++) {
552 args.push("arguments[" + i + "]");
553 }
554 return eval("(func(" + args.join(",") + "))");
555 };
556 },
557
558 /** @id MochiKit.Base.methodcaller */
559 methodcaller: function (func/*, args... */) {
560 var args = MochiKit.Base.extend(null, arguments, 1);
561 if (typeof(func) == "function") {
562 return function (obj) {
563 return func.apply(obj, args);
564 };
565 } else {
566 return function (obj) {
567 return obj[func].apply(obj, args);
568 };
569 }
570 },
571
572 /** @id MochiKit.Base.method */
573 method: function (self, func) {
574 var m = MochiKit.Base;
575 return m.bind.apply(this, m.extend([func, self], arguments, 2));
576 },
577
578 /** @id MochiKit.Base.compose */
579 compose: function (f1, f2/*, f3, ... fN */) {
580 var fnlist = [];
581 var m = MochiKit.Base;
582 if (arguments.length === 0) {
583 throw new TypeError("compose() requires at least one argument");
584 }
585 for (var i = 0; i < arguments.length; i++) {
586 var fn = arguments[i];
587 if (typeof(fn) != "function") {
588 throw new TypeError(m.repr(fn) + " is not a function");
589 }
590 fnlist.push(fn);
591 }
592 return function () {
593 var args = arguments;
594 for (var i = fnlist.length - 1; i >= 0; i--) {
595 args = [fnlist[i].apply(this, args)];
596 }
597 return args[0];
598 };
599 },
600
601 /** @id MochiKit.Base.bind */
602 bind: function (func, self/* args... */) {
603 if (typeof(func) == "string") {
604 func = self[func];
605 }
606 var im_func = func.im_func;
607 var im_preargs = func.im_preargs;
608 var im_self = func.im_self;
609 var m = MochiKit.Base;
610 if (typeof(func) == "function" && typeof(func.apply) == "undefined") {
611 // this is for cases where JavaScript sucks ass and gives you a
612 // really dumb built-in function like alert() that doesn't have
613 // an apply
614 func = m._wrapDumbFunction(func);
615 }
616 if (typeof(im_func) != 'function') {
617 im_func = func;
618 }
619 if (typeof(self) != 'undefined') {
620 im_self = self;
621 }
622 if (typeof(im_preargs) == 'undefined') {
623 im_preargs = [];
624 } else {
625 im_preargs = im_preargs.slice();
626 }
627 m.extend(im_preargs, arguments, 2);
628 var newfunc = function () {
629 var args = arguments;
630 var me = arguments.callee;
631 if (me.im_preargs.length > 0) {
632 args = m.concat(me.im_preargs, args);
633 }
634 var self = me.im_self;
635 if (!self) {
636 self = this;
637 }
638 return me.im_func.apply(self, args);
639 };
640 newfunc.im_self = im_self;
641 newfunc.im_func = im_func;
642 newfunc.im_preargs = im_preargs;
643 return newfunc;
644 },
645
646 /** @id MochiKit.Base.bindMethods */
647 bindMethods: function (self) {
648 var bind = MochiKit.Base.bind;
649 for (var k in self) {
650 var func = self[k];
651 if (typeof(func) == 'function') {
652 self[k] = bind(func, self);
653 }
654 }
655 },
656
657 /** @id MochiKit.Base.registerComparator */
658 registerComparator: function (name, check, comparator, /* optional */ override) {
659 MochiKit.Base.comparatorRegistry.register(name, check, comparator, override);
660 },
661
662 _primitives: {'boolean': true, 'string': true, 'number': true},
663
664 /** @id MochiKit.Base.compare */
665 compare: function (a, b) {
666 if (a == b) {
667 return 0;
668 }
669 var aIsNull = (typeof(a) == 'undefined' || a === null);
670 var bIsNull = (typeof(b) == 'undefined' || b === null);
671 if (aIsNull && bIsNull) {
672 return 0;
673 } else if (aIsNull) {
674 return -1;
675 } else if (bIsNull) {
676 return 1;
677 }
678 var m = MochiKit.Base;
679 // bool, number, string have meaningful comparisons
680 var prim = m._primitives;
681 if (!(typeof(a) in prim && typeof(b) in prim)) {
682 try {
683 return m.comparatorRegistry.match(a, b);
684 } catch (e) {
685 if (e != m.NotFound) {
686 throw e;
687 }
688 }
689 }
690 if (a < b) {
691 return -1;
692 } else if (a > b) {
693 return 1;
694 }
695 // These types can't be compared
696 var repr = m.repr;
697 throw new TypeError(repr(a) + " and " + repr(b) + " can not be compared");
698 },
699
700 /** @id MochiKit.Base.compareDateLike */
701 compareDateLike: function (a, b) {
702 return MochiKit.Base.compare(a.getTime(), b.getTime());
703 },
704
705 /** @id MochiKit.Base.compareArrayLike */
706 compareArrayLike: function (a, b) {
707 var compare = MochiKit.Base.compare;
708 var count = a.length;
709 var rval = 0;
710 if (count > b.length) {
711 rval = 1;
712 count = b.length;
713 } else if (count < b.length) {
714 rval = -1;
715 }
716 for (var i = 0; i < count; i++) {
717 var cmp = compare(a[i], b[i]);
718 if (cmp) {
719 return cmp;
720 }
721 }
722 return rval;
723 },
724
725 /** @id MochiKit.Base.registerRepr */
726 registerRepr: function (name, check, wrap, /* optional */override) {
727 MochiKit.Base.reprRegistry.register(name, check, wrap, override);
728 },
729
730 /** @id MochiKit.Base.repr */
731 repr: function (o) {
732 if (typeof(o) == "undefined") {
733 return "undefined";
734 } else if (o === null) {
735 return "null";
736 }
737 try {
738 if (typeof(o.__repr__) == 'function') {
739 return o.__repr__();
740 } else if (typeof(o.repr) == 'function' && o.repr != arguments.callee) {
741 return o.repr();
742 }
743 return MochiKit.Base.reprRegistry.match(o);
744 } catch (e) {
745 if (typeof(o.NAME) == 'string' && (
746 o.toString == Function.prototype.toString ||
747 o.toString == Object.prototype.toString
748 )) {
749 return o.NAME;
750 }
751 }
752 try {
753 var ostring = (o + "");
754 } catch (e) {
755 return "[" + typeof(o) + "]";
756 }
757 if (typeof(o) == "function") {
758 o = ostring.replace(/^\s+/, "");
759 var idx = o.indexOf("{");
760 if (idx != -1) {
761 o = o.substr(0, idx) + "{...}";
762 }
763 }
764 return ostring;
765 },
766
767 /** @id MochiKit.Base.reprArrayLike */
768 reprArrayLike: function (o) {
769 var m = MochiKit.Base;
770 return "[" + m.map(m.repr, o).join(", ") + "]";
771 },
772
773 /** @id MochiKit.Base.reprString */
774 reprString: function (o) {
775 return ('"' + o.replace(/(["\\])/g, '\\$1') + '"'
776 ).replace(/[\f]/g, "\\f"
777 ).replace(/[\b]/g, "\\b"
778 ).replace(/[\n]/g, "\\n"
779 ).replace(/[\t]/g, "\\t"
780 ).replace(/[\r]/g, "\\r");
781 },
782
783 /** @id MochiKit.Base.reprNumber */
784 reprNumber: function (o) {
785 return o + "";
786 },
787
788 /** @id MochiKit.Base.registerJSON */
789 registerJSON: function (name, check, wrap, /* optional */override) {
790 MochiKit.Base.jsonRegistry.register(name, check, wrap, override);
791 },
792
793
794 /** @id MochiKit.Base.evalJSON */
795 evalJSON: function () {
796 return eval("(" + arguments[0] + ")");
797 },
798
799 /** @id MochiKit.Base.serializeJSON */
800 serializeJSON: function (o) {
801 var objtype = typeof(o);
802 if (objtype == "number" || objtype == "boolean") {
803 return o + "";
804 } else if (o === null) {
805 return "null";
806 }
807 var m = MochiKit.Base;
808 var reprString = m.reprString;
809 if (objtype == "string") {
810 return reprString(o);
811 }
812 // recurse
813 var me = arguments.callee;
814 // short-circuit for objects that support "json" serialization
815 // if they return "self" then just pass-through...
816 var newObj;
817 if (typeof(o.__json__) == "function") {
818 newObj = o.__json__();
819 if (o !== newObj) {
820 return me(newObj);
821 }
822 }
823 if (typeof(o.json) == "function") {
824 newObj = o.json();
825 if (o !== newObj) {
826 return me(newObj);
827 }
828 }
829 // array
830 if (objtype != "function" && typeof(o.length) == "number") {
831 var res = [];
832 for (var i = 0; i < o.length; i++) {
833 var val = me(o[i]);
834 if (typeof(val) != "string") {
835 val = "undefined";
836 }
837 res.push(val);
838 }
839 return "[" + res.join(", ") + "]";
840 }
841 // look in the registry
842 try {
843 newObj = m.jsonRegistry.match(o);
844 if (o !== newObj) {
845 return me(newObj);
846 }
847 } catch (e) {
848 if (e != m.NotFound) {
849 // something really bad happened
850 throw e;
851 }
852 }
853 // undefined is outside of the spec
854 if (objtype == "undefined") {
855 throw new TypeError("undefined can not be serialized as JSON");
856 }
857 // it's a function with no adapter, bad
858 if (objtype == "function") {
859 return null;
860 }
861 // generic object code path
862 res = [];
863 for (var k in o) {
864 var useKey;
865 if (typeof(k) == "number") {
866 useKey = '"' + k + '"';
867 } else if (typeof(k) == "string") {
868 useKey = reprString(k);
869 } else {
870 // skip non-string or number keys
871 continue;
872 }
873 val = me(o[k]);
874 if (typeof(val) != "string") {
875 // skip non-serializable values
876 continue;
877 }
878 res.push(useKey + ":" + val);
879 }
880 return "{" + res.join(", ") + "}";
881 },
882
883
884 /** @id MochiKit.Base.objEqual */
885 objEqual: function (a, b) {
886 return (MochiKit.Base.compare(a, b) === 0);
887 },
888
889 /** @id MochiKit.Base.arrayEqual */
890 arrayEqual: function (self, arr) {
891 if (self.length != arr.length) {
892 return false;
893 }
894 return (MochiKit.Base.compare(self, arr) === 0);
895 },
896
897 /** @id MochiKit.Base.concat */
898 concat: function (/* lst... */) {
899 var rval = [];
900 var extend = MochiKit.Base.extend;
901 for (var i = 0; i < arguments.length; i++) {
902 extend(rval, arguments[i]);
903 }
904 return rval;
905 },
906
907 /** @id MochiKit.Base.keyComparator */
908 keyComparator: function (key/* ... */) {
909 // fast-path for single key comparisons
910 var m = MochiKit.Base;
911 var compare = m.compare;
912 if (arguments.length == 1) {
913 return function (a, b) {
914 return compare(a[key], b[key]);
915 };
916 }
917 var compareKeys = m.extend(null, arguments);
918 return function (a, b) {
919 var rval = 0;
920 // keep comparing until something is inequal or we run out of
921 // keys to compare
922 for (var i = 0; (rval === 0) && (i < compareKeys.length); i++) {
923 var key = compareKeys[i];
924 rval = compare(a[key], b[key]);
925 }
926 return rval;
927 };
928 },
929
930 /** @id MochiKit.Base.reverseKeyComparator */
931 reverseKeyComparator: function (key) {
932 var comparator = MochiKit.Base.keyComparator.apply(this, arguments);
933 return function (a, b) {
934 return comparator(b, a);
935 };
936 },
937
938 /** @id MochiKit.Base.partial */
939 partial: function (func) {
940 var m = MochiKit.Base;
941 return m.bind.apply(this, m.extend([func, undefined], arguments, 1));
942 },
943
944 /** @id MochiKit.Base.listMinMax */
945 listMinMax: function (which, lst) {
946 if (lst.length === 0) {
947 return null;
948 }
949 var cur = lst[0];
950 var compare = MochiKit.Base.compare;
951 for (var i = 1; i < lst.length; i++) {
952 var o = lst[i];
953 if (compare(o, cur) == which) {
954 cur = o;
955 }
956 }
957 return cur;
958 },
959
960 /** @id MochiKit.Base.objMax */
961 objMax: function (/* obj... */) {
962 return MochiKit.Base.listMinMax(1, arguments);
963 },
964
965 /** @id MochiKit.Base.objMin */
966 objMin: function (/* obj... */) {
967 return MochiKit.Base.listMinMax(-1, arguments);
968 },
969
970 /** @id MochiKit.Base.findIdentical */
971 findIdentical: function (lst, value, start/* = 0 */, /* optional */end) {
972 if (typeof(end) == "undefined" || end === null) {
973 end = lst.length;
974 }
975 if (typeof(start) == "undefined" || start === null) {
976 start = 0;
977 }
978 for (var i = start; i < end; i++) {
979 if (lst[i] === value) {
980 return i;
981 }
982 }
983 return -1;
984 },
985
986 /** @id MochiKit.Base.mean */
987 mean: function(/* lst... */) {
988 /* http://www.nist.gov/dads/HTML/mean.html */
989 var sum = 0;
990
991 var m = MochiKit.Base;
992 var args = m.extend(null, arguments);
993 var count = args.length;
994
995 while (args.length) {
996 var o = args.shift();
997 if (o && typeof(o) == "object" && typeof(o.length) == "number") {
998 count += o.length - 1;
999 for (var i = o.length - 1; i >= 0; i--) {
1000 sum += o[i];
1001 }
1002 } else {
1003 sum += o;
1004 }
1005 }
1006
1007 if (count <= 0) {
1008 throw new TypeError('mean() requires at least one argument');
1009 }
1010
1011 return sum/count;
1012 },
1013
1014 /** @id MochiKit.Base.median */
1015 median: function(/* lst... */) {
1016 /* http://www.nist.gov/dads/HTML/median.html */
1017 var data = MochiKit.Base.flattenArguments(arguments);
1018 if (data.length === 0) {
1019 throw new TypeError('median() requires at least one argument');
1020 }
1021 data.sort(compare);
1022 if (data.length % 2 == 0) {
1023 var upper = data.length / 2;
1024 return (data[upper] + data[upper - 1]) / 2;
1025 } else {
1026 return data[(data.length - 1) / 2];
1027 }
1028 },
1029
1030 /** @id MochiKit.Base.findValue */
1031 findValue: function (lst, value, start/* = 0 */, /* optional */end) {
1032 if (typeof(end) == "undefined" || end === null) {
1033 end = lst.length;
1034 }
1035 if (typeof(start) == "undefined" || start === null) {
1036 start = 0;
1037 }
1038 var cmp = MochiKit.Base.compare;
1039 for (var i = start; i < end; i++) {
1040 if (cmp(lst[i], value) === 0) {
1041 return i;
1042 }
1043 }
1044 return -1;
1045 },
1046
1047 /** @id MochiKit.Base.nodeWalk */
1048 nodeWalk: function (node, visitor) {
1049 var nodes = [node];
1050 var extend = MochiKit.Base.extend;
1051 while (nodes.length) {
1052 var res = visitor(nodes.shift());
1053 if (res) {
1054 extend(nodes, res);
1055 }
1056 }
1057 },
1058
1059
1060 /** @id MochiKit.Base.nameFunctions */
1061 nameFunctions: function (namespace) {
1062 var base = namespace.NAME;
1063 if (typeof(base) == 'undefined') {
1064 base = '';
1065 } else {
1066 base = base + '.';
1067 }
1068 for (var name in namespace) {
1069 var o = namespace[name];
1070 if (typeof(o) == 'function' && typeof(o.NAME) == 'undefined') {
1071 try {
1072 o.NAME = base + name;
1073 } catch (e) {
1074 // pass
1075 }
1076 }
1077 }
1078 },
1079
1080
1081 /** @id MochiKit.Base.queryString */
1082 queryString: function (names, values) {
1083 // check to see if names is a string or a DOM element, and if
1084 // MochiKit.DOM is available. If so, drop it like it's a form
1085 // Ugliest conditional in MochiKit? Probably!
1086 if (typeof(MochiKit.DOM) != "undefined" && arguments.length == 1
1087 && (typeof(names) == "string" || (
1088 typeof(names.nodeType) != "undefined" && names.nodeType > 0
1089 ))
1090 ) {
1091 var kv = MochiKit.DOM.formContents(names);
1092 names = kv[0];
1093 values = kv[1];
1094 } else if (arguments.length == 1) {
1095 // Allow the return value of formContents to be passed directly
1096 if (typeof(names.length) == "number" && names.length == 2) {
1097 return arguments.callee(names[0], names[1]);
1098 }
1099 var o = names;
1100 names = [];
1101 values = [];
1102 for (var k in o) {
1103 var v = o[k];
1104 if (typeof(v) == "function") {
1105 continue;
1106 } else if (typeof(v) != "string" &&
1107 typeof(v.length) == "number") {
1108 for (var i = 0; i < v.length; i++) {
1109 names.push(k);
1110 values.push(v[i]);
1111 }
1112 } else {
1113 names.push(k);
1114 values.push(v);
1115 }
1116 }
1117 }
1118 var rval = [];
1119 var len = Math.min(names.length, values.length);
1120 var urlEncode = MochiKit.Base.urlEncode;
1121 for (var i = 0; i < len; i++) {
1122 v = values[i];
1123 if (typeof(v) != 'undefined' && v !== null) {
1124 rval.push(urlEncode(names[i]) + "=" + urlEncode(v));
1125 }
1126 }
1127 return rval.join("&");
1128 },
1129
1130
1131 /** @id MochiKit.Base.parseQueryString */
1132 parseQueryString: function (encodedString, useArrays) {
1133 // strip a leading '?' from the encoded string
1134 var qstr = (encodedString.charAt(0) == "?")
1135 ? encodedString.substring(1)
1136 : encodedString;
1137 var pairs = qstr.replace(/\+/g, "%20").split(/(\&amp\;|\&\#38\;|\&#x26;|\&)/);
1138 var o = {};
1139 var decode;
1140 if (typeof(decodeURIComponent) != "undefined") {
1141 decode = decodeURIComponent;
1142 } else {
1143 decode = unescape;
1144 }
1145 if (useArrays) {
1146 for (var i = 0; i < pairs.length; i++) {
1147 var pair = pairs[i].split("=");
1148 if (pair.length !== 2) {
1149 continue;
1150 }
1151 var name = decode(pair[0]);
1152 var arr = o[name];
1153 if (!(arr instanceof Array)) {
1154 arr = [];
1155 o[name] = arr;
1156 }
1157 arr.push(decode(pair[1]));
1158 }
1159 } else {
1160 for (i = 0; i < pairs.length; i++) {
1161 pair = pairs[i].split("=");
1162 if (pair.length !== 2) {
1163 continue;
1164 }
1165 o[decode(pair[0])] = decode(pair[1]);
1166 }
1167 }
1168 return o;
1169 }
1170});
1171
1172/** @id MochiKit.Base.AdapterRegistry */
1173MochiKit.Base.AdapterRegistry = function () {
1174 this.pairs = [];
1175};
1176
1177MochiKit.Base.AdapterRegistry.prototype = {
1178 /** @id MochiKit.Base.AdapterRegistry.prototype.register */
1179 register: function (name, check, wrap, /* optional */ override) {
1180 if (override) {
1181 this.pairs.unshift([name, check, wrap]);
1182 } else {
1183 this.pairs.push([name, check, wrap]);
1184 }
1185 },
1186
1187 /** @id MochiKit.Base.AdapterRegistry.prototype.match */
1188 match: function (/* ... */) {
1189 for (var i = 0; i < this.pairs.length; i++) {
1190 var pair = this.pairs[i];
1191 if (pair[1].apply(this, arguments)) {
1192 return pair[2].apply(this, arguments);
1193 }
1194 }
1195 throw MochiKit.Base.NotFound;
1196 },
1197
1198 /** @id MochiKit.Base.AdapterRegistry.prototype.unregister */
1199 unregister: function (name) {
1200 for (var i = 0; i < this.pairs.length; i++) {
1201 var pair = this.pairs[i];
1202 if (pair[0] == name) {
1203 this.pairs.splice(i, 1);
1204 return true;
1205 }
1206 }
1207 return false;
1208 }
1209};
1210
1211
1212MochiKit.Base.EXPORT = [
1213 "flattenArray",
1214 "noop",
1215 "camelize",
1216 "counter",
1217 "clone",
1218 "extend",
1219 "update",
1220 "updatetree",
1221 "setdefault",
1222 "keys",
1223 "values",
1224 "items",
1225 "NamedError",
1226 "operator",
1227 "forwardCall",
1228 "itemgetter",
1229 "typeMatcher",
1230 "isCallable",
1231 "isUndefined",
1232 "isUndefinedOrNull",
1233 "isNull",
1234 "isEmpty",
1235 "isNotEmpty",
1236 "isArrayLike",
1237 "isDateLike",
1238 "xmap",
1239 "map",
1240 "xfilter",
1241 "filter",
1242 "methodcaller",
1243 "compose",
1244 "bind",
1245 "bindMethods",
1246 "NotFound",
1247 "AdapterRegistry",
1248 "registerComparator",
1249 "compare",
1250 "registerRepr",
1251 "repr",
1252 "objEqual",
1253 "arrayEqual",
1254 "concat",
1255 "keyComparator",
1256 "reverseKeyComparator",
1257 "partial",
1258 "merge",
1259 "listMinMax",
1260 "listMax",
1261 "listMin",
1262 "objMax",
1263 "objMin",
1264 "nodeWalk",
1265 "zip",
1266 "urlEncode",
1267 "queryString",
1268 "serializeJSON",
1269 "registerJSON",
1270 "evalJSON",
1271 "parseQueryString",
1272 "findValue",
1273 "findIdentical",
1274 "flattenArguments",
1275 "method",
1276 "average",
1277 "mean",
1278 "median"
1279];
1280
1281MochiKit.Base.EXPORT_OK = [
1282 "nameFunctions",
1283 "comparatorRegistry",
1284 "reprRegistry",
1285 "jsonRegistry",
1286 "compareDateLike",
1287 "compareArrayLike",
1288 "reprArrayLike",
1289 "reprString",
1290 "reprNumber"
1291];
1292
1293MochiKit.Base._exportSymbols = function (globals, module) {
1294 if (!MochiKit.__export__) {
1295 return;
1296 }
1297 var all = module.EXPORT_TAGS[":all"];
1298 for (var i = 0; i < all.length; i++) {
1299 globals[all[i]] = module[all[i]];
1300 }
1301};
1302
1303MochiKit.Base.__new__ = function () {
1304 // A singleton raised when no suitable adapter is found
1305 var m = this;
1306
1307 // convenience
1308 /** @id MochiKit.Base.noop */
1309 m.noop = m.operator.identity;
1310
1311 // Backwards compat
1312 m.forward = m.forwardCall;
1313 m.find = m.findValue;
1314
1315 if (typeof(encodeURIComponent) != "undefined") {
1316 /** @id MochiKit.Base.urlEncode */
1317 m.urlEncode = function (unencoded) {
1318 return encodeURIComponent(unencoded).replace(/\'/g, '%27');
1319 };
1320 } else {
1321 m.urlEncode = function (unencoded) {
1322 return escape(unencoded
1323 ).replace(/\+/g, '%2B'
1324 ).replace(/\"/g,'%22'
1325 ).rval.replace(/\'/g, '%27');
1326 };
1327 }
1328
1329 /** @id MochiKit.Base.NamedError */
1330 m.NamedError = function (name) {
1331 this.message = name;
1332 this.name = name;
1333 };
1334 m.NamedError.prototype = new Error();
1335 m.update(m.NamedError.prototype, {
1336 repr: function () {
1337 if (this.message && this.message != this.name) {
1338 return this.name + "(" + m.repr(this.message) + ")";
1339 } else {
1340 return this.name + "()";
1341 }
1342 },
1343 toString: m.forwardCall("repr")
1344 });
1345
1346 /** @id MochiKit.Base.NotFound */
1347 m.NotFound = new m.NamedError("MochiKit.Base.NotFound");
1348
1349
1350 /** @id MochiKit.Base.listMax */
1351 m.listMax = m.partial(m.listMinMax, 1);
1352 /** @id MochiKit.Base.listMin */
1353 m.listMin = m.partial(m.listMinMax, -1);
1354
1355 /** @id MochiKit.Base.isCallable */
1356 m.isCallable = m.typeMatcher('function');
1357 /** @id MochiKit.Base.isUndefined */
1358 m.isUndefined = m.typeMatcher('undefined');
1359
1360 /** @id MochiKit.Base.merge */
1361 m.merge = m.partial(m.update, null);
1362 /** @id MochiKit.Base.zip */
1363 m.zip = m.partial(m.map, null);
1364
1365 /** @id MochiKit.Base.average */
1366 m.average = m.mean;
1367
1368 /** @id MochiKit.Base.comparatorRegistry */
1369 m.comparatorRegistry = new m.AdapterRegistry();
1370 m.registerComparator("dateLike", m.isDateLike, m.compareDateLike);
1371 m.registerComparator("arrayLike", m.isArrayLike, m.compareArrayLike);
1372
1373 /** @id MochiKit.Base.reprRegistry */
1374 m.reprRegistry = new m.AdapterRegistry();
1375 m.registerRepr("arrayLike", m.isArrayLike, m.reprArrayLike);
1376 m.registerRepr("string", m.typeMatcher("string"), m.reprString);
1377 m.registerRepr("numbers", m.typeMatcher("number", "boolean"), m.reprNumber);
1378
1379 /** @id MochiKit.Base.jsonRegistry */
1380 m.jsonRegistry = new m.AdapterRegistry();
1381
1382 var all = m.concat(m.EXPORT, m.EXPORT_OK);
1383 m.EXPORT_TAGS = {
1384 ":common": m.concat(m.EXPORT_OK),
1385 ":all": all
1386 };
1387
1388 m.nameFunctions(this);
1389
1390};
1391
1392MochiKit.Base.__new__();
1393
1394//
1395// XXX: Internet Explorer blows
1396//
1397if (MochiKit.__export__) {
1398 compare = MochiKit.Base.compare;
1399 compose = MochiKit.Base.compose;
1400 serializeJSON = MochiKit.Base.serializeJSON;
1401}
1402
1403MochiKit.Base._exportSymbols(this, MochiKit.Base);
diff --git a/frontend/beta/js/MochiKit/Color.js b/frontend/beta/js/MochiKit/Color.js
new file mode 100644
index 0000000..37cb43b
--- a/dev/null
+++ b/frontend/beta/js/MochiKit/Color.js
@@ -0,0 +1,902 @@
1/***
2
3MochiKit.Color 1.4
4
5See <http://mochikit.com/> for documentation, downloads, license, etc.
6
7(c) 2005 Bob Ippolito and others. All rights Reserved.
8
9***/
10
11if (typeof(dojo) != 'undefined') {
12 dojo.provide('MochiKit.Color');
13 dojo.require('MochiKit.Base');
14 dojo.require('MochiKit.DOM');
15 dojo.require('MochiKit.Style');
16}
17
18if (typeof(JSAN) != 'undefined') {
19 JSAN.use("MochiKit.Base", []);
20 JSAN.use("MochiKit.DOM", []);
21 JSAN.use("MochiKit.Style", []);
22}
23
24try {
25 if (typeof(MochiKit.Base) == 'undefined') {
26 throw "";
27 }
28} catch (e) {
29 throw "MochiKit.Color depends on MochiKit.Base";
30}
31
32try {
33 if (typeof(MochiKit.DOM) == 'undefined') {
34 throw "";
35 }
36} catch (e) {
37 throw "MochiKit.Color depends on MochiKit.DOM";
38}
39
40try {
41 if (typeof(MochiKit.Style) == 'undefined') {
42 throw "";
43 }
44} catch (e) {
45 throw "MochiKit.Color depends on MochiKit.Style";
46}
47
48if (typeof(MochiKit.Color) == "undefined") {
49 MochiKit.Color = {};
50}
51
52MochiKit.Color.NAME = "MochiKit.Color";
53MochiKit.Color.VERSION = "1.4";
54
55MochiKit.Color.__repr__ = function () {
56 return "[" + this.NAME + " " + this.VERSION + "]";
57};
58
59MochiKit.Color.toString = function () {
60 return this.__repr__();
61};
62
63
64/** @id MochiKit.Color.Color */
65MochiKit.Color.Color = function (red, green, blue, alpha) {
66 if (typeof(alpha) == 'undefined' || alpha === null) {
67 alpha = 1.0;
68 }
69 this.rgb = {
70 r: red,
71 g: green,
72 b: blue,
73 a: alpha
74 };
75};
76
77
78// Prototype methods
79
80MochiKit.Color.Color.prototype = {
81
82 __class__: MochiKit.Color.Color,
83
84 /** @id MochiKit.Color.Color.prototype.colorWithAlpha */
85 colorWithAlpha: function (alpha) {
86 var rgb = this.rgb;
87 var m = MochiKit.Color;
88 return m.Color.fromRGB(rgb.r, rgb.g, rgb.b, alpha);
89 },
90
91 /** @id MochiKit.Color.Color.prototype.colorWithHue */
92 colorWithHue: function (hue) {
93 // get an HSL model, and set the new hue...
94 var hsl = this.asHSL();
95 hsl.h = hue;
96 var m = MochiKit.Color;
97 // convert back to RGB...
98 return m.Color.fromHSL(hsl);
99 },
100
101 /** @id MochiKit.Color.Color.prototype.colorWithSaturation */
102 colorWithSaturation: function (saturation) {
103 // get an HSL model, and set the new hue...
104 var hsl = this.asHSL();
105 hsl.s = saturation;
106 var m = MochiKit.Color;
107 // convert back to RGB...
108 return m.Color.fromHSL(hsl);
109 },
110
111 /** @id MochiKit.Color.Color.prototype.colorWithLightness */
112 colorWithLightness: function (lightness) {
113 // get an HSL model, and set the new hue...
114 var hsl = this.asHSL();
115 hsl.l = lightness;
116 var m = MochiKit.Color;
117 // convert back to RGB...
118 return m.Color.fromHSL(hsl);
119 },
120
121 /** @id MochiKit.Color.Color.prototype.darkerColorWithLevel */
122 darkerColorWithLevel: function (level) {
123 var hsl = this.asHSL();
124 hsl.l = Math.max(hsl.l - level, 0);
125 var m = MochiKit.Color;
126 return m.Color.fromHSL(hsl);
127 },
128
129 /** @id MochiKit.Color.Color.prototype.lighterColorWithLevel */
130 lighterColorWithLevel: function (level) {
131 var hsl = this.asHSL();
132 hsl.l = Math.min(hsl.l + level, 1);
133 var m = MochiKit.Color;
134 return m.Color.fromHSL(hsl);
135 },
136
137 /** @id MochiKit.Color.Color.prototype.blendedColor */
138 blendedColor: function (other, /* optional */ fraction) {
139 if (typeof(fraction) == 'undefined' || fraction === null) {
140 fraction = 0.5;
141 }
142 var sf = 1.0 - fraction;
143 var s = this.rgb;
144 var d = other.rgb;
145 var df = fraction;
146 return MochiKit.Color.Color.fromRGB(
147 (s.r * sf) + (d.r * df),
148 (s.g * sf) + (d.g * df),
149 (s.b * sf) + (d.b * df),
150 (s.a * sf) + (d.a * df)
151 );
152 },
153
154 /** @id MochiKit.Color.Color.prototype.compareRGB */
155 compareRGB: function (other) {
156 var a = this.asRGB();
157 var b = other.asRGB();
158 return MochiKit.Base.compare(
159 [a.r, a.g, a.b, a.a],
160 [b.r, b.g, b.b, b.a]
161 );
162 },
163
164 /** @id MochiKit.Color.Color.prototype.isLight */
165 isLight: function () {
166 return this.asHSL().b > 0.5;
167 },
168
169 /** @id MochiKit.Color.Color.prototype.isDark */
170 isDark: function () {
171 return (!this.isLight());
172 },
173
174 /** @id MochiKit.Color.Color.prototype.toHSLString */
175 toHSLString: function () {
176 var c = this.asHSL();
177 var ccc = MochiKit.Color.clampColorComponent;
178 var rval = this._hslString;
179 if (!rval) {
180 var mid = (
181 ccc(c.h, 360).toFixed(0)
182 + "," + ccc(c.s, 100).toPrecision(4) + "%"
183 + "," + ccc(c.l, 100).toPrecision(4) + "%"
184 );
185 var a = c.a;
186 if (a >= 1) {
187 a = 1;
188 rval = "hsl(" + mid + ")";
189 } else {
190 if (a <= 0) {
191 a = 0;
192 }
193 rval = "hsla(" + mid + "," + a + ")";
194 }
195 this._hslString = rval;
196 }
197 return rval;
198 },
199
200 /** @id MochiKit.Color.Color.prototype.toRGBString */
201 toRGBString: function () {
202 var c = this.rgb;
203 var ccc = MochiKit.Color.clampColorComponent;
204 var rval = this._rgbString;
205 if (!rval) {
206 var mid = (
207 ccc(c.r, 255).toFixed(0)
208 + "," + ccc(c.g, 255).toFixed(0)
209 + "," + ccc(c.b, 255).toFixed(0)
210 );
211 if (c.a != 1) {
212 rval = "rgba(" + mid + "," + c.a + ")";
213 } else {
214 rval = "rgb(" + mid + ")";
215 }
216 this._rgbString = rval;
217 }
218 return rval;
219 },
220
221 /** @id MochiKit.Color.Color.prototype.asRGB */
222 asRGB: function () {
223 return MochiKit.Base.clone(this.rgb);
224 },
225
226 /** @id MochiKit.Color.Color.prototype.toHexString */
227 toHexString: function () {
228 var m = MochiKit.Color;
229 var c = this.rgb;
230 var ccc = MochiKit.Color.clampColorComponent;
231 var rval = this._hexString;
232 if (!rval) {
233 rval = ("#" +
234 m.toColorPart(ccc(c.r, 255)) +
235 m.toColorPart(ccc(c.g, 255)) +
236 m.toColorPart(ccc(c.b, 255))
237 );
238 this._hexString = rval;
239 }
240 return rval;
241 },
242
243 /** @id MochiKit.Color.Color.prototype.asHSV */
244 asHSV: function () {
245 var hsv = this.hsv;
246 var c = this.rgb;
247 if (typeof(hsv) == 'undefined' || hsv === null) {
248 hsv = MochiKit.Color.rgbToHSV(this.rgb);
249 this.hsv = hsv;
250 }
251 return MochiKit.Base.clone(hsv);
252 },
253
254 /** @id MochiKit.Color.Color.prototype.asHSL */
255 asHSL: function () {
256 var hsl = this.hsl;
257 var c = this.rgb;
258 if (typeof(hsl) == 'undefined' || hsl === null) {
259 hsl = MochiKit.Color.rgbToHSL(this.rgb);
260 this.hsl = hsl;
261 }
262 return MochiKit.Base.clone(hsl);
263 },
264
265 /** @id MochiKit.Color.Color.prototype.toString */
266 toString: function () {
267 return this.toRGBString();
268 },
269
270 /** @id MochiKit.Color.Color.prototype.repr */
271 repr: function () {
272 var c = this.rgb;
273 var col = [c.r, c.g, c.b, c.a];
274 return this.__class__.NAME + "(" + col.join(", ") + ")";
275 }
276
277};
278
279// Constructor methods
280
281MochiKit.Base.update(MochiKit.Color.Color, {
282 /** @id MochiKit.Color.Color.fromRGB */
283 fromRGB: function (red, green, blue, alpha) {
284 // designated initializer
285 var Color = MochiKit.Color.Color;
286 if (arguments.length == 1) {
287 var rgb = red;
288 red = rgb.r;
289 green = rgb.g;
290 blue = rgb.b;
291 if (typeof(rgb.a) == 'undefined') {
292 alpha = undefined;
293 } else {
294 alpha = rgb.a;
295 }
296 }
297 return new Color(red, green, blue, alpha);
298 },
299
300 /** @id MochiKit.Color.Color.fromHSL */
301 fromHSL: function (hue, saturation, lightness, alpha) {
302 var m = MochiKit.Color;
303 return m.Color.fromRGB(m.hslToRGB.apply(m, arguments));
304 },
305
306 /** @id MochiKit.Color.Color.fromHSV */
307 fromHSV: function (hue, saturation, value, alpha) {
308 var m = MochiKit.Color;
309 return m.Color.fromRGB(m.hsvToRGB.apply(m, arguments));
310 },
311
312 /** @id MochiKit.Color.Color.fromName */
313 fromName: function (name) {
314 var Color = MochiKit.Color.Color;
315 // Opera 9 seems to "quote" named colors(?!)
316 if (name.charAt(0) == '"') {
317 name = name.substr(1, name.length - 2);
318 }
319 var htmlColor = Color._namedColors[name.toLowerCase()];
320 if (typeof(htmlColor) == 'string') {
321 return Color.fromHexString(htmlColor);
322 } else if (name == "transparent") {
323 return Color.transparentColor();
324 }
325 return null;
326 },
327
328 /** @id MochiKit.Color.Color.fromString */
329 fromString: function (colorString) {
330 var self = MochiKit.Color.Color;
331 var three = colorString.substr(0, 3);
332 if (three == "rgb") {
333 return self.fromRGBString(colorString);
334 } else if (three == "hsl") {
335 return self.fromHSLString(colorString);
336 } else if (colorString.charAt(0) == "#") {
337 return self.fromHexString(colorString);
338 }
339 return self.fromName(colorString);
340 },
341
342
343 /** @id MochiKit.Color.Color.fromHexString */
344 fromHexString: function (hexCode) {
345 if (hexCode.charAt(0) == '#') {
346 hexCode = hexCode.substring(1);
347 }
348 var components = [];
349 var i, hex;
350 if (hexCode.length == 3) {
351 for (i = 0; i < 3; i++) {
352 hex = hexCode.substr(i, 1);
353 components.push(parseInt(hex + hex, 16) / 255.0);
354 }
355 } else {
356 for (i = 0; i < 6; i += 2) {
357 hex = hexCode.substr(i, 2);
358 components.push(parseInt(hex, 16) / 255.0);
359 }
360 }
361 var Color = MochiKit.Color.Color;
362 return Color.fromRGB.apply(Color, components);
363 },
364
365
366 _fromColorString: function (pre, method, scales, colorCode) {
367 // parses either HSL or RGB
368 if (colorCode.indexOf(pre) === 0) {
369 colorCode = colorCode.substring(colorCode.indexOf("(", 3) + 1, colorCode.length - 1);
370 }
371 var colorChunks = colorCode.split(/\s*,\s*/);
372 var colorFloats = [];
373 for (var i = 0; i < colorChunks.length; i++) {
374 var c = colorChunks[i];
375 var val;
376 var three = c.substring(c.length - 3);
377 if (c.charAt(c.length - 1) == '%') {
378 val = 0.01 * parseFloat(c.substring(0, c.length - 1));
379 } else if (three == "deg") {
380 val = parseFloat(c) / 360.0;
381 } else if (three == "rad") {
382 val = parseFloat(c) / (Math.PI * 2);
383 } else {
384 val = scales[i] * parseFloat(c);
385 }
386 colorFloats.push(val);
387 }
388 return this[method].apply(this, colorFloats);
389 },
390
391 /** @id MochiKit.Color.Color.fromComputedStyle */
392 fromComputedStyle: function (elem, style) {
393 var d = MochiKit.DOM;
394 var cls = MochiKit.Color.Color;
395 for (elem = d.getElement(elem); elem; elem = elem.parentNode) {
396 var actualColor = MochiKit.Style.getStyle.apply(d, arguments);
397 if (!actualColor) {
398 continue;
399 }
400 var color = cls.fromString(actualColor);
401 if (!color) {
402 break;
403 }
404 if (color.asRGB().a > 0) {
405 return color;
406 }
407 }
408 return null;
409 },
410
411 /** @id MochiKit.Color.Color.fromBackground */
412 fromBackground: function (elem) {
413 var cls = MochiKit.Color.Color;
414 return cls.fromComputedStyle(
415 elem, "backgroundColor", "background-color") || cls.whiteColor();
416 },
417
418 /** @id MochiKit.Color.Color.fromText */
419 fromText: function (elem) {
420 var cls = MochiKit.Color.Color;
421 return cls.fromComputedStyle(
422 elem, "color", "color") || cls.blackColor();
423 },
424
425 /** @id MochiKit.Color.Color.namedColors */
426 namedColors: function () {
427 return MochiKit.Base.clone(MochiKit.Color.Color._namedColors);
428 }
429});
430
431
432// Module level functions
433
434MochiKit.Base.update(MochiKit.Color, {
435 /** @id MochiKit.Color.clampColorComponent */
436 clampColorComponent: function (v, scale) {
437 v *= scale;
438 if (v < 0) {
439 return 0;
440 } else if (v > scale) {
441 return scale;
442 } else {
443 return v;
444 }
445 },
446
447 _hslValue: function (n1, n2, hue) {
448 if (hue > 6.0) {
449 hue -= 6.0;
450 } else if (hue < 0.0) {
451 hue += 6.0;
452 }
453 var val;
454 if (hue < 1.0) {
455 val = n1 + (n2 - n1) * hue;
456 } else if (hue < 3.0) {
457 val = n2;
458 } else if (hue < 4.0) {
459 val = n1 + (n2 - n1) * (4.0 - hue);
460 } else {
461 val = n1;
462 }
463 return val;
464 },
465
466 /** @id MochiKit.Color.hsvToRGB */
467 hsvToRGB: function (hue, saturation, value, alpha) {
468 if (arguments.length == 1) {
469 var hsv = hue;
470 hue = hsv.h;
471 saturation = hsv.s;
472 value = hsv.v;
473 alpha = hsv.a;
474 }
475 var red;
476 var green;
477 var blue;
478 if (saturation === 0) {
479 red = 0;
480 green = 0;
481 blue = 0;
482 } else {
483 var i = Math.floor(hue * 6);
484 var f = (hue * 6) - i;
485 var p = value * (1 - saturation);
486 var q = value * (1 - (saturation * f));
487 var t = value * (1 - (saturation * (1 - f)));
488 switch (i) {
489 case 1: red = q; green = value; blue = p; break;
490 case 2: red = p; green = value; blue = t; break;
491 case 3: red = p; green = q; blue = value; break;
492 case 4: red = t; green = p; blue = value; break;
493 case 5: red = value; green = p; blue = q; break;
494 case 6: // fall through
495 case 0: red = value; green = t; blue = p; break;
496 }
497 }
498 return {
499 r: red,
500 g: green,
501 b: blue,
502 a: alpha
503 };
504 },
505
506 /** @id MochiKit.Color.hslToRGB */
507 hslToRGB: function (hue, saturation, lightness, alpha) {
508 if (arguments.length == 1) {
509 var hsl = hue;
510 hue = hsl.h;
511 saturation = hsl.s;
512 lightness = hsl.l;
513 alpha = hsl.a;
514 }
515 var red;
516 var green;
517 var blue;
518 if (saturation === 0) {
519 red = lightness;
520 green = lightness;
521 blue = lightness;
522 } else {
523 var m2;
524 if (lightness <= 0.5) {
525 m2 = lightness * (1.0 + saturation);
526 } else {
527 m2 = lightness + saturation - (lightness * saturation);
528 }
529 var m1 = (2.0 * lightness) - m2;
530 var f = MochiKit.Color._hslValue;
531 var h6 = hue * 6.0;
532 red = f(m1, m2, h6 + 2);
533 green = f(m1, m2, h6);
534 blue = f(m1, m2, h6 - 2);
535 }
536 return {
537 r: red,
538 g: green,
539 b: blue,
540 a: alpha
541 };
542 },
543
544 /** @id MochiKit.Color.rgbToHSV */
545 rgbToHSV: function (red, green, blue, alpha) {
546 if (arguments.length == 1) {
547 var rgb = red;
548 red = rgb.r;
549 green = rgb.g;
550 blue = rgb.b;
551 alpha = rgb.a;
552 }
553 var max = Math.max(Math.max(red, green), blue);
554 var min = Math.min(Math.min(red, green), blue);
555 var hue;
556 var saturation;
557 var value = max;
558 if (min == max) {
559 hue = 0;
560 saturation = 0;
561 } else {
562 var delta = (max - min);
563 saturation = delta / max;
564
565 if (red == max) {
566 hue = (green - blue) / delta;
567 } else if (green == max) {
568 hue = 2 + ((blue - red) / delta);
569 } else {
570 hue = 4 + ((red - green) / delta);
571 }
572 hue /= 6;
573 if (hue < 0) {
574 hue += 1;
575 }
576 if (hue > 1) {
577 hue -= 1;
578 }
579 }
580 return {
581 h: hue,
582 s: saturation,
583 v: value,
584 a: alpha
585 };
586 },
587
588 /** @id MochiKit.Color.rgbToHSL */
589 rgbToHSL: function (red, green, blue, alpha) {
590 if (arguments.length == 1) {
591 var rgb = red;
592 red = rgb.r;
593 green = rgb.g;
594 blue = rgb.b;
595 alpha = rgb.a;
596 }
597 var max = Math.max(red, Math.max(green, blue));
598 var min = Math.min(red, Math.min(green, blue));
599 var hue;
600 var saturation;
601 var lightness = (max + min) / 2.0;
602 var delta = max - min;
603 if (delta === 0) {
604 hue = 0;
605 saturation = 0;
606 } else {
607 if (lightness <= 0.5) {
608 saturation = delta / (max + min);
609 } else {
610 saturation = delta / (2 - max - min);
611 }
612 if (red == max) {
613 hue = (green - blue) / delta;
614 } else if (green == max) {
615 hue = 2 + ((blue - red) / delta);
616 } else {
617 hue = 4 + ((red - green) / delta);
618 }
619 hue /= 6;
620 if (hue < 0) {
621 hue += 1;
622 }
623 if (hue > 1) {
624 hue -= 1;
625 }
626
627 }
628 return {
629 h: hue,
630 s: saturation,
631 l: lightness,
632 a: alpha
633 };
634 },
635
636 /** @id MochiKit.Color.toColorPart */
637 toColorPart: function (num) {
638 num = Math.round(num);
639 var digits = num.toString(16);
640 if (num < 16) {
641 return '0' + digits;
642 }
643 return digits;
644 },
645
646 __new__: function () {
647 var m = MochiKit.Base;
648 /** @id MochiKit.Color.fromRGBString */
649 this.Color.fromRGBString = m.bind(
650 this.Color._fromColorString, this.Color, "rgb", "fromRGB",
651 [1.0/255.0, 1.0/255.0, 1.0/255.0, 1]
652 );
653 /** @id MochiKit.Color.fromHSLString */
654 this.Color.fromHSLString = m.bind(
655 this.Color._fromColorString, this.Color, "hsl", "fromHSL",
656 [1.0/360.0, 0.01, 0.01, 1]
657 );
658
659 var third = 1.0 / 3.0;
660 /** @id MochiKit.Color.colors */
661 var colors = {
662 // NSColor colors plus transparent
663 /** @id MochiKit.Color.blackColor */
664 black: [0, 0, 0],
665 /** @id MochiKit.Color.blueColor */
666 blue: [0, 0, 1],
667 /** @id MochiKit.Color.brownColor */
668 brown: [0.6, 0.4, 0.2],
669 /** @id MochiKit.Color.cyanColor */
670 cyan: [0, 1, 1],
671 /** @id MochiKit.Color.darkGrayColor */
672 darkGray: [third, third, third],
673 /** @id MochiKit.Color.grayColor */
674 gray: [0.5, 0.5, 0.5],
675 /** @id MochiKit.Color.greenColor */
676 green: [0, 1, 0],
677 /** @id MochiKit.Color.lightGrayColor */
678 lightGray: [2 * third, 2 * third, 2 * third],
679 /** @id MochiKit.Color.magentaColor */
680 magenta: [1, 0, 1],
681 /** @id MochiKit.Color.orangeColor */
682 orange: [1, 0.5, 0],
683 /** @id MochiKit.Color.purpleColor */
684 purple: [0.5, 0, 0.5],
685 /** @id MochiKit.Color.redColor */
686 red: [1, 0, 0],
687 /** @id MochiKit.Color.transparentColor */
688 transparent: [0, 0, 0, 0],
689 /** @id MochiKit.Color.whiteColor */
690 white: [1, 1, 1],
691 /** @id MochiKit.Color.yellowColor */
692 yellow: [1, 1, 0]
693 };
694
695 var makeColor = function (name, r, g, b, a) {
696 var rval = this.fromRGB(r, g, b, a);
697 this[name] = function () { return rval; };
698 return rval;
699 };
700
701 for (var k in colors) {
702 var name = k + "Color";
703 var bindArgs = m.concat(
704 [makeColor, this.Color, name],
705 colors[k]
706 );
707 this.Color[name] = m.bind.apply(null, bindArgs);
708 }
709
710 var isColor = function () {
711 for (var i = 0; i < arguments.length; i++) {
712 if (!(arguments[i] instanceof Color)) {
713 return false;
714 }
715 }
716 return true;
717 };
718
719 var compareColor = function (a, b) {
720 return a.compareRGB(b);
721 };
722
723 m.nameFunctions(this);
724
725 m.registerComparator(this.Color.NAME, isColor, compareColor);
726
727 this.EXPORT_TAGS = {
728 ":common": this.EXPORT,
729 ":all": m.concat(this.EXPORT, this.EXPORT_OK)
730 };
731
732 }
733});
734
735MochiKit.Color.EXPORT = [
736 "Color"
737];
738
739MochiKit.Color.EXPORT_OK = [
740 "clampColorComponent",
741 "rgbToHSL",
742 "hslToRGB",
743 "rgbToHSV",
744 "hsvToRGB",
745 "toColorPart"
746];
747
748MochiKit.Color.__new__();
749
750MochiKit.Base._exportSymbols(this, MochiKit.Color);
751
752// Full table of css3 X11 colors <http://www.w3.org/TR/css3-color/#X11COLORS>
753
754MochiKit.Color.Color._namedColors = {
755 aliceblue: "#f0f8ff",
756 antiquewhite: "#faebd7",
757 aqua: "#00ffff",
758 aquamarine: "#7fffd4",
759 azure: "#f0ffff",
760 beige: "#f5f5dc",
761 bisque: "#ffe4c4",
762 black: "#000000",
763 blanchedalmond: "#ffebcd",
764 blue: "#0000ff",
765 blueviolet: "#8a2be2",
766 brown: "#a52a2a",
767 burlywood: "#deb887",
768 cadetblue: "#5f9ea0",
769 chartreuse: "#7fff00",
770 chocolate: "#d2691e",
771 coral: "#ff7f50",
772 cornflowerblue: "#6495ed",
773 cornsilk: "#fff8dc",
774 crimson: "#dc143c",
775 cyan: "#00ffff",
776 darkblue: "#00008b",
777 darkcyan: "#008b8b",
778 darkgoldenrod: "#b8860b",
779 darkgray: "#a9a9a9",
780 darkgreen: "#006400",
781 darkgrey: "#a9a9a9",
782 darkkhaki: "#bdb76b",
783 darkmagenta: "#8b008b",
784 darkolivegreen: "#556b2f",
785 darkorange: "#ff8c00",
786 darkorchid: "#9932cc",
787 darkred: "#8b0000",
788 darksalmon: "#e9967a",
789 darkseagreen: "#8fbc8f",
790 darkslateblue: "#483d8b",
791 darkslategray: "#2f4f4f",
792 darkslategrey: "#2f4f4f",
793 darkturquoise: "#00ced1",
794 darkviolet: "#9400d3",
795 deeppink: "#ff1493",
796 deepskyblue: "#00bfff",
797 dimgray: "#696969",
798 dimgrey: "#696969",
799 dodgerblue: "#1e90ff",
800 firebrick: "#b22222",
801 floralwhite: "#fffaf0",
802 forestgreen: "#228b22",
803 fuchsia: "#ff00ff",
804 gainsboro: "#dcdcdc",
805 ghostwhite: "#f8f8ff",
806 gold: "#ffd700",
807 goldenrod: "#daa520",
808 gray: "#808080",
809 green: "#008000",
810 greenyellow: "#adff2f",
811 grey: "#808080",
812 honeydew: "#f0fff0",
813 hotpink: "#ff69b4",
814 indianred: "#cd5c5c",
815 indigo: "#4b0082",
816 ivory: "#fffff0",
817 khaki: "#f0e68c",
818 lavender: "#e6e6fa",
819 lavenderblush: "#fff0f5",
820 lawngreen: "#7cfc00",
821 lemonchiffon: "#fffacd",
822 lightblue: "#add8e6",
823 lightcoral: "#f08080",
824 lightcyan: "#e0ffff",
825 lightgoldenrodyellow: "#fafad2",
826 lightgray: "#d3d3d3",
827 lightgreen: "#90ee90",
828 lightgrey: "#d3d3d3",
829 lightpink: "#ffb6c1",
830 lightsalmon: "#ffa07a",
831 lightseagreen: "#20b2aa",
832 lightskyblue: "#87cefa",
833 lightslategray: "#778899",
834 lightslategrey: "#778899",
835 lightsteelblue: "#b0c4de",
836 lightyellow: "#ffffe0",
837 lime: "#00ff00",
838 limegreen: "#32cd32",
839 linen: "#faf0e6",
840 magenta: "#ff00ff",
841 maroon: "#800000",
842 mediumaquamarine: "#66cdaa",
843 mediumblue: "#0000cd",
844 mediumorchid: "#ba55d3",
845 mediumpurple: "#9370db",
846 mediumseagreen: "#3cb371",
847 mediumslateblue: "#7b68ee",
848 mediumspringgreen: "#00fa9a",
849 mediumturquoise: "#48d1cc",
850 mediumvioletred: "#c71585",
851 midnightblue: "#191970",
852 mintcream: "#f5fffa",
853 mistyrose: "#ffe4e1",
854 moccasin: "#ffe4b5",
855 navajowhite: "#ffdead",
856 navy: "#000080",
857 oldlace: "#fdf5e6",
858 olive: "#808000",
859 olivedrab: "#6b8e23",
860 orange: "#ffa500",
861 orangered: "#ff4500",
862 orchid: "#da70d6",
863 palegoldenrod: "#eee8aa",
864 palegreen: "#98fb98",
865 paleturquoise: "#afeeee",
866 palevioletred: "#db7093",
867 papayawhip: "#ffefd5",
868 peachpuff: "#ffdab9",
869 peru: "#cd853f",
870 pink: "#ffc0cb",
871 plum: "#dda0dd",
872 powderblue: "#b0e0e6",
873 purple: "#800080",
874 red: "#ff0000",
875 rosybrown: "#bc8f8f",
876 royalblue: "#4169e1",
877 saddlebrown: "#8b4513",
878 salmon: "#fa8072",
879 sandybrown: "#f4a460",
880 seagreen: "#2e8b57",
881 seashell: "#fff5ee",
882 sienna: "#a0522d",
883 silver: "#c0c0c0",
884 skyblue: "#87ceeb",
885 slateblue: "#6a5acd",
886 slategray: "#708090",
887 slategrey: "#708090",
888 snow: "#fffafa",
889 springgreen: "#00ff7f",
890 steelblue: "#4682b4",
891 tan: "#d2b48c",
892 teal: "#008080",
893 thistle: "#d8bfd8",
894 tomato: "#ff6347",
895 turquoise: "#40e0d0",
896 violet: "#ee82ee",
897 wheat: "#f5deb3",
898 white: "#ffffff",
899 whitesmoke: "#f5f5f5",
900 yellow: "#ffff00",
901 yellowgreen: "#9acd32"
902};
diff --git a/frontend/beta/js/MochiKit/Controls.js b/frontend/beta/js/MochiKit/Controls.js
new file mode 100644
index 0000000..b0bc5bf
--- a/dev/null
+++ b/frontend/beta/js/MochiKit/Controls.js
@@ -0,0 +1,1388 @@
1/***
2Copyright (c) 2005 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
3 (c) 2005 Ivan Krstic (http://blogs.law.harvard.edu/ivan)
4 (c) 2005 Jon Tirsen (http://www.tirsen.com)
5Contributors:
6 Richard Livsey
7 Rahul Bhargava
8 Rob Wills
9 Mochi-ized By Thomas Herve (_firstname_@nimail.org)
10
11See scriptaculous.js for full license.
12
13Autocompleter.Base handles all the autocompletion functionality
14that's independent of the data source for autocompletion. This
15includes drawing the autocompletion menu, observing keyboard
16and mouse events, and similar.
17
18Specific autocompleters need to provide, at the very least,
19a getUpdatedChoices function that will be invoked every time
20the text inside the monitored textbox changes. This method
21should get the text for which to provide autocompletion by
22invoking this.getToken(), NOT by directly accessing
23this.element.value. This is to allow incremental tokenized
24autocompletion. Specific auto-completion logic (AJAX, etc)
25belongs in getUpdatedChoices.
26
27Tokenized incremental autocompletion is enabled automatically
28when an autocompleter is instantiated with the 'tokens' option
29in the options parameter, e.g.:
30new Ajax.Autocompleter('id','upd', '/url/', { tokens: ',' });
31will incrementally autocomplete with a comma as the token.
32Additionally, ',' in the above example can be replaced with
33a token array, e.g. { tokens: [',', '\n'] } which
34enables autocompletion on multiple tokens. This is most
35useful when one of the tokens is \n (a newline), as it
36allows smart autocompletion after linebreaks.
37
38***/
39
40MochiKit.Base.update(MochiKit.Base, {
41 ScriptFragment: '(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)',
42
43/** @id MochiKit.Base.stripScripts */
44 stripScripts: function (str) {
45 return str.replace(new RegExp(MochiKit.Base.ScriptFragment, 'img'), '');
46 },
47
48/** @id MochiKit.Base.stripTags */
49 stripTags: function(str) {
50 return str.replace(/<\/?[^>]+>/gi, '');
51 },
52
53/** @id MochiKit.Base.extractScripts */
54 extractScripts: function (str) {
55 var matchAll = new RegExp(MochiKit.Base.ScriptFragment, 'img');
56 var matchOne = new RegExp(MochiKit.Base.ScriptFragment, 'im');
57 return MochiKit.Base.map(function (scriptTag) {
58 return (scriptTag.match(matchOne) || ['', ''])[1];
59 }, str.match(matchAll) || []);
60 },
61
62/** @id MochiKit.Base.evalScripts */
63 evalScripts: function (str) {
64 return MochiKit.Base.map(function (scr) {
65 eval(scr);
66 }, MochiKit.Base.extractScripts(str));
67 }
68});
69
70MochiKit.Form = {
71
72/** @id MochiKit.Form.serialize */
73 serialize: function (form) {
74 var elements = MochiKit.Form.getElements(form);
75 var queryComponents = [];
76
77 for (var i = 0; i < elements.length; i++) {
78 var queryComponent = MochiKit.Form.serializeElement(elements[i]);
79 if (queryComponent) {
80 queryComponents.push(queryComponent);
81 }
82 }
83
84 return queryComponents.join('&');
85 },
86
87/** @id MochiKit.Form.getElements */
88 getElements: function (form) {
89 form = MochiKit.DOM.getElement(form);
90 var elements = [];
91
92 for (tagName in MochiKit.Form.Serializers) {
93 var tagElements = form.getElementsByTagName(tagName);
94 for (var j = 0; j < tagElements.length; j++) {
95 elements.push(tagElements[j]);
96 }
97 }
98 return elements;
99 },
100
101/** @id MochiKit.Form.serializeElement */
102 serializeElement: function (element) {
103 element = MochiKit.DOM.getElement(element);
104 var method = element.tagName.toLowerCase();
105 var parameter = MochiKit.Form.Serializers[method](element);
106
107 if (parameter) {
108 var key = encodeURIComponent(parameter[0]);
109 if (key.length === 0) {
110 return;
111 }
112
113 if (!(parameter[1] instanceof Array)) {
114 parameter[1] = [parameter[1]];
115 }
116
117 return parameter[1].map(function (value) {
118 return key + '=' + encodeURIComponent(value);
119 }).join('&');
120 }
121 }
122};
123
124MochiKit.Form.Serializers = {
125
126/** @id MochiKit.Form.Serializers.input */
127 input: function (element) {
128 switch (element.type.toLowerCase()) {
129 case 'submit':
130 case 'hidden':
131 case 'password':
132 case 'text':
133 return MochiKit.Form.Serializers.textarea(element);
134 case 'checkbox':
135 case 'radio':
136 return MochiKit.Form.Serializers.inputSelector(element);
137 }
138 return false;
139 },
140
141/** @id MochiKit.Form.Serializers.inputSelector */
142 inputSelector: function (element) {
143 if (element.checked) {
144 return [element.name, element.value];
145 }
146 },
147
148/** @id MochiKit.Form.Serializers.textarea */
149 textarea: function (element) {
150 return [element.name, element.value];
151 },
152
153/** @id MochiKit.Form.Serializers.select */
154 select: function (element) {
155 return MochiKit.Form.Serializers[element.type == 'select-one' ?
156 'selectOne' : 'selectMany'](element);
157 },
158
159/** @id MochiKit.Form.Serializers.selectOne */
160 selectOne: function (element) {
161 var value = '', opt, index = element.selectedIndex;
162 if (index >= 0) {
163 opt = element.options[index];
164 value = opt.value;
165 if (!value && !('value' in opt)) {
166 value = opt.text;
167 }
168 }
169 return [element.name, value];
170 },
171
172/** @id MochiKit.Form.Serializers.selectMany */
173 selectMany: function (element) {
174 var value = [];
175 for (var i = 0; i < element.length; i++) {
176 var opt = element.options[i];
177 if (opt.selected) {
178 var optValue = opt.value;
179 if (!optValue && !('value' in opt)) {
180 optValue = opt.text;
181 }
182 value.push(optValue);
183 }
184 }
185 return [element.name, value];
186 }
187};
188
189/** @id Ajax */
190var Ajax = {
191 activeRequestCount: 0
192};
193
194Ajax.Responders = {
195 responders: [],
196
197/** @id Ajax.Responders.register */
198 register: function (responderToAdd) {
199 if (MochiKit.Base.find(this.responders, responderToAdd) == -1) {
200 this.responders.push(responderToAdd);
201 }
202 },
203
204/** @id Ajax.Responders.unregister */
205 unregister: function (responderToRemove) {
206 this.responders = this.responders.without(responderToRemove);
207 },
208
209/** @id Ajax.Responders.dispatch */
210 dispatch: function (callback, request, transport, json) {
211 MochiKit.Iter.forEach(this.responders, function (responder) {
212 if (responder[callback] &&
213 typeof(responder[callback]) == 'function') {
214 try {
215 responder[callback].apply(responder, [request, transport, json]);
216 } catch (e) {}
217 }
218 });
219 }
220};
221
222Ajax.Responders.register({
223
224/** @id Ajax.Responders.onCreate */
225 onCreate: function () {
226 Ajax.activeRequestCount++;
227 },
228
229/** @id Ajax.Responders.onComplete */
230 onComplete: function () {
231 Ajax.activeRequestCount--;
232 }
233});
234
235/** @id Ajax.Base */
236Ajax.Base = function () {};
237
238Ajax.Base.prototype = {
239
240/** @id Ajax.Base.prototype.setOptions */
241 setOptions: function (options) {
242 this.options = {
243 method: 'post',
244 asynchronous: true,
245 parameters: ''
246 }
247 MochiKit.Base.update(this.options, options || {});
248 },
249
250/** @id Ajax.Base.prototype.responseIsSuccess */
251 responseIsSuccess: function () {
252 return this.transport.status == undefined
253 || this.transport.status === 0
254 || (this.transport.status >= 200 && this.transport.status < 300);
255 },
256
257/** @id Ajax.Base.prototype.responseIsFailure */
258 responseIsFailure: function () {
259 return !this.responseIsSuccess();
260 }
261};
262
263/** @id Ajax.Request */
264Ajax.Request = function (url, options) {
265 this.__init__(url, options);
266};
267
268/** @id Ajax.Events */
269Ajax.Request.Events = ['Uninitialized', 'Loading', 'Loaded',
270 'Interactive', 'Complete'];
271
272MochiKit.Base.update(Ajax.Request.prototype, Ajax.Base.prototype);
273
274MochiKit.Base.update(Ajax.Request.prototype, {
275 __init__: function (url, options) {
276 this.transport = MochiKit.Async.getXMLHttpRequest();
277 this.setOptions(options);
278 this.request(url);
279 },
280
281/** @id Ajax.Request.prototype.request */
282 request: function (url) {
283 var parameters = this.options.parameters || '';
284 if (parameters.length > 0){
285 parameters += '&_=';
286 }
287
288 try {
289 this.url = url;
290 if (this.options.method == 'get' && parameters.length > 0) {
291 this.url += (this.url.match(/\?/) ? '&' : '?') + parameters;
292 }
293 Ajax.Responders.dispatch('onCreate', this, this.transport);
294
295 this.transport.open(this.options.method, this.url,
296 this.options.asynchronous);
297
298 if (this.options.asynchronous) {
299 this.transport.onreadystatechange = MochiKit.Base.bind(this.onStateChange, this);
300 setTimeout(MochiKit.Base.bind(function () {
301 this.respondToReadyState(1);
302 }, this), 10);
303 }
304
305 this.setRequestHeaders();
306
307 var body = this.options.postBody ? this.options.postBody : parameters;
308 this.transport.send(this.options.method == 'post' ? body : null);
309
310 } catch (e) {
311 this.dispatchException(e);
312 }
313 },
314
315/** @id Ajax.Request.prototype.setRequestHeaders */
316 setRequestHeaders: function () {
317 var requestHeaders = ['X-Requested-With', 'XMLHttpRequest'];
318
319 if (this.options.method == 'post') {
320 requestHeaders.push('Content-type',
321 'application/x-www-form-urlencoded');
322
323 /* Force 'Connection: close' for Mozilla browsers to work around
324 * a bug where XMLHttpRequest sends an incorrect Content-length
325 * header. See Mozilla Bugzilla #246651.
326 */
327 if (this.transport.overrideMimeType) {
328 requestHeaders.push('Connection', 'close');
329 }
330 }
331
332 if (this.options.requestHeaders) {
333 requestHeaders.push.apply(requestHeaders, this.options.requestHeaders);
334 }
335
336 for (var i = 0; i < requestHeaders.length; i += 2) {
337 this.transport.setRequestHeader(requestHeaders[i], requestHeaders[i+1]);
338 }
339 },
340
341/** @id Ajax.Request.prototype.onStateChange */
342 onStateChange: function () {
343 var readyState = this.transport.readyState;
344 if (readyState != 1) {
345 this.respondToReadyState(this.transport.readyState);
346 }
347 },
348
349/** @id Ajax.Request.prototype.header */
350 header: function (name) {
351 try {
352 return this.transport.getResponseHeader(name);
353 } catch (e) {}
354 },
355
356/** @id Ajax.Request.prototype.evalJSON */
357 evalJSON: function () {
358 try {
359 return eval(this.header('X-JSON'));
360 } catch (e) {}
361 },
362
363/** @id Ajax.Request.prototype.evalResponse */
364 evalResponse: function () {
365 try {
366 return eval(this.transport.responseText);
367 } catch (e) {
368 this.dispatchException(e);
369 }
370 },
371
372/** @id Ajax.Request.prototype.respondToReadyState */
373 respondToReadyState: function (readyState) {
374 var event = Ajax.Request.Events[readyState];
375 var transport = this.transport, json = this.evalJSON();
376
377 if (event == 'Complete') {
378 try {
379 (this.options['on' + this.transport.status]
380 || this.options['on' + (this.responseIsSuccess() ? 'Success' : 'Failure')]
381 || MochiKit.Base.noop)(transport, json);
382 } catch (e) {
383 this.dispatchException(e);
384 }
385
386 if ((this.header('Content-type') || '').match(/^text\/javascript/i)) {
387 this.evalResponse();
388 }
389 }
390
391 try {
392 (this.options['on' + event] || MochiKit.Base.noop)(transport, json);
393 Ajax.Responders.dispatch('on' + event, this, transport, json);
394 } catch (e) {
395 this.dispatchException(e);
396 }
397
398 /* Avoid memory leak in MSIE: clean up the oncomplete event handler */
399 if (event == 'Complete') {
400 this.transport.onreadystatechange = MochiKit.Base.noop;
401 }
402 },
403
404/** @id Ajax.Request.prototype.dispatchException */
405 dispatchException: function (exception) {
406 (this.options.onException || MochiKit.Base.noop)(this, exception);
407 Ajax.Responders.dispatch('onException', this, exception);
408 }
409});
410
411/** @id Ajax.Updater */
412Ajax.Updater = function (container, url, options) {
413 this.__init__(container, url, options);
414};
415
416MochiKit.Base.update(Ajax.Updater.prototype, Ajax.Request.prototype);
417
418MochiKit.Base.update(Ajax.Updater.prototype, {
419 __init__: function (container, url, options) {
420 this.containers = {
421 success: container.success ? MochiKit.DOM.getElement(container.success) : MochiKit.DOM.getElement(container),
422 failure: container.failure ? MochiKit.DOM.getElement(container.failure) :
423 (container.success ? null : MochiKit.DOM.getElement(container))
424 }
425 this.transport = MochiKit.Async.getXMLHttpRequest();
426 this.setOptions(options);
427
428 var onComplete = this.options.onComplete || MochiKit.Base.noop;
429 this.options.onComplete = MochiKit.Base.bind(function (transport, object) {
430 this.updateContent();
431 onComplete(transport, object);
432 }, this);
433
434 this.request(url);
435 },
436
437/** @id Ajax.Updater.prototype.updateContent */
438 updateContent: function () {
439 var receiver = this.responseIsSuccess() ?
440 this.containers.success : this.containers.failure;
441 var response = this.transport.responseText;
442
443 if (!this.options.evalScripts) {
444 response = MochiKit.Base.stripScripts(response);
445 }
446
447 if (receiver) {
448 if (this.options.insertion) {
449 new this.options.insertion(receiver, response);
450 } else {
451 MochiKit.DOM.getElement(receiver).innerHTML =
452 MochiKit.Base.stripScripts(response);
453 setTimeout(function () {
454 MochiKit.Base.evalScripts(response);
455 }, 10);
456 }
457 }
458
459 if (this.responseIsSuccess()) {
460 if (this.onComplete) {
461 setTimeout(MochiKit.Base.bind(this.onComplete, this), 10);
462 }
463 }
464 }
465});
466
467/** @id Field */
468var Field = {
469
470/** @id clear */
471 clear: function () {
472 for (var i = 0; i < arguments.length; i++) {
473 MochiKit.DOM.getElement(arguments[i]).value = '';
474 }
475 },
476
477/** @id focus */
478 focus: function (element) {
479 MochiKit.DOM.getElement(element).focus();
480 },
481
482/** @id present */
483 present: function () {
484 for (var i = 0; i < arguments.length; i++) {
485 if (MochiKit.DOM.getElement(arguments[i]).value == '') {
486 return false;
487 }
488 }
489 return true;
490 },
491
492/** @id select */
493 select: function (element) {
494 MochiKit.DOM.getElement(element).select();
495 },
496
497/** @id activate */
498 activate: function (element) {
499 element = MochiKit.DOM.getElement(element);
500 element.focus();
501 if (element.select) {
502 element.select();
503 }
504 },
505
506/** @id scrollFreeActivate */
507 scrollFreeActivate: function (field) {
508 setTimeout(function () {
509 Field.activate(field);
510 }, 1);
511 }
512};
513
514
515/** @id Autocompleter */
516var Autocompleter = {};
517
518/** @id Autocompleter.Base */
519Autocompleter.Base = function () {};
520
521Autocompleter.Base.prototype = {
522
523/** @id Autocompleter.Base.prototype.baseInitialize */
524 baseInitialize: function (element, update, options) {
525 this.element = MochiKit.DOM.getElement(element);
526 this.update = MochiKit.DOM.getElement(update);
527 this.hasFocus = false;
528 this.changed = false;
529 this.active = false;
530 this.index = 0;
531 this.entryCount = 0;
532
533 if (this.setOptions) {
534 this.setOptions(options);
535 }
536 else {
537 this.options = options || {};
538 }
539
540 this.options.paramName = this.options.paramName || this.element.name;
541 this.options.tokens = this.options.tokens || [];
542 this.options.frequency = this.options.frequency || 0.4;
543 this.options.minChars = this.options.minChars || 1;
544 this.options.onShow = this.options.onShow || function (element, update) {
545 if (!update.style.position || update.style.position == 'absolute') {
546 update.style.position = 'absolute';
547 MochiKit.Position.clone(element, update, {
548 setHeight: false,
549 offsetTop: element.offsetHeight
550 });
551 }
552 MochiKit.Visual.appear(update, {duration:0.15});
553 };
554 this.options.onHide = this.options.onHide || function (element, update) {
555 MochiKit.Visual.fade(update, {duration: 0.15});
556 };
557
558 if (typeof(this.options.tokens) == 'string') {
559 this.options.tokens = new Array(this.options.tokens);
560 }
561
562 this.observer = null;
563
564 this.element.setAttribute('autocomplete', 'off');
565
566 MochiKit.Style.hideElement(this.update);
567
568 MochiKit.Signal.connect(this.element, 'onblur', this, this.onBlur);
569 MochiKit.Signal.connect(this.element, 'onkeypress', this, this.onKeyPress, this);
570 },
571
572/** @id Autocompleter.Base.prototype.show */
573 show: function () {
574 if (MochiKit.Style.getStyle(this.update, 'display') == 'none') {
575 this.options.onShow(this.element, this.update);
576 }
577 if (!this.iefix && /MSIE/.test(navigator.userAgent &&
578 (MochiKit.Style.getStyle(this.update, 'position') == 'absolute'))) {
579 new Insertion.After(this.update,
580 '<iframe id="' + this.update.id + '_iefix" '+
581 'style="display:none;position:absolute;filter:progid:DXImageTransform.Microsoft.Alpha(opacity=0);" ' +
582 'src="javascript:false;" frameborder="0" scrolling="no"></iframe>');
583 this.iefix = MochiKit.DOM.getElement(this.update.id + '_iefix');
584 }
585 if (this.iefix) {
586 setTimeout(MochiKit.Base.bind(this.fixIEOverlapping, this), 50);
587 }
588 },
589
590/** @id Autocompleter.Base.prototype.fixIEOverlapping */
591 fixIEOverlapping: function () {
592 MochiKit.Position.clone(this.update, this.iefix);
593 this.iefix.style.zIndex = 1;
594 this.update.style.zIndex = 2;
595 MochiKit.Style.showElement(this.iefix);
596 },
597
598/** @id Autocompleter.Base.prototype.hide */
599 hide: function () {
600 this.stopIndicator();
601 if (MochiKit.Style.getStyle(this.update, 'display') != 'none') {
602 this.options.onHide(this.element, this.update);
603 }
604 if (this.iefix) {
605 MochiKit.Style.hideElement(this.iefix);
606 }
607 },
608
609/** @id Autocompleter.Base.prototype.startIndicator */
610 startIndicator: function () {
611 if (this.options.indicator) {
612 MochiKit.Style.showElement(this.options.indicator);
613 }
614 },
615
616/** @id Autocompleter.Base.prototype.stopIndicator */
617 stopIndicator: function () {
618 if (this.options.indicator) {
619 MochiKit.Style.hideElement(this.options.indicator);
620 }
621 },
622
623/** @id Autocompleter.Base.prototype.onKeyPress */
624 onKeyPress: function (event) {
625 if (this.active) {
626 if (event.key().string == "KEY_TAB" || event.key().string == "KEY_RETURN") {
627 this.selectEntry();
628 MochiKit.Event.stop(event);
629 } else if (event.key().string == "KEY_ESCAPE") {
630 this.hide();
631 this.active = false;
632 MochiKit.Event.stop(event);
633 return;
634 } else if (event.key().string == "KEY_LEFT" || event.key().string == "KEY_RIGHT") {
635 return;
636 } else if (event.key().string == "KEY_UP") {
637 this.markPrevious();
638 this.render();
639 if (/AppleWebKit'/.test(navigator.appVersion)) {
640 event.stop();
641 }
642 return;
643 } else if (event.key().string == "KEY_DOWN") {
644 this.markNext();
645 this.render();
646 if (/AppleWebKit'/.test(navigator.appVersion)) {
647 event.stop();
648 }
649 return;
650 }
651 } else {
652 if (event.key().string == "KEY_TAB" || event.key().string == "KEY_RETURN") {
653 return;
654 }
655 }
656
657 this.changed = true;
658 this.hasFocus = true;
659
660 if (this.observer) {
661 clearTimeout(this.observer);
662 }
663 this.observer = setTimeout(MochiKit.Base.bind(this.onObserverEvent, this),
664 this.options.frequency*1000);
665 },
666
667/** @id Autocompleter.Base.prototype.findElement */
668 findElement: function (event, tagName) {
669 var element = event.target;
670 while (element.parentNode && (!element.tagName ||
671 (element.tagName.toUpperCase() != tagName.toUpperCase()))) {
672 element = element.parentNode;
673 }
674 return element;
675 },
676
677/** @id Autocompleter.Base.prototype.hover */
678 onHover: function (event) {
679 var element = this.findElement(event, 'LI');
680 if (this.index != element.autocompleteIndex) {
681 this.index = element.autocompleteIndex;
682 this.render();
683 }
684 event.stop();
685 },
686
687/** @id Autocompleter.Base.prototype.onClick */
688 onClick: function (event) {
689 var element = this.findElement(event, 'LI');
690 this.index = element.autocompleteIndex;
691 this.selectEntry();
692 this.hide();
693 },
694
695/** @id Autocompleter.Base.prototype.onBlur */
696 onBlur: function (event) {
697 // needed to make click events working
698 setTimeout(MochiKit.Base.bind(this.hide, this), 250);
699 this.hasFocus = false;
700 this.active = false;
701 },
702
703/** @id Autocompleter.Base.prototype.render */
704 render: function () {
705 if (this.entryCount > 0) {
706 for (var i = 0; i < this.entryCount; i++) {
707 this.index == i ?
708 MochiKit.DOM.addElementClass(this.getEntry(i), 'selected') :
709 MochiKit.DOM.removeElementClass(this.getEntry(i), 'selected');
710 }
711 if (this.hasFocus) {
712 this.show();
713 this.active = true;
714 }
715 } else {
716 this.active = false;
717 this.hide();
718 }
719 },
720
721/** @id Autocompleter.Base.prototype.markPrevious */
722 markPrevious: function () {
723 if (this.index > 0) {
724 this.index--
725 } else {
726 this.index = this.entryCount-1;
727 }
728 },
729
730/** @id Autocompleter.Base.prototype.markNext */
731 markNext: function () {
732 if (this.index < this.entryCount-1) {
733 this.index++
734 } else {
735 this.index = 0;
736 }
737 },
738
739/** @id Autocompleter.Base.prototype.getEntry */
740 getEntry: function (index) {
741 return this.update.firstChild.childNodes[index];
742 },
743
744/** @id Autocompleter.Base.prototype.getCurrentEntry */
745 getCurrentEntry: function () {
746 return this.getEntry(this.index);
747 },
748
749/** @id Autocompleter.Base.prototype.selectEntry */
750 selectEntry: function () {
751 this.active = false;
752 this.updateElement(this.getCurrentEntry());
753 },
754
755/** @id Autocompleter.Base.prototype.collectTextNodesIgnoreClass */
756 collectTextNodesIgnoreClass: function (element, className) {
757 return MochiKit.Base.flattenArray(MochiKit.Base.map(function (node) {
758 if (node.nodeType == 3) {
759 return node.nodeValue;
760 } else if (node.hasChildNodes() && !MochiKit.DOM.hasElementClass(node, className)) {
761 return this.collectTextNodesIgnoreClass(node, className);
762 }
763 return '';
764 }, MochiKit.DOM.getElement(element).childNodes)).join('');
765 },
766
767/** @id Autocompleter.Base.prototype.updateElement */
768 updateElement: function (selectedElement) {
769 if (this.options.updateElement) {
770 this.options.updateElement(selectedElement);
771 return;
772 }
773 var value = '';
774 if (this.options.select) {
775 var nodes = document.getElementsByClassName(this.options.select, selectedElement) || [];
776 if (nodes.length > 0) {
777 value = MochiKit.DOM.scrapeText(nodes[0]);
778 }
779 } else {
780 value = this.collectTextNodesIgnoreClass(selectedElement, 'informal');
781 }
782 var lastTokenPos = this.findLastToken();
783 if (lastTokenPos != -1) {
784 var newValue = this.element.value.substr(0, lastTokenPos + 1);
785 var whitespace = this.element.value.substr(lastTokenPos + 1).match(/^\s+/);
786 if (whitespace) {
787 newValue += whitespace[0];
788 }
789 this.element.value = newValue + value;
790 } else {
791 this.element.value = value;
792 }
793 this.element.focus();
794
795 if (this.options.afterUpdateElement) {
796 this.options.afterUpdateElement(this.element, selectedElement);
797 }
798 },
799
800/** @id Autocompleter.Base.prototype.updateChoices */
801 updateChoices: function (choices) {
802 if (!this.changed && this.hasFocus) {
803 this.update.innerHTML = choices;
804 var d = MochiKit.DOM;
805 d.removeEmptyTextNodes(this.update);
806 d.removeEmptyTextNodes(this.update.firstChild);
807
808 if (this.update.firstChild && this.update.firstChild.childNodes) {
809 this.entryCount = this.update.firstChild.childNodes.length;
810 for (var i = 0; i < this.entryCount; i++) {
811 var entry = this.getEntry(i);
812 entry.autocompleteIndex = i;
813 this.addObservers(entry);
814 }
815 } else {
816 this.entryCount = 0;
817 }
818
819 this.stopIndicator();
820
821 this.index = 0;
822 this.render();
823 }
824 },
825
826/** @id Autocompleter.Base.prototype.addObservers */
827 addObservers: function (element) {
828 MochiKit.Signal.connect(element, 'onmouseover', this, this.onHover);
829 MochiKit.Signal.connect(element, 'onclick', this, this.onClick);
830 },
831
832/** @id Autocompleter.Base.prototype.onObserverEvent */
833 onObserverEvent: function () {
834 this.changed = false;
835 if (this.getToken().length >= this.options.minChars) {
836 this.startIndicator();
837 this.getUpdatedChoices();
838 } else {
839 this.active = false;
840 this.hide();
841 }
842 },
843
844/** @id Autocompleter.Base.prototype.getToken */
845 getToken: function () {
846 var tokenPos = this.findLastToken();
847 if (tokenPos != -1) {
848 var ret = this.element.value.substr(tokenPos + 1).replace(/^\s+/,'').replace(/\s+$/,'');
849 } else {
850 var ret = this.element.value;
851 }
852 return /\n/.test(ret) ? '' : ret;
853 },
854
855/** @id Autocompleter.Base.prototype.findLastToken */
856 findLastToken: function () {
857 var lastTokenPos = -1;
858
859 for (var i = 0; i < this.options.tokens.length; i++) {
860 var thisTokenPos = this.element.value.lastIndexOf(this.options.tokens[i]);
861 if (thisTokenPos > lastTokenPos) {
862 lastTokenPos = thisTokenPos;
863 }
864 }
865 return lastTokenPos;
866 }
867}
868
869/** @id Ajax.Autocompleter */
870Ajax.Autocompleter = function (element, update, url, options) {
871 this.__init__(element, update, url, options);
872};
873
874MochiKit.Base.update(Ajax.Autocompleter.prototype, Autocompleter.Base.prototype);
875
876MochiKit.Base.update(Ajax.Autocompleter.prototype, {
877 __init__: function (element, update, url, options) {
878 this.baseInitialize(element, update, options);
879 this.options.asynchronous = true;
880 this.options.onComplete = MochiKit.Base.bind(this.onComplete, this);
881 this.options.defaultParams = this.options.parameters || null;
882 this.url = url;
883 },
884
885/** @id Ajax.Autocompleter.prototype.getUpdatedChoices */
886 getUpdatedChoices: function () {
887 var entry = encodeURIComponent(this.options.paramName) + '=' +
888 encodeURIComponent(this.getToken());
889
890 this.options.parameters = this.options.callback ?
891 this.options.callback(this.element, entry) : entry;
892
893 if (this.options.defaultParams) {
894 this.options.parameters += '&' + this.options.defaultParams;
895 }
896 new Ajax.Request(this.url, this.options);
897 },
898
899/** @id Ajax.Autocompleter.prototype.onComplete */
900 onComplete: function (request) {
901 this.updateChoices(request.responseText);
902 }
903});
904
905/***
906
907The local array autocompleter. Used when you'd prefer to
908inject an array of autocompletion options into the page, rather
909than sending out Ajax queries, which can be quite slow sometimes.
910
911The constructor takes four parameters. The first two are, as usual,
912the id of the monitored textbox, and id of the autocompletion menu.
913The third is the array you want to autocomplete from, and the fourth
914is the options block.
915
916Extra local autocompletion options:
917- choices - How many autocompletion choices to offer
918
919- partialSearch - If false, the autocompleter will match entered
920 text only at the beginning of strings in the
921 autocomplete array. Defaults to true, which will
922 match text at the beginning of any *word* in the
923 strings in the autocomplete array. If you want to
924 search anywhere in the string, additionally set
925 the option fullSearch to true (default: off).
926
927- fullSsearch - Search anywhere in autocomplete array strings.
928
929- partialChars - How many characters to enter before triggering
930 a partial match (unlike minChars, which defines
931 how many characters are required to do any match
932 at all). Defaults to 2.
933
934- ignoreCase - Whether to ignore case when autocompleting.
935 Defaults to true.
936
937It's possible to pass in a custom function as the 'selector'
938option, if you prefer to write your own autocompletion logic.
939In that case, the other options above will not apply unless
940you support them.
941
942***/
943
944/** @id Autocompleter.Local */
945Autocompleter.Local = function (element, update, array, options) {
946 this.__init__(element, update, array, options);
947};
948
949MochiKit.Base.update(Autocompleter.Local.prototype, Autocompleter.Base.prototype);
950
951MochiKit.Base.update(Autocompleter.Local.prototype, {
952 __init__: function (element, update, array, options) {
953 this.baseInitialize(element, update, options);
954 this.options.array = array;
955 },
956
957/** @id Autocompleter.Local.prototype.getUpdatedChoices */
958 getUpdatedChoices: function () {
959 this.updateChoices(this.options.selector(this));
960 },
961
962/** @id Autocompleter.Local.prototype.setOptions */
963 setOptions: function (options) {
964 this.options = MochiKit.Base.update({
965 choices: 10,
966 partialSearch: true,
967 partialChars: 2,
968 ignoreCase: true,
969 fullSearch: false,
970 selector: function (instance) {
971 var ret = []; // Beginning matches
972 var partial = []; // Inside matches
973 var entry = instance.getToken();
974 var count = 0;
975
976 for (var i = 0; i < instance.options.array.length &&
977 ret.length < instance.options.choices ; i++) {
978
979 var elem = instance.options.array[i];
980 var foundPos = instance.options.ignoreCase ?
981 elem.toLowerCase().indexOf(entry.toLowerCase()) :
982 elem.indexOf(entry);
983
984 while (foundPos != -1) {
985 if (foundPos === 0 && elem.length != entry.length) {
986 ret.push('<li><strong>' + elem.substr(0, entry.length) + '</strong>' +
987 elem.substr(entry.length) + '</li>');
988 break;
989 } else if (entry.length >= instance.options.partialChars &&
990 instance.options.partialSearch && foundPos != -1) {
991 if (instance.options.fullSearch || /\s/.test(elem.substr(foundPos - 1, 1))) {
992 partial.push('<li>' + elem.substr(0, foundPos) + '<strong>' +
993 elem.substr(foundPos, entry.length) + '</strong>' + elem.substr(
994 foundPos + entry.length) + '</li>');
995 break;
996 }
997 }
998
999 foundPos = instance.options.ignoreCase ?
1000 elem.toLowerCase().indexOf(entry.toLowerCase(), foundPos + 1) :
1001 elem.indexOf(entry, foundPos + 1);
1002
1003 }
1004 }
1005 if (partial.length) {
1006 ret = ret.concat(partial.slice(0, instance.options.choices - ret.length))
1007 }
1008 return '<ul>' + ret.join('') + '</ul>';
1009 }
1010 }, options || {});
1011 }
1012});
1013
1014/***
1015
1016AJAX in-place editor
1017
1018see documentation on http://wiki.script.aculo.us/scriptaculous/show/Ajax.InPlaceEditor
1019
1020Use this if you notice weird scrolling problems on some browsers,
1021the DOM might be a bit confused when this gets called so do this
1022waits 1 ms (with setTimeout) until it does the activation
1023
1024***/
1025
1026/** @id Ajax.InPlaceEditor */
1027Ajax.InPlaceEditor = function (element, url, options) {
1028 this.__init__(element, url, options);
1029};
1030
1031/** @id Ajax.InPlaceEditor.defaultHighlightColor */
1032Ajax.InPlaceEditor.defaultHighlightColor = '#FFFF99';
1033
1034Ajax.InPlaceEditor.prototype = {
1035 __init__: function (element, url, options) {
1036 this.url = url;
1037 this.element = MochiKit.DOM.getElement(element);
1038
1039 this.options = MochiKit.Base.update({
1040 okButton: true,
1041 okText: 'ok',
1042 cancelLink: true,
1043 cancelText: 'cancel',
1044 savingText: 'Saving...',
1045 clickToEditText: 'Click to edit',
1046 okText: 'ok',
1047 rows: 1,
1048 onComplete: function (transport, element) {
1049 new MochiKit.Visual.Highlight(element, {startcolor: this.options.highlightcolor});
1050 },
1051 onFailure: function (transport) {
1052 alert('Error communicating with the server: ' + MochiKit.Base.stripTags(transport.responseText));
1053 },
1054 callback: function (form) {
1055 return MochiKit.DOM.formContents(form);
1056 },
1057 handleLineBreaks: true,
1058 loadingText: 'Loading...',
1059 savingClassName: 'inplaceeditor-saving',
1060 loadingClassName: 'inplaceeditor-loading',
1061 formClassName: 'inplaceeditor-form',
1062 highlightcolor: Ajax.InPlaceEditor.defaultHighlightColor,
1063 highlightendcolor: '#FFFFFF',
1064 externalControl: null,
1065 submitOnBlur: false,
1066 ajaxOptions: {}
1067 }, options || {});
1068
1069 if (!this.options.formId && this.element.id) {
1070 this.options.formId = this.element.id + '-inplaceeditor';
1071 if (MochiKit.DOM.getElement(this.options.formId)) {
1072 // there's already a form with that name, don't specify an id
1073 this.options.formId = null;
1074 }
1075 }
1076
1077 if (this.options.externalControl) {
1078 this.options.externalControl = MochiKit.DOM.getElement(this.options.externalControl);
1079 }
1080
1081 this.originalBackground = MochiKit.Style.getStyle(this.element, 'background-color');
1082 if (!this.originalBackground) {
1083 this.originalBackground = 'transparent';
1084 }
1085
1086 this.element.title = this.options.clickToEditText;
1087
1088 this.onclickListener = MochiKit.Signal.connect(this.element, 'onclick', this, this.enterEditMode);
1089 this.mouseoverListener = MochiKit.Signal.connect(this.element, 'onmouseover', this, this.enterHover);
1090 this.mouseoutListener = MochiKit.Signal.connect(this.element, 'onmouseout', this, this.leaveHover);
1091 if (this.options.externalControl) {
1092 this.onclickListenerExternal = MochiKit.Signal.connect(this.options.externalControl,
1093 'onclick', this, this.enterEditMode);
1094 this.mouseoverListenerExternal = MochiKit.Signal.connect(this.options.externalControl,
1095 'onmouseover', this, this.enterHover);
1096 this.mouseoutListenerExternal = MochiKit.Signal.connect(this.options.externalControl,
1097 'onmouseout', this, this.leaveHover);
1098 }
1099 },
1100
1101/** @id Ajax.InPlaceEditor.prototype.enterEditMode */
1102 enterEditMode: function (evt) {
1103 if (this.saving) {
1104 return;
1105 }
1106 if (this.editing) {
1107 return;
1108 }
1109 this.editing = true;
1110 this.onEnterEditMode();
1111 if (this.options.externalControl) {
1112 MochiKit.Style.hideElement(this.options.externalControl);
1113 }
1114 MochiKit.Style.hideElement(this.element);
1115 this.createForm();
1116 this.element.parentNode.insertBefore(this.form, this.element);
1117 Field.scrollFreeActivate(this.editField);
1118 // stop the event to avoid a page refresh in Safari
1119 if (evt) {
1120 evt.stop();
1121 }
1122 return false;
1123 },
1124
1125/** @id Ajax.InPlaceEditor.prototype.createForm */
1126 createForm: function () {
1127 this.form = document.createElement('form');
1128 this.form.id = this.options.formId;
1129 MochiKit.DOM.addElementClass(this.form, this.options.formClassName)
1130 this.form.onsubmit = MochiKit.Base.bind(this.onSubmit, this);
1131
1132 this.createEditField();
1133
1134 if (this.options.textarea) {
1135 var br = document.createElement('br');
1136 this.form.appendChild(br);
1137 }
1138
1139 if (this.options.okButton) {
1140 okButton = document.createElement('input');
1141 okButton.type = 'submit';
1142 okButton.value = this.options.okText;
1143 this.form.appendChild(okButton);
1144 }
1145
1146 if (this.options.cancelLink) {
1147 cancelLink = document.createElement('a');
1148 cancelLink.href = '#';
1149 cancelLink.appendChild(document.createTextNode(this.options.cancelText));
1150 cancelLink.onclick = MochiKit.Base.bind(this.onclickCancel, this);
1151 this.form.appendChild(cancelLink);
1152 }
1153 },
1154
1155/** @id Ajax.InPlaceEditor.prototype.hasHTMLLineBreaks */
1156 hasHTMLLineBreaks: function (string) {
1157 if (!this.options.handleLineBreaks) {
1158 return false;
1159 }
1160 return string.match(/<br/i) || string.match(/<p>/i);
1161 },
1162
1163/** @id Ajax.InPlaceEditor.prototype.convertHTMLLineBreaks */
1164 convertHTMLLineBreaks: function (string) {
1165 return string.replace(/<br>/gi, '\n').replace(/<br\/>/gi, '\n').replace(/<\/p>/gi, '\n').replace(/<p>/gi, '');
1166 },
1167
1168/** @id Ajax.InPlaceEditor.prototype.createEditField */
1169 createEditField: function () {
1170 var text;
1171 if (this.options.loadTextURL) {
1172 text = this.options.loadingText;
1173 } else {
1174 text = this.getText();
1175 }
1176
1177 var obj = this;
1178
1179 if (this.options.rows == 1 && !this.hasHTMLLineBreaks(text)) {
1180 this.options.textarea = false;
1181 var textField = document.createElement('input');
1182 textField.obj = this;
1183 textField.type = 'text';
1184 textField.name = 'value';
1185 textField.value = text;
1186 textField.style.backgroundColor = this.options.highlightcolor;
1187 var size = this.options.size || this.options.cols || 0;
1188 if (size !== 0) {
1189 textField.size = size;
1190 }
1191 if (this.options.submitOnBlur) {
1192 textField.onblur = MochiKit.Base.bind(this.onSubmit, this);
1193 }
1194 this.editField = textField;
1195 } else {
1196 this.options.textarea = true;
1197 var textArea = document.createElement('textarea');
1198 textArea.obj = this;
1199 textArea.name = 'value';
1200 textArea.value = this.convertHTMLLineBreaks(text);
1201 textArea.rows = this.options.rows;
1202 textArea.cols = this.options.cols || 40;
1203 if (this.options.submitOnBlur) {
1204 textArea.onblur = MochiKit.Base.bind(this.onSubmit, this);
1205 }
1206 this.editField = textArea;
1207 }
1208
1209 if (this.options.loadTextURL) {
1210 this.loadExternalText();
1211 }
1212 this.form.appendChild(this.editField);
1213 },
1214
1215/** @id Ajax.InPlaceEditor.prototype.getText */
1216 getText: function () {
1217 return this.element.innerHTML;
1218 },
1219
1220/** @id Ajax.InPlaceEditor.prototype.loadExternalText */
1221 loadExternalText: function () {
1222 MochiKit.DOM.addElementClass(this.form, this.options.loadingClassName);
1223 this.editField.disabled = true;
1224 new Ajax.Request(
1225 this.options.loadTextURL,
1226 MochiKit.Base.update({
1227 asynchronous: true,
1228 onComplete: MochiKit.Base.bind(this.onLoadedExternalText, this)
1229 }, this.options.ajaxOptions)
1230 );
1231 },
1232
1233/** @id Ajax.InPlaceEditor.prototype.onLoadedExternalText */
1234 onLoadedExternalText: function (transport) {
1235 MochiKit.DOM.removeElementClass(this.form, this.options.loadingClassName);
1236 this.editField.disabled = false;
1237 this.editField.value = MochiKit.Base.stripTags(transport);
1238 },
1239
1240/** @id Ajax.InPlaceEditor.prototype.onclickCancel */
1241 onclickCancel: function () {
1242 this.onComplete();
1243 this.leaveEditMode();
1244 return false;
1245 },
1246
1247/** @id Ajax.InPlaceEditor.prototype.onFailure */
1248 onFailure: function (transport) {
1249 this.options.onFailure(transport);
1250 if (this.oldInnerHTML) {
1251 this.element.innerHTML = this.oldInnerHTML;
1252 this.oldInnerHTML = null;
1253 }
1254 return false;
1255 },
1256
1257/** @id Ajax.InPlaceEditor.prototype.onSubmit */
1258 onSubmit: function () {
1259 // onLoading resets these so we need to save them away for the Ajax call
1260 var form = this.form;
1261 var value = this.editField.value;
1262
1263 // do this first, sometimes the ajax call returns before we get a
1264 // chance to switch on Saving which means this will actually switch on
1265 // Saving *after* we have left edit mode causing Saving to be
1266 // displayed indefinitely
1267 this.onLoading();
1268
1269 new Ajax.Updater(
1270 {
1271 success: this.element,
1272 // dont update on failure (this could be an option)
1273 failure: null
1274 },
1275 this.url,
1276 MochiKit.Base.update({
1277 parameters: this.options.callback(form, value),
1278 onComplete: MochiKit.Base.bind(this.onComplete, this),
1279 onFailure: MochiKit.Base.bind(this.onFailure, this)
1280 }, this.options.ajaxOptions)
1281 );
1282 // stop the event to avoid a page refresh in Safari
1283 if (arguments.length > 1) {
1284 arguments[0].stop();
1285 }
1286 return false;
1287 },
1288
1289/** @id Ajax.InPlaceEditor.prototype.onLoading */
1290 onLoading: function () {
1291 this.saving = true;
1292 this.removeForm();
1293 this.leaveHover();
1294 this.showSaving();
1295 },
1296
1297/** @id Ajax.InPlaceEditor.prototype.onSaving */
1298 showSaving: function () {
1299 this.oldInnerHTML = this.element.innerHTML;
1300 this.element.innerHTML = this.options.savingText;
1301 MochiKit.DOM.addElementClass(this.element, this.options.savingClassName);
1302 this.element.style.backgroundColor = this.originalBackground;
1303 MochiKit.Style.showElement(this.element);
1304 },
1305
1306/** @id Ajax.InPlaceEditor.prototype.removeForm */
1307 removeForm: function () {
1308 if (this.form) {
1309 if (this.form.parentNode) {
1310 MochiKit.DOM.removeElement(this.form);
1311 }
1312 this.form = null;
1313 }
1314 },
1315
1316/** @id Ajax.InPlaceEditor.prototype.enterHover */
1317 enterHover: function () {
1318 if (this.saving) {
1319 return;
1320 }
1321 this.element.style.backgroundColor = this.options.highlightcolor;
1322 if (this.effect) {
1323 this.effect.cancel();
1324 }
1325 MochiKit.DOM.addElementClass(this.element, this.options.hoverClassName)
1326 },
1327
1328/** @id Ajax.InPlaceEditor.prototype.leaveHover */
1329 leaveHover: function () {
1330 if (this.options.backgroundColor) {
1331 this.element.style.backgroundColor = this.oldBackground;
1332 }
1333 MochiKit.DOM.removeElementClass(this.element, this.options.hoverClassName)
1334 if (this.saving) {
1335 return;
1336 }
1337 this.effect = new MochiKit.Visual.Highlight(this.element, {
1338 startcolor: this.options.highlightcolor,
1339 endcolor: this.options.highlightendcolor,
1340 restorecolor: this.originalBackground
1341 });
1342 },
1343
1344/** @id Ajax.InPlaceEditor.prototype.leaveEditMode */
1345 leaveEditMode: function () {
1346 MochiKit.DOM.removeElementClass(this.element, this.options.savingClassName);
1347 this.removeForm();
1348 this.leaveHover();
1349 this.element.style.backgroundColor = this.originalBackground;
1350 MochiKit.Style.showElement(this.element);
1351 if (this.options.externalControl) {
1352 MochiKit.Style.showElement(this.options.externalControl);
1353 }
1354 this.editing = false;
1355 this.saving = false;
1356 this.oldInnerHTML = null;
1357 this.onLeaveEditMode();
1358 },
1359
1360/** @id Ajax.InPlaceEditor.prototype.onComplete */
1361 onComplete: function (transport) {
1362 this.leaveEditMode();
1363 MochiKit.Base.bind(this.options.onComplete, this)(transport, this.element);
1364 },
1365
1366/** @id Ajax.InPlaceEditor.prototype.onEnterEditMode */
1367 onEnterEditMode: function () {},
1368
1369/** @id Ajax.InPlaceEditor.prototype.onLeaveEditMode */
1370 onLeaveEditMode: function () {},
1371
1372 /** @id Ajax.InPlaceEditor.prototype.dispose */
1373 dispose: function () {
1374 if (this.oldInnerHTML) {
1375 this.element.innerHTML = this.oldInnerHTML;
1376 }
1377 this.leaveEditMode();
1378 MochiKit.Signal.disconnect(this.onclickListener);
1379 MochiKit.Signal.disconnect(this.mouseoverListener);
1380 MochiKit.Signal.disconnect(this.mouseoutListener);
1381 if (this.options.externalControl) {
1382 MochiKit.Signal.disconnect(this.onclickListenerExternal);
1383 MochiKit.Signal.disconnect(this.mouseoverListenerExternal);
1384 MochiKit.Signal.disconnect(this.mouseoutListenerExternal);
1385 }
1386 }
1387};
1388
diff --git a/frontend/beta/js/MochiKit/DOM.js b/frontend/beta/js/MochiKit/DOM.js
new file mode 100644
index 0000000..591c597
--- a/dev/null
+++ b/frontend/beta/js/MochiKit/DOM.js
@@ -0,0 +1,1267 @@
1/***
2
3MochiKit.DOM 1.4
4
5See <http://mochikit.com/> for documentation, downloads, license, etc.
6
7(c) 2005 Bob Ippolito. All rights Reserved.
8
9***/
10
11if (typeof(dojo) != 'undefined') {
12 dojo.provide("MochiKit.DOM");
13 dojo.require("MochiKit.Base");
14}
15if (typeof(JSAN) != 'undefined') {
16 JSAN.use("MochiKit.Base", []);
17}
18
19try {
20 if (typeof(MochiKit.Base) == 'undefined') {
21 throw "";
22 }
23} catch (e) {
24 throw "MochiKit.DOM depends on MochiKit.Base!";
25}
26
27if (typeof(MochiKit.DOM) == 'undefined') {
28 MochiKit.DOM = {};
29}
30
31MochiKit.DOM.NAME = "MochiKit.DOM";
32MochiKit.DOM.VERSION = "1.4";
33MochiKit.DOM.__repr__ = function () {
34 return "[" + this.NAME + " " + this.VERSION + "]";
35};
36MochiKit.DOM.toString = function () {
37 return this.__repr__();
38};
39
40MochiKit.DOM.EXPORT = [
41 "removeEmptyTextNodes",
42 "formContents",
43 "currentWindow",
44 "currentDocument",
45 "withWindow",
46 "withDocument",
47 "registerDOMConverter",
48 "coerceToDOM",
49 "createDOM",
50 "createDOMFunc",
51 "isChildNode",
52 "getNodeAttribute",
53 "removeNodeAttribute",
54 "setNodeAttribute",
55 "updateNodeAttributes",
56 "appendChildNodes",
57 "insertSiblingNodesAfter",
58 "insertSiblingNodesBefore",
59 "replaceChildNodes",
60 "removeElement",
61 "swapDOM",
62 "BUTTON",
63 "TT",
64 "PRE",
65 "H1",
66 "H2",
67 "H3",
68 "BR",
69 "CANVAS",
70 "HR",
71 "LABEL",
72 "TEXTAREA",
73 "FORM",
74 "STRONG",
75 "SELECT",
76 "OPTION",
77 "OPTGROUP",
78 "LEGEND",
79 "FIELDSET",
80 "P",
81 "UL",
82 "OL",
83 "LI",
84 "TD",
85 "TR",
86 "THEAD",
87 "TBODY",
88 "TFOOT",
89 "TABLE",
90 "TH",
91 "INPUT",
92 "SPAN",
93 "A",
94 "DIV",
95 "IMG",
96 "getElement",
97 "$",
98 "getElementsByTagAndClassName",
99 "addToCallStack",
100 "addLoadEvent",
101 "focusOnLoad",
102 "setElementClass",
103 "toggleElementClass",
104 "addElementClass",
105 "removeElementClass",
106 "swapElementClass",
107 "hasElementClass",
108 "escapeHTML",
109 "toHTML",
110 "emitHTML",
111 "scrapeText",
112 "isParent",
113 "getFirstParentByTagAndClassName",
114 "makeClipping",
115 "undoClipping",
116 "makePositioned",
117 "undoPositioned",
118 "getFirstElementByTagAndClassName"
119];
120
121MochiKit.DOM.EXPORT_OK = [
122 "domConverters"
123];
124
125MochiKit.DOM.DEPRECATED = [
126 ['computedStyle', 'MochiKit.Style.getStyle', '1.4'],
127 /** @id MochiKit.DOM.elementDimensions */
128 ['elementDimensions', 'MochiKit.Style.getElementDimensions', '1.4'],
129 /** @id MochiKit.DOM.elementPosition */
130 ['elementPosition', 'MochiKit.Style.getElementPosition', '1.4'],
131 ['hideElement', 'MochiKit.Style.hideElement', '1.4'],
132 /** @id MochiKit.DOM.setElementDimensions */
133 ['setElementDimensions', 'MochiKit.Style.setElementDimensions', '1.4'],
134 /** @id MochiKit.DOM.setElementPosition */
135 ['setElementPosition', 'MochiKit.Style.setElementPosition', '1.4'],
136 ['setDisplayForElement', 'MochiKit.Style.setDisplayForElement', '1.4'],
137 /** @id MochiKit.DOM.setOpacity */
138 ['setOpacity', 'MochiKit.Style.setOpacity', '1.4'],
139 ['showElement', 'MochiKit.Style.showElement', '1.4'],
140 /** @id MochiKit.DOM.Coordinates */
141 ['Coordinates', 'MochiKit.Style.Coordinates', '1.4'], // FIXME: broken
142 /** @id MochiKit.DOM.Dimensions */
143 ['Dimensions', 'MochiKit.Style.Dimensions', '1.4'] // FIXME: broken
144];
145
146/** @id MochiKit.DOM.getViewportDimensions */
147MochiKit.DOM.getViewportDimensions = new Function('' +
148 'if (!MochiKit["Style"]) {' +
149 ' throw new Error("This function has been deprecated and depends on MochiKit.Style.");' +
150 '}' +
151 'return MochiKit.Style.getViewportDimensions.apply(this, arguments);');
152
153MochiKit.Base.update(MochiKit.DOM, {
154
155 /** @id MochiKit.DOM.currentWindow */
156 currentWindow: function () {
157 return MochiKit.DOM._window;
158 },
159
160 /** @id MochiKit.DOM.currentDocument */
161 currentDocument: function () {
162 return MochiKit.DOM._document;
163 },
164
165 /** @id MochiKit.DOM.withWindow */
166 withWindow: function (win, func) {
167 var self = MochiKit.DOM;
168 var oldDoc = self._document;
169 var oldWin = self._window;
170 var rval;
171 try {
172 self._window = win;
173 self._document = win.document;
174 rval = func();
175 } catch (e) {
176 self._window = oldWin;
177 self._document = oldDoc;
178 throw e;
179 }
180 self._window = oldWin;
181 self._document = oldDoc;
182 return rval;
183 },
184
185 /** @id MochiKit.DOM.formContents */
186 formContents: function (elem/* = document.body */) {
187 var names = [];
188 var values = [];
189 var m = MochiKit.Base;
190 var self = MochiKit.DOM;
191 if (typeof(elem) == "undefined" || elem === null) {
192 elem = self._document.body;
193 } else {
194 elem = self.getElement(elem);
195 }
196 m.nodeWalk(elem, function (elem) {
197 var name = elem.name;
198 if (m.isNotEmpty(name)) {
199 var tagName = elem.tagName.toUpperCase();
200 if (tagName === "INPUT"
201 && (elem.type == "radio" || elem.type == "checkbox")
202 && !elem.checked
203 ) {
204 return null;
205 }
206 if (tagName === "SELECT") {
207 if (elem.type == "select-one") {
208 if (elem.selectedIndex >= 0) {
209 var opt = elem.options[elem.selectedIndex];
210 var v = opt.value;
211 if (!v) {
212 var h = opt.outerHTML;
213 // internet explorer sure does suck.
214 if (h && !h.match(/^[^>]+\svalue\s*=/i)) {
215 v = opt.text;
216 }
217 }
218 names.push(name);
219 values.push(v);
220 return null;
221 }
222 // no form elements?
223 names.push(name);
224 values.push("");
225 return null;
226 } else {
227 var opts = elem.options;
228 if (!opts.length) {
229 names.push(name);
230 values.push("");
231 return null;
232 }
233 for (var i = 0; i < opts.length; i++) {
234 var opt = opts[i];
235 if (!opt.selected) {
236 continue;
237 }
238 var v = opt.value;
239 if (!v) {
240 var h = opt.outerHTML;
241 // internet explorer sure does suck.
242 if (h && !h.match(/^[^>]+\svalue\s*=/i)) {
243 v = opt.text;
244 }
245 }
246 names.push(name);
247 values.push(v);
248 }
249 return null;
250 }
251 }
252 if (tagName === "FORM" || tagName === "P" || tagName === "SPAN"
253 || tagName === "DIV"
254 ) {
255 return elem.childNodes;
256 }
257 names.push(name);
258 values.push(elem.value || '');
259 return null;
260 }
261 return elem.childNodes;
262 });
263 return [names, values];
264 },
265
266 /** @id MochiKit.DOM.withDocument */
267 withDocument: function (doc, func) {
268 var self = MochiKit.DOM;
269 var oldDoc = self._document;
270 var rval;
271 try {
272 self._document = doc;
273 rval = func();
274 } catch (e) {
275 self._document = oldDoc;
276 throw e;
277 }
278 self._document = oldDoc;
279 return rval;
280 },
281
282 /** @id MochiKit.DOM.registerDOMConverter */
283 registerDOMConverter: function (name, check, wrap, /* optional */override) {
284 MochiKit.DOM.domConverters.register(name, check, wrap, override);
285 },
286
287 /** @id MochiKit.DOM.coerceToDOM */
288 coerceToDOM: function (node, ctx) {
289 var m = MochiKit.Base;
290 var im = MochiKit.Iter;
291 var self = MochiKit.DOM;
292 if (im) {
293 var iter = im.iter;
294 var repeat = im.repeat;
295 var map = m.map;
296 }
297 var domConverters = self.domConverters;
298 var coerceToDOM = arguments.callee;
299 var NotFound = m.NotFound;
300 while (true) {
301 if (typeof(node) == 'undefined' || node === null) {
302 return null;
303 }
304 if (typeof(node.nodeType) != 'undefined' && node.nodeType > 0) {
305 return node;
306 }
307 if (typeof(node) == 'number' || typeof(node) == 'boolean') {
308 node = node.toString();
309 // FALL THROUGH
310 }
311 if (typeof(node) == 'string') {
312 return self._document.createTextNode(node);
313 }
314 if (typeof(node.__dom__) == 'function') {
315 node = node.__dom__(ctx);
316 continue;
317 }
318 if (typeof(node.dom) == 'function') {
319 node = node.dom(ctx);
320 continue;
321 }
322 if (typeof(node) == 'function') {
323 node = node.apply(ctx, [ctx]);
324 continue;
325 }
326
327 if (im) {
328 // iterable
329 var iterNodes = null;
330 try {
331 iterNodes = iter(node);
332 } catch (e) {
333 // pass
334 }
335 if (iterNodes) {
336 return map(coerceToDOM, iterNodes, repeat(ctx));
337 }
338 }
339
340 // adapter
341 try {
342 node = domConverters.match(node, ctx);
343 continue;
344 } catch (e) {
345 if (e != NotFound) {
346 throw e;
347 }
348 }
349
350 // fallback
351 return self._document.createTextNode(node.toString());
352 }
353 // mozilla warnings aren't too bright
354 return undefined;
355 },
356
357 /** @id MochiKit.DOM.isChildNode */
358 isChildNode: function (node, maybeparent) {
359 var self = MochiKit.DOM;
360 if (typeof(node) == "string") {
361 node = self.getElement(node);
362 }
363 if (typeof(maybeparent) == "string") {
364 maybeparent = self.getElement(maybeparent);
365 }
366 if (node === maybeparent) {
367 return true;
368 }
369 while (node && node.tagName.toUpperCase() != "BODY") {
370 node = node.parentNode;
371 if (node === maybeparent) {
372 return true;
373 }
374 }
375 return false;
376 },
377
378 /** @id MochiKit.DOM.setNodeAttribute */
379 setNodeAttribute: function (node, attr, value) {
380 var o = {};
381 o[attr] = value;
382 try {
383 return MochiKit.DOM.updateNodeAttributes(node, o);
384 } catch (e) {
385 // pass
386 }
387 return null;
388 },
389
390 /** @id MochiKit.DOM.getNodeAttribute */
391 getNodeAttribute: function (node, attr) {
392 var self = MochiKit.DOM;
393 var rename = self.attributeArray.renames[attr];
394 node = self.getElement(node);
395 try {
396 if (rename) {
397 return node[rename];
398 }
399 return node.getAttribute(attr);
400 } catch (e) {
401 // pass
402 }
403 return null;
404 },
405
406 /** @id MochiKit.DOM.removeNodeAttribute */
407 removeNodeAttribute: function (node, attr) {
408 var self = MochiKit.DOM;
409 var rename = self.attributeArray.renames[attr];
410 node = self.getElement(node);
411 try {
412 if (rename) {
413 return node[rename];
414 }
415 return node.removeAttribute(attr);
416 } catch (e) {
417 // pass
418 }
419 return null;
420 },
421
422 /** @id MochiKit.DOM.updateNodeAttributes */
423 updateNodeAttributes: function (node, attrs) {
424 var elem = node;
425 var self = MochiKit.DOM;
426 if (typeof(node) == 'string') {
427 elem = self.getElement(node);
428 }
429 if (attrs) {
430 var updatetree = MochiKit.Base.updatetree;
431 if (self.attributeArray.compliant) {
432 // not IE, good.
433 for (var k in attrs) {
434 var v = attrs[k];
435 if (typeof(v) == 'object' && typeof(elem[k]) == 'object') {
436 if (k == "style" && MochiKit.Style) {
437 MochiKit.Style.setStyle(elem, v);
438 } else {
439 updatetree(elem[k], v);
440 }
441 } else if (k.substring(0, 2) == "on") {
442 if (typeof(v) == "string") {
443 v = new Function(v);
444 }
445 elem[k] = v;
446 } else {
447 elem.setAttribute(k, v);
448 }
449 }
450 } else {
451 // IE is insane in the membrane
452 var renames = self.attributeArray.renames;
453 for (k in attrs) {
454 v = attrs[k];
455 var renamed = renames[k];
456 if (k == "style" && typeof(v) == "string") {
457 elem.style.cssText = v;
458 } else if (typeof(renamed) == "string") {
459 elem[renamed] = v;
460 } else if (typeof(elem[k]) == 'object'
461 && typeof(v) == 'object') {
462 if (k == "style" && MochiKit.Style) {
463 MochiKit.Style.setStyle(elem, v);
464 } else {
465 updatetree(elem[k], v);
466 }
467 } else if (k.substring(0, 2) == "on") {
468 if (typeof(v) == "string") {
469 v = new Function(v);
470 }
471 elem[k] = v;
472 } else {
473 elem.setAttribute(k, v);
474 }
475 }
476 }
477 }
478 return elem;
479 },
480
481 /** @id MochiKit.DOM.appendChildNodes */
482 appendChildNodes: function (node/*, nodes...*/) {
483 var elem = node;
484 var self = MochiKit.DOM;
485 if (typeof(node) == 'string') {
486 elem = self.getElement(node);
487 }
488 var nodeStack = [
489 self.coerceToDOM(
490 MochiKit.Base.extend(null, arguments, 1),
491 elem
492 )
493 ];
494 var concat = MochiKit.Base.concat;
495 while (nodeStack.length) {
496 var n = nodeStack.shift();
497 if (typeof(n) == 'undefined' || n === null) {
498 // pass
499 } else if (typeof(n.nodeType) == 'number') {
500 elem.appendChild(n);
501 } else {
502 nodeStack = concat(n, nodeStack);
503 }
504 }
505 return elem;
506 },
507
508
509 /** @id MochiKit.DOM.insertSiblingNodesBefore */
510 insertSiblingNodesBefore: function (node/*, nodes...*/) {
511 var elem = node;
512 var self = MochiKit.DOM;
513 if (typeof(node) == 'string') {
514 elem = self.getElement(node);
515 }
516 var nodeStack = [
517 self.coerceToDOM(
518 MochiKit.Base.extend(null, arguments, 1),
519 elem
520 )
521 ];
522 var parentnode = elem.parentNode;
523 var concat = MochiKit.Base.concat;
524 while (nodeStack.length) {
525 var n = nodeStack.shift();
526 if (typeof(n) == 'undefined' || n === null) {
527 // pass
528 } else if (typeof(n.nodeType) == 'number') {
529 parentnode.insertBefore(n, elem);
530 } else {
531 nodeStack = concat(n, nodeStack);
532 }
533 }
534 return parentnode;
535 },
536
537 /** @id MochiKit.DOM.insertSiblingNodesAfter */
538 insertSiblingNodesAfter: function (node/*, nodes...*/) {
539 var elem = node;
540 var self = MochiKit.DOM;
541
542 if (typeof(node) == 'string') {
543 elem = self.getElement(node);
544 }
545 var nodeStack = [
546 self.coerceToDOM(
547 MochiKit.Base.extend(null, arguments, 1),
548 elem
549 )
550 ];
551
552 if (elem.nextSibling) {
553 return self.insertSiblingNodesBefore(elem.nextSibling, nodeStack);
554 }
555 else {
556 return self.appendChildNodes(elem.parentNode, nodeStack);
557 }
558 },
559
560 /** @id MochiKit.DOM.replaceChildNodes */
561 replaceChildNodes: function (node/*, nodes...*/) {
562 var elem = node;
563 var self = MochiKit.DOM;
564 if (typeof(node) == 'string') {
565 elem = self.getElement(node);
566 arguments[0] = elem;
567 }
568 var child;
569 while ((child = elem.firstChild)) {
570 elem.removeChild(child);
571 }
572 if (arguments.length < 2) {
573 return elem;
574 } else {
575 return self.appendChildNodes.apply(this, arguments);
576 }
577 },
578
579 /** @id MochiKit.DOM.createDOM */
580 createDOM: function (name, attrs/*, nodes... */) {
581 var elem;
582 var self = MochiKit.DOM;
583 var m = MochiKit.Base;
584 if (typeof(attrs) == "string" || typeof(attrs) == "number") {
585 var args = m.extend([name, null], arguments, 1);
586 return arguments.callee.apply(this, args);
587 }
588 if (typeof(name) == 'string') {
589 // Internet Explorer is dumb
590 var xhtml = self._xhtml;
591 if (attrs && !self.attributeArray.compliant) {
592 // http://msdn.microsoft.com/workshop/author/dhtml/reference/properties/name_2.asp
593 var contents = "";
594 if ('name' in attrs) {
595 contents += ' name="' + self.escapeHTML(attrs.name) + '"';
596 }
597 if (name == 'input' && 'type' in attrs) {
598 contents += ' type="' + self.escapeHTML(attrs.type) + '"';
599 }
600 if (contents) {
601 name = "<" + name + contents + ">";
602 xhtml = false;
603 }
604 }
605 var d = self._document;
606 if (xhtml && d === document) {
607 elem = d.createElementNS("http://www.w3.org/1999/xhtml", name);
608 } else {
609 elem = d.createElement(name);
610 }
611 } else {
612 elem = name;
613 }
614 if (attrs) {
615 self.updateNodeAttributes(elem, attrs);
616 }
617 if (arguments.length <= 2) {
618 return elem;
619 } else {
620 var args = m.extend([elem], arguments, 2);
621 return self.appendChildNodes.apply(this, args);
622 }
623 },
624
625 /** @id MochiKit.DOM.createDOMFunc */
626 createDOMFunc: function (/* tag, attrs, *nodes */) {
627 var m = MochiKit.Base;
628 return m.partial.apply(
629 this,
630 m.extend([MochiKit.DOM.createDOM], arguments)
631 );
632 },
633
634 /** @id MochiKit.DOM.removeElement */
635 removeElement: function (elem) {
636 var e = MochiKit.DOM.getElement(elem);
637 e.parentNode.removeChild(e);
638 return e;
639 },
640
641 /** @id MochiKit.DOM.swapDOM */
642 swapDOM: function (dest, src) {
643 var self = MochiKit.DOM;
644 dest = self.getElement(dest);
645 var parent = dest.parentNode;
646 if (src) {
647 src = self.getElement(src);
648 parent.replaceChild(src, dest);
649 } else {
650 parent.removeChild(dest);
651 }
652 return src;
653 },
654
655 /** @id MochiKit.DOM.getElement */
656 getElement: function (id) {
657 var self = MochiKit.DOM;
658 if (arguments.length == 1) {
659 return ((typeof(id) == "string") ?
660 self._document.getElementById(id) : id);
661 } else {
662 return MochiKit.Base.map(self.getElement, arguments);
663 }
664 },
665
666 /** @id MochiKit.DOM.getElementsByTagAndClassName */
667 getElementsByTagAndClassName: function (tagName, className,
668 /* optional */parent) {
669 var self = MochiKit.DOM;
670 if (typeof(tagName) == 'undefined' || tagName === null) {
671 tagName = '*';
672 }
673 if (typeof(parent) == 'undefined' || parent === null) {
674 parent = self._document;
675 }
676 parent = self.getElement(parent);
677 var children = (parent.getElementsByTagName(tagName)
678 || self._document.all);
679 if (typeof(className) == 'undefined' || className === null) {
680 return MochiKit.Base.extend(null, children);
681 }
682
683 var elements = [];
684 for (var i = 0; i < children.length; i++) {
685 var child = children[i];
686 var cls = child.className;
687 if (!cls) {
688 continue;
689 }
690 var classNames = cls.split(' ');
691 for (var j = 0; j < classNames.length; j++) {
692 if (classNames[j] == className) {
693 elements.push(child);
694 break;
695 }
696 }
697 }
698
699 return elements;
700 },
701
702 _newCallStack: function (path, once) {
703 var rval = function () {
704 var callStack = arguments.callee.callStack;
705 for (var i = 0; i < callStack.length; i++) {
706 if (callStack[i].apply(this, arguments) === false) {
707 break;
708 }
709 }
710 if (once) {
711 try {
712 this[path] = null;
713 } catch (e) {
714 // pass
715 }
716 }
717 };
718 rval.callStack = [];
719 return rval;
720 },
721
722 /** @id MochiKit.DOM.addToCallStack */
723 addToCallStack: function (target, path, func, once) {
724 var self = MochiKit.DOM;
725 var existing = target[path];
726 var regfunc = existing;
727 if (!(typeof(existing) == 'function'
728 && typeof(existing.callStack) == "object"
729 && existing.callStack !== null)) {
730 regfunc = self._newCallStack(path, once);
731 if (typeof(existing) == 'function') {
732 regfunc.callStack.push(existing);
733 }
734 target[path] = regfunc;
735 }
736 regfunc.callStack.push(func);
737 },
738
739 /** @id MochiKit.DOM.addLoadEvent */
740 addLoadEvent: function (func) {
741 var self = MochiKit.DOM;
742 self.addToCallStack(self._window, "onload", func, true);
743
744 },
745
746 /** @id MochiKit.DOM.focusOnLoad */
747 focusOnLoad: function (element) {
748 var self = MochiKit.DOM;
749 self.addLoadEvent(function () {
750 element = self.getElement(element);
751 if (element) {
752 element.focus();
753 }
754 });
755 },
756
757 /** @id MochiKit.DOM.setElementClass */
758 setElementClass: function (element, className) {
759 var self = MochiKit.DOM;
760 var obj = self.getElement(element);
761 if (self.attributeArray.compliant) {
762 obj.setAttribute("class", className);
763 } else {
764 obj.setAttribute("className", className);
765 }
766 },
767
768 /** @id MochiKit.DOM.toggleElementClass */
769 toggleElementClass: function (className/*, element... */) {
770 var self = MochiKit.DOM;
771 for (var i = 1; i < arguments.length; i++) {
772 var obj = self.getElement(arguments[i]);
773 if (!self.addElementClass(obj, className)) {
774 self.removeElementClass(obj, className);
775 }
776 }
777 },
778
779 /** @id MochiKit.DOM.addElementClass */
780 addElementClass: function (element, className) {
781 var self = MochiKit.DOM;
782 var obj = self.getElement(element);
783 var cls = obj.className;
784 // trivial case, no className yet
785 if (cls == undefined || cls.length === 0) {
786 self.setElementClass(obj, className);
787 return true;
788 }
789 // the other trivial case, already set as the only class
790 if (cls == className) {
791 return false;
792 }
793 var classes = cls.split(" ");
794 for (var i = 0; i < classes.length; i++) {
795 // already present
796 if (classes[i] == className) {
797 return false;
798 }
799 }
800 // append class
801 self.setElementClass(obj, cls + " " + className);
802 return true;
803 },
804
805 /** @id MochiKit.DOM.removeElementClass */
806 removeElementClass: function (element, className) {
807 var self = MochiKit.DOM;
808 var obj = self.getElement(element);
809 var cls = obj.className;
810 // trivial case, no className yet
811 if (cls == undefined || cls.length === 0) {
812 return false;
813 }
814 // other trivial case, set only to className
815 if (cls == className) {
816 self.setElementClass(obj, "");
817 return true;
818 }
819 var classes = cls.split(" ");
820 for (var i = 0; i < classes.length; i++) {
821 // already present
822 if (classes[i] == className) {
823 // only check sane case where the class is used once
824 classes.splice(i, 1);
825 self.setElementClass(obj, classes.join(" "));
826 return true;
827 }
828 }
829 // not found
830 return false;
831 },
832
833 /** @id MochiKit.DOM.swapElementClass */
834 swapElementClass: function (element, fromClass, toClass) {
835 var obj = MochiKit.DOM.getElement(element);
836 var res = MochiKit.DOM.removeElementClass(obj, fromClass);
837 if (res) {
838 MochiKit.DOM.addElementClass(obj, toClass);
839 }
840 return res;
841 },
842
843 /** @id MochiKit.DOM.hasElementClass */
844 hasElementClass: function (element, className/*...*/) {
845 var obj = MochiKit.DOM.getElement(element);
846 var cls = obj.className;
847 if (!cls) {
848 return false;
849 }
850 var classes = cls.split(" ");
851 for (var i = 1; i < arguments.length; i++) {
852 var good = false;
853 for (var j = 0; j < classes.length; j++) {
854 if (classes[j] == arguments[i]) {
855 good = true;
856 break;
857 }
858 }
859 if (!good) {
860 return false;
861 }
862 }
863 return true;
864 },
865
866 /** @id MochiKit.DOM.escapeHTML */
867 escapeHTML: function (s) {
868 return s.replace(/&/g, "&amp;"
869 ).replace(/"/g, "&quot;"
870 ).replace(/</g, "&lt;"
871 ).replace(/>/g, "&gt;");
872 },
873
874 /** @id MochiKit.DOM.toHTML */
875 toHTML: function (dom) {
876 return MochiKit.DOM.emitHTML(dom).join("");
877 },
878
879 /** @id MochiKit.DOM.emitHTML */
880 emitHTML: function (dom, /* optional */lst) {
881 if (typeof(lst) == 'undefined' || lst === null) {
882 lst = [];
883 }
884 // queue is the call stack, we're doing this non-recursively
885 var queue = [dom];
886 var self = MochiKit.DOM;
887 var escapeHTML = self.escapeHTML;
888 var attributeArray = self.attributeArray;
889 while (queue.length) {
890 dom = queue.pop();
891 if (typeof(dom) == 'string') {
892 lst.push(dom);
893 } else if (dom.nodeType == 1) {
894 // we're not using higher order stuff here
895 // because safari has heisenbugs.. argh.
896 //
897 // I think it might have something to do with
898 // garbage collection and function calls.
899 lst.push('<' + dom.tagName.toLowerCase());
900 var attributes = [];
901 var domAttr = attributeArray(dom);
902 for (var i = 0; i < domAttr.length; i++) {
903 var a = domAttr[i];
904 attributes.push([
905 " ",
906 a.name,
907 '="',
908 escapeHTML(a.value),
909 '"'
910 ]);
911 }
912 attributes.sort();
913 for (i = 0; i < attributes.length; i++) {
914 var attrs = attributes[i];
915 for (var j = 0; j < attrs.length; j++) {
916 lst.push(attrs[j]);
917 }
918 }
919 if (dom.hasChildNodes()) {
920 lst.push(">");
921 // queue is the FILO call stack, so we put the close tag
922 // on first
923 queue.push("</" + dom.tagName.toLowerCase() + ">");
924 var cnodes = dom.childNodes;
925 for (i = cnodes.length - 1; i >= 0; i--) {
926 queue.push(cnodes[i]);
927 }
928 } else {
929 lst.push('/>');
930 }
931 } else if (dom.nodeType == 3) {
932 lst.push(escapeHTML(dom.nodeValue));
933 }
934 }
935 return lst;
936 },
937
938 /** @id MochiKit.DOM.scrapeText */
939 scrapeText: function (node, /* optional */asArray) {
940 var rval = [];
941 (function (node) {
942 var cn = node.childNodes;
943 if (cn) {
944 for (var i = 0; i < cn.length; i++) {
945 arguments.callee.call(this, cn[i]);
946 }
947 }
948 var nodeValue = node.nodeValue;
949 if (typeof(nodeValue) == 'string') {
950 rval.push(nodeValue);
951 }
952 })(MochiKit.DOM.getElement(node));
953 if (asArray) {
954 return rval;
955 } else {
956 return rval.join("");
957 }
958 },
959
960 /** @id MochiKit.DOM.removeEmptyTextNodes */
961 removeEmptyTextNodes: function (element) {
962 element = MochiKit.DOM.getElement(element);
963 for (var i = 0; i < element.childNodes.length; i++) {
964 var node = element.childNodes[i];
965 if (node.nodeType == 3 && !/\S/.test(node.nodeValue)) {
966 node.parentNode.removeChild(node);
967 }
968 }
969 },
970
971 /** @id MochiKit.DOM.makeClipping */
972 makeClipping: function (element) {
973 element = MochiKit.DOM.getElement(element);
974 var oldOverflow = element.style.overflow;
975 if ((MochiKit.Style.getStyle(element, 'overflow') || 'visible') != 'hidden') {
976 element.style.overflow = 'hidden';
977 }
978 return oldOverflow;
979 },
980
981 /** @id MochiKit.DOM.undoClipping */
982 undoClipping: function (element, overflow) {
983 element = MochiKit.DOM.getElement(element);
984 if (!overflow) {
985 return;
986 }
987 element.style.overflow = overflow;
988 },
989
990 /** @id MochiKit.DOM.makePositioned */
991 makePositioned: function (element) {
992 element = MochiKit.DOM.getElement(element);
993 var pos = MochiKit.Style.getStyle(element, 'position');
994 if (pos == 'static' || !pos) {
995 element.style.position = 'relative';
996 // Opera returns the offset relative to the positioning context,
997 // when an element is position relative but top and left have
998 // not been defined
999 if (/Opera/.test(navigator.userAgent)) {
1000 element.style.top = 0;
1001 element.style.left = 0;
1002 }
1003 }
1004 },
1005
1006 /** @id MochiKit.DOM.undoPositioned */
1007 undoPositioned: function (element) {
1008 element = MochiKit.DOM.getElement(element);
1009 if (element.style.position == 'relative') {
1010 element.style.position = element.style.top = element.style.left = element.style.bottom = element.style.right = '';
1011 }
1012 },
1013
1014 /** @id MochiKit.DOM.getFirstElementByTagAndClassName */
1015 getFirstElementByTagAndClassName: function (tagName, className,
1016 /* optional */parent) {
1017 var self = MochiKit.DOM;
1018 if (typeof(tagName) == 'undefined' || tagName === null) {
1019 tagName = '*';
1020 }
1021 if (typeof(parent) == 'undefined' || parent === null) {
1022 parent = self._document;
1023 }
1024 parent = self.getElement(parent);
1025 var children = (parent.getElementsByTagName(tagName)
1026 || self._document.all);
1027 if (typeof(className) == 'undefined' || className === null) {
1028 return children[0];
1029 }
1030
1031 for (var i = 0; i < children.length; i++) {
1032 var child = children[i];
1033 var classNames = child.className.split(' ');
1034 for (var j = 0; j < classNames.length; j++) {
1035 if (classNames[j] == className) {
1036 return child;
1037 }
1038 }
1039 }
1040 },
1041
1042 /** @id MochiKit.DOM.getFirstParentByTagAndClassName */
1043 getFirstParentByTagAndClassName: function (elem, tagName, className) {
1044 var self = MochiKit.DOM;
1045 elem = self.getElement(elem);
1046 if (typeof(tagName) == 'undefined' || tagName === null) {
1047 tagName = '*';
1048 } else {
1049 tagName = tagName.toUpperCase();
1050 }
1051 if (typeof(className) == 'undefined' || className === null) {
1052 className = null;
1053 }
1054
1055 var classList = '';
1056 var curTagName = '';
1057 while (elem && elem.tagName) {
1058 elem = elem.parentNode;
1059 if (tagName == '*' && className === null) {
1060 return elem;
1061 }
1062 classList = elem.className.split(' ');
1063 curTagName = elem.tagName.toUpperCase();
1064 if (className === null && tagName == curTagName) {
1065 return elem;
1066 } else if (className !== null) {
1067 for (var i = 0; i < classList.length; i++) {
1068 if (tagName == '*' && classList[i] == className) {
1069 return elem;
1070 } else if (tagName == curTagName && classList[i] == className) {
1071 return elem;
1072 }
1073 }
1074 }
1075 }
1076 return elem;
1077 },
1078
1079 /** @id MochiKit.DOM.isParent */
1080 isParent: function (child, element) {
1081 if (!child.parentNode || child == element) {
1082 return false;
1083 }
1084
1085 if (child.parentNode == element) {
1086 return true;
1087 }
1088
1089 return MochiKit.DOM.isParent(child.parentNode, element);
1090 },
1091
1092 __new__: function (win) {
1093
1094 var m = MochiKit.Base;
1095 if (typeof(document) != "undefined") {
1096 this._document = document;
1097 var kXULNSURI = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
1098 this._xhtml = (document.documentElement &&
1099 document.createElementNS &&
1100 document.documentElement.namespaceURI === kXULNSURI);
1101 } else if (MochiKit.MockDOM) {
1102 this._document = MochiKit.MockDOM.document;
1103 }
1104 this._window = win;
1105
1106 this.domConverters = new m.AdapterRegistry();
1107
1108 var __tmpElement = this._document.createElement("span");
1109 var attributeArray;
1110 if (__tmpElement && __tmpElement.attributes &&
1111 __tmpElement.attributes.length > 0) {
1112 // for braindead browsers (IE) that insert extra junk
1113 var filter = m.filter;
1114 attributeArray = function (node) {
1115 return filter(attributeArray.ignoreAttrFilter, node.attributes);
1116 };
1117 attributeArray.ignoreAttr = {};
1118 var attrs = __tmpElement.attributes;
1119 var ignoreAttr = attributeArray.ignoreAttr;
1120 for (var i = 0; i < attrs.length; i++) {
1121 var a = attrs[i];
1122 ignoreAttr[a.name] = a.value;
1123 }
1124 attributeArray.ignoreAttrFilter = function (a) {
1125 return (attributeArray.ignoreAttr[a.name] != a.value);
1126 };
1127 attributeArray.compliant = false;
1128 attributeArray.renames = {
1129 "class": "className",
1130 "checked": "defaultChecked",
1131 "usemap": "useMap",
1132 "for": "htmlFor",
1133 "readonly": "readOnly",
1134 "colspan": "colSpan",
1135 "bgcolor": "bgColor"
1136 };
1137 } else {
1138 attributeArray = function (node) {
1139 /***
1140
1141 Return an array of attributes for a given node,
1142 filtering out attributes that don't belong for
1143 that are inserted by "Certain Browsers".
1144
1145 ***/
1146 return node.attributes;
1147 };
1148 attributeArray.compliant = true;
1149 attributeArray.renames = {};
1150 }
1151 this.attributeArray = attributeArray;
1152
1153 // FIXME: this really belongs in Base, and could probably be cleaner
1154 var _deprecated = function(fromModule, arr) {
1155 var modules = arr[1].split('.');
1156 var str = '';
1157 var obj = {};
1158
1159 str += 'if (!MochiKit.' + modules[1] + ') { throw new Error("';
1160 str += 'This function has been deprecated and depends on MochiKit.';
1161 str += modules[1] + '.");}';
1162 str += 'return MochiKit.' + modules[1] + '.' + arr[0];
1163 str += '.apply(this, arguments);';
1164
1165 obj[modules[2]] = new Function(str);
1166 MochiKit.Base.update(MochiKit[fromModule], obj);
1167 }
1168 for (var i; i < MochiKit.DOM.DEPRECATED.length; i++) {
1169 _deprecated('DOM', MochiKit.DOM.DEPRECATED[i]);
1170 }
1171
1172 // shorthand for createDOM syntax
1173 var createDOMFunc = this.createDOMFunc;
1174 /** @id MochiKit.DOM.UL */
1175 this.UL = createDOMFunc("ul");
1176 /** @id MochiKit.DOM.OL */
1177 this.OL = createDOMFunc("ol");
1178 /** @id MochiKit.DOM.LI */
1179 this.LI = createDOMFunc("li");
1180 /** @id MochiKit.DOM.TD */
1181 this.TD = createDOMFunc("td");
1182 /** @id MochiKit.DOM.TR */
1183 this.TR = createDOMFunc("tr");
1184 /** @id MochiKit.DOM.TBODY */
1185 this.TBODY = createDOMFunc("tbody");
1186 /** @id MochiKit.DOM.THEAD */
1187 this.THEAD = createDOMFunc("thead");
1188 /** @id MochiKit.DOM.TFOOT */
1189 this.TFOOT = createDOMFunc("tfoot");
1190 /** @id MochiKit.DOM.TABLE */
1191 this.TABLE = createDOMFunc("table");
1192 /** @id MochiKit.DOM.TH */
1193 this.TH = createDOMFunc("th");
1194 /** @id MochiKit.DOM.INPUT */
1195 this.INPUT = createDOMFunc("input");
1196 /** @id MochiKit.DOM.SPAN */
1197 this.SPAN = createDOMFunc("span");
1198 /** @id MochiKit.DOM.A */
1199 this.A = createDOMFunc("a");
1200 /** @id MochiKit.DOM.DIV */
1201 this.DIV = createDOMFunc("div");
1202 /** @id MochiKit.DOM.IMG */
1203 this.IMG = createDOMFunc("img");
1204 /** @id MochiKit.DOM.BUTTON */
1205 this.BUTTON = createDOMFunc("button");
1206 /** @id MochiKit.DOM.TT */
1207 this.TT = createDOMFunc("tt");
1208 /** @id MochiKit.DOM.PRE */
1209 this.PRE = createDOMFunc("pre");
1210 /** @id MochiKit.DOM.H1 */
1211 this.H1 = createDOMFunc("h1");
1212 /** @id MochiKit.DOM.H2 */
1213 this.H2 = createDOMFunc("h2");
1214 /** @id MochiKit.DOM.H3 */
1215 this.H3 = createDOMFunc("h3");
1216 /** @id MochiKit.DOM.BR */
1217 this.BR = createDOMFunc("br");
1218 /** @id MochiKit.DOM.HR */
1219 this.HR = createDOMFunc("hr");
1220 /** @id MochiKit.DOM.LABEL */
1221 this.LABEL = createDOMFunc("label");
1222 /** @id MochiKit.DOM.TEXTAREA */
1223 this.TEXTAREA = createDOMFunc("textarea");
1224 /** @id MochiKit.DOM.FORM */
1225 this.FORM = createDOMFunc("form");
1226 /** @id MochiKit.DOM.P */
1227 this.P = createDOMFunc("p");
1228 /** @id MochiKit.DOM.SELECT */
1229 this.SELECT = createDOMFunc("select");
1230 /** @id MochiKit.DOM.OPTION */
1231 this.OPTION = createDOMFunc("option");
1232 /** @id MochiKit.DOM.OPTGROUP */
1233 this.OPTGROUP = createDOMFunc("optgroup");
1234 /** @id MochiKit.DOM.LEGEND */
1235 this.LEGEND = createDOMFunc("legend");
1236 /** @id MochiKit.DOM.FIELDSET */
1237 this.FIELDSET = createDOMFunc("fieldset");
1238 /** @id MochiKit.DOM.STRONG */
1239 this.STRONG = createDOMFunc("strong");
1240 /** @id MochiKit.DOM.CANVAS */
1241 this.CANVAS = createDOMFunc("canvas");
1242
1243 /** @id MochiKit.DOM.$ */
1244 this.$ = this.getElement;
1245
1246 this.EXPORT_TAGS = {
1247 ":common": this.EXPORT,
1248 ":all": m.concat(this.EXPORT, this.EXPORT_OK)
1249 };
1250
1251 m.nameFunctions(this);
1252
1253 }
1254});
1255
1256
1257MochiKit.DOM.__new__(((typeof(window) == "undefined") ? this : window));
1258
1259//
1260// XXX: Internet Explorer blows
1261//
1262if (MochiKit.__export__) {
1263 withWindow = MochiKit.DOM.withWindow;
1264 withDocument = MochiKit.DOM.withDocument;
1265}
1266
1267MochiKit.Base._exportSymbols(this, MochiKit.DOM);
diff --git a/frontend/beta/js/MochiKit/DateTime.js b/frontend/beta/js/MochiKit/DateTime.js
new file mode 100644
index 0000000..c0b03ee
--- a/dev/null
+++ b/frontend/beta/js/MochiKit/DateTime.js
@@ -0,0 +1,216 @@
1/***
2
3MochiKit.DateTime 1.4
4
5See <http://mochikit.com/> for documentation, downloads, license, etc.
6
7(c) 2005 Bob Ippolito. All rights Reserved.
8
9***/
10
11if (typeof(dojo) != 'undefined') {
12 dojo.provide('MochiKit.DateTime');
13}
14
15if (typeof(MochiKit) == 'undefined') {
16 MochiKit = {};
17}
18
19if (typeof(MochiKit.DateTime) == 'undefined') {
20 MochiKit.DateTime = {};
21}
22
23MochiKit.DateTime.NAME = "MochiKit.DateTime";
24MochiKit.DateTime.VERSION = "1.4";
25MochiKit.DateTime.__repr__ = function () {
26 return "[" + this.NAME + " " + this.VERSION + "]";
27};
28MochiKit.DateTime.toString = function () {
29 return this.__repr__();
30};
31
32/** @id MochiKit.DateTime.isoDate */
33MochiKit.DateTime.isoDate = function (str) {
34 str = str + "";
35 if (typeof(str) != "string" || str.length === 0) {
36 return null;
37 }
38 var iso = str.split('-');
39 if (iso.length === 0) {
40 return null;
41 }
42 return new Date(iso[0], iso[1] - 1, iso[2]);
43};
44
45MochiKit.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}))?)?)?)?)?/;
46
47/** @id MochiKit.DateTime.isoTimestamp */
48MochiKit.DateTime.isoTimestamp = function (str) {
49 str = str + "";
50 if (typeof(str) != "string" || str.length === 0) {
51 return null;
52 }
53 var res = str.match(MochiKit.DateTime._isoRegexp);
54 if (typeof(res) == "undefined" || res === null) {
55 return null;
56 }
57 var year, month, day, hour, min, sec, msec;
58 year = parseInt(res[1], 10);
59 if (typeof(res[2]) == "undefined" || res[2] === '') {
60 return new Date(year);
61 }
62 month = parseInt(res[2], 10) - 1;
63 day = parseInt(res[3], 10);
64 if (typeof(res[4]) == "undefined" || res[4] === '') {
65 return new Date(year, month, day);
66 }
67 hour = parseInt(res[4], 10);
68 min = parseInt(res[5], 10);
69 sec = (typeof(res[6]) != "undefined" && res[6] !== '') ? parseInt(res[6], 10) : 0;
70 if (typeof(res[7]) != "undefined" && res[7] !== '') {
71 msec = Math.round(1000.0 * parseFloat("0." + res[7]));
72 } else {
73 msec = 0;
74 }
75 if ((typeof(res[8]) == "undefined" || res[8] === '') && (typeof(res[9]) == "undefined" || res[9] === '')) {
76 return new Date(year, month, day, hour, min, sec, msec);
77 }
78 var ofs;
79 if (typeof(res[9]) != "undefined" && res[9] !== '') {
80 ofs = parseInt(res[10], 10) * 3600000;
81 if (typeof(res[11]) != "undefined" && res[11] !== '') {
82 ofs += parseInt(res[11], 10) * 60000;
83 }
84 if (res[9] == "-") {
85 ofs = -ofs;
86 }
87 } else {
88 ofs = 0;
89 }
90 return new Date(Date.UTC(year, month, day, hour, min, sec, msec) - ofs);
91};
92
93/** @id MochiKit.DateTime.toISOTime */
94MochiKit.DateTime.toISOTime = function (date, realISO/* = false */) {
95 if (typeof(date) == "undefined" || date === null) {
96 return null;
97 }
98 var hh = date.getHours();
99 var mm = date.getMinutes();
100 var ss = date.getSeconds();
101 var lst = [
102 ((realISO && (hh < 10)) ? "0" + hh : hh),
103 ((mm < 10) ? "0" + mm : mm),
104 ((ss < 10) ? "0" + ss : ss)
105 ];
106 return lst.join(":");
107};
108
109/** @id MochiKit.DateTime.toISOTimeStamp */
110MochiKit.DateTime.toISOTimestamp = function (date, realISO/* = false*/) {
111 if (typeof(date) == "undefined" || date === null) {
112 return null;
113 }
114 var sep = realISO ? "T" : " ";
115 var foot = realISO ? "Z" : "";
116 if (realISO) {
117 date = new Date(date.getTime() + (date.getTimezoneOffset() * 60000));
118 }
119 return MochiKit.DateTime.toISODate(date) + sep + MochiKit.DateTime.toISOTime(date, realISO) + foot;
120};
121
122/** @id MochiKit.DateTime.toISODate */
123MochiKit.DateTime.toISODate = function (date) {
124 if (typeof(date) == "undefined" || date === null) {
125 return null;
126 }
127 var _padTwo = MochiKit.DateTime._padTwo;
128 return [
129 date.getFullYear(),
130 _padTwo(date.getMonth() + 1),
131 _padTwo(date.getDate())
132 ].join("-");
133};
134
135/** @id MochiKit.DateTime.americanDate */
136MochiKit.DateTime.americanDate = function (d) {
137 d = d + "";
138 if (typeof(d) != "string" || d.length === 0) {
139 return null;
140 }
141 var a = d.split('/');
142 return new Date(a[2], a[0] - 1, a[1]);
143};
144
145MochiKit.DateTime._padTwo = function (n) {
146 return (n > 9) ? n : "0" + n;
147};
148
149/** @id MochiKit.DateTime.toPaddedAmericanDate */
150MochiKit.DateTime.toPaddedAmericanDate = function (d) {
151 if (typeof(d) == "undefined" || d === null) {
152 return null;
153 }
154 var _padTwo = MochiKit.DateTime._padTwo;
155 return [
156 _padTwo(d.getMonth() + 1),
157 _padTwo(d.getDate()),
158 d.getFullYear()
159 ].join('/');
160};
161
162/** @id MochiKit.DateTime.toAmericanDate */
163MochiKit.DateTime.toAmericanDate = function (d) {
164 if (typeof(d) == "undefined" || d === null) {
165 return null;
166 }
167 return [d.getMonth() + 1, d.getDate(), d.getFullYear()].join('/');
168};
169
170MochiKit.DateTime.EXPORT = [
171 "isoDate",
172 "isoTimestamp",
173 "toISOTime",
174 "toISOTimestamp",
175 "toISODate",
176 "americanDate",
177 "toPaddedAmericanDate",
178 "toAmericanDate"
179];
180
181MochiKit.DateTime.EXPORT_OK = [];
182MochiKit.DateTime.EXPORT_TAGS = {
183 ":common": MochiKit.DateTime.EXPORT,
184 ":all": MochiKit.DateTime.EXPORT
185};
186
187MochiKit.DateTime.__new__ = function () {
188 // MochiKit.Base.nameFunctions(this);
189 var base = this.NAME + ".";
190 for (var k in this) {
191 var o = this[k];
192 if (typeof(o) == 'function' && typeof(o.NAME) == 'undefined') {
193 try {
194 o.NAME = base + k;
195 } catch (e) {
196 // pass
197 }
198 }
199 }
200};
201
202MochiKit.DateTime.__new__();
203
204if (typeof(MochiKit.Base) != "undefined") {
205 MochiKit.Base._exportSymbols(this, MochiKit.DateTime);
206} else {
207 (function (globals, module) {
208 if ((typeof(JSAN) == 'undefined' && typeof(dojo) == 'undefined')
209 || (MochiKit.__export__ === false)) {
210 var all = module.EXPORT_TAGS[":all"];
211 for (var i = 0; i < all.length; i++) {
212 globals[all[i]] = module[all[i]];
213 }
214 }
215 })(this, MochiKit.DateTime);
216}
diff --git a/frontend/beta/js/MochiKit/DragAndDrop.js b/frontend/beta/js/MochiKit/DragAndDrop.js
new file mode 100644
index 0000000..c471ffe
--- a/dev/null
+++ b/frontend/beta/js/MochiKit/DragAndDrop.js
@@ -0,0 +1,824 @@
1/***
2MochiKit.DragAndDrop 1.4
3
4See <http://mochikit.com/> for documentation, downloads, license, etc.
5
6Copyright (c) 2005 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
7 Mochi-ized By Thomas Herve (_firstname_@nimail.org)
8
9***/
10
11if (typeof(dojo) != 'undefined') {
12 dojo.provide('MochiKit.DragAndDrop');
13 dojo.require('MochiKit.Base');
14 dojo.require('MochiKit.DOM');
15 dojo.require('MochiKit.Iter');
16 dojo.require('MochiKit.Visual');
17 dojo.require('MochiKit.Signal');
18}
19
20if (typeof(JSAN) != 'undefined') {
21 JSAN.use("MochiKit.Base", []);
22 JSAN.use("MochiKit.DOM", []);
23 JSAN.use("MochiKit.Visual", []);
24 JSAN.use("MochiKit.Iter", []);
25 JSAN.use("MochiKit.Signal", []);
26}
27
28try {
29 if (typeof(MochiKit.Base) == 'undefined' ||
30 typeof(MochiKit.DOM) == 'undefined' ||
31 typeof(MochiKit.Visual) == 'undefined' ||
32 typeof(MochiKit.Signal) == 'undefined' ||
33 typeof(MochiKit.Iter) == 'undefined') {
34 throw "";
35 }
36} catch (e) {
37 throw "MochiKit.DragAndDrop depends on MochiKit.Base, MochiKit.DOM, MochiKit.Visual, MochiKit.Signal and MochiKit.Iter!";
38}
39
40if (typeof(MochiKit.DragAndDrop) == 'undefined') {
41 MochiKit.DragAndDrop = {};
42}
43
44MochiKit.DragAndDrop.NAME = 'MochiKit.DragAndDrop';
45MochiKit.DragAndDrop.VERSION = '1.4';
46
47MochiKit.DragAndDrop.__repr__ = function () {
48 return '[' + this.NAME + ' ' + this.VERSION + ']';
49};
50
51MochiKit.DragAndDrop.toString = function () {
52 return this.__repr__();
53};
54
55MochiKit.DragAndDrop.EXPORT = [
56 "Droppable",
57 "Draggable"
58];
59
60MochiKit.DragAndDrop.EXPORT_OK = [
61 "Droppables",
62 "Draggables"
63];
64
65MochiKit.DragAndDrop.Droppables = {
66 /***
67
68 Manage all droppables. Shouldn't be used, use the Droppable object instead.
69
70 ***/
71 drops: [],
72
73 remove: function (element) {
74 this.drops = MochiKit.Base.filter(function (d) {
75 return d.element != MochiKit.DOM.getElement(element);
76 }, this.drops);
77 },
78
79 register: function (drop) {
80 this.drops.push(drop);
81 },
82
83 unregister: function (drop) {
84 this.drops = MochiKit.Base.filter(function (d) {
85 return d != drop;
86 }, this.drops);
87 },
88
89 prepare: function (element) {
90 MochiKit.Base.map(function (drop) {
91 if (drop.isAccepted(element)) {
92 if (drop.options.activeclass) {
93 MochiKit.DOM.addElementClass(drop.element,
94 drop.options.activeclass);
95 }
96 drop.options.onactive(drop.element, element);
97 }
98 }, this.drops);
99 },
100
101 findDeepestChild: function (drops) {
102 deepest = drops[0];
103
104 for (i = 1; i < drops.length; ++i) {
105 if (MochiKit.DOM.isParent(drops[i].element, deepest.element)) {
106 deepest = drops[i];
107 }
108 }
109 return deepest;
110 },
111
112 show: function (point, element) {
113 if (!this.drops.length) {
114 return;
115 }
116 var affected = [];
117
118 if (this.last_active) {
119 this.last_active.deactivate();
120 }
121 MochiKit.Iter.forEach(this.drops, function (drop) {
122 if (drop.isAffected(point, element)) {
123 affected.push(drop);
124 }
125 });
126 if (affected.length > 0) {
127 drop = this.findDeepestChild(affected);
128 MochiKit.Position.within(drop.element, point.page.x, point.page.y);
129 drop.options.onhover(element, drop.element,
130 MochiKit.Position.overlap(drop.options.overlap, drop.element));
131 drop.activate();
132 }
133 },
134
135 fire: function (event, element) {
136 if (!this.last_active) {
137 return;
138 }
139 MochiKit.Position.prepare();
140
141 if (this.last_active.isAffected(event.mouse(), element)) {
142 this.last_active.options.ondrop(element,
143 this.last_active.element, event);
144 }
145 },
146
147 reset: function (element) {
148 MochiKit.Base.map(function (drop) {
149 if (drop.options.activeclass) {
150 MochiKit.DOM.removeElementClass(drop.element,
151 drop.options.activeclass);
152 }
153 drop.options.ondesactive(drop.element, element);
154 }, this.drops);
155 if (this.last_active) {
156 this.last_active.deactivate();
157 }
158 }
159};
160
161/** @id MochiKit.DragAndDrop.Droppable */
162MochiKit.DragAndDrop.Droppable = function (element, options) {
163 var cls = arguments.callee;
164 if (!(this instanceof cls)) {
165 return new cls(element, options);
166 }
167 this.__init__(element, options);
168};
169
170MochiKit.DragAndDrop.Droppable.prototype = {
171 /***
172
173 A droppable object. Simple use is to create giving an element:
174
175 new MochiKit.DragAndDrop.Droppable('myelement');
176
177 Generally you'll want to define the 'ondrop' function and maybe the
178 'accept' option to filter draggables.
179
180 ***/
181 __class__: MochiKit.DragAndDrop.Droppable,
182
183 __init__: function (element, /* optional */options) {
184 var d = MochiKit.DOM;
185 var b = MochiKit.Base;
186 this.element = d.getElement(element);
187 this.options = b.update({
188
189 /** @id MochiKit.DragAndDrop.greedy */
190 greedy: true,
191
192 /** @id MochiKit.DragAndDrop.hoverclass */
193 hoverclass: null,
194
195 /** @id MochiKit.DragAndDrop.activeclass */
196 activeclass: null,
197
198 /** @id MochiKit.DragAndDrop.hoverfunc */
199 hoverfunc: b.noop,
200
201 /** @id MochiKit.DragAndDrop.accept */
202 accept: null,
203
204 /** @id MochiKit.DragAndDrop.onactive */
205 onactive: b.noop,
206
207 /** @id MochiKit.DragAndDrop.ondesactive */
208 ondesactive: b.noop,
209
210 /** @id MochiKit.DragAndDrop.onhover */
211 onhover: b.noop,
212
213 /** @id MochiKit.DragAndDrop.ondrop */
214 ondrop: b.noop,
215
216 /** @id MochiKit.DragAndDrop.containment */
217 containment: [],
218 tree: false
219 }, options || {});
220
221 // cache containers
222 this.options._containers = [];
223 b.map(MochiKit.Base.bind(function (c) {
224 this.options._containers.push(d.getElement(c));
225 }, this), this.options.containment);
226
227 d.makePositioned(this.element); // fix IE
228
229 MochiKit.DragAndDrop.Droppables.register(this);
230 },
231
232 /** @id MochiKit.DragAndDrop.isContained */
233 isContained: function (element) {
234 if (this.options._containers.length) {
235 var containmentNode;
236 if (this.options.tree) {
237 containmentNode = element.treeNode;
238 } else {
239 containmentNode = element.parentNode;
240 }
241 return MochiKit.Iter.some(this.options._containers, function (c) {
242 return containmentNode == c;
243 });
244 } else {
245 return true;
246 }
247 },
248
249 /** @id MochiKit.DragAndDrop.isAccepted */
250 isAccepted: function (element) {
251 return ((!this.options.accept) || MochiKit.Iter.some(
252 this.options.accept, function (c) {
253 return MochiKit.DOM.hasElementClass(element, c);
254 }));
255 },
256
257 /** @id MochiKit.DragAndDrop.isAffected */
258 isAffected: function (point, element) {
259 return ((this.element != element) &&
260 this.isContained(element) &&
261 this.isAccepted(element) &&
262 MochiKit.Position.within(this.element, point.page.x,
263 point.page.y));
264 },
265
266 /** @id MochiKit.DragAndDrop.deactivate */
267 deactivate: function () {
268 /***
269
270 A droppable is deactivate when a draggable has been over it and left.
271
272 ***/
273 if (this.options.hoverclass) {
274 MochiKit.DOM.removeElementClass(this.element,
275 this.options.hoverclass);
276 }
277 this.options.hoverfunc(this.element, false);
278 MochiKit.DragAndDrop.Droppables.last_active = null;
279 },
280
281 /** @id MochiKit.DragAndDrop.activate */
282 activate: function () {
283 /***
284
285 A droppable is active when a draggable is over it.
286
287 ***/
288 if (this.options.hoverclass) {
289 MochiKit.DOM.addElementClass(this.element, this.options.hoverclass);
290 }
291 this.options.hoverfunc(this.element, true);
292 MochiKit.DragAndDrop.Droppables.last_active = this;
293 },
294
295 /** @id MochiKit.DragAndDrop.destroy */
296 destroy: function () {
297 /***
298
299 Delete this droppable.
300
301 ***/
302 MochiKit.DragAndDrop.Droppables.unregister(this);
303 },
304
305 /** @id MochiKit.DragAndDrop.repr */
306 repr: function () {
307 return '[' + this.__class__.NAME + ", options:" + MochiKit.Base.repr(this.options) + "]";
308 }
309};
310
311MochiKit.DragAndDrop.Draggables = {
312 /***
313
314 Manage draggables elements. Not intended to direct use.
315
316 ***/
317 drags: [],
318
319 register: function (draggable) {
320 if (this.drags.length === 0) {
321 var conn = MochiKit.Signal.connect;
322 this.eventMouseUp = conn(document, 'onmouseup', this, this.endDrag);
323 this.eventMouseMove = conn(document, 'onmousemove', this,
324 this.updateDrag);
325 this.eventKeypress = conn(document, 'onkeypress', this,
326 this.keyPress);
327 }
328 this.drags.push(draggable);
329 },
330
331 unregister: function (draggable) {
332 this.drags = MochiKit.Base.filter(function (d) {
333 return d != draggable;
334 }, this.drags);
335 if (this.drags.length === 0) {
336 var disc = MochiKit.Signal.disconnect;
337 disc(this.eventMouseUp);
338 disc(this.eventMouseMove);
339 disc(this.eventKeypress);
340 }
341 },
342
343 activate: function (draggable) {
344 // allows keypress events if window is not currently focused
345 // fails for Safari
346 window.focus();
347 this.activeDraggable = draggable;
348 },
349
350 deactivate: function () {
351 this.activeDraggable = null;
352 },
353
354 updateDrag: function (event) {
355 if (!this.activeDraggable) {
356 return;
357 }
358 var pointer = event.mouse();
359 // Mozilla-based browsers fire successive mousemove events with
360 // the same coordinates, prevent needless redrawing (moz bug?)
361 if (this._lastPointer && (MochiKit.Base.repr(this._lastPointer.page) ==
362 MochiKit.Base.repr(pointer.page))) {
363 return;
364 }
365 this._lastPointer = pointer;
366 this.activeDraggable.updateDrag(event, pointer);
367 },
368
369 endDrag: function (event) {
370 if (!this.activeDraggable) {
371 return;
372 }
373 this._lastPointer = null;
374 this.activeDraggable.endDrag(event);
375 this.activeDraggable = null;
376 },
377
378 keyPress: function (event) {
379 if (this.activeDraggable) {
380 this.activeDraggable.keyPress(event);
381 }
382 },
383
384 notify: function (eventName, draggable, event) {
385 MochiKit.Signal.signal(this, eventName, draggable, event);
386 }
387};
388
389/** @id MochiKit.DragAndDrop.Draggable */
390MochiKit.DragAndDrop.Draggable = function (element, options) {
391 var cls = arguments.callee;
392 if (!(this instanceof cls)) {
393 return new cls(element, options);
394 }
395 this.__init__(element, options);
396};
397
398MochiKit.DragAndDrop.Draggable.prototype = {
399 /***
400
401 A draggable object. Simple instantiate :
402
403 new MochiKit.DragAndDrop.Draggable('myelement');
404
405 ***/
406 __class__ : MochiKit.DragAndDrop.Draggable,
407
408 __init__: function (element, /* optional */options) {
409 var v = MochiKit.Visual;
410 var b = MochiKit.Base;
411 options = b.update({
412
413 /** @id MochiKit.DragAndDrop.handle */
414 handle: false,
415
416 /** @id MochiKit.DragAndDrop.starteffect */
417 starteffect: function (innerelement) {
418 this._savedOpacity = MochiKit.Style.getStyle(innerelement, 'opacity') || 1.0;
419 new v.Opacity(innerelement, {duration:0.2, from:this._savedOpacity, to:0.7});
420 },
421 /** @id MochiKit.DragAndDrop.reverteffect */
422 reverteffect: function (innerelement, top_offset, left_offset) {
423 var dur = Math.sqrt(Math.abs(top_offset^2) +
424 Math.abs(left_offset^2))*0.02;
425 return new v.Move(innerelement,
426 {x: -left_offset, y: -top_offset, duration: dur});
427 },
428
429 /** @id MochiKit.DragAndDrop.endeffect */
430 endeffect: function (innerelement) {
431 new v.Opacity(innerelement, {duration:0.2, from:0.7, to:this._savedOpacity});
432 },
433
434 /** @id MochiKit.DragAndDrop.onchange */
435 onchange: b.noop,
436
437 /** @id MochiKit.DragAndDrop.zindex */
438 zindex: 1000,
439
440 /** @id MochiKit.DragAndDrop.revert */
441 revert: false,
442
443 /** @id MochiKit.DragAndDrop.scroll */
444 scroll: false,
445
446 /** @id MochiKit.DragAndDrop.scrollSensitivity */
447 scrollSensitivity: 20,
448
449 /** @id MochiKit.DragAndDrop.scrollSpeed */
450 scrollSpeed: 15,
451 // false, or xy or [x, y] or function (x, y){return [x, y];}
452
453 /** @id MochiKit.DragAndDrop.snap */
454 snap: false
455 }, options || {});
456
457 var d = MochiKit.DOM;
458 this.element = d.getElement(element);
459
460 if (options.handle && (typeof(options.handle) == 'string')) {
461 this.handle = d.getFirstElementByTagAndClassName(null,
462 options.handle, this.element);
463 }
464 if (!this.handle) {
465 this.handle = d.getElement(options.handle);
466 }
467 if (!this.handle) {
468 this.handle = this.element;
469 }
470
471 if (options.scroll && !options.scroll.scrollTo && !options.scroll.outerHTML) {
472 options.scroll = d.getElement(options.scroll);
473 this._isScrollChild = MochiKit.DOM.isChildNode(this.element, options.scroll);
474 }
475
476 d.makePositioned(this.element); // fix IE
477
478 this.delta = this.currentDelta();
479 this.options = options;
480 this.dragging = false;
481
482 this.eventMouseDown = MochiKit.Signal.connect(this.handle,
483 'onmousedown', this, this.initDrag);
484 MochiKit.DragAndDrop.Draggables.register(this);
485 },
486
487 /** @id MochiKit.DragAndDrop.destroy */
488 destroy: function () {
489 MochiKit.Signal.disconnect(this.eventMouseDown);
490 MochiKit.DragAndDrop.Draggables.unregister(this);
491 },
492
493 /** @id MochiKit.DragAndDrop.currentDelta */
494 currentDelta: function () {
495 var s = MochiKit.Style.getStyle;
496 return [
497 parseInt(s(this.element, 'left') || '0'),
498 parseInt(s(this.element, 'top') || '0')];
499 },
500
501 /** @id MochiKit.DragAndDrop.initDrag */
502 initDrag: function (event) {
503 if (!event.mouse().button.left) {
504 return;
505 }
506 // abort on form elements, fixes a Firefox issue
507 var src = event.target();
508 var tagName = (src.tagName || '').toUpperCase();
509 if (tagName === 'INPUT' || tagName === 'SELECT' ||
510 tagName === 'OPTION' || tagName === 'BUTTON' ||
511 tagName === 'TEXTAREA') {
512 return;
513 }
514
515 if (this._revert) {
516 this._revert.cancel();
517 this._revert = null;
518 }
519
520 var pointer = event.mouse();
521 var pos = MochiKit.Position.cumulativeOffset(this.element);
522 this.offset = [pointer.page.x - pos.x, pointer.page.y - pos.y];
523
524 MochiKit.DragAndDrop.Draggables.activate(this);
525 event.stop();
526 },
527
528 /** @id MochiKit.DragAndDrop.startDrag */
529 startDrag: function (event) {
530 this.dragging = true;
531 if (this.options.selectclass) {
532 MochiKit.DOM.addElementClass(this.element,
533 this.options.selectclass);
534 }
535 if (this.options.zindex) {
536 this.originalZ = parseInt(MochiKit.Style.getStyle(this.element,
537 'z-index') || '0');
538 this.element.style.zIndex = this.options.zindex;
539 }
540
541 if (this.options.ghosting) {
542 this._clone = this.element.cloneNode(true);
543 this.ghostPosition = MochiKit.Position.absolutize(this.element);
544 this.element.parentNode.insertBefore(this._clone, this.element);
545 }
546
547 if (this.options.scroll) {
548 if (this.options.scroll == window) {
549 var where = this._getWindowScroll(this.options.scroll);
550 this.originalScrollLeft = where.left;
551 this.originalScrollTop = where.top;
552 } else {
553 this.originalScrollLeft = this.options.scroll.scrollLeft;
554 this.originalScrollTop = this.options.scroll.scrollTop;
555 }
556 }
557
558 MochiKit.DragAndDrop.Droppables.prepare(this.element);
559 MochiKit.DragAndDrop.Draggables.notify('start', this, event);
560 if (this.options.starteffect) {
561 this.options.starteffect(this.element);
562 }
563 },
564
565 /** @id MochiKit.DragAndDrop.updateDrag */
566 updateDrag: function (event, pointer) {
567 if (!this.dragging) {
568 this.startDrag(event);
569 }
570 MochiKit.Position.prepare();
571 MochiKit.DragAndDrop.Droppables.show(pointer, this.element);
572 MochiKit.DragAndDrop.Draggables.notify('drag', this, event);
573 this.draw(pointer);
574 this.options.onchange(this);
575
576 if (this.options.scroll) {
577 this.stopScrolling();
578 var p, q;
579 if (this.options.scroll == window) {
580 var s = this._getWindowScroll(this.options.scroll);
581 p = new MochiKit.Style.Coordinates(s.left, s.top);
582 q = new MochiKit.Style.Coordinates(s.left + s.width,
583 s.top + s.height);
584 } else {
585 p = MochiKit.Position.page(this.options.scroll);
586 p.x += this.options.scroll.scrollLeft;
587 p.y += this.options.scroll.scrollTop;
588 p.x += (window.pageXOffset || document.documentElement.scrollLeft || document.body.scrollLeft || 0);
589 p.y += (window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop || 0);
590 q = new MochiKit.Style.Coordinates(p.x + this.options.scroll.offsetWidth,
591 p.y + this.options.scroll.offsetHeight);
592 }
593 var speed = [0, 0];
594 if (pointer.page.x > (q.x - this.options.scrollSensitivity)) {
595 speed[0] = pointer.page.x - (q.x - this.options.scrollSensitivity);
596 } else if (pointer.page.x < (p.x + this.options.scrollSensitivity)) {
597 speed[0] = pointer.page.x - (p.x + this.options.scrollSensitivity);
598 }
599 if (pointer.page.y > (q.y - this.options.scrollSensitivity)) {
600 speed[1] = pointer.page.y - (q.y - this.options.scrollSensitivity);
601 } else if (pointer.page.y < (p.y + this.options.scrollSensitivity)) {
602 speed[1] = pointer.page.y - (p.y + this.options.scrollSensitivity);
603 }
604 this.startScrolling(speed);
605 }
606
607 // fix AppleWebKit rendering
608 if (/AppleWebKit'/.test(navigator.appVersion)) {
609 window.scrollBy(0, 0);
610 }
611 event.stop();
612 },
613
614 /** @id MochiKit.DragAndDrop.finishDrag */
615 finishDrag: function (event, success) {
616 var dr = MochiKit.DragAndDrop;
617 this.dragging = false;
618 if (this.options.selectclass) {
619 MochiKit.DOM.removeElementClass(this.element,
620 this.options.selectclass);
621 }
622
623 if (this.options.ghosting) {
624 // XXX: from a user point of view, it would be better to remove
625 // the node only *after* the MochiKit.Visual.Move end when used
626 // with revert.
627 MochiKit.Position.relativize(this.element, this.ghostPosition);
628 MochiKit.DOM.removeElement(this._clone);
629 this._clone = null;
630 }
631
632 if (success) {
633 dr.Droppables.fire(event, this.element);
634 }
635 dr.Draggables.notify('end', this, event);
636
637 var revert = this.options.revert;
638 if (revert && typeof(revert) == 'function') {
639 revert = revert(this.element);
640 }
641
642 var d = this.currentDelta();
643 if (revert && this.options.reverteffect) {
644 this._revert = this.options.reverteffect(this.element,
645 d[1] - this.delta[1], d[0] - this.delta[0]);
646 } else {
647 this.delta = d;
648 }
649
650 if (this.options.zindex) {
651 this.element.style.zIndex = this.originalZ;
652 }
653
654 if (this.options.endeffect) {
655 this.options.endeffect(this.element);
656 }
657
658 dr.Draggables.deactivate();
659 dr.Droppables.reset(this.element);
660 },
661
662 /** @id MochiKit.DragAndDrop.keyPress */
663 keyPress: function (event) {
664 if (event.key().string != "KEY_ESCAPE") {
665 return;
666 }
667 this.finishDrag(event, false);
668 event.stop();
669 },
670
671 /** @id MochiKit.DragAndDrop.endDrag */
672 endDrag: function (event) {
673 if (!this.dragging) {
674 return;
675 }
676 this.stopScrolling();
677 this.finishDrag(event, true);
678 event.stop();
679 },
680
681 /** @id MochiKit.DragAndDrop.draw */
682 draw: function (point) {
683 var pos = MochiKit.Position.cumulativeOffset(this.element);
684 var d = this.currentDelta();
685 pos.x -= d[0];
686 pos.y -= d[1];
687
688 if (this.options.scroll && (this.options.scroll != window && this._isScrollChild)) {
689 pos.x -= this.options.scroll.scrollLeft - this.originalScrollLeft;
690 pos.y -= this.options.scroll.scrollTop - this.originalScrollTop;
691 }
692
693 var p = [point.page.x - pos.x - this.offset[0],
694 point.page.y - pos.y - this.offset[1]];
695
696 if (this.options.snap) {
697 if (typeof(this.options.snap) == 'function') {
698 p = this.options.snap(p[0], p[1]);
699 } else {
700 if (this.options.snap instanceof Array) {
701 var i = -1;
702 p = MochiKit.Base.map(MochiKit.Base.bind(function (v) {
703 i += 1;
704 return Math.round(v/this.options.snap[i]) *
705 this.options.snap[i];
706 }, this), p);
707 } else {
708 p = MochiKit.Base.map(MochiKit.Base.bind(function (v) {
709 return Math.round(v/this.options.snap) *
710 this.options.snap;
711 }, this), p);
712 }
713 }
714 }
715 var style = this.element.style;
716 if ((!this.options.constraint) ||
717 (this.options.constraint == 'horizontal')) {
718 style.left = p[0] + 'px';
719 }
720 if ((!this.options.constraint) ||
721 (this.options.constraint == 'vertical')) {
722 style.top = p[1] + 'px';
723 }
724 if (style.visibility == 'hidden') {
725 style.visibility = ''; // fix gecko rendering
726 }
727 },
728
729 /** @id MochiKit.DragAndDrop.stopScrolling */
730 stopScrolling: function () {
731 if (this.scrollInterval) {
732 clearInterval(this.scrollInterval);
733 this.scrollInterval = null;
734 MochiKit.DragAndDrop.Draggables._lastScrollPointer = null;
735 }
736 },
737
738 /** @id MochiKit.DragAndDrop.startScrolling */
739 startScrolling: function (speed) {
740 if (!speed[0] && !speed[1]) {
741 return;
742 }
743 this.scrollSpeed = [speed[0] * this.options.scrollSpeed,
744 speed[1] * this.options.scrollSpeed];
745 this.lastScrolled = new Date();
746 this.scrollInterval = setInterval(MochiKit.Base.bind(this.scroll, this), 10);
747 },
748
749 /** @id MochiKit.DragAndDrop.scroll */
750 scroll: function () {
751 var current = new Date();
752 var delta = current - this.lastScrolled;
753 this.lastScrolled = current;
754
755 if (this.options.scroll == window) {
756 var s = this._getWindowScroll(this.options.scroll);
757 if (this.scrollSpeed[0] || this.scrollSpeed[1]) {
758 var dm = delta / 1000;
759 this.options.scroll.scrollTo(s.left + dm * this.scrollSpeed[0],
760 s.top + dm * this.scrollSpeed[1]);
761 }
762 } else {
763 this.options.scroll.scrollLeft += this.scrollSpeed[0] * delta / 1000;
764 this.options.scroll.scrollTop += this.scrollSpeed[1] * delta / 1000;
765 }
766
767 var d = MochiKit.DragAndDrop;
768
769 MochiKit.Position.prepare();
770 d.Droppables.show(d.Draggables._lastPointer, this.element);
771 d.Draggables.notify('drag', this);
772 if (this._isScrollChild) {
773 d.Draggables._lastScrollPointer = d.Draggables._lastScrollPointer || d.Draggables._lastPointer;
774 d.Draggables._lastScrollPointer.x += this.scrollSpeed[0] * delta / 1000;
775 d.Draggables._lastScrollPointer.y += this.scrollSpeed[1] * delta / 1000;
776 if (d.Draggables._lastScrollPointer.x < 0) {
777 d.Draggables._lastScrollPointer.x = 0;
778 }
779 if (d.Draggables._lastScrollPointer.y < 0) {
780 d.Draggables._lastScrollPointer.y = 0;
781 }
782 this.draw(d.Draggables._lastScrollPointer);
783 }
784
785 this.options.onchange(this);
786 },
787
788 _getWindowScroll: function (win) {
789 var vp, w, h;
790 MochiKit.DOM.withWindow(win, function () {
791 vp = MochiKit.Style.getViewportPosition(win.document);
792 });
793 if (win.innerWidth) {
794 w = win.innerWidth;
795 h = win.innerHeight;
796 } else if (win.document.documentElement && win.document.documentElement.clientWidth) {
797 w = win.document.documentElement.clientWidth;
798 h = win.document.documentElement.clientHeight;
799 } else {
800 w = win.document.body.offsetWidth;
801 h = win.document.body.offsetHeight;
802 }
803 return {top: vp.x, left: vp.y, width: w, height: h};
804 },
805
806 /** @id MochiKit.DragAndDrop.repr */
807 repr: function () {
808 return '[' + this.__class__.NAME + ", options:" + MochiKit.Base.repr(this.options) + "]";
809 }
810};
811
812MochiKit.DragAndDrop.__new__ = function () {
813 MochiKit.Base.nameFunctions(this);
814
815 this.EXPORT_TAGS = {
816 ":common": this.EXPORT,
817 ":all": MochiKit.Base.concat(this.EXPORT, this.EXPORT_OK)
818 };
819};
820
821MochiKit.DragAndDrop.__new__();
822
823MochiKit.Base._exportSymbols(this, MochiKit.DragAndDrop);
824
diff --git a/frontend/beta/js/MochiKit/Format.js b/frontend/beta/js/MochiKit/Format.js
new file mode 100644
index 0000000..937b681
--- a/dev/null
+++ b/frontend/beta/js/MochiKit/Format.js
@@ -0,0 +1,304 @@
1/***
2
3MochiKit.Format 1.4
4
5See <http://mochikit.com/> for documentation, downloads, license, etc.
6
7(c) 2005 Bob Ippolito. All rights Reserved.
8
9***/
10
11if (typeof(dojo) != 'undefined') {
12 dojo.provide('MochiKit.Format');
13}
14
15if (typeof(MochiKit) == 'undefined') {
16 MochiKit = {};
17}
18
19if (typeof(MochiKit.Format) == 'undefined') {
20 MochiKit.Format = {};
21}
22
23MochiKit.Format.NAME = "MochiKit.Format";
24MochiKit.Format.VERSION = "1.4";
25MochiKit.Format.__repr__ = function () {
26 return "[" + this.NAME + " " + this.VERSION + "]";
27};
28MochiKit.Format.toString = function () {
29 return this.__repr__();
30};
31
32MochiKit.Format._numberFormatter = function (placeholder, header, footer, locale, isPercent, precision, leadingZeros, separatorAt, trailingZeros) {
33 return function (num) {
34 num = parseFloat(num);
35 if (typeof(num) == "undefined" || num === null || isNaN(num)) {
36 return placeholder;
37 }
38 var curheader = header;
39 var curfooter = footer;
40 if (num < 0) {
41 num = -num;
42 } else {
43 curheader = curheader.replace(/-/, "");
44 }
45 var me = arguments.callee;
46 var fmt = MochiKit.Format.formatLocale(locale);
47 if (isPercent) {
48 num = num * 100.0;
49 curfooter = fmt.percent + curfooter;
50 }
51 num = MochiKit.Format.roundToFixed(num, precision);
52 var parts = num.split(/\./);
53 var whole = parts[0];
54 var frac = (parts.length == 1) ? "" : parts[1];
55 var res = "";
56 while (whole.length < leadingZeros) {
57 whole = "0" + whole;
58 }
59 if (separatorAt) {
60 while (whole.length > separatorAt) {
61 var i = whole.length - separatorAt;
62 //res = res + fmt.separator + whole.substring(i, whole.length);
63 res = fmt.separator + whole.substring(i, whole.length) + res;
64 whole = whole.substring(0, i);
65 }
66 }
67 res = whole + res;
68 if (precision > 0) {
69 while (frac.length < trailingZeros) {
70 frac = frac + "0";
71 }
72 res = res + fmt.decimal + frac;
73 }
74 return curheader + res + curfooter;
75 };
76};
77
78/** @id MochiKit.Format.numberFormatter */
79MochiKit.Format.numberFormatter = function (pattern, placeholder/* = "" */, locale/* = "default" */) {
80 // http://java.sun.com/docs/books/tutorial/i18n/format/numberpattern.html
81 // | 0 | leading or trailing zeros
82 // | # | just the number
83 // | , | separator
84 // | . | decimal separator
85 // | % | Multiply by 100 and format as percent
86 if (typeof(placeholder) == "undefined") {
87 placeholder = "";
88 }
89 var match = pattern.match(/((?:[0#]+,)?[0#]+)(?:\.([0#]+))?(%)?/);
90 if (!match) {
91 throw TypeError("Invalid pattern");
92 }
93 var header = pattern.substr(0, match.index);
94 var footer = pattern.substr(match.index + match[0].length);
95 if (header.search(/-/) == -1) {
96 header = header + "-";
97 }
98 var whole = match[1];
99 var frac = (typeof(match[2]) == "string" && match[2] != "") ? match[2] : "";
100 var isPercent = (typeof(match[3]) == "string" && match[3] != "");
101 var tmp = whole.split(/,/);
102 var separatorAt;
103 if (typeof(locale) == "undefined") {
104 locale = "default";
105 }
106 if (tmp.length == 1) {
107 separatorAt = null;
108 } else {
109 separatorAt = tmp[1].length;
110 }
111 var leadingZeros = whole.length - whole.replace(/0/g, "").length;
112 var trailingZeros = frac.length - frac.replace(/0/g, "").length;
113 var precision = frac.length;
114 var rval = MochiKit.Format._numberFormatter(
115 placeholder, header, footer, locale, isPercent, precision,
116 leadingZeros, separatorAt, trailingZeros
117 );
118 var m = MochiKit.Base;
119 if (m) {
120 var fn = arguments.callee;
121 var args = m.concat(arguments);
122 rval.repr = function () {
123 return [
124 self.NAME,
125 "(",
126 map(m.repr, args).join(", "),
127 ")"
128 ].join("");
129 };
130 }
131 return rval;
132};
133
134/** @id MochiKit.Format.formatLocale */
135MochiKit.Format.formatLocale = function (locale) {
136 if (typeof(locale) == "undefined" || locale === null) {
137 locale = "default";
138 }
139 if (typeof(locale) == "string") {
140 var rval = MochiKit.Format.LOCALE[locale];
141 if (typeof(rval) == "string") {
142 rval = arguments.callee(rval);
143 MochiKit.Format.LOCALE[locale] = rval;
144 }
145 return rval;
146 } else {
147 return locale;
148 }
149};
150
151/** @id MochiKit.Format.twoDigitAverage */
152MochiKit.Format.twoDigitAverage = function (numerator, denominator) {
153 if (denominator) {
154 var res = numerator / denominator;
155 if (!isNaN(res)) {
156 return MochiKit.Format.twoDigitFloat(numerator / denominator);
157 }
158 }
159 return "0";
160};
161
162/** @id MochiKit.Format.twoDigitFloat */
163MochiKit.Format.twoDigitFloat = function (someFloat) {
164 var sign = (someFloat < 0 ? '-' : '');
165 var s = Math.floor(Math.abs(someFloat) * 100).toString();
166 if (s == '0') {
167 return s;
168 }
169 if (s.length < 3) {
170 while (s.charAt(s.length - 1) == '0') {
171 s = s.substring(0, s.length - 1);
172 }
173 return sign + '0.' + s;
174 }
175 var head = sign + s.substring(0, s.length - 2);
176 var tail = s.substring(s.length - 2, s.length);
177 if (tail == '00') {
178 return head;
179 } else if (tail.charAt(1) == '0') {
180 return head + '.' + tail.charAt(0);
181 } else {
182 return head + '.' + tail;
183 }
184};
185
186/** @id MochiKit.Format.lstrip */
187MochiKit.Format.lstrip = function (str, /* optional */chars) {
188 str = str + "";
189 if (typeof(str) != "string") {
190 return null;
191 }
192 if (!chars) {
193 return str.replace(/^\s+/, "");
194 } else {
195 return str.replace(new RegExp("^[" + chars + "]+"), "");
196 }
197};
198
199/** @id MochiKit.Format.rstrip */
200MochiKit.Format.rstrip = function (str, /* optional */chars) {
201 str = str + "";
202 if (typeof(str) != "string") {
203 return null;
204 }
205 if (!chars) {
206 return str.replace(/\s+$/, "");
207 } else {
208 return str.replace(new RegExp("[" + chars + "]+$"), "");
209 }
210};
211
212/** @id MochiKit.Format.strip */
213MochiKit.Format.strip = function (str, /* optional */chars) {
214 var self = MochiKit.Format;
215 return self.rstrip(self.lstrip(str, chars), chars);
216};
217
218/** @id MochiKit.Format.truncToFixed */
219MochiKit.Format.truncToFixed = function (aNumber, precision) {
220 aNumber = Math.floor(aNumber * Math.pow(10, precision));
221 var res = (aNumber * Math.pow(10, -precision)).toFixed(precision);
222 if (res.charAt(0) == ".") {
223 res = "0" + res;
224 }
225 return res;
226};
227
228/** @id MochiKit.Format.roundToFixed */
229MochiKit.Format.roundToFixed = function (aNumber, precision) {
230 return MochiKit.Format.truncToFixed(
231 aNumber + 0.5 * Math.pow(10, -precision),
232 precision
233 );
234};
235
236/** @id MochiKit.Format.percentFormat */
237MochiKit.Format.percentFormat = function (someFloat) {
238 return MochiKit.Format.twoDigitFloat(100 * someFloat) + '%';
239};
240
241MochiKit.Format.EXPORT = [
242 "truncToFixed",
243 "roundToFixed",
244 "numberFormatter",
245 "formatLocale",
246 "twoDigitAverage",
247 "twoDigitFloat",
248 "percentFormat",
249 "lstrip",
250 "rstrip",
251 "strip"
252];
253
254MochiKit.Format.LOCALE = {
255 en_US: {separator: ",", decimal: ".", percent: "%"},
256 de_DE: {separator: ".", decimal: ",", percent: "%"},
257 fr_FR: {separator: " ", decimal: ",", percent: "%"},
258 "default": "en_US"
259};
260
261MochiKit.Format.EXPORT_OK = [];
262MochiKit.Format.EXPORT_TAGS = {
263 ':all': MochiKit.Format.EXPORT,
264 ':common': MochiKit.Format.EXPORT
265};
266
267MochiKit.Format.__new__ = function () {
268 // MochiKit.Base.nameFunctions(this);
269 var base = this.NAME + ".";
270 var k, v, o;
271 for (k in this.LOCALE) {
272 o = this.LOCALE[k];
273 if (typeof(o) == "object") {
274 o.repr = function () { return this.NAME; };
275 o.NAME = base + "LOCALE." + k;
276 }
277 }
278 for (k in this) {
279 o = this[k];
280 if (typeof(o) == 'function' && typeof(o.NAME) == 'undefined') {
281 try {
282 o.NAME = base + k;
283 } catch (e) {
284 // pass
285 }
286 }
287 }
288};
289
290MochiKit.Format.__new__();
291
292if (typeof(MochiKit.Base) != "undefined") {
293 MochiKit.Base._exportSymbols(this, MochiKit.Format);
294} else {
295 (function (globals, module) {
296 if ((typeof(JSAN) == 'undefined' && typeof(dojo) == 'undefined')
297 || (MochiKit.__export__ === false)) {
298 var all = module.EXPORT_TAGS[":all"];
299 for (var i = 0; i < all.length; i++) {
300 globals[all[i]] = module[all[i]];
301 }
302 }
303 })(this, MochiKit.Format);
304}
diff --git a/frontend/beta/js/MochiKit/Iter.js b/frontend/beta/js/MochiKit/Iter.js
new file mode 100644
index 0000000..1d008e2
--- a/dev/null
+++ b/frontend/beta/js/MochiKit/Iter.js
@@ -0,0 +1,843 @@
1/***
2
3MochiKit.Iter 1.4
4
5See <http://mochikit.com/> for documentation, downloads, license, etc.
6
7(c) 2005 Bob Ippolito. All rights Reserved.
8
9***/
10
11if (typeof(dojo) != 'undefined') {
12 dojo.provide('MochiKit.Iter');
13 dojo.require('MochiKit.Base');
14}
15
16if (typeof(JSAN) != 'undefined') {
17 JSAN.use("MochiKit.Base", []);
18}
19
20try {
21 if (typeof(MochiKit.Base) == 'undefined') {
22 throw "";
23 }
24} catch (e) {
25 throw "MochiKit.Iter depends on MochiKit.Base!";
26}
27
28if (typeof(MochiKit.Iter) == 'undefined') {
29 MochiKit.Iter = {};
30}
31
32MochiKit.Iter.NAME = "MochiKit.Iter";
33MochiKit.Iter.VERSION = "1.4";
34MochiKit.Base.update(MochiKit.Iter, {
35 __repr__: function () {
36 return "[" + this.NAME + " " + this.VERSION + "]";
37 },
38 toString: function () {
39 return this.__repr__();
40 },
41
42 /** @id MochiKit.Iter.registerIteratorFactory */
43 registerIteratorFactory: function (name, check, iterfactory, /* optional */ override) {
44 MochiKit.Iter.iteratorRegistry.register(name, check, iterfactory, override);
45 },
46
47 /** @id MochiKit.Iter.iter */
48 iter: function (iterable, /* optional */ sentinel) {
49 var self = MochiKit.Iter;
50 if (arguments.length == 2) {
51 return self.takewhile(
52 function (a) { return a != sentinel; },
53 iterable
54 );
55 }
56 if (typeof(iterable.next) == 'function') {
57 return iterable;
58 } else if (typeof(iterable.iter) == 'function') {
59 return iterable.iter();
60 /*
61 } else if (typeof(iterable.__iterator__) == 'function') {
62 //
63 // XXX: We can't support JavaScript 1.7 __iterator__ directly
64 // because of Object.prototype.__iterator__
65 //
66 return iterable.__iterator__();
67 */
68 }
69
70 try {
71 return self.iteratorRegistry.match(iterable);
72 } catch (e) {
73 var m = MochiKit.Base;
74 if (e == m.NotFound) {
75 e = new TypeError(typeof(iterable) + ": " + m.repr(iterable) + " is not iterable");
76 }
77 throw e;
78 }
79 },
80
81 /** @id MochiKit.Iter.count */
82 count: function (n) {
83 if (!n) {
84 n = 0;
85 }
86 var m = MochiKit.Base;
87 return {
88 repr: function () { return "count(" + n + ")"; },
89 toString: m.forwardCall("repr"),
90 next: m.counter(n)
91 };
92 },
93
94 /** @id MochiKit.Iter.cycle */
95 cycle: function (p) {
96 var self = MochiKit.Iter;
97 var m = MochiKit.Base;
98 var lst = [];
99 var iterator = self.iter(p);
100 return {
101 repr: function () { return "cycle(...)"; },
102 toString: m.forwardCall("repr"),
103 next: function () {
104 try {
105 var rval = iterator.next();
106 lst.push(rval);
107 return rval;
108 } catch (e) {
109 if (e != self.StopIteration) {
110 throw e;
111 }
112 if (lst.length === 0) {
113 this.next = function () {
114 throw self.StopIteration;
115 };
116 } else {
117 var i = -1;
118 this.next = function () {
119 i = (i + 1) % lst.length;
120 return lst[i];
121 };
122 }
123 return this.next();
124 }
125 }
126 };
127 },
128
129 /** @id MochiKit.Iter.repeat */
130 repeat: function (elem, /* optional */n) {
131 var m = MochiKit.Base;
132 if (typeof(n) == 'undefined') {
133 return {
134 repr: function () {
135 return "repeat(" + m.repr(elem) + ")";
136 },
137 toString: m.forwardCall("repr"),
138 next: function () {
139 return elem;
140 }
141 };
142 }
143 return {
144 repr: function () {
145 return "repeat(" + m.repr(elem) + ", " + n + ")";
146 },
147 toString: m.forwardCall("repr"),
148 next: function () {
149 if (n <= 0) {
150 throw MochiKit.Iter.StopIteration;
151 }
152 n -= 1;
153 return elem;
154 }
155 };
156 },
157
158 /** @id MochiKit.Iter.next */
159 next: function (iterator) {
160 return iterator.next();
161 },
162
163 /** @id MochiKit.Iter.izip */
164 izip: function (p, q/*, ...*/) {
165 var m = MochiKit.Base;
166 var self = MochiKit.Iter;
167 var next = self.next;
168 var iterables = m.map(self.iter, arguments);
169 return {
170 repr: function () { return "izip(...)"; },
171 toString: m.forwardCall("repr"),
172 next: function () { return m.map(next, iterables); }
173 };
174 },
175
176 /** @id MochiKit.Iter.ifilter */
177 ifilter: function (pred, seq) {
178 var m = MochiKit.Base;
179 seq = MochiKit.Iter.iter(seq);
180 if (pred === null) {
181 pred = m.operator.truth;
182 }
183 return {
184 repr: function () { return "ifilter(...)"; },
185 toString: m.forwardCall("repr"),
186 next: function () {
187 while (true) {
188 var rval = seq.next();
189 if (pred(rval)) {
190 return rval;
191 }
192 }
193 // mozilla warnings aren't too bright
194 return undefined;
195 }
196 };
197 },
198
199 /** @id MochiKit.Iter.ifilterfalse */
200 ifilterfalse: function (pred, seq) {
201 var m = MochiKit.Base;
202 seq = MochiKit.Iter.iter(seq);
203 if (pred === null) {
204 pred = m.operator.truth;
205 }
206 return {
207 repr: function () { return "ifilterfalse(...)"; },
208 toString: m.forwardCall("repr"),
209 next: function () {
210 while (true) {
211 var rval = seq.next();
212 if (!pred(rval)) {
213 return rval;
214 }
215 }
216 // mozilla warnings aren't too bright
217 return undefined;
218 }
219 };
220 },
221
222 /** @id MochiKit.Iter.islice */
223 islice: function (seq/*, [start,] stop[, step] */) {
224 var self = MochiKit.Iter;
225 var m = MochiKit.Base;
226 seq = self.iter(seq);
227 var start = 0;
228 var stop = 0;
229 var step = 1;
230 var i = -1;
231 if (arguments.length == 2) {
232 stop = arguments[1];
233 } else if (arguments.length == 3) {
234 start = arguments[1];
235 stop = arguments[2];
236 } else {
237 start = arguments[1];
238 stop = arguments[2];
239 step = arguments[3];
240 }
241 return {
242 repr: function () {
243 return "islice(" + ["...", start, stop, step].join(", ") + ")";
244 },
245 toString: m.forwardCall("repr"),
246 next: function () {
247 var rval;
248 while (i < start) {
249 rval = seq.next();
250 i++;
251 }
252 if (start >= stop) {
253 throw self.StopIteration;
254 }
255 start += step;
256 return rval;
257 }
258 };
259 },
260
261 /** @id MochiKit.Iter.imap */
262 imap: function (fun, p, q/*, ...*/) {
263 var m = MochiKit.Base;
264 var self = MochiKit.Iter;
265 var iterables = m.map(self.iter, m.extend(null, arguments, 1));
266 var map = m.map;
267 var next = self.next;
268 return {
269 repr: function () { return "imap(...)"; },
270 toString: m.forwardCall("repr"),
271 next: function () {
272 return fun.apply(this, map(next, iterables));
273 }
274 };
275 },
276
277 /** @id MochiKit.Iter.applymap */
278 applymap: function (fun, seq, self) {
279 seq = MochiKit.Iter.iter(seq);
280 var m = MochiKit.Base;
281 return {
282 repr: function () { return "applymap(...)"; },
283 toString: m.forwardCall("repr"),
284 next: function () {
285 return fun.apply(self, seq.next());
286 }
287 };
288 },
289
290 /** @id MochiKit.Iter.chain */
291 chain: function (p, q/*, ...*/) {
292 // dumb fast path
293 var self = MochiKit.Iter;
294 var m = MochiKit.Base;
295 if (arguments.length == 1) {
296 return self.iter(arguments[0]);
297 }
298 var argiter = m.map(self.iter, arguments);
299 return {
300 repr: function () { return "chain(...)"; },
301 toString: m.forwardCall("repr"),
302 next: function () {
303 while (argiter.length > 1) {
304 try {
305 return argiter[0].next();
306 } catch (e) {
307 if (e != self.StopIteration) {
308 throw e;
309 }
310 argiter.shift();
311 }
312 }
313 if (argiter.length == 1) {
314 // optimize last element
315 var arg = argiter.shift();
316 this.next = m.bind("next", arg);
317 return this.next();
318 }
319 throw self.StopIteration;
320 }
321 };
322 },
323
324 /** @id MochiKit.Iter.takewhile */
325 takewhile: function (pred, seq) {
326 var self = MochiKit.Iter;
327 seq = self.iter(seq);
328 return {
329 repr: function () { return "takewhile(...)"; },
330 toString: MochiKit.Base.forwardCall("repr"),
331 next: function () {
332 var rval = seq.next();
333 if (!pred(rval)) {
334 this.next = function () {
335 throw self.StopIteration;
336 };
337 this.next();
338 }
339 return rval;
340 }
341 };
342 },
343
344 /** @id MochiKit.Iter.dropwhile */
345 dropwhile: function (pred, seq) {
346 seq = MochiKit.Iter.iter(seq);
347 var m = MochiKit.Base;
348 var bind = m.bind;
349 return {
350 "repr": function () { return "dropwhile(...)"; },
351 "toString": m.forwardCall("repr"),
352 "next": function () {
353 while (true) {
354 var rval = seq.next();
355 if (!pred(rval)) {
356 break;
357 }
358 }
359 this.next = bind("next", seq);
360 return rval;
361 }
362 };
363 },
364
365 _tee: function (ident, sync, iterable) {
366 sync.pos[ident] = -1;
367 var m = MochiKit.Base;
368 var listMin = m.listMin;
369 return {
370 repr: function () { return "tee(" + ident + ", ...)"; },
371 toString: m.forwardCall("repr"),
372 next: function () {
373 var rval;
374 var i = sync.pos[ident];
375
376 if (i == sync.max) {
377 rval = iterable.next();
378 sync.deque.push(rval);
379 sync.max += 1;
380 sync.pos[ident] += 1;
381 } else {
382 rval = sync.deque[i - sync.min];
383 sync.pos[ident] += 1;
384 if (i == sync.min && listMin(sync.pos) != sync.min) {
385 sync.min += 1;
386 sync.deque.shift();
387 }
388 }
389 return rval;
390 }
391 };
392 },
393
394 /** @id MochiKit.Iter.tee */
395 tee: function (iterable, n/* = 2 */) {
396 var rval = [];
397 var sync = {
398 "pos": [],
399 "deque": [],
400 "max": -1,
401 "min": -1
402 };
403 if (arguments.length == 1 || typeof(n) == "undefined" || n === null) {
404 n = 2;
405 }
406 var self = MochiKit.Iter;
407 iterable = self.iter(iterable);
408 var _tee = self._tee;
409 for (var i = 0; i < n; i++) {
410 rval.push(_tee(i, sync, iterable));
411 }
412 return rval;
413 },
414
415 /** @id MochiKit.Iter.list */
416 list: function (iterable) {
417 // Fast-path for Array and Array-like
418 var m = MochiKit.Base;
419 if (typeof(iterable.slice) == 'function') {
420 return iterable.slice();
421 } else if (m.isArrayLike(iterable)) {
422 return m.concat(iterable);
423 }
424
425 var self = MochiKit.Iter;
426 iterable = self.iter(iterable);
427 var rval = [];
428 try {
429 while (true) {
430 rval.push(iterable.next());
431 }
432 } catch (e) {
433 if (e != self.StopIteration) {
434 throw e;
435 }
436 return rval;
437 }
438 // mozilla warnings aren't too bright
439 return undefined;
440 },
441
442
443 /** @id MochiKit.Iter.reduce */
444 reduce: function (fn, iterable, /* optional */initial) {
445 var i = 0;
446 var x = initial;
447 var self = MochiKit.Iter;
448 iterable = self.iter(iterable);
449 if (arguments.length < 3) {
450 try {
451 x = iterable.next();
452 } catch (e) {
453 if (e == self.StopIteration) {
454 e = new TypeError("reduce() of empty sequence with no initial value");
455 }
456 throw e;
457 }
458 i++;
459 }
460 try {
461 while (true) {
462 x = fn(x, iterable.next());
463 }
464 } catch (e) {
465 if (e != self.StopIteration) {
466 throw e;
467 }
468 }
469 return x;
470 },
471
472 /** @id MochiKit.Iter.range */
473 range: function (/* [start,] stop[, step] */) {
474 var start = 0;
475 var stop = 0;
476 var step = 1;
477 if (arguments.length == 1) {
478 stop = arguments[0];
479 } else if (arguments.length == 2) {
480 start = arguments[0];
481 stop = arguments[1];
482 } else if (arguments.length == 3) {
483 start = arguments[0];
484 stop = arguments[1];
485 step = arguments[2];
486 } else {
487 throw new TypeError("range() takes 1, 2, or 3 arguments!");
488 }
489 if (step === 0) {
490 throw new TypeError("range() step must not be 0");
491 }
492 return {
493 next: function () {
494 if ((step > 0 && start >= stop) || (step < 0 && start <= stop)) {
495 throw MochiKit.Iter.StopIteration;
496 }
497 var rval = start;
498 start += step;
499 return rval;
500 },
501 repr: function () {
502 return "range(" + [start, stop, step].join(", ") + ")";
503 },
504 toString: MochiKit.Base.forwardCall("repr")
505 };
506 },
507
508 /** @id MochiKit.Iter.sum */
509 sum: function (iterable, start/* = 0 */) {
510 if (typeof(start) == "undefined" || start === null) {
511 start = 0;
512 }
513 var x = start;
514 var self = MochiKit.Iter;
515 iterable = self.iter(iterable);
516 try {
517 while (true) {
518 x += iterable.next();
519 }
520 } catch (e) {
521 if (e != self.StopIteration) {
522 throw e;
523 }
524 }
525 return x;
526 },
527
528 /** @id MochiKit.Iter.exhaust */
529 exhaust: function (iterable) {
530 var self = MochiKit.Iter;
531 iterable = self.iter(iterable);
532 try {
533 while (true) {
534 iterable.next();
535 }
536 } catch (e) {
537 if (e != self.StopIteration) {
538 throw e;
539 }
540 }
541 },
542
543 /** @id MochiKit.Iter.forEach */
544 forEach: function (iterable, func, /* optional */self) {
545 var m = MochiKit.Base;
546 if (arguments.length > 2) {
547 func = m.bind(func, self);
548 }
549 // fast path for array
550 if (m.isArrayLike(iterable)) {
551 try {
552 for (var i = 0; i < iterable.length; i++) {
553 func(iterable[i]);
554 }
555 } catch (e) {
556 if (e != MochiKit.Iter.StopIteration) {
557 throw e;
558 }
559 }
560 } else {
561 self = MochiKit.Iter;
562 self.exhaust(self.imap(func, iterable));
563 }
564 },
565
566 /** @id MochiKit.Iter.every */
567 every: function (iterable, func) {
568 var self = MochiKit.Iter;
569 try {
570 self.ifilterfalse(func, iterable).next();
571 return false;
572 } catch (e) {
573 if (e != self.StopIteration) {
574 throw e;
575 }
576 return true;
577 }
578 },
579
580 /** @id MochiKit.Iter.sorted */
581 sorted: function (iterable, /* optional */cmp) {
582 var rval = MochiKit.Iter.list(iterable);
583 if (arguments.length == 1) {
584 cmp = MochiKit.Base.compare;
585 }
586 rval.sort(cmp);
587 return rval;
588 },
589
590 /** @id MochiKit.Iter.reversed */
591 reversed: function (iterable) {
592 var rval = MochiKit.Iter.list(iterable);
593 rval.reverse();
594 return rval;
595 },
596
597 /** @id MochiKit.Iter.some */
598 some: function (iterable, func) {
599 var self = MochiKit.Iter;
600 try {
601 self.ifilter(func, iterable).next();
602 return true;
603 } catch (e) {
604 if (e != self.StopIteration) {
605 throw e;
606 }
607 return false;
608 }
609 },
610
611 /** @id MochiKit.Iter.iextend */
612 iextend: function (lst, iterable) {
613 if (MochiKit.Base.isArrayLike(iterable)) {
614 // fast-path for array-like
615 for (var i = 0; i < iterable.length; i++) {
616 lst.push(iterable[i]);
617 }
618 } else {
619 var self = MochiKit.Iter;
620 iterable = self.iter(iterable);
621 try {
622 while (true) {
623 lst.push(iterable.next());
624 }
625 } catch (e) {
626 if (e != self.StopIteration) {
627 throw e;
628 }
629 }
630 }
631 return lst;
632 },
633
634 /** @id MochiKit.Iter.groupby */
635 groupby: function(iterable, /* optional */ keyfunc) {
636 var m = MochiKit.Base;
637 var self = MochiKit.Iter;
638 if (arguments.length < 2) {
639 keyfunc = m.operator.identity;
640 }
641 iterable = self.iter(iterable);
642
643 // shared
644 var pk = undefined;
645 var k = undefined;
646 var v;
647
648 function fetch() {
649 v = iterable.next();
650 k = keyfunc(v);
651 };
652
653 function eat() {
654 var ret = v;
655 v = undefined;
656 return ret;
657 };
658
659 var first = true;
660 var compare = m.compare;
661 return {
662 repr: function () { return "groupby(...)"; },
663 next: function() {
664 // iterator-next
665
666 // iterate until meet next group
667 while (compare(k, pk) === 0) {
668 fetch();
669 if (first) {
670 first = false;
671 break;
672 }
673 }
674 pk = k;
675 return [k, {
676 next: function() {
677 // subiterator-next
678 if (v == undefined) { // Is there something to eat?
679 fetch();
680 }
681 if (compare(k, pk) !== 0) {
682 throw self.StopIteration;
683 }
684 return eat();
685 }
686 }];
687 }
688 };
689 },
690
691 /** @id MochiKit.Iter.groupby_as_array */
692 groupby_as_array: function (iterable, /* optional */ keyfunc) {
693 var m = MochiKit.Base;
694 var self = MochiKit.Iter;
695 if (arguments.length < 2) {
696 keyfunc = m.operator.identity;
697 }
698
699 iterable = self.iter(iterable);
700 var result = [];
701 var first = true;
702 var prev_key;
703 var compare = m.compare;
704 while (true) {
705 try {
706 var value = iterable.next();
707 var key = keyfunc(value);
708 } catch (e) {
709 if (e == self.StopIteration) {
710 break;
711 }
712 throw e;
713 }
714 if (first || compare(key, prev_key) !== 0) {
715 var values = [];
716 result.push([key, values]);
717 }
718 values.push(value);
719 first = false;
720 prev_key = key;
721 }
722 return result;
723 },
724
725 /** @id MochiKit.Iter.arrayLikeIter */
726 arrayLikeIter: function (iterable) {
727 var i = 0;
728 return {
729 repr: function () { return "arrayLikeIter(...)"; },
730 toString: MochiKit.Base.forwardCall("repr"),
731 next: function () {
732 if (i >= iterable.length) {
733 throw MochiKit.Iter.StopIteration;
734 }
735 return iterable[i++];
736 }
737 };
738 },
739
740 /** @id MochiKit.Iter.hasIterateNext */
741 hasIterateNext: function (iterable) {
742 return (iterable && typeof(iterable.iterateNext) == "function");
743 },
744
745 /** @id MochiKit.Iter.iterateNextIter */
746 iterateNextIter: function (iterable) {
747 return {
748 repr: function () { return "iterateNextIter(...)"; },
749 toString: MochiKit.Base.forwardCall("repr"),
750 next: function () {
751 var rval = iterable.iterateNext();
752 if (rval === null || rval === undefined) {
753 throw MochiKit.Iter.StopIteration;
754 }
755 return rval;
756 }
757 };
758 }
759});
760
761
762MochiKit.Iter.EXPORT_OK = [
763 "iteratorRegistry",
764 "arrayLikeIter",
765 "hasIterateNext",
766 "iterateNextIter",
767];
768
769MochiKit.Iter.EXPORT = [
770 "StopIteration",
771 "registerIteratorFactory",
772 "iter",
773 "count",
774 "cycle",
775 "repeat",
776 "next",
777 "izip",
778 "ifilter",
779 "ifilterfalse",
780 "islice",
781 "imap",
782 "applymap",
783 "chain",
784 "takewhile",
785 "dropwhile",
786 "tee",
787 "list",
788 "reduce",
789 "range",
790 "sum",
791 "exhaust",
792 "forEach",
793 "every",
794 "sorted",
795 "reversed",
796 "some",
797 "iextend",
798 "groupby",
799 "groupby_as_array"
800];
801
802MochiKit.Iter.__new__ = function () {
803 var m = MochiKit.Base;
804 // Re-use StopIteration if exists (e.g. SpiderMonkey)
805 if (typeof(StopIteration) != "undefined") {
806 this.StopIteration = StopIteration;
807 } else {
808 /** @id MochiKit.Iter.StopIteration */
809 this.StopIteration = new m.NamedError("StopIteration");
810 }
811 this.iteratorRegistry = new m.AdapterRegistry();
812 // Register the iterator factory for arrays
813 this.registerIteratorFactory(
814 "arrayLike",
815 m.isArrayLike,
816 this.arrayLikeIter
817 );
818
819 this.registerIteratorFactory(
820 "iterateNext",
821 this.hasIterateNext,
822 this.iterateNextIter
823 );
824
825 this.EXPORT_TAGS = {
826 ":common": this.EXPORT,
827 ":all": m.concat(this.EXPORT, this.EXPORT_OK)
828 };
829
830 m.nameFunctions(this);
831
832};
833
834MochiKit.Iter.__new__();
835
836//
837// XXX: Internet Explorer blows
838//
839if (MochiKit.__export__) {
840 reduce = MochiKit.Iter.reduce;
841}
842
843MochiKit.Base._exportSymbols(this, MochiKit.Iter);
diff --git a/frontend/beta/js/MochiKit/Logging.js b/frontend/beta/js/MochiKit/Logging.js
new file mode 100644
index 0000000..4d25c3e
--- a/dev/null
+++ b/frontend/beta/js/MochiKit/Logging.js
@@ -0,0 +1,321 @@
1/***
2
3MochiKit.Logging 1.4
4
5See <http://mochikit.com/> for documentation, downloads, license, etc.
6
7(c) 2005 Bob Ippolito. All rights Reserved.
8
9***/
10
11if (typeof(dojo) != 'undefined') {
12 dojo.provide('MochiKit.Logging');
13 dojo.require('MochiKit.Base');
14}
15
16if (typeof(JSAN) != 'undefined') {
17 JSAN.use("MochiKit.Base", []);
18}
19
20try {
21 if (typeof(MochiKit.Base) == 'undefined') {
22 throw "";
23 }
24} catch (e) {
25 throw "MochiKit.Logging depends on MochiKit.Base!";
26}
27
28if (typeof(MochiKit.Logging) == 'undefined') {
29 MochiKit.Logging = {};
30}
31
32MochiKit.Logging.NAME = "MochiKit.Logging";
33MochiKit.Logging.VERSION = "1.4";
34MochiKit.Logging.__repr__ = function () {
35 return "[" + this.NAME + " " + this.VERSION + "]";
36};
37
38MochiKit.Logging.toString = function () {
39 return this.__repr__();
40};
41
42
43MochiKit.Logging.EXPORT = [
44 "LogLevel",
45 "LogMessage",
46 "Logger",
47 "alertListener",
48 "logger",
49 "log",
50 "logError",
51 "logDebug",
52 "logFatal",
53 "logWarning"
54];
55
56
57MochiKit.Logging.EXPORT_OK = [
58 "logLevelAtLeast",
59 "isLogMessage",
60 "compareLogMessage"
61];
62
63
64/** @id MochiKit.Logging.LogMessage */
65MochiKit.Logging.LogMessage = function (num, level, info) {
66 this.num = num;
67 this.level = level;
68 this.info = info;
69 this.timestamp = new Date();
70};
71
72MochiKit.Logging.LogMessage.prototype = {
73 /** @id MochiKit.Logging.LogMessage.prototype.repr */
74 repr: function () {
75 var m = MochiKit.Base;
76 return 'LogMessage(' +
77 m.map(
78 m.repr,
79 [this.num, this.level, this.info]
80 ).join(', ') + ')';
81 },
82 /** @id MochiKit.Logging.LogMessage.prototype.toString */
83 toString: MochiKit.Base.forwardCall("repr")
84};
85
86MochiKit.Base.update(MochiKit.Logging, {
87 /** @id MochiKit.Logging.logLevelAtLeast */
88 logLevelAtLeast: function (minLevel) {
89 var self = MochiKit.Logging;
90 if (typeof(minLevel) == 'string') {
91 minLevel = self.LogLevel[minLevel];
92 }
93 return function (msg) {
94 var msgLevel = msg.level;
95 if (typeof(msgLevel) == 'string') {
96 msgLevel = self.LogLevel[msgLevel];
97 }
98 return msgLevel >= minLevel;
99 };
100 },
101
102 /** @id MochiKit.Logging.isLogMessage */
103 isLogMessage: function (/* ... */) {
104 var LogMessage = MochiKit.Logging.LogMessage;
105 for (var i = 0; i < arguments.length; i++) {
106 if (!(arguments[i] instanceof LogMessage)) {
107 return false;
108 }
109 }
110 return true;
111 },
112
113 /** @id MochiKit.Logging.compareLogMessage */
114 compareLogMessage: function (a, b) {
115 return MochiKit.Base.compare([a.level, a.info], [b.level, b.info]);
116 },
117
118 /** @id MochiKit.Logging.alertListener */
119 alertListener: function (msg) {
120 alert(
121 "num: " + msg.num +
122 "\nlevel: " + msg.level +
123 "\ninfo: " + msg.info.join(" ")
124 );
125 }
126
127});
128
129/** @id MochiKit.Logging.Logger */
130MochiKit.Logging.Logger = function (/* optional */maxSize) {
131 this.counter = 0;
132 if (typeof(maxSize) == 'undefined' || maxSize === null) {
133 maxSize = -1;
134 }
135 this.maxSize = maxSize;
136 this._messages = [];
137 this.listeners = {};
138 this.useNativeConsole = false;
139};
140
141MochiKit.Logging.Logger.prototype = {
142 /** @id MochiKit.Logging.Logger.prototype.clear */
143 clear: function () {
144 this._messages.splice(0, this._messages.length);
145 },
146
147 /** @id MochiKit.Logging.Logger.prototype.logToConsole */
148 logToConsole: function (msg) {
149 if (typeof(window) != "undefined" && window.console
150 && window.console.log) {
151 // Safari and FireBug 0.4
152 // Percent replacement is a workaround for cute Safari crashing bug
153 window.console.log(msg.replace(/%/g, '\uFF05'));
154 } else if (typeof(opera) != "undefined" && opera.postError) {
155 // Opera
156 opera.postError(msg);
157 } else if (typeof(printfire) == "function") {
158 // FireBug 0.3 and earlier
159 printfire(msg);
160 } else if (typeof(Debug) != "undefined" && Debug.writeln) {
161 // IE Web Development Helper (?)
162 // http://www.nikhilk.net/Entry.aspx?id=93
163 Debug.writeln(msg);
164 } else if (typeof(debug) != "undefined" && debug.trace) {
165 // Atlas framework (?)
166 // http://www.nikhilk.net/Entry.aspx?id=93
167 debug.trace(msg);
168 }
169 },
170
171 /** @id MochiKit.Logging.Logger.prototype.dispatchListeners */
172 dispatchListeners: function (msg) {
173 for (var k in this.listeners) {
174 var pair = this.listeners[k];
175 if (pair.ident != k || (pair[0] && !pair[0](msg))) {
176 continue;
177 }
178 pair[1](msg);
179 }
180 },
181
182 /** @id MochiKit.Logging.Logger.prototype.addListener */
183 addListener: function (ident, filter, listener) {
184 if (typeof(filter) == 'string') {
185 filter = MochiKit.Logging.logLevelAtLeast(filter);
186 }
187 var entry = [filter, listener];
188 entry.ident = ident;
189 this.listeners[ident] = entry;
190 },
191
192 /** @id MochiKit.Logging.Logger.prototype.removeListener */
193 removeListener: function (ident) {
194 delete this.listeners[ident];
195 },
196
197 /** @id MochiKit.Logging.Logger.prototype.baseLog */
198 baseLog: function (level, message/*, ...*/) {
199 var msg = new MochiKit.Logging.LogMessage(
200 this.counter,
201 level,
202 MochiKit.Base.extend(null, arguments, 1)
203 );
204 this._messages.push(msg);
205 this.dispatchListeners(msg);
206 if (this.useNativeConsole) {
207 this.logToConsole(msg.level + ": " + msg.info.join(" "));
208 }
209 this.counter += 1;
210 while (this.maxSize >= 0 && this._messages.length > this.maxSize) {
211 this._messages.shift();
212 }
213 },
214
215 /** @id MochiKit.Logging.Logger.prototype.getMessages */
216 getMessages: function (howMany) {
217 var firstMsg = 0;
218 if (!(typeof(howMany) == 'undefined' || howMany === null)) {
219 firstMsg = Math.max(0, this._messages.length - howMany);
220 }
221 return this._messages.slice(firstMsg);
222 },
223
224 /** @id MochiKit.Logging.Logger.prototype.getMessageText */
225 getMessageText: function (howMany) {
226 if (typeof(howMany) == 'undefined' || howMany === null) {
227 howMany = 30;
228 }
229 var messages = this.getMessages(howMany);
230 if (messages.length) {
231 var lst = map(function (m) {
232 return '\n [' + m.num + '] ' + m.level + ': ' + m.info.join(' ');
233 }, messages);
234 lst.unshift('LAST ' + messages.length + ' MESSAGES:');
235 return lst.join('');
236 }
237 return '';
238 },
239
240 /** @id MochiKit.Logging.Logger.prototype.debuggingBookmarklet */
241 debuggingBookmarklet: function (inline) {
242 if (typeof(MochiKit.LoggingPane) == "undefined") {
243 alert(this.getMessageText());
244 } else {
245 MochiKit.LoggingPane.createLoggingPane(inline || false);
246 }
247 }
248};
249
250MochiKit.Logging.__new__ = function () {
251 this.LogLevel = {
252 ERROR: 40,
253 FATAL: 50,
254 WARNING: 30,
255 INFO: 20,
256 DEBUG: 10
257 };
258
259 var m = MochiKit.Base;
260 m.registerComparator("LogMessage",
261 this.isLogMessage,
262 this.compareLogMessage
263 );
264
265 var partial = m.partial;
266
267 var Logger = this.Logger;
268 var baseLog = Logger.prototype.baseLog;
269 m.update(this.Logger.prototype, {
270 debug: partial(baseLog, 'DEBUG'),
271 log: partial(baseLog, 'INFO'),
272 error: partial(baseLog, 'ERROR'),
273 fatal: partial(baseLog, 'FATAL'),
274 warning: partial(baseLog, 'WARNING')
275 });
276
277 // indirectly find logger so it can be replaced
278 var self = this;
279 var connectLog = function (name) {
280 return function () {
281 self.logger[name].apply(self.logger, arguments);
282 };
283 };
284
285 /** @id MochiKit.Logging.log */
286 this.log = connectLog('log');
287 /** @id MochiKit.Logging.logError */
288 this.logError = connectLog('error');
289 /** @id MochiKit.Logging.logDebug */
290 this.logDebug = connectLog('debug');
291 /** @id MochiKit.Logging.logFatal */
292 this.logFatal = connectLog('fatal');
293 /** @id MochiKit.Logging.logWarning */
294 this.logWarning = connectLog('warning');
295 this.logger = new Logger();
296 this.logger.useNativeConsole = true;
297
298 this.EXPORT_TAGS = {
299 ":common": this.EXPORT,
300 ":all": m.concat(this.EXPORT, this.EXPORT_OK)
301 };
302
303 m.nameFunctions(this);
304
305};
306
307if (typeof(printfire) == "undefined" &&
308 typeof(document) != "undefined" && document.createEvent &&
309 typeof(dispatchEvent) != "undefined") {
310 // FireBug really should be less lame about this global function
311 printfire = function () {
312 printfire.args = arguments;
313 var ev = document.createEvent("Events");
314 ev.initEvent("printfire", false, true);
315 dispatchEvent(ev);
316 };
317}
318
319MochiKit.Logging.__new__();
320
321MochiKit.Base._exportSymbols(this, MochiKit.Logging);
diff --git a/frontend/beta/js/MochiKit/LoggingPane.js b/frontend/beta/js/MochiKit/LoggingPane.js
new file mode 100644
index 0000000..3798ae4
--- a/dev/null
+++ b/frontend/beta/js/MochiKit/LoggingPane.js
@@ -0,0 +1,374 @@
1/***
2
3MochiKit.LoggingPane 1.4
4
5See <http://mochikit.com/> for documentation, downloads, license, etc.
6
7(c) 2005 Bob Ippolito. All rights Reserved.
8
9***/
10
11if (typeof(dojo) != 'undefined') {
12 dojo.provide('MochiKit.LoggingPane');
13 dojo.require('MochiKit.Logging');
14 dojo.require('MochiKit.Base');
15}
16
17if (typeof(JSAN) != 'undefined') {
18 JSAN.use("MochiKit.Logging", []);
19 JSAN.use("MochiKit.Base", []);
20}
21
22try {
23 if (typeof(MochiKit.Base) == 'undefined' || typeof(MochiKit.Logging) == 'undefined') {
24 throw "";
25 }
26} catch (e) {
27 throw "MochiKit.LoggingPane depends on MochiKit.Base and MochiKit.Logging!";
28}
29
30if (typeof(MochiKit.LoggingPane) == 'undefined') {
31 MochiKit.LoggingPane = {};
32}
33
34MochiKit.LoggingPane.NAME = "MochiKit.LoggingPane";
35MochiKit.LoggingPane.VERSION = "1.4";
36MochiKit.LoggingPane.__repr__ = function () {
37 return "[" + this.NAME + " " + this.VERSION + "]";
38};
39
40MochiKit.LoggingPane.toString = function () {
41 return this.__repr__();
42};
43
44/** @id MochiKit.LoggingPane.createLoggingPane */
45MochiKit.LoggingPane.createLoggingPane = function (inline/* = false */) {
46 var m = MochiKit.LoggingPane;
47 inline = !(!inline);
48 if (m._loggingPane && m._loggingPane.inline != inline) {
49 m._loggingPane.closePane();
50 m._loggingPane = null;
51 }
52 if (!m._loggingPane || m._loggingPane.closed) {
53 m._loggingPane = new m.LoggingPane(inline, MochiKit.Logging.logger);
54 }
55 return m._loggingPane;
56};
57
58/** @id MochiKit.LoggingPane.LoggingPane */
59MochiKit.LoggingPane.LoggingPane = function (inline/* = false */, logger/* = MochiKit.Logging.logger */) {
60
61 /* Use a div if inline, pop up a window if not */
62 /* Create the elements */
63 if (typeof(logger) == "undefined" || logger === null) {
64 logger = MochiKit.Logging.logger;
65 }
66 this.logger = logger;
67 var update = MochiKit.Base.update;
68 var updatetree = MochiKit.Base.updatetree;
69 var bind = MochiKit.Base.bind;
70 var clone = MochiKit.Base.clone;
71 var win = window;
72 var uid = "_MochiKit_LoggingPane";
73 if (typeof(MochiKit.DOM) != "undefined") {
74 win = MochiKit.DOM.currentWindow();
75 }
76 if (!inline) {
77 // name the popup with the base URL for uniqueness
78 var url = win.location.href.split("?")[0].replace(/[#:\/.><&-]/g, "_");
79 var name = uid + "_" + url;
80 var nwin = win.open("", name, "dependent,resizable,height=200");
81 if (!nwin) {
82 alert("Not able to open debugging window due to pop-up blocking.");
83 return undefined;
84 }
85 nwin.document.write(
86 '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" '
87 + '"http://www.w3.org/TR/html4/loose.dtd">'
88 + '<html><head><title>[MochiKit.LoggingPane]</title></head>'
89 + '<body></body></html>'
90 );
91 nwin.document.close();
92 nwin.document.title += ' ' + win.document.title;
93 win = nwin;
94 }
95 var doc = win.document;
96 this.doc = doc;
97
98 // Connect to the debug pane if it already exists (i.e. in a window orphaned by the page being refreshed)
99 var debugPane = doc.getElementById(uid);
100 var existing_pane = !!debugPane;
101 if (debugPane && typeof(debugPane.loggingPane) != "undefined") {
102 debugPane.loggingPane.logger = this.logger;
103 debugPane.loggingPane.buildAndApplyFilter();
104 return debugPane.loggingPane;
105 }
106
107 if (existing_pane) {
108 // clear any existing contents
109 var child;
110 while ((child = debugPane.firstChild)) {
111 debugPane.removeChild(child);
112 }
113 } else {
114 debugPane = doc.createElement("div");
115 debugPane.id = uid;
116 }
117 debugPane.loggingPane = this;
118 var levelFilterField = doc.createElement("input");
119 var infoFilterField = doc.createElement("input");
120 var filterButton = doc.createElement("button");
121 var loadButton = doc.createElement("button");
122 var clearButton = doc.createElement("button");
123 var closeButton = doc.createElement("button");
124 var logPaneArea = doc.createElement("div");
125 var logPane = doc.createElement("div");
126
127 /* Set up the functions */
128 var listenerId = uid + "_Listener";
129 this.colorTable = clone(this.colorTable);
130 var messages = [];
131 var messageFilter = null;
132
133 /** @id MochiKit.LoggingPane.messageLevel */
134 var messageLevel = function (msg) {
135 var level = msg.level;
136 if (typeof(level) == "number") {
137 level = MochiKit.Logging.LogLevel[level];
138 }
139 return level;
140 };
141
142 /** @id MochiKit.LoggingPane.messageText */
143 var messageText = function (msg) {
144 return msg.info.join(" ");
145 };
146
147 /** @id MochiKit.LoggingPane.addMessageText */
148 var addMessageText = bind(function (msg) {
149 var level = messageLevel(msg);
150 var text = messageText(msg);
151 var c = this.colorTable[level];
152 var p = doc.createElement("span");
153 p.className = "MochiKit-LogMessage MochiKit-LogLevel-" + level;
154 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;
155 p.appendChild(doc.createTextNode(level + ": " + text));
156 logPane.appendChild(p);
157 logPane.appendChild(doc.createElement("br"));
158 if (logPaneArea.offsetHeight > logPaneArea.scrollHeight) {
159 logPaneArea.scrollTop = 0;
160 } else {
161 logPaneArea.scrollTop = logPaneArea.scrollHeight;
162 }
163 }, this);
164
165 /** @id MochiKit.LoggingPane.addMessage */
166 var addMessage = function (msg) {
167 messages[messages.length] = msg;
168 addMessageText(msg);
169 };
170
171 /** @id MochiKit.LoggingPane.buildMessageFilter */
172 var buildMessageFilter = function () {
173 var levelre, infore;
174 try {
175 /* Catch any exceptions that might arise due to invalid regexes */
176 levelre = new RegExp(levelFilterField.value);
177 infore = new RegExp(infoFilterField.value);
178 } catch(e) {
179 /* If there was an error with the regexes, do no filtering */
180 logDebug("Error in filter regex: " + e.message);
181 return null;
182 }
183
184 return function (msg) {
185 return (
186 levelre.test(messageLevel(msg)) &&
187 infore.test(messageText(msg))
188 );
189 };
190 };
191
192 /** @id MochiKit.LoggingPane.clearMessagePane */
193 var clearMessagePane = function () {
194 while (logPane.firstChild) {
195 logPane.removeChild(logPane.firstChild);
196 }
197 };
198
199 /** @id MochiKit.LoggingPane.clearMessages */
200 var clearMessages = function () {
201 messages = [];
202 clearMessagePane();
203 };
204
205 /** @id MochiKit.LoggingPane.closePane */
206 var closePane = bind(function () {
207 if (this.closed) {
208 return;
209 }
210 this.closed = true;
211 if (MochiKit.LoggingPane._loggingPane == this) {
212 MochiKit.LoggingPane._loggingPane = null;
213 }
214 this.logger.removeListener(listenerId);
215 try {
216 try {
217 debugPane.loggingPane = null;
218 } catch(e) { logFatal("Bookmarklet was closed incorrectly."); }
219 if (inline) {
220 debugPane.parentNode.removeChild(debugPane);
221 } else {
222 this.win.close();
223 }
224 } catch(e) {}
225 }, this);
226
227 /** @id MochiKit.LoggingPane.filterMessages */
228 var filterMessages = function () {
229 clearMessagePane();
230
231 for (var i = 0; i < messages.length; i++) {
232 var msg = messages[i];
233 if (messageFilter === null || messageFilter(msg)) {
234 addMessageText(msg);
235 }
236 }
237 };
238
239 this.buildAndApplyFilter = function () {
240 messageFilter = buildMessageFilter();
241
242 filterMessages();
243
244 this.logger.removeListener(listenerId);
245 this.logger.addListener(listenerId, messageFilter, addMessage);
246 };
247
248
249 /** @id MochiKit.LoggingPane.loadMessages */
250 var loadMessages = bind(function () {
251 messages = this.logger.getMessages();
252 filterMessages();
253 }, this);
254
255 /** @id MochiKit.LoggingPane.filterOnEnter */
256 var filterOnEnter = bind(function (event) {
257 event = event || window.event;
258 key = event.which || event.keyCode;
259 if (key == 13) {
260 this.buildAndApplyFilter();
261 }
262 }, this);
263
264 /* Create the debug pane */
265 var style = "display: block; z-index: 1000; left: 0px; bottom: 0px; position: fixed; width: 100%; background-color: white; font: " + this.logFont;
266 if (inline) {
267 style += "; height: 10em; border-top: 2px solid black";
268 } else {
269 style += "; height: 100%;";
270 }
271 debugPane.style.cssText = style;
272
273 if (!existing_pane) {
274 doc.body.appendChild(debugPane);
275 }
276
277 /* Create the filter fields */
278 style = {"cssText": "width: 33%; display: inline; font: " + this.logFont};
279
280 updatetree(levelFilterField, {
281 "value": "FATAL|ERROR|WARNING|INFO|DEBUG",
282 "onkeypress": filterOnEnter,
283 "style": style
284 });
285 debugPane.appendChild(levelFilterField);
286
287 updatetree(infoFilterField, {
288 "value": ".*",
289 "onkeypress": filterOnEnter,
290 "style": style
291 });
292 debugPane.appendChild(infoFilterField);
293
294 /* Create the buttons */
295 style = "width: 8%; display:inline; font: " + this.logFont;
296
297 filterButton.appendChild(doc.createTextNode("Filter"));
298 filterButton.onclick = bind("buildAndApplyFilter", this);
299 filterButton.style.cssText = style;
300 debugPane.appendChild(filterButton);
301
302 loadButton.appendChild(doc.createTextNode("Load"));
303 loadButton.onclick = loadMessages;
304 loadButton.style.cssText = style;
305 debugPane.appendChild(loadButton);
306
307 clearButton.appendChild(doc.createTextNode("Clear"));
308 clearButton.onclick = clearMessages;
309 clearButton.style.cssText = style;
310 debugPane.appendChild(clearButton);
311
312 closeButton.appendChild(doc.createTextNode("Close"));
313 closeButton.onclick = closePane;
314 closeButton.style.cssText = style;
315 debugPane.appendChild(closeButton);
316
317 /* Create the logging pane */
318 logPaneArea.style.cssText = "overflow: auto; width: 100%";
319 logPane.style.cssText = "width: 100%; height: " + (inline ? "8em" : "100%");
320
321 logPaneArea.appendChild(logPane);
322 debugPane.appendChild(logPaneArea);
323
324 this.buildAndApplyFilter();
325 loadMessages();
326
327 if (inline) {
328 this.win = undefined;
329 } else {
330 this.win = win;
331 }
332 this.inline = inline;
333 this.closePane = closePane;
334 this.closed = false;
335
336
337 return this;
338};
339
340MochiKit.LoggingPane.LoggingPane.prototype = {
341 "logFont": "8pt Verdana,sans-serif",
342 "colorTable": {
343 "ERROR": "red",
344 "FATAL": "darkred",
345 "WARNING": "blue",
346 "INFO": "black",
347 "DEBUG": "green"
348 }
349};
350
351
352MochiKit.LoggingPane.EXPORT_OK = [
353 "LoggingPane"
354];
355
356MochiKit.LoggingPane.EXPORT = [
357 "createLoggingPane"
358];
359
360MochiKit.LoggingPane.__new__ = function () {
361 this.EXPORT_TAGS = {
362 ":common": this.EXPORT,
363 ":all": MochiKit.Base.concat(this.EXPORT, this.EXPORT_OK)
364 };
365
366 MochiKit.Base.nameFunctions(this);
367
368 MochiKit.LoggingPane._loggingPane = null;
369
370};
371
372MochiKit.LoggingPane.__new__();
373
374MochiKit.Base._exportSymbols(this, MochiKit.LoggingPane);
diff --git a/frontend/beta/js/MochiKit/MochiKit.js b/frontend/beta/js/MochiKit/MochiKit.js
new file mode 100644
index 0000000..3a13b24
--- a/dev/null
+++ b/frontend/beta/js/MochiKit/MochiKit.js
@@ -0,0 +1,154 @@
1/***
2
3MochiKit.MochiKit 1.4
4
5See <http://mochikit.com/> for documentation, downloads, license, etc.
6
7(c) 2005 Bob Ippolito. All rights Reserved.
8
9***/
10
11if (typeof(MochiKit) == 'undefined') {
12 MochiKit = {};
13}
14
15if (typeof(MochiKit.MochiKit) == 'undefined') {
16 /** @id MochiKit.MochiKit */
17 MochiKit.MochiKit = {};
18}
19
20MochiKit.MochiKit.NAME = "MochiKit.MochiKit";
21MochiKit.MochiKit.VERSION = "1.4";
22MochiKit.MochiKit.__repr__ = function () {
23 return "[" + this.NAME + " " + this.VERSION + "]";
24};
25
26/** @id MochiKit.MochiKit.toString */
27MochiKit.MochiKit.toString = function () {
28 return this.__repr__();
29};
30
31/** @id MochiKit.MochiKit.SUBMODULES */
32MochiKit.MochiKit.SUBMODULES = [
33 "Base",
34 "Iter",
35 "Logging",
36 "DateTime",
37 "Format",
38 "Async",
39 "DOM",
40 "Selector",
41 "Style",
42 "LoggingPane",
43 "Color",
44 "Signal",
45 "Position",
46 "Visual"
47];
48
49if (typeof(JSAN) != 'undefined' || typeof(dojo) != 'undefined') {
50 if (typeof(dojo) != 'undefined') {
51 dojo.provide('MochiKit.MochiKit');
52 dojo.require("MochiKit.*");
53 }
54 if (typeof(JSAN) != 'undefined') {
55 (function (lst) {
56 for (var i = 0; i < lst.length; i++) {
57 JSAN.use("MochiKit." + lst[i], []);
58 }
59 })(MochiKit.MochiKit.SUBMODULES);
60 }
61 (function () {
62 var extend = MochiKit.Base.extend;
63 var self = MochiKit.MochiKit;
64 var modules = self.SUBMODULES;
65 var EXPORT = [];
66 var EXPORT_OK = [];
67 var EXPORT_TAGS = {};
68 var i, k, m, all;
69 for (i = 0; i < modules.length; i++) {
70 m = MochiKit[modules[i]];
71 extend(EXPORT, m.EXPORT);
72 extend(EXPORT_OK, m.EXPORT_OK);
73 for (k in m.EXPORT_TAGS) {
74 EXPORT_TAGS[k] = extend(EXPORT_TAGS[k], m.EXPORT_TAGS[k]);
75 }
76 all = m.EXPORT_TAGS[":all"];
77 if (!all) {
78 all = extend(null, m.EXPORT, m.EXPORT_OK);
79 }
80 var j;
81 for (j = 0; j < all.length; j++) {
82 k = all[j];
83 self[k] = m[k];
84 }
85 }
86 self.EXPORT = EXPORT;
87 self.EXPORT_OK = EXPORT_OK;
88 self.EXPORT_TAGS = EXPORT_TAGS;
89 }());
90
91} else {
92 if (typeof(MochiKit.__compat__) == 'undefined') {
93 MochiKit.__compat__ = true;
94 }
95 (function () {
96 if (typeof(document) == "undefined") {
97 return;
98 }
99 var scripts = document.getElementsByTagName("script");
100 var kXULNSURI = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
101 var base = null;
102 var baseElem = null;
103 var allScripts = {};
104 var i;
105 for (i = 0; i < scripts.length; i++) {
106 var src = scripts[i].getAttribute("src");
107 if (!src) {
108 continue;
109 }
110 allScripts[src] = true;
111 if (src.match(/MochiKit.js$/)) {
112 base = src.substring(0, src.lastIndexOf('MochiKit.js'));
113 baseElem = scripts[i];
114 }
115 }
116 if (base === null) {
117 return;
118 }
119 var modules = MochiKit.MochiKit.SUBMODULES;
120 for (var i = 0; i < modules.length; i++) {
121 if (MochiKit[modules[i]]) {
122 continue;
123 }
124 var uri = base + modules[i] + '.js';
125 if (uri in allScripts) {
126 continue;
127 }
128 if (document.documentElement &&
129 document.documentElement.namespaceURI == kXULNSURI) {
130 // XUL
131 var s = document.createElementNS(kXULNSURI, 'script');
132 s.setAttribute("id", "MochiKit_" + base + modules[i]);
133 s.setAttribute("src", uri);
134 s.setAttribute("type", "application/x-javascript");
135 baseElem.parentNode.appendChild(s);
136 } else {
137 // HTML
138 /*
139 DOM can not be used here because Safari does
140 deferred loading of scripts unless they are
141 in the document or inserted with document.write
142
143 This is not XHTML compliant. If you want XHTML
144 compliance then you must use the packed version of MochiKit
145 or include each script individually (basically unroll
146 these document.write calls into your XHTML source)
147
148 */
149 document.write('<script src="' + uri +
150 '" type="text/javascript"></script>');
151 }
152 };
153 })();
154}
diff --git a/frontend/beta/js/MochiKit/MockDOM.js b/frontend/beta/js/MochiKit/MockDOM.js
new file mode 100644
index 0000000..92558cb
--- a/dev/null
+++ b/frontend/beta/js/MochiKit/MockDOM.js
@@ -0,0 +1,115 @@
1/***
2
3MochiKit.MockDOM 1.4
4
5See <http://mochikit.com/> for documentation, downloads, license, etc.
6
7(c) 2005 Bob Ippolito. All rights Reserved.
8
9***/
10
11if (typeof(MochiKit) == "undefined") {
12 MochiKit = {};
13}
14
15if (typeof(MochiKit.MockDOM) == "undefined") {
16 MochiKit.MockDOM = {};
17}
18
19MochiKit.MockDOM.NAME = "MochiKit.MockDOM";
20MochiKit.MockDOM.VERSION = "1.4";
21
22MochiKit.MockDOM.__repr__ = function () {
23 return "[" + this.NAME + " " + this.VERSION + "]";
24};
25
26/** @id MochiKit.MockDOM.toString */
27MochiKit.MockDOM.toString = function () {
28 return this.__repr__();
29};
30
31/** @id MochiKit.MockDOM.createDocument */
32MochiKit.MockDOM.createDocument = function () {
33 var doc = new MochiKit.MockDOM.MockElement("DOCUMENT");
34 doc.body = doc.createElement("BODY");
35 doc.appendChild(doc.body);
36 return doc;
37};
38
39/** @id MochiKit.MockDOM.MockElement */
40MochiKit.MockDOM.MockElement = function (name, data, ownerDocument) {
41 this.tagName = this.nodeName = name.toUpperCase();
42 this.ownerDocument = ownerDocument || null;
43 if (name == "DOCUMENT") {
44 this.nodeType = 9;
45 this.childNodes = [];
46 } else if (typeof(data) == "string") {
47 this.nodeValue = data;
48 this.nodeType = 3;
49 } else {
50 this.nodeType = 1;
51 this.childNodes = [];
52 }
53 if (name.substring(0, 1) == "<") {
54 var nameattr = name.substring(
55 name.indexOf('"') + 1, name.lastIndexOf('"'));
56 name = name.substring(1, name.indexOf(" "));
57 this.tagName = this.nodeName = name.toUpperCase();
58 this.setAttribute("name", nameattr);
59 }
60};
61
62MochiKit.MockDOM.MockElement.prototype = {
63 /** @id MochiKit.MockDOM.MockElement.prototype.createElement */
64 createElement: function (tagName) {
65 return new MochiKit.MockDOM.MockElement(tagName, null, this.nodeType == 9 ? this : this.ownerDocument);
66 },
67 /** @id MochiKit.MockDOM.MockElement.prototype.createTextNode */
68 createTextNode: function (text) {
69 return new MochiKit.MockDOM.MockElement("text", text, this.nodeType == 9 ? this : this.ownerDocument);
70 },
71 /** @id MochiKit.MockDOM.MockElement.prototype.setAttribute */
72 setAttribute: function (name, value) {
73 this[name] = value;
74 },
75 /** @id MochiKit.MockDOM.MockElement.prototype.getAttribute */
76 getAttribute: function (name) {
77 return this[name];
78 },
79 /** @id MochiKit.MockDOM.MockElement.prototype.appendChild */
80 appendChild: function (child) {
81 this.childNodes.push(child);
82 },
83 /** @id MochiKit.MockDOM.MockElement.prototype.toString */
84 toString: function () {
85 return "MockElement(" + this.tagName + ")";
86 },
87 /** @id MochiKit.MockDOM.MockElement.prototype.getElementsByTagName */
88 getElementsByTagName: function (tagName) {
89 var foundElements = [];
90 MochiKit.Base.nodeWalk(this, function(node){
91 if (tagName == '*' || tagName == node.tagName) {
92 foundElements.push(node);
93 return node.childNodes;
94 }
95 });
96 return foundElements;
97 }
98};
99
100 /** @id MochiKit.MockDOM.EXPORT_OK */
101MochiKit.MockDOM.EXPORT_OK = [
102 "mockElement",
103 "createDocument"
104];
105
106 /** @id MochiKit.MockDOM.EXPORT */
107MochiKit.MockDOM.EXPORT = [
108 "document"
109];
110
111MochiKit.MockDOM.__new__ = function () {
112 this.document = this.createDocument();
113};
114
115MochiKit.MockDOM.__new__();
diff --git a/frontend/beta/js/MochiKit/New.js b/frontend/beta/js/MochiKit/New.js
new file mode 100644
index 0000000..8b13789
--- a/dev/null
+++ b/frontend/beta/js/MochiKit/New.js
@@ -0,0 +1 @@
diff --git a/frontend/beta/js/MochiKit/Position.js b/frontend/beta/js/MochiKit/Position.js
new file mode 100644
index 0000000..6092fe9
--- a/dev/null
+++ b/frontend/beta/js/MochiKit/Position.js
@@ -0,0 +1,246 @@
1/***
2
3MochiKit.Position 1.4
4
5See <http://mochikit.com/> for documentation, downloads, license, etc.
6
7(c) 2005-2006 Bob Ippolito and others. All rights Reserved.
8
9***/
10
11if (typeof(dojo) != 'undefined') {
12 dojo.provide('MochiKit.Position');
13 dojo.require('MochiKit.Base');
14 dojo.require('MochiKit.DOM');
15 dojo.require('MochiKit.Style');
16}
17if (typeof(JSAN) != 'undefined') {
18 JSAN.use('MochiKit.Base', []);
19 JSAN.use('MochiKit.DOM', []);
20 JSAN.use('MochiKit.Style', []);
21}
22
23try {
24 if (typeof(MochiKit.Base) == 'undefined' ||
25 typeof(MochiKit.Style) == 'undefined' ||
26 typeof(MochiKit.DOM) == 'undefined') {
27 throw '';
28 }
29} catch (e) {
30 throw 'MochiKit.Style depends on MochiKit.Base, MochiKit.DOM, and MochiKit.Style!';
31}
32
33if (typeof(MochiKit.Position) == 'undefined') {
34 MochiKit.Position = {};
35}
36
37MochiKit.Position.NAME = 'MochiKit.Position';
38MochiKit.Position.VERSION = '1.4';
39MochiKit.Position.__repr__ = function () {
40 return '[' + this.NAME + ' ' + this.VERSION + ']';
41};
42MochiKit.Position.toString = function () {
43 return this.__repr__();
44};
45
46MochiKit.Position.EXPORT_OK = [];
47
48MochiKit.Position.EXPORT = [
49];
50
51
52MochiKit.Base.update(MochiKit.Position, {
53 // set to true if needed, warning: firefox performance problems
54 // NOT neeeded for page scrolling, only if draggable contained in
55 // scrollable elements
56 includeScrollOffsets: false,
57
58 /** @id MochiKit.Position.prepare */
59 prepare: function () {
60 var deltaX = window.pageXOffset
61 || document.documentElement.scrollLeft
62 || document.body.scrollLeft
63 || 0;
64 var deltaY = window.pageYOffset
65 || document.documentElement.scrollTop
66 || document.body.scrollTop
67 || 0;
68 this.windowOffset = new MochiKit.Style.Coordinates(deltaX, deltaY);
69 },
70
71 /** @id MochiKit.Position.cumulativeOffset */
72 cumulativeOffset: function (element) {
73 var valueT = 0;
74 var valueL = 0;
75 do {
76 valueT += element.offsetTop || 0;
77 valueL += element.offsetLeft || 0;
78 element = element.offsetParent;
79 } while (element);
80 return new MochiKit.Style.Coordinates(valueL, valueT);
81 },
82
83 /** @id MochiKit.Position.realOffset */
84 realOffset: function (element) {
85 var valueT = 0;
86 var valueL = 0;
87 do {
88 valueT += element.scrollTop || 0;
89 valueL += element.scrollLeft || 0;
90 element = element.parentNode;
91 } while (element);
92 return new MochiKit.Style.Coordinates(valueL, valueT);
93 },
94
95 /** @id MochiKit.Position.within */
96 within: function (element, x, y) {
97 if (this.includeScrollOffsets) {
98 return this.withinIncludingScrolloffsets(element, x, y);
99 }
100 this.xcomp = x;
101 this.ycomp = y;
102 this.offset = this.cumulativeOffset(element);
103 if (element.style.position == "fixed") {
104 this.offset.x += this.windowOffset.x;
105 this.offset.y += this.windowOffset.y;
106 }
107
108 return (y >= this.offset.y &&
109 y < this.offset.y + element.offsetHeight &&
110 x >= this.offset.x &&
111 x < this.offset.x + element.offsetWidth);
112 },
113
114 /** @id MochiKit.Position.withinIncludingScrolloffsets */
115 withinIncludingScrolloffsets: function (element, x, y) {
116 var offsetcache = this.realOffset(element);
117
118 this.xcomp = x + offsetcache.x - this.windowOffset.x;
119 this.ycomp = y + offsetcache.y - this.windowOffset.y;
120 this.offset = this.cumulativeOffset(element);
121
122 return (this.ycomp >= this.offset.y &&
123 this.ycomp < this.offset.y + element.offsetHeight &&
124 this.xcomp >= this.offset.x &&
125 this.xcomp < this.offset.x + element.offsetWidth);
126 },
127
128 // within must be called directly before
129 /** @id MochiKit.Position.overlap */
130 overlap: function (mode, element) {
131 if (!mode) {
132 return 0;
133 }
134 if (mode == 'vertical') {
135 return ((this.offset.y + element.offsetHeight) - this.ycomp) /
136 element.offsetHeight;
137 }
138 if (mode == 'horizontal') {
139 return ((this.offset.x + element.offsetWidth) - this.xcomp) /
140 element.offsetWidth;
141 }
142 },
143
144 /** @id MochiKit.Position.absolutize */
145 absolutize: function (element) {
146 element = MochiKit.DOM.getElement(element);
147 if (element.style.position == 'absolute') {
148 return;
149 }
150 MochiKit.Position.prepare();
151
152 var offsets = MochiKit.Position.positionedOffset(element);
153 var width = element.clientWidth;
154 var height = element.clientHeight;
155
156 var oldStyle = {
157 'position': element.style.position,
158 'left': offsets.x - parseFloat(element.style.left || 0),
159 'top': offsets.y - parseFloat(element.style.top || 0),
160 'width': element.style.width,
161 'height': element.style.height
162 };
163
164 element.style.position = 'absolute';
165 element.style.top = offsets.y + 'px';
166 element.style.left = offsets.x + 'px';
167 element.style.width = width + 'px';
168 element.style.height = height + 'px';
169
170 return oldStyle;
171 },
172
173 /** @id MochiKit.Position.positionedOffset */
174 positionedOffset: function (element) {
175 var valueT = 0, valueL = 0;
176 do {
177 valueT += element.offsetTop || 0;
178 valueL += element.offsetLeft || 0;
179 element = element.offsetParent;
180 if (element) {
181 p = MochiKit.Style.getStyle(element, 'position');
182 if (p == 'relative' || p == 'absolute') {
183 break;
184 }
185 }
186 } while (element);
187 return new MochiKit.Style.Coordinates(valueL, valueT);
188 },
189
190 /** @id MochiKit.Position.relativize */
191 relativize: function (element, oldPos) {
192 element = MochiKit.DOM.getElement(element);
193 if (element.style.position == 'relative') {
194 return;
195 }
196 MochiKit.Position.prepare();
197
198 var top = parseFloat(element.style.top || 0) -
199 (oldPos['top'] || 0);
200 var left = parseFloat(element.style.left || 0) -
201 (oldPos['left'] || 0);
202
203 element.style.position = oldPos['position'];
204 element.style.top = top + 'px';
205 element.style.left = left + 'px';
206 element.style.width = oldPos['width'];
207 element.style.height = oldPos['height'];
208 },
209
210 /** @id MochiKit.Position.clone */
211 clone: function (source, target) {
212 source = MochiKit.DOM.getElement(source);
213 target = MochiKit.DOM.getElement(target);
214 target.style.position = 'absolute';
215 var offsets = this.cumulativeOffset(source);
216 target.style.top = offsets.y + 'px';
217 target.style.left = offsets.x + 'px';
218 target.style.width = source.offsetWidth + 'px';
219 target.style.height = source.offsetHeight + 'px';
220 },
221
222 /** @id MochiKit.Position.page */
223 page: function (forElement) {
224 var valueT = 0;
225 var valueL = 0;
226
227 var element = forElement;
228 do {
229 valueT += element.offsetTop || 0;
230 valueL += element.offsetLeft || 0;
231
232 // Safari fix
233 if (element.offsetParent == document.body && MochiKit.Style.getStyle(element, 'position') == 'absolute') {
234 break;
235 }
236 } while (element = element.offsetParent);
237
238 element = forElement;
239 do {
240 valueT -= element.scrollTop || 0;
241 valueL -= element.scrollLeft || 0;
242 } while (element = element.parentNode);
243
244 return new MochiKit.Style.Coordinates(valueL, valueT);
245 }
246});
diff --git a/frontend/beta/js/MochiKit/Selector.js b/frontend/beta/js/MochiKit/Selector.js
new file mode 100644
index 0000000..c385df7
--- a/dev/null
+++ b/frontend/beta/js/MochiKit/Selector.js
@@ -0,0 +1,431 @@
1/***
2
3MochiKit.Selector 1.4
4
5See <http://mochikit.com/> for documentation, downloads, license, etc.
6
7(c) 2005 Bob Ippolito and others. All rights Reserved.
8
9***/
10
11if (typeof(dojo) != 'undefined') {
12 dojo.provide('MochiKit.Selector');
13 dojo.require('MochiKit.Base');
14 dojo.require('MochiKit.DOM');
15 dojo.require('MochiKit.Iter');
16}
17
18if (typeof(JSAN) != 'undefined') {
19 JSAN.use("MochiKit.Base", []);
20 JSAN.use("MochiKit.DOM", []);
21 JSAN.use("MochiKit.Iter", []);
22}
23
24try {
25 if (typeof(MochiKit.Base) === 'undefined' ||
26 typeof(MochiKit.DOM) === 'undefined' ||
27 typeof(MochiKit.Iter) === 'undefined') {
28 throw "";
29 }
30} catch (e) {
31 throw "MochiKit.Selector depends on MochiKit.Base, MochiKit.DOM and MochiKit.Iter!";
32}
33
34if (typeof(MochiKit.Selector) == 'undefined') {
35 MochiKit.Selector = {};
36}
37
38MochiKit.Selector.NAME = "MochiKit.Selector";
39
40MochiKit.Selector.VERSION = "1.4";
41
42MochiKit.Selector.__repr__ = function () {
43 return "[" + this.NAME + " " + this.VERSION + "]";
44};
45
46MochiKit.Selector.toString = function () {
47 return this.__repr__();
48};
49
50MochiKit.Selector.EXPORT = [
51 "Selector",
52 "findChildElements",
53 "findDocElements",
54 "$$"
55];
56
57MochiKit.Selector.EXPORT_OK = [
58];
59
60MochiKit.Selector.Selector = function (expression) {
61 this.params = {classNames: [], pseudoClassNames: []};
62 this.expression = expression.toString().replace(/(^\s+|\s+$)/g, '');
63 this.parseExpression();
64 this.compileMatcher();
65};
66
67MochiKit.Selector.Selector.prototype = {
68 /***
69
70 Selector class: convenient object to make CSS selections.
71
72 ***/
73 __class__: MochiKit.Selector.Selector,
74
75 /** @id MochiKit.Selector.Selector.prototype.parseExpression */
76 parseExpression: function () {
77 function abort(message) {
78 throw 'Parse error in selector: ' + message;
79 }
80
81 if (this.expression == '') {
82 abort('empty expression');
83 }
84
85 var repr = MochiKit.Base.repr;
86 var params = this.params;
87 var expr = this.expression;
88 var match, modifier, clause, rest;
89 while (match = expr.match(/^(.*)\[([a-z0-9_:-]+?)(?:([~\|!^$*]?=)(?:"([^"]*)"|([^\]\s]*)))?\]$/i)) {
90 params.attributes = params.attributes || [];
91 params.attributes.push({name: match[2], operator: match[3], value: match[4] || match[5] || ''});
92 expr = match[1];
93 }
94
95 if (expr == '*') {
96 return this.params.wildcard = true;
97 }
98
99 while (match = expr.match(/^([^a-z0-9_-])?([a-z0-9_-]+(?:\([^)]*\))?)(.*)/i)) {
100 modifier = match[1];
101 clause = match[2];
102 rest = match[3];
103 switch (modifier) {
104 case '#':
105 params.id = clause;
106 break;
107 case '.':
108 params.classNames.push(clause);
109 break;
110 case ':':
111 params.pseudoClassNames.push(clause);
112 break;
113 case '':
114 case undefined:
115 params.tagName = clause.toUpperCase();
116 break;
117 default:
118 abort(repr(expr));
119 }
120 expr = rest;
121 }
122
123 if (expr.length > 0) {
124 abort(repr(expr));
125 }
126 },
127
128 /** @id MochiKit.Selector.Selector.prototype.buildMatchExpression */
129 buildMatchExpression: function () {
130 var repr = MochiKit.Base.repr;
131 var params = this.params;
132 var conditions = [];
133 var clause, i;
134
135 function childElements(element) {
136 return "MochiKit.Base.filter(function (node) { return node.nodeType == 1; }, " + element + ".childNodes)";
137 }
138
139 if (params.wildcard) {
140 conditions.push('true');
141 }
142 if (clause = params.id) {
143 conditions.push('element.id == ' + repr(clause));
144 }
145 if (clause = params.tagName) {
146 conditions.push('element.tagName.toUpperCase() == ' + repr(clause));
147 }
148 if ((clause = params.classNames).length > 0) {
149 for (i = 0; i < clause.length; i++) {
150 conditions.push('MochiKit.DOM.hasElementClass(element, ' + repr(clause[i]) + ')');
151 }
152 }
153 if ((clause = params.pseudoClassNames).length > 0) {
154 for (i = 0; i < clause.length; i++) {
155 var match = clause[i].match(/^([^(]+)(?:\((.*)\))?$/);
156 var pseudoClass = match[1];
157 var pseudoClassArgument = match[2];
158 switch (pseudoClass) {
159 case 'root':
160 conditions.push('element.nodeType == 9 || element === element.ownerDocument.documentElement'); break;
161 case 'nth-child':
162 case 'nth-last-child':
163 case 'nth-of-type':
164 case 'nth-last-of-type':
165 match = pseudoClassArgument.match(/^((?:(\d+)n\+)?(\d+)|odd|even)$/);
166 if (!match) {
167 throw "Invalid argument to pseudo element nth-child: " + pseudoClassArgument;
168 }
169 var a, b;
170 if (match[0] == 'odd') {
171 a = 2;
172 b = 1;
173 } else if (match[0] == 'even') {
174 a = 2;
175 b = 0;
176 } else {
177 a = match[2] && parseInt(match) || null;
178 b = parseInt(match[3]);
179 }
180 conditions.push('this.nthChild(element,' + a + ',' + b
181 + ',' + !!pseudoClass.match('^nth-last') // Reverse
182 + ',' + !!pseudoClass.match('of-type$') // Restrict to same tagName
183 + ')');
184 break;
185 case 'first-child':
186 conditions.push('this.nthChild(element, null, 1)');
187 break;
188 case 'last-child':
189 conditions.push('this.nthChild(element, null, 1, true)');
190 break;
191 case 'first-of-type':
192 conditions.push('this.nthChild(element, null, 1, false, true)');
193 break;
194 case 'last-of-type':
195 conditions.push('this.nthChild(element, null, 1, true, true)');
196 break;
197 case 'only-child':
198 conditions.push(childElements('element.parentNode') + '.length == 1');
199 break;
200 case 'only-of-type':
201 conditions.push('MochiKit.Base.filter(function (node) { return node.tagName == element.tagName; }, ' + childElements('element.parentNode') + ').length == 1');
202 break;
203 case 'empty':
204 conditions.push('element.childNodes.length == 0');
205 break;
206 case 'enabled':
207 conditions.push('(this.isUIElement(element) && element.disabled === false)');
208 break;
209 case 'disabled':
210 conditions.push('(this.isUIElement(element) && element.disabled === true)');
211 break;
212 case 'checked':
213 conditions.push('(this.isUIElement(element) && element.checked === true)');
214 break;
215 case 'not':
216 var subselector = new MochiKit.Selector.Selector(pseudoClassArgument);
217 conditions.push('!( ' + subselector.buildMatchExpression() + ')')
218 break;
219 }
220 }
221 }
222 if (clause = params.attributes) {
223 MochiKit.Base.map(function (attribute) {
224 var value = 'MochiKit.DOM.getNodeAttribute(element, ' + repr(attribute.name) + ')';
225 var splitValueBy = function (delimiter) {
226 return value + ' && ' + value + '.split(' + repr(delimiter) + ')';
227 }
228
229 switch (attribute.operator) {
230 case '=':
231 conditions.push(value + ' == ' + repr(attribute.value));
232 break;
233 case '~=':
234 conditions.push('MochiKit.Base.findValue(' + splitValueBy(' ') + ', ' + repr(attribute.value) + ') > -1');
235 break;
236 case '^=':
237 conditions.push(value + '.substring(0, ' + attribute.value.length + ') == ' + repr(attribute.value));
238 break;
239 case '$=':
240 conditions.push(value + '.substring(' + value + '.length - ' + attribute.value.length + ') == ' + repr(attribute.value));
241 break;
242 case '*=':
243 conditions.push(value + '.match(' + repr(attribute.value) + ')');
244 break;
245 case '|=':
246 conditions.push(
247 splitValueBy('-') + '[0].toUpperCase() == ' + repr(attribute.value.toUpperCase())
248 );
249 break;
250 case '!=':
251 conditions.push(value + ' != ' + repr(attribute.value));
252 break;
253 case '':
254 case undefined:
255 conditions.push(value + ' != null');
256 break;
257 default:
258 throw 'Unknown operator ' + attribute.operator + ' in selector';
259 }
260 }, clause);
261 }
262
263 return conditions.join(' && ');
264 },
265
266 /** @id MochiKit.Selector.Selector.prototype.compileMatcher */
267 compileMatcher: function () {
268 this.match = new Function('element', 'if (!element.tagName) return false; \
269 return ' + this.buildMatchExpression());
270 },
271
272 /** @id MochiKit.Selector.Selector.prototype.nthChild */
273 nthChild: function (element, a, b, reverse, sametag){
274 var siblings = MochiKit.Base.filter(function (node) {
275 return node.nodeType == 1;
276 }, element.parentNode.childNodes);
277 if (sametag) {
278 siblings = MochiKit.Base.filter(function (node) {
279 return node.tagName == element.tagName;
280 }, siblings);
281 }
282 if (reverse) {
283 siblings = MochiKit.Iter.reversed(siblings);
284 }
285 if (a) {
286 var actualIndex = MochiKit.Base.findIdentical(siblings, element);
287 return ((actualIndex + 1 - b) / a) % 1 == 0;
288 } else {
289 return b == MochiKit.Base.findIdentical(siblings, element) + 1;
290 }
291 },
292
293 /** @id MochiKit.Selector.Selector.prototype.isUIElement */
294 isUIElement: function (element) {
295 return findValue(['input', 'button', 'select', 'option', 'textarea', 'object'],
296 element.tagName.toLowerCase()) > -1;
297 },
298
299 /** @id MochiKit.Selector.Selector.prototype.findElements */
300 findElements: function (scope, axis) {
301 var element;
302
303 if (axis == undefined) {
304 axis = "";
305 }
306
307 function inScope(element, scope) {
308 if (axis == "") {
309 return MochiKit.DOM.isChildNode(element, scope);
310 } else if (axis == ">") {
311 return element.parentNode == scope;
312 } else if (axis == "+") {
313 return element == nextSiblingElement(scope);
314 } else if (axis == "~") {
315 var sibling = scope;
316 while (sibling = nextSiblingElement(sibling)) {
317 if (element == sibling) {
318 return true;
319 }
320 }
321 return false;
322 } else {
323 throw "Invalid axis: " + axis;
324 }
325 }
326
327 if (element = MochiKit.DOM.getElement(this.params.id)) {
328 if (this.match(element)) {
329 if (!scope || inScope(element, scope)) {
330 return [element];
331 }
332 }
333 }
334
335 function nextSiblingElement(node) {
336 node = node.nextSibling;
337 while (node && node.nodeType != 1) {
338 node = node.nextSibling;
339 }
340 return node;
341 }
342
343 if (axis == "") {
344 scope = (scope || currentDocument()).getElementsByTagName(this.params.tagName || '*');
345 } else if (axis == ">") {
346 if (!scope) {
347 throw "> combinator not allowed without preceeding expression";
348 }
349 scope = MochiKit.Base.filter(function (node) {
350 return node.nodeType == 1;
351 }, scope.childNodes);
352 } else if (axis == "+") {
353 if (!scope) {
354 throw "+ combinator not allowed without preceeding expression";
355 }
356 scope = nextSiblingElement(scope) && [nextSiblingElement(scope)];
357 } else if (axis == "~") {
358 if (!scope) {
359 throw "~ combinator not allowed without preceeding expression";
360 }
361 var newscope = [];
362 while (nextSiblingElement(scope)) {
363 scope = nextSiblingElement(scope);
364 newscope.push(scope);
365 }
366 scope = newscope;
367 }
368
369 if (!scope) {
370 return [];
371 }
372
373 var results = MochiKit.Base.filter(MochiKit.Base.bind(function (scopeElt) {
374 return this.match(scopeElt);
375 }, this), scope);
376
377 return results;
378 },
379
380 /** @id MochiKit.Selector.Selector.prototype.repr */
381 repr: function () {
382 return 'Selector(' + this.expression + ')';
383 },
384
385 toString: MochiKit.Base.forwardCall("repr")
386};
387
388MochiKit.Base.update(MochiKit.Selector, {
389
390 /** @id MochiKit.Selector.findChildElements */
391 findChildElements: function (element, expressions) {
392 return MochiKit.Base.flattenArray(MochiKit.Base.map(function (expression) {
393 var nextScope = "";
394 return MochiKit.Iter.reduce(function (results, expr) {
395 if (match = expr.match(/^[>+~]$/)) {
396 nextScope = match[0];
397 return results;
398 } else {
399 var selector = new MochiKit.Selector.Selector(expr);
400 var elements = MochiKit.Iter.reduce(function (elements, result) {
401 return MochiKit.Base.extend(elements, selector.findElements(result || element, nextScope));
402 }, results, []);
403 nextScope = "";
404 return elements;
405 }
406 }, expression.replace(/(^\s+|\s+$)/g, '').split(/\s+/), [null]);
407 }, expressions));
408 },
409
410 findDocElements: function () {
411 return MochiKit.Selector.findChildElements(MochiKit.DOM.currentDocument(), arguments);
412 },
413
414 __new__: function () {
415 var m = MochiKit.Base;
416
417 this.$$ = this.findDocElements;
418
419 this.EXPORT_TAGS = {
420 ":common": this.EXPORT,
421 ":all": m.concat(this.EXPORT, this.EXPORT_OK)
422 };
423
424 m.nameFunctions(this);
425 }
426});
427
428MochiKit.Selector.__new__();
429
430MochiKit.Base._exportSymbols(this, MochiKit.Selector);
431
diff --git a/frontend/beta/js/MochiKit/Signal.js b/frontend/beta/js/MochiKit/Signal.js
new file mode 100644
index 0000000..a11a3de
--- a/dev/null
+++ b/frontend/beta/js/MochiKit/Signal.js
@@ -0,0 +1,864 @@
1/***
2
3MochiKit.Signal 1.4
4
5See <http://mochikit.com/> for documentation, downloads, license, etc.
6
7(c) 2006 Jonathan Gardner, Beau Hartshorne, Bob Ippolito. All rights Reserved.
8
9***/
10
11if (typeof(dojo) != 'undefined') {
12 dojo.provide('MochiKit.Signal');
13 dojo.require('MochiKit.Base');
14 dojo.require('MochiKit.DOM');
15 dojo.require('MochiKit.Style');
16}
17if (typeof(JSAN) != 'undefined') {
18 JSAN.use('MochiKit.Base', []);
19 JSAN.use('MochiKit.DOM', []);
20 JSAN.use('MochiKit.Style', []);
21}
22
23try {
24 if (typeof(MochiKit.Base) == 'undefined') {
25 throw '';
26 }
27} catch (e) {
28 throw 'MochiKit.Signal depends on MochiKit.Base!';
29}
30
31try {
32 if (typeof(MochiKit.DOM) == 'undefined') {
33 throw '';
34 }
35} catch (e) {
36 throw 'MochiKit.Signal depends on MochiKit.DOM!';
37}
38
39try {
40 if (typeof(MochiKit.Style) == 'undefined') {
41 throw '';
42 }
43} catch (e) {
44 throw 'MochiKit.Signal depends on MochiKit.Style!';
45}
46
47if (typeof(MochiKit.Signal) == 'undefined') {
48 MochiKit.Signal = {};
49}
50
51MochiKit.Signal.NAME = 'MochiKit.Signal';
52MochiKit.Signal.VERSION = '1.4';
53
54MochiKit.Signal._observers = [];
55
56/** @id MochiKit.Signal.Event */
57MochiKit.Signal.Event = function (src, e) {
58 this._event = e || window.event;
59 this._src = src;
60};
61
62MochiKit.Base.update(MochiKit.Signal.Event.prototype, {
63
64 __repr__: function () {
65 var repr = MochiKit.Base.repr;
66 var str = '{event(): ' + repr(this.event()) +
67 ', src(): ' + repr(this.src()) +
68 ', type(): ' + repr(this.type()) +
69 ', target(): ' + repr(this.target());
70
71 if (this.type() &&
72 this.type().indexOf('key') === 0 ||
73 this.type().indexOf('mouse') === 0 ||
74 this.type().indexOf('click') != -1 ||
75 this.type() == 'contextmenu') {
76 str += ', modifier(): ' + '{alt: ' + repr(this.modifier().alt) +
77 ', ctrl: ' + repr(this.modifier().ctrl) +
78 ', meta: ' + repr(this.modifier().meta) +
79 ', shift: ' + repr(this.modifier().shift) +
80 ', any: ' + repr(this.modifier().any) + '}';
81 }
82
83 if (this.type() && this.type().indexOf('key') === 0) {
84 str += ', key(): {code: ' + repr(this.key().code) +
85 ', string: ' + repr(this.key().string) + '}';
86 }
87
88 if (this.type() && (
89 this.type().indexOf('mouse') === 0 ||
90 this.type().indexOf('click') != -1 ||
91 this.type() == 'contextmenu')) {
92
93 str += ', mouse(): {page: ' + repr(this.mouse().page) +
94 ', client: ' + repr(this.mouse().client);
95
96 if (this.type() != 'mousemove') {
97 str += ', button: {left: ' + repr(this.mouse().button.left) +
98 ', middle: ' + repr(this.mouse().button.middle) +
99 ', right: ' + repr(this.mouse().button.right) + '}}';
100 } else {
101 str += '}';
102 }
103 }
104 if (this.type() == 'mouseover' || this.type() == 'mouseout') {
105 str += ', relatedTarget(): ' + repr(this.relatedTarget());
106 }
107 str += '}';
108 return str;
109 },
110
111 /** @id MochiKit.Signal.Event.prototype.toString */
112 toString: function () {
113 return this.__repr__();
114 },
115
116 /** @id MochiKit.Signal.Event.prototype.src */
117 src: function () {
118 return this._src;
119 },
120
121 /** @id MochiKit.Signal.Event.prototype.event */
122 event: function () {
123 return this._event;
124 },
125
126 /** @id MochiKit.Signal.Event.prototype.type */
127 type: function () {
128 return this._event.type || undefined;
129 },
130
131 /** @id MochiKit.Signal.Event.prototype.target */
132 target: function () {
133 return this._event.target || this._event.srcElement;
134 },
135
136 _relatedTarget: null,
137 /** @id MochiKit.Signal.Event.prototype.relatedTarget */
138 relatedTarget: function () {
139 if (this._relatedTarget !== null) {
140 return this._relatedTarget;
141 }
142
143 var elem = null;
144 if (this.type() == 'mouseover') {
145 elem = (this._event.relatedTarget ||
146 this._event.fromElement);
147 } else if (this.type() == 'mouseout') {
148 elem = (this._event.relatedTarget ||
149 this._event.toElement);
150 }
151 if (elem !== null) {
152 this._relatedTarget = elem;
153 return elem;
154 }
155
156 return undefined;
157 },
158
159 _modifier: null,
160 /** @id MochiKit.Signal.Event.prototype.modifier */
161 modifier: function () {
162 if (this._modifier !== null) {
163 return this._modifier;
164 }
165 var m = {};
166 m.alt = this._event.altKey;
167 m.ctrl = this._event.ctrlKey;
168 m.meta = this._event.metaKey || false; // IE and Opera punt here
169 m.shift = this._event.shiftKey;
170 m.any = m.alt || m.ctrl || m.shift || m.meta;
171 this._modifier = m;
172 return m;
173 },
174
175 _key: null,
176 /** @id MochiKit.Signal.Event.prototype.key */
177 key: function () {
178 if (this._key !== null) {
179 return this._key;
180 }
181 var k = {};
182 if (this.type() && this.type().indexOf('key') === 0) {
183
184 /*
185
186 If you're looking for a special key, look for it in keydown or
187 keyup, but never keypress. If you're looking for a Unicode
188 chracter, look for it with keypress, but never keyup or
189 keydown.
190
191 Notes:
192
193 FF key event behavior:
194 key event charCode keyCode
195 DOWN ku,kd 0 40
196 DOWN kp 0 40
197 ESC ku,kd 0 27
198 ESC kp 0 27
199 a ku,kd 0 65
200 a kp 97 0
201 shift+a ku,kd 0 65
202 shift+a kp 65 0
203 1 ku,kd 0 49
204 1 kp 49 0
205 shift+1 ku,kd 0 0
206 shift+1 kp 33 0
207
208 IE key event behavior:
209 (IE doesn't fire keypress events for special keys.)
210 key event keyCode
211 DOWN ku,kd 40
212 DOWN kp undefined
213 ESC ku,kd 27
214 ESC kp 27
215 a ku,kd 65
216 a kp 97
217 shift+a ku,kd 65
218 shift+a kp 65
219 1 ku,kd 49
220 1 kp 49
221 shift+1 ku,kd 49
222 shift+1 kp 33
223
224 Safari key event behavior:
225 (Safari sets charCode and keyCode to something crazy for
226 special keys.)
227 key event charCode keyCode
228 DOWN ku,kd 63233 40
229 DOWN kp 63233 63233
230 ESC ku,kd 27 27
231 ESC kp 27 27
232 a ku,kd 97 65
233 a kp 97 97
234 shift+a ku,kd 65 65
235 shift+a kp 65 65
236 1 ku,kd 49 49
237 1 kp 49 49
238 shift+1 ku,kd 33 49
239 shift+1 kp 33 33
240
241 */
242
243 /* look for special keys here */
244 if (this.type() == 'keydown' || this.type() == 'keyup') {
245 k.code = this._event.keyCode;
246 k.string = (MochiKit.Signal._specialKeys[k.code] ||
247 'KEY_UNKNOWN');
248 this._key = k;
249 return k;
250
251 /* look for characters here */
252 } else if (this.type() == 'keypress') {
253
254 /*
255
256 Special key behavior:
257
258 IE: does not fire keypress events for special keys
259 FF: sets charCode to 0, and sets the correct keyCode
260 Safari: sets keyCode and charCode to something stupid
261
262 */
263
264 k.code = 0;
265 k.string = '';
266
267 if (typeof(this._event.charCode) != 'undefined' &&
268 this._event.charCode !== 0 &&
269 !MochiKit.Signal._specialMacKeys[this._event.charCode]) {
270 k.code = this._event.charCode;
271 k.string = String.fromCharCode(k.code);
272 } else if (this._event.keyCode &&
273 typeof(this._event.charCode) == 'undefined') { // IE
274 k.code = this._event.keyCode;
275 k.string = String.fromCharCode(k.code);
276 }
277
278 this._key = k;
279 return k;
280 }
281 }
282 return undefined;
283 },
284
285 _mouse: null,
286 /** @id MochiKit.Signal.Event.prototype.mouse */
287 mouse: function () {
288 if (this._mouse !== null) {
289 return this._mouse;
290 }
291
292 var m = {};
293 var e = this._event;
294
295 if (this.type() && (
296 this.type().indexOf('mouse') === 0 ||
297 this.type().indexOf('click') != -1 ||
298 this.type() == 'contextmenu')) {
299
300 m.client = new MochiKit.Style.Coordinates(0, 0);
301 if (e.clientX || e.clientY) {
302 m.client.x = (!e.clientX || e.clientX < 0) ? 0 : e.clientX;
303 m.client.y = (!e.clientY || e.clientY < 0) ? 0 : e.clientY;
304 }
305
306 m.page = new MochiKit.Style.Coordinates(0, 0);
307 if (e.pageX || e.pageY) {
308 m.page.x = (!e.pageX || e.pageX < 0) ? 0 : e.pageX;
309 m.page.y = (!e.pageY || e.pageY < 0) ? 0 : e.pageY;
310 } else {
311 /*
312
313 The IE shortcut can be off by two. We fix it. See:
314 http://msdn.microsoft.com/workshop/author/dhtml/reference/methods/getboundingclientrect.asp
315
316 This is similar to the method used in
317 MochiKit.Style.getElementPosition().
318
319 */
320 var de = MochiKit.DOM._document.documentElement;
321 var b = MochiKit.DOM._document.body;
322
323 m.page.x = e.clientX +
324 (de.scrollLeft || b.scrollLeft) -
325 (de.clientLeft || 0);
326
327 m.page.y = e.clientY +
328 (de.scrollTop || b.scrollTop) -
329 (de.clientTop || 0);
330
331 }
332 if (this.type() != 'mousemove') {
333 m.button = {};
334 m.button.left = false;
335 m.button.right = false;
336 m.button.middle = false;
337
338 /* we could check e.button, but which is more consistent */
339 if (e.which) {
340 m.button.left = (e.which == 1);
341 m.button.middle = (e.which == 2);
342 m.button.right = (e.which == 3);
343
344 /*
345
346 Mac browsers and right click:
347
348 - Safari doesn't fire any click events on a right
349 click:
350 http://bugs.webkit.org/show_bug.cgi?id=6595
351
352 - Firefox fires the event, and sets ctrlKey = true
353
354 - Opera fires the event, and sets metaKey = true
355
356 oncontextmenu is fired on right clicks between
357 browsers and across platforms.
358
359 */
360
361 } else {
362 m.button.left = !!(e.button & 1);
363 m.button.right = !!(e.button & 2);
364 m.button.middle = !!(e.button & 4);
365 }
366 }
367 this._mouse = m;
368 return m;
369 }
370 return undefined;
371 },
372
373 /** @id MochiKit.Signal.Event.prototype.stop */
374 stop: function () {
375 this.stopPropagation();
376 this.preventDefault();
377 },
378
379 /** @id MochiKit.Signal.Event.prototype.stopPropagation */
380 stopPropagation: function () {
381 if (this._event.stopPropagation) {
382 this._event.stopPropagation();
383 } else {
384 this._event.cancelBubble = true;
385 }
386 },
387
388 /** @id MochiKit.Signal.Event.prototype.preventDefault */
389 preventDefault: function () {
390 if (this._event.preventDefault) {
391 this._event.preventDefault();
392 } else if (this._confirmUnload === null) {
393 this._event.returnValue = false;
394 }
395 },
396
397 _confirmUnload: null,
398
399 /** @id MochiKit.Signal.Event.prototype.confirmUnload */
400 confirmUnload: function (msg) {
401 if (this.type() == 'beforeunload') {
402 this._confirmUnload = msg;
403 this._event.returnValue = msg;
404 }
405 }
406});
407
408/* Safari sets keyCode to these special values onkeypress. */
409MochiKit.Signal._specialMacKeys = {
410 3: 'KEY_ENTER',
411 63289: 'KEY_NUM_PAD_CLEAR',
412 63276: 'KEY_PAGE_UP',
413 63277: 'KEY_PAGE_DOWN',
414 63275: 'KEY_END',
415 63273: 'KEY_HOME',
416 63234: 'KEY_ARROW_LEFT',
417 63232: 'KEY_ARROW_UP',
418 63235: 'KEY_ARROW_RIGHT',
419 63233: 'KEY_ARROW_DOWN',
420 63302: 'KEY_INSERT',
421 63272: 'KEY_DELETE'
422};
423
424/* for KEY_F1 - KEY_F12 */
425(function () {
426 var _specialMacKeys = MochiKit.Signal._specialMacKeys;
427 for (i = 63236; i <= 63242; i++) {
428 // no F0
429 _specialMacKeys[i] = 'KEY_F' + (i - 63236 + 1);
430 }
431})();
432
433/* Standard keyboard key codes. */
434MochiKit.Signal._specialKeys = {
435 8: 'KEY_BACKSPACE',
436 9: 'KEY_TAB',
437 12: 'KEY_NUM_PAD_CLEAR', // weird, for Safari and Mac FF only
438 13: 'KEY_ENTER',
439 16: 'KEY_SHIFT',
440 17: 'KEY_CTRL',
441 18: 'KEY_ALT',
442 19: 'KEY_PAUSE',
443 20: 'KEY_CAPS_LOCK',
444 27: 'KEY_ESCAPE',
445 32: 'KEY_SPACEBAR',
446 33: 'KEY_PAGE_UP',
447 34: 'KEY_PAGE_DOWN',
448 35: 'KEY_END',
449 36: 'KEY_HOME',
450 37: 'KEY_ARROW_LEFT',
451 38: 'KEY_ARROW_UP',
452 39: 'KEY_ARROW_RIGHT',
453 40: 'KEY_ARROW_DOWN',
454 44: 'KEY_PRINT_SCREEN',
455 45: 'KEY_INSERT',
456 46: 'KEY_DELETE',
457 59: 'KEY_SEMICOLON', // weird, for Safari and IE only
458 91: 'KEY_WINDOWS_LEFT',
459 92: 'KEY_WINDOWS_RIGHT',
460 93: 'KEY_SELECT',
461 106: 'KEY_NUM_PAD_ASTERISK',
462 107: 'KEY_NUM_PAD_PLUS_SIGN',
463 109: 'KEY_NUM_PAD_HYPHEN-MINUS',
464 110: 'KEY_NUM_PAD_FULL_STOP',
465 111: 'KEY_NUM_PAD_SOLIDUS',
466 144: 'KEY_NUM_LOCK',
467 145: 'KEY_SCROLL_LOCK',
468 186: 'KEY_SEMICOLON',
469 187: 'KEY_EQUALS_SIGN',
470 188: 'KEY_COMMA',
471 189: 'KEY_HYPHEN-MINUS',
472 190: 'KEY_FULL_STOP',
473 191: 'KEY_SOLIDUS',
474 192: 'KEY_GRAVE_ACCENT',
475 219: 'KEY_LEFT_SQUARE_BRACKET',
476 220: 'KEY_REVERSE_SOLIDUS',
477 221: 'KEY_RIGHT_SQUARE_BRACKET',
478 222: 'KEY_APOSTROPHE'
479 // undefined: 'KEY_UNKNOWN'
480};
481
482(function () {
483 /* for KEY_0 - KEY_9 */
484 var _specialKeys = MochiKit.Signal._specialKeys;
485 for (var i = 48; i <= 57; i++) {
486 _specialKeys[i] = 'KEY_' + (i - 48);
487 }
488
489 /* for KEY_A - KEY_Z */
490 for (i = 65; i <= 90; i++) {
491 _specialKeys[i] = 'KEY_' + String.fromCharCode(i);
492 }
493
494 /* for KEY_NUM_PAD_0 - KEY_NUM_PAD_9 */
495 for (i = 96; i <= 105; i++) {
496 _specialKeys[i] = 'KEY_NUM_PAD_' + (i - 96);
497 }
498
499 /* for KEY_F1 - KEY_F12 */
500 for (i = 112; i <= 123; i++) {
501 // no F0
502 _specialKeys[i] = 'KEY_F' + (i - 112 + 1);
503 }
504})();
505
506MochiKit.Base.update(MochiKit.Signal, {
507
508 __repr__: function () {
509 return '[' + this.NAME + ' ' + this.VERSION + ']';
510 },
511
512 toString: function () {
513 return this.__repr__();
514 },
515
516 _unloadCache: function () {
517 var self = MochiKit.Signal;
518 var observers = self._observers;
519
520 for (var i = 0; i < observers.length; i++) {
521 self._disconnect(observers[i]);
522 }
523
524 delete self._observers;
525
526 try {
527 window.onload = undefined;
528 } catch(e) {
529 // pass
530 }
531
532 try {
533 window.onunload = undefined;
534 } catch(e) {
535 // pass
536 }
537 },
538
539 _listener: function (src, func, obj, isDOM) {
540 var self = MochiKit.Signal;
541 var E = self.Event;
542 if (!isDOM) {
543 return MochiKit.Base.bind(func, obj);
544 }
545 obj = obj || src;
546 if (typeof(func) == "string") {
547 return function (nativeEvent) {
548 obj[func].apply(obj, [new E(src, nativeEvent)]);
549 };
550 } else {
551 return function (nativeEvent) {
552 func.apply(obj, [new E(src, nativeEvent)]);
553 };
554 }
555 },
556
557 _browserAlreadyHasMouseEnterAndLeave: function () {
558 return /MSIE/.test(navigator.userAgent);
559 },
560
561 _mouseEnterListener: function (src, sig, func, obj) {
562 var E = MochiKit.Signal.Event;
563 return function (nativeEvent) {
564 var e = new E(src, nativeEvent);
565 try {
566 e.relatedTarget().nodeName;
567 } catch (err) {
568 /* probably hit a permission denied error; possibly one of
569 * firefox's screwy anonymous DIVs inside an input element.
570 * Allow this event to propogate up.
571 */
572 return;
573 }
574 e.stop();
575 if (MochiKit.DOM.isChildNode(e.relatedTarget(), src)) {
576 /* We've moved between our node and a child. Ignore. */
577 return;
578 }
579 e.type = function () { return sig; };
580 if (typeof(func) == "string") {
581 return obj[func].apply(obj, [e]);
582 } else {
583 return func.apply(obj, [e]);
584 }
585 };
586 },
587
588 _getDestPair: function (objOrFunc, funcOrStr) {
589 var obj = null;
590 var func = null;
591 if (typeof(funcOrStr) != 'undefined') {
592 obj = objOrFunc;
593 func = funcOrStr;
594 if (typeof(funcOrStr) == 'string') {
595 if (typeof(objOrFunc[funcOrStr]) != "function") {
596 throw new Error("'funcOrStr' must be a function on 'objOrFunc'");
597 }
598 } else if (typeof(funcOrStr) != 'function') {
599 throw new Error("'funcOrStr' must be a function or string");
600 }
601 } else if (typeof(objOrFunc) != "function") {
602 throw new Error("'objOrFunc' must be a function if 'funcOrStr' is not given");
603 } else {
604 func = objOrFunc;
605 }
606 return [obj, func];
607
608 },
609
610 /** @id MochiKit.Signal.connect */
611 connect: function (src, sig, objOrFunc/* optional */, funcOrStr) {
612 src = MochiKit.DOM.getElement(src);
613 var self = MochiKit.Signal;
614
615 if (typeof(sig) != 'string') {
616 throw new Error("'sig' must be a string");
617 }
618
619 var destPair = self._getDestPair(objOrFunc, funcOrStr);
620 var obj = destPair[0];
621 var func = destPair[1];
622 if (typeof(obj) == 'undefined' || obj === null) {
623 obj = src;
624 }
625
626 var isDOM = !!(src.addEventListener || src.attachEvent);
627 if (isDOM && (sig === "onmouseenter" || sig === "onmouseleave")
628 && !self._browserAlreadyHasMouseEnterAndLeave()) {
629 var listener = self._mouseEnterListener(src, sig.substr(2), func, obj);
630 if (sig === "onmouseenter") {
631 sig = "onmouseover";
632 } else {
633 sig = "onmouseout";
634 }
635 } else {
636 var listener = self._listener(src, func, obj, isDOM);
637 }
638
639 if (src.addEventListener) {
640 src.addEventListener(sig.substr(2), listener, false);
641 } else if (src.attachEvent) {
642 src.attachEvent(sig, listener); // useCapture unsupported
643 }
644
645 var ident = [src, sig, listener, isDOM, objOrFunc, funcOrStr, true];
646 self._observers.push(ident);
647
648
649 if (!isDOM && typeof(src.__connect__) == 'function') {
650 var args = MochiKit.Base.extend([ident], arguments, 1);
651 src.__connect__.apply(src, args);
652 }
653
654
655 return ident;
656 },
657
658 _disconnect: function (ident) {
659 // already disconnected
660 if (!ident[6]) { return; }
661 ident[6] = false;
662 // check isDOM
663 if (!ident[3]) { return; }
664 var src = ident[0];
665 var sig = ident[1];
666 var listener = ident[2];
667 if (src.removeEventListener) {
668 src.removeEventListener(sig.substr(2), listener, false);
669 } else if (src.detachEvent) {
670 src.detachEvent(sig, listener); // useCapture unsupported
671 } else {
672 throw new Error("'src' must be a DOM element");
673 }
674 },
675
676 /** @id MochiKit.Signal.disconnect */
677 disconnect: function (ident) {
678 var self = MochiKit.Signal;
679 var observers = self._observers;
680 var m = MochiKit.Base;
681 if (arguments.length > 1) {
682 // compatibility API
683 var src = MochiKit.DOM.getElement(arguments[0]);
684 var sig = arguments[1];
685 var obj = arguments[2];
686 var func = arguments[3];
687 for (var i = observers.length - 1; i >= 0; i--) {
688 var o = observers[i];
689 if (o[0] === src && o[1] === sig && o[4] === obj && o[5] === func) {
690 self._disconnect(o);
691 if (!self._lock) {
692 observers.splice(i, 1);
693 } else {
694 self._dirty = true;
695 }
696 return true;
697 }
698 }
699 } else {
700 var idx = m.findIdentical(observers, ident);
701 if (idx >= 0) {
702 self._disconnect(ident);
703 if (!self._lock) {
704 observers.splice(idx, 1);
705 } else {
706 self._dirty = true;
707 }
708 return true;
709 }
710 }
711 return false;
712 },
713
714 /** @id MochiKit.Signal.disconnectAllTo */
715 disconnectAllTo: function (objOrFunc, /* optional */funcOrStr) {
716 var self = MochiKit.Signal;
717 var observers = self._observers;
718 var disconnect = self._disconnect;
719 var locked = self._lock;
720 var dirty = self._dirty;
721 if (typeof(funcOrStr) === 'undefined') {
722 funcOrStr = null;
723 }
724 for (var i = observers.length - 1; i >= 0; i--) {
725 var ident = observers[i];
726 if (ident[4] === objOrFunc &&
727 (funcOrStr === null || ident[5] === funcOrStr)) {
728 disconnect(ident);
729 if (locked) {
730 dirty = true;
731 } else {
732 observers.splice(i, 1);
733 }
734 }
735 }
736 self._dirty = dirty;
737 },
738
739 /** @id MochiKit.Signal.disconnectAll */
740 disconnectAll: function (src/* optional */, sig) {
741 src = MochiKit.DOM.getElement(src);
742 var m = MochiKit.Base;
743 var signals = m.flattenArguments(m.extend(null, arguments, 1));
744 var self = MochiKit.Signal;
745 var disconnect = self._disconnect;
746 var observers = self._observers;
747 var i, ident;
748 var locked = self._lock;
749 var dirty = self._dirty;
750 if (signals.length === 0) {
751 // disconnect all
752 for (i = observers.length - 1; i >= 0; i--) {
753 ident = observers[i];
754 if (ident[0] === src) {
755 disconnect(ident);
756 if (!locked) {
757 observers.splice(i, 1);
758 } else {
759 dirty = true;
760 }
761 }
762 }
763 } else {
764 var sigs = {};
765 for (i = 0; i < signals.length; i++) {
766 sigs[signals[i]] = true;
767 }
768 for (i = observers.length - 1; i >= 0; i--) {
769 ident = observers[i];
770 if (ident[0] === src && ident[1] in sigs) {
771 disconnect(ident);
772 if (!locked) {
773 observers.splice(i, 1);
774 } else {
775 dirty = true;
776 }
777 }
778 }
779 }
780 self._dirty = dirty;
781 },
782
783 /** @id MochiKit.Signal.signal */
784 signal: function (src, sig) {
785 var self = MochiKit.Signal;
786 var observers = self._observers;
787 src = MochiKit.DOM.getElement(src);
788 var args = MochiKit.Base.extend(null, arguments, 2);
789 var errors = [];
790 self._lock = true;
791 for (var i = 0; i < observers.length; i++) {
792 var ident = observers[i];
793 if (ident[0] === src && ident[1] === sig) {
794 try {
795 ident[2].apply(src, args);
796 } catch (e) {
797 errors.push(e);
798 }
799 }
800 }
801 self._lock = false;
802 if (self._dirty) {
803 self._dirty = false;
804 for (var i = observers.length - 1; i >= 0; i--) {
805 if (!observers[i][6]) {
806 observers.splice(i, 1);
807 }
808 }
809 }
810 if (errors.length == 1) {
811 throw errors[0];
812 } else if (errors.length > 1) {
813 var e = new Error("Multiple errors thrown in handling 'sig', see errors property");
814 e.errors = errors;
815 throw e;
816 }
817 }
818
819});
820
821MochiKit.Signal.EXPORT_OK = [];
822
823MochiKit.Signal.EXPORT = [
824 'connect',
825 'disconnect',
826 'signal',
827 'disconnectAll',
828 'disconnectAllTo'
829];
830
831MochiKit.Signal.__new__ = function (win) {
832 var m = MochiKit.Base;
833 this._document = document;
834 this._window = win;
835 this._lock = false;
836 this._dirty = false;
837
838 try {
839 this.connect(window, 'onunload', this._unloadCache);
840 } catch (e) {
841 // pass: might not be a browser
842 }
843
844 this.EXPORT_TAGS = {
845 ':common': this.EXPORT,
846 ':all': m.concat(this.EXPORT, this.EXPORT_OK)
847 };
848
849 m.nameFunctions(this);
850};
851
852MochiKit.Signal.__new__(this);
853
854//
855// XXX: Internet Explorer blows
856//
857if (MochiKit.__export__) {
858 connect = MochiKit.Signal.connect;
859 disconnect = MochiKit.Signal.disconnect;
860 disconnectAll = MochiKit.Signal.disconnectAll;
861 signal = MochiKit.Signal.signal;
862}
863
864MochiKit.Base._exportSymbols(this, MochiKit.Signal);
diff --git a/frontend/beta/js/MochiKit/Sortable.js b/frontend/beta/js/MochiKit/Sortable.js
new file mode 100644
index 0000000..8976ec0
--- a/dev/null
+++ b/frontend/beta/js/MochiKit/Sortable.js
@@ -0,0 +1,589 @@
1/***
2Copyright (c) 2005 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
3 Mochi-ized By Thomas Herve (_firstname_@nimail.org)
4
5See scriptaculous.js for full license.
6
7***/
8
9if (typeof(dojo) != 'undefined') {
10 dojo.provide('MochiKit.Sortable');
11 dojo.require('MochiKit.Base');
12 dojo.require('MochiKit.DOM');
13 dojo.require('MochiKit.Iter');
14}
15
16if (typeof(JSAN) != 'undefined') {
17 JSAN.use("MochiKit.Base", []);
18 JSAN.use("MochiKit.DOM", []);
19 JSAN.use("MochiKit.Iter", []);
20}
21
22try {
23 if (typeof(MochiKit.Base) == 'undefined' ||
24 typeof(MochiKit.DOM) == 'undefined' ||
25 typeof(MochiKit.Iter) == 'undefined') {
26 throw "";
27 }
28} catch (e) {
29 throw "MochiKit.DragAndDrop depends on MochiKit.Base, MochiKit.DOM and MochiKit.Iter!";
30}
31
32if (typeof(MochiKit.Sortable) == 'undefined') {
33 MochiKit.Sortable = {};
34}
35
36MochiKit.Sortable.NAME = 'MochiKit.Sortable';
37MochiKit.Sortable.VERSION = '1.4';
38
39MochiKit.Sortable.__repr__ = function () {
40 return '[' + this.NAME + ' ' + this.VERSION + ']';
41};
42
43MochiKit.Sortable.toString = function () {
44 return this.__repr__();
45};
46
47MochiKit.Sortable.EXPORT = [
48];
49
50MochiKit.Sortable.EXPORT_OK = [
51];
52
53MochiKit.Base.update(MochiKit.Sortable, {
54 /***
55
56 Manage sortables. Mainly use the create function to add a sortable.
57
58 ***/
59 sortables: {},
60
61 _findRootElement: function (element) {
62 while (element.tagName.toUpperCase() != "BODY") {
63 if (element.id && MochiKit.Sortable.sortables[element.id]) {
64 return element;
65 }
66 element = element.parentNode;
67 }
68 },
69
70 /** @id MochiKit.Sortable.options */
71 options: function (element) {
72 element = MochiKit.Sortable._findRootElement(MochiKit.DOM.getElement(element));
73 if (!element) {
74 return;
75 }
76 return MochiKit.Sortable.sortables[element.id];
77 },
78
79 /** @id MochiKit.Sortable.destroy */
80 destroy: function (element){
81 var s = MochiKit.Sortable.options(element);
82 var b = MochiKit.Base;
83 var d = MochiKit.DragAndDrop;
84
85 if (s) {
86 MochiKit.Signal.disconnect(s.startHandle);
87 MochiKit.Signal.disconnect(s.endHandle);
88 b.map(function (dr) {
89 d.Droppables.remove(dr);
90 }, s.droppables);
91 b.map(function (dr) {
92 dr.destroy();
93 }, s.draggables);
94
95 delete MochiKit.Sortable.sortables[s.element.id];
96 }
97 },
98
99 /** @id MochiKit.Sortable.create */
100 create: function (element, options) {
101 element = MochiKit.DOM.getElement(element);
102 var self = MochiKit.Sortable;
103
104 /** @id MochiKit.Sortable.options */
105 options = MochiKit.Base.update({
106
107 /** @id MochiKit.Sortable.element */
108 element: element,
109
110 /** @id MochiKit.Sortable.tag */
111 tag: 'li', // assumes li children, override with tag: 'tagname'
112
113 /** @id MochiKit.Sortable.dropOnEmpty */
114 dropOnEmpty: false,
115
116 /** @id MochiKit.Sortable.tree */
117 tree: false,
118
119 /** @id MochiKit.Sortable.treeTag */
120 treeTag: 'ul',
121
122 /** @id MochiKit.Sortable.overlap */
123 overlap: 'vertical', // one of 'vertical', 'horizontal'
124
125 /** @id MochiKit.Sortable.constraint */
126 constraint: 'vertical', // one of 'vertical', 'horizontal', false
127 // also takes array of elements (or ids); or false
128
129 /** @id MochiKit.Sortable.containment */
130 containment: [element],
131
132 /** @id MochiKit.Sortable.handle */
133 handle: false, // or a CSS class
134
135 /** @id MochiKit.Sortable.only */
136 only: false,
137
138 /** @id MochiKit.Sortable.hoverclass */
139 hoverclass: null,
140
141 /** @id MochiKit.Sortable.ghosting */
142 ghosting: false,
143
144 /** @id MochiKit.Sortable.scroll */
145 scroll: false,
146
147 /** @id MochiKit.Sortable.scrollSensitivity */
148 scrollSensitivity: 20,
149
150 /** @id MochiKit.Sortable.scrollSpeed */
151 scrollSpeed: 15,
152
153 /** @id MochiKit.Sortable.format */
154 format: /^[^_]*_(.*)$/,
155
156 /** @id MochiKit.Sortable.onChange */
157 onChange: MochiKit.Base.noop,
158
159 /** @id MochiKit.Sortable.onUpdate */
160 onUpdate: MochiKit.Base.noop,
161
162 /** @id MochiKit.Sortable.accept */
163 accept: null
164 }, options);
165
166 // clear any old sortable with same element
167 self.destroy(element);
168
169 // build options for the draggables
170 var options_for_draggable = {
171 revert: true,
172 ghosting: options.ghosting,
173 scroll: options.scroll,
174 scrollSensitivity: options.scrollSensitivity,
175 scrollSpeed: options.scrollSpeed,
176 constraint: options.constraint,
177 handle: options.handle
178 };
179
180 if (options.starteffect) {
181 options_for_draggable.starteffect = options.starteffect;
182 }
183
184 if (options.reverteffect) {
185 options_for_draggable.reverteffect = options.reverteffect;
186 } else if (options.ghosting) {
187 options_for_draggable.reverteffect = function (innerelement) {
188 innerelement.style.top = 0;
189 innerelement.style.left = 0;
190 };
191 }
192
193 if (options.endeffect) {
194 options_for_draggable.endeffect = options.endeffect;
195 }
196
197 if (options.zindex) {
198 options_for_draggable.zindex = options.zindex;
199 }
200
201 // build options for the droppables
202 var options_for_droppable = {
203 overlap: options.overlap,
204 containment: options.containment,
205 hoverclass: options.hoverclass,
206 onhover: self.onHover,
207 tree: options.tree,
208 accept: options.accept
209 }
210
211 var options_for_tree = {
212 onhover: self.onEmptyHover,
213 overlap: options.overlap,
214 containment: options.containment,
215 hoverclass: options.hoverclass,
216 accept: options.accept
217 }
218
219 // fix for gecko engine
220 MochiKit.DOM.removeEmptyTextNodes(element);
221
222 options.draggables = [];
223 options.droppables = [];
224
225 // drop on empty handling
226 if (options.dropOnEmpty || options.tree) {
227 new MochiKit.DragAndDrop.Droppable(element, options_for_tree);
228 options.droppables.push(element);
229 }
230 MochiKit.Base.map(function (e) {
231 // handles are per-draggable
232 var handle = options.handle ?
233 MochiKit.DOM.getFirstElementByTagAndClassName(null,
234 options.handle, e) : e;
235 options.draggables.push(
236 new MochiKit.DragAndDrop.Draggable(e,
237 MochiKit.Base.update(options_for_draggable,
238 {handle: handle})));
239 new MochiKit.DragAndDrop.Droppable(e, options_for_droppable);
240 if (options.tree) {
241 e.treeNode = element;
242 }
243 options.droppables.push(e);
244 }, (self.findElements(element, options) || []));
245
246 if (options.tree) {
247 MochiKit.Base.map(function (e) {
248 new MochiKit.DragAndDrop.Droppable(e, options_for_tree);
249 e.treeNode = element;
250 options.droppables.push(e);
251 }, (self.findTreeElements(element, options) || []));
252 }
253
254 // keep reference
255 self.sortables[element.id] = options;
256
257 options.lastValue = self.serialize(element);
258 options.startHandle = MochiKit.Signal.connect(MochiKit.DragAndDrop.Draggables, 'start',
259 MochiKit.Base.partial(self.onStart, element));
260 options.endHandle = MochiKit.Signal.connect(MochiKit.DragAndDrop.Draggables, 'end',
261 MochiKit.Base.partial(self.onEnd, element));
262 },
263
264 /** @id MochiKit.Sortable.onStart */
265 onStart: function (element, draggable) {
266 var self = MochiKit.Sortable;
267 var options = self.options(element);
268 options.lastValue = self.serialize(options.element);
269 },
270
271 /** @id MochiKit.Sortable.onEnd */
272 onEnd: function (element, draggable) {
273 var self = MochiKit.Sortable;
274 self.unmark();
275 var options = self.options(element);
276 if (options.lastValue != self.serialize(options.element)) {
277 options.onUpdate(options.element);
278 }
279 },
280
281 // return all suitable-for-sortable elements in a guaranteed order
282
283 /** @id MochiKit.Sortable.findElements */
284 findElements: function (element, options) {
285 return MochiKit.Sortable.findChildren(
286 element, options.only, options.tree ? true : false, options.tag);
287 },
288
289 /** @id MochiKit.Sortable.findTreeElements */
290 findTreeElements: function (element, options) {
291 return MochiKit.Sortable.findChildren(
292 element, options.only, options.tree ? true : false, options.treeTag);
293 },
294
295 /** @id MochiKit.Sortable.findChildren */
296 findChildren: function (element, only, recursive, tagName) {
297 if (!element.hasChildNodes()) {
298 return null;
299 }
300 tagName = tagName.toUpperCase();
301 if (only) {
302 only = MochiKit.Base.flattenArray([only]);
303 }
304 var elements = [];
305 MochiKit.Base.map(function (e) {
306 if (e.tagName &&
307 e.tagName.toUpperCase() == tagName &&
308 (!only ||
309 MochiKit.Iter.some(only, function (c) {
310 return MochiKit.DOM.hasElementClass(e, c);
311 }))) {
312 elements.push(e);
313 }
314 if (recursive) {
315 var grandchildren = MochiKit.Sortable.findChildren(e, only, recursive, tagName);
316 if (grandchildren && grandchildren.length > 0) {
317 elements = elements.concat(grandchildren);
318 }
319 }
320 }, element.childNodes);
321 return elements;
322 },
323
324 /** @id MochiKit.Sortable.onHover */
325 onHover: function (element, dropon, overlap) {
326 if (MochiKit.DOM.isParent(dropon, element)) {
327 return;
328 }
329 var self = MochiKit.Sortable;
330
331 if (overlap > .33 && overlap < .66 && self.options(dropon).tree) {
332 return;
333 } else if (overlap > 0.5) {
334 self.mark(dropon, 'before');
335 if (dropon.previousSibling != element) {
336 var oldParentNode = element.parentNode;
337 element.style.visibility = 'hidden'; // fix gecko rendering
338 dropon.parentNode.insertBefore(element, dropon);
339 if (dropon.parentNode != oldParentNode) {
340 self.options(oldParentNode).onChange(element);
341 }
342 self.options(dropon.parentNode).onChange(element);
343 }
344 } else {
345 self.mark(dropon, 'after');
346 var nextElement = dropon.nextSibling || null;
347 if (nextElement != element) {
348 var oldParentNode = element.parentNode;
349 element.style.visibility = 'hidden'; // fix gecko rendering
350 dropon.parentNode.insertBefore(element, nextElement);
351 if (dropon.parentNode != oldParentNode) {
352 self.options(oldParentNode).onChange(element);
353 }
354 self.options(dropon.parentNode).onChange(element);
355 }
356 }
357 },
358
359 _offsetSize: function (element, type) {
360 if (type == 'vertical' || type == 'height') {
361 return element.offsetHeight;
362 } else {
363 return element.offsetWidth;
364 }
365 },
366
367 /** @id MochiKit.Sortable.onEmptyHover */
368 onEmptyHover: function (element, dropon, overlap) {
369 var oldParentNode = element.parentNode;
370 var self = MochiKit.Sortable;
371 var droponOptions = self.options(dropon);
372
373 if (!MochiKit.DOM.isParent(dropon, element)) {
374 var index;
375
376 var children = self.findElements(dropon, {tag: droponOptions.tag,
377 only: droponOptions.only});
378 var child = null;
379
380 if (children) {
381 var offset = self._offsetSize(dropon, droponOptions.overlap) * (1.0 - overlap);
382
383 for (index = 0; index < children.length; index += 1) {
384 if (offset - self._offsetSize(children[index], droponOptions.overlap) >= 0) {
385 offset -= self._offsetSize(children[index], droponOptions.overlap);
386 } else if (offset - (self._offsetSize (children[index], droponOptions.overlap) / 2) >= 0) {
387 child = index + 1 < children.length ? children[index + 1] : null;
388 break;
389 } else {
390 child = children[index];
391 break;
392 }
393 }
394 }
395
396 dropon.insertBefore(element, child);
397
398 self.options(oldParentNode).onChange(element);
399 droponOptions.onChange(element);
400 }
401 },
402
403 /** @id MochiKit.Sortable.unmark */
404 unmark: function () {
405 var m = MochiKit.Sortable._marker;
406 if (m) {
407 MochiKit.Style.hideElement(m);
408 }
409 },
410
411 /** @id MochiKit.Sortable.mark */
412 mark: function (dropon, position) {
413 // mark on ghosting only
414 var d = MochiKit.DOM;
415 var self = MochiKit.Sortable;
416 var sortable = self.options(dropon.parentNode);
417 if (sortable && !sortable.ghosting) {
418 return;
419 }
420
421 if (!self._marker) {
422 self._marker = d.getElement('dropmarker') ||
423 document.createElement('DIV');
424 MochiKit.Style.hideElement(self._marker);
425 d.addElementClass(self._marker, 'dropmarker');
426 self._marker.style.position = 'absolute';
427 document.getElementsByTagName('body').item(0).appendChild(self._marker);
428 }
429 var offsets = MochiKit.Position.cumulativeOffset(dropon);
430 self._marker.style.left = offsets.x + 'px';
431 self._marker.style.top = offsets.y + 'px';
432
433 if (position == 'after') {
434 if (sortable.overlap == 'horizontal') {
435 self._marker.style.left = (offsets.x + dropon.clientWidth) + 'px';
436 } else {
437 self._marker.style.top = (offsets.y + dropon.clientHeight) + 'px';
438 }
439 }
440 MochiKit.Style.showElement(self._marker);
441 },
442
443 _tree: function (element, options, parent) {
444 var self = MochiKit.Sortable;
445 var children = self.findElements(element, options) || [];
446
447 for (var i = 0; i < children.length; ++i) {
448 var match = children[i].id.match(options.format);
449
450 if (!match) {
451 continue;
452 }
453
454 var child = {
455 id: encodeURIComponent(match ? match[1] : null),
456 element: element,
457 parent: parent,
458 children: [],
459 position: parent.children.length,
460 container: self._findChildrenElement(children[i], options.treeTag.toUpperCase())
461 }
462
463 /* Get the element containing the children and recurse over it */
464 if (child.container) {
465 self._tree(child.container, options, child)
466 }
467
468 parent.children.push (child);
469 }
470
471 return parent;
472 },
473
474 /* Finds the first element of the given tag type within a parent element.
475 Used for finding the first LI[ST] within a L[IST]I[TEM].*/
476 _findChildrenElement: function (element, containerTag) {
477 if (element && element.hasChildNodes) {
478 containerTag = containerTag.toUpperCase();
479 for (var i = 0; i < element.childNodes.length; ++i) {
480 if (element.childNodes[i].tagName.toUpperCase() == containerTag) {
481 return element.childNodes[i];
482 }
483 }
484 }
485 return null;
486 },
487
488 /** @id MochiKit.Sortable.tree */
489 tree: function (element, options) {
490 element = MochiKit.DOM.getElement(element);
491 var sortableOptions = MochiKit.Sortable.options(element);
492 options = MochiKit.Base.update({
493 tag: sortableOptions.tag,
494 treeTag: sortableOptions.treeTag,
495 only: sortableOptions.only,
496 name: element.id,
497 format: sortableOptions.format
498 }, options || {});
499
500 var root = {
501 id: null,
502 parent: null,
503 children: new Array,
504 container: element,
505 position: 0
506 }
507
508 return MochiKit.Sortable._tree(element, options, root);
509 },
510
511 /**
512 * Specifies the sequence for the Sortable.
513 * @param {Node} element Element to use as the Sortable.
514 * @param {Object} newSequence New sequence to use.
515 * @param {Object} options Options to use fro the Sortable.
516 */
517 setSequence: function (element, newSequence, options) {
518 var self = MochiKit.Sortable;
519 var b = MochiKit.Base;
520 element = MochiKit.DOM.getElement(element);
521 options = b.update(self.options(element), options || {});
522
523 var nodeMap = {};
524 b.map(function (n) {
525 var m = n.id.match(options.format);
526 if (m) {
527 nodeMap[m[1]] = [n, n.parentNode];
528 }
529 n.parentNode.removeChild(n);
530 }, self.findElements(element, options));
531
532 b.map(function (ident) {
533 var n = nodeMap[ident];
534 if (n) {
535 n[1].appendChild(n[0]);
536 delete nodeMap[ident];
537 }
538 }, newSequence);
539 },
540
541 /* Construct a [i] index for a particular node */
542 _constructIndex: function (node) {
543 var index = '';
544 do {
545 if (node.id) {
546 index = '[' + node.position + ']' + index;
547 }
548 } while ((node = node.parent) != null);
549 return index;
550 },
551
552 /** @id MochiKit.Sortable.sequence */
553 sequence: function (element, options) {
554 element = MochiKit.DOM.getElement(element);
555 var self = MochiKit.Sortable;
556 var options = MochiKit.Base.update(self.options(element), options || {});
557
558 return MochiKit.Base.map(function (item) {
559 return item.id.match(options.format) ? item.id.match(options.format)[1] : '';
560 }, MochiKit.DOM.getElement(self.findElements(element, options) || []));
561 },
562
563 /**
564 * Serializes the content of a Sortable. Useful to send this content through a XMLHTTPRequest.
565 * These options override the Sortable options for the serialization only.
566 * @param {Node} element Element to serialize.
567 * @param {Object} options Serialization options.
568 */
569 serialize: function (element, options) {
570 element = MochiKit.DOM.getElement(element);
571 var self = MochiKit.Sortable;
572 options = MochiKit.Base.update(self.options(element), options || {});
573 var name = encodeURIComponent(options.name || element.id);
574
575 if (options.tree) {
576 return MochiKit.Base.flattenArray(MochiKit.Base.map(function (item) {
577 return [name + self._constructIndex(item) + "[id]=" +
578 encodeURIComponent(item.id)].concat(item.children.map(arguments.callee));
579 }, self.tree(element, options).children)).join('&');
580 } else {
581 return MochiKit.Base.map(function (item) {
582 return name + "[]=" + encodeURIComponent(item);
583 }, self.sequence(element, options)).join('&');
584 }
585 }
586});
587
588// trunk compatibility
589MochiKit.Sortable.Sortable = MochiKit.Sortable;
diff --git a/frontend/beta/js/MochiKit/Style.js b/frontend/beta/js/MochiKit/Style.js
new file mode 100644
index 0000000..6fdfbfb
--- a/dev/null
+++ b/frontend/beta/js/MochiKit/Style.js
@@ -0,0 +1,444 @@
1/***
2
3MochiKit.Style 1.4
4
5See <http://mochikit.com/> for documentation, downloads, license, etc.
6
7(c) 2005-2006 Bob Ippolito, Beau Hartshorne. All rights Reserved.
8
9***/
10
11if (typeof(dojo) != 'undefined') {
12 dojo.provide('MochiKit.Style');
13 dojo.require('MochiKit.Base');
14 dojo.require('MochiKit.DOM');
15}
16if (typeof(JSAN) != 'undefined') {
17 JSAN.use('MochiKit.Base', []);
18}
19
20try {
21 if (typeof(MochiKit.Base) == 'undefined') {
22 throw '';
23 }
24} catch (e) {
25 throw 'MochiKit.Style depends on MochiKit.Base!';
26}
27
28try {
29 if (typeof(MochiKit.DOM) == 'undefined') {
30 throw '';
31 }
32} catch (e) {
33 throw 'MochiKit.Style depends on MochiKit.DOM!';
34}
35
36
37if (typeof(MochiKit.Style) == 'undefined') {
38 MochiKit.Style = {};
39}
40
41MochiKit.Style.NAME = 'MochiKit.Style';
42MochiKit.Style.VERSION = '1.4';
43MochiKit.Style.__repr__ = function () {
44 return '[' + this.NAME + ' ' + this.VERSION + ']';
45};
46MochiKit.Style.toString = function () {
47 return this.__repr__();
48};
49
50MochiKit.Style.EXPORT_OK = [];
51
52MochiKit.Style.EXPORT = [
53 'setStyle',
54 'setOpacity',
55 'getStyle',
56 'getElementDimensions',
57 'elementDimensions', // deprecated
58 'setElementDimensions',
59 'getElementPosition',
60 'elementPosition', // deprecated
61 'setElementPosition',
62 'setDisplayForElement',
63 'hideElement',
64 'showElement',
65 'getViewportDimensions',
66 'getViewportPosition',
67 'Dimensions',
68 'Coordinates'
69];
70
71
72/*
73
74 Dimensions
75
76*/
77/** @id MochiKit.Style.Dimensions */
78MochiKit.Style.Dimensions = function (w, h) {
79 this.w = w;
80 this.h = h;
81};
82
83MochiKit.Style.Dimensions.prototype.__repr__ = function () {
84 var repr = MochiKit.Base.repr;
85 return '{w: ' + repr(this.w) + ', h: ' + repr(this.h) + '}';
86};
87
88MochiKit.Style.Dimensions.prototype.toString = function () {
89 return this.__repr__();
90};
91
92
93/*
94
95 Coordinates
96
97*/
98/** @id MochiKit.Style.Coordinates */
99MochiKit.Style.Coordinates = function (x, y) {
100 this.x = x;
101 this.y = y;
102};
103
104MochiKit.Style.Coordinates.prototype.__repr__ = function () {
105 var repr = MochiKit.Base.repr;
106 return '{x: ' + repr(this.x) + ', y: ' + repr(this.y) + '}';
107};
108
109MochiKit.Style.Coordinates.prototype.toString = function () {
110 return this.__repr__();
111};
112
113
114MochiKit.Base.update(MochiKit.Style, {
115
116 /** @id MochiKit.Style.getStyle */
117 getStyle: function (elem, cssProperty) {
118 var dom = MochiKit.DOM;
119 var d = dom._document;
120
121 elem = dom.getElement(elem);
122 cssProperty = MochiKit.Base.camelize(cssProperty);
123
124 if (!elem || elem == d) {
125 return undefined;
126 }
127 if (cssProperty == 'opacity' && elem.filters) {
128 var opacity = (MochiKit.Style.getStyle(elem, 'filter') || '').match(/alpha\(opacity=(.*)\)/);
129 if (opacity && opacity[1]) {
130 return parseFloat(opacity[1]) / 100;
131 }
132 return 1.0;
133 }
134 var value = elem.style ? elem.style[cssProperty] : null;
135 if (!value) {
136 if (d.defaultView && d.defaultView.getComputedStyle) {
137 var css = d.defaultView.getComputedStyle(elem, null);
138 cssProperty = cssProperty.replace(/([A-Z])/g, '-$1'
139 ).toLowerCase(); // from dojo.style.toSelectorCase
140 value = css ? css.getPropertyValue(cssProperty) : null;
141 } else if (elem.currentStyle) {
142 value = elem.currentStyle[cssProperty];
143 }
144 }
145 if (cssProperty == 'opacity') {
146 value = parseFloat(value);
147 }
148
149 if (/Opera/.test(navigator.userAgent) && (MochiKit.Base.find(['left', 'top', 'right', 'bottom'], cssProperty) != -1)) {
150 if (MochiKit.Style.getStyle(elem, 'position') == 'static') {
151 value = 'auto';
152 }
153 }
154
155 return value == 'auto' ? null : value;
156 },
157
158 /** @id MochiKit.Style.setStyle */
159 setStyle: function (elem, style) {
160 elem = MochiKit.DOM.getElement(elem);
161 for (name in style) {
162 if (name == 'opacity') {
163 MochiKit.Style.setOpacity(elem, style[name]);
164 } else {
165 elem.style[MochiKit.Base.camelize(name)] = style[name];
166 }
167 }
168 },
169
170 /** @id MochiKit.Style.setOpacity */
171 setOpacity: function (elem, o) {
172 elem = MochiKit.DOM.getElement(elem);
173 var self = MochiKit.Style;
174 if (o == 1) {
175 var toSet = /Gecko/.test(navigator.userAgent) && !(/Konqueror|AppleWebKit|KHTML/.test(navigator.userAgent));
176 elem.style["opacity"] = toSet ? 0.999999 : 1.0;
177 if (/MSIE/.test(navigator.userAgent)) {
178 elem.style['filter'] =
179 self.getStyle(elem, 'filter').replace(/alpha\([^\)]*\)/gi, '');
180 }
181 } else {
182 if (o < 0.00001) {
183 o = 0;
184 }
185 elem.style["opacity"] = o;
186 if (/MSIE/.test(navigator.userAgent)) {
187 elem.style['filter'] =
188 self.getStyle(elem, 'filter').replace(/alpha\([^\)]*\)/gi, '') + 'alpha(opacity=' + o * 100 + ')';
189 }
190 }
191 },
192
193 /*
194
195 getElementPosition is adapted from YAHOO.util.Dom.getXY v0.9.0.
196 Copyright: Copyright (c) 2006, Yahoo! Inc. All rights reserved.
197 License: BSD, http://developer.yahoo.net/yui/license.txt
198
199 */
200
201 /** @id MochiKit.Style.getElementPosition */
202 getElementPosition: function (elem, /* optional */relativeTo) {
203 var self = MochiKit.Style;
204 var dom = MochiKit.DOM;
205 elem = dom.getElement(elem);
206
207 if (!elem ||
208 (!(elem.x && elem.y) &&
209 (!elem.parentNode === null ||
210 self.getStyle(elem, 'display') == 'none'))) {
211 return undefined;
212 }
213
214 var c = new self.Coordinates(0, 0);
215 var box = null;
216 var parent = null;
217
218 var d = MochiKit.DOM._document;
219 var de = d.documentElement;
220 var b = d.body;
221
222 if (!elem.parentNode && elem.x && elem.y) {
223 /* it's just a MochiKit.Style.Coordinates object */
224 c.x += elem.x || 0;
225 c.y += elem.y || 0;
226 } else if (elem.getBoundingClientRect) { // IE shortcut
227 /*
228
229 The IE shortcut can be off by two. We fix it. See:
230 http://msdn.microsoft.com/workshop/author/dhtml/reference/methods/getboundingclientrect.asp
231
232 This is similar to the method used in
233 MochiKit.Signal.Event.mouse().
234
235 */
236 box = elem.getBoundingClientRect();
237
238 c.x += box.left +
239 (de.scrollLeft || b.scrollLeft) -
240 (de.clientLeft || 0);
241
242 c.y += box.top +
243 (de.scrollTop || b.scrollTop) -
244 (de.clientTop || 0);
245
246 } else if (elem.offsetParent) {
247 c.x += elem.offsetLeft;
248 c.y += elem.offsetTop;
249 parent = elem.offsetParent;
250
251 if (parent != elem) {
252 while (parent) {
253 c.x += parent.offsetLeft;
254 c.y += parent.offsetTop;
255 parent = parent.offsetParent;
256 }
257 }
258
259 /*
260
261 Opera < 9 and old Safari (absolute) incorrectly account for
262 body offsetTop and offsetLeft.
263
264 */
265 var ua = navigator.userAgent.toLowerCase();
266 if ((typeof(opera) != 'undefined' &&
267 parseFloat(opera.version()) < 9) ||
268 (ua.indexOf('AppleWebKit') != -1 &&
269 self.getStyle(elem, 'position') == 'absolute')) {
270
271 c.x -= b.offsetLeft;
272 c.y -= b.offsetTop;
273
274 }
275 }
276
277 if (typeof(relativeTo) != 'undefined') {
278 relativeTo = arguments.callee(relativeTo);
279 if (relativeTo) {
280 c.x -= (relativeTo.x || 0);
281 c.y -= (relativeTo.y || 0);
282 }
283 }
284
285 if (elem.parentNode) {
286 parent = elem.parentNode;
287 } else {
288 parent = null;
289 }
290
291 while (parent) {
292 var tagName = parent.tagName.toUpperCase();
293 if (tagName === 'BODY' || tagName === 'HTML') {
294 break;
295 }
296 var disp = self.getStyle(parent, 'display');
297 // Handle strange Opera bug for some display
298 if (disp != 'inline' && disp != 'table-row') {
299 c.x -= parent.scrollLeft;
300 c.y -= parent.scrollTop;
301 }
302 if (parent.parentNode) {
303 parent = parent.parentNode;
304 } else {
305 parent = null;
306 }
307 }
308
309 return c;
310 },
311
312 /** @id MochiKit.Style.setElementPosition */
313 setElementPosition: function (elem, newPos/* optional */, units) {
314 elem = MochiKit.DOM.getElement(elem);
315 if (typeof(units) == 'undefined') {
316 units = 'px';
317 }
318 var newStyle = {};
319 var isUndefNull = MochiKit.Base.isUndefinedOrNull;
320 if (!isUndefNull(newPos.x)) {
321 newStyle['left'] = newPos.x + units;
322 }
323 if (!isUndefNull(newPos.y)) {
324 newStyle['top'] = newPos.y + units;
325 }
326 MochiKit.DOM.updateNodeAttributes(elem, {'style': newStyle});
327 },
328
329 /** @id MochiKit.Style.getElementDimensions */
330 getElementDimensions: function (elem) {
331 var self = MochiKit.Style;
332 var dom = MochiKit.DOM;
333 if (typeof(elem.w) == 'number' || typeof(elem.h) == 'number') {
334 return new self.Dimensions(elem.w || 0, elem.h || 0);
335 }
336 elem = dom.getElement(elem);
337 if (!elem) {
338 return undefined;
339 }
340 var disp = self.getStyle(elem, 'display');
341 // display can be empty/undefined on WebKit/KHTML
342 if (disp != 'none' && disp !== '' && typeof(disp) != 'undefined') {
343 return new self.Dimensions(elem.offsetWidth || 0,
344 elem.offsetHeight || 0);
345 }
346 var s = elem.style;
347 var originalVisibility = s.visibility;
348 var originalPosition = s.position;
349 s.visibility = 'hidden';
350 s.position = 'absolute';
351 s.display = '';
352 var originalWidth = elem.offsetWidth;
353 var originalHeight = elem.offsetHeight;
354 s.display = 'none';
355 s.position = originalPosition;
356 s.visibility = originalVisibility;
357 return new self.Dimensions(originalWidth, originalHeight);
358 },
359
360 /** @id MochiKit.Style.setElementDimensions */
361 setElementDimensions: function (elem, newSize/* optional */, units) {
362 elem = MochiKit.DOM.getElement(elem);
363 if (typeof(units) == 'undefined') {
364 units = 'px';
365 }
366 var newStyle = {};
367 var isUndefNull = MochiKit.Base.isUndefinedOrNull;
368 if (!isUndefNull(newSize.w)) {
369 newStyle['width'] = newSize.w + units;
370 }
371 if (!isUndefNull(newSize.h)) {
372 newStyle['height'] = newSize.h + units;
373 }
374 MochiKit.DOM.updateNodeAttributes(elem, {'style': newStyle});
375 },
376
377 /** @id MochiKit.Style.setDisplayForElement */
378 setDisplayForElement: function (display, element/*, ...*/) {
379 var elements = MochiKit.Base.extend(null, arguments, 1);
380 var getElement = MochiKit.DOM.getElement;
381 for (var i = 0; i < elements.length; i++) {
382 element = getElement(elements[i]);
383 if (element) {
384 element.style.display = display;
385 }
386 }
387 },
388
389 /** @id MochiKit.Style.getViewportDimensions */
390 getViewportDimensions: function () {
391 var d = new MochiKit.Style.Dimensions();
392
393 var w = MochiKit.DOM._window;
394 var b = MochiKit.DOM._document.body;
395
396 if (w.innerWidth) {
397 d.w = w.innerWidth;
398 d.h = w.innerHeight;
399 } else if (b.parentElement.clientWidth) {
400 d.w = b.parentElement.clientWidth;
401 d.h = b.parentElement.clientHeight;
402 } else if (b && b.clientWidth) {
403 d.w = b.clientWidth;
404 d.h = b.clientHeight;
405 }
406 return d;
407 },
408
409 /** @id MochiKit.Style.getViewportPosition */
410 getViewportPosition: function () {
411 var c = new MochiKit.Style.Coordinates(0, 0);
412 var d = MochiKit.DOM._document;
413 var de = d.documentElement;
414 var db = d.body;
415 if (de && (de.scrollTop || de.scrollLeft)) {
416 c.x = de.scrollLeft;
417 c.y = de.scrollTop;
418 } else if (db) {
419 c.x = db.scrollLeft;
420 c.y = db.scrollTop;
421 }
422 return c;
423 },
424
425 __new__: function () {
426 var m = MochiKit.Base;
427
428 this.elementPosition = this.getElementPosition;
429 this.elementDimensions = this.getElementDimensions;
430
431 this.hideElement = m.partial(this.setDisplayForElement, 'none');
432 this.showElement = m.partial(this.setDisplayForElement, 'block');
433
434 this.EXPORT_TAGS = {
435 ':common': this.EXPORT,
436 ':all': m.concat(this.EXPORT, this.EXPORT_OK)
437 };
438
439 m.nameFunctions(this);
440 }
441});
442
443MochiKit.Style.__new__();
444MochiKit.Base._exportSymbols(this, MochiKit.Style);
diff --git a/frontend/beta/js/MochiKit/Test.js b/frontend/beta/js/MochiKit/Test.js
new file mode 100644
index 0000000..494a5b4
--- a/dev/null
+++ b/frontend/beta/js/MochiKit/Test.js
@@ -0,0 +1,181 @@
1/***
2
3MochiKit.Test 1.4
4
5See <http://mochikit.com/> for documentation, downloads, license, etc.
6
7(c) 2005 Bob Ippolito. All rights Reserved.
8
9***/
10
11if (typeof(dojo) != 'undefined') {
12 dojo.provide('MochiKit.Test');
13 dojo.require('MochiKit.Base');
14}
15
16if (typeof(JSAN) != 'undefined') {
17 JSAN.use("MochiKit.Base", []);
18}
19
20try {
21 if (typeof(MochiKit.Base) == 'undefined') {
22 throw "";
23 }
24} catch (e) {
25 throw "MochiKit.Test depends on MochiKit.Base!";
26}
27
28if (typeof(MochiKit.Test) == 'undefined') {
29 MochiKit.Test = {};
30}
31
32MochiKit.Test.NAME = "MochiKit.Test";
33MochiKit.Test.VERSION = "1.4";
34MochiKit.Test.__repr__ = function () {
35 return "[" + this.NAME + " " + this.VERSION + "]";
36};
37
38MochiKit.Test.toString = function () {
39 return this.__repr__();
40};
41
42
43MochiKit.Test.EXPORT = ["runTests"];
44MochiKit.Test.EXPORT_OK = [];
45
46MochiKit.Test.runTests = function (obj) {
47 if (typeof(obj) == "string") {
48 obj = JSAN.use(obj);
49 }
50 var suite = new MochiKit.Test.Suite();
51 suite.run(obj);
52};
53
54MochiKit.Test.Suite = function () {
55 this.testIndex = 0;
56 MochiKit.Base.bindMethods(this);
57};
58
59MochiKit.Test.Suite.prototype = {
60 run: function (obj) {
61 try {
62 obj(this);
63 } catch (e) {
64 this.traceback(e);
65 }
66 },
67 traceback: function (e) {
68 var items = MochiKit.Iter.sorted(MochiKit.Base.items(e));
69 print("not ok " + this.testIndex + " - Error thrown");
70 for (var i = 0; i < items.length; i++) {
71 var kv = items[i];
72 if (kv[0] == "stack") {
73 kv[1] = kv[1].split(/\n/)[0];
74 }
75 this.print("# " + kv.join(": "));
76 }
77 },
78 print: function (s) {
79 print(s);
80 },
81 is: function (got, expected, /* optional */message) {
82 var res = 1;
83 var msg = null;
84 try {
85 res = MochiKit.Base.compare(got, expected);
86 } catch (e) {
87 msg = "Can not compare " + typeof(got) + ":" + typeof(expected);
88 }
89 if (res) {
90 msg = "Expected value did not compare equal";
91 }
92 if (!res) {
93 return this.testResult(true, message);
94 }
95 return this.testResult(false, message,
96 [[msg], ["got:", got], ["expected:", expected]]);
97 },
98
99 testResult: function (pass, msg, failures) {
100 this.testIndex += 1;
101 if (pass) {
102 this.print("ok " + this.testIndex + " - " + msg);
103 return;
104 }
105 this.print("not ok " + this.testIndex + " - " + msg);
106 if (failures) {
107 for (var i = 0; i < failures.length; i++) {
108 this.print("# " + failures[i].join(" "));
109 }
110 }
111 },
112
113 isDeeply: function (got, expected, /* optional */message) {
114 var m = MochiKit.Base;
115 var res = 1;
116 try {
117 res = m.compare(got, expected);
118 } catch (e) {
119 // pass
120 }
121 if (res === 0) {
122 return this.ok(true, message);
123 }
124 var gk = m.keys(got);
125 var ek = m.keys(expected);
126 gk.sort();
127 ek.sort();
128 if (m.compare(gk, ek)) {
129 // differing keys
130 var cmp = {};
131 var i;
132 for (i = 0; i < gk.length; i++) {
133 cmp[gk[i]] = "got";
134 }
135 for (i = 0; i < ek.length; i++) {
136 if (ek[i] in cmp) {
137 delete cmp[ek[i]];
138 } else {
139 cmp[ek[i]] = "expected";
140 }
141 }
142 var diffkeys = m.keys(cmp);
143 diffkeys.sort();
144 var gotkeys = [];
145 var expkeys = [];
146 while (diffkeys.length) {
147 var k = diffkeys.shift();
148 if (k in Object.prototype) {
149 continue;
150 }
151 (cmp[k] == "got" ? gotkeys : expkeys).push(k);
152 }
153
154
155 }
156
157 return this.testResult((!res), msg,
158 (msg ? [["got:", got], ["expected:", expected]] : undefined)
159 );
160 },
161
162 ok: function (res, message) {
163 return this.testResult(res, message);
164 }
165};
166
167MochiKit.Test.__new__ = function () {
168 var m = MochiKit.Base;
169
170 this.EXPORT_TAGS = {
171 ":common": this.EXPORT,
172 ":all": m.concat(this.EXPORT, this.EXPORT_OK)
173 };
174
175 m.nameFunctions(this);
176
177};
178
179MochiKit.Test.__new__();
180
181MochiKit.Base._exportSymbols(this, MochiKit.Test);
diff --git a/frontend/beta/js/MochiKit/Visual.js b/frontend/beta/js/MochiKit/Visual.js
new file mode 100644
index 0000000..914b3b4
--- a/dev/null
+++ b/frontend/beta/js/MochiKit/Visual.js
@@ -0,0 +1,1976 @@
1/***
2
3MochiKit.Visual 1.4
4
5See <http://mochikit.com/> for documentation, downloads, license, etc.
6
7(c) 2005 Bob Ippolito and others. All rights Reserved.
8
9***/
10
11if (typeof(dojo) != 'undefined') {
12 dojo.provide('MochiKit.Visual');
13 dojo.require('MochiKit.Base');
14 dojo.require('MochiKit.DOM');
15 dojo.require('MochiKit.Style');
16 dojo.require('MochiKit.Color');
17 dojo.require('MochiKit.Position');
18}
19
20if (typeof(JSAN) != 'undefined') {
21 JSAN.use("MochiKit.Base", []);
22 JSAN.use("MochiKit.DOM", []);
23 JSAN.use("MochiKit.Style", []);
24 JSAN.use("MochiKit.Color", []);
25 JSAN.use("MochiKit.Position", []);
26}
27
28try {
29 if (typeof(MochiKit.Base) === 'undefined' ||
30 typeof(MochiKit.DOM) === 'undefined' ||
31 typeof(MochiKit.Style) === 'undefined' ||
32 typeof(MochiKit.Position) === 'undefined' ||
33 typeof(MochiKit.Color) === 'undefined') {
34 throw "";
35 }
36} catch (e) {
37 throw "MochiKit.Visual depends on MochiKit.Base, MochiKit.DOM, MochiKit.Style, MochiKit.Position and MochiKit.Color!";
38}
39
40if (typeof(MochiKit.Visual) == "undefined") {
41 MochiKit.Visual = {};
42}
43
44MochiKit.Visual.NAME = "MochiKit.Visual";
45MochiKit.Visual.VERSION = "1.4";
46
47MochiKit.Visual.__repr__ = function () {
48 return "[" + this.NAME + " " + this.VERSION + "]";
49};
50
51MochiKit.Visual.toString = function () {
52 return this.__repr__();
53};
54
55MochiKit.Visual._RoundCorners = function (e, options) {
56 e = MochiKit.DOM.getElement(e);
57 this._setOptions(options);
58 if (this.options.__unstable__wrapElement) {
59 e = this._doWrap(e);
60 }
61
62 var color = this.options.color;
63 var C = MochiKit.Color.Color;
64 if (this.options.color === "fromElement") {
65 color = C.fromBackground(e);
66 } else if (!(color instanceof C)) {
67 color = C.fromString(color);
68 }
69 this.isTransparent = (color.asRGB().a <= 0);
70
71 var bgColor = this.options.bgColor;
72 if (this.options.bgColor === "fromParent") {
73 bgColor = C.fromBackground(e.offsetParent);
74 } else if (!(bgColor instanceof C)) {
75 bgColor = C.fromString(bgColor);
76 }
77
78 this._roundCornersImpl(e, color, bgColor);
79};
80
81MochiKit.Visual._RoundCorners.prototype = {
82 _doWrap: function (e) {
83 var parent = e.parentNode;
84 var doc = MochiKit.DOM.currentDocument();
85 if (typeof(doc.defaultView) === "undefined"
86 || doc.defaultView === null) {
87 return e;
88 }
89 var style = doc.defaultView.getComputedStyle(e, null);
90 if (typeof(style) === "undefined" || style === null) {
91 return e;
92 }
93 var wrapper = MochiKit.DOM.DIV({"style": {
94 display: "block",
95 // convert padding to margin
96 marginTop: style.getPropertyValue("padding-top"),
97 marginRight: style.getPropertyValue("padding-right"),
98 marginBottom: style.getPropertyValue("padding-bottom"),
99 marginLeft: style.getPropertyValue("padding-left"),
100 // remove padding so the rounding looks right
101 padding: "0px"
102 /*
103 paddingRight: "0px",
104 paddingLeft: "0px"
105 */
106 }});
107 wrapper.innerHTML = e.innerHTML;
108 e.innerHTML = "";
109 e.appendChild(wrapper);
110 return e;
111 },
112
113 _roundCornersImpl: function (e, color, bgColor) {
114 if (this.options.border) {
115 this._renderBorder(e, bgColor);
116 }
117 if (this._isTopRounded()) {
118 this._roundTopCorners(e, color, bgColor);
119 }
120 if (this._isBottomRounded()) {
121 this._roundBottomCorners(e, color, bgColor);
122 }
123 },
124
125 _renderBorder: function (el, bgColor) {
126 var borderValue = "1px solid " + this._borderColor(bgColor);
127 var borderL = "border-left: " + borderValue;
128 var borderR = "border-right: " + borderValue;
129 var style = "style='" + borderL + ";" + borderR + "'";
130 el.innerHTML = "<div " + style + ">" + el.innerHTML + "</div>";
131 },
132
133 _roundTopCorners: function (el, color, bgColor) {
134 var corner = this._createCorner(bgColor);
135 for (var i = 0; i < this.options.numSlices; i++) {
136 corner.appendChild(
137 this._createCornerSlice(color, bgColor, i, "top")
138 );
139 }
140 el.style.paddingTop = 0;
141 el.insertBefore(corner, el.firstChild);
142 },
143
144 _roundBottomCorners: function (el, color, bgColor) {
145 var corner = this._createCorner(bgColor);
146 for (var i = (this.options.numSlices - 1); i >= 0; i--) {
147 corner.appendChild(
148 this._createCornerSlice(color, bgColor, i, "bottom")
149 );
150 }
151 el.style.paddingBottom = 0;
152 el.appendChild(corner);
153 },
154
155 _createCorner: function (bgColor) {
156 var dom = MochiKit.DOM;
157 return dom.DIV({style: {backgroundColor: bgColor.toString()}});
158 },
159
160 _createCornerSlice: function (color, bgColor, n, position) {
161 var slice = MochiKit.DOM.SPAN();
162
163 var inStyle = slice.style;
164 inStyle.backgroundColor = color.toString();
165 inStyle.display = "block";
166 inStyle.height = "1px";
167 inStyle.overflow = "hidden";
168 inStyle.fontSize = "1px";
169
170 var borderColor = this._borderColor(color, bgColor);
171 if (this.options.border && n === 0) {
172 inStyle.borderTopStyle = "solid";
173 inStyle.borderTopWidth = "1px";
174 inStyle.borderLeftWidth = "0px";
175 inStyle.borderRightWidth = "0px";
176 inStyle.borderBottomWidth = "0px";
177 // assumes css compliant box model
178 inStyle.height = "0px";
179 inStyle.borderColor = borderColor.toString();
180 } else if (borderColor) {
181 inStyle.borderColor = borderColor.toString();
182 inStyle.borderStyle = "solid";
183 inStyle.borderWidth = "0px 1px";
184 }
185
186 if (!this.options.compact && (n == (this.options.numSlices - 1))) {
187 inStyle.height = "2px";
188 }
189
190 this._setMargin(slice, n, position);
191 this._setBorder(slice, n, position);
192
193 return slice;
194 },
195
196 _setOptions: function (options) {
197 this.options = {
198 corners: "all",
199 color: "fromElement",
200 bgColor: "fromParent",
201 blend: true,
202 border: false,
203 compact: false,
204 __unstable__wrapElement: false
205 };
206 MochiKit.Base.update(this.options, options);
207
208 this.options.numSlices = (this.options.compact ? 2 : 4);
209 },
210
211 _whichSideTop: function () {
212 var corners = this.options.corners;
213 if (this._hasString(corners, "all", "top")) {
214 return "";
215 }
216
217 var has_tl = (corners.indexOf("tl") != -1);
218 var has_tr = (corners.indexOf("tr") != -1);
219 if (has_tl && has_tr) {
220 return "";
221 }
222 if (has_tl) {
223 return "left";
224 }
225 if (has_tr) {
226 return "right";
227 }
228 return "";
229 },
230
231 _whichSideBottom: function () {
232 var corners = this.options.corners;
233 if (this._hasString(corners, "all", "bottom")) {
234 return "";
235 }
236
237 var has_bl = (corners.indexOf('bl') != -1);
238 var has_br = (corners.indexOf('br') != -1);
239 if (has_bl && has_br) {
240 return "";
241 }
242 if (has_bl) {
243 return "left";
244 }
245 if (has_br) {
246 return "right";
247 }
248 return "";
249 },
250
251 _borderColor: function (color, bgColor) {
252 if (color == "transparent") {
253 return bgColor;
254 } else if (this.options.border) {
255 return this.options.border;
256 } else if (this.options.blend) {
257 return bgColor.blendedColor(color);
258 }
259 return "";
260 },
261
262
263 _setMargin: function (el, n, corners) {
264 var marginSize = this._marginSize(n) + "px";
265 var whichSide = (
266 corners == "top" ? this._whichSideTop() : this._whichSideBottom()
267 );
268 var style = el.style;
269
270 if (whichSide == "left") {
271 style.marginLeft = marginSize;
272 style.marginRight = "0px";
273 } else if (whichSide == "right") {
274 style.marginRight = marginSize;
275 style.marginLeft = "0px";
276 } else {
277 style.marginLeft = marginSize;
278 style.marginRight = marginSize;
279 }
280 },
281
282 _setBorder: function (el, n, corners) {
283 var borderSize = this._borderSize(n) + "px";
284 var whichSide = (
285 corners == "top" ? this._whichSideTop() : this._whichSideBottom()
286 );
287
288 var style = el.style;
289 if (whichSide == "left") {
290 style.borderLeftWidth = borderSize;
291 style.borderRightWidth = "0px";
292 } else if (whichSide == "right") {
293 style.borderRightWidth = borderSize;
294 style.borderLeftWidth = "0px";
295 } else {
296 style.borderLeftWidth = borderSize;
297 style.borderRightWidth = borderSize;
298 }
299 },
300
301 _marginSize: function (n) {
302 if (this.isTransparent) {
303 return 0;
304 }
305
306 var o = this.options;
307 if (o.compact && o.blend) {
308 var smBlendedMarginSizes = [1, 0];
309 return smBlendedMarginSizes[n];
310 } else if (o.compact) {
311 var compactMarginSizes = [2, 1];
312 return compactMarginSizes[n];
313 } else if (o.blend) {
314 var blendedMarginSizes = [3, 2, 1, 0];
315 return blendedMarginSizes[n];
316 } else {
317 var marginSizes = [5, 3, 2, 1];
318 return marginSizes[n];
319 }
320 },
321
322 _borderSize: function (n) {
323 var o = this.options;
324 var borderSizes;
325 if (o.compact && (o.blend || this.isTransparent)) {
326 return 1;
327 } else if (o.compact) {
328 borderSizes = [1, 0];
329 } else if (o.blend) {
330 borderSizes = [2, 1, 1, 1];
331 } else if (o.border) {
332 borderSizes = [0, 2, 0, 0];
333 } else if (this.isTransparent) {
334 borderSizes = [5, 3, 2, 1];
335 } else {
336 return 0;
337 }
338 return borderSizes[n];
339 },
340
341 _hasString: function (str) {
342 for (var i = 1; i< arguments.length; i++) {
343 if (str.indexOf(arguments[i]) != -1) {
344 return true;
345 }
346 }
347 return false;
348 },
349
350 _isTopRounded: function () {
351 return this._hasString(this.options.corners,
352 "all", "top", "tl", "tr"
353 );
354 },
355
356 _isBottomRounded: function () {
357 return this._hasString(this.options.corners,
358 "all", "bottom", "bl", "br"
359 );
360 },
361
362 _hasSingleTextChild: function (el) {
363 return (el.childNodes.length == 1 && el.childNodes[0].nodeType == 3);
364 }
365};
366
367/** @id MochiKit.Visual.roundElement */
368MochiKit.Visual.roundElement = function (e, options) {
369 new MochiKit.Visual._RoundCorners(e, options);
370};
371
372/** @id MochiKit.Visual.roundClass */
373MochiKit.Visual.roundClass = function (tagName, className, options) {
374 var elements = MochiKit.DOM.getElementsByTagAndClassName(
375 tagName, className
376 );
377 for (var i = 0; i < elements.length; i++) {
378 MochiKit.Visual.roundElement(elements[i], options);
379 }
380};
381
382/** @id MochiKit.Visual.tagifyText */
383MochiKit.Visual.tagifyText = function (element, /* optional */tagifyStyle) {
384 /***
385
386 Change a node text to character in tags.
387
388 @param tagifyStyle: the style to apply to character nodes, default to
389 'position: relative'.
390
391 ***/
392 tagifyStyle = tagifyStyle || 'position:relative';
393 if (/MSIE/.test(navigator.userAgent)) {
394 tagifyStyle += ';zoom:1';
395 }
396 element = MochiKit.DOM.getElement(element);
397 var ma = MochiKit.Base.map;
398 ma(function (child) {
399 if (child.nodeType == 3) {
400 ma(function (character) {
401 element.insertBefore(
402 MochiKit.DOM.SPAN({style: tagifyStyle},
403 character == ' ' ? String.fromCharCode(160) : character), child);
404 }, child.nodeValue.split(''));
405 MochiKit.DOM.removeElement(child);
406 }
407 }, element.childNodes);
408};
409
410/** @id MochiKit.Visual.forceRerendering */
411MochiKit.Visual.forceRerendering = function (element) {
412 try {
413 element = MochiKit.DOM.getElement(element);
414 var n = document.createTextNode(' ');
415 element.appendChild(n);
416 element.removeChild(n);
417 } catch(e) {
418 }
419};
420
421/** @id MochiKit.Visual.multiple */
422MochiKit.Visual.multiple = function (elements, effect, /* optional */options) {
423 /***
424
425 Launch the same effect subsequently on given elements.
426
427 ***/
428 options = MochiKit.Base.update({
429 speed: 0.1, delay: 0.0
430 }, options || {});
431 var masterDelay = options.delay;
432 var index = 0;
433 MochiKit.Base.map(function (innerelement) {
434 options.delay = index * options.speed + masterDelay;
435 new effect(innerelement, options);
436 index += 1;
437 }, elements);
438};
439
440MochiKit.Visual.PAIRS = {
441 'slide': ['slideDown', 'slideUp'],
442 'blind': ['blindDown', 'blindUp'],
443 'appear': ['appear', 'fade'],
444 'size': ['grow', 'shrink']
445};
446
447/** @id MochiKit.Visual.toggle */
448MochiKit.Visual.toggle = function (element, /* optional */effect, /* optional */options) {
449 /***
450
451 Toggle an item between two state depending of its visibility, making
452 a effect between these states. Default effect is 'appear', can be
453 'slide' or 'blind'.
454
455 ***/
456 element = MochiKit.DOM.getElement(element);
457 effect = (effect || 'appear').toLowerCase();
458 options = MochiKit.Base.update({
459 queue: {position: 'end', scope: (element.id || 'global'), limit: 1}
460 }, options || {});
461 var v = MochiKit.Visual;
462 v[element.style.display != 'none' ?
463 v.PAIRS[effect][1] : v.PAIRS[effect][0]](element, options);
464};
465
466/***
467
468Transitions: define functions calculating variations depending of a position.
469
470***/
471
472MochiKit.Visual.Transitions = {};
473
474/** @id MochiKit.Visual.Transitions.linear */
475MochiKit.Visual.Transitions.linear = function (pos) {
476 return pos;
477};
478
479/** @id MochiKit.Visual.Transitions.sinoidal */
480MochiKit.Visual.Transitions.sinoidal = function (pos) {
481 return (-Math.cos(pos*Math.PI)/2) + 0.5;
482};
483
484/** @id MochiKit.Visual.Transitions.reverse */
485MochiKit.Visual.Transitions.reverse = function (pos) {
486 return 1 - pos;
487};
488
489/** @id MochiKit.Visual.Transitions.flicker */
490MochiKit.Visual.Transitions.flicker = function (pos) {
491 return ((-Math.cos(pos*Math.PI)/4) + 0.75) + Math.random()/4;
492};
493
494/** @id MochiKit.Visual.Transitions.wobble */
495MochiKit.Visual.Transitions.wobble = function (pos) {
496 return (-Math.cos(pos*Math.PI*(9*pos))/2) + 0.5;
497};
498
499/** @id MochiKit.Visual.Transitions.pulse */
500MochiKit.Visual.Transitions.pulse = function (pos) {
501 return (Math.floor(pos*10) % 2 === 0 ?
502 (pos*10 - Math.floor(pos*10)) : 1 - (pos*10 - Math.floor(pos*10)));
503};
504
505/** @id MochiKit.Visual.Transitions.none */
506MochiKit.Visual.Transitions.none = function (pos) {
507 return 0;
508};
509
510/** @id MochiKit.Visual.Transitions.full */
511MochiKit.Visual.Transitions.full = function (pos) {
512 return 1;
513};
514
515/***
516
517Core effects
518
519***/
520
521MochiKit.Visual.ScopedQueue = function () {
522 var cls = arguments.callee;
523 if (!(this instanceof cls)) {
524 return new cls();
525 }
526 this.__init__();
527};
528
529MochiKit.Base.update(MochiKit.Visual.ScopedQueue.prototype, {
530 __init__: function () {
531 this.effects = [];
532 this.interval = null;
533 },
534
535 /** @id MochiKit.Visual.ScopedQueue.prototype.add */
536 add: function (effect) {
537 var timestamp = new Date().getTime();
538
539 var position = (typeof(effect.options.queue) == 'string') ?
540 effect.options.queue : effect.options.queue.position;
541
542 var ma = MochiKit.Base.map;
543 switch (position) {
544 case 'front':
545 // move unstarted effects after this effect
546 ma(function (e) {
547 if (e.state == 'idle') {
548 e.startOn += effect.finishOn;
549 e.finishOn += effect.finishOn;
550 }
551 }, this.effects);
552 break;
553 case 'end':
554 var finish;
555 // start effect after last queued effect has finished
556 ma(function (e) {
557 var i = e.finishOn;
558 if (i >= (finish || i)) {
559 finish = i;
560 }
561 }, this.effects);
562 timestamp = finish || timestamp;
563 break;
564 case 'break':
565 ma(function (e) {
566 e.finalize();
567 }, this.effects);
568 break;
569 }
570
571 effect.startOn += timestamp;
572 effect.finishOn += timestamp;
573 if (!effect.options.queue.limit ||
574 this.effects.length < effect.options.queue.limit) {
575 this.effects.push(effect);
576 }
577
578 if (!this.interval) {
579 this.interval = this.startLoop(MochiKit.Base.bind(this.loop, this),
580 40);
581 }
582 },
583
584 /** @id MochiKit.Visual.ScopedQueue.prototype.startLoop */
585 startLoop: function (func, interval) {
586 return setInterval(func, interval);
587 },
588
589 /** @id MochiKit.Visual.ScopedQueue.prototype.remove */
590 remove: function (effect) {
591 this.effects = MochiKit.Base.filter(function (e) {
592 return e != effect;
593 }, this.effects);
594 if (!this.effects.length) {
595 this.stopLoop(this.interval);
596 this.interval = null;
597 }
598 },
599
600 /** @id MochiKit.Visual.ScopedQueue.prototype.stopLoop */
601 stopLoop: function (interval) {
602 clearInterval(interval);
603 },
604
605 /** @id MochiKit.Visual.ScopedQueue.prototype.loop */
606 loop: function () {
607 var timePos = new Date().getTime();
608 MochiKit.Base.map(function (effect) {
609 effect.loop(timePos);
610 }, this.effects);
611 }
612});
613
614MochiKit.Visual.Queues = {
615 instances: {},
616
617 get: function (queueName) {
618 if (typeof(queueName) != 'string') {
619 return queueName;
620 }
621
622 if (!this.instances[queueName]) {
623 this.instances[queueName] = new MochiKit.Visual.ScopedQueue();
624 }
625 return this.instances[queueName];
626 }
627};
628
629MochiKit.Visual.Queue = MochiKit.Visual.Queues.get('global');
630
631MochiKit.Visual.DefaultOptions = {
632 transition: MochiKit.Visual.Transitions.sinoidal,
633 duration: 1.0, // seconds
634 fps: 25.0, // max. 25fps due to MochiKit.Visual.Queue implementation
635 sync: false, // true for combining
636 from: 0.0,
637 to: 1.0,
638 delay: 0.0,
639 queue: 'parallel'
640};
641
642MochiKit.Visual.Base = function () {};
643
644MochiKit.Visual.Base.prototype = {
645 /***
646
647 Basic class for all Effects. Define a looping mechanism called for each step
648 of an effect. Don't instantiate it, only subclass it.
649
650 ***/
651
652 __class__ : MochiKit.Visual.Base,
653
654 /** @id MochiKit.Visual.Base.prototype.start */
655 start: function (options) {
656 var v = MochiKit.Visual;
657 this.options = MochiKit.Base.setdefault(options || {},
658 v.DefaultOptions);
659 this.currentFrame = 0;
660 this.state = 'idle';
661 this.startOn = this.options.delay*1000;
662 this.finishOn = this.startOn + (this.options.duration*1000);
663 this.event('beforeStart');
664 if (!this.options.sync) {
665 v.Queues.get(typeof(this.options.queue) == 'string' ?
666 'global' : this.options.queue.scope).add(this);
667 }
668 },
669
670 /** @id MochiKit.Visual.Base.prototype.loop */
671 loop: function (timePos) {
672 if (timePos >= this.startOn) {
673 if (timePos >= this.finishOn) {
674 return this.finalize();
675 }
676 var pos = (timePos - this.startOn) / (this.finishOn - this.startOn);
677 var frame =
678 Math.round(pos * this.options.fps * this.options.duration);
679 if (frame > this.currentFrame) {
680 this.render(pos);
681 this.currentFrame = frame;
682 }
683 }
684 },
685
686 /** @id MochiKit.Visual.Base.prototype.render */
687 render: function (pos) {
688 if (this.state == 'idle') {
689 this.state = 'running';
690 this.event('beforeSetup');
691 this.setup();
692 this.event('afterSetup');
693 }
694 if (this.state == 'running') {
695 if (this.options.transition) {
696 pos = this.options.transition(pos);
697 }
698 pos *= (this.options.to - this.options.from);
699 pos += this.options.from;
700 this.event('beforeUpdate');
701 this.update(pos);
702 this.event('afterUpdate');
703 }
704 },
705
706 /** @id MochiKit.Visual.Base.prototype.cancel */
707 cancel: function () {
708 if (!this.options.sync) {
709 MochiKit.Visual.Queues.get(typeof(this.options.queue) == 'string' ?
710 'global' : this.options.queue.scope).remove(this);
711 }
712 this.state = 'finished';
713 },
714
715 /** @id MochiKit.Visual.Base.prototype.finalize */
716 finalize: function () {
717 this.render(1.0);
718 this.cancel();
719 this.event('beforeFinish');
720 this.finish();
721 this.event('afterFinish');
722 },
723
724 setup: function () {
725 },
726
727 finish: function () {
728 },
729
730 update: function (position) {
731 },
732
733 /** @id MochiKit.Visual.Base.prototype.event */
734 event: function (eventName) {
735 if (this.options[eventName + 'Internal']) {
736 this.options[eventName + 'Internal'](this);
737 }
738 if (this.options[eventName]) {
739 this.options[eventName](this);
740 }
741 },
742
743 /** @id MochiKit.Visual.Base.prototype.repr */
744 repr: function () {
745 return '[' + this.__class__.NAME + ', options:' +
746 MochiKit.Base.repr(this.options) + ']';
747 }
748};
749
750 /** @id MochiKit.Visual.Parallel */
751MochiKit.Visual.Parallel = function (effects, options) {
752 var cls = arguments.callee;
753 if (!(this instanceof cls)) {
754 return new cls(effects, options);
755 }
756
757 this.__init__(effects, options);
758};
759
760MochiKit.Visual.Parallel.prototype = new MochiKit.Visual.Base();
761
762MochiKit.Base.update(MochiKit.Visual.Parallel.prototype, {
763 /***
764
765 Run multiple effects at the same time.
766
767 ***/
768
769 __class__ : MochiKit.Visual.Parallel,
770
771 __init__: function (effects, options) {
772 this.effects = effects || [];
773 this.start(options);
774 },
775
776 /** @id MochiKit.Visual.Parallel.prototype.update */
777 update: function (position) {
778 MochiKit.Base.map(function (effect) {
779 effect.render(position);
780 }, this.effects);
781 },
782
783 /** @id MochiKit.Visual.Parallel.prototype.finish */
784 finish: function () {
785 MochiKit.Base.map(function (effect) {
786 effect.finalize();
787 }, this.effects);
788 }
789});
790
791/** @id MochiKit.Visual.Opacity */
792MochiKit.Visual.Opacity = function (element, options) {
793 var cls = arguments.callee;
794 if (!(this instanceof cls)) {
795 return new cls(element, options);
796 }
797 this.__init__(element, options);
798};
799
800MochiKit.Visual.Opacity.prototype = new MochiKit.Visual.Base();
801
802MochiKit.Base.update(MochiKit.Visual.Opacity.prototype, {
803 /***
804
805 Change the opacity of an element.
806
807 @param options: 'from' and 'to' change the starting and ending opacities.
808 Must be between 0.0 and 1.0. Default to current opacity and 1.0.
809
810 ***/
811
812 __class__ : MochiKit.Visual.Opacity,
813
814 __init__: function (element, /* optional */options) {
815 var b = MochiKit.Base;
816 var s = MochiKit.Style;
817 this.element = MochiKit.DOM.getElement(element);
818 // make this work on IE on elements without 'layout'
819 if (this.element.currentStyle &&
820 (!this.element.currentStyle.hasLayout)) {
821 s.setStyle(this.element, {zoom: 1});
822 }
823 options = b.update({
824 from: s.getStyle(this.element, 'opacity') || 0.0,
825 to: 1.0
826 }, options || {});
827 this.start(options);
828 },
829
830 /** @id MochiKit.Visual.Opacity.prototype.update */
831 update: function (position) {
832 MochiKit.Style.setStyle(this.element, {'opacity': position});
833 }
834});
835
836/** @id MochiKit.Visual.Move.prototype */
837MochiKit.Visual.Move = function (element, options) {
838 var cls = arguments.callee;
839 if (!(this instanceof cls)) {
840 return new cls(element, options);
841 }
842 this.__init__(element, options);
843};
844
845MochiKit.Visual.Move.prototype = new MochiKit.Visual.Base();
846
847MochiKit.Base.update(MochiKit.Visual.Move.prototype, {
848 /***
849
850 Move an element between its current position to a defined position
851
852 @param options: 'x' and 'y' for final positions, default to 0, 0.
853
854 ***/
855
856 __class__ : MochiKit.Visual.Move,
857
858 __init__: function (element, /* optional */options) {
859 this.element = MochiKit.DOM.getElement(element);
860 options = MochiKit.Base.update({
861 x: 0,
862 y: 0,
863 mode: 'relative'
864 }, options || {});
865 this.start(options);
866 },
867
868 /** @id MochiKit.Visual.Move.prototype.setup */
869 setup: function () {
870 // Bug in Opera: Opera returns the 'real' position of a static element
871 // or relative element that does not have top/left explicitly set.
872 // ==> Always set top and left for position relative elements in your
873 // stylesheets (to 0 if you do not need them)
874 MochiKit.DOM.makePositioned(this.element);
875
876 var s = this.element.style;
877 var originalVisibility = s.visibility;
878 var originalDisplay = s.display;
879 if (originalDisplay == 'none') {
880 s.visibility = 'hidden';
881 s.display = '';
882 }
883
884 this.originalLeft = parseFloat(MochiKit.Style.getStyle(this.element, 'left') || '0');
885 this.originalTop = parseFloat(MochiKit.Style.getStyle(this.element, 'top') || '0');
886
887 if (this.options.mode == 'absolute') {
888 // absolute movement, so we need to calc deltaX and deltaY
889 this.options.x -= this.originalLeft;
890 this.options.y -= this.originalTop;
891 }
892 if (originalDisplay == 'none') {
893 s.visibility = originalVisibility;
894 s.display = originalDisplay;
895 }
896 },
897
898 /** @id MochiKit.Visual.Move.prototype.update */
899 update: function (position) {
900 MochiKit.Style.setStyle(this.element, {
901 left: Math.round(this.options.x * position + this.originalLeft) + 'px',
902 top: Math.round(this.options.y * position + this.originalTop) + 'px'
903 });
904 }
905});
906
907/** @id MochiKit.Visual.Scale */
908MochiKit.Visual.Scale = function (element, percent, options) {
909 var cls = arguments.callee;
910 if (!(this instanceof cls)) {
911 return new cls(element, percent, options);
912 }
913 this.__init__(element, percent, options);
914};
915
916MochiKit.Visual.Scale.prototype = new MochiKit.Visual.Base();
917
918MochiKit.Base.update(MochiKit.Visual.Scale.prototype, {
919 /***
920
921 Change the size of an element.
922
923 @param percent: final_size = percent*original_size
924
925 @param options: several options changing scale behaviour
926
927 ***/
928
929 __class__ : MochiKit.Visual.Scale,
930
931 __init__: function (element, percent, /* optional */options) {
932 this.element = MochiKit.DOM.getElement(element);
933 options = MochiKit.Base.update({
934 scaleX: true,
935 scaleY: true,
936 scaleContent: true,
937 scaleFromCenter: false,
938 scaleMode: 'box', // 'box' or 'contents' or {} with provided values
939 scaleFrom: 100.0,
940 scaleTo: percent
941 }, options || {});
942 this.start(options);
943 },
944
945 /** @id MochiKit.Visual.Scale.prototype.setup */
946 setup: function () {
947 this.restoreAfterFinish = this.options.restoreAfterFinish || false;
948 this.elementPositioning = MochiKit.Style.getStyle(this.element,
949 'position');
950
951 var ma = MochiKit.Base.map;
952 var b = MochiKit.Base.bind;
953 this.originalStyle = {};
954 ma(b(function (k) {
955 this.originalStyle[k] = this.element.style[k];
956 }, this), ['top', 'left', 'width', 'height', 'fontSize']);
957
958 this.originalTop = this.element.offsetTop;
959 this.originalLeft = this.element.offsetLeft;
960
961 var fontSize = MochiKit.Style.getStyle(this.element,
962 'font-size') || '100%';
963 ma(b(function (fontSizeType) {
964 if (fontSize.indexOf(fontSizeType) > 0) {
965 this.fontSize = parseFloat(fontSize);
966 this.fontSizeType = fontSizeType;
967 }
968 }, this), ['em', 'px', '%']);
969
970 this.factor = (this.options.scaleTo - this.options.scaleFrom)/100;
971
972 if (/^content/.test(this.options.scaleMode)) {
973 this.dims = [this.element.scrollHeight, this.element.scrollWidth];
974 } else if (this.options.scaleMode == 'box') {
975 this.dims = [this.element.offsetHeight, this.element.offsetWidth];
976 } else {
977 this.dims = [this.options.scaleMode.originalHeight,
978 this.options.scaleMode.originalWidth];
979 }
980 },
981
982 /** @id MochiKit.Visual.Scale.prototype.update */
983 update: function (position) {
984 var currentScale = (this.options.scaleFrom/100.0) +
985 (this.factor * position);
986 if (this.options.scaleContent && this.fontSize) {
987 MochiKit.Style.setStyle(this.element, {
988 fontSize: this.fontSize * currentScale + this.fontSizeType
989 });
990 }
991 this.setDimensions(this.dims[0] * currentScale,
992 this.dims[1] * currentScale);
993 },
994
995 /** @id MochiKit.Visual.Scale.prototype.finish */
996 finish: function () {
997 if (this.restoreAfterFinish) {
998 MochiKit.Style.setStyle(this.element, this.originalStyle);
999 }
1000 },
1001
1002 /** @id MochiKit.Visual.Scale.prototype.setDimensions */
1003 setDimensions: function (height, width) {
1004 var d = {};
1005 var r = Math.round;
1006 if (/MSIE/.test(navigator.userAgent)) {
1007 r = Math.ceil;
1008 }
1009 if (this.options.scaleX) {
1010 d.width = r(width) + 'px';
1011 }
1012 if (this.options.scaleY) {
1013 d.height = r(height) + 'px';
1014 }
1015 if (this.options.scaleFromCenter) {
1016 var topd = (height - this.dims[0])/2;
1017 var leftd = (width - this.dims[1])/2;
1018 if (this.elementPositioning == 'absolute') {
1019 if (this.options.scaleY) {
1020 d.top = this.originalTop - topd + 'px';
1021 }
1022 if (this.options.scaleX) {
1023 d.left = this.originalLeft - leftd + 'px';
1024 }
1025 } else {
1026 if (this.options.scaleY) {
1027 d.top = -topd + 'px';
1028 }
1029 if (this.options.scaleX) {
1030 d.left = -leftd + 'px';
1031 }
1032 }
1033 }
1034 MochiKit.Style.setStyle(this.element, d);
1035 }
1036});
1037
1038/** @id MochiKit.Visual.Highlight */
1039MochiKit.Visual.Highlight = function (element, options) {
1040 var cls = arguments.callee;
1041 if (!(this instanceof cls)) {
1042 return new cls(element, options);
1043 }
1044 this.__init__(element, options);
1045};
1046
1047MochiKit.Visual.Highlight.prototype = new MochiKit.Visual.Base();
1048
1049MochiKit.Base.update(MochiKit.Visual.Highlight.prototype, {
1050 /***
1051
1052 Highlight an item of the page.
1053
1054 @param options: 'startcolor' for choosing highlighting color, default
1055 to '#ffff99'.
1056
1057 ***/
1058
1059 __class__ : MochiKit.Visual.Highlight,
1060
1061 __init__: function (element, /* optional */options) {
1062 this.element = MochiKit.DOM.getElement(element);
1063 options = MochiKit.Base.update({
1064 startcolor: '#ffff99'
1065 }, options || {});
1066 this.start(options);
1067 },
1068
1069 /** @id MochiKit.Visual.Highlight.prototype.setup */
1070 setup: function () {
1071 var b = MochiKit.Base;
1072 var s = MochiKit.Style;
1073 // Prevent executing on elements not in the layout flow
1074 if (s.getStyle(this.element, 'display') == 'none') {
1075 this.cancel();
1076 return;
1077 }
1078 // Disable background image during the effect
1079 this.oldStyle = {
1080 backgroundImage: s.getStyle(this.element, 'background-image')
1081 };
1082 s.setStyle(this.element, {
1083 backgroundImage: 'none'
1084 });
1085
1086 if (!this.options.endcolor) {
1087 this.options.endcolor =
1088 MochiKit.Color.Color.fromBackground(this.element).toHexString();
1089 }
1090 if (b.isUndefinedOrNull(this.options.restorecolor)) {
1091 this.options.restorecolor = s.getStyle(this.element,
1092 'background-color');
1093 }
1094 // init color calculations
1095 this._base = b.map(b.bind(function (i) {
1096 return parseInt(
1097 this.options.startcolor.slice(i*2 + 1, i*2 + 3), 16);
1098 }, this), [0, 1, 2]);
1099 this._delta = b.map(b.bind(function (i) {
1100 return parseInt(this.options.endcolor.slice(i*2 + 1, i*2 + 3), 16)
1101 - this._base[i];
1102 }, this), [0, 1, 2]);
1103 },
1104
1105 /** @id MochiKit.Visual.Highlight.prototype.update */
1106 update: function (position) {
1107 var m = '#';
1108 MochiKit.Base.map(MochiKit.Base.bind(function (i) {
1109 m += MochiKit.Color.toColorPart(Math.round(this._base[i] +
1110 this._delta[i]*position));
1111 }, this), [0, 1, 2]);
1112 MochiKit.Style.setStyle(this.element, {
1113 backgroundColor: m
1114 });
1115 },
1116
1117 /** @id MochiKit.Visual.Highlight.prototype.finish */
1118 finish: function () {
1119 MochiKit.Style.setStyle(this.element,
1120 MochiKit.Base.update(this.oldStyle, {
1121 backgroundColor: this.options.restorecolor
1122 }));
1123 }
1124});
1125
1126/** @id MochiKit.Visual.ScrollTo */
1127MochiKit.Visual.ScrollTo = function (element, options) {
1128 var cls = arguments.callee;
1129 if (!(this instanceof cls)) {
1130 return new cls(element, options);
1131 }
1132 this.__init__(element, options);
1133};
1134
1135MochiKit.Visual.ScrollTo.prototype = new MochiKit.Visual.Base();
1136
1137MochiKit.Base.update(MochiKit.Visual.ScrollTo.prototype, {
1138 /***
1139
1140 Scroll to an element in the page.
1141
1142 ***/
1143
1144 __class__ : MochiKit.Visual.ScrollTo,
1145
1146 __init__: function (element, /* optional */options) {
1147 this.element = MochiKit.DOM.getElement(element);
1148 this.start(options || {});
1149 },
1150
1151 /** @id MochiKit.Visual.ScrollTo.prototype.setup */
1152 setup: function () {
1153 var p = MochiKit.Position;
1154 p.prepare();
1155 var offsets = p.cumulativeOffset(this.element);
1156 if (this.options.offset) {
1157 offsets.y += this.options.offset;
1158 }
1159 var max;
1160 if (window.innerHeight) {
1161 max = window.innerHeight - window.height;
1162 } else if (document.documentElement &&
1163 document.documentElement.clientHeight) {
1164 max = document.documentElement.clientHeight -
1165 document.body.scrollHeight;
1166 } else if (document.body) {
1167 max = document.body.clientHeight - document.body.scrollHeight;
1168 }
1169 this.scrollStart = p.windowOffset.y;
1170 this.delta = (offsets.y > max ? max : offsets.y) - this.scrollStart;
1171 },
1172
1173 /** @id MochiKit.Visual.ScrollTo.prototype.update */
1174 update: function (position) {
1175 var p = MochiKit.Position;
1176 p.prepare();
1177 window.scrollTo(p.windowOffset.x, this.scrollStart + (position * this.delta));
1178 }
1179});
1180
1181MochiKit.Visual.CSS_LENGTH = /^(([\+\-]?[0-9\.]+)(em|ex|px|in|cm|mm|pt|pc|\%))|0$/;
1182
1183MochiKit.Visual.Morph = function (element, options) {
1184 var cls = arguments.callee;
1185 if (!(this instanceof cls)) {
1186 return new cls(element, options);
1187 }
1188 this.__init__(element, options);
1189};
1190
1191MochiKit.Visual.Morph.prototype = new MochiKit.Visual.Base();
1192
1193MochiKit.Base.update(MochiKit.Visual.Morph.prototype, {
1194 /***
1195
1196 Morph effect: make a transformation from current style to the given style,
1197 automatically making a transition between the two.
1198
1199 ***/
1200
1201 __class__ : MochiKit.Visual.Morph,
1202
1203 __init__: function (element, /* optional */options) {
1204 this.element = MochiKit.DOM.getElement(element);
1205 this.start(options || {});
1206 },
1207
1208 /** @id MochiKit.Visual.Morph.prototype.setup */
1209 setup: function () {
1210 var b = MochiKit.Base;
1211 var style = this.options.style;
1212 this.styleStart = {};
1213 this.styleEnd = {};
1214 this.units = {};
1215 var value, unit;
1216 for (var s in style) {
1217 value = style[s];
1218 s = b.camelize(s);
1219 if (MochiKit.Visual.CSS_LENGTH.test(value)) {
1220 var components = value.match(/^([\+\-]?[0-9\.]+)(.*)$/);
1221 value = parseFloat(components[1]);
1222 unit = (components.length == 3) ? components[2] : null;
1223 this.styleEnd[s] = value;
1224 this.units[s] = unit;
1225 value = MochiKit.Style.getStyle(this.element, s);
1226 components = value.match(/^([\+\-]?[0-9\.]+)(.*)$/);
1227 value = parseFloat(components[1]);
1228 this.styleStart[s] = value;
1229 } else {
1230 var c = MochiKit.Color.Color;
1231 value = c.fromString(value);
1232 if (value) {
1233 this.units[s] = "color";
1234 this.styleEnd[s] = value.toHexString();
1235 value = MochiKit.Style.getStyle(this.element, s);
1236 this.styleStart[s] = c.fromString(value).toHexString();
1237
1238 this.styleStart[s] = b.map(b.bind(function (i) {
1239 return parseInt(
1240 this.styleStart[s].slice(i*2 + 1, i*2 + 3), 16);
1241 }, this), [0, 1, 2]);
1242 this.styleEnd[s] = b.map(b.bind(function (i) {
1243 return parseInt(
1244 this.styleEnd[s].slice(i*2 + 1, i*2 + 3), 16);
1245 }, this), [0, 1, 2]);
1246 }
1247 }
1248 }
1249 },
1250
1251 /** @id MochiKit.Visual.Morph.prototype.update */
1252 update: function (position) {
1253 var value;
1254 for (var s in this.styleStart) {
1255 if (this.units[s] == "color") {
1256 var m = '#';
1257 var start = this.styleStart[s];
1258 var end = this.styleEnd[s];
1259 MochiKit.Base.map(MochiKit.Base.bind(function (i) {
1260 m += MochiKit.Color.toColorPart(Math.round(start[i] +
1261 (end[i] - start[i])*position));
1262 }, this), [0, 1, 2]);
1263 this.element.style[s] = m;
1264 } else {
1265 value = this.styleStart[s] + Math.round((this.styleEnd[s] - this.styleStart[s]) * position * 1000) / 1000 + this.units[s];
1266 this.element.style[s] = value;
1267 }
1268 }
1269 }
1270});
1271
1272/***
1273
1274Combination effects.
1275
1276***/
1277
1278/** @id MochiKit.Visual.fade */
1279MochiKit.Visual.fade = function (element, /* optional */ options) {
1280 /***
1281
1282 Fade a given element: change its opacity and hide it in the end.
1283
1284 @param options: 'to' and 'from' to change opacity.
1285
1286 ***/
1287 var s = MochiKit.Style;
1288 var oldOpacity = s.getStyle(element, 'opacity');
1289 options = MochiKit.Base.update({
1290 from: s.getStyle(element, 'opacity') || 1.0,
1291 to: 0.0,
1292 afterFinishInternal: function (effect) {
1293 if (effect.options.to !== 0) {
1294 return;
1295 }
1296 s.hideElement(effect.element);
1297 s.setStyle(effect.element, {'opacity': oldOpacity});
1298 }
1299 }, options || {});
1300 return new MochiKit.Visual.Opacity(element, options);
1301};
1302
1303/** @id MochiKit.Visual.appear */
1304MochiKit.Visual.appear = function (element, /* optional */ options) {
1305 /***
1306
1307 Make an element appear.
1308
1309 @param options: 'to' and 'from' to change opacity.
1310
1311 ***/
1312 var s = MochiKit.Style;
1313 var v = MochiKit.Visual;
1314 options = MochiKit.Base.update({
1315 from: (s.getStyle(element, 'display') == 'none' ? 0.0 :
1316 s.getStyle(element, 'opacity') || 0.0),
1317 to: 1.0,
1318 // force Safari to render floated elements properly
1319 afterFinishInternal: function (effect) {
1320 v.forceRerendering(effect.element);
1321 },
1322 beforeSetupInternal: function (effect) {
1323 s.setStyle(effect.element, {'opacity': effect.options.from});
1324 s.showElement(effect.element);
1325 }
1326 }, options || {});
1327 return new v.Opacity(element, options);
1328};
1329
1330/** @id MochiKit.Visual.puff */
1331MochiKit.Visual.puff = function (element, /* optional */ options) {
1332 /***
1333
1334 'Puff' an element: grow it to double size, fading it and make it hidden.
1335
1336 ***/
1337 var s = MochiKit.Style;
1338 var v = MochiKit.Visual;
1339 element = MochiKit.DOM.getElement(element);
1340 var oldStyle = {
1341 position: s.getStyle(element, 'position'),
1342 top: element.style.top,
1343 left: element.style.left,
1344 width: element.style.width,
1345 height: element.style.height,
1346 opacity: s.getStyle(element, 'opacity')
1347 };
1348 options = MochiKit.Base.update({
1349 beforeSetupInternal: function (effect) {
1350 MochiKit.Position.absolutize(effect.effects[0].element);
1351 },
1352 afterFinishInternal: function (effect) {
1353 s.hideElement(effect.effects[0].element);
1354 s.setStyle(effect.effects[0].element, oldStyle);
1355 },
1356 scaleContent: true,
1357 scaleFromCenter: true
1358 }, options || {});
1359 return new v.Parallel(
1360 [new v.Scale(element, 200,
1361 {sync: true, scaleFromCenter: options.scaleFromCenter,
1362 scaleContent: options.scaleContent, restoreAfterFinish: true}),
1363 new v.Opacity(element, {sync: true, to: 0.0 })],
1364 options);
1365};
1366
1367/** @id MochiKit.Visual.blindUp */
1368MochiKit.Visual.blindUp = function (element, /* optional */ options) {
1369 /***
1370
1371 Blind an element up: change its vertical size to 0.
1372
1373 ***/
1374 var d = MochiKit.DOM;
1375 element = d.getElement(element);
1376 var elemClip = d.makeClipping(element);
1377 options = MochiKit.Base.update({
1378 scaleContent: false,
1379 scaleX: false,
1380 restoreAfterFinish: true,
1381 afterFinishInternal: function (effect) {
1382 MochiKit.Style.hideElement(effect.element);
1383 d.undoClipping(effect.element, elemClip);
1384 }
1385 }, options || {});
1386
1387 return new MochiKit.Visual.Scale(element, 0, options);
1388};
1389
1390/** @id MochiKit.Visual.blindDown */
1391MochiKit.Visual.blindDown = function (element, /* optional */ options) {
1392 /***
1393
1394 Blind an element down: restore its vertical size.
1395
1396 ***/
1397 var d = MochiKit.DOM;
1398 var s = MochiKit.Style;
1399 element = d.getElement(element);
1400 var elementDimensions = s.getElementDimensions(element);
1401 var elemClip;
1402 options = MochiKit.Base.update({
1403 scaleContent: false,
1404 scaleX: false,
1405 scaleFrom: 0,
1406 scaleMode: {originalHeight: elementDimensions.h,
1407 originalWidth: elementDimensions.w},
1408 restoreAfterFinish: true,
1409 afterSetupInternal: function (effect) {
1410 elemClip = d.makeClipping(effect.element);
1411 s.setStyle(effect.element, {height: '0px'});
1412 s.showElement(effect.element);
1413 },
1414 afterFinishInternal: function (effect) {
1415 d.undoClipping(effect.element, elemClip);
1416 }
1417 }, options || {});
1418 return new MochiKit.Visual.Scale(element, 100, options);
1419};
1420
1421/** @id MochiKit.Visual.switchOff */
1422MochiKit.Visual.switchOff = function (element, /* optional */ options) {
1423 /***
1424
1425 Apply a switch-off-like effect.
1426
1427 ***/
1428 var d = MochiKit.DOM;
1429 element = d.getElement(element);
1430 var oldOpacity = MochiKit.Style.getStyle(element, 'opacity');
1431 var elemClip;
1432 options = MochiKit.Base.update({
1433 duration: 0.3,
1434 scaleFromCenter: true,
1435 scaleX: false,
1436 scaleContent: false,
1437 restoreAfterFinish: true,
1438 beforeSetupInternal: function (effect) {
1439 d.makePositioned(effect.element);
1440 elemClip = d.makeClipping(effect.element);
1441 },
1442 afterFinishInternal: function (effect) {
1443 MochiKit.Style.hideElement(effect.element);
1444 d.undoClipping(effect.element, elemClip);
1445 d.undoPositioned(effect.element);
1446 MochiKit.Style.setStyle(effect.element, {'opacity': oldOpacity});
1447 }
1448 }, options || {});
1449 var v = MochiKit.Visual;
1450 return new v.appear(element, {
1451 duration: 0.4,
1452 from: 0,
1453 transition: v.Transitions.flicker,
1454 afterFinishInternal: function (effect) {
1455 new v.Scale(effect.element, 1, options);
1456 }
1457 });
1458};
1459
1460/** @id MochiKit.Visual.dropOut */
1461MochiKit.Visual.dropOut = function (element, /* optional */ options) {
1462 /***
1463
1464 Make an element fall and disappear.
1465
1466 ***/
1467 var d = MochiKit.DOM;
1468 var s = MochiKit.Style;
1469 element = d.getElement(element);
1470 var oldStyle = {
1471 top: s.getStyle(element, 'top'),
1472 left: s.getStyle(element, 'left'),
1473 opacity: s.getStyle(element, 'opacity')
1474 };
1475
1476 options = MochiKit.Base.update({
1477 duration: 0.5,
1478 distance: 100,
1479 beforeSetupInternal: function (effect) {
1480 d.makePositioned(effect.effects[0].element);
1481 },
1482 afterFinishInternal: function (effect) {
1483 s.hideElement(effect.effects[0].element);
1484 d.undoPositioned(effect.effects[0].element);
1485 s.setStyle(effect.effects[0].element, oldStyle);
1486 }
1487 }, options || {});
1488 var v = MochiKit.Visual;
1489 return new v.Parallel(
1490 [new v.Move(element, {x: 0, y: options.distance, sync: true}),
1491 new v.Opacity(element, {sync: true, to: 0.0})],
1492 options);
1493};
1494
1495/** @id MochiKit.Visual.shake */
1496MochiKit.Visual.shake = function (element, /* optional */ options) {
1497 /***
1498
1499 Move an element from left to right several times.
1500
1501 ***/
1502 var d = MochiKit.DOM;
1503 var v = MochiKit.Visual;
1504 var s = MochiKit.Style;
1505 element = d.getElement(element);
1506 options = MochiKit.Base.update({
1507 x: -20,
1508 y: 0,
1509 duration: 0.05,
1510 afterFinishInternal: function (effect) {
1511 d.undoPositioned(effect.element);
1512 s.setStyle(effect.element, oldStyle);
1513 }
1514 }, options || {});
1515 var oldStyle = {
1516 top: s.getStyle(element, 'top'),
1517 left: s.getStyle(element, 'left') };
1518 return new v.Move(element,
1519 {x: 20, y: 0, duration: 0.05, afterFinishInternal: function (effect) {
1520 new v.Move(effect.element,
1521 {x: -40, y: 0, duration: 0.1, afterFinishInternal: function (effect) {
1522 new v.Move(effect.element,
1523 {x: 40, y: 0, duration: 0.1, afterFinishInternal: function (effect) {
1524 new v.Move(effect.element,
1525 {x: -40, y: 0, duration: 0.1, afterFinishInternal: function (effect) {
1526 new v.Move(effect.element,
1527 {x: 40, y: 0, duration: 0.1, afterFinishInternal: function (effect) {
1528 new v.Move(effect.element, options
1529 ) }}) }}) }}) }}) }});
1530};
1531
1532/** @id MochiKit.Visual.slideDown */
1533MochiKit.Visual.slideDown = function (element, /* optional */ options) {
1534 /***
1535
1536 Slide an element down.
1537 It needs to have the content of the element wrapped in a container
1538 element with fixed height.
1539
1540 ***/
1541 var d = MochiKit.DOM;
1542 var b = MochiKit.Base;
1543 var s = MochiKit.Style;
1544 element = d.getElement(element);
1545 if (!element.firstChild) {
1546 throw "MochiKit.Visual.slideDown must be used on a element with a child";
1547 }
1548 d.removeEmptyTextNodes(element);
1549 var oldInnerBottom = s.getStyle(element.firstChild, 'bottom') || 0;
1550 var elementDimensions = s.getElementDimensions(element);
1551 var elemClip;
1552 options = b.update({
1553 scaleContent: false,
1554 scaleX: false,
1555 scaleFrom: 0,
1556 scaleMode: {originalHeight: elementDimensions.h,
1557 originalWidth: elementDimensions.w},
1558 restoreAfterFinish: true,
1559 afterSetupInternal: function (effect) {
1560 d.makePositioned(effect.element);
1561 d.makePositioned(effect.element.firstChild);
1562 if (/Opera/.test(navigator.userAgent)) {
1563 s.setStyle(effect.element, {top: ''});
1564 }
1565 elemClip = d.makeClipping(effect.element);
1566 s.setStyle(effect.element, {height: '0px'});
1567 s.showElement(effect.element);
1568 },
1569 afterUpdateInternal: function (effect) {
1570 s.setStyle(effect.element.firstChild,
1571 {bottom: (effect.dims[0] - effect.element.clientHeight) + 'px'});
1572 },
1573 afterFinishInternal: function (effect) {
1574 d.undoClipping(effect.element, elemClip);
1575 // IE will crash if child is undoPositioned first
1576 if (/MSIE/.test(navigator.userAgent)) {
1577 d.undoPositioned(effect.element);
1578 d.undoPositioned(effect.element.firstChild);
1579 } else {
1580 d.undoPositioned(effect.element.firstChild);
1581 d.undoPositioned(effect.element);
1582 }
1583 s.setStyle(effect.element.firstChild,
1584 {bottom: oldInnerBottom});
1585 }
1586 }, options || {});
1587
1588 return new MochiKit.Visual.Scale(element, 100, options);
1589};
1590
1591/** @id MochiKit.Visual.slideUp */
1592MochiKit.Visual.slideUp = function (element, /* optional */ options) {
1593 /***
1594
1595 Slide an element up.
1596 It needs to have the content of the element wrapped in a container
1597 element with fixed height.
1598
1599 ***/
1600 var d = MochiKit.DOM;
1601 var b = MochiKit.Base;
1602 var s = MochiKit.Style;
1603 element = d.getElement(element);
1604 if (!element.firstChild) {
1605 throw "MochiKit.Visual.slideUp must be used on a element with a child";
1606 }
1607 d.removeEmptyTextNodes(element);
1608 var oldInnerBottom = s.getStyle(element.firstChild, 'bottom');
1609 var elemClip;
1610 options = b.update({
1611 scaleContent: false,
1612 scaleX: false,
1613 scaleMode: 'box',
1614 scaleFrom: 100,
1615 restoreAfterFinish: true,
1616 beforeStartInternal: function (effect) {
1617 d.makePositioned(effect.element);
1618 d.makePositioned(effect.element.firstChild);
1619 if (/Opera/.test(navigator.userAgent)) {
1620 s.setStyle(effect.element, {top: ''});
1621 }
1622 elemClip = d.makeClipping(effect.element);
1623 s.showElement(effect.element);
1624 },
1625 afterUpdateInternal: function (effect) {
1626 s.setStyle(effect.element.firstChild,
1627 {bottom: (effect.dims[0] - effect.element.clientHeight) + 'px'});
1628 },
1629 afterFinishInternal: function (effect) {
1630 s.hideElement(effect.element);
1631 d.undoClipping(effect.element, elemClip);
1632 d.undoPositioned(effect.element.firstChild);
1633 d.undoPositioned(effect.element);
1634 s.setStyle(effect.element.firstChild, {bottom: oldInnerBottom});
1635 }
1636 }, options || {});
1637 return new MochiKit.Visual.Scale(element, 0, options);
1638};
1639
1640// Bug in opera makes the TD containing this element expand for a instance
1641// after finish
1642/** @id MochiKit.Visual.squish */
1643MochiKit.Visual.squish = function (element, /* optional */ options) {
1644 /***
1645
1646 Reduce an element and make it disappear.
1647
1648 ***/
1649 var d = MochiKit.DOM;
1650 var b = MochiKit.Base;
1651 var elemClip;
1652 options = b.update({
1653 restoreAfterFinish: true,
1654 beforeSetupInternal: function (effect) {
1655 elemClip = d.makeClipping(effect.element);
1656 },
1657 afterFinishInternal: function (effect) {
1658 MochiKit.Style.hideElement(effect.element);
1659 d.undoClipping(effect.element, elemClip);
1660 }
1661 }, options || {});
1662
1663 return new MochiKit.Visual.Scale(element, /Opera/.test(navigator.userAgent) ? 1 : 0, options);
1664};
1665
1666/** @id MochiKit.Visual.grow */
1667MochiKit.Visual.grow = function (element, /* optional */ options) {
1668 /***
1669
1670 Grow an element to its original size. Make it zero-sized before
1671 if necessary.
1672
1673 ***/
1674 var d = MochiKit.DOM;
1675 var v = MochiKit.Visual;
1676 var s = MochiKit.Style;
1677 element = d.getElement(element);
1678 options = MochiKit.Base.update({
1679 direction: 'center',
1680 moveTransition: v.Transitions.sinoidal,
1681 scaleTransition: v.Transitions.sinoidal,
1682 opacityTransition: v.Transitions.full,
1683 scaleContent: true,
1684 scaleFromCenter: false
1685 }, options || {});
1686 var oldStyle = {
1687 top: element.style.top,
1688 left: element.style.left,
1689 height: element.style.height,
1690 width: element.style.width,
1691 opacity: s.getStyle(element, 'opacity')
1692 };
1693
1694 var dims = s.getElementDimensions(element);
1695 var initialMoveX, initialMoveY;
1696 var moveX, moveY;
1697
1698 switch (options.direction) {
1699 case 'top-left':
1700 initialMoveX = initialMoveY = moveX = moveY = 0;
1701 break;
1702 case 'top-right':
1703 initialMoveX = dims.w;
1704 initialMoveY = moveY = 0;
1705 moveX = -dims.w;
1706 break;
1707 case 'bottom-left':
1708 initialMoveX = moveX = 0;
1709 initialMoveY = dims.h;
1710 moveY = -dims.h;
1711 break;
1712 case 'bottom-right':
1713 initialMoveX = dims.w;
1714 initialMoveY = dims.h;
1715 moveX = -dims.w;
1716 moveY = -dims.h;
1717 break;
1718 case 'center':
1719 initialMoveX = dims.w / 2;
1720 initialMoveY = dims.h / 2;
1721 moveX = -dims.w / 2;
1722 moveY = -dims.h / 2;
1723 break;
1724 }
1725
1726 var optionsParallel = MochiKit.Base.update({
1727 beforeSetupInternal: function (effect) {
1728 s.setStyle(effect.effects[0].element, {height: '0px'});
1729 s.showElement(effect.effects[0].element);
1730 },
1731 afterFinishInternal: function (effect) {
1732 d.undoClipping(effect.effects[0].element);
1733 d.undoPositioned(effect.effects[0].element);
1734 s.setStyle(effect.effects[0].element, oldStyle);
1735 }
1736 }, options || {});
1737
1738 return new v.Move(element, {
1739 x: initialMoveX,
1740 y: initialMoveY,
1741 duration: 0.01,
1742 beforeSetupInternal: function (effect) {
1743 s.hideElement(effect.element);
1744 d.makeClipping(effect.element);
1745 d.makePositioned(effect.element);
1746 },
1747 afterFinishInternal: function (effect) {
1748 new v.Parallel(
1749 [new v.Opacity(effect.element, {
1750 sync: true, to: 1.0, from: 0.0,
1751 transition: options.opacityTransition
1752 }),
1753 new v.Move(effect.element, {
1754 x: moveX, y: moveY, sync: true,
1755 transition: options.moveTransition
1756 }),
1757 new v.Scale(effect.element, 100, {
1758 scaleMode: {originalHeight: dims.h,
1759 originalWidth: dims.w},
1760 sync: true,
1761 scaleFrom: /Opera/.test(navigator.userAgent) ? 1 : 0,
1762 transition: options.scaleTransition,
1763 scaleContent: options.scaleContent,
1764 scaleFromCenter: options.scaleFromCenter,
1765 restoreAfterFinish: true
1766 })
1767 ], optionsParallel
1768 );
1769 }
1770 });
1771};
1772
1773/** @id MochiKit.Visual.shrink */
1774MochiKit.Visual.shrink = function (element, /* optional */ options) {
1775 /***
1776
1777 Shrink an element and make it disappear.
1778
1779 ***/
1780 var d = MochiKit.DOM;
1781 var v = MochiKit.Visual;
1782 var s = MochiKit.Style;
1783 element = d.getElement(element);
1784 options = MochiKit.Base.update({
1785 direction: 'center',
1786 moveTransition: v.Transitions.sinoidal,
1787 scaleTransition: v.Transitions.sinoidal,
1788 opacityTransition: v.Transitions.none,
1789 scaleContent: true,
1790 scaleFromCenter: false
1791 }, options || {});
1792 var oldStyle = {
1793 top: element.style.top,
1794 left: element.style.left,
1795 height: element.style.height,
1796 width: element.style.width,
1797 opacity: s.getStyle(element, 'opacity')
1798 };
1799
1800 var dims = s.getElementDimensions(element);
1801 var moveX, moveY;
1802
1803 switch (options.direction) {
1804 case 'top-left':
1805 moveX = moveY = 0;
1806 break;
1807 case 'top-right':
1808 moveX = dims.w;
1809 moveY = 0;
1810 break;
1811 case 'bottom-left':
1812 moveX = 0;
1813 moveY = dims.h;
1814 break;
1815 case 'bottom-right':
1816 moveX = dims.w;
1817 moveY = dims.h;
1818 break;
1819 case 'center':
1820 moveX = dims.w / 2;
1821 moveY = dims.h / 2;
1822 break;
1823 }
1824 var elemClip;
1825
1826 var optionsParallel = MochiKit.Base.update({
1827 beforeStartInternal: function (effect) {
1828 elemClip = d.makePositioned(effect.effects[0].element);
1829 d.makeClipping(effect.effects[0].element);
1830 },
1831 afterFinishInternal: function (effect) {
1832 s.hideElement(effect.effects[0].element);
1833 d.undoClipping(effect.effects[0].element, elemClip);
1834 d.undoPositioned(effect.effects[0].element);
1835 s.setStyle(effect.effects[0].element, oldStyle);
1836 }
1837 }, options || {});
1838
1839 return new v.Parallel(
1840 [new v.Opacity(element, {
1841 sync: true, to: 0.0, from: 1.0,
1842 transition: options.opacityTransition
1843 }),
1844 new v.Scale(element, /Opera/.test(navigator.userAgent) ? 1 : 0, {
1845 sync: true, transition: options.scaleTransition,
1846 scaleContent: options.scaleContent,
1847 scaleFromCenter: options.scaleFromCenter,
1848 restoreAfterFinish: true
1849 }),
1850 new v.Move(element, {
1851 x: moveX, y: moveY, sync: true, transition: options.moveTransition
1852 })
1853 ], optionsParallel
1854 );
1855};
1856
1857/** @id MochiKit.Visual.pulsate */
1858MochiKit.Visual.pulsate = function (element, /* optional */ options) {
1859 /***
1860
1861 Pulse an element between appear/fade.
1862
1863 ***/
1864 var d = MochiKit.DOM;
1865 var v = MochiKit.Visual;
1866 var b = MochiKit.Base;
1867 var oldOpacity = MochiKit.Style.getStyle(element, 'opacity');
1868 options = b.update({
1869 duration: 3.0,
1870 from: 0,
1871 afterFinishInternal: function (effect) {
1872 MochiKit.Style.setStyle(effect.element, {'opacity': oldOpacity});
1873 }
1874 }, options || {});
1875 var transition = options.transition || v.Transitions.sinoidal;
1876 var reverser = b.bind(function (pos) {
1877 return transition(1 - v.Transitions.pulse(pos));
1878 }, transition);
1879 b.bind(reverser, transition);
1880 return new v.Opacity(element, b.update({
1881 transition: reverser}, options));
1882};
1883
1884/** @id MochiKit.Visual.fold */
1885MochiKit.Visual.fold = function (element, /* optional */ options) {
1886 /***
1887
1888 Fold an element, first vertically, then horizontally.
1889
1890 ***/
1891 var d = MochiKit.DOM;
1892 var v = MochiKit.Visual;
1893 var s = MochiKit.Style;
1894 element = d.getElement(element);
1895 var oldStyle = {
1896 top: element.style.top,
1897 left: element.style.left,
1898 width: element.style.width,
1899 height: element.style.height
1900 };
1901 var elemClip = d.makeClipping(element);
1902 options = MochiKit.Base.update({
1903 scaleContent: false,
1904 scaleX: false,
1905 afterFinishInternal: function (effect) {
1906 new v.Scale(element, 1, {
1907 scaleContent: false,
1908 scaleY: false,
1909 afterFinishInternal: function (effect) {
1910 s.hideElement(effect.element);
1911 d.undoClipping(effect.element, elemClip);
1912 s.setStyle(effect.element, oldStyle);
1913 }
1914 });
1915 }
1916 }, options || {});
1917 return new v.Scale(element, 5, options);
1918};
1919
1920
1921// Compatibility with MochiKit 1.0
1922MochiKit.Visual.Color = MochiKit.Color.Color;
1923MochiKit.Visual.getElementsComputedStyle = MochiKit.DOM.computedStyle;
1924
1925/* end of Rico adaptation */
1926
1927MochiKit.Visual.__new__ = function () {
1928 var m = MochiKit.Base;
1929
1930 m.nameFunctions(this);
1931
1932 this.EXPORT_TAGS = {
1933 ":common": this.EXPORT,
1934 ":all": m.concat(this.EXPORT, this.EXPORT_OK)
1935 };
1936
1937};
1938
1939MochiKit.Visual.EXPORT = [
1940 "roundElement",
1941 "roundClass",
1942 "tagifyText",
1943 "multiple",
1944 "toggle",
1945 "Parallel",
1946 "Opacity",
1947 "Move",
1948 "Scale",
1949 "Highlight",
1950 "ScrollTo",
1951 "Morph",
1952 "fade",
1953 "appear",
1954 "puff",
1955 "blindUp",
1956 "blindDown",
1957 "switchOff",
1958 "dropOut",
1959 "shake",
1960 "slideDown",
1961 "slideUp",
1962 "squish",
1963 "grow",
1964 "shrink",
1965 "pulsate",
1966 "fold"
1967];
1968
1969MochiKit.Visual.EXPORT_OK = [
1970 "Base",
1971 "PAIRS"
1972];
1973
1974MochiKit.Visual.__new__();
1975
1976MochiKit.Base._exportSymbols(this, MochiKit.Visual);
diff --git a/frontend/beta/js/MochiKit/__package__.js b/frontend/beta/js/MochiKit/__package__.js
new file mode 100644
index 0000000..8d644b1
--- a/dev/null
+++ b/frontend/beta/js/MochiKit/__package__.js
@@ -0,0 +1,18 @@
1dojo.kwCompoundRequire({
2 "common": [
3 "MochiKit.Base",
4 "MochiKit.Iter",
5 "MochiKit.Logging",
6 "MochiKit.DateTime",
7 "MochiKit.Format",
8 "MochiKit.Async",
9 "MochiKit.DOM",
10 "MochiKit.Style",
11 "MochiKit.LoggingPane",
12 "MochiKit.Color",
13 "MochiKit.Signal",
14 "MochiKit.Position",
15 "MochiKit.Visual"
16 ]
17});
18dojo.provide("MochiKit.*");
diff --git a/frontend/beta/js/YUI-extensions/Bench.js b/frontend/beta/js/YUI-extensions/Bench.js
new file mode 100644
index 0000000..6921131
--- a/dev/null
+++ b/frontend/beta/js/YUI-extensions/Bench.js
@@ -0,0 +1,40 @@
1// @deprecated
2// Use YAHOO.timer() instead
3YAHOO.ext.util.Bench = function(){
4 this.timers = {};
5 this.lastKey = null;
6};
7YAHOO.ext.util.Bench.prototype = {
8 start : function(key){
9 this.lastKey = key;
10 this.timers[key] = {};
11 this.timers[key].startTime = new Date().getTime();
12 },
13
14 stop : function(key){
15 key = key || this.lastKey;
16 this.timers[key].endTime = new Date().getTime();
17 },
18
19 getElapsed : function(key){
20 key = key || this.lastKey;
21 return this.timers[key].endTime - this.timers[key].startTime;
22 },
23
24 toString : function(html){
25 var results = "";
26 for(var key in this.timers){
27 if(typeof this.timers[key] != 'function'){
28 results += key + ":\t" + (this.getElapsed(key) / 1000) + " seconds\n";
29 }
30 }
31 if(html){
32 results = results.replace("\n", '<br>');
33 }
34 return results;
35 },
36
37 show : function(){
38 alert(this.toString());
39 }
40};
diff --git a/frontend/beta/js/YUI-extensions/CSS.js b/frontend/beta/js/YUI-extensions/CSS.js
new file mode 100644
index 0000000..4fba37c
--- a/dev/null
+++ b/frontend/beta/js/YUI-extensions/CSS.js
@@ -0,0 +1,208 @@
1/**
2 * @class YAHOO.ext.util.CSS
3 * Class for manipulating CSS Rules
4 * @singleton
5 */
6YAHOO.ext.util.CSS = new function(){
7 var rules = null;
8
9 var toCamel = function(property) {
10 var convert = function(prop) {
11 var test = /(-[a-z])/i.exec(prop);
12 return prop.replace(RegExp.$1, RegExp.$1.substr(1).toUpperCase());
13 };
14 while(property.indexOf('-') > -1) {
15 property = convert(property);
16 }
17 return property;
18 };
19
20 /**
21 * Very simple dynamic creation of stylesheets from a text blob of rules.
22 * @param {String} cssText The text containing the css rules
23 * @return {StyleSheet}
24 */
25 this.createStyleSheet = function(cssText){
26 var ss;
27 if(YAHOO.ext.util.Browser.isIE){
28 ss = document.createStyleSheet();
29 ss.cssText = cssText;
30 }else{
31 var head = document.getElementsByTagName("head")[0];
32 var rules = document.createElement('style');
33 rules.setAttribute('type', 'text/css');
34 try{
35 rules.appendChild(document.createTextNode(cssText));
36 }catch(e){
37 rules.cssText = cssText;
38 }
39 head.appendChild(rules);
40 ss = document.styleSheets[document.styleSheets.length-1];
41 }
42 this.cacheStyleSheet(ss);
43 return ss;
44 };
45
46 this.removeStyleSheet = function(id){
47 var existing = document.getElementById(id);
48 if(existing){
49 existing.parentNode.removeChild(existing);
50 }
51 };
52
53 this.swapStyleSheet = function(id, url){
54 this.removeStyleSheet(id);
55 var ss = document.createElement('link');
56 ss.setAttribute('rel', 'stylesheet');
57 ss.setAttribute('type', 'text/css');
58 ss.setAttribute('id', id);
59 ss.setAttribute('href', url);
60 document.getElementsByTagName("head")[0].appendChild(ss);
61 };
62
63 /**
64 * Refresh the rule cache if you have dynamically added stylesheets
65 * @return {Object} An object (hash) of rules indexed by selector
66 */
67 this.refreshCache = function(){
68 return this.getRules(true);
69 };
70
71 this.cacheStyleSheet = function(ss){
72 try{// try catch for cross domain access issue
73 var ssRules = ss.cssRules || ss.rules;
74 for(var j = ssRules.length-1; j >= 0; --j){
75 rules[ssRules[j].selectorText] = ssRules[j];
76 }
77 }catch(e){}
78 };
79
80 /**
81 * Gets all css rules for the document
82 * @param {Boolean} refreshCache true to refresh the internal cache
83 * @return {Object} An object (hash) of rules indexed by selector
84 */
85 this.getRules = function(refreshCache){
86 if(rules == null || refreshCache){
87 rules = {};
88 var ds = document.styleSheets;
89 for(var i =0, len = ds.length; i < len; i++){
90 try{
91 this.cacheStyleSheet(ds[i]);
92 }catch(e){}
93 }
94 }
95 return rules;
96 };
97
98 /**
99 * Gets an an individual CSS rule by selector(s)
100 * @param {String/Array} selector The CSS selector or an array of selectors to try. The first selector that is found is returned.
101 * @param {Boolean} refreshCache true to refresh the internal cache
102 * @return {CSSRule} The CSS rule or null if one is not found
103 */
104 this.getRule = function(selector, refreshCache){
105 var rs = this.getRules(refreshCache);
106 if(!(selector instanceof Array)){
107 return rs[selector];
108 }
109 for(var i = 0; i < selector.length; i++){
110 if(rs[selector[i]]){
111 return rs[selector[i]];
112 }
113 }
114 return null;
115 };
116
117
118 /**
119 * Updates a rule property
120 * @param {String/Array} selector If it's an array it tries each selector until it finds one. Stops immediately once one is found.
121 * @param {String} property The css property
122 * @param {String} value The new value for the property
123 * @return {Boolean} true if a rule was found and updated
124 */
125 this.updateRule = function(selector, property, value){
126 if(!(selector instanceof Array)){
127 var rule = this.getRule(selector);
128 if(rule){
129 rule.style[toCamel(property)] = value;
130 return true;
131 }
132 }else{
133 for(var i = 0; i < selector.length; i++){
134 if(this.updateRule(selector[i], property, value)){
135 return true;
136 }
137 }
138 }
139 return false;
140 };
141
142 /**
143 * Applies a rule to an element without adding the class
144 * @param {HTMLElement} el The element
145 * @param {String/Array} selector If it's an array it tries each selector until it finds one. Stops immediately once one is found.
146 * @return {Boolean} true if a rule was found and applied
147 */
148 this.apply = function(el, selector){
149 if(!(selector instanceof Array)){
150 var rule = this.getRule(selector);
151 if(rule){
152 var s = rule.style;
153 for(var key in s){
154 if(typeof s[key] != 'function'){
155 if(s[key] && String(s[key]).indexOf(':') < 0 && s[key] != 'false'){
156 try{el.style[key] = s[key];}catch(e){}
157 }
158 }
159 }
160 return true;
161 }
162 }else{
163 for(var i = 0; i < selector.length; i++){
164 if(this.apply(el, selector[i])){
165 return true;
166 }
167 }
168 }
169 return false;
170 };
171
172 this.applyFirst = function(el, id, selector){
173 var selectors = [
174 '#' + id + ' ' + selector,
175 selector
176 ];
177 return this.apply(el, selectors);
178 };
179
180 this.revert = function(el, selector){
181 if(!(selector instanceof Array)){
182 var rule = this.getRule(selector);
183 if(rule){
184 for(key in rule.style){
185 if(rule.style[key] && String(rule.style[key]).indexOf(':') < 0 && rule.style[key] != 'false'){
186 try{el.style[key] = '';}catch(e){}
187 }
188 }
189 return true;
190 }
191 }else{
192 for(var i = 0; i < selector.length; i++){
193 if(this.revert(el, selector[i])){
194 return true;
195 }
196 }
197 }
198 return false;
199 };
200
201 this.revertFirst = function(el, id, selector){
202 var selectors = [
203 '#' + id + ' ' + selector,
204 selector
205 ];
206 return this.revert(el, selectors);
207 };
208}();
diff --git a/frontend/beta/js/YUI-extensions/CompositeElement.js b/frontend/beta/js/YUI-extensions/CompositeElement.js
new file mode 100644
index 0000000..7b9c875
--- a/dev/null
+++ b/frontend/beta/js/YUI-extensions/CompositeElement.js
@@ -0,0 +1,140 @@
1/**
2 * @class YAHOO.ext.CompositeElement
3 * Standard composite class. Creates a YAHOO.ext.Element for every element in the collection.
4 * <br><br>
5 * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of YAHOO.ext.Element. All YAHOO.ext.Element
6 * actions will be performed on all the elements in this collection.</b>
7 * <br><br>
8 * All methods return <i>this</i> and can be chained.
9 <pre><code>
10 var els = getEls('#some-el div.some-class');
11 // or
12 var els = YAHOO.ext.Element.select('#some-el div.some-class');
13 els.setWidth(100); // all elements become 100 width
14 els.hide(true); // all elements fade out and hide
15 // or
16 els.setWidth(100).hide(true);
17 </code></pre>
18 */
19YAHOO.ext.CompositeElement = function(els){
20 this.elements = [];
21 this.addElements(els);
22};
23YAHOO.ext.CompositeElement.prototype = {
24 isComposite: true,
25 addElements : function(els){
26 if(!els) return this;
27 var yels = this.elements;
28 var index = yels.length-1;
29 for(var i = 0, len = els.length; i < len; i++) {
30 yels[++index] = getEl(els[i], true);
31 }
32 return this;
33 },
34 invoke : function(fn, args){
35 var els = this.elements;
36 for(var i = 0, len = els.length; i < len; i++) {
37 YAHOO.ext.Element.prototype[fn].apply(els[i], args);
38 }
39 return this;
40 },
41 /**
42 * Adds elements to this composite.
43 * @param {String/Array} els A string CSS selector, an array of elements or an element
44 * @return {CompositeElement} this
45 */
46 add : function(els){
47 if(typeof els == 'string'){
48 this.addElements(YAHOO.ext.Element.selectorFunction(string));
49 }else if(els instanceof Array){
50 this.addElements(els);
51 }else{
52 this.addElements([els]);
53 }
54 return this;
55 },
56 /**
57 * Calls the passed function passing (el, this, index) for each element in this composite.
58 * @param {Function} fn The function to call
59 * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
60 * @return {CompositeElement} this
61 */
62 each : function(fn, scope){
63 var els = this.elements;
64 for(var i = 0, len = els.length; i < len; i++){
65 fn.call(scope || els[i], els[i], this, i);
66 }
67 return this;
68 }
69};
70/**
71 * @class YAHOO.ext.CompositeElementLite
72 * @extends YAHOO.ext.CompositeElement
73 * Flyweight composite class. Reuses the same YAHOO.ext.Element for element operations.
74 * <br><br>
75 * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of YAHOO.ext.Element. All YAHOO.ext.Element
76 * actions will be performed on all the elements in this collection.</b>
77 */
78YAHOO.ext.CompositeElementLite = function(els){
79 YAHOO.ext.CompositeElementLite.superclass.constructor.call(this, els);
80 this.el = YAHOO.ext.Element.get(this.elements[0], true);
81};
82YAHOO.extendX(YAHOO.ext.CompositeElementLite, YAHOO.ext.CompositeElement, {
83 addElements : function(els){
84 if(els){
85 this.elements = this.elements.concat(els);
86 }
87 return this;
88 },
89 invoke : function(fn, args){
90 var els = this.elements;
91 var el = this.el;
92 for(var i = 0, len = els.length; i < len; i++) {
93 el.dom = els[i];
94 YAHOO.ext.Element.prototype[fn].apply(el, args);
95 }
96 return this;
97 }
98});
99YAHOO.ext.CompositeElement.createCall = function(proto, fnName){
100 if(!proto[fnName]){
101 proto[fnName] = function(){
102 return this.invoke(fnName, arguments);
103 };
104 }
105};
106for(var fnName in YAHOO.ext.Element.prototype){
107 if(typeof YAHOO.ext.Element.prototype[fnName] == 'function'){
108 YAHOO.ext.CompositeElement.createCall(YAHOO.ext.CompositeElement.prototype, fnName);
109 }
110}
111if(typeof cssQuery == 'function'){// Dean Edwards cssQuery
112 YAHOO.ext.Element.selectorFunction = cssQuery;
113}else if(typeof document.getElementsBySelector == 'function'){ // Simon Willison's getElementsBySelector
114 YAHOO.ext.Element.selectorFunction = document.getElementsBySelector.createDelegate(document);
115}
116/**
117 * @member YAHOO.ext.Element
118* Selects elements based on the passed CSS selector to enable working on them as 1.
119* @param {String/Array} selector The CSS selector or an array of elements
120* @param {Boolean} unique (optional) true to create a unique YAHOO.ext.Element for each element (defaults to a shared flyweight object)
121* @return {CompositeElementLite/CompositeElement}
122* @method @static
123*/
124YAHOO.ext.Element.select = function(selector, unique){
125 var els;
126 if(typeof selector == 'string'){
127 els = YAHOO.ext.Element.selectorFunction(selector);
128 }else if(selector instanceof Array){
129 els = selector;
130 }else{
131 throw 'Invalid selector';
132 }
133 if(unique === true){
134 return new YAHOO.ext.CompositeElement(els);
135 }else{
136 return new YAHOO.ext.CompositeElementLite(els);
137 }
138};
139
140var getEls = YAHOO.ext.Element.select;
diff --git a/frontend/beta/js/YUI-extensions/CustomTagReader.js b/frontend/beta/js/YUI-extensions/CustomTagReader.js
new file mode 100644
index 0000000..12faaa9
--- a/dev/null
+++ b/frontend/beta/js/YUI-extensions/CustomTagReader.js
@@ -0,0 +1,40 @@
1/**
2 * @class YAHOO.ext.CustomTagReader
3 * Utility class to normalize reading of custom tags across browsers.
4 */
5YAHOO.ext.CustomTagReader = function(namespace){
6 this.namespace = namespace;
7};
8YAHOO.ext.CustomTagReader.prototype = {
9 getAttribute : function(el, name, defaultValue){
10 return (this.useNS ?
11 v = el.getAttributeNS(this.namespace, name) : null) ||
12 el.getAttribute(this.namespace+':'+name) ||
13 el.getAttribute(name);
14 },
15
16 getElements : function(tagName, targetEl){
17 targetEl = targetEl || document.body;
18 var els;
19 if(this.useNS){ // no namespaces in IE
20 els = targetEl.getElementsByTagNameNS(this.namespace, tagName);
21 }
22 if(!els || els.length < 1){ // ie6, firefox 1.5, firefox 2 depending on doc type
23 els = targetEl.getElementsByTagName(this.namespace+':'+tagName);
24 }
25 if(!els || els.length < 1){ // everyone else
26 els = targetEl.getElementsByTagName(tagName);
27 }
28 return els;
29 },
30
31 eachElement : function(tagName, targetEl, fn, scope){
32 var els = this.getElements(tagName, targetEl);
33 for(var i = 0, len = els.length; i < len; i++) {
34 var el = els[i];
35 fn.call(scope || el, el);
36 }
37 },
38
39 useNS : (!YAHOO.ext.util.Browser.isIE && document.getElementsByTagNameNS) ? true : false
40};
diff --git a/frontend/beta/js/YUI-extensions/Date.js b/frontend/beta/js/YUI-extensions/Date.js
new file mode 100644
index 0000000..f79c8a5
--- a/dev/null
+++ b/frontend/beta/js/YUI-extensions/Date.js
@@ -0,0 +1,407 @@
1/*
2 * All the Date functions below are the excellent work of Baron Schwartz
3 * They generate precompiled functions from date formats instead of parsing and processing
4 * the format everytime you do something with a date.
5 */
6/** @ignore */
7Date.parseFunctions = {count:0};
8/** @ignore */
9Date.parseRegexes = [];
10/** @ignore */
11Date.formatFunctions = {count:0};
12
13/**
14 * Formats a date given to the supplied format - the format syntax is the same as <a href="http://www.php.net/date">PHP's date() function</a>.
15 */
16Date.prototype.dateFormat = function(format) {
17 if (Date.formatFunctions[format] == null) {
18 Date.createNewFormat(format);
19 }
20 var func = Date.formatFunctions[format];
21 return this[func]();
22};
23
24/**
25 * Same as {@link #dateFormat}
26 */
27Date.prototype.format = Date.prototype.dateFormat;
28
29/** @ignore */
30Date.createNewFormat = function(format) {
31 var funcName = "format" + Date.formatFunctions.count++;
32 Date.formatFunctions[format] = funcName;
33 var code = "Date.prototype." + funcName + " = function(){return ";
34 var special = false;
35 var ch = '';
36 for (var i = 0; i < format.length; ++i) {
37 ch = format.charAt(i);
38 if (!special && ch == "\\") {
39 special = true;
40 }
41 else if (special) {
42 special = false;
43 code += "'" + String.escape(ch) + "' + ";
44 }
45 else {
46 code += Date.getFormatCode(ch);
47 }
48 }
49 eval(code.substring(0, code.length - 3) + ";}");
50};
51
52/** @ignore */
53Date.getFormatCode = function(character) {
54 switch (character) {
55 case "d":
56 return "String.leftPad(this.getDate(), 2, '0') + ";
57 case "D":
58 return "Date.dayNames[this.getDay()].substring(0, 3) + ";
59 case "j":
60 return "this.getDate() + ";
61 case "l":
62 return "Date.dayNames[this.getDay()] + ";
63 case "S":
64 return "this.getSuffix() + ";
65 case "w":
66 return "this.getDay() + ";
67 case "z":
68 return "this.getDayOfYear() + ";
69 case "W":
70 return "this.getWeekOfYear() + ";
71 case "F":
72 return "Date.monthNames[this.getMonth()] + ";
73 case "m":
74 return "String.leftPad(this.getMonth() + 1, 2, '0') + ";
75 case "M":
76 return "Date.monthNames[this.getMonth()].substring(0, 3) + ";
77 case "n":
78 return "(this.getMonth() + 1) + ";
79 case "t":
80 return "this.getDaysInMonth() + ";
81 case "L":
82 return "(this.isLeapYear() ? 1 : 0) + ";
83 case "Y":
84 return "this.getFullYear() + ";
85 case "y":
86 return "('' + this.getFullYear()).substring(2, 4) + ";
87 case "a":
88 return "(this.getHours() < 12 ? 'am' : 'pm') + ";
89 case "A":
90 return "(this.getHours() < 12 ? 'AM' : 'PM') + ";
91 case "g":
92 return "((this.getHours() %12) ? this.getHours() % 12 : 12) + ";
93 case "G":
94 return "this.getHours() + ";
95 case "h":
96 return "String.leftPad((this.getHours() %12) ? this.getHours() % 12 : 12, 2, '0') + ";
97 case "H":
98 return "String.leftPad(this.getHours(), 2, '0') + ";
99 case "i":
100 return "String.leftPad(this.getMinutes(), 2, '0') + ";
101 case "s":
102 return "String.leftPad(this.getSeconds(), 2, '0') + ";
103 case "O":
104 return "this.getGMTOffset() + ";
105 case "T":
106 return "this.getTimezone() + ";
107 case "Z":
108 return "(this.getTimezoneOffset() * -60) + ";
109 default:
110 return "'" + String.escape(character) + "' + ";
111 };
112};
113
114/**
115 * Parses a date given the supplied format - the format syntax is the same as <a href="http://www.php.net/date">PHP's date() function</a>.
116 */
117Date.parseDate = function(input, format) {
118 if (Date.parseFunctions[format] == null) {
119 Date.createParser(format);
120 }
121 var func = Date.parseFunctions[format];
122 return Date[func](input);
123};
124
125/** @ignore */
126Date.createParser = function(format) {
127 var funcName = "parse" + Date.parseFunctions.count++;
128 var regexNum = Date.parseRegexes.length;
129 var currentGroup = 1;
130 Date.parseFunctions[format] = funcName;
131
132 var code = "Date." + funcName + " = function(input){\n"
133 + "var y = -1, m = -1, d = -1, h = -1, i = -1, s = -1;\n"
134 + "var d = new Date();\n"
135 + "y = d.getFullYear();\n"
136 + "m = d.getMonth();\n"
137 + "d = d.getDate();\n"
138 + "var results = input.match(Date.parseRegexes[" + regexNum + "]);\n"
139 + "if (results && results.length > 0) {"
140 var regex = "";
141
142 var special = false;
143 var ch = '';
144 for (var i = 0; i < format.length; ++i) {
145 ch = format.charAt(i);
146 if (!special && ch == "\\") {
147 special = true;
148 }
149 else if (special) {
150 special = false;
151 regex += String.escape(ch);
152 }
153 else {
154 obj = Date.formatCodeToRegex(ch, currentGroup);
155 currentGroup += obj.g;
156 regex += obj.s;
157 if (obj.g && obj.c) {
158 code += obj.c;
159 }
160 }
161 }
162
163 code += "if (y > 0 && m >= 0 && d > 0 && h >= 0 && i >= 0 && s >= 0)\n"
164 + "{return new Date(y, m, d, h, i, s);}\n"
165 + "else if (y > 0 && m >= 0 && d > 0 && h >= 0 && i >= 0)\n"
166 + "{return new Date(y, m, d, h, i);}\n"
167 + "else if (y > 0 && m >= 0 && d > 0 && h >= 0)\n"
168 + "{return new Date(y, m, d, h);}\n"
169 + "else if (y > 0 && m >= 0 && d > 0)\n"
170 + "{return new Date(y, m, d);}\n"
171 + "else if (y > 0 && m >= 0)\n"
172 + "{return new Date(y, m);}\n"
173 + "else if (y > 0)\n"
174 + "{return new Date(y);}\n"
175 + "}return null;}";
176
177 Date.parseRegexes[regexNum] = new RegExp("^" + regex + "$");
178 eval(code);
179};
180
181/** @ignore */
182Date.formatCodeToRegex = function(character, currentGroup) {
183 switch (character) {
184 case "D":
185 return {g:0,
186 c:null,
187 s:"(?:Sun|Mon|Tue|Wed|Thu|Fri|Sat)"};
188 case "j":
189 case "d":
190 return {g:1,
191 c:"d = parseInt(results[" + currentGroup + "], 10);\n",
192 s:"(\\d{1,2})"};
193 case "l":
194 return {g:0,
195 c:null,
196 s:"(?:" + Date.dayNames.join("|") + ")"};
197 case "S":
198 return {g:0,
199 c:null,
200 s:"(?:st|nd|rd|th)"};
201 case "w":
202 return {g:0,
203 c:null,
204 s:"\\d"};
205 case "z":
206 return {g:0,
207 c:null,
208 s:"(?:\\d{1,3})"};
209 case "W":
210 return {g:0,
211 c:null,
212 s:"(?:\\d{2})"};
213 case "F":
214 return {g:1,
215 c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "].substring(0, 3)], 10);\n",
216 s:"(" + Date.monthNames.join("|") + ")"};
217 case "M":
218 return {g:1,
219 c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "]], 10);\n",
220 s:"(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)"};
221 case "n":
222 case "m":
223 return {g:1,
224 c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
225 s:"(\\d{1,2})"};
226 case "t":
227 return {g:0,
228 c:null,
229 s:"\\d{1,2}"};
230 case "L":
231 return {g:0,
232 c:null,
233 s:"(?:1|0)"};
234 case "Y":
235 return {g:1,
236 c:"y = parseInt(results[" + currentGroup + "], 10);\n",
237 s:"(\\d{4})"};
238 case "y":
239 return {g:1,
240 c:"var ty = parseInt(results[" + currentGroup + "], 10);\n"
241 + "y = ty > Date.y2kYear ? 1900 + ty : 2000 + ty;\n",
242 s:"(\\d{1,2})"};
243 case "a":
244 return {g:1,
245 c:"if (results[" + currentGroup + "] == 'am') {\n"
246 + "if (h == 12) { h = 0; }\n"
247 + "} else { if (h < 12) { h += 12; }}",
248 s:"(am|pm)"};
249 case "A":
250 return {g:1,
251 c:"if (results[" + currentGroup + "] == 'AM') {\n"
252 + "if (h == 12) { h = 0; }\n"
253 + "} else { if (h < 12) { h += 12; }}",
254 s:"(AM|PM)"};
255 case "g":
256 case "G":
257 case "h":
258 case "H":
259 return {g:1,
260 c:"h = parseInt(results[" + currentGroup + "], 10);\n",
261 s:"(\\d{1,2})"};
262 case "i":
263 return {g:1,
264 c:"i = parseInt(results[" + currentGroup + "], 10);\n",
265 s:"(\\d{2})"};
266 case "s":
267 return {g:1,
268 c:"s = parseInt(results[" + currentGroup + "], 10);\n",
269 s:"(\\d{2})"};
270 case "O":
271 return {g:0,
272 c:null,
273 s:"[+-]\\d{4}"};
274 case "T":
275 return {g:0,
276 c:null,
277 s:"[A-Z]{3}"};
278 case "Z":
279 return {g:0,
280 c:null,
281 s:"[+-]\\d{1,5}"};
282 default:
283 return {g:0,
284 c:null,
285 s:String.escape(character)};
286 }
287};
288
289Date.prototype.getTimezone = function() {
290 return this.toString().replace(
291 /^.*? ([A-Z]{3}) [0-9]{4}.*$/, "$1").replace(
292 /^.*?\(([A-Z])[a-z]+ ([A-Z])[a-z]+ ([A-Z])[a-z]+\)$/, "$1$2$3");
293};
294
295Date.prototype.getGMTOffset = function() {
296 return (this.getTimezoneOffset() > 0 ? "-" : "+")
297 + String.leftPad(Math.floor(this.getTimezoneOffset() / 60), 2, "0")
298 + String.leftPad(this.getTimezoneOffset() % 60, 2, "0");
299};
300
301Date.prototype.getDayOfYear = function() {
302 var num = 0;
303 Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
304 for (var i = 0; i < this.getMonth(); ++i) {
305 num += Date.daysInMonth[i];
306 }
307 return num + this.getDate() - 1;
308};
309
310Date.prototype.getWeekOfYear = function() {
311 // Skip to Thursday of this week
312 var now = this.getDayOfYear() + (4 - this.getDay());
313 // Find the first Thursday of the year
314 var jan1 = new Date(this.getFullYear(), 0, 1);
315 var then = (7 - jan1.getDay() + 4);
316 return String.leftPad(((now - then) / 7) + 1, 2, "0");
317};
318
319Date.prototype.isLeapYear = function() {
320 var year = this.getFullYear();
321 return ((year & 3) == 0 && (year % 100 || (year % 400 == 0 && year)));
322};
323
324Date.prototype.getFirstDayOfMonth = function() {
325 var day = (this.getDay() - (this.getDate() - 1)) % 7;
326 return (day < 0) ? (day + 7) : day;
327};
328
329Date.prototype.getLastDayOfMonth = function() {
330 var day = (this.getDay() + (Date.daysInMonth[this.getMonth()] - this.getDate())) % 7;
331 return (day < 0) ? (day + 7) : day;
332};
333
334Date.prototype.getDaysInMonth = function() {
335 Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
336 return Date.daysInMonth[this.getMonth()];
337};
338
339/** @ignore */
340Date.prototype.getSuffix = function() {
341 switch (this.getDate()) {
342 case 1:
343 case 21:
344 case 31:
345 return "st";
346 case 2:
347 case 22:
348 return "nd";
349 case 3:
350 case 23:
351 return "rd";
352 default:
353 return "th";
354 }
355};
356
357/** @ignore */
358Date.daysInMonth = [31,28,31,30,31,30,31,31,30,31,30,31];
359
360/**
361 * Override these values for international dates, for example...
362 * Date.monthNames = ['JanInYourLang', 'FebInYourLang', ...];
363 */
364Date.monthNames =
365 ["January",
366 "February",
367 "March",
368 "April",
369 "May",
370 "June",
371 "July",
372 "August",
373 "September",
374 "October",
375 "November",
376 "December"];
377
378/**
379 * Override these values for international dates, for example...
380 * Date.dayNames = ['SundayInYourLang', 'MondayInYourLang', ...];
381 */
382Date.dayNames =
383 ["Sunday",
384 "Monday",
385 "Tuesday",
386 "Wednesday",
387 "Thursday",
388 "Friday",
389 "Saturday"];
390
391/** @ignore */
392Date.y2kYear = 50;
393
394/** @ignore */
395Date.monthNumbers = {
396 Jan:0,
397 Feb:1,
398 Mar:2,
399 Apr:3,
400 May:4,
401 Jun:5,
402 Jul:6,
403 Aug:7,
404 Sep:8,
405 Oct:9,
406 Nov:10,
407 Dec:11};
diff --git a/frontend/beta/js/YUI-extensions/DomHelper.js b/frontend/beta/js/YUI-extensions/DomHelper.js
new file mode 100644
index 0000000..d9e7484
--- a/dev/null
+++ b/frontend/beta/js/YUI-extensions/DomHelper.js
@@ -0,0 +1,416 @@
1/**
2 * @class YAHOO.ext.DomHelper
3 * Utility class for working with DOM and/or Templates. It transparently supports using HTML fragments or DOM.
4 * For more information see <a href="http://www.jackslocum.com/yui/2006/10/06/domhelper-create-elements-using-dom-html-fragments-or-templates/">this blog post with examples</a>.
5 * @singleton
6 */
7YAHOO.ext.DomHelper = new function(){
8 /**@private*/
9 var d = document;
10 var tempTableEl = null;
11 /** True to force the use of DOM instead of html fragments @type Boolean */
12 this.useDom = false;
13 var emptyTags = /^(?:base|basefont|br|frame|hr|img|input|isindex|link|meta|nextid|range|spacer|wbr|audioscope|area|param|keygen|col|limittext|spot|tab|over|right|left|choose|atop|of)$/i;
14 /**
15 * Applies a style specification to an element
16 * @param {String/HTMLElement} el The element to apply styles to
17 * @param {String/Object/Function} styles A style specification string eg "width:100px", or object in the form {width:"100px"}, or
18 * a function which returns such a specification.
19 */
20 this.applyStyles = function(el, styles){
21 if(styles){
22 var D = YAHOO.util.Dom;
23 if (typeof styles == "string"){
24 var re = /\s?([a-z\-]*)\:([^;]*);?/gi;
25 var matches;
26 while ((matches = re.exec(styles)) != null){
27 D.setStyle(el, matches[1], matches[2]);
28 }
29 }else if (typeof styles == "object"){
30 for (var style in styles){
31 D.setStyle(el, style, styles[style]);
32 }
33 }else if (typeof styles == "function"){
34 YAHOO.ext.DomHelper.applyStyles(el, styles.call());
35 }
36 }
37 };
38
39 // build as innerHTML where available
40 /** @ignore */
41 var createHtml = function(o){
42 var b = '';
43 b += '<' + o.tag;
44 for(var attr in o){
45 if(attr == 'tag' || attr == 'children' || attr == 'html' || typeof o[attr] == 'function') continue;
46 if(attr == 'style'){
47 var s = o['style'];
48 if(typeof s == 'function'){
49 s = s.call();
50 }
51 if(typeof s == 'string'){
52 b += ' style="' + s + '"';
53 }else if(typeof s == 'object'){
54 b += ' style="';
55 for(var key in s){
56 if(typeof s[key] != 'function'){
57 b += key + ':' + s[key] + ';';
58 }
59 }
60 b += '"';
61 }
62 }else{
63 if(attr == 'cls'){
64 b += ' class="' + o['cls'] + '"';
65 }else if(attr == 'htmlFor'){
66 b += ' for="' + o['htmlFor'] + '"';
67 }else{
68 b += ' ' + attr + '="' + o[attr] + '"';
69 }
70 }
71 }
72 if(emptyTags.test(o.tag)){
73 b += ' />';
74 }else{
75 b += '>';
76 if(o.children){
77 for(var i = 0, len = o.children.length; i < len; i++) {
78 b += createHtml(o.children[i], b);
79 }
80 }
81 if(o.html){
82 b += o.html;
83 }
84 b += '</' + o.tag + '>';
85 }
86 return b;
87 }
88
89 // build as dom
90 /** @ignore */
91 var createDom = function(o, parentNode){
92 var el = d.createElement(o.tag);
93 var useSet = el.setAttribute ? true : false; // In IE some elements don't have setAttribute
94 for(var attr in o){
95 if(attr == 'tag' || attr == 'children' || attr == 'html' || attr == 'style' || typeof o[attr] == 'function') continue;
96 if(attr=='cls'){
97 el.className = o['cls'];
98 }else{
99 if(useSet) el.setAttribute(attr, o[attr]);
100 else el[attr] = o[attr];
101 }
102 }
103 YAHOO.ext.DomHelper.applyStyles(el, o.style);
104 if(o.children){
105 for(var i = 0, len = o.children.length; i < len; i++) {
106 createDom(o.children[i], el);
107 }
108 }
109 if(o.html){
110 el.innerHTML = o.html;
111 }
112 if(parentNode){
113 parentNode.appendChild(el);
114 }
115 return el;
116 };
117
118 /**
119 * @ignore
120 * Nasty code for IE's broken table implementation
121 */
122 var insertIntoTable = function(tag, where, el, html){
123 if(!tempTableEl){
124 tempTableEl = document.createElement('div');
125 }
126 var node;
127 if(tag == 'table' || tag == 'tbody'){
128 tempTableEl.innerHTML = '<table><tbody>'+html+'</tbody></table>';
129 node = tempTableEl.firstChild.firstChild.firstChild;
130 }else{
131 tempTableEl.innerHTML = '<table><tbody><tr>'+html+'</tr></tbody></table>';
132 node = tempTableEl.firstChild.firstChild.firstChild.firstChild;
133 }
134 if(where == 'beforebegin'){
135 el.parentNode.insertBefore(node, el);
136 return node;
137 }else if(where == 'afterbegin'){
138 el.insertBefore(node, el.firstChild);
139 return node;
140 }else if(where == 'beforeend'){
141 el.appendChild(node);
142 return node;
143 }else if(where == 'afterend'){
144 el.parentNode.insertBefore(node, el.nextSibling);
145 return node;
146 }
147 }
148
149 /**
150 * Inserts an HTML fragment into the Dom
151 * @param {String} where Where to insert the html in relation to el - beforeBegin, afterBegin, beforeEnd, afterEnd.
152 * @param {HTMLElement} el The context element
153 * @param {String} html The HTML fragmenet
154 * @return {HTMLElement} The new node
155 */
156 this.insertHtml = function(where, el, html){
157 where = where.toLowerCase();
158 if(el.insertAdjacentHTML){
159 var tag = el.tagName.toLowerCase();
160 if(tag == 'table' || tag == 'tbody' || tag == 'tr'){
161 return insertIntoTable(tag, where, el, html);
162 }
163 switch(where){
164 case 'beforebegin':
165 el.insertAdjacentHTML(where, html);
166 return el.previousSibling;
167 case 'afterbegin':
168 el.insertAdjacentHTML(where, html);
169 return el.firstChild;
170 case 'beforeend':
171 el.insertAdjacentHTML(where, html);
172 return el.lastChild;
173 case 'afterend':
174 el.insertAdjacentHTML(where, html);
175 return el.nextSibling;
176 }
177 throw 'Illegal insertion point -> "' + where + '"';
178 }
179 var range = el.ownerDocument.createRange();
180 var frag;
181 switch(where){
182 case 'beforebegin':
183 range.setStartBefore(el);
184 frag = range.createContextualFragment(html);
185 el.parentNode.insertBefore(frag, el);
186 return el.previousSibling;
187 case 'afterbegin':
188 if(el.firstChild){ // faster
189 range.setStartBefore(el.firstChild);
190 }else{
191 range.selectNodeContents(el);
192 range.collapse(true);
193 }
194 frag = range.createContextualFragment(html);
195 el.insertBefore(frag, el.firstChild);
196 return el.firstChild;
197 case 'beforeend':
198 if(el.lastChild){
199 range.setStartAfter(el.lastChild); // faster
200 }else{
201 range.selectNodeContents(el);
202 range.collapse(false);
203 }
204 frag = range.createContextualFragment(html);
205 el.appendChild(frag);
206 return el.lastChild;
207 case 'afterend':
208 range.setStartAfter(el);
209 frag = range.createContextualFragment(html);
210 el.parentNode.insertBefore(frag, el.nextSibling);
211 return el.nextSibling;
212 }
213 throw 'Illegal insertion point -> "' + where + '"';
214 };
215
216 /**
217 * Creates new Dom element(s) and inserts them before el
218 * @param {String/HTMLElement/Element} el The context element
219 * @param {Object} o The Dom object spec (and children)
220 * @param {<i>Boolean</i>} returnElement (optional) true to return a YAHOO.ext.Element
221 * @return {HTMLElement} The new node
222 */
223 this.insertBefore = function(el, o, returnElement){
224 el = el.dom ? el.dom : YAHOO.util.Dom.get(el);
225 var newNode;
226 if(this.useDom){
227 newNode = createDom(o, null);
228 el.parentNode.insertBefore(newNode, el);
229 }else{
230 var html = createHtml(o);
231 newNode = this.insertHtml('beforeBegin', el, html);
232 }
233 return returnElement ? YAHOO.ext.Element.get(newNode, true) : newNode;
234 };
235
236 /**
237 * Creates new Dom element(s) and inserts them after el
238 * @param {String/HTMLElement/Element} el The context element
239 * @param {Object} o The Dom object spec (and children)
240 * @param {<i>Boolean</i>} returnElement (optional) true to return a YAHOO.ext.Element
241 * @return {HTMLElement} The new node
242 */
243 this.insertAfter = function(el, o, returnElement){
244 el = el.dom ? el.dom : YAHOO.util.Dom.get(el);
245 var newNode;
246 if(this.useDom){
247 newNode = createDom(o, null);
248 el.parentNode.insertBefore(newNode, el.nextSibling);
249 }else{
250 var html = createHtml(o);
251 newNode = this.insertHtml('afterEnd', el, html);
252 }
253 return returnElement ? YAHOO.ext.Element.get(newNode, true) : newNode;
254 };
255
256 /**
257 * Creates new Dom element(s) and appends them to el
258 * @param {String/HTMLElement/Element} el The context element
259 * @param {Object} o The Dom object spec (and children)
260 * @param {<i>Boolean</i>} returnElement (optional) true to return a YAHOO.ext.Element
261 * @return {HTMLElement} The new node
262 */
263 this.append = function(el, o, returnElement){
264 el = el.dom ? el.dom : YAHOO.util.Dom.get(el);
265 var newNode;
266 if(this.useDom){
267 newNode = createDom(o, null);
268 el.appendChild(newNode);
269 }else{
270 var html = createHtml(o);
271 newNode = this.insertHtml('beforeEnd', el, html);
272 }
273 return returnElement ? YAHOO.ext.Element.get(newNode, true) : newNode;
274 };
275
276 /**
277 * Creates new Dom element(s) and overwrites the contents of el with them
278 * @param {String/HTMLElement/Element} el The context element
279 * @param {Object} o The Dom object spec (and children)
280 * @param {<i>Boolean</i>} returnElement (optional) true to return a YAHOO.ext.Element
281 * @return {HTMLElement} The new node
282 */
283 this.overwrite = function(el, o, returnElement){
284 el = el.dom ? el.dom : YAHOO.util.Dom.get(el);
285 el.innerHTML = createHtml(o);
286 return returnElement ? YAHOO.ext.Element.get(el.firstChild, true) : el.firstChild;
287 };
288
289 /**
290 * Creates a new YAHOO.ext.DomHelper.Template from the Dom object spec
291 * @param {Object} o The Dom object spec (and children)
292 * @return {YAHOO.ext.DomHelper.Template} The new template
293 */
294 this.createTemplate = function(o){
295 var html = createHtml(o);
296 return new YAHOO.ext.DomHelper.Template(html);
297 };
298}();
299
300/**
301* @class YAHOO.ext.DomHelper.Template
302* Represents an HTML fragment template.
303* For more information see <a href="http://www.jackslocum.com/yui/2006/10/06/domhelper-create-elements-using-dom-html-fragments-or-templates/">this blog post with examples</a>.
304* <br>
305* <b>This class is also available as YAHOO.ext.Template</b>.
306* @constructor
307* @param {String/Array} html The HTML fragment or an array of fragments to join('') or multiple arguments to join('')
308*/
309YAHOO.ext.DomHelper.Template = function(html){
310 if(html instanceof Array){
311 html = html.join('');
312 }else if(arguments.length > 1){
313 html = Array.prototype.join.call(arguments, '');
314 }
315 /**@private*/
316 this.html = html;
317};
318YAHOO.ext.DomHelper.Template.prototype = {
319 /**
320 * Returns an HTML fragment of this template with the specified values applied
321 * @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'})
322 * @return {String}
323 */
324 applyTemplate : function(values){
325 if(this.compiled){
326 return this.compiled(values);
327 }
328 var empty = '';
329 var fn = function(match, index){
330 if(typeof values[index] != 'undefined'){
331 return values[index];
332 }else{
333 return empty;
334 }
335 }
336 return this.html.replace(this.re, fn);
337 },
338
339 /**
340 * The regular expression used to match template variables
341 * @type RegExp
342 * @property
343 */
344 re : /\{([\w|-]+)\}/g,
345
346 /**
347 * Compiles the template into an internal function, eliminating the RegEx overhead
348 */
349 compile : function(){
350 var body = ["this.compiled = function(values){ return ['"];
351 body.push(this.html.replace(this.re, "', values['$1'], '"));
352 body.push("'].join('');};");
353 eval(body.join(''));
354 return this;
355 },
356
357 /**
358 * Applies the supplied values to the template and inserts the new node(s) before el
359 * @param {String/HTMLElement/Element} el The context element
360 * @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'})
361 * @param {<i>Boolean</i>} returnElement (optional) true to return a YAHOO.ext.Element
362 * @return {HTMLElement} The new node
363 */
364 insertBefore: function(el, values, returnElement){
365 el = el.dom ? el.dom : YAHOO.util.Dom.get(el);
366 var newNode = YAHOO.ext.DomHelper.insertHtml('beforeBegin', el, this.applyTemplate(values));
367 return returnElement ? YAHOO.ext.Element.get(newNode, true) : newNode;
368 },
369
370 /**
371 * Applies the supplied values to the template and inserts the new node(s) after el
372 * @param {String/HTMLElement/Element} el The context element
373 * @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'})
374 * @param {<i>Boolean</i>} returnElement (optional) true to return a YAHOO.ext.Element
375 * @return {HTMLElement} The new node
376 */
377 insertAfter : function(el, values, returnElement){
378 el = el.dom ? el.dom : YAHOO.util.Dom.get(el);
379 var newNode = YAHOO.ext.DomHelper.insertHtml('afterEnd', el, this.applyTemplate(values));
380 return returnElement ? YAHOO.ext.Element.get(newNode, true) : newNode;
381 },
382
383 /**
384 * Applies the supplied values to the template and append the new node(s) to el
385 * @param {String/HTMLElement/Element} el The context element
386 * @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'})
387 * @param {<i>Boolean</i>} returnElement (optional) true to return a YAHOO.ext.Element
388 * @return {HTMLElement} The new node
389 */
390 append : function(el, values, returnElement){
391 el = el.dom ? el.dom : YAHOO.util.Dom.get(el);
392 var newNode = YAHOO.ext.DomHelper.insertHtml('beforeEnd', el, this.applyTemplate(values));
393 return returnElement ? YAHOO.ext.Element.get(newNode, true) : newNode;
394 },
395
396 /**
397 * Applies the supplied values to the template and overwrites the content of el with the new node(s)
398 * @param {String/HTMLElement/Element} el The context element
399 * @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'})
400 * @param {<i>Boolean</i>} returnElement (optional) true to return a YAHOO.ext.Element
401 * @return {HTMLElement} The new node
402 */
403 overwrite : function(el, values, returnElement){
404 el = el.dom ? el.dom : YAHOO.util.Dom.get(el);
405 el.innerHTML = '';
406 var newNode = YAHOO.ext.DomHelper.insertHtml('beforeEnd', el, this.applyTemplate(values));
407 return returnElement ? YAHOO.ext.Element.get(newNode, true) : newNode;
408 }
409};
410/**
411 * Alias for applyTemplate
412 * @method
413 */
414YAHOO.ext.DomHelper.Template.prototype.apply = YAHOO.ext.DomHelper.Template.prototype.applyTemplate;
415
416YAHOO.ext.Template = YAHOO.ext.DomHelper.Template;
diff --git a/frontend/beta/js/YUI-extensions/Element.js b/frontend/beta/js/YUI-extensions/Element.js
new file mode 100644
index 0000000..4019923
--- a/dev/null
+++ b/frontend/beta/js/YUI-extensions/Element.js
@@ -0,0 +1,2157 @@
1/**
2 * @class YAHOO.ext.Element
3 * Wraps around a DOM element and provides convenient access to Yahoo
4 * UI library functionality (and more).<br><br>
5 * Usage:<br>
6 * <pre><code>
7 * var el = YAHOO.ext.Element.get('myElementId');
8 * // or the shorter
9 * var el = getEl('myElementId');
10 * </code></pre>
11 * Using YAHOO.ext.Element.get() instead of calling the constructor directly ensures you get the same object
12 * each call instead of constructing a new one.<br><br>
13 * For working with collections of Elements, see <a href="YAHOO.ext.CompositeElement.html">YAHOO.ext.CompositeElement</a>
14 * @requires YAHOO.util.Dom
15 * @requires YAHOO.util.Event
16 * @requires YAHOO.util.CustomEvent
17 * @requires YAHOO.util.Anim (optional) to support animation
18 * @requires YAHOO.util.Motion (optional) to support animation
19 * @requires YAHOO.util.Easing (optional) to support animation
20 * @constructor Create a new Element directly.
21 * @param {String/HTMLElement} element
22 * @param {<i>Boolean</i>} forceNew (optional) By default the constructor checks to see if there is already an instance of this element in the cache and if there is it returns the same instance. This will skip that check (useful for extending this class).
23 */
24YAHOO.ext.Element = function(element, forceNew){
25 var dom = typeof element == 'string' ?
26 document.getElementById(element) : element;
27 if(!dom){ // invalid id/element
28 return null;
29 }
30 if(!forceNew && YAHOO.ext.Element.cache[dom.id]){ // element object already exists
31 return YAHOO.ext.Element.cache[dom.id];
32 }
33 /**
34 * The DOM element
35 * @type HTMLElement
36 */
37 this.dom = dom;
38
39 /**
40 * The DOM element ID
41 * @type String
42 */
43 this.id = dom.id;
44
45 /**
46 * The element's default display mode @type String
47 */
48 this.originalDisplay = YAHOO.util.Dom.getStyle(dom, 'display') || '';
49 if(this.autoDisplayMode){
50 if(this.originalDisplay == 'none'){
51 this.setVisibilityMode(YAHOO.ext.Element.DISPLAY);
52 }
53 }
54 if(this.originalDisplay == 'none'){
55 this.originalDisplay = '';
56 }
57}
58
59YAHOO.ext.Element.prototype = {
60 visibilityMode : 1,
61 /**
62 * The default unit to append to CSS values where a unit isn't provided (Defaults to px).
63 * @type String
64 */
65 defaultUnit : 'px',
66 /**
67 * Sets the elements visibility mode. When setVisible() is called it
68 * will use this to determine whether to set the visibility or the display property.
69 * @param visMode Element.VISIBILITY or Element.DISPLAY
70 * @return {YAHOO.ext.Element} this
71 */
72 setVisibilityMode : function(visMode){
73 this.visibilityMode = visMode;
74 return this;
75 },
76 /**
77 * Convenience method for setVisibilityMode(Element.DISPLAY)
78 * @param {String} display (optional) What to set display to when visible
79 * @return {YAHOO.ext.Element} this
80 */
81 enableDisplayMode : function(display){
82 this.setVisibilityMode(YAHOO.ext.Element.DISPLAY);
83 if(typeof display != 'undefined') this.originalDisplay = display;
84 return this;
85 },
86
87 /**
88 * Perform Yahoo UI animation on this element.
89 * @param {Object} args The YUI animation control args
90 * @param {<i>Float</i>} duration (optional) How long the animation lasts. (Defaults to .35 seconds)
91 * @param {<i>Function</i>} onComplete (optional) Function to call when animation completes.
92 * @param {<i>Function</i>} easing (optional) YAHOO.util.Easing method to use. (Defaults to YAHOO.util.Easing.easeBoth)
93 * @param {<i>Function</i>} animType (optional) YAHOO.util.Anim subclass to use. For example: YAHOO.util.Motion
94 * @return {YAHOO.ext.Element} this
95 */
96 animate : function(args, duration, onComplete, easing, animType, stopAnims){
97 this.anim(args, duration, onComplete, easing, animType);
98 return this;
99 },
100
101 /**
102 * @private Internal animation call
103 */
104 anim : function(args, duration, onComplete, easing, animType){
105 animType = animType || YAHOO.util.Anim;
106 var anim = new animType(this.dom, args, duration || .35,
107 easing || YAHOO.util.Easing.easeBoth);
108 if(onComplete){
109 anim.onComplete.subscribe(function(){
110 if(typeof onComplete == 'function'){
111 onComplete.call(this);
112 }else if(onComplete instanceof Array){
113 for(var i = 0; i < onComplete.length; i++){
114 var fn = onComplete[i];
115 if(fn) fn.call(this);
116 }
117 }
118 }, this, true);
119 }
120 anim.animate();
121 return anim;
122 },
123
124 /**
125 * Scrolls this element into view within the passed container.
126 * @param {<i>String/HTMLElement/Element</i>} container (optional) The container element to scroll (defaults to document.body)
127 * @return {YAHOO.ext.Element} this
128 */
129 scrollIntoView : function(container){
130 var c = getEl(container || document.body, true);
131 var cp = c.getStyle('position');
132 var restorePos = false;
133 if(cp != 'relative' && cp != 'absolute'){
134 c.setStyle('position', 'relative');
135 restorePos = true;
136 }
137 var el = this.dom;
138 var childTop = parseInt(el.offsetTop, 10);
139 var childBottom = childTop + el.offsetHeight;
140 var containerTop = parseInt(c.dom.scrollTop, 10); // parseInt for safari bug
141 var containerBottom = containerTop + c.dom.clientHeight;
142 if(childTop < containerTop){
143 c.dom.scrollTop = childTop;
144 }else if(childBottom > containerBottom){
145 c.dom.scrollTop = childBottom-c.dom.clientHeight;
146 }
147 if(restorePos){
148 c.setStyle('position', cp);
149 }
150 return this;
151 },
152
153 /**
154 * Measures the elements content height and updates height to match. Note, this function uses setTimeout and
155 * the new height may not be available immediately.
156 * @param {<i>Boolean</i>} animate (optional) Animate the transition (Default is false)
157 * @param {<i>Float</i>} duration (optional) Length of the animation. (Defaults to .35 seconds)
158 * @param {<i>Function</i>} onComplete (optional) Function to call when animation completes.
159 * @param {<i>Function</i>} easing (optional) YAHOO.util.Easing method to use. (Defaults to YAHOO.util.Easing.easeOut for hiding or YAHOO.util.Easing.easeIn for showing)
160 * @return {YAHOO.ext.Element} this
161 */
162 autoHeight : function(animate, duration, onComplete, easing){
163 var oldHeight = this.getHeight();
164 this.clip();
165 this.setHeight(1); // force clipping
166 setTimeout(function(){
167 var height = parseInt(this.dom.scrollHeight, 10); // parseInt for Safari
168 if(!animate){
169 this.setHeight(height);
170 this.unclip();
171 if(typeof onComplete == 'function'){
172 onComplete();
173 }
174 }else{
175 this.setHeight(oldHeight); // restore original height
176 this.setHeight(height, animate, duration, function(){
177 this.unclip();
178 if(typeof onComplete == 'function') onComplete();
179 }.createDelegate(this), easing);
180 }
181 }.createDelegate(this), 0);
182 return this;
183 },
184
185 contains : function(el){
186 if(!el){return false;}
187 return YAHOO.util.Dom.isAncestor(this.dom, el.dom ? el.dom : el);
188 },
189
190 /**
191 * Checks whether the element is currently visible using both visibility and display properties.
192 * @param {<i>Boolean</i>} deep True to walk the dom and see if parent elements are hidden.
193 * @return {Boolean} true if the element is currently visible
194 */
195 isVisible : function(deep) {
196 var vis = YAHOO.util.Dom.getStyle(this.dom, 'visibility') != 'hidden'
197 && YAHOO.util.Dom.getStyle(this.dom, 'display') != 'none';
198 if(!deep || !vis){
199 return vis;
200 }
201 var p = this.dom.parentNode;
202 while(p && p.tagName.toLowerCase() != 'body'){
203 if(YAHOO.util.Dom.getStyle(p, 'visibility') == 'hidden' || YAHOO.util.Dom.getStyle(p, 'display') == 'none'){
204 return false;
205 }
206 p = p.parentNode;
207 }
208 return true;
209 },
210
211 /**
212 * Selects child nodes based on the passed CSS selector (the selector should not contain an id)
213 * @param {String} selector The CSS selector
214 * @param {Boolean} unique true to create a unique YAHOO.ext.Element for each child (defaults to a shared flyweight object)
215 * @return {CompositeElement/CompositeElementLite} The composite element
216 */
217 select : function(selector, unique){
218 return YAHOO.ext.Element.select('#' + this.dom.id + ' ' + selector, unique);
219 },
220
221 /**
222 * Initializes a YAHOO.util.DD object for this element.
223 * @param {String} group The group the DD object is member of
224 * @param {Object} config The DD config object
225 * @param {Object} overrides An object containing methods to override/implement on the DD object
226 * @return {YAHOO.util.DD} The DD object
227 */
228 initDD : function(group, config, overrides){
229 var dd = new YAHOO.util.DD(YAHOO.util.Dom.generateId(this.dom), group, config);
230 return YAHOO.ext.util.Config.apply(dd, overrides);
231 },
232
233 /**
234 * Initializes a YAHOO.util.DDProxy object for this element.
235 * @param {String} group The group the DDProxy object is member of
236 * @param {Object} config The DDProxy config object
237 * @param {Object} overrides An object containing methods to override/implement on the DDProxy object
238 * @return {YAHOO.util.DDProxy} The DDProxy object
239 */
240 initDDProxy : function(group, config, overrides){
241 var dd = new YAHOO.util.DDProxy(YAHOO.util.Dom.generateId(this.dom), group, config);
242 return YAHOO.ext.util.Config.apply(dd, overrides);
243 },
244
245 /**
246 * Initializes a YAHOO.util.DDTarget object for this element.
247 * @param {String} group The group the DDTarget object is member of
248 * @param {Object} config The DDTarget config object
249 * @param {Object} overrides An object containing methods to override/implement on the DDTarget object
250 * @return {YAHOO.util.DDTarget} The DDTarget object
251 */
252 initDDTarget : function(group, config, overrides){
253 var dd = new YAHOO.util.DDTarget(YAHOO.util.Dom.generateId(this.dom), group, config);
254 return YAHOO.ext.util.Config.apply(dd, overrides);
255 },
256
257 /**
258 * Sets the visibility of the element (see details). If the visibilityMode is set to Element.DISPLAY, it will use
259 * the display property to hide the element, otherwise it uses visibility. The default is to hide and show using the visibility property.
260 * @param {Boolean} visible Whether the element is visible
261 * @param {<i>Boolean</i>} animate (optional) Fade the element in or out (Default is false)
262 * @param {<i>Float</i>} duration (optional) How long the fade effect lasts. (Defaults to .35 seconds)
263 * @param {<i>Function</i>} onComplete (optional) Function to call when animation completes.
264 * @param {<i>Function</i>} easing (optional) YAHOO.util.Easing method to use. (Defaults to YAHOO.util.Easing.easeOut for hiding or YAHOO.util.Easing.easeIn for showing)
265 * @return {YAHOO.ext.Element} this
266 */
267 setVisible : function(visible, animate, duration, onComplete, easing){
268 //if(this.isVisible() == visible) return; // nothing to do
269 if(!animate || !YAHOO.util.Anim){
270 if(this.visibilityMode == YAHOO.ext.Element.DISPLAY){
271 this.setDisplayed(visible);
272 }else{
273 YAHOO.util.Dom.setStyle(this.dom, 'visibility', visible ? 'visible' : 'hidden');
274 }
275 }else{
276 // make sure they can see the transition
277 this.setOpacity(visible?0:1);
278 YAHOO.util.Dom.setStyle(this.dom, 'visibility', 'visible');
279 if(this.visibilityMode == YAHOO.ext.Element.DISPLAY){
280 this.setDisplayed(true);
281 }
282 var args = {opacity: { from: (visible?0:1), to: (visible?1:0) }};
283 var anim = new YAHOO.util.Anim(this.dom, args, duration || .35,
284 easing || (visible ? YAHOO.util.Easing.easeIn : YAHOO.util.Easing.easeOut));
285 anim.onComplete.subscribe((function(){
286 if(this.visibilityMode == YAHOO.ext.Element.DISPLAY){
287 this.setDisplayed(visible);
288 }else{
289 YAHOO.util.Dom.setStyle(this.dom, 'visibility', visible ? 'visible' : 'hidden');
290 }
291 }).createDelegate(this));
292 if(onComplete){
293 anim.onComplete.subscribe(onComplete);
294 }
295 anim.animate();
296 }
297 return this;
298 },
299
300 /**
301 * Returns true if display is not "none"
302 * @return {Boolean}
303 */
304 isDisplayed : function() {
305 return YAHOO.util.Dom.getStyle(this.dom, 'display') != 'none';
306 },
307
308 /**
309 * Toggles the elements visibility or display, depending on visibility mode.
310 * @param {<i>Boolean</i>} animate (optional) Fade the element in or out (Default is false)
311 * @param {<i>float</i>} duration (optional) How long the fade effect lasts. (Defaults to .35 seconds)
312 * @param {<i>Function</i>} onComplete (optional) Function to call when animation completes.
313 * @param {<i>Function</i>} easing (optional) YAHOO.util.Easing method to use. (Defaults to YAHOO.util.Easing.easeOut for hiding or YAHOO.util.Easing.easeIn for showing)
314 * @return {YAHOO.ext.Element} this
315 */
316 toggle : function(animate, duration, onComplete, easing){
317 this.setVisible(!this.isVisible(), animate, duration, onComplete, easing);
318 return this;
319 },
320
321 /**
322 * Sets the css display. Uses originalDisplay if value is a boolean true.
323 * @param {Boolean} value Boolean to display the element using it's default display or a string to set the display directly
324 * @return {YAHOO.ext.Element} this
325 */
326 setDisplayed : function(value) {
327 if(typeof value == 'boolean'){
328 value = value ? this.originalDisplay : 'none';
329 }
330 YAHOO.util.Dom.setStyle(this.dom, 'display', value);
331 return this;
332 },
333
334 /**
335 * Tries to focus the element. Any exceptions are caught.
336 * @return {YAHOO.ext.Element} this
337 */
338 focus : function() {
339 try{
340 this.dom.focus();
341 }catch(e){}
342 return this;
343 },
344
345 /**
346 * Tries to blur the element. Any exceptions are caught.
347 * @return {YAHOO.ext.Element} this
348 */
349 blur : function() {
350 try{
351 this.dom.blur();
352 }catch(e){}
353 return this;
354 },
355
356 /**
357 * Add a CSS class to the element.
358 * @param {String/Array} className The CSS class to add or an array of classes
359 * @return {YAHOO.ext.Element} this
360 */
361 addClass : function(className){
362 if(className instanceof Array){
363 for(var i = 0, len = className.length; i < len; i++) {
364 this.addClass(className[i]);
365 }
366 }else{
367 if(!this.hasClass(className)){
368 this.dom.className = this.dom.className + ' ' + className;
369 }
370 }
371 return this;
372 },
373
374 /**
375 * Adds the passed className to this element and removes the class from all siblings
376 * @param {String} className The className to add
377 * @return {YAHOO.ext.Element} this
378 */
379 radioClass : function(className){
380 var siblings = this.dom.parentNode.childNodes;
381 for(var i = 0; i < siblings.length; i++) {
382 var s = siblings[i];
383 if(s.nodeType == 1){
384 YAHOO.util.Dom.removeClass(s, className);
385 }
386 }
387 this.addClass(className);
388 return this;
389 },
390 /**
391 * Removes a CSS class from the element.
392 * @param {String/Array} className The CSS class to remove or an array of classes
393 * @return {YAHOO.ext.Element} this
394 */
395 removeClass : function(className){
396 if(!className){
397 return this;
398 }
399 if(className instanceof Array){
400 for(var i = 0, len = className.length; i < len; i++) {
401 this.removeClass(className[i]);
402 }
403 }else{
404 var re = new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)', 'g');
405 var c = this.dom.className;
406 if(re.test(c)){
407 this.dom.className = c.replace(re, ' ');
408 }
409 }
410 return this;
411 },
412
413 /**
414 * Toggles (adds or removes) the passed class.
415 * @param {String} className
416 * @return {YAHOO.ext.Element} this
417 */
418 toggleClass : function(className){
419 if(this.hasClass(className)){
420 this.removeClass(className);
421 }else{
422 this.addClass(className);
423 }
424 return this;
425 },
426
427 /**
428 * Checks if a CSS class is in use by the element.
429 * @param {String} className The CSS class to check
430 * @return {Boolean} true or false
431 */
432 hasClass : function(className){
433 var re = new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)');
434 return re.test(this.dom.className);
435 },
436
437 /**
438 * Replaces a CSS class on the element with another.
439 * @param {String} oldClassName The CSS class to replace
440 * @param {String} newClassName The replacement CSS class
441 * @return {YAHOO.ext.Element} this
442 */
443 replaceClass : function(oldClassName, newClassName){
444 this.removeClass(oldClassName);
445 this.addClass(newClassName);
446 return this;
447 },
448
449 /**
450 * Normalizes currentStyle and ComputedStyle.
451 * @param {String} property The style property whose value is returned.
452 * @return {String} The current value of the style property for this element.
453 */
454 getStyle : function(name){
455 return YAHOO.util.Dom.getStyle(this.dom, name);
456 },
457
458 /**
459 * Wrapper for setting style properties, also takes single object parameter of multiple styles
460 * @param {String/Object} property The style property to be set or an object of multiple styles.
461 * @param {String} val (optional) The value to apply to the given property or null if an object was passed.
462 * @return {YAHOO.ext.Element} this
463 */
464 setStyle : function(name, value){
465 if(typeof name == 'string'){
466 YAHOO.util.Dom.setStyle(this.dom, name, value);
467 }else{
468 var D = YAHOO.util.Dom;
469 for(var style in name){
470 if(typeof name[style] != 'function'){
471 D.setStyle(this.dom, style, name[style]);
472 }
473 }
474 }
475 return this;
476 },
477
478 /**
479 * More flexible version of {@link #setStyle} for setting style properties.
480 * @param {String/Object/Function} styles A style specification string eg "width:100px", or object in the form {width:"100px"}, or
481 * a function which returns such a specification.
482 * @return {YAHOO.ext.Element} this
483 */
484 applyStyles : function(style){
485 YAHOO.ext.DomHelper.applyStyles(this.dom, style);
486 },
487
488 /**
489 * Gets the current X position of the element based on page coordinates. Element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
490 @ return {Number} The X position of the element
491 */
492 getX : function(){
493 return YAHOO.util.Dom.getX(this.dom);
494 },
495
496 /**
497 * Gets the current Y position of the element based on page coordinates. Element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
498 @ return {Number} The Y position of the element
499 */
500 getY : function(){
501 return YAHOO.util.Dom.getY(this.dom);
502 },
503
504 /**
505 * Gets the current position of the element based on page coordinates. Element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
506 @ return {Array} The XY position of the element
507 */
508 getXY : function(){
509 return YAHOO.util.Dom.getXY(this.dom);
510 },
511
512 /**
513 * Sets the X position of the element based on page coordinates. Element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
514 @param {Number} The X position of the element
515 * @param {<i>Boolean</i>} animate (optional) Animate the transition (Default is false)
516 * @param {<i>float</i>} duration (optional) How long the animation lasts. (Defaults to .35 seconds)
517 * @param {<i>Function</i>} onComplete (optional) Function to call when animation completes.
518 * @param {<i>Function</i>} easing (optional) YAHOO.util.Easing method to use. (Defaults to YAHOO.util.Easing.easeBoth)
519 * @return {YAHOO.ext.Element} this
520 */
521 setX : function(x, animate, duration, onComplete, easing){
522 if(!animate || !YAHOO.util.Anim){
523 YAHOO.util.Dom.setX(this.dom, x);
524 }else{
525 this.setXY([x, this.getY()], animate, duration, onComplete, easing);
526 }
527 return this;
528 },
529
530 /**
531 * Sets the Y position of the element based on page coordinates. Element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
532 @param {Number} The Y position of the element
533 * @param {<i>Boolean</i>} animate (optional) Animate the transition (Default is false)
534 * @param {<i>float</i>} duration (optional) How long the animation lasts. (Defaults to .35 seconds)
535 * @param {<i>Function</i>} onComplete (optional) Function to call when animation completes.
536 * @param {<i>Function</i>} easing (optional) YAHOO.util.Easing method to use. (Defaults to YAHOO.util.Easing.easeBoth)
537 * @return {YAHOO.ext.Element} this
538 */
539 setY : function(y, animate, duration, onComplete, easing){
540 if(!animate || !YAHOO.util.Anim){
541 YAHOO.util.Dom.setY(this.dom, y);
542 }else{
543 this.setXY([this.getX(), y], animate, duration, onComplete, easing);
544 }
545 return this;
546 },
547
548 /**
549 * Set the element's left position directly using CSS style (instead of setX())
550 * @param {String} left The left CSS property value
551 * @return {YAHOO.ext.Element} this
552 */
553 setLeft : function(left){
554 YAHOO.util.Dom.setStyle(this.dom, 'left', this.addUnits(left));
555 return this;
556 },
557
558 /**
559 * Set the element's top position directly using CSS style (instead of setY())
560 * @param {String} top The top CSS property value
561 * @return {YAHOO.ext.Element} this
562 */
563 setTop : function(top){
564 YAHOO.util.Dom.setStyle(this.dom, 'top', this.addUnits(top));
565 return this;
566 },
567
568 /**
569 * Set the element's css right style
570 * @param {String} right The right CSS property value
571 * @return {YAHOO.ext.Element} this
572 */
573 setRight : function(right){
574 YAHOO.util.Dom.setStyle(this.dom, 'right', this.addUnits(right));
575 return this;
576 },
577
578 /**
579 * Set the element's css bottom style
580 * @param {String} bottom The bottom CSS property value
581 * @return {YAHOO.ext.Element} this
582 */
583 setBottom : function(bottom){
584 YAHOO.util.Dom.setStyle(this.dom, 'bottom', this.addUnits(bottom));
585 return this;
586 },
587
588 /**
589 * Set the position of the element in page coordinates, regardless of how the element is positioned.
590 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
591 * @param {Array} pos Contains X & Y [x, y] values for new position (coordinates are page-based)
592 * @param {<i>Boolean</i>} animate (optional) Animate the transition (Default is false)
593 * @param {<i>float</i>} duration (optional) How long the animation lasts. (Defaults to .35 seconds)
594 * @param {<i>Function</i>} onComplete (optional) Function to call when animation completes.
595 * @param {<i>Function</i>} easing (optional) YAHOO.util.Easing method to use. (Defaults to YAHOO.util.Easing.easeBoth)
596 * @return {YAHOO.ext.Element} this
597 */
598 setXY : function(pos, animate, duration, onComplete, easing){
599 if(!animate || !YAHOO.util.Anim){
600 YAHOO.util.Dom.setXY(this.dom, pos);
601 }else{
602 this.anim({points: {to: pos}}, duration, onComplete, easing, YAHOO.util.Motion);
603 }
604 return this;
605 },
606
607 /**
608 * Set the position of the element in page coordinates, regardless of how the element is positioned.
609 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
610 * @param {Number} x X value for new position (coordinates are page-based)
611 * @param {Number} y Y value for new position (coordinates are page-based)
612 * @param {<i>Boolean</i>} animate (optional) Animate the transition (Default is false)
613 * @param {<i>float</i>} duration (optional) How long the animation lasts. (Defaults to .35 seconds)
614 * @param {<i>Function</i>} onComplete (optional) Function to call when animation completes.
615 * @param {<i>Function</i>} easing (optional) YAHOO.util.Easing method to use. (Defaults to YAHOO.util.Easing.easeBoth)
616 * @return {YAHOO.ext.Element} this
617 */
618 setLocation : function(x, y, animate, duration, onComplete, easing){
619 this.setXY([x, y], animate, duration, onComplete, easing);
620 return this;
621 },
622
623 /**
624 * Set the position of the element in page coordinates, regardless of how the element is positioned.
625 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
626 * @param {Number} x X value for new position (coordinates are page-based)
627 * @param {Number} y Y value for new position (coordinates are page-based)
628 * @param {<i>Boolean</i>} animate (optional) Animate the transition (Default is false)
629 * @param {<i>float</i>} duration (optional) How long the animation lasts. (Defaults to .35 seconds)
630 * @param {<i>Function</i>} onComplete (optional) Function to call when animation completes.
631 * @param {<i>Function</i>} easing (optional) YAHOO.util.Easing method to use. (Defaults to YAHOO.util.Easing.easeBoth)
632 * @return {YAHOO.ext.Element} this
633 */
634 moveTo : function(x, y, animate, duration, onComplete, easing){
635 //YAHOO.util.Dom.setStyle(this.dom, 'left', this.addUnits(x));
636 //YAHOO.util.Dom.setStyle(this.dom, 'top', this.addUnits(y));
637 this.setXY([x, y], animate, duration, onComplete, easing);
638 return this;
639 },
640
641 /**
642 * Returns the region of the given element.
643 * The element must be part of the DOM tree to have a region (display:none or elements not appended return false).
644 * @return {Region} A YAHOO.util.Region containing "top, left, bottom, right" member data.
645 */
646 getRegion : function(){
647 return YAHOO.util.Dom.getRegion(this.dom);
648 },
649
650 /**
651 * Returns the offset height of the element
652 * @param {Boolean} contentHeight (optional) true to get the height minus borders and padding
653 * @return {Number} The element's height
654 */
655 getHeight : function(contentHeight){
656 var h = this.dom.offsetHeight;
657 return contentHeight !== true ? h : h-this.getBorderWidth('tb')-this.getPadding('tb');
658 },
659
660 /**
661 * Returns the offset width of the element
662 * @param {Boolean} contentWidth (optional) true to get the width minus borders and padding
663 * @return {Number} The element's width
664 */
665 getWidth : function(contentWidth){
666 var w = this.dom.offsetWidth;
667 return contentWidth !== true ? w : w-this.getBorderWidth('lr')-this.getPadding('lr');
668 },
669
670 /**
671 * Returns the size of the element
672 * @param {Boolean} contentSize (optional) true to get the width/size minus borders and padding
673 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
674 */
675 getSize : function(contentSize){
676 return {width: this.getWidth(contentSize), height: this.getHeight(contentSize)};
677 },
678
679 /** @private */
680 adjustWidth : function(width){
681 if(typeof width == 'number'){
682 if(this.autoBoxAdjust && !this.isBorderBox()){
683 width -= (this.getBorderWidth('lr') + this.getPadding('lr'));
684 }
685 if(width < 0){
686 width = 0;
687 }
688 }
689 return width;
690 },
691
692 /** @private */
693 adjustHeight : function(height){
694 if(typeof height == 'number'){
695 if(this.autoBoxAdjust && !this.isBorderBox()){
696 height -= (this.getBorderWidth('tb') + this.getPadding('tb'));
697 }
698 if(height < 0){
699 height = 0;
700 }
701 }
702 return height;
703 },
704
705 /**
706 * Set the width of the element
707 * @param {Number} width The new width
708 * @param {<i>Boolean</i>} animate (optional) Animate the transition (Default is false)
709 * @param {<i>float</i>} duration (optional) How long the animation lasts. (Defaults to .35 seconds)
710 * @param {<i>Function</i>} onComplete (optional) Function to call when animation completes.
711 * @param {<i>Function</i>} easing (optional) YAHOO.util.Easing method to use. (Defaults to YAHOO.util.Easing.easeOut if width is larger or YAHOO.util.Easing.easeIn if it is smaller)
712 * @return {YAHOO.ext.Element} this
713 */
714 setWidth : function(width, animate, duration, onComplete, easing){
715 width = this.adjustWidth(width);
716 if(!animate || !YAHOO.util.Anim){
717 this.dom.style.width = this.addUnits(width);
718 //YAHOO.util.Dom.setStyle(this.dom, 'width', this.addUnits(width));
719 }else{
720 this.anim({width: {to: width}}, duration, onComplete,
721 easing || (width > this.getWidth() ? YAHOO.util.Easing.easeOut : YAHOO.util.Easing.easeIn));
722 }
723 return this;
724 },
725
726 /**
727 * Set the height of the element
728 * @param {Number} height The new height
729 * @param {<i>Boolean</i>} animate (optional) Animate the transition (Default is false)
730 * @param {<i>float</i>} duration (optional) How long the animation lasts. (Defaults to .35 seconds)
731 * @param {<i>Function</i>} onComplete (optional) Function to call when animation completes.
732 * @param {<i>Function</i>} easing (optional) YAHOO.util.Easing method to use. (Defaults to YAHOO.util.Easing.easeOut if height is larger or YAHOO.util.Easing.easeIn if it is smaller)
733 * @return {YAHOO.ext.Element} this
734 */
735 setHeight : function(height, animate, duration, onComplete, easing){
736 height = this.adjustHeight(height);
737 if(!animate || !YAHOO.util.Anim){
738 this.dom.style.height = this.addUnits(height);
739 //YAHOO.util.Dom.setStyle(this.dom, 'height', this.addUnits(height));
740 }else{
741 this.anim({height: {to: height}}, duration, onComplete,
742 easing || (height > this.getHeight() ? YAHOO.util.Easing.easeOut : YAHOO.util.Easing.easeIn));
743 }
744 return this;
745 },
746
747 /**
748 * Set the size of the element. If animation is true, both width an height will be animated concurrently.
749 * @param {Number} width The new width
750 * @param {Number} height The new height
751 * @param {<i>Boolean</i>} animate (optional) Animate the transition (Default is false)
752 * @param {<i>float</i>} duration (optional) How long the animation lasts. (Defaults to .35 seconds)
753 * @param {<i>Function</i>} onComplete (optional) Function to call when animation completes.
754 * @param {<i>Function</i>} easing (optional) YAHOO.util.Easing method to use. (Defaults to YAHOO.util.Easing.easeBoth)
755 * @return {YAHOO.ext.Element} this
756 */
757 setSize : function(width, height, animate, duration, onComplete, easing){
758 width = this.adjustWidth(width); height = this.adjustHeight(height);
759 if(!animate || !YAHOO.util.Anim){
760 this.dom.style.width = this.addUnits(width);
761 this.dom.style.height = this.addUnits(height);
762 }else{
763 this.anim({width: {to: width}, height: {to: height}}, duration, onComplete, easing);
764 }
765 return this;
766 },
767
768 /**
769 * Sets the element's position and size in one shot. If animation is true then width, height, x and y will be animated concurrently.
770 * @param {Number} x X value for new position (coordinates are page-based)
771 * @param {Number} y Y value for new position (coordinates are page-based)
772 * @param {Number} width The new width
773 * @param {Number} height The new height
774 * @param {<i>Boolean</i>} animate (optional) Animate the transition (Default is false)
775 * @param {<i>float</i>} duration (optional) How long the animation lasts. (Defaults to .35 seconds)
776 * @param {<i>Function</i>} onComplete (optional) Function to call when animation completes.
777 * @param {<i>Function</i>} easing (optional) YAHOO.util.Easing method to use. (Defaults to YAHOO.util.Easing.easeBoth)
778 * @return {YAHOO.ext.Element} this
779 */
780 setBounds : function(x, y, width, height, animate, duration, onComplete, easing){
781 if(!animate || !YAHOO.util.Anim){
782 this.setSize(width, height);
783 this.setLocation(x, y);
784 }else{
785 width = this.adjustWidth(width); height = this.adjustHeight(height);
786 this.anim({points: {to: [x, y]}, width: {to: width}, height: {to: height}}, duration, onComplete, easing, YAHOO.util.Motion);
787 }
788 return this;
789 },
790
791 /**
792 * Sets the element's position and size the the specified region. If animation is true then width, height, x and y will be animated concurrently.
793 * @param {YAHOO.util.Region} region The region to fill
794 * @param {<i>Boolean</i>} animate (optional) Animate the transition (Default is false)
795 * @param {<i>float</i>} duration (optional) How long the animation lasts. (Defaults to .35 seconds)
796 * @param {<i>Function</i>} onComplete (optional) Function to call when animation completes.
797 * @param {<i>Function</i>} easing (optional) YAHOO.util.Easing method to use. (Defaults to YAHOO.util.Easing.easeBoth)
798 * @return {YAHOO.ext.Element} this
799 */
800 setRegion : function(region, animate, duration, onComplete, easing){
801 this.setBounds(region.left, region.top, region.right-region.left, region.bottom-region.top, animate, duration, onComplete, easing);
802 return this;
803 },
804
805 /**
806 * Appends an event handler to this element
807 * @param {String} eventName The type of event to listen for
808 * @param {Function} handler The method the event invokes
809 * @param {<i>Object</i>} scope (optional) An arbitrary object that will be
810 * passed as a parameter to the handler
811 * @param {<i>boolean</i>} override (optional) If true, the obj passed in becomes
812 * the execution scope of the listener
813 * @return {YAHOO.ext.Element} this
814 */
815 addListener : function(eventName, handler, scope, override){
816 YAHOO.util.Event.addListener(this.dom, eventName, handler, scope || this, true);
817 return this;
818 },
819 /**
820 * Appends an event handler to this element that is buffered. If the event is triggered more than once
821 * in the specified time-frame, only the last one actually fires.
822 * @param {String} eventName The type of event to listen for
823 * @param {Function} handler The method the event invokes
824 * @param {<i>Object</i>} scope (optional) The scope (this object) for the handler
825 * @param {<i>Number</i>} millis (optional) The number of milliseconds to buffer (defaults to 250)
826 * @return {Function} The wrapped function that was created (can be used to remove the listener)
827 */
828 bufferedListener : function(eventName, fn, scope, millis){
829 var task = new YAHOO.ext.util.DelayedTask();
830 scope = scope || this;
831 var newFn = function(e){
832 task.delay(millis || 250, fn, scope, Array.prototype.slice.call(arguments, 0));
833 }
834 this.addListener(eventName, newFn);
835 return newFn;
836 },
837
838
839 /**
840 * Appends an event handler to this element. The difference between this function and addListener is this
841 * function prevents the default action, and if set stops propagation (bubbling) as well
842 * @param {String} eventName The type of event to listen for
843 * @param {Boolean} stopPropagation Whether to also stopPropagation (bubbling)
844 * @param {Function} handler The method the event invokes
845 * @param {<i>Object</i>} scope (optional) An arbitrary object that will be
846 * passed as a parameter to the handler
847 * @param {<i>boolean</i>} override (optional) If true, the obj passed in becomes
848 * the execution scope of the listener
849 * @return {YAHOO.ext.Element} this
850 */
851 addHandler : function(eventName, stopPropagation, handler, scope, override){
852 var fn = YAHOO.ext.Element.createStopHandler(stopPropagation, handler, scope || this, true);
853 YAHOO.util.Event.addListener(this.dom, eventName, fn);
854 return fn;
855 },
856
857 /**
858 * Appends an event handler to this element (Same as addListener)
859 * @param {String} eventName The type of event to listen for
860 * @param {Function} handler The method the event invokes
861 * @param {<i>Object</i>} scope (optional) An arbitrary object that will be
862 * passed as a parameter to the handler
863 * @param {<i>boolean</i>} override (optional) If true, the obj passed in becomes
864 * the execution scope of the listener
865 * @return {YAHOO.ext.Element} this
866 */
867 on : function(eventName, handler, scope, override){
868 YAHOO.util.Event.addListener(this.dom, eventName, handler, scope || this, true);
869 return this;
870 },
871
872 /**
873 * Append a managed listener - See {@link YAHOO.ext.EventObject} for more details. Use mon() for a shorter version.
874 * @param {String} eventName The type of event to listen for
875 * @param {Function} fn The method the event invokes
876 * @param {<i>Object</i>} scope (optional) An arbitrary object that will be
877 * passed as a parameter to the handler
878 * @param {<i>boolean</i>} override (optional) If true, the obj passed in becomes
879 * the execution scope of the listener
880 * @return {Function} The EventManager wrapped function that can be used to remove the listener
881 */
882 addManagedListener : function(eventName, fn, scope, override){
883 return YAHOO.ext.EventManager.on(this.dom, eventName, fn, scope || this, true);
884 },
885
886 /**
887 * Append a managed listener (shorthanded for {@link #addManagedListener})
888 * @param {String} eventName The type of event to listen for
889 * @param {Function} fn The method the event invokes
890 * @param {<i>Object</i>} scope (optional) An arbitrary object that will be
891 * passed as a parameter to the handler
892 * @param {<i>boolean</i>} override (optional) If true, the obj passed in becomes
893 * the execution scope of the listener
894 * @return {Function} The EventManager wrapped function that can be used to remove the listener
895 */
896 mon : function(eventName, fn, scope, override){
897 return YAHOO.ext.EventManager.on(this.dom, eventName, fn, scope || this, true);
898 },
899 /**
900 * Removes an event handler from this element
901 * @param {String} sType the type of event to remove
902 * @param {Function} fn the method the event invokes
903 * @param {Object} scope
904 * @return {YAHOO.ext.Element} this
905 */
906 removeListener : function(eventName, handler, scope){
907 YAHOO.util.Event.removeListener(this.dom, eventName, handler);
908 return this;
909 },
910
911 /**
912 * Removes all previous added listeners from this element
913 * @return {YAHOO.ext.Element} this
914 */
915 removeAllListeners : function(){
916 YAHOO.util.Event.purgeElement(this.dom);
917 return this;
918 },
919
920
921 /**
922 * Set the opacity of the element
923 * @param {Float} opacity The new opacity. 0 = transparent, .5 = 50% visibile, 1 = fully visible, etc
924 * @param {<i>Boolean</i>} animate (optional) Animate (fade) the transition (Default is false)
925 * @param {<i>Float</i>} duration (optional) How long the animation lasts. (Defaults to .35 seconds)
926 * @param {<i>Function</i>} onComplete (optional) Function to call when animation completes.
927 * @param {<i>Function</i>} easing (optional) YAHOO.util.Easing method to use. (Defaults to YAHOO.util.Easing.easeOut if height is larger or YAHOO.util.Easing.easeIn if it is smaller)
928 * @return {YAHOO.ext.Element} this
929 */
930 setOpacity : function(opacity, animate, duration, onComplete, easing){
931 if(!animate || !YAHOO.util.Anim){
932 YAHOO.util.Dom.setStyle(this.dom, 'opacity', opacity);
933 }else{
934 this.anim({opacity: {to: opacity}}, duration, onComplete, easing);
935 }
936 return this;
937 },
938
939 /**
940 * Gets the left X coordinate
941 * @param {Boolean} local True to get the local css position instead of page coordinate
942 * @return {Number}
943 */
944 getLeft : function(local){
945 if(!local){
946 return this.getX();
947 }else{
948 return parseInt(this.getStyle('left'), 10) || 0;
949 }
950 },
951
952 /**
953 * Gets the right X coordinate of the element (element X position + element width)
954 * @param {Boolean} local True to get the local css position instead of page coordinate
955 * @return {Number}
956 */
957 getRight : function(local){
958 if(!local){
959 return this.getX() + this.getWidth();
960 }else{
961 return (this.getLeft(true) + this.getWidth()) || 0;
962 }
963 },
964
965 /**
966 * Gets the top Y coordinate
967 * @param {Boolean} local True to get the local css position instead of page coordinate
968 * @return {Number}
969 */
970 getTop : function(local) {
971 if(!local){
972 return this.getY();
973 }else{
974 return parseInt(this.getStyle('top'), 10) || 0;
975 }
976 },
977
978 /**
979 * Gets the bottom Y coordinate of the element (element Y position + element height)
980 * @param {Boolean} local True to get the local css position instead of page coordinate
981 * @return {Number}
982 */
983 getBottom : function(local){
984 if(!local){
985 return this.getY() + this.getHeight();
986 }else{
987 return (this.getTop(true) + this.getHeight()) || 0;
988 }
989 },
990
991 /**
992 * Set the element as absolute positioned with the specified z-index
993 * @param {<i>Number</i>} zIndex (optional)
994 * @return {YAHOO.ext.Element} this
995 */
996 setAbsolutePositioned : function(zIndex){
997 this.setStyle('position', 'absolute');
998 if(zIndex){
999 this.setStyle('z-index', zIndex);
1000 }
1001 return this;
1002 },
1003
1004 /**
1005 * Set the element as relative positioned with the specified z-index
1006 * @param {<i>Number</i>} zIndex (optional)
1007 * @return {YAHOO.ext.Element} this
1008 */
1009 setRelativePositioned : function(zIndex){
1010 this.setStyle('position', 'relative');
1011 if(zIndex){
1012 this.setStyle('z-index', zIndex);
1013 }
1014 return this;
1015 },
1016
1017 /**
1018 * Clear positioning back to the default when the document was loaded
1019 * @return {YAHOO.ext.Element} this
1020 */
1021 clearPositioning : function(){
1022 this.setStyle('position', '');
1023 this.setStyle('left', '');
1024 this.setStyle('right', '');
1025 this.setStyle('top', '');
1026 this.setStyle('bottom', '');
1027 return this;
1028 },
1029
1030 /**
1031 * Gets an object with all CSS positioning properties. Useful along with setPostioning to get
1032 * snapshot before performing an update and then restoring the element.
1033 * @return {Object}
1034 */
1035 getPositioning : function(){
1036 return {
1037 'position' : this.getStyle('position'),
1038 'left' : this.getStyle('left'),
1039 'right' : this.getStyle('right'),
1040 'top' : this.getStyle('top'),
1041 'bottom' : this.getStyle('bottom')
1042 };
1043 },
1044
1045 /**
1046 * Gets the width of the border(s) for the specified side(s)
1047 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
1048 * passing lr would get the border (l)eft width + the border (r)ight width.
1049 * @return {Number} The width of the sides passed added together
1050 */
1051 getBorderWidth : function(side){
1052 return this.addStyles(side, YAHOO.ext.Element.borders);
1053 },
1054
1055 /**
1056 * Gets the width of the padding(s) for the specified side(s)
1057 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
1058 * passing lr would get the padding (l)eft + the padding (r)ight.
1059 * @return {Number} The padding of the sides passed added together
1060 */
1061 getPadding : function(side){
1062 return this.addStyles(side, YAHOO.ext.Element.paddings);
1063 },
1064
1065 /**
1066 * Set positioning with an object returned by getPositioning().
1067 * @param {Object} posCfg
1068 * @return {YAHOO.ext.Element} this
1069 */
1070 setPositioning : function(positionCfg){
1071 if(positionCfg.position)this.setStyle('position', positionCfg.position);
1072 if(positionCfg.left)this.setLeft(positionCfg.left);
1073 if(positionCfg.right)this.setRight(positionCfg.right);
1074 if(positionCfg.top)this.setTop(positionCfg.top);
1075 if(positionCfg.bottom)this.setBottom(positionCfg.bottom);
1076 return this;
1077 },
1078
1079
1080 /**
1081 * Quick set left and top adding default units
1082 * @return {YAHOO.ext.Element} this
1083 */
1084 setLeftTop : function(left, top){
1085 this.dom.style.left = this.addUnits(left);
1086 this.dom.style.top = this.addUnits(top);
1087 return this;
1088 },
1089
1090 /**
1091 * Move this element relative to it's current position.
1092 * @param {String} direction Possible values are: 'l','left' - 'r','right' - 't','top','up' - 'b','bottom','down'.
1093 * @param {Number} distance How far to move the element in pixels
1094 * @param {<i>Boolean</i>} animate (optional) Animate the movement (Default is false)
1095 * @param {<i>Float</i>} duration (optional) How long the animation lasts. (Defaults to .35 seconds)
1096 * @param {<i>Function</i>} onComplete (optional) Function to call when animation completes.
1097 * @param {<i>Function</i>} easing (optional) YAHOO.util.Easing method to use.
1098 * @return {YAHOO.ext.Element} this
1099 */
1100 move : function(direction, distance, animate, duration, onComplete, easing){
1101 var xy = this.getXY();
1102 direction = direction.toLowerCase();
1103 switch(direction){
1104 case 'l':
1105 case 'left':
1106 this.moveTo(xy[0]-distance, xy[1], animate, duration, onComplete, easing);
1107 break;
1108 case 'r':
1109 case 'right':
1110 this.moveTo(xy[0]+distance, xy[1], animate, duration, onComplete, easing);
1111 break;
1112 case 't':
1113 case 'top':
1114 case 'up':
1115 this.moveTo(xy[0], xy[1]-distance, animate, duration, onComplete, easing);
1116 break;
1117 case 'b':
1118 case 'bottom':
1119 case 'down':
1120 this.moveTo(xy[0], xy[1]+distance, animate, duration, onComplete, easing);
1121 break;
1122 }
1123 return this;
1124 },
1125
1126 /**
1127 * Store the current overflow setting and clip overflow on the element - use {@link #unclip} to remove
1128 * @return {YAHOO.ext.Element} this
1129 */
1130 clip : function(){
1131 if(!this.isClipped){
1132 this.isClipped = true;
1133 this.originalClip = {
1134 'o': this.getStyle('overflow'),
1135 'x': this.getStyle('overflow-x'),
1136 'y': this.getStyle('overflow-y')
1137 };
1138 this.setStyle('overflow', 'hidden');
1139 this.setStyle('overflow-x', 'hidden');
1140 this.setStyle('overflow-y', 'hidden');
1141 }
1142 return this;
1143 },
1144
1145 /**
1146 * Return clipping (overflow) to original clipping before clip() was called
1147 * @return {YAHOO.ext.Element} this
1148 */
1149 unclip : function(){
1150 if(this.isClipped){
1151 this.isClipped = false;
1152 var o = this.originalClip;
1153 if(o.o){this.setStyle('overflow', o.o);}
1154 if(o.x){this.setStyle('overflow-x', o.x);}
1155 if(o.y){this.setStyle('overflow-y', o.y);}
1156 }
1157 return this;
1158 },
1159
1160 /**
1161 * Align this element with another element.
1162 * @param {String/HTMLElement/YAHOO.ext.Element} element The element to align to.
1163 * @param {String} position The position to align to. Possible values are 'tl' - top left, 'tr' - top right, 'bl' - bottom left, and 'br' - bottom right.
1164 * @param {<i>Array</i>} offsets (optional) Offset the positioning by [x, y]
1165 * @param {<i>Boolean</i>} animate (optional) Animate the movement (Default is false)
1166 * @param {<i>Float</i>} duration (optional) How long the animation lasts. (Defaults to .35 seconds)
1167 * @param {<i>Function</i>} onComplete (optional) Function to call when animation completes.
1168 * @param {<i>Function</i>} easing (optional) YAHOO.util.Easing method to use.
1169 * @return {YAHOO.ext.Element} this
1170 */
1171 alignTo : function(element, position, offsets, animate, duration, onComplete, easing){
1172 var otherEl = getEl(element);
1173 if(!otherEl){
1174 return this; // must not exist
1175 }
1176 offsets = offsets || [0, 0];
1177 var r = otherEl.getRegion();
1178 position = position.toLowerCase();
1179 switch(position){
1180 case 'bl':
1181 this.moveTo(r.left + offsets[0], r.bottom + offsets[1],
1182 animate, duration, onComplete, easing);
1183 break;
1184 case 'br':
1185 this.moveTo(r.right + offsets[0], r.bottom + offsets[1],
1186 animate, duration, onComplete, easing);
1187 break;
1188 case 'tl':
1189 this.moveTo(r.left + offsets[0], r.top + offsets[1],
1190 animate, duration, onComplete, easing);
1191 break;
1192 case 'tr':
1193 this.moveTo(r.right + offsets[0], r.top + offsets[1],
1194 animate, duration, onComplete, easing);
1195 break;
1196 }
1197 return this;
1198 },
1199
1200 /**
1201 * Clears any opacity settings from this element. Required in some cases for IE.
1202 * @return {YAHOO.ext.Element} this
1203 */
1204 clearOpacity : function(){
1205 if (window.ActiveXObject) {
1206 this.dom.style.filter = '';
1207 } else {
1208 this.dom.style.opacity = '';
1209 this.dom.style['-moz-opacity'] = '';
1210 this.dom.style['-khtml-opacity'] = '';
1211 }
1212 return this;
1213 },
1214
1215 /**
1216 * Hide this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
1217 * @param {<i>Boolean</i>} animate (optional) Animate (fade) the transition (Default is false)
1218 * @param {<i>Float</i>} duration (optional) How long the animation lasts. (Defaults to .35 seconds)
1219 * @param {<i>Function</i>} onComplete (optional) Function to call when animation completes.
1220 * @param {<i>Function</i>} easing (optional) YAHOO.util.Easing method to use. (Defaults to YAHOO.util.Easing.easeBoth)
1221 * @return {YAHOO.ext.Element} this
1222 */
1223 hide : function(animate, duration, onComplete, easing){
1224 this.setVisible(false, animate, duration, onComplete, easing);
1225 return this;
1226 },
1227
1228 /**
1229 * Show this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
1230 * @param {<i>Boolean</i>} animate (optional) Animate (fade in) the transition (Default is false)
1231 * @param {<i>Float</i>} duration (optional) How long the animation lasts. (Defaults to .35 seconds)
1232 * @param {<i>Function</i>} onComplete (optional) Function to call when animation completes.
1233 * @param {<i>Function</i>} easing (optional) YAHOO.util.Easing method to use. (Defaults to YAHOO.util.Easing.easeBoth)
1234 * @return {YAHOO.ext.Element} this
1235 */
1236 show : function(animate, duration, onComplete, easing){
1237 this.setVisible(true, animate, duration, onComplete, easing);
1238 return this;
1239 },
1240
1241 /**
1242 * @private Test if size has a unit, otherwise appends the default
1243 */
1244 addUnits : function(size){
1245 if(size === '' || size == 'auto' || typeof size == 'undefined'){
1246 return size;
1247 }
1248 if(typeof size == 'number' || !YAHOO.ext.Element.unitPattern.test(size)){
1249 return size + this.defaultUnit;
1250 }
1251 return size;
1252 },
1253
1254 /**
1255 * Temporarily enables offsets (width,height,x,y) for an element with display:none, use endMeasure() when done.
1256 * @return {YAHOO.ext.Element} this
1257 */
1258 beginMeasure : function(){
1259 var el = this.dom;
1260 if(el.offsetWidth || el.offsetHeight){
1261 return this; // offsets work already
1262 }
1263 var changed = [];
1264 var p = this.dom; // start with this element
1265 while((!el.offsetWidth && !el.offsetHeight) && p && p.tagName && p.tagName.toLowerCase() != 'body'){
1266 if(YAHOO.util.Dom.getStyle(p, 'display') == 'none'){
1267 changed.push({el: p, visibility: YAHOO.util.Dom.getStyle(p, 'visibility')});
1268 p.style.visibility = 'hidden';
1269 p.style.display = 'block';
1270 }
1271 p = p.parentNode;
1272 }
1273 this._measureChanged = changed;
1274 return this;
1275
1276 },
1277
1278 /**
1279 * Restores displays to before beginMeasure was called
1280 * @return {YAHOO.ext.Element} this
1281 */
1282 endMeasure : function(){
1283 var changed = this._measureChanged;
1284 if(changed){
1285 for(var i = 0, len = changed.length; i < len; i++) {
1286 var r = changed[i];
1287 r.el.style.visibility = r.visibility;
1288 r.el.style.display = 'none';
1289 }
1290 this._measureChanged = null;
1291 }
1292 return this;
1293 },
1294
1295 /**
1296 * Update the innerHTML of this element, optionally searching for and processing scripts
1297 * @param {String} html The new HTML
1298 * @param {<i>Boolean</i>} loadScripts (optional) true to look for and process scripts
1299 * @param {Function} callback For async script loading you can be noticed when the update completes
1300 * @return {YAHOO.ext.Element} this
1301 */
1302 update : function(html, loadScripts, callback){
1303 if(typeof html == 'undefined'){
1304 html = '';
1305 }
1306 if(loadScripts !== true){
1307 this.dom.innerHTML = html;
1308 if(typeof callback == 'function'){
1309 callback();
1310 }
1311 return this;
1312 }
1313 var id = YAHOO.util.Dom.generateId();
1314 var dom = this.dom;
1315
1316 html += '<span id="' + id + '"></span>';
1317
1318 YAHOO.util.Event.onAvailable(id, function(){
1319 var hd = document.getElementsByTagName("head")[0];
1320 var re = /(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/img;
1321 var srcRe = /\ssrc=([\'\"])(.*?)\1/i;
1322 var match;
1323 while(match = re.exec(html)){
1324 var srcMatch = match[0].match(srcRe);
1325 if(srcMatch && srcMatch[2]){
1326 var s = document.createElement("script");
1327 s.src = srcMatch[2];
1328 hd.appendChild(s);
1329 }else if(match[1] && match[1].length > 0){
1330 eval(match[1]);
1331 }
1332 }
1333 var el = document.getElementById(id);
1334 if(el){el.parentNode.removeChild(el);}
1335 if(typeof callback == 'function'){
1336 callback();
1337 }
1338 });
1339 dom.innerHTML = html.replace(/(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/img, '');
1340 return this;
1341 },
1342
1343 /**
1344 * Direct access to the UpdateManager update() method (takes the same parameters).
1345 * @param {String/Function} url The url for this request or a function to call to get the url
1346 * @param {<i>String/Object</i>} params (optional) The parameters to pass as either a url encoded string "param1=1&amp;param2=2" or an object {param1: 1, param2: 2}
1347 * @param {<i>Function</i>} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
1348 * @param {<i>Boolean</i>} discardUrl (optional) By default when you execute an update the defaultUrl is changed to the last used url. If true, it will not store the url.
1349 * @return {YAHOO.ext.Element} this
1350 */
1351 load : function(){
1352 var um = this.getUpdateManager();
1353 um.update.apply(um, arguments);
1354 return this;
1355 },
1356
1357 /**
1358 * Gets this elements UpdateManager
1359 * @return {YAHOO.ext.UpdateManager} The UpdateManager
1360 */
1361 getUpdateManager : function(){
1362 if(!this.updateManager){
1363 this.updateManager = new YAHOO.ext.UpdateManager(this);
1364 }
1365 return this.updateManager;
1366 },
1367
1368 /**
1369 * Disables text selection for this element (normalized across browsers)
1370 * @return {YAHOO.ext.Element} this
1371 */
1372 unselectable : function(){
1373 this.dom.unselectable = 'on';
1374 this.swallowEvent('selectstart', true);
1375 this.applyStyles('-moz-user-select:none;-khtml-user-select:none;');
1376 return this;
1377 },
1378
1379 /**
1380 * Calculates the x, y to center this element on the screen
1381 * @param {Boolean} offsetScroll True to offset the documents current scroll position
1382 * @return {Array} The x, y values [x, y]
1383 */
1384 getCenterXY : function(offsetScroll){
1385 var centerX = Math.round((YAHOO.util.Dom.getViewportWidth()-this.getWidth())/2);
1386 var centerY = Math.round((YAHOO.util.Dom.getViewportHeight()-this.getHeight())/2);
1387 if(!offsetScroll){
1388 return [centerX, centerY];
1389 }else{
1390 var scrollX = document.documentElement.scrollLeft || document.body.scrollLeft || 0;
1391 var scrollY = document.documentElement.scrollTop || document.body.scrollTop || 0;
1392 return[centerX + scrollX, centerY + scrollY];
1393 }
1394 },
1395
1396 /**
1397 * Centers the Element in either the viewport, or another Element.
1398 * @param {String/HTMLElement/YAHOO.ext.Element} centerIn (optional) The element in which to center the element.
1399 */
1400 center : function(centerIn) {
1401 if(!centerIn){
1402 this.setXY(this.getCenterXY(true));
1403 }else{
1404 var box = YAHOO.ext.Element.get(centerIn).getBox();
1405 this.setXY([box.x + (box.width / 2) - (this.getWidth() / 2),
1406 box.y + (box.height / 2) - (this.getHeight() / 2)]);
1407 }
1408 return this;
1409 },
1410
1411 /**
1412 * Gets an array of child YAHOO.ext.Element objects by tag name
1413 * @param {String} tagName
1414 * @return {Array} The children
1415 */
1416 getChildrenByTagName : function(tagName){
1417 var children = this.dom.getElementsByTagName(tagName);
1418 var len = children.length;
1419 var ce = new Array(len);
1420 for(var i = 0; i < len; ++i){
1421 ce[i] = YAHOO.ext.Element.get(children[i], true);
1422 }
1423 return ce;
1424 },
1425
1426 /**
1427 * Gets an array of child YAHOO.ext.Element objects by class name and optional tagName
1428 * @param {String} className
1429 * @param {<i>String</i>} tagName (optional)
1430 * @return {Array} The children
1431 */
1432 getChildrenByClassName : function(className, tagName){
1433 var children = YAHOO.util.Dom.getElementsByClassName(className, tagName, this.dom);
1434 var len = children.length;
1435 var ce = new Array(len);
1436 for(var i = 0; i < len; ++i){
1437 ce[i] = YAHOO.ext.Element.get(children[i], true);
1438 }
1439 return ce;
1440 },
1441
1442 /**
1443 * Tests various css rules/browsers to determine if this element uses a border box
1444 * @return {Boolean}
1445 */
1446 isBorderBox : function(){
1447 if(typeof this.bbox == 'undefined'){
1448 var el = this.dom;
1449 var b = YAHOO.ext.util.Browser;
1450 var strict = YAHOO.ext.Strict;
1451 this.bbox = ((b.isIE && !strict && el.style.boxSizing != 'content-box') ||
1452 (b.isGecko && YAHOO.util.Dom.getStyle(el, "-moz-box-sizing") == 'border-box') ||
1453 (!b.isSafari && YAHOO.util.Dom.getStyle(el, "box-sizing") == 'border-box'));
1454 }
1455 return this.bbox;
1456 },
1457
1458 /**
1459 * Return a box {x, y, width, height} that can be used to set another elements
1460 * size/location to match this element.
1461 * @param {Boolean} contentBox (optional) If true a box for the content of the element is returned.
1462 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page x/y.
1463 * @return {Object}
1464 */
1465 getBox : function(contentBox, local){
1466 var xy;
1467 if(!local){
1468 xy = this.getXY();
1469 }else{
1470 var left = parseInt(YAHOO.util.Dom.getStyle('left'), 10) || 0;
1471 var top = parseInt(YAHOO.util.Dom.getStyle('top'), 10) || 0;
1472 xy = [left, top];
1473 }
1474 var el = this.dom;
1475 var w = el.offsetWidth;
1476 var h = el.offsetHeight;
1477 if(!contentBox){
1478 return {x: xy[0], y: xy[1], width: w, height: h};
1479 }else{
1480 var l = this.getBorderWidth('l')+this.getPadding('l');
1481 var r = this.getBorderWidth('r')+this.getPadding('r');
1482 var t = this.getBorderWidth('t')+this.getPadding('t');
1483 var b = this.getBorderWidth('b')+this.getPadding('b');
1484 return {x: xy[0]+l, y: xy[1]+t, width: w-(l+r), height: h-(t+b)};
1485 }
1486 },
1487
1488 /**
1489 * Sets the element's box. Use getBox() on another element to get a box obj. If animate is true then width, height, x and y will be animated concurrently.
1490 * @param {Object} box The box to fill {x, y, width, height}
1491 * @param {<i>Boolean</i>} adjust (optional) Whether to adjust for box-model issues automatically
1492 * @param {<i>Boolean</i>} animate (optional) Animate the transition (Default is false)
1493 * @param {<i>float</i>} duration (optional) How long the animation lasts. (Defaults to .35 seconds)
1494 * @param {<i>Function</i>} onComplete (optional) Function to call when animation completes.
1495 * @param {<i>Function</i>} easing (optional) YAHOO.util.Easing method to use. (Defaults to YAHOO.util.Easing.easeBoth)
1496 * @return {YAHOO.ext.Element} this
1497 */
1498 setBox : function(box, adjust, animate, duration, onComplete, easing){
1499 var w = box.width, h = box.height;
1500 if((adjust && !this.autoBoxAdjust) && !this.isBorderBox()){
1501 w -= (this.getBorderWidth('lr') + this.getPadding('lr'));
1502 h -= (this.getBorderWidth('tb') + this.getPadding('tb'));
1503 }
1504 this.setBounds(box.x, box.y, w, h, animate, duration, onComplete, easing);
1505 return this;
1506 },
1507
1508 /**
1509 * Forces the browser to repaint this element
1510 * @return {YAHOO.ext.Element} this
1511 */
1512 repaint : function(){
1513 var dom = this.dom;
1514 YAHOO.util.Dom.addClass(dom, 'yui-ext-repaint');
1515 setTimeout(function(){
1516 YAHOO.util.Dom.removeClass(dom, 'yui-ext-repaint');
1517 }, 1);
1518 return this;
1519 },
1520
1521 /**
1522 * Returns an object with properties top, left, right and bottom representing the margins of this element unless sides is passed,
1523 * then it returns the calculated width of the sides (see getPadding)
1524 * @param {String} sides (optional) Any combination of l, r, t, b to get the sum of those sides
1525 * @return {Object/Number}
1526 */
1527 getMargins : function(side){
1528 if(!side){
1529 return {
1530 top: parseInt(this.getStyle('margin-top'), 10) || 0,
1531 left: parseInt(this.getStyle('margin-left'), 10) || 0,
1532 bottom: parseInt(this.getStyle('margin-bottom'), 10) || 0,
1533 right: parseInt(this.getStyle('margin-right'), 10) || 0
1534 };
1535 }else{
1536 return this.addStyles(side, YAHOO.ext.Element.margins);
1537 }
1538 },
1539
1540 addStyles : function(sides, styles){
1541 var val = 0;
1542 for(var i = 0, len = sides.length; i < len; i++){
1543 var w = parseInt(this.getStyle(styles[sides.charAt(i)]), 10);
1544 if(!isNaN(w)) val += w;
1545 }
1546 return val;
1547 },
1548
1549 /**
1550 * Creates a proxy element of this element
1551 * @param {String/Object} config The class name of the proxy element or a DomHelper config object
1552 * @param {<i>String/HTMLElement</i>} renderTo (optional) The element or element id to render the proxy to (defaults to document.body)
1553 * @param {<i>Boolean</i>} matchBox (optional) True to align and size the proxy to this element now (defaults to false)
1554 * @return {YAHOO.ext.Element} The new proxy element
1555 */
1556 createProxy : function(config, renderTo, matchBox){
1557 if(renderTo){
1558 renderTo = YAHOO.util.Dom.get(renderTo);
1559 }else{
1560 renderTo = document.body;
1561 }
1562 config = typeof config == 'object' ?
1563 config : {tag : 'div', cls: config};
1564 var proxy = YAHOO.ext.DomHelper.append(renderTo, config, true);
1565 if(matchBox){
1566 proxy.setBox(this.getBox());
1567 }
1568 return proxy;
1569 },
1570
1571 /**
1572 * Puts a mask over this element to disable user interaction. Requires core.css.
1573 * This method can only be applied to elements which accept child nodes.
1574 * @return {Element} The message element
1575 */
1576 mask : function(){
1577 if(this.getStyle('position') == 'static'){
1578 this.setStyle('position', 'relative');
1579 }
1580 if(!this._mask){
1581 this._mask = YAHOO.ext.DomHelper.append(this.dom, {tag:'div', cls:'ext-el-mask'}, true);
1582 }
1583 this.addClass('ext-masked');
1584 this._mask.setDisplayed(true);
1585 return this._mask;
1586 },
1587
1588 /**
1589 * Removes a previously applied mask. If removeEl is true the mask overlay is destroyed, otherwise
1590 * it is cached for reuse.
1591 */
1592 unmask : function(removeEl){
1593 if(this._mask){
1594 removeEl === true ?
1595 this._mask.remove() : this._mask.setDisplayed(false);
1596 }
1597 this.removeClass('ext-masked');
1598 },
1599
1600 /**
1601 * Creates an iframe shim for this element to keep selects and other windowed objects from
1602 * showing through.
1603 * @return {YAHOO.ext.Element} The new shim element
1604 */
1605 createShim : function(){
1606 var config = {
1607 tag : 'iframe',
1608 frameBorder:'no',
1609 cls: 'yiframe-shim',
1610 style: 'position:absolute;visibility:hidden;left:0;top:0;overflow:hidden;',
1611 src: YAHOO.ext.SSL_SECURE_URL
1612 };
1613 var shim = YAHOO.ext.DomHelper.insertBefore(this.dom, config, true);
1614 shim.setOpacity(.01);
1615 shim.setBox(this.getBox());
1616 return shim;
1617 },
1618
1619 /**
1620 * Removes this element from the DOM and deletes it from the cache
1621 */
1622 remove : function(){
1623 this.dom.parentNode.removeChild(this.dom);
1624 delete YAHOO.ext.Element.cache[this.dom.id];
1625 },
1626
1627 /**
1628 * Sets up event handlers to add and remove a css class when the mouse is over this element
1629 * @param {String} className
1630 * @return {YAHOO.ext.Element} this
1631 */
1632 addClassOnOver : function(className){
1633 this.on('mouseover', function(){
1634 this.addClass(className);
1635 }, this, true);
1636 this.on('mouseout', function(){
1637 this.removeClass(className);
1638 }, this, true);
1639 return this;
1640 },
1641
1642 /**
1643 * Stops the specified event from bubbling and optionally prevent's the default action
1644 * @param {String} eventName
1645 * @param {Boolean} preventDefault (optional) true to prevent the default action too
1646 * @return {YAHOO.ext.Element} this
1647 */
1648 swallowEvent : function(eventName, preventDefault){
1649 var fn = function(e){
1650 e.stopPropagation();
1651 if(preventDefault){
1652 e.preventDefault();
1653 }
1654 };
1655 this.mon(eventName, fn);
1656 return this;
1657 },
1658
1659 /**
1660 * Sizes this element to it's parent element's dimensions performing
1661 * neccessary box adjustments.
1662 * @param {Boolean} monitorResize (optional) If true maintains the fit when the browser window is resized.
1663 * @param {String/HTMLElment/Element} targetParent (optional) The target parent, default to the parentNode.
1664 * @return {YAHOO.ext.Element} this
1665 */
1666 fitToParent : function(monitorResize, targetParent){
1667 var p = getEl(targetParent || this.dom.parentNode);
1668 p.beginMeasure(); // in case parent is display:none
1669 var box = p.getBox(true, true);
1670 p.endMeasure();
1671 this.setSize(box.width, box.height);
1672 if(monitorResize === true){
1673 YAHOO.ext.EventManager.onWindowResize(this.fitToParent, this, true);
1674 }
1675 return this;
1676 },
1677
1678 /**
1679 * Gets the next sibling, skipping text nodes
1680 * @return {HTMLElement} The next sibling or null
1681 */
1682 getNextSibling : function(){
1683 var n = this.dom.nextSibling;
1684 while(n && n.nodeType != 1){
1685 n = n.nextSibling;
1686 }
1687 return n;
1688 },
1689
1690 /**
1691 * Gets the previous sibling, skipping text nodes
1692 * @return {HTMLElement} The previous sibling or null
1693 */
1694 getPrevSibling : function(){
1695 var n = this.dom.previousSibling;
1696 while(n && n.nodeType != 1){
1697 n = n.previousSibling;
1698 }
1699 return n;
1700 },
1701
1702
1703 /**
1704 * Appends the passed element(s) to this element
1705 * @param {String/HTMLElement/Array/Element/CompositeElement} el
1706 * @return {YAHOO.ext.Element} this
1707 */
1708 appendChild: function(el){
1709 el = getEl(el);
1710 el.appendTo(this);
1711 return this;
1712 },
1713
1714 /**
1715 * Creates the passed DomHelper config and appends it to this element or optionally inserts it before the passed child element.
1716 * @param {Object} config DomHelper element config object
1717 * @param {<i>HTMLElement</i>} insertBefore (optional) a child element of this element
1718 * @return {YAHOO.ext.Element} The new child element
1719 */
1720 createChild: function(config, insertBefore){
1721 var c;
1722 if(insertBefore){
1723 c = YAHOO.ext.DomHelper.insertBefore(insertBefore, config, true);
1724 }else{
1725 c = YAHOO.ext.DomHelper.append(this.dom, config, true);
1726 }
1727 return c;
1728 },
1729
1730 /**
1731 * Appends this element to the passed element
1732 * @param {String/HTMLElement/Element} el The new parent element
1733 * @return {YAHOO.ext.Element} this
1734 */
1735 appendTo: function(el){
1736 var node = getEl(el).dom;
1737 node.appendChild(this.dom);
1738 return this;
1739 },
1740
1741 /**
1742 * Inserts this element before the passed element in the DOM
1743 * @param {String/HTMLElement/Element} el The element to insert before
1744 * @return {YAHOO.ext.Element} this
1745 */
1746 insertBefore: function(el){
1747 var node = getEl(el).dom;
1748 node.parentNode.insertBefore(this.dom, node);
1749 return this;
1750 },
1751
1752 /**
1753 * Inserts this element after the passed element in the DOM
1754 * @param {String/HTMLElement/Element} el The element to insert after
1755 * @return {YAHOO.ext.Element} this
1756 */
1757 insertAfter: function(el){
1758 var node = getEl(el).dom;
1759 node.parentNode.insertBefore(this.dom, node.nextSibling);
1760 return this;
1761 },
1762
1763 /**
1764 * Creates and wraps this element with another element
1765 * @param {Object} config (optional) DomHelper element config object for the wrapper element or null for an empty div
1766 * @return {Element} The newly created wrapper element
1767 */
1768 wrap: function(config){
1769 if(!config){
1770 config = {tag: 'div'};
1771 }
1772 var newEl = YAHOO.ext.DomHelper.insertBefore(this.dom, config, true);
1773 newEl.dom.appendChild(this.dom);
1774 return newEl;
1775 },
1776
1777 /**
1778 * Replaces the passed element with this element
1779 * @param {String/HTMLElement/Element} el The element to replace
1780 * @return {YAHOO.ext.Element} this
1781 */
1782 replace: function(el){
1783 el = getEl(el);
1784 this.insertBefore(el);
1785 el.remove();
1786 return this;
1787 },
1788
1789 /**
1790 * Inserts an html fragment into this element
1791 * @param {String} where Where to insert the html in relation to the this element - beforeBegin, afterBegin, beforeEnd, afterEnd.
1792 * @param {String} html The HTML fragment
1793 * @return {HTMLElement} The inserted node (or nearest related if more than 1 inserted)
1794 */
1795 insertHtml : function(where, html){
1796 return YAHOO.ext.DomHelper.insertHtml(where, this.dom, html);
1797 },
1798
1799 /**
1800 * Sets the passed attributes as attributes of this element (a style attribute can be a string, object or function)
1801 * @param {Object} o The object with the attributes
1802 * @return {YAHOO.ext.Element} this
1803 */
1804 set : function(o){
1805 var el = this.dom;
1806 var useSet = el.setAttribute ? true : false;
1807 for(var attr in o){
1808 if(attr == 'style' || typeof o[attr] == 'function') continue;
1809 if(attr=='cls'){
1810 el.className = o['cls'];
1811 }else{
1812 if(useSet) el.setAttribute(attr, o[attr]);
1813 else el[attr] = o[attr];
1814 }
1815 }
1816 YAHOO.ext.DomHelper.applyStyles(el, o.style);
1817 return this;
1818 },
1819
1820 /**
1821 * Convenience method for constructing a KeyMap
1822 * @param {Number/Array/Object/String} key Either a string with the keys to listen for, the numeric key code, array of key codes or an object with the following options:
1823 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
1824 * @param {Function} fn The function to call
1825 * @param {Object} scope (optional) The scope of the function
1826 * @return {YAHOO.ext.KeyMap} The KeyMap created
1827 */
1828 addKeyListener : function(key, fn, scope){
1829 var config;
1830 if(typeof key != 'object' || key instanceof Array){
1831 config = {
1832 key: key,
1833 fn: fn,
1834 scope: scope
1835 };
1836 }else{
1837 config = {
1838 key : key.key,
1839 shift : key.shift,
1840 ctrl : key.ctrl,
1841 alt : key.alt,
1842 fn: fn,
1843 scope: scope
1844 };
1845 }
1846 var map = new YAHOO.ext.KeyMap(this, config);
1847 return map;
1848 },
1849
1850 /**
1851 * Creates a KeyMap for this element
1852 * @param {Object} config The KeyMap config. See {@link YAHOO.ext.KeyMap} for more details
1853 * @return {YAHOO.ext.KeyMap} The KeyMap created
1854 */
1855 addKeyMap : function(config){
1856 return new YAHOO.ext.KeyMap(this, config);
1857 },
1858
1859 /**
1860 * Returns true if this element is scrollable.
1861 * @return {Boolean}
1862 */
1863 isScrollable : function(){
1864 var dom = this.dom;
1865 return dom.scrollHeight > dom.clientHeight || dom.scrollWidth > dom.clientWidth;
1866 },
1867
1868 /**
1869 * Scrolls this element the specified scroll point. It does NOT do bounds checking so if you scroll to a weird value it will try to do it. For auto bounds checking, use scroll().
1870 * @param {String} side Either 'left' for scrollLeft values or 'top' for scrollTop values.
1871 * @param {Number} value The new scroll value
1872 * @param {<i>Boolean</i>} animate (optional) Animate the scroll (Default is false)
1873 * @param {<i>Float</i>} duration (optional) How long the animation lasts. (Defaults to .35 seconds)
1874 * @param {<i>Function</i>} onComplete (optional) Function to call when animation completes.
1875 * @param {<i>Function</i>} easing (optional) YAHOO.util.Easing method to use.
1876 * @return {Element} this
1877 */
1878
1879 scrollTo : function(side, value, animate, duration, onComplete, easing){
1880 var prop = side.toLowerCase() == 'left' ? 'scrollLeft' : 'scrollTop';
1881 if(!animate || !YAHOO.util.Anim){
1882 this.dom[prop] = value;
1883 }else{
1884 var to = prop == 'scrollLeft' ? [value, this.dom.scrollTop] : [this.dom.scrollLeft, value];
1885 this.anim({scroll: {'to': to}}, duration, onComplete, easing || YAHOO.util.Easing.easeOut, YAHOO.util.Scroll);
1886 }
1887 return this;
1888 },
1889
1890 /**
1891 * Scrolls this element the specified direction. Does bounds checking to make sure the scroll is
1892 * within this elements scrollable range.
1893 * @param {String} direction Possible values are: 'l','left' - 'r','right' - 't','top','up' - 'b','bottom','down'.
1894 * @param {Number} distance How far to scroll the element in pixels
1895 * @param {<i>Boolean</i>} animate (optional) Animate the scroll (Default is false)
1896 * @param {<i>Float</i>} duration (optional) How long the animation lasts. (Defaults to .35 seconds)
1897 * @param {<i>Function</i>} onComplete (optional) Function to call when animation completes.
1898 * @param {<i>Function</i>} easing (optional) YAHOO.util.Easing method to use.
1899 * @return {Boolean} Returns true if a scroll was triggered or false if the element
1900 * was scrolled as far as it could go.
1901 */
1902 scroll : function(direction, distance, animate, duration, onComplete, easing){
1903 if(!this.isScrollable()){
1904 return;
1905 }
1906 var el = this.dom;
1907 var l = el.scrollLeft, t = el.scrollTop;
1908 var w = el.scrollWidth, h = el.scrollHeight;
1909 var cw = el.clientWidth, ch = el.clientHeight;
1910 direction = direction.toLowerCase();
1911 var scrolled = false;
1912 switch(direction){
1913 case 'l':
1914 case 'left':
1915 if(w - l > cw){
1916 var v = Math.min(l + distance, w-cw);
1917 this.scrollTo('left', v, animate, duration, onComplete, easing);
1918 scrolled = true;
1919 }
1920 break;
1921 case 'r':
1922 case 'right':
1923 if(l > 0){
1924 var v = Math.max(l - distance, 0);
1925 this.scrollTo('left', v, animate, duration, onComplete, easing);
1926 scrolled = true;
1927 }
1928 break;
1929 case 't':
1930 case 'top':
1931 case 'up':
1932 if(t > 0){
1933 var v = Math.max(t - distance, 0);
1934 this.scrollTo('top', v, animate, duration, onComplete, easing);
1935 scrolled = true;
1936 }
1937 break;
1938 case 'b':
1939 case 'bottom':
1940 case 'down':
1941 if(h - t > ch){
1942 var v = Math.min(t + distance, h-ch);
1943 this.scrollTo('top', v, animate, duration, onComplete, easing);
1944 scrolled = true;
1945 }
1946 break;
1947 }
1948 return scrolled;
1949 },
1950
1951 /**
1952 * Return the CSS color for the specified CSS attribute. rgb, 3 digit (like #fff) and valid values
1953 * are convert to standard 6 digit hex color.
1954 * @param {String} attr The css attribute
1955 * @param {String} defaultValue The default value to use when a valid color isn't found
1956 * @param {String} prefix (optional) defaults to #. Use an empty string when working with
1957 * YUI color anims.
1958 */
1959 getColor : function(attr, defaultValue, prefix){
1960 var v = this.getStyle(attr);
1961 if(!v || v == 'transparent' || v == 'inherit') {
1962 return defaultValue;
1963 }
1964 var color = typeof prefix == 'undefined' ? '#' : prefix;
1965 if(v.substr(0, 4) == 'rgb('){
1966 var rvs = v.slice(4, v.length -1).split(',');
1967 for(var i = 0; i < 3; i++){
1968 var h = parseInt(rvs[i]).toString(16);
1969 if(h < 16){
1970 h = '0' + h;
1971 }
1972 color += h;
1973 }
1974 } else {
1975 if(v.substr(0, 1) == '#'){
1976 if(v.length == 4) {
1977 for(var i = 1; i < 4; i++){
1978 var c = v.charAt(i);
1979 color += c + c;
1980 }
1981 }else if(v.length == 7){
1982 color += v.slice(1, 6);
1983 }
1984 }
1985 }
1986 return(color.length > 5 ? color.toLowerCase() : defaultValue);
1987 },
1988
1989 /**
1990 * Highlights the Element by setting a color (defaults to background-color) and then
1991 * fading back to the original color. If no original color is available, you should
1992 * provide an "endColor" option which will be cleared after the animation. The available options
1993 * for the "options" parameter are listed below (with their default values): <br/>
1994<pre><code>
1995el.highlight('ff0000', {<br/>
1996 attr: 'background-color',<br/>
1997 endColor: (current color) or 'ffffff'<br/>
1998 callback: yourFunction,<br/>
1999 scope: yourObject,<br/>
2000 easing: YAHOO.util.Easing.easeNone, <br/>
2001 duration: .75<br/>
2002});
2003</code></pre>
2004 * @param {String} color (optional) The highlight color. Should be a 6 char hex color (no #). (defaults to ffff9c)
2005 * @param {Object} options (optional) Object literal with any of the options listed above
2006 */
2007 highlight : function(color, options){
2008 color = color || 'ffff9c';
2009 options = options || {};
2010 attr = options.attr || 'background-color';
2011 var origColor = this.getColor(attr);
2012 endColor = (options.endColor || origColor) || 'ffffff';
2013 var dom = this.dom;
2014 var cb = function(){
2015 YAHOO.util.Dom.setStyle(dom, attr, origColor || '');
2016 if(options.callback){
2017 options.callback.call(options.scope || window);
2018 }
2019 };
2020 var o = {};
2021 o[attr] = {from: color, to: endColor};
2022 this.anim(o, options.duration || .75, cb, options.easing || YAHOO.util.Easing.easeNone, YAHOO.util.ColorAnim);
2023 return this;
2024 }
2025};
2026
2027/**
2028 * true to automatically adjust width and height settings for box-model issues (default to true)
2029 */
2030YAHOO.ext.Element.prototype.autoBoxAdjust = true;
2031/**
2032 * true to automatically detect display mode and use display instead of visibility with show()/hide() (defaults to false).
2033 * To enable this globally:<pre><code>YAHOO.ext.Element.prototype.autoDisplayMode = true;</code></pre>
2034 */
2035YAHOO.ext.Element.prototype.autoDisplayMode = true;
2036
2037YAHOO.ext.Element.unitPattern = /\d+(px|em|%|en|ex|pt|in|cm|mm|pc)$/i;
2038/**
2039 * Visibility mode constant - Use visibility to hide element
2040 * @static
2041 * @type Number
2042 */
2043YAHOO.ext.Element.VISIBILITY = 1;
2044/**
2045 * Visibility mode constant - Use display to hide element
2046 * @static
2047 * @type Number
2048 */
2049YAHOO.ext.Element.DISPLAY = 2;
2050
2051YAHOO.ext.Element.blockElements = /^(?:address|blockquote|center|dir|div|dl|fieldset|form|h\d|hr|isindex|menu|ol|ul|p|pre|table|dd|dt|li|tbody|tr|td|thead|tfoot|iframe)$/i;
2052YAHOO.ext.Element.borders = {l: 'border-left-width', r: 'border-right-width', t: 'border-top-width', b: 'border-bottom-width'};
2053YAHOO.ext.Element.paddings = {l: 'padding-left', r: 'padding-right', t: 'padding-top', b: 'padding-bottom'};
2054YAHOO.ext.Element.margins = {l: 'margin-left', r: 'margin-right', t: 'margin-top', b: 'margin-bottom'};
2055
2056/**
2057 * @private Call out to here so we make minimal closure
2058 */
2059YAHOO.ext.Element.createStopHandler = function(stopPropagation, handler, scope, override){
2060 return function(e){
2061 if(e){
2062 if(stopPropagation){
2063 YAHOO.util.Event.stopEvent(e);
2064 }else {
2065 YAHOO.util.Event.preventDefault(e);
2066 }
2067 }
2068 handler.call(override && scope ? scope : window, e, scope);
2069 };
2070};
2071
2072/**
2073 * @private
2074 */
2075YAHOO.ext.Element.cache = {};
2076
2077/**
2078 * Static method to retreive Element objects. Uses simple caching to consistently return the same object.
2079 * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
2080 * @param {String/HTMLElement/Element} el The id of the element or the element to wrap (must have an id). If you pass in an element, it is returned
2081 * @return {Element} The element object
2082 * @static
2083 */
2084YAHOO.ext.Element.get = function(){
2085 var doc = document; // prevent IE dom lookup on every call to getEl
2086 var docEl;
2087 var E = YAHOO.ext.Element;
2088 var D = YAHOO.util.Dom;
2089
2090 return function(el){
2091 if(!el){ return null; }
2092 if(el instanceof E){
2093 if(el != docEl){
2094 el.dom = doc.getElementById(el.id); // refresh dom element in case no longer valid
2095 E.cache[el.id] = el; // in case it was created directly with Element(), let's cache it
2096 }
2097 return el;
2098 }else if(el.isComposite){
2099 return el;
2100 }else if(el instanceof Array){
2101 return E.select(el);
2102 }else if(el == doc){
2103 // create a bogus element object representing the document object
2104 if(!docEl){
2105 var f = function(){};
2106 f.prototype = E.prototype;
2107 docEl = new f();
2108 docEl.dom = doc;
2109 }
2110 return docEl;
2111 }
2112 var key = el;
2113 if(typeof el != 'string'){ // must be an element
2114 D.generateId(el, 'elgen-');
2115 key = el.id;
2116 }
2117 var element = E.cache[key];
2118 if(!element){
2119 element = new E(key);
2120 if(!element.dom) return null;
2121 E.cache[key] = element;
2122 }else{
2123 element.dom = doc.getElementById(key);
2124 }
2125 return element;
2126 };
2127}();
2128
2129/*
2130 * Gets the globally shared flyweight Element. Use sparingly for
2131 * bulk operations where a unique instance isn't needed.
2132 * Do not store a reference to this element - the dom node
2133 * can be overwritten by other code.
2134 */
2135YAHOO.ext.Element.fly = function(el){
2136 var E = YAHOO.ext.Element;
2137 if(typeof el == 'string'){
2138 el = document.getElementById(el);
2139 }
2140 if(!E._flyweight){
2141 var f = function(){};
2142 f.prototype = E.prototype;
2143 E._flyweight = new f();
2144 }
2145 E._flyweight.dom = el;
2146 return E._flyweight;
2147}
2148
2149/*
2150 * Shorthand function for YAHOO.ext.Element.get()
2151 */
2152getEl = YAHOO.ext.Element.get;
2153
2154YAHOO.util.Event.addListener(window, 'unload', function(){
2155 YAHOO.ext.Element.cache = null;
2156});
2157
diff --git a/frontend/beta/js/YUI-extensions/EventManager.js b/frontend/beta/js/YUI-extensions/EventManager.js
new file mode 100644
index 0000000..f9db759
--- a/dev/null
+++ b/frontend/beta/js/YUI-extensions/EventManager.js
@@ -0,0 +1,456 @@
1
2/**
3 * @class YAHOO.ext.EventManager
4 * Registers event handlers that want to receive a normalized EventObject instead of the standard browser event and provides
5 * several useful events directly.
6 * See {@link YAHOO.ext.EventObject} for more details on normalized event objects.
7 * @singleton
8 */
9YAHOO.ext.EventManager = new function(){
10 var docReadyEvent;
11 var docReadyProcId;
12 var docReadyState = false;
13 this.ieDeferSrc = false;
14 var resizeEvent;
15 var resizeTask;
16
17 var fireDocReady = function(){
18 if(!docReadyState){
19 docReadyState = true;
20 if(docReadyProcId){
21 clearInterval(docReadyProcId);
22 }
23 if(docReadyEvent){
24 docReadyEvent.fire();
25 }
26 }
27 };
28
29 var initDocReady = function(){
30 docReadyEvent = new YAHOO.util.CustomEvent('documentready');
31 if(document.addEventListener) {
32 YAHOO.util.Event.on(document, "DOMContentLoaded", fireDocReady);
33 }else if(YAHOO.ext.util.Browser.isIE){
34 // inspired by http://www.thefutureoftheweb.com/blog/2006/6/adddomloadevent
35 document.write('<s'+'cript id="ie-deferred-loader" defer="defer" src="' +
36 (YAHOO.ext.EventManager.ieDeferSrc || YAHOO.ext.SSL_SECURE_URL) + '"></s'+'cript>');
37 YAHOO.util.Event.on('ie-deferred-loader', 'readystatechange', function(){
38 if(this.readyState == 'complete'){
39 fireDocReady();
40 }
41 });
42 }else if(YAHOO.ext.util.Browser.isSafari){
43 docReadyProcId = setInterval(function(){
44 var rs = document.readyState;
45 if(rs == 'loaded' || rs == 'complete') {
46 fireDocReady();
47 }
48 }, 10);
49 }
50 // no matter what, make sure it fires on load
51 YAHOO.util.Event.on(window, 'load', fireDocReady);
52 };
53 /**
54 * Places a simple wrapper around an event handler to override the browser event
55 * object with a YAHOO.ext.EventObject
56 * @param {Function} fn The method the event invokes
57 * @param {Object} scope An object that becomes the scope of the handler
58 * @param {boolean} override If true, the obj passed in becomes
59 * the execution scope of the listener
60 * @return {Function} The wrapped function
61 */
62 this.wrap = function(fn, scope, override){
63 var wrappedFn = function(e){
64 YAHOO.ext.EventObject.setEvent(e);
65 fn.call(override ? scope || window : window, YAHOO.ext.EventObject, scope);
66 };
67 return wrappedFn;
68 };
69
70 /**
71 * Appends an event handler
72 *
73 * @param {Object} element The html element to assign the
74 * event to
75 * @param {String} eventName The type of event to append
76 * @param {Function} fn The method the event invokes
77 * @param {Object} scope An object that becomes the scope of the handler
78 * @param {boolean} override If true, the obj passed in becomes
79 * the execution scope of the listener
80 * @return {Function} The wrapper function created (to be used to remove the listener if necessary)
81 */
82 this.addListener = function(element, eventName, fn, scope, override){
83 var wrappedFn = this.wrap(fn, scope, override);
84 YAHOO.util.Event.addListener(element, eventName, wrappedFn);
85 return wrappedFn;
86 };
87
88 /**
89 * Removes an event handler
90 *
91 * @param {Object} element The html element to remove the
92 * event from
93 * @param {String} eventName The type of event to append
94 * @param {Function} wrappedFn The wrapper method returned when adding the listener
95 * @return {Boolean} True if a listener was actually removed
96 */
97 this.removeListener = function(element, eventName, wrappedFn){
98 return YAHOO.util.Event.removeListener(element, eventName, wrappedFn);
99 };
100
101 /**
102 * Appends an event handler (shorthand for addListener)
103 *
104 * @param {Object} element The html element to assign the
105 * event to
106 * @param {String} eventName The type of event to append
107 * @param {Function} fn The method the event invokes
108 * @param {Object} scope An arbitrary object that will be
109 * passed as a parameter to the handler
110 * @param {boolean} override If true, the obj passed in becomes
111 * the execution scope of the listener
112 * @return {Function} The wrapper function created (to be used to remove the listener if necessary)
113 * @method
114 */
115 this.on = this.addListener;
116
117 /**
118 * Fires when the document is ready (before onload and before images are loaded). Can be
119 * accessed shorthanded Ext.onReady().
120 * @param {Function} fn The method the event invokes
121 * @param {Object} scope An object that becomes the scope of the handler
122 * @param {boolean} override If true, the obj passed in becomes
123 * the execution scope of the listener
124 */
125 this.onDocumentReady = function(fn, scope, override){
126 if(docReadyState){ // if it already fired
127 fn.call(override? scope || window : window, scope);
128 return;
129 }
130 if(!docReadyEvent){
131 initDocReady();
132 }
133 docReadyEvent.subscribe(fn, scope, override);
134 }
135
136 /**
137 * Fires when the window is resized and provides resize event buffering (50 milliseconds), passes new viewport width and height to handlers.
138 * @param {Function} fn The method the event invokes
139 * @param {Object} scope An object that becomes the scope of the handler
140 * @param {boolean} override If true, the obj passed in becomes
141 * the execution scope of the listener
142 */
143 this.onWindowResize = function(fn, scope, override){
144 if(!resizeEvent){
145 resizeEvent = new YAHOO.util.CustomEvent('windowresize');
146 resizeTask = new YAHOO.ext.util.DelayedTask(function(){
147 resizeEvent.fireDirect(YAHOO.util.Dom.getViewportWidth(), YAHOO.util.Dom.getViewportHeight());
148 });
149 YAHOO.util.Event.on(window, 'resize', function(){
150 resizeTask.delay(50);
151 });
152 }
153 resizeEvent.subscribe(fn, scope, override);
154 };
155
156 /**
157 * Removes the passed window resize listener.
158 * @param {Function} fn The method the event invokes
159 * @param {Object} scope The scope of handler
160 */
161 this.removeResizeListener = function(fn, scope){
162 if(resizeEvent){
163 resizeEvent.unsubscribe(fn, scope);
164 }
165 };
166
167 this.fireResize = function(){
168 if(resizeEvent){
169 resizeEvent.fireDirect(YAHOO.util.Dom.getViewportWidth(), YAHOO.util.Dom.getViewportHeight());
170 }
171 };
172};
173
174YAHOO.ext.onReady = YAHOO.ext.EventManager.onDocumentReady;
175
176/**
177 * @class YAHOO.ext.EventObject
178 * EventObject exposes the Yahoo! UI Event functionality directly on the object
179 * passed to your event handler. It exists mostly for convenience. It also fixes the annoying null checks automatically to cleanup your code
180 * (All the YAHOO.util.Event methods throw javascript errors if the passed event is null).
181 * To get an EventObject instead of the standard browser event,
182 * your must register your listener thru the {@link YAHOO.ext.EventManager} or directly on an Element
183 * with {@link YAHOO.ext.Element#addManagedListener} or the shorthanded equivalent {@link YAHOO.ext.Element#mon}.<br>
184 * Example:
185 * <pre><code>
186 fu<>nction handleClick(e){ // e is not a standard event object, it is a YAHOO.ext.EventObject
187 e.preventDefault();
188 var target = e.getTarget();
189 ...
190 }
191 var myDiv = getEl('myDiv');
192 myDiv.mon('click', handleClick);
193 //or
194 YAHOO.ext.EventManager.on('myDiv', 'click', handleClick);
195 YAHOO.ext.EventManager.addListener('myDiv', 'click', handleClick);
196 </code></pre>
197 * @singleton
198 */
199YAHOO.ext.EventObject = new function(){
200 /** The normal browser event */
201 this.browserEvent = null;
202 /** The button pressed in a mouse event */
203 this.button = -1;
204 /** True if the shift key was down during the event */
205 this.shiftKey = false;
206 /** True if the control key was down during the event */
207 this.ctrlKey = false;
208 /** True if the alt key was down during the event */
209 this.altKey = false;
210
211 /** Key constant @type Number */
212 this.BACKSPACE = 8;
213 /** Key constant @type Number */
214 this.TAB = 9;
215 /** Key constant @type Number */
216 this.RETURN = 13;
217 /** Key constant @type Number */
218 this.ESC = 27;
219 /** Key constant @type Number */
220 this.SPACE = 32;
221 /** Key constant @type Number */
222 this.PAGEUP = 33;
223 /** Key constant @type Number */
224 this.PAGEDOWN = 34;
225 /** Key constant @type Number */
226 this.END = 35;
227 /** Key constant @type Number */
228 this.HOME = 36;
229 /** Key constant @type Number */
230 this.LEFT = 37;
231 /** Key constant @type Number */
232 this.UP = 38;
233 /** Key constant @type Number */
234 this.RIGHT = 39;
235 /** Key constant @type Number */
236 this.DOWN = 40;
237 /** Key constant @type Number */
238 this.DELETE = 46;
239 /** Key constant @type Number */
240 this.F5 = 116;
241
242 /** @private */
243 this.setEvent = function(e){
244 if(e == this){ // already wrapped
245 return this;
246 }
247 this.browserEvent = e;
248 if(e){
249 this.button = e.button;
250 this.shiftKey = e.shiftKey;
251 this.ctrlKey = e.ctrlKey;
252 this.altKey = e.altKey;
253 }else{
254 this.button = -1;
255 this.shiftKey = false;
256 this.ctrlKey = false;
257 this.altKey = false;
258 }
259 return this;
260 };
261
262 /**
263 * Stop the event. Calls YAHOO.util.Event.stopEvent() if the event is not null.
264 */
265 this.stopEvent = function(){
266 if(this.browserEvent){
267 YAHOO.util.Event.stopEvent(this.browserEvent);
268 }
269 };
270
271 /**
272 * Prevents the browsers default handling of the event. Calls YAHOO.util.Event.preventDefault() if the event is not null.
273 */
274 this.preventDefault = function(){
275 if(this.browserEvent){
276 YAHOO.util.Event.preventDefault(this.browserEvent);
277 }
278 };
279
280 /** @private */
281 this.isNavKeyPress = function(){
282 return (this.browserEvent.keyCode && this.browserEvent.keyCode >= 33 && this.browserEvent.keyCode <= 40);
283 };
284
285 /**
286 * Cancels bubbling of the event. Calls YAHOO.util.Event.stopPropagation() if the event is not null.
287 */
288 this.stopPropagation = function(){
289 if(this.browserEvent){
290 YAHOO.util.Event.stopPropagation(this.browserEvent);
291 }
292 };
293
294 /**
295 * Gets the key code for the event. Returns value from YAHOO.util.Event.getCharCode() if the event is not null.
296 * @return {Number}
297 */
298 this.getCharCode = function(){
299 if(this.browserEvent){
300 return YAHOO.util.Event.getCharCode(this.browserEvent);
301 }
302 return null;
303 };
304
305 /**
306 * Returns a browsers key for a keydown event
307 * @return {Number} The key code
308 */
309 this.getKey = function(){
310 if(this.browserEvent){
311 return this.browserEvent.keyCode || this.browserEvent.charCode;
312 }
313 return null;
314 };
315
316 /**
317 * Gets the x coordinate of the event. Returns value from YAHOO.util.Event.getPageX() if the event is not null.
318 * @return {Number}
319 */
320 this.getPageX = function(){
321 if(this.browserEvent){
322 return YAHOO.util.Event.getPageX(this.browserEvent);
323 }
324 return null;
325 };
326
327 /**
328 * Gets the y coordinate of the event. Returns value from YAHOO.util.Event.getPageY() if the event is not null.
329 * @return {Number}
330 */
331 this.getPageY = function(){
332 if(this.browserEvent){
333 return YAHOO.util.Event.getPageY(this.browserEvent);
334 }
335 return null;
336 };
337
338 /**
339 * Gets the time of the event. Returns value from YAHOO.util.Event.getTime() if the event is not null.
340 * @return {Number}
341 */
342 this.getTime = function(){
343 if(this.browserEvent){
344 return YAHOO.util.Event.getTime(this.browserEvent);
345 }
346 return null;
347 };
348
349 /**
350 * Gets the page coordinates of the event. Returns value from YAHOO.util.Event.getXY() if the event is not null.
351 * @return {Array} The xy values like [x, y]
352 */
353 this.getXY = function(){
354 if(this.browserEvent){
355 return YAHOO.util.Event.getXY(this.browserEvent);
356 }
357 return [];
358 };
359
360 /**
361 * Gets the target for the event. Returns value from YAHOO.util.Event.getTarget() if the event is not null.
362 * @return {HTMLelement}
363 */
364 this.getTarget = function(){
365 if(this.browserEvent){
366 return YAHOO.util.Event.getTarget(this.browserEvent);
367 }
368 return null;
369 };
370
371 /**
372 * Walk up the DOM looking for a particular target - if the default target matches, it is returned.
373 * @param {String} className The class name to look for or null
374 * @param {String} tagName (optional) The tag name to look for
375 * @return {HTMLelement}
376 */
377 this.findTarget = function(className, tagName){
378 if(tagName) tagName = tagName.toLowerCase();
379 if(this.browserEvent){
380 function isMatch(el){
381 if(!el){
382 return false;
383 }
384 if(className && !YAHOO.util.Dom.hasClass(el, className)){
385 return false;
386 }
387 if(tagName && el.tagName.toLowerCase() != tagName){
388 return false;
389 }
390 return true;
391 };
392
393 var t = this.getTarget();
394 if(!t || isMatch(t)){
395 return t;
396 }
397 var p = t.parentNode;
398 var b = document.body;
399 while(p && p != b){
400 if(isMatch(p)){
401 return p;
402 }
403 p = p.parentNode;
404 }
405 }
406 return null;
407 };
408 /**
409 * Gets the related target. Returns value from YAHOO.util.Event.getRelatedTarget() if the event is not null.
410 * @return {HTMLElement}
411 */
412 this.getRelatedTarget = function(){
413 if(this.browserEvent){
414 return YAHOO.util.Event.getRelatedTarget(this.browserEvent);
415 }
416 return null;
417 };
418
419 /**
420 * Normalizes mouse wheel delta across browsers
421 * @return {Number} The delta
422 */
423 this.getWheelDelta = function(){
424 var e = this.browserEvent;
425 var delta = 0;
426 if(e.wheelDelta){ /* IE/Opera. */
427 delta = e.wheelDelta/120;
428 /* In Opera 9, delta differs in sign as compared to IE. */
429 if(window.opera) delta = -delta;
430 }else if(e.detail){ /* Mozilla case. */
431 delta = -e.detail/3;
432 }
433 return delta;
434 };
435
436 /**
437 * Returns true if the control, shift or alt key was pressed during this event.
438 * @return {Boolean}
439 */
440 this.hasModifier = function(){
441 return this.ctrlKey || this.altKey || this.shiftKey;
442 };
443
444 /**
445 * Returns true if the target of this event equals el or is a child of el
446 * @param {String/HTMLElement/Element} el
447 * @return {Boolean}
448 */
449 this.within = function(el){
450 el = getEl(el);
451 var t = this.getTarget();
452 return t && el && (el.dom == t || YAHOO.util.Dom.isAncestor(el.dom, t));
453 }
454}();
455
456
diff --git a/frontend/beta/js/YUI-extensions/JSON.js b/frontend/beta/js/YUI-extensions/JSON.js
new file mode 100644
index 0000000..ffc9573
--- a/dev/null
+++ b/frontend/beta/js/YUI-extensions/JSON.js
@@ -0,0 +1,132 @@
1/**
2 * @class YAHOO.ext.util.JSON
3 * Modified version of Douglas Crockford's json.js that doesn't
4 * mess with the Object prototype
5 * http://www.json.org/js.html
6 * @singleton
7 */
8YAHOO.ext.util.JSON = new function(){
9 var useHasOwn = {}.hasOwnProperty ? true : false;
10
11 // crashes Safari in some instances
12 //var validRE = /^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/;
13
14 var pad = function(n) {
15 return n < 10 ? '0' + n : n;
16 };
17
18 var m = {
19 '\b': '\\b',
20 '\t': '\\t',
21 '\n': '\\n',
22 '\f': '\\f',
23 '\r': '\\r',
24 '"' : '\\"',
25 '\\': '\\\\'
26 };
27
28 var encodeString = function(s){
29 if (/["\\\x00-\x1f]/.test(s)) {
30 return '"' + s.replace(/([\x00-\x1f\\"])/g, function(a, b) {
31 var c = m[b];
32 if(c){
33 return c;
34 }
35 c = b.charCodeAt();
36 return '\\u00' +
37 Math.floor(c / 16).toString(16) +
38 (c % 16).toString(16);
39 }) + '"';
40 }
41 return '"' + s + '"';
42 };
43
44 var encodeArray = function(o){
45 var a = ['['], b, i, l = o.length, v;
46 for (i = 0; i < l; i += 1) {
47 v = o[i];
48 switch (typeof v) {
49 case 'undefined':
50 case 'function':
51 case 'unknown':
52 break;
53 default:
54 if (b) {
55 a.push(',');
56 }
57 a.push(v === null ? "null" : YAHOO.ext.util.JSON.encode(v));
58 b = true;
59 }
60 }
61 a.push(']');
62 return a.join('');
63 };
64
65 var encodeDate = function(o){
66 return '"' + o.getFullYear() + '-' +
67 pad(o.getMonth() + 1) + '-' +
68 pad(o.getDate()) + 'T' +
69 pad(o.getHours()) + ':' +
70 pad(o.getMinutes()) + ':' +
71 pad(o.getSeconds()) + '"';
72 };
73
74 /**
75 * Encodes an Object, Array or other value
76 * @param {Mixed} o The variable to encode
77 * @return {String} The JSON string
78 */
79 this.encode = function(o){
80 if(typeof o == 'undefined' || o === null){
81 return 'null';
82 }else if(o instanceof Array){
83 return encodeArray(o);
84 }else if(o instanceof Date){
85 return encodeDate(o);
86 }else if(typeof o == 'string'){
87 return encodeString(o);
88 }else if(typeof o == 'number'){
89 return isFinite(o) ? String(o) : "null";
90 }else if(typeof o == 'boolean'){
91 return String(o);
92 }else {
93 var a = ['{'], b, i, v;
94 for (var i in o) {
95 if(!useHasOwn || o.hasOwnProperty(i)) {
96 v = o[i];
97 switch (typeof v) {
98 case 'undefined':
99 case 'function':
100 case 'unknown':
101 break;
102 default:
103 if(b){
104 a.push(',');
105 }
106 a.push(this.encode(i), ':',
107 v === null ? "null" : this.encode(v));
108 b = true;
109 }
110 }
111 }
112 a.push('}');
113 return a.join('');
114 }
115 };
116
117 /**
118 * Decodes (parses) a JSON string to an object. If the JSON is invalid, this function throws a SyntaxError.
119 * @param {String} json The JSON string
120 * @return {Object} The resulting object
121 */
122 this.decode = function(json){
123 // although crockford had a good idea, this line crashes safari in some instances
124 //try{
125 //if(validRE.test(json)) {
126 return eval('(' + json + ')');
127 // }
128 // }catch(e){
129 // }
130 // throw new SyntaxError("parseJSON");
131 };
132}();
diff --git a/frontend/beta/js/YUI-extensions/KeyMap.js b/frontend/beta/js/YUI-extensions/KeyMap.js
new file mode 100644
index 0000000..c5af567
--- a/dev/null
+++ b/frontend/beta/js/YUI-extensions/KeyMap.js
@@ -0,0 +1,135 @@
1/**
2 * @class YAHOO.ext.KeyMap
3 * Handles mapping keys to actions for an element. One key map can be used for multiple actions.
4 * A KeyMap can also handle a string representation of keys.<br />
5 * Usage:
6 <pre><code>
7 // map one key by key code
8 var map = new YAHOO.ext.KeyMap('my-element', {
9 key: 13,
10 fn: myHandler,
11 scope: myObject
12 });
13
14 // map multiple keys to one action by string
15 var map = new YAHOO.ext.KeyMap('my-element', {
16 key: "a\r\n\t",
17 fn: myHandler,
18 scope: myObject
19 });
20
21 // map multiple keys to multiple actions by strings and array of codes
22 var map = new YAHOO.ext.KeyMap('my-element', [
23 {
24 key: [10,13],
25 fn: function(){ alert('Return was pressed'); }
26 }, {
27 key: "abc",
28 fn: function(){ alert('a, b or c was pressed'); }
29 }, {
30 key: "\t",
31 ctrl:true,
32 shift:true,
33 fn: function(){ alert('Control + shift + tab was pressed.'); }
34 }
35]);
36 </code></pre>
37* <b>Note: A KepMap starts enabled</b>
38* @constructor
39* @param {String/HTMLElement/YAHOO.ext.Element} el The element to bind to
40* @param {Object} config The config
41* @param {String} eventName (optional) The event to bind to (Defaults to "keydown").
42 */
43YAHOO.ext.KeyMap = function(el, config, eventName){
44 this.el = getEl(el);
45 this.eventName = eventName || 'keydown';
46 this.bindings = [];
47 if(config instanceof Array){
48 for(var i = 0, len = config.length; i < len; i++){
49 this.addBinding(config[i]);
50 }
51 }else{
52 this.addBinding(config);
53 }
54 this.keyDownDelegate = YAHOO.ext.EventManager.wrap(this.handleKeyDown, this, true);
55 this.enable();
56}
57
58YAHOO.ext.KeyMap.prototype = {
59 /**
60 * Add a new binding to this KeyMap
61 * @param {Object} config A single KeyMap config
62 */
63 addBinding : function(config){
64 var keyCode = config.key,
65 shift = config.shift,
66 ctrl = config.ctrl,
67 alt = config.alt,
68 fn = config.fn,
69 scope = config.scope;
70 if(typeof keyCode == 'string'){
71 var ks = [];
72 var keyString = keyCode.toUpperCase();
73 for(var j = 0, len = keyString.length; j < len; j++){
74 ks.push(keyString.charCodeAt(j));
75 }
76 keyCode = ks;
77 }
78 var keyArray = keyCode instanceof Array;
79 var handler = function(e){
80 if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) && (!alt || e.altKey)){
81 var k = e.getKey();
82 if(keyArray){
83 for(var i = 0, len = keyCode.length; i < len; i++){
84 if(keyCode[i] == k){
85 fn.call(scope || window, k, e);
86 return;
87 }
88 }
89 }else{
90 if(k == keyCode){
91 fn.call(scope || window, k, e);
92 }
93 }
94 }
95 };
96 this.bindings.push(handler);
97 },
98
99 handleKeyDown : function(e){
100 if(this.enabled){ //just in case
101 var b = this.bindings;
102 for(var i = 0, len = b.length; i < len; i++){
103 b[i](e);
104 }
105 }
106 },
107
108 /**
109 * Returns true if this KepMap is enabled
110 * @return {Boolean}
111 */
112 isEnabled : function(){
113 return this.enabled;
114 },
115
116 /**
117 * Enable this KeyMap
118 */
119 enable: function(){
120 if(!this.enabled){
121 this.el.on(this.eventName, this.keyDownDelegate);
122 this.enabled = true;
123 }
124 },
125
126 /**
127 * Disable this KeyMap
128 */
129 disable: function(){
130 if(this.enabled){
131 this.el.removeListener(this.eventName, this.keyDownDelegate);
132 this.enabled = false;
133 }
134 }
135};
diff --git a/frontend/beta/js/YUI-extensions/Layer.js b/frontend/beta/js/YUI-extensions/Layer.js
new file mode 100644
index 0000000..9eeaf7c
--- a/dev/null
+++ b/frontend/beta/js/YUI-extensions/Layer.js
@@ -0,0 +1,246 @@
1/**
2 * @class YAHOO.ext.Layer
3 * @extends YAHOO.ext.Element
4 * An extended Element object that supports a shadow and shim, constrain to viewport and
5 * automatic maintaining of shadow/shim positions.
6 * @cfg {Boolean} shim False to disable the iframe shim in browsers which need one (defaults to true)
7 * @cfg {String/Boolean} shadow True to create a shadow element with default class "ylayer-shadow" or
8 * you can pass a string with a css class name. False turns off the shadow.
9 * @cfg {Object} dh DomHelper object config to create element with (defaults to {tag: 'div', cls: 'ylayer'}).
10 * @cfg {Boolean} constrain False to disable constrain to viewport (defaults to true)
11 * @cfg {String} cls CSS class to add to the element
12 * @cfg {Number} zindex Starting z-index (defaults to 11000!)
13 * @cfg {Number} shadowOffset Offset for the shadow (defaults to 3)
14 * @constructor
15 * @param {Object} config
16 * @param {String/HTMLElement} existingEl (optional) Uses an existing dom element. If the element is not found it creates it.
17 */
18YAHOO.ext.Layer = function(config, existingEl){
19 config = config || {};
20 var dh = YAHOO.ext.DomHelper;
21 if(existingEl){
22 this.dom = YAHOO.util.Dom.get(existingEl);
23 }
24 if(!this.dom){
25 var o = config.dh || {tag: 'div', cls: 'ylayer'};
26 this.dom = dh.insertBefore(document.body.firstChild, o);
27 }
28 if(config.cls){
29 this.addClass(config.cls);
30 }
31 this.constrain = config.constrain !== false;
32 this.visibilityMode = YAHOO.ext.Element.VISIBILITY;
33 this.id = YAHOO.util.Dom.generateId(this.dom);
34 var zindex = (config.zindex || parseInt(this.getStyle('z-index'), 10)) || 11000;
35 this.setAbsolutePositioned(zindex);
36 if(config.shadow){
37 var cls = (typeof config.shadow == 'string' ? config.shadow : 'ylayer-shadow');
38 this.shadow = dh.insertBefore(this.dom,
39 {tag: 'div', cls: cls}, true);
40 this.shadowOffset = config.shadowOffset || 3;
41 this.shadow.setAbsolutePositioned(zindex-1);
42 }else{
43 this.shadowOffset = 0;
44 }
45 var b = YAHOO.ext.util.Browser;
46 if(config.shim !== false && (b.isIE || (b.isGecko && b.isMac))){
47 this.shim = this.createShim();
48 this.shim.setOpacity(0);
49 this.shim.setAbsolutePositioned(zindex-2);
50 }
51 this.hide();
52};
53YAHOO.extendX(YAHOO.ext.Layer, YAHOO.ext.Element, {
54 sync : function(doShow){
55 if(this.isVisible() && (this.shadow || this.shim)){
56 var b = this.getBox();
57 if(this.shim){
58 if(doShow){
59 this.shim.show();
60 }
61 this.shim.setBox(b);
62 }
63 if(this.shadow){
64 if(doShow){
65 this.shadow.show();
66 }
67 b.x += this.shadowOffset;
68 b.y += this.shadowOffset;
69 this.shadow.setBox(b);
70 }
71 }
72 },
73
74 syncLocalXY : function(){
75 var l = this.getLeft(true);
76 var t = this.getTop(true);
77 if(this.shim){
78 this.shim.setLeftTop(l, t);
79 }
80 if(this.shadow){
81 this.shadow.setLeftTop(l + this.shadowOffset,
82 t + this.shadowOffset);
83 }
84 },
85
86 hideUnders : function(negOffset){
87 if(this.shadow){
88 this.shadow.hide();
89 if(negOffset){
90 this.shadow.setLeftTop(-10000,-10000);
91 }
92 }
93 if(this.shim){
94 this.shim.hide();
95 if(negOffset){
96 this.shim.setLeftTop(-10000,-10000);
97 }
98 }
99 },
100
101 constrainXY : function(){
102 if(this.constrain){
103 var vw = YAHOO.util.Dom.getViewportWidth(),
104 vh = YAHOO.util.Dom.getViewportHeight();
105 var xy = this.getXY();
106 var x = xy[0], y = xy[1];
107 var w = this.dom.offsetWidth+this.shadowOffset, h = this.dom.offsetHeight+this.shadowOffset;
108 // only move it if it needs it
109 var moved = false;
110 // first validate right/bottom
111 if(x + w > vw){
112 x = vw - w;
113 moved = true;
114 }
115 if(y + h > vh){
116 y = vh - h;
117 moved = true;
118 }
119 // then make sure top/left isn't negative
120 if(x < 0){
121 x = 0;
122 moved = true;
123 }
124 if(y < 0){
125 y = 0;
126 moved = true;
127 }
128 if(moved){
129 xy = [x, y];
130 this.lastXY = xy;
131 this.beforeAction();
132 YAHOO.ext.Layer.superclass.setXY.call(this, xy);
133 this.sync(true);
134 }
135 }
136 },
137
138 setVisible : function(v, a, d, c, e){
139 if(this.lastXY){
140 YAHOO.ext.Layer.superclass.setXY.call(this, this.lastXY);
141 }
142 if(a && v){
143 var cb = function(){
144 this.sync(true);
145 if(c){
146 c();
147 }
148 }.createDelegate(this);
149 YAHOO.ext.Layer.superclass.setVisible.call(this, true, true, d, cb, e);
150 }else{
151 if(!v){
152 this.hideUnders(true);
153 }
154 var cb = c;
155 if(a){
156 cb = function(){
157 this.setLeftTop(-10000,-10000);
158 if(c){
159 c();
160 }
161 }.createDelegate(this);
162 }
163 YAHOO.ext.Layer.superclass.setVisible.call(this, v, a, d, cb, e);
164 if(v){
165 this.sync(true);
166 }else if(!a){
167 this.setLeftTop(-10000,-10000);
168 }
169 }
170 },
171
172 beforeAction : function(){
173 if(this.shadow){
174 this.shadow.hide();
175 }
176 },
177
178 setXY : function(xy, a, d, c, e){
179 this.lastXY = xy;
180 this.beforeAction();
181 var cb = this.createCB(c);
182 YAHOO.ext.Layer.superclass.setXY.call(this, xy, a, d, cb, e);
183 if(!a){
184 cb();
185 }
186 },
187
188 createCB : function(c){
189 var el = this;
190 return function(){
191 el.constrainXY();
192 el.sync(true);
193 if(c){
194 c();
195 }
196 };
197 },
198
199 setX : function(x, a, d, c, e){
200 this.setXY([x, this.getY()], a, d, c, e);
201 },
202
203 setY : function(y, a, d, c, e){
204 this.setXY([this.getX(), y], a, d, c, e);
205 },
206
207 setSize : function(w, h, a, d, c, e){
208 this.beforeAction();
209 var cb = this.createCB(c);
210 YAHOO.ext.Layer.superclass.setSize.call(this, w, h, a, d, cb, e);
211 if(!a){
212 cb();
213 }
214 },
215
216 setWidth : function(w, a, d, c, e){
217 this.beforeAction();
218 var cb = this.createCB(c);
219 YAHOO.ext.Layer.superclass.setWidth.call(this, w, a, d, cb, e);
220 if(!a){
221 cb();
222 }
223 },
224
225 setHeight : function(h, a, d, c, e){
226 this.beforeAction();
227 var cb = this.createCB(c);
228 YAHOO.ext.Layer.superclass.setHeight.call(this, h, a, d, cb, e);
229 if(!a){
230 cb();
231 }
232 },
233
234 setBounds : function(x, y, w, h, a, d, c, e){
235 this.beforeAction();
236 var cb = this.createCB(c);
237 if(!a){
238 YAHOO.ext.Layer.superclass.setXY.call(this, [x, y]);
239 YAHOO.ext.Layer.superclass.setSize.call(this, w, h, a, d, cb, e);
240 cb();
241 }else{
242 YAHOO.ext.Layer.superclass.setBounds.call(this, x, y, w, h, a, d, cb, e);
243 }
244 return this;
245 }
246});
diff --git a/frontend/beta/js/YUI-extensions/MixedCollection.js b/frontend/beta/js/YUI-extensions/MixedCollection.js
new file mode 100644
index 0000000..2e3d88a
--- a/dev/null
+++ b/frontend/beta/js/YUI-extensions/MixedCollection.js
@@ -0,0 +1,344 @@
1/**
2 * @class YAHOO.ext.util.MixedCollection
3 * A Collection class that maintains both numeric indexes and keys and exposes events.<br>
4 * @constructor
5 * @param {Boolean} allowFunctions True if the addAll function should add function references
6 * to the collection.
7 */
8YAHOO.ext.util.MixedCollection = function(allowFunctions){
9 this.items = [];
10 this.keys = [];
11 this.events = {
12 /**
13 * @event clear
14 * Fires when the collection is cleared.
15 */
16 'clear' : new YAHOO.util.CustomEvent('clear'),
17 /**
18 * @event add
19 * Fires when an item is added to the collection.
20 * @param {Number} index The index at which the item was added.
21 * @param {Object} o The item added.
22 * @param {String} key The key associated with the added item.
23 */
24 'add' : new YAHOO.util.CustomEvent('add'),
25 /**
26 * @event replace
27 * Fires when an item is replaced in the collection.
28 * @param {String} key he key associated with the new added.
29 * @param {Object} old The item being replaced.
30 * @param {Object} new The new item.
31 */
32 'replace' : new YAHOO.util.CustomEvent('replace'),
33 /**
34 * @event remove
35 * Fires when an item is removed from the collection.
36 * @param {Object} o The item being removed.
37 * @param {String} key (optional) The key associated with the removed item.
38 */
39 'remove' : new YAHOO.util.CustomEvent('remove')
40 }
41 this.allowFunctions = allowFunctions === true;
42};
43
44YAHOO.extendX(YAHOO.ext.util.MixedCollection, YAHOO.ext.util.Observable, {
45 allowFunctions : false,
46
47/**
48 * Adds an item to the collection.
49 * @param {String} key The key to associate with the item
50 * @param {Object} o The item to add.
51 * @return {Object} The item added.
52 */
53 add : function(key, o){
54 if(arguments.length == 1){
55 o = arguments[0];
56 key = this.getKey(o);
57 }
58 this.items.push(o);
59 if(typeof key != 'undefined' && key != null){
60 this.items[key] = o;
61 this.keys.push(key);
62 }
63 this.fireEvent('add', this.items.length-1, o, key);
64 return o;
65 },
66
67/**
68 * MixedCollection has a generic way to fetch keys if you implement getKey.
69 <pre><code>
70 // normal way
71 var mc = new YAHOO.ext.util.MixedCollection();
72 mc.add(someEl.dom.id, someEl);
73 mc.add(otherEl.dom.id, otherEl);
74 //and so on
75
76 // using getKey
77 var mc = new YAHOO.ext.util.MixedCollection();
78 mc.getKey = function(el){
79 return el.dom.id;
80 }
81 mc.add(someEl);
82 mc.add(otherEl);
83 // etc
84 </code>
85 * @param o {Object} The item for which to find the key.
86 * @return {Object} The key for the passed item.
87 */
88 getKey : function(o){
89 return null;
90 },
91
92/**
93 * Replaces an item in the collection.
94 * @param {String} key The key associated with the item to replace, or the item to replace.
95 * @param o {Object} o (optional) If the first parameter passed was a key, the item to associate with that key.
96 * @return {Object} The new item.
97 */
98 replace : function(key, o){
99 if(arguments.length == 1){
100 o = arguments[0];
101 key = this.getKey(o);
102 }
103 if(typeof this.items[key] == 'undefined'){
104 return this.add(key, o);
105 }
106 var old = this.items[key];
107 if(typeof key == 'number'){ // array index key
108 this.items[key] = o;
109 }else{
110 var index = this.indexOfKey(key);
111 this.items[index] = o;
112 this.items[key] = o;
113 }
114 this.fireEvent('replace', key, old, o);
115 return o;
116 },
117
118/**
119 * Adds all elements of an Array or an Object to the collection.
120 * @param {Object/Array} objs An Object containing properties which will be added to the collection, or
121 * an Array of values, each of which are added to the collection.
122 */
123 addAll : function(objs){
124 if(arguments.length > 1 || objs instanceof Array){
125 var args = arguments.length > 1 ? arguments : objs;
126 for(var i = 0, len = args.length; i < len; i++){
127 this.add(args[i]);
128 }
129 }else{
130 for(var key in objs){
131 if(this.allowFunctions || typeof objs[key] != 'function'){
132 this.add(objs[key], key);
133 }
134 }
135 }
136 },
137
138/**
139 * Executes the specified function once for every item in the collection, passing each
140 * item as the first and only parameter.
141 * @param {Function} fn The function to execute for each item.
142 * @param {Object} scope (optional) The scope in which to execute the function.
143 */
144 each : function(fn, scope){
145 for(var i = 0, len = this.items.length; i < len; i++){
146 fn.call(scope || window, this.items[i]);
147 }
148 },
149
150/**
151 * Executes the specified function once for every key in the collection, passing each
152 * key, and its associated item as the first two parameters.
153 * @param {Function} fn The function to execute for each item.
154 * @param {Object} scope (optional) The scope in which to execute the function.
155 */
156 eachKey : function(fn, scope){
157 for(var i = 0, len = this.keys.length; i < len; i++){
158 fn.call(scope || window, this.keys[i], this.items[i]);
159 }
160 },
161
162/**
163 * Returns the first item in the collection which elicits a true return value from the
164 * passed selection function.
165 * @param {Function} fn The selection function to execute for each item.
166 * @param {Object} scope (optional) The scope in which to execute the function.
167 * @return {Object} The first item in the collection which returned true from the selection function.
168 */
169 find : function(fn, scope){
170 for(var i = 0, len = this.items.length; i < len; i++){
171 if(fn.call(scope || window, this.items[i])){
172 return this.items[i];
173 }
174 }
175 return null;
176 },
177
178/**
179 * Inserts an item at the specified index in the collection.
180 * @param {Number} index The index to insert the item at.
181 * @param {String} key The key to associate with the new item, or the item itself.
182 * @param {Object} o (optional) If the second parameter was a key, the new item.
183 * @return {Object} The item inserted.
184 */
185 insert : function(index, key, o){
186 if(arguments.length == 2){
187 o = arguments[1];
188 key = this.getKey(o);
189 }
190 if(index >= this.items.length){
191 return this.add(o, key);
192 }
193 this.items.splice(index, 0, o);
194 if(typeof key != 'undefined' && key != null){
195 this.items[key] = o;
196 this.keys.splice(index, 0, key);
197 }
198 this.fireEvent('add', index, o, key);
199 return o;
200 },
201
202/**
203 * Removed an item from the collection.
204 * @param {Object} o The item to remove.
205 * @return {Object} The item removed.
206 */
207 remove : function(o){
208 var index = this.indexOf(o);
209 this.items.splice(index, 1);
210 if(typeof this.keys[index] != 'undefined'){
211 var key = this.keys[index];
212 this.keys.splice(index, 1);
213 delete this.items[key];
214 }
215 this.fireEvent('remove', o);
216 return o;
217 },
218
219/**
220 * Remove an item from a specified index in the collection.
221 * @param {Number} index The index within the collection of the item to remove.
222 */
223 removeAt : function(index){
224 this.items.splice(index, 1);
225 var key = this.keys[index];
226 if(typeof key != 'undefined'){
227 this.keys.splice(index, 1);
228 delete this.items[key];
229 }
230 this.fireEvent('remove', o, key);
231 },
232
233/**
234 * Removed an item associated with the passed key fom the collection.
235 * @param {String} key The key of the item to remove.
236 */
237 removeKey : function(key){
238 var o = this.items[key];
239 var index = this.indexOf(o);
240 this.items.splice(index, 1);
241 this.keys.splice(index, 1);
242 delete this.items[key];
243 this.fireEvent('remove', o, key);
244 },
245
246/**
247 * Returns the number of items in the collection.
248 * @return {Number} the number of items in the collection.
249 */
250 getCount : function(){
251 return this.items.length;
252 },
253
254/**
255 * Returns index within the collection of the passed Object.
256 * @param {Object} o The item to find the index of.
257 * @return {Number} index of the item.
258 */
259 indexOf : function(o){
260 if(!this.items.indexOf){
261 for(var i = 0, len = this.items.length; i < len; i++){
262 if(this.items[i] == o) return i;
263 }
264 return -1;
265 }else{
266 return this.items.indexOf(o);
267 }
268 },
269
270/**
271 * Returns index within the collection of the passed key.
272 * @param {String} key The key to find the index of.
273 * @return {Number} index of the key.
274 */
275 indexOfKey : function(key){
276 if(!this.keys.indexOf){
277 for(var i = 0, len = this.keys.length; i < len; i++){
278 if(this.keys[i] == key) return i;
279 }
280 return -1;
281 }else{
282 return this.keys.indexOf(key);
283 }
284 },
285
286/**
287 * Returns the item associated with the passed key.
288 * @param {String/Number} key The key or index of the item.
289 * @return {Object} The item associated with the passed key.
290 */
291 item : function(key){
292 return this.items[key];
293 },
294
295/**
296 * Returns true if the collection contains the passed Object as an item.
297 * @param {Object} o The Object to look for in the collection.
298 * @return {Boolean} True if the collection contains the Object as an item.
299 */
300 contains : function(o){
301 return this.indexOf(o) != -1;
302 },
303
304/**
305 * Returns true if the collection contains the passed Object as a key.
306 * @param {String} key The key to look for in the collection.
307 * @return {Boolean} True if the collection contains the Object as a key.
308 */
309 containsKey : function(key){
310 return typeof this.items[key] != 'undefined';
311 },
312
313/**
314 * Removes all items from the collection.
315 */
316 clear : function(o){
317 this.items = [];
318 this.keys = [];
319 this.fireEvent('clear');
320 },
321
322/**
323 * Returns the first item in the collection.
324 * @return {Object} the first item in the collection..
325 */
326 first : function(){
327 return this.items[0];
328 },
329
330/**
331 * Returns the last item in the collection.
332 * @return {Object} the last item in the collection..
333 */
334 last : function(){
335 return this.items[this.items.length];
336 }
337});
338/**
339 * Returns the item associated with the passed key or index.
340 * @method
341 * @param {String/Number} key The key or index of the item.
342 * @return {Object} The item associated with the passed key.
343 */
344YAHOO.ext.util.MixedCollection.prototype.get = YAHOO.ext.util.MixedCollection.prototype.item;
diff --git a/frontend/beta/js/YUI-extensions/State.js b/frontend/beta/js/YUI-extensions/State.js
new file mode 100644
index 0000000..76a9618
--- a/dev/null
+++ b/frontend/beta/js/YUI-extensions/State.js
@@ -0,0 +1,264 @@
1YAHOO.namespace('ext.state');
2/**
3 * @class YAHOO.ext.state.Provider
4 * Abstract base class for provider implementations. This class provides methods
5 * for encoding and decoding <b>typed</b> variables including dates and defines the
6 * Provider interface.
7 */
8YAHOO.ext.state.Provider = function(){
9 YAHOO.ext.state.Provider.superclass.constructor.call(this);
10 /**
11 * @event statechange
12 * Fires when a state change occurs.
13 * @param {Provider} this
14 * @param {String} key The state key which was changed
15 * @param {String} value The encoded value for the state
16 */
17 this.events = {
18 'statechange': new YAHOO.util.CustomEvent('statechange')
19 };
20 this.state = {};
21};
22YAHOO.extendX(YAHOO.ext.state.Provider, YAHOO.ext.util.Observable, {
23 /**
24 * Get the current value for a key.
25 * @param {String} name
26 * @param {Mixed} defaultValue
27 * @return {Mixed}
28 */
29 get : function(name, defaultValue){
30 return typeof this.state[name] == 'undefined' ?
31 defaultValue : this.state[name];
32 },
33
34 /**
35 * Clear a value from the state.
36 */
37 clear : function(name){
38 delete this.state[name];
39 this.fireEvent('statechange', this, name, null);
40 },
41
42 /**
43 * Set the value for a key.
44 * @param {String} name
45 * @param {Mixed} value
46 */
47 set : function(name, value){
48 this.state[name] = value;
49 this.fireEvent('statechange', this, name, value);
50 },
51
52 /**
53 * Decodes a string previously encoded with {@link #encodeValue}.
54 * @param {String} value
55 * @return {Mixed} The value
56 */
57 decodeValue : function(cookie){
58 var re = /^(a|n|d|b|s|o)\:(.*)$/;
59 var matches = re.exec(unescape(cookie));
60 if(!matches || !matches[1]) return; // non state cookie
61 var type = matches[1];
62 var v = matches[2];
63 switch(type){
64 case 'n':
65 return parseFloat(v);
66 case 'd':
67 return new Date(Date.parse(v));
68 case 'b':
69 return (v == '1');
70 case 'a':
71 var all = [];
72 var values = v.split('^');
73 for(var i = 0, len = values.length; i < len; i++){
74 all.push(this.decodeValue(values[i]))
75 }
76 return all;
77 case 'o':
78 var all = {};
79 var values = v.split('^');
80 for(var i = 0, len = values.length; i < len; i++){
81 var kv = values[i].split('=');
82 all[kv[0]] = this.decodeValue(kv[1]);
83 }
84 return all;
85 default:
86 return v;
87 }
88 },
89
90 /**
91 * Encode a value including type information.
92 * @param {Mixed} value
93 * @return {String}
94 */
95 encodeValue : function(v){
96 var enc;
97 if(typeof v == 'number'){
98 enc = 'n:' + v;
99 }else if(typeof v == 'boolean'){
100 enc = 'b:' + (v ? '1' : '0');
101 }else if(v instanceof Date){
102 enc = 'd:' + v.toGMTString();
103 }else if(v instanceof Array){
104 var flat = '';
105 for(var i = 0, len = v.length; i < len; i++){
106 flat += this.encodeValue(v[i]);
107 if(i != len-1) flat += '^';
108 }
109 enc = 'a:' + flat;
110 }else if(typeof v == 'object'){
111 var flat = '';
112 for(var key in v){
113 if(typeof v[key] != 'function'){
114 flat += key + '=' + this.encodeValue(v[key]) + '^';
115 }
116 }
117 enc = 'o:' + flat.substring(0, flat.length-1);
118 }else{
119 enc = 's:' + v;
120 }
121 return escape(enc);
122 }
123});
124
125/**
126 * @class YAHOO.ext.state.Manager
127 * This is the global state manager. By default all components that are "state aware" check this class
128 * for state information if you don't pass them a custom state provider. In order for this class
129 * to be useful, it must be initialized with a provider when your application initializes.
130 <pre><code>
131// in your initialization function
132init : function(){
133 YAHOO.ext.state.Manager.setProvider(new YAHOO.ext.state.CookieProvider());
134 ...
135 // supposed you have a {@link YAHOO.ext.BorderLayout}
136 var layout = new YAHOO.ext.BorderLayout(...);
137 layout.restoreState();
138 // or a {YAHOO.ext.BasicDialog}
139 var dialog = new YAHOO.ext.BasicDialog(...);
140 dialog.restoreState();
141 </code></pre>
142 * @singleton
143 */
144YAHOO.ext.state.Manager = new function(){
145 var provider = new YAHOO.ext.state.Provider();
146
147 return {
148 /**
149 * Configures the default provider for your application.
150 * @param {Provider} stateProvider
151 */
152 setProvider : function(stateProvider){
153 provider = stateProvider;
154 },
155
156 /**
157 * Get the current value for a key.
158 * @param {String} name
159 * @param {Mixed} defaultValue
160 * @return {Mixed}
161 */
162 get : function(key, defaultValue){
163 return provider.get(key, defaultValue);
164 },
165
166 /**
167 * Set the value for a key.
168 * @param {String} name
169 * @param {Mixed} value
170 */
171 set : function(key, value){
172 provider.set(key, value);
173 },
174
175 /**
176 * Clear a value from the state.
177 */
178 clear : function(key){
179 provider.clear(key);
180 },
181
182 /**
183 * Gets the currently configured provider.
184 * @return {Provider}
185 */
186 getProvider : function(){
187 return provider;
188 }
189 };
190}();
191
192/**
193 * @class YAHOO.ext.state.CookieProvider
194 * @extends YAHOO.ext.state.Provider
195 * The default Provider implementation. The example below includes all valid configuration options and their
196 * default values.
197 <pre><code>
198 var cp = new YAHOO.ext.state.CookieProvider({
199 path: '/',
200 expires: new Date(new Date().getTime()+(1000*60*60*24*7)); //7 days
201 domain: null,
202 secure: false
203 })
204 YAHOO.ext.state.Manager.setProvider(cp);
205 </code></pre>
206 * @constructor
207 * Create a new CookieProvider
208 * @param {Object} config The configuration object
209 */
210YAHOO.ext.state.CookieProvider = function(config){
211 YAHOO.ext.state.CookieProvider.superclass.constructor.call(this);
212 this.path = '/';
213 this.expires = new Date(new Date().getTime()+(1000*60*60*24*7)); //7 days
214 this.domain = null;
215 this.secure = false;
216 YAHOO.ext.util.Config.apply(this, config);
217 this.state = this.readCookies();
218};
219
220YAHOO.extendX(YAHOO.ext.state.CookieProvider, YAHOO.ext.state.Provider, {
221 set : function(name, value){
222 if(typeof value == 'undefined' || value === null){
223 this.clear(name);
224 return;
225 }
226 this.setCookie(name, value);
227 YAHOO.ext.state.CookieProvider.superclass.set.call(this, name, value);
228 },
229
230 clear : function(name){
231 this.clearCookie(name);
232 YAHOO.ext.state.CookieProvider.superclass.clear.call(this, name);
233 },
234
235 readCookies : function(){
236 var cookies = {};
237 var c = document.cookie + ';';
238 var re = /\s?(.*?)=(.*?);/g;
239 var matches;
240 while((matches = re.exec(c)) != null){
241 var name = matches[1];
242 var value = matches[2];
243 if(name && name.substring(0,3) == 'ys-'){
244 cookies[name.substr(3)] = this.decodeValue(value);
245 }
246 }
247 return cookies;
248 },
249
250 setCookie : function(name, value){
251 document.cookie = "ys-"+ name + "=" + this.encodeValue(value) +
252 ((this.expires == null) ? "" : ("; expires=" + this.expires.toGMTString())) +
253 ((this.path == null) ? "" : ("; path=" + this.path)) +
254 ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
255 ((this.secure == true) ? "; secure" : "");
256 },
257
258 clearCookie : function(name){
259 document.cookie = "ys-" + name + "=null; expires=Thu, 01-Jan-70 00:00:01 GMT" +
260 ((this.path == null) ? "" : ("; path=" + this.path)) +
261 ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
262 ((this.secure == true) ? "; secure" : "");
263 }
264});
diff --git a/frontend/beta/js/YUI-extensions/UpdateManager.js b/frontend/beta/js/YUI-extensions/UpdateManager.js
new file mode 100644
index 0000000..c2eb23f
--- a/dev/null
+++ b/frontend/beta/js/YUI-extensions/UpdateManager.js
@@ -0,0 +1,484 @@
1/**
2 * @class YAHOO.ext.UpdateManager
3 * @extends YAHOO.ext.util.Observable
4 * Provides AJAX-style update for Element object using Yahoo
5 * UI library YAHOO.util.Connect functionality.<br><br>
6 * Usage:<br>
7 * <pre><code>
8 * // Get it from a YAHOO.ext.Element object
9 * var el = getEl('foo');
10 * var mgr = el.getUpdateManager();
11 * mgr.update('http://myserver.com/index.php', 'param1=1&amp;param2=2');
12 * ...
13 * mgr.formUpdate('myFormId', 'http://myserver.com/index.php');
14 * <br>
15 * // or directly (returns the same UpdateManager instance)
16 * var mgr = new YAHOO.ext.UpdateManager('myElementId');
17 * mgr.startAutoRefresh(60, 'http://myserver.com/index.php');
18 * mgr.on('update', myFcnNeedsToKnow);
19 * <br>
20 * </code></pre>
21 * @requires YAHOO.ext.Element
22 * @requires YAHOO.util.Dom
23 * @requires YAHOO.util.Event
24 * @requires YAHOO.util.CustomEvent
25 * @requires YAHOO.util.Connect
26 * @constructor
27 * Create new UpdateManager directly.
28 * @param {String/HTMLElement/YAHOO.ext.Element} el The element to update
29 * @param {<i>Boolean</i>} forceNew (optional) By default the constructor checks to see if the passed element already has an UpdateManager and if it does it returns the same instance. This will skip that check (useful for extending this class).
30 */
31YAHOO.ext.UpdateManager = function(el, forceNew){
32 el = YAHOO.ext.Element.get(el);
33 if(!forceNew && el.updateManager){
34 return el.updateManager;
35 }
36 /**
37 * The Element object
38 * @type YAHOO.ext.Element
39 */
40 this.el = el;
41 /**
42 * Cached url to use for refreshes. Overwritten every time update() is called unless 'discardUrl' param is set to true.
43 * @type String
44 */
45 this.defaultUrl = null;
46 this.beforeUpdate = new YAHOO.util.CustomEvent('UpdateManager.beforeUpdate');
47 this.onUpdate = new YAHOO.util.CustomEvent('UpdateManager.onUpdate');
48 this.onFailure = new YAHOO.util.CustomEvent('UpdateManager.onFailure');
49
50 this.events = {
51 /**
52 * @event beforeupdate
53 * Fired before an update is made, return false from your handler and the update is cancelled.
54 * @param {YAHOO.ext.Element} el
55 * @param {String/Object/Function} url
56 * @param {String/Object} params
57 */
58 'beforeupdate': this.beforeUpdate,
59 /**
60 * @event update
61 * Fired after successful update is made.
62 * @param {YAHOO.ext.Element} el
63 * @param {Object} oResponseObject The YAHOO.util.Connect response Object
64 */
65 'update': this.onUpdate,
66 /**
67 * @event failure
68 * Fired on update failure. Uses fireDirect with signature: (oElement, oResponseObject)
69 * @param {YAHOO.ext.Element} el
70 * @param {Object} oResponseObject The YAHOO.util.Connect response Object
71 */
72 'failure': this.onFailure
73 };
74
75 /**
76 * Blank page URL to use with SSL file uploads (Defaults to YAHOO.ext.UpdateManager.defaults.sslBlankUrl or 'about:blank').
77 * @type String
78 */
79 this.sslBlankUrl = YAHOO.ext.UpdateManager.defaults.sslBlankUrl;
80 /**
81 * Whether to append unique parameter on get request to disable caching (Defaults to YAHOO.ext.UpdateManager.defaults.disableCaching or false).
82 * @type Boolean
83 */
84 this.disableCaching = YAHOO.ext.UpdateManager.defaults.disableCaching;
85 /**
86 * Text for loading indicator (Defaults to YAHOO.ext.UpdateManager.defaults.indicatorText or '&lt;div class="loading-indicator"&gt;Loading...&lt;/div&gt;').
87 * @type String
88 */
89 this.indicatorText = YAHOO.ext.UpdateManager.defaults.indicatorText;
90 /**
91 * Whether to show indicatorText when loading (Defaults to YAHOO.ext.UpdateManager.defaults.showLoadIndicator or true).
92 * @type String
93 */
94 this.showLoadIndicator = YAHOO.ext.UpdateManager.defaults.showLoadIndicator;
95 /**
96 * Timeout for requests or form posts in seconds (Defaults to YAHOO.ext.UpdateManager.defaults.timeout or 30 seconds).
97 * @type Number
98 */
99 this.timeout = YAHOO.ext.UpdateManager.defaults.timeout;
100
101 /**
102 * True to process scripts in the output (Defaults to YAHOO.ext.UpdateManager.defaults.loadScripts (false)).
103 * @type Boolean
104 */
105 this.loadScripts = YAHOO.ext.UpdateManager.defaults.loadScripts;
106
107 /**
108 * YAHOO.util.Connect transaction object of current executing transaction
109 */
110 this.transaction = null;
111
112 /**
113 * @private
114 */
115 this.autoRefreshProcId = null;
116 /**
117 * Delegate for refresh() prebound to 'this', use myUpdater.refreshDelegate.createCallback(arg1, arg2) to bind arguments
118 * @type Function
119 */
120 this.refreshDelegate = this.refresh.createDelegate(this);
121 /**
122 * Delegate for update() prebound to 'this', use myUpdater.updateDelegate.createCallback(arg1, arg2) to bind arguments
123 * @type Function
124 */
125 this.updateDelegate = this.update.createDelegate(this);
126 /**
127 * Delegate for formUpdate() prebound to 'this', use myUpdater.formUpdateDelegate.createCallback(arg1, arg2) to bind arguments
128 * @type Function
129 */
130 this.formUpdateDelegate = this.formUpdate.createDelegate(this);
131 /**
132 * @private
133 */
134 this.successDelegate = this.processSuccess.createDelegate(this);
135 /**
136 * @private
137 */
138 this.failureDelegate = this.processFailure.createDelegate(this);
139
140 /**
141 * The renderer for this UpdateManager. Defaults to {@link YAHOO.ext.UpdateManager.BasicRenderer}.
142 */
143 this.renderer = new YAHOO.ext.UpdateManager.BasicRenderer();
144};
145
146YAHOO.ext.UpdateManager.prototype = {
147 fireEvent : YAHOO.ext.util.Observable.prototype.fireEvent,
148 on : YAHOO.ext.util.Observable.prototype.on,
149 addListener : YAHOO.ext.util.Observable.prototype.addListener,
150 delayedListener : YAHOO.ext.util.Observable.prototype.delayedListener,
151 removeListener : YAHOO.ext.util.Observable.prototype.removeListener,
152 purgeListeners : YAHOO.ext.util.Observable.prototype.purgeListeners,
153 bufferedListener : YAHOO.ext.util.Observable.prototype.bufferedListener,
154 /**
155 * Get the Element this UpdateManager is bound to
156 * @return {YAHOO.ext.Element} The element
157 */
158 getEl : function(){
159 return this.el;
160 },
161
162 /**
163 * Performs an async request, updating this element with the response. If params are specified it uses POST, otherwise it uses GET.
164 * @param {Object/String/Function} url The url for this request or a function to call to get the url or a config object containing any of the following options:
165<pre><code>
166um.update({<br/>
167 url: 'your-url.php',<br/>
168 params: {param1: 'foo', param2: 'bar'}, // or a URL encoded string<br/>
169 callback: yourFunction,<br/>
170 scope: yourObject, //(optional scope) <br/>
171 discardUrl: false, <br/>
172 nocache: false,<br/>
173 text: 'Loading...',<br/>
174 timeout: 30,<br/>
175 scripts: false<br/>
176});
177</code></pre>
178 * The only required property is url. The optional properties nocache, text and scripts
179 * are shorthand for disableCaching, indicatorText and loadScripts and are used to set their associated property on this UpdateManager instance.
180 * @param {<i>String/Object</i>} params (optional) The parameters to pass as either a url encoded string "param1=1&amp;param2=2" or an object {param1: 1, param2: 2}
181 * @param {<i>Function</i>} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
182 * @param {<i>Boolean</i>} discardUrl (optional) By default when you execute an update the defaultUrl is changed to the last used url. If true, it will not store the url.
183 */
184 update : function(url, params, callback, discardUrl){
185 if(this.beforeUpdate.fireDirect(this.el, url, params) !== false){
186 if(typeof url == 'object'){ // must be config object
187 var cfg = url;
188 url = cfg.url;
189 params = params || cfg.params;
190 callback = callback || cfg.callback;
191 discardUrl = discardUrl || cfg.discardUrl;
192 if(callback && cfg.scope){
193 callback = callback.createDelegate(cfg.scope);
194 }
195 if(typeof cfg.nocache != 'undefined'){this.disableCaching = cfg.nocache};
196 if(typeof cfg.text != 'undefined'){this.indicatorText = '<div class="loading-indicator">'+cfg.text+'</div>'};
197 if(typeof cfg.scripts != 'undefined'){this.loadScripts = cfg.scripts};
198 if(typeof cfg.timeout != 'undefined'){this.timeout = cfg.timeout};
199 }
200 this.showLoading();
201 if(!discardUrl){
202 this.defaultUrl = url;
203 }
204 if(typeof url == 'function'){
205 url = url();
206 }
207 if(typeof params == 'function'){
208 params = params();
209 }
210 if(params && typeof params != 'string'){ // must be object
211 var buf = [];
212 for(var key in params){
213 if(typeof params[key] != 'function'){
214 buf.push(encodeURIComponent(key), '=', encodeURIComponent(params[key]), '&');
215 }
216 }
217 delete buf[buf.length-1];
218 params = buf.join('');
219 }
220 var callback = {
221 success: this.successDelegate,
222 failure: this.failureDelegate,
223 timeout: (this.timeout*1000),
224 argument: {'url': url, 'form': null, 'callback': callback, 'params': params}
225 };
226 var method = params ? 'POST' : 'GET';
227 if(method == 'GET'){
228 url = this.prepareUrl(url);
229 }
230 this.transaction = YAHOO.util.Connect.asyncRequest(method, url, callback, params);
231 }
232 },
233
234 /**
235 * Performs an async form post, updating this element with the response. If the form has the attribute enctype="multipart/form-data", it assumes it's a file upload.
236 * Uses this.sslBlankUrl for SSL file uploads to prevent IE security warning. See YUI docs for more info.
237 * @param {String/HTMLElement} form The form Id or form element
238 * @param {<i>String</i>} url (optional) The url to pass the form to. If omitted the action attribute on the form will be used.
239 * @param {<i>Boolean</i>} reset (optional) Whether to try to reset the form after the update
240 * @param {<i>Function</i>} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
241 */
242 formUpdate : function(form, url, reset, callback){
243 if(this.beforeUpdate.fireDirect(this.el, form, url) !== false){
244 formEl = YAHOO.util.Dom.get(form);
245 this.showLoading();
246 if(typeof url == 'function'){
247 url = url();
248 }
249 if(typeof params == 'function'){
250 params = params();
251 }
252 url = url || formEl.action;
253 var callback = {
254 success: this.successDelegate,
255 failure: this.failureDelegate,
256 timeout: (this.timeout*1000),
257 argument: {'url': url, 'form': form, 'callback': callback, 'reset': reset}
258 };
259 var isUpload = false;
260 var enctype = formEl.getAttribute('enctype');
261 if(enctype && enctype.toLowerCase() == 'multipart/form-data'){
262 isUpload = true;
263 }
264 YAHOO.util.Connect.setForm(form, isUpload, this.sslBlankUrl);
265 this.transaction = YAHOO.util.Connect.asyncRequest('POST', url, callback);
266 }
267 },
268
269 /**
270 * Refresh the element with the last used url or defaultUrl. If there is no url, it returns immediately
271 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
272 */
273 refresh : function(callback){
274 if(this.defaultUrl == null){
275 return;
276 }
277 this.update(this.defaultUrl, null, callback, true);
278 },
279
280 /**
281 * Set this element to auto refresh.
282 * @param {Number} interval How often to update (in seconds).
283 * @param {<i>String/Function</i>} url (optional) The url for this request or a function to call to get the url (Defaults to the last used url)
284 * @param {<i>String/Object</i>} params (optional) The parameters to pass as either a url encoded string "&param1=1&param2=2" or as an object {param1: 1, param2: 2}
285 * @param {<i>Function</i>} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
286 * @param {<i>Boolean</i>} refreshNow (optional) Whether to execute the refresh now, or wait the interval
287 */
288 startAutoRefresh : function(interval, url, params, callback, refreshNow){
289 if(refreshNow){
290 this.update(url || this.defaultUrl, params, callback, true);
291 }
292 if(this.autoRefreshProcId){
293 clearInterval(this.autoRefreshProcId);
294 }
295 this.autoRefreshProcId = setInterval(this.update.createDelegate(this, [url || this.defaultUrl, params, callback, true]), interval*1000);
296 },
297
298 /**
299 * Stop auto refresh on this element.
300 */
301 stopAutoRefresh : function(){
302 if(this.autoRefreshProcId){
303 clearInterval(this.autoRefreshProcId);
304 }
305 },
306
307 /**
308 * Called to update the element to "Loading" state. Override to perform custom action.
309 */
310 showLoading : function(){
311 if(this.showLoadIndicator){
312 this.el.update(this.indicatorText);
313 }
314 },
315
316 /**
317 * Adds unique parameter to query string if disableCaching = true
318 * @private
319 */
320 prepareUrl : function(url){
321 if(this.disableCaching){
322 var append = '_dc=' + (new Date().getTime());
323 if(url.indexOf('?') !== -1){
324 url += '&' + append;
325 }else{
326 url += '?' + append;
327 }
328 }
329 return url;
330 },
331
332 /**
333 * @private
334 */
335 processSuccess : function(response){
336 this.transaction = null;
337 if(response.argument.form && response.argument.reset){
338 try{ // put in try/catch since some older FF releases had problems with this
339 response.argument.form.reset();
340 }catch(e){}
341 }
342 if(this.loadScripts){
343 this.renderer.render(this.el, response, this,
344 this.updateComplete.createDelegate(this, [response]));
345 }else{
346 this.renderer.render(this.el, response, this);
347 this.updateComplete(response);
348 }
349 },
350
351 updateComplete : function(response){
352 this.fireEvent('update', this.el, response);
353 if(typeof response.argument.callback == 'function'){
354 response.argument.callback(this.el, true, response);
355 }
356 },
357
358 /**
359 * @private
360 */
361 processFailure : function(response){
362 this.transaction = null;
363 this.onFailure.fireDirect(this.el, response);
364 if(typeof response.argument.callback == 'function'){
365 response.argument.callback(this.el, false, response);
366 }
367 },
368
369 /**
370 * Set the content renderer for this UpdateManager. See {@link YAHOO.ext.UpdateManager.BasicRenderer#render} for more details.
371 * @param {Object} renderer The object implementing the render() method
372 */
373 setRenderer : function(renderer){
374 this.renderer = renderer;
375 },
376
377 getRenderer : function(){
378 return this.renderer;
379 },
380
381 /**
382 * Set the defaultUrl used for updates
383 * @param {String/Function} defaultUrl The url or a function to call to get the url
384 */
385 setDefaultUrl : function(defaultUrl){
386 this.defaultUrl = defaultUrl;
387 },
388
389 /**
390 * Aborts the executing transaction
391 */
392 abort : function(){
393 if(this.transaction){
394 YAHOO.util.Connect.abort(this.transaction);
395 }
396 },
397
398 /**
399 * Returns true if an update is in progress
400 * @return {Boolean}
401 */
402 isUpdating : function(){
403 if(this.transaction){
404 return YAHOO.util.Connect.isCallInProgress(this.transaction);
405 }
406 return false;
407 }
408};
409
410/**
411 * @class YAHOO.ext.UpdateManager.defaults
412 * The defaults collection enables customizing the default properties of UpdateManager
413 */
414 YAHOO.ext.UpdateManager.defaults = {
415 /**
416 * Timeout for requests or form posts in seconds (Defaults 30 seconds).
417 * @type Number
418 */
419 timeout : 30,
420
421 /**
422 * True to process scripts by default (Defaults to false).
423 * @type Boolean
424 */
425 loadScripts : false,
426
427 /**
428 * Blank page URL to use with SSL file uploads (Defaults to 'javascript:false').
429 * @type String
430 */
431 sslBlankUrl : (YAHOO.ext.SSL_SECURE_URL || 'javascript:false'),
432 /**
433 * Whether to append unique parameter on get request to disable caching (Defaults to false).
434 * @type Boolean
435 */
436 disableCaching : false,
437 /**
438 * Whether to show indicatorText when loading (Defaults to true).
439 * @type Boolean
440 */
441 showLoadIndicator : true,
442 /**
443 * Text for loading indicator (Defaults to '&lt;div class="loading-indicator"&gt;Loading...&lt;/div&gt;').
444 * @type String
445 */
446 indicatorText : '<div class="loading-indicator">Loading...</div>'
447 };
448
449/**
450 * Static convenience method, Usage:
451 * <pre><code>YAHOO.ext.UpdateManager.updateElement('my-div', 'stuff.php');</code></pre>
452 * @param {String/HTMLElement/YAHOO.ext.Element} el The element to update
453 * @param {String} url The url
454 * @param {<i>String/Object</i>} params (optional) Url encoded param string or an object of name/value pairs
455 * @param {<i>Object</i>} options (optional) A config object with any of the UpdateManager properties you want to set - for example: {disableCaching:true, indicatorText: 'Loading data...'}
456 * @static
457 */
458YAHOO.ext.UpdateManager.updateElement = function(el, url, params, options){
459 var um = getEl(el, true).getUpdateManager();
460 YAHOO.ext.util.Config.apply(um, options);
461 um.update(url, params, options ? options.callback : null);
462};
463// alias for backwards compat
464YAHOO.ext.UpdateManager.update = YAHOO.ext.UpdateManager.updateElement;
465/**
466 * @class YAHOO.ext.UpdateManager.BasicRenderer
467 * Default Content renderer. Updates the elements innerHTML with the responseText.
468 */
469YAHOO.ext.UpdateManager.BasicRenderer = function(){};
470
471YAHOO.ext.UpdateManager.BasicRenderer.prototype = {
472 /**
473 * This is called when the transaction is completed and it's time to update the element - The BasicRenderer
474 * updates the elements innerHTML with the responseText - To perform a custom render (i.e. XML or JSON processing),
475 * create an object with a "render(el, response)" method and pass it to setRenderer on the UpdateManager.
476 * @param {YAHOO.ext.Element} el The element being rendered
477 * @param {Object} response The YUI Connect response object
478 * @param {UpdateManager} updateManager The calling update manager
479 * @param {Function} callback A callback that will need to be called if loadScripts is true on the UpdateManager
480 */
481 render : function(el, response, updateManager, callback){
482 el.update(response.responseText, updateManager.loadScripts, callback);
483 }
484};
diff --git a/frontend/beta/js/YUI-extensions/anim/Actor.js b/frontend/beta/js/YUI-extensions/anim/Actor.js
new file mode 100644
index 0000000..f5574e6
--- a/dev/null
+++ b/frontend/beta/js/YUI-extensions/anim/Actor.js
@@ -0,0 +1,759 @@
1
2/**
3 * @class YAHOO.ext.Actor
4 * Provides support for syncing and chaining of Element Yahoo! UI based animation and some common effects. Actors support "self-play" without an Animator.<br><br>
5 * <b>Note: Along with the animation methods defined below, this class inherits and captures all of the "set" or animation methods of {@link YAHOO.ext.Element}. "get" methods are not captured and execute immediately.</b>
6 * <br><br>Usage:<br>
7 * <pre><code>
8 * var actor = new YAHOO.ext.Actor('myElementId');
9 * actor.startCapture(true);
10 * actor.moveTo(100, 100, true);
11 * actor.squish();
12 * actor.play();
13 * <br>
14 * // or to start capturing immediately, with no Animator (the null second param)
15 * <br>
16 * var actor = new YAHOO.ext.Actor('myElementId', null, true);
17 * actor.moveTo(100, 100, true);
18 * actor.squish();
19 * actor.play();
20 * </code></pre>
21 * @extends YAHOO.ext.Element
22 * @requires YAHOO.ext.Element
23 * @requires YAHOO.util.Dom
24 * @requires YAHOO.util.Event
25 * @requires YAHOO.util.CustomEvent
26 * @requires YAHOO.util.Anim
27 * @requires YAHOO.util.ColorAnim
28 * @requires YAHOO.util.Motion
29 * @className YAHOO.ext.Actor
30 * @constructor
31 * Create new Actor.
32 * @param {String/HTMLElement} el The dom element or element id
33 * @param {<i>YAHOO.ext.Animator</i>} animator (optional) The Animator that will capture this Actor's actions
34 * @param {<i>Boolean</i>} selfCapture (optional) Whether this actor should capture it's own actions to support self playback without an animator (defaults to false)
35 */
36YAHOO.ext.Actor = function(element, animator, selfCapture){
37 this.el = YAHOO.ext.Element.get(element, true); // cache el object for playback
38 YAHOO.ext.Actor.superclass.constructor.call(this, element, true);
39 this.onCapture = new YAHOO.util.CustomEvent('Actor.onCapture');
40 if(animator){
41 /**
42 * The animator used to sync this actor with other actors
43 * @member YAHOO.ext.Actor
44 */
45 animator.addActor(this);
46 }
47 /**
48 * Whether this actor is currently capturing
49 * @member YAHOO.ext.Actor
50 */
51 this.capturing = selfCapture;
52 this.playlist = selfCapture ? new YAHOO.ext.Animator.AnimSequence() : null;
53};
54
55YAHOO.extendX(YAHOO.ext.Actor, YAHOO.ext.Element);
56
57/**
58 * Captures an action for this actor. Generally called internally but can be called directly.
59 * @param {YAHOO.ext.Actor.Action} action
60 */
61YAHOO.ext.Actor.prototype.capture = function(action){
62 if(this.playlist != null){
63 this.playlist.add(action);
64 }
65 this.onCapture.fireDirect(this, action);
66 return action;
67};
68
69/** @ignore */
70YAHOO.ext.Actor.overrideAnimation = function(method, animParam, onParam){
71 return function(){
72 if(!this.capturing){
73 return method.apply(this, arguments);
74 }
75 var args = Array.prototype.slice.call(arguments, 0);
76 if(args[animParam] === true){
77 return this.capture(new YAHOO.ext.Actor.AsyncAction(this, method, args, onParam));
78 }else{
79 return this.capture(new YAHOO.ext.Actor.Action(this, method, args));
80 }
81 };
82}
83
84/** @ignore */
85YAHOO.ext.Actor.overrideBasic = function(method){
86 return function(){
87 if(!this.capturing){
88 return method.apply(this, arguments);
89 }
90 var args = Array.prototype.slice.call(arguments, 0);
91 return this.capture(new YAHOO.ext.Actor.Action(this, method, args));
92 };
93}
94
95// All of these methods below are marked "ignore" because JSDoc treats them as fields, not function. How brilliant. The Element methods are documented anyway though.
96/** Capturing override - See {@link YAHOO.ext.Element#setVisibilityMode} for method details.
97 * @method */
98YAHOO.ext.Actor.prototype.setVisibilityMode = YAHOO.ext.Actor.overrideBasic(YAHOO.ext.Actor.superclass.setVisibilityMode);
99/** Capturing override - See {@link YAHOO.ext.Element#enableDisplayMode} for method details.
100 * @method */
101YAHOO.ext.Actor.prototype.enableDisplayMode = YAHOO.ext.Actor.overrideBasic(YAHOO.ext.Actor.superclass.enableDisplayMode);
102/** Capturing override - See {@link YAHOO.ext.Element#focus} for method details.
103 * @method */
104YAHOO.ext.Actor.prototype.focus = YAHOO.ext.Actor.overrideBasic(YAHOO.ext.Actor.superclass.focus);
105/** Capturing override - See {@link YAHOO.ext.Element#addClass} for method details.
106 * @method */
107YAHOO.ext.Actor.prototype.addClass = YAHOO.ext.Actor.overrideBasic(YAHOO.ext.Actor.superclass.addClass);
108/** Capturing override - See {@link YAHOO.ext.Element#removeClass} for method details.
109 * @method */
110YAHOO.ext.Actor.prototype.removeClass = YAHOO.ext.Actor.overrideBasic(YAHOO.ext.Actor.superclass.removeClass);
111/** Capturing override - See {@link YAHOO.ext.Element#replaceClass} for method details.
112 * @method */
113YAHOO.ext.Actor.prototype.replaceClass = YAHOO.ext.Actor.overrideBasic(YAHOO.ext.Actor.superclass.replaceClass);
114/** Capturing override - See {@link YAHOO.ext.Element#setStyle} for method details.
115 * @method */
116YAHOO.ext.Actor.prototype.setStyle = YAHOO.ext.Actor.overrideBasic(YAHOO.ext.Actor.superclass.setStyle);
117/** Capturing override - See {@link YAHOO.ext.Element#setLeft} for method details.
118 * @method */
119YAHOO.ext.Actor.prototype.setLeft = YAHOO.ext.Actor.overrideBasic(YAHOO.ext.Actor.superclass.setLeft);
120/** Capturing override - See {@link YAHOO.ext.Element#setTop} for method details.
121 * @method */
122YAHOO.ext.Actor.prototype.setTop = YAHOO.ext.Actor.overrideBasic(YAHOO.ext.Actor.superclass.setTop);
123/** Capturing override - See {@link YAHOO.ext.Element#setAbsolutePositioned} for method details.
124 * @method */
125YAHOO.ext.Actor.prototype.setAbsolutePositioned = YAHOO.ext.Actor.overrideBasic(YAHOO.ext.Actor.superclass.setAbsolutePositioned);
126/** Capturing override - See {@link YAHOO.ext.Element#setRelativePositioned} for method details.
127 * @method */
128YAHOO.ext.Actor.prototype.setRelativePositioned = YAHOO.ext.Actor.overrideBasic(YAHOO.ext.Actor.superclass.setRelativePositioned);
129/** Capturing override - See {@link YAHOO.ext.Element#clearPositioning} for method details.
130 * @method */
131YAHOO.ext.Actor.prototype.clearPositioning = YAHOO.ext.Actor.overrideBasic(YAHOO.ext.Actor.superclass.clearPositioning);
132/** Capturing override - See {@link YAHOO.ext.Element#setPositioning} for method details.
133 * @method */
134YAHOO.ext.Actor.prototype.setPositioning = YAHOO.ext.Actor.overrideBasic(YAHOO.ext.Actor.superclass.setPositioning);
135/** Capturing override - See {@link YAHOO.ext.Element#clip} for method details.
136 * @method */
137YAHOO.ext.Actor.prototype.clip = YAHOO.ext.Actor.overrideBasic(YAHOO.ext.Actor.superclass.clip);
138/** Capturing override - See {@link YAHOO.ext.Element#unclip} for method details.
139 * @method */
140YAHOO.ext.Actor.prototype.unclip = YAHOO.ext.Actor.overrideBasic(YAHOO.ext.Actor.superclass.unclip);
141/** Capturing override - See {@link YAHOO.ext.Element#clearOpacity} for method details.
142 * @method */
143YAHOO.ext.Actor.prototype.clearOpacity = YAHOO.ext.Actor.overrideBasic(YAHOO.ext.Actor.superclass.clearOpacity);
144/** Capturing override - See {@link YAHOO.ext.Element#update} for method details.
145 * @method */
146YAHOO.ext.Actor.prototype.update = YAHOO.ext.Actor.overrideBasic(YAHOO.ext.Actor.superclass.update);
147/** Capturing override - See {@link YAHOO.ext.Element#remove} for method details.
148 * @method */
149YAHOO.ext.Actor.prototype.remove = YAHOO.ext.Actor.overrideBasic(YAHOO.ext.Actor.superclass.remove);
150YAHOO.ext.Actor.prototype.fitToParent = YAHOO.ext.Actor.overrideBasic(YAHOO.ext.Actor.superclass.fitToParent);
151YAHOO.ext.Actor.prototype.appendChild = YAHOO.ext.Actor.overrideBasic(YAHOO.ext.Actor.superclass.appendChild);
152YAHOO.ext.Actor.prototype.createChild = YAHOO.ext.Actor.overrideBasic(YAHOO.ext.Actor.superclass.createChild);
153YAHOO.ext.Actor.prototype.appendTo = YAHOO.ext.Actor.overrideBasic(YAHOO.ext.Actor.superclass.appendTo);
154YAHOO.ext.Actor.prototype.insertBefore = YAHOO.ext.Actor.overrideBasic(YAHOO.ext.Actor.superclass.insertBefore);
155YAHOO.ext.Actor.prototype.insertAfter = YAHOO.ext.Actor.overrideBasic(YAHOO.ext.Actor.superclass.insertAfter);
156YAHOO.ext.Actor.prototype.wrap = YAHOO.ext.Actor.overrideBasic(YAHOO.ext.Actor.superclass.wrap);
157YAHOO.ext.Actor.prototype.replace = YAHOO.ext.Actor.overrideBasic(YAHOO.ext.Actor.superclass.replace);
158YAHOO.ext.Actor.prototype.insertHtml = YAHOO.ext.Actor.overrideBasic(YAHOO.ext.Actor.superclass.insertHtml);
159YAHOO.ext.Actor.prototype.set = YAHOO.ext.Actor.overrideBasic(YAHOO.ext.Actor.superclass.set);
160
161/**Capturing and animation syncing override - See {@link YAHOO.ext.Element#load} for method details.
162 * @method */
163YAHOO.ext.Actor.prototype.load = function(){
164 if(!this.capturing){
165 return YAHOO.ext.Actor.superclass.load.apply(this, arguments);
166 }
167 var args = Array.prototype.slice.call(arguments, 0);
168 return this.capture(new YAHOO.ext.Actor.AsyncAction(this, YAHOO.ext.Actor.superclass.load,
169 args, 2));
170};
171
172/**Capturing and animation syncing override - See {@link YAHOO.ext.Element#animate} for method details.
173 * @method */
174YAHOO.ext.Actor.prototype.animate = function(args, duration, onComplete, easing, animType){
175 if(!this.capturing){
176 return YAHOO.ext.Actor.superclass.animate.apply(this, arguments);
177 }
178 return this.capture(new YAHOO.ext.Actor.AsyncAction(this, YAHOO.ext.Actor.superclass.animate,
179 [args, duration, onComplete, easing, animType], 2));
180};
181
182/** Capturing and animation syncing override - See {@link YAHOO.ext.Element#setVisible} for method details.
183 * @method */
184YAHOO.ext.Actor.prototype.setVisible = YAHOO.ext.Actor.overrideAnimation(YAHOO.ext.Actor.superclass.setVisible, 1, 3);
185/**Capturing and animation syncing override - See {@link YAHOO.ext.Element#toggle} for method details.
186 * @method */
187YAHOO.ext.Actor.prototype.toggle = YAHOO.ext.Actor.overrideAnimation(YAHOO.ext.Actor.superclass.toggle, 0, 2);
188/**Capturing and animation syncing override - See {@link YAHOO.ext.Element#setXY} for method details.
189 * @method */
190YAHOO.ext.Actor.prototype.setXY = YAHOO.ext.Actor.overrideAnimation(YAHOO.ext.Actor.superclass.setXY, 1, 3);
191/**Capturing and animation syncing override - See {@link YAHOO.ext.Element#setLocation} for method details.
192 * @method */
193YAHOO.ext.Actor.prototype.setLocation = YAHOO.ext.Actor.overrideAnimation(YAHOO.ext.Actor.superclass.setLocation, 2, 4);
194/**Capturing and animation syncing override - See {@link YAHOO.ext.Element#setWidth} for method details.
195 * @method */
196YAHOO.ext.Actor.prototype.setWidth = YAHOO.ext.Actor.overrideAnimation(YAHOO.ext.Actor.superclass.setWidth, 1, 3);
197/**Capturing and animation syncing override - See {@link YAHOO.ext.Element#setHeight} for method details.
198 * @method */
199YAHOO.ext.Actor.prototype.setHeight = YAHOO.ext.Actor.overrideAnimation(YAHOO.ext.Actor.superclass.setHeight, 1, 3);
200/**Capturing and animation syncing override - See {@link YAHOO.ext.Element#setSize} for method details.
201 * @method */
202YAHOO.ext.Actor.prototype.setSize = YAHOO.ext.Actor.overrideAnimation(YAHOO.ext.Actor.superclass.setSize, 2, 4);
203/**Capturing and animation syncing override - See {@link YAHOO.ext.Element#setBounds} for method details.
204 * @method */
205YAHOO.ext.Actor.prototype.setBounds = YAHOO.ext.Actor.overrideAnimation(YAHOO.ext.Actor.superclass.setBounds, 4, 6);
206/**Capturing and animation syncing override - See {@link YAHOO.ext.Element#setOpacity} for method details.
207 * @method */
208YAHOO.ext.Actor.prototype.setOpacity = YAHOO.ext.Actor.overrideAnimation(YAHOO.ext.Actor.superclass.setOpacity, 1, 3);
209/**Capturing and animation syncing override - See {@link YAHOO.ext.Element#moveTo} for method details.
210 * @method */
211YAHOO.ext.Actor.prototype.moveTo = YAHOO.ext.Actor.overrideAnimation(YAHOO.ext.Actor.superclass.moveTo, 2, 4);
212/**Capturing and animation syncing override - See {@link YAHOO.ext.Element#move} for method details.
213 * @method */
214YAHOO.ext.Actor.prototype.move = YAHOO.ext.Actor.overrideAnimation(YAHOO.ext.Actor.superclass.move, 2, 4);
215/**Capturing and animation syncing override - See {@link YAHOO.ext.Element#alignTo} for method details.
216 * @method */
217YAHOO.ext.Actor.prototype.alignTo = YAHOO.ext.Actor.overrideAnimation(YAHOO.ext.Actor.superclass.alignTo, 3, 5);
218/**Capturing and animation syncing override - See {@link YAHOO.ext.Element#hide} for method details.
219 * @method */
220YAHOO.ext.Actor.prototype.hide = YAHOO.ext.Actor.overrideAnimation(YAHOO.ext.Actor.superclass.hide, 0, 2);
221/**Capturing and animation syncing override - See {@link YAHOO.ext.Element#show} for method details.
222 * @method */
223YAHOO.ext.Actor.prototype.show = YAHOO.ext.Actor.overrideAnimation(YAHOO.ext.Actor.superclass.show, 0, 2);
224
225/**Capturing and animation syncing override - See {@link YAHOO.ext.Element#setBox} for method details.
226 * @method */
227YAHOO.ext.Actor.prototype.setBox = YAHOO.ext.Actor.overrideAnimation(YAHOO.ext.Actor.superclass.setBox, 2, 4);
228
229/**Capturing and animation syncing override - See {@link YAHOO.ext.Element#autoHeight} for method details.
230 * @method */
231YAHOO.ext.Actor.prototype.autoHeight = YAHOO.ext.Actor.overrideAnimation(YAHOO.ext.Actor.superclass.autoHeight, 0, 2);
232/** Capturing override - See {@link YAHOO.ext.Element#setX} for method details.
233 * @method */
234YAHOO.ext.Actor.prototype.setX = YAHOO.ext.Actor.overrideAnimation(YAHOO.ext.Actor.superclass.setX, 1, 3);
235/** Capturing override - See {@link YAHOO.ext.Element#setY} for method details.
236 * @method */
237YAHOO.ext.Actor.prototype.setY = YAHOO.ext.Actor.overrideAnimation(YAHOO.ext.Actor.superclass.setY, 1, 3);
238
239/**
240 * Start self capturing calls on this Actor. All subsequent calls are captured and executed when play() is called.
241 */
242YAHOO.ext.Actor.prototype.startCapture = function(){
243 this.capturing = true;
244 this.playlist = new YAHOO.ext.Animator.AnimSequence();
245 };
246
247 /**
248 * Stop self capturing calls on this Actor.
249 */
250 YAHOO.ext.Actor.prototype.stopCapture = function(){
251 this.capturing = false;
252 };
253
254/**
255 * Clears any calls that have been self captured.
256 */
257YAHOO.ext.Actor.prototype.clear = function(){
258 this.playlist = new YAHOO.ext.Animator.AnimSequence();
259};
260
261/**
262 * Starts playback of self captured calls.
263 * @param {<i>Function</i>} oncomplete (optional) Callback to execute when playback has completed
264 */
265YAHOO.ext.Actor.prototype.play = function(oncomplete){
266 this.capturing = false;
267 if(this.playlist){
268 this.playlist.play(oncomplete);
269 }
270 };
271
272/**
273 * Capture a function call.
274 * @param {Function} fcn The function to call
275 * @param {<i>Array</i>} args (optional) The arguments to call the function with
276 * @param {<i>Object</i>} scope (optional) The scope of the function
277 */
278YAHOO.ext.Actor.prototype.addCall = function(fcn, args, scope){
279 if(!this.capturing){
280 fcn.apply(scope || this, args || []);
281 }else{
282 this.capture(new YAHOO.ext.Actor.Action(scope, fcn, args || []));
283 }
284};
285
286/**
287 * Capture an async function call.
288 * @param {Function} fcn The function to call
289 * @param {Number} callbackIndex The index of the callback parameter on the passed function. A CALLBACK IS REQUIRED.
290 * @param {<i>Array</i>} args The arguments to call the function with
291 * @param {<i>Object</i>} scope (optional) The scope of the function
292 */
293YAHOO.ext.Actor.prototype.addAsyncCall = function(fcn, callbackIndex, args, scope){
294 if(!this.capturing){
295 fcn.apply(scope || this, args || []);
296 }else{
297 this.capture(new YAHOO.ext.Actor.AsyncAction(scope, fcn, args || [], callbackIndex));
298 }
299 },
300
301/**
302 * Capture a pause (in seconds).
303 * @param {Number} seconds The seconds to pause
304 */
305YAHOO.ext.Actor.prototype.pause = function(seconds){
306 this.capture(new YAHOO.ext.Actor.PauseAction(seconds));
307 };
308
309/**
310* Shake this element from side to side
311*/
312YAHOO.ext.Actor.prototype.shake = function(){
313 this.move('left', 20, true, .05);
314 this.move('right', 40, true, .05);
315 this.move('left', 40, true, .05);
316 this.move('right', 20, true, .05);
317};
318
319/**
320* Bounce this element from up and down
321*/
322YAHOO.ext.Actor.prototype.bounce = function(){
323 this.move('up', 20, true, .05);
324 this.move('down', 40, true, .05);
325 this.move('up', 40, true, .05);
326 this.move('down', 20, true, .05);
327};
328
329/**
330* Show the element using a "blinds" effect
331* @param {String} anchor The part of the element that it should appear to exapand from.
332 The short/long options currently are t/top, l/left
333* @param {<i>Number</i>} newSize (optional) The size to animate to. (Default to current size)
334* @param {<i>Float</i>} duration (optional) How long the effect lasts (in seconds)
335* @param {<i>Function</i>} easing (optional) YAHOO.util.Easing method to use. (Defaults to YAHOO.util.Easing.easeOut)
336*/
337YAHOO.ext.Actor.prototype.blindShow = function(anchor, newSize, duration, easing){
338 var size = this.getSize();
339 this.clip();
340 anchor = anchor.toLowerCase();
341 switch(anchor){
342 case 't':
343 case 'top':
344 this.setHeight(1);
345 this.setVisible(true);
346 this.setHeight(newSize || size.height, true, duration || .5, null, easing || YAHOO.util.Easing.easeOut);
347 break;
348 case 'l':
349 case 'left':
350 this.setWidth(1);
351 this.setVisible(true);
352 this.setWidth(newSize || size.width, true, duration || .5, null, easing || YAHOO.util.Easing.easeOut);
353 break;
354 }
355 this.unclip();
356 return size;
357};
358
359/**
360* Hide the element using a "blinds" effect
361* @param {String} anchor The part of the element that it should appear to collapse to.
362 The short/long options are t/top, l/left, b/bottom, r/right.
363* @param {<i>Float</i>} duration (optional) How long the effect lasts (in seconds)
364* @param {<i>Function</i>} easing (optional) YAHOO.util.Easing method to use. (Defaults to YAHOO.util.Easing.easeIn)
365*/
366YAHOO.ext.Actor.prototype.blindHide = function(anchor, duration, easing){
367 var size = this.getSize();
368 this.clip();
369 anchor = anchor.toLowerCase();
370 switch(anchor){
371 case 't':
372 case 'top':
373 this.setSize(size.width, 1, true, duration || .5, null, easing || YAHOO.util.Easing.easeIn);
374 this.setVisible(false);
375 break;
376 case 'l':
377 case 'left':
378 this.setSize(1, size.height, true, duration || .5, null, easing || YAHOO.util.Easing.easeIn);
379 this.setVisible(false);
380 break;
381 case 'r':
382 case 'right':
383 this.animate({width: {to: 1}, points: {by: [size.width, 0]}},
384 duration || .5, null, YAHOO.util.Easing.easeIn, YAHOO.util.Motion);
385 this.setVisible(false);
386 break;
387 case 'b':
388 case 'bottom':
389 this.animate({height: {to: 1}, points: {by: [0, size.height]}},
390 duration || .5, null, YAHOO.util.Easing.easeIn, YAHOO.util.Motion);
391 this.setVisible(false);
392 break;
393 }
394 return size;
395};
396
397/**
398* Show the element using a "slide in" effect - In order for this effect to work the element MUST have a child element container that can be "slid" otherwise a blindShow effect is rendered.
399* @param {String} anchor The part of the element that it should appear to slide from.
400 The short/long options currently are t/top, l/left
401* @param {<i>Number</i>} newSize (optional) The size to animate to. (Default to current size)
402* @param {<i>Float</i>} duration (optional) How long the effect lasts (in seconds)
403* @param {<i>Function</i>} easing (optional) YAHOO.util.Easing method to use. (Defaults to YAHOO.util.Easing.easeOuth)
404*/
405YAHOO.ext.Actor.prototype.slideShow = function(anchor, newSize, duration, easing, clearPositioning){
406 var size = this.getSize();
407 this.clip();
408 var firstChild = this.dom.firstChild;
409 if(!firstChild || (firstChild.nodeName && "#TEXT" == firstChild.nodeName.toUpperCase())) { // can't do a slide with only a textnode
410 this.blindShow(anchor, newSize, duration, easing);
411 return;
412 }
413 var child = YAHOO.ext.Element.get(firstChild, true);
414 var pos = child.getPositioning();
415 this.addCall(child.setAbsolutePositioned, null, child);
416 this.setVisible(true);
417 anchor = anchor.toLowerCase();
418 switch(anchor){
419 case 't':
420 case 'top':
421 this.addCall(child.setStyle, ['right', ''], child);
422 this.addCall(child.setStyle, ['top', ''], child);
423 this.addCall(child.setStyle, ['left', '0px'], child);
424 this.addCall(child.setStyle, ['bottom', '0px'], child);
425 this.setHeight(1);
426 this.setHeight(newSize || size.height, true, duration || .5, null, easing || YAHOO.util.Easing.easeOut);
427 break;
428 case 'l':
429 case 'left':
430 this.addCall(child.setStyle, ['left', ''], child);
431 this.addCall(child.setStyle, ['bottom', ''], child);
432 this.addCall(child.setStyle, ['right', '0px'], child);
433 this.addCall(child.setStyle, ['top', '0px'], child);
434 this.setWidth(1);
435 this.setWidth(newSize || size.width, true, duration || .5, null, easing || YAHOO.util.Easing.easeOut);
436 break;
437 case 'r':
438 case 'right':
439 this.addCall(child.setStyle, ['left', '0px'], child);
440 this.addCall(child.setStyle, ['top', '0px'], child);
441 this.addCall(child.setStyle, ['right', ''], child);
442 this.addCall(child.setStyle, ['bottom', ''], child);
443 this.setWidth(1);
444 this.setWidth(newSize || size.width, true, duration || .5, null, easing || YAHOO.util.Easing.easeOut);
445 break;
446 case 'b':
447 case 'bottom':
448 this.addCall(child.setStyle, ['right', ''], child);
449 this.addCall(child.setStyle, ['top', '0px'], child);
450 this.addCall(child.setStyle, ['left', '0px'], child);
451 this.addCall(child.setStyle, ['bottom', ''], child);
452 this.setHeight(1);
453 this.setHeight(newSize || size.height, true, duration || .5, null, easing || YAHOO.util.Easing.easeOut);
454 break;
455 }
456 if(clearPositioning !== false){
457 this.addCall(child.setPositioning, [pos], child);
458 }
459 this.unclip();
460 return size;
461};
462
463/**
464* Hide the element using a "slide in" effect - In order for this effect to work the element MUST have a child element container that can be "slid" otherwise a blindHide effect is rendered.
465* @param {String} anchor The part of the element that it should appear to slide to.
466 The short/long options are t/top, l/left, b/bottom, r/right.
467* @param {<i>Float</i>} duration (optional) How long the effect lasts (in seconds)
468* @param {<i>Function</i>} easing (optional) YAHOO.util.Easing method to use. (Defaults to YAHOO.util.Easing.easeIn)
469*/
470YAHOO.ext.Actor.prototype.slideHide = function(anchor, duration, easing){
471 var size = this.getSize();
472 this.clip();
473 var firstChild = this.dom.firstChild;
474 if(!firstChild || (firstChild.nodeName && "#TEXT" == firstChild.nodeName.toUpperCase())) { // can't do a slide with only a textnode
475 this.blindHide(anchor, duration, easing);
476 return;
477 }
478 var child = YAHOO.ext.Element.get(firstChild, true);
479 var pos = child.getPositioning();
480 this.addCall(child.setAbsolutePositioned, null, child);
481 anchor = anchor.toLowerCase();
482 switch(anchor){
483 case 't':
484 case 'top':
485 this.addCall(child.setStyle, ['right', ''], child);
486 this.addCall(child.setStyle, ['top', ''], child);
487 this.addCall(child.setStyle, ['left', '0px'], child);
488 this.addCall(child.setStyle, ['bottom', '0px'], child);
489 this.setSize(size.width, 1, true, duration || .5, null, easing || YAHOO.util.Easing.easeIn);
490 this.setVisible(false);
491 break;
492 case 'l':
493 case 'left':
494 this.addCall(child.setStyle, ['left', ''], child);
495 this.addCall(child.setStyle, ['bottom', ''], child);
496 this.addCall(child.setStyle, ['right', '0px'], child);
497 this.addCall(child.setStyle, ['top', '0px'], child);
498 this.setSize(1, size.height, true, duration || .5, null, easing || YAHOO.util.Easing.easeIn);
499 this.setVisible(false);
500 break;
501 case 'r':
502 case 'right':
503 this.addCall(child.setStyle, ['right', ''], child);
504 this.addCall(child.setStyle, ['bottom', ''], child);
505 this.addCall(child.setStyle, ['left', '0px'], child);
506 this.addCall(child.setStyle, ['top', '0px'], child);
507 this.setSize(1, size.height, true, duration || .5, null, easing || YAHOO.util.Easing.easeIn);
508 this.setVisible(false);
509 break;
510 case 'b':
511 case 'bottom':
512 this.addCall(child.setStyle, ['right', ''], child);
513 this.addCall(child.setStyle, ['top', '0px'], child);
514 this.addCall(child.setStyle, ['left', '0px'], child);
515 this.addCall(child.setStyle, ['bottom', ''], child);
516 this.setSize(size.width, 1, true, duration || .5, null, easing || YAHOO.util.Easing.easeIn);
517 this.setVisible(false);
518 break;
519 }
520 this.addCall(child.setPositioning, [pos], child);
521 return size;
522};
523
524/**
525* Hide the element by "squishing" it into the corner
526* @param {<i>Float</i>} duration (optional) How long the effect lasts (in seconds)
527*/
528YAHOO.ext.Actor.prototype.squish = function(duration){
529 var size = this.getSize();
530 this.clip();
531 this.setSize(1, 1, true, duration || .5);
532 this.setVisible(false);
533 return size;
534};
535
536/**
537* Fade an element in
538* @param {<i>Float</i>} duration (optional) How long the effect lasts (in seconds)
539*/
540YAHOO.ext.Actor.prototype.appear = function(duration){
541 this.setVisible(true, true, duration);
542};
543
544/**
545* Fade an element out
546* @param {<i>Float</i>} duration (optional) How long the effect lasts (in seconds)
547*/
548YAHOO.ext.Actor.prototype.fade = function(duration){
549 this.setVisible(false, true, duration);
550};
551
552/**
553* Blink the element as if it was clicked and then collapse on it's center
554* @param {<i>Float</i>} duration (optional) How long the effect lasts (in seconds)
555*/
556YAHOO.ext.Actor.prototype.switchOff = function(duration){
557 this.clip();
558 this.setVisible(false, true, .1);
559 this.clearOpacity();
560 this.setVisible(true);
561 this.animate({height: {to: 1}, points: {by: [0, this.getHeight()/2]}},
562 duration || .5, null, YAHOO.util.Easing.easeOut, YAHOO.util.Motion);
563 this.setVisible(false);
564};
565
566/**
567* Highlight the element using a background color (or passed attribute) animation
568* @param {String} color (optional) The color to use for the highlight
569* @param {<i>String</i>} fromColor (optional) If the element does not currently have a background color, you will need to pass in a color to animate from
570* @param {<i>Float</i>} duration (optional) How long the effect lasts (in seconds)
571* @param {<i>String</i>} attribute (optional) Specify a CSS attribute to use other than background color - camelCase
572*/
573YAHOO.ext.Actor.prototype.highlight = function(color, fromColor, duration, attribute){
574 attribute = attribute || 'background-color';
575 var original = this.getStyle(attribute);
576 fromColor = fromColor || ((original && original != '' && original != 'transparent') ? original : '#FFFFFF');
577 var cfg = {};
578 cfg[attribute] = {to: color, from: fromColor};
579 this.setVisible(true);
580 this.animate(cfg, duration || .5, null, YAHOO.util.Easing.bounceOut, YAHOO.util.ColorAnim);
581 this.setStyle(attribute, original);
582};
583
584/**
585* Fade the element in and out the specified amount of times
586* @param {<i>Number</i>} count (optional) How many times to pulse (Defaults to 3)
587* @param {<i>Float</i>} duration (optional) How long the effect lasts (in seconds)
588*/
589YAHOO.ext.Actor.prototype.pulsate = function(count, duration){
590 count = count || 3;
591 for(var i = 0; i < count; i++){
592 this.toggle(true, duration || .25);
593 this.toggle(true, duration || .25);
594 }
595};
596
597/**
598* Fade the element as it is falling from it's current position
599* @param {<i>Float</i>} duration (optional) How long the effect lasts (in seconds)
600*/
601YAHOO.ext.Actor.prototype.dropOut = function(duration){
602 this.animate({opacity: {to: 0}, points: {by: [0, this.getHeight()]}},
603 duration || .5, null, YAHOO.util.Easing.easeIn, YAHOO.util.Motion);
604 this.setVisible(false);
605};
606
607/**
608* Hide the element in a way that it appears as if it is flying off the screen
609* @param {String} anchor The part of the page that the element should appear to move to.
610 The short/long options are t/top, l/left, b/bottom, r/right, tl/top-left,
611 tr/top-right, bl/bottom-left or br/bottom-right.
612* @param {<i>Float</i>} duration (optional) How long the effect lasts (in seconds)
613* @param {<i>Function</i>} easing (optional) YAHOO.util.Easing method to use. (Defaults to YAHOO.util.Easing.easeIn)
614*/
615YAHOO.ext.Actor.prototype.moveOut = function(anchor, duration, easing){
616 var Y = YAHOO.util;
617 var vw = Y.Dom.getViewportWidth();
618 var vh = Y.Dom.getViewportHeight();
619 var cpoints = this.getCenterXY()
620 var centerX = cpoints[0];
621 var centerY = cpoints[1];
622 var anchor = anchor.toLowerCase();
623 var p;
624 switch(anchor){
625 case 't':
626 case 'top':
627 p = [centerX, -this.getHeight()];
628 break;
629 case 'l':
630 case 'left':
631 p = [-this.getWidth(), centerY];
632 break;
633 case 'r':
634 case 'right':
635 p = [vw+this.getWidth(), centerY];
636 break;
637 case 'b':
638 case 'bottom':
639 p = [centerX, vh+this.getHeight()];
640 break;
641 case 'tl':
642 case 'top-left':
643 p = [-this.getWidth(), -this.getHeight()];
644 break;
645 case 'bl':
646 case 'bottom-left':
647 p = [-this.getWidth(), vh+this.getHeight()];
648 break;
649 case 'br':
650 case 'bottom-right':
651 p = [vw+this.getWidth(), vh+this.getHeight()];
652 break;
653 case 'tr':
654 case 'top-right':
655 p = [vw+this.getWidth(), -this.getHeight()];
656 break;
657 }
658 this.moveTo(p[0], p[1], true, duration || .35, null, easing || Y.Easing.easeIn);
659 this.setVisible(false);
660};
661
662/**
663* Show the element in a way that it appears as if it is flying onto the screen
664* @param {String} anchor The part of the page that the element should appear to move from.
665 The short/long options are t/top, l/left, b/bottom, r/right, tl/top-left,
666 tr/top-right, bl/bottom-left or br/bottom-right.
667* @param {<i>Array</i>} to (optional) Array of x and y position to move to like [x, y] (Defaults to center screen)
668* @param {<i>Float</i>} duration (optional) How long the effect lasts (in seconds)
669* @param {<i>Function</i>} easing (optional) YAHOO.util.Easing method to use. (Defaults to YAHOO.util.Easing.easeOut)
670*/
671YAHOO.ext.Actor.prototype.moveIn = function(anchor, to, duration, easing){
672 to = to || this.getCenterXY();
673 this.moveOut(anchor, .01);
674 this.setVisible(true);
675 this.setXY(to, true, duration || .35, null, easing || YAHOO.util.Easing.easeOut);
676};
677/**
678* Show a ripple of exploding, attenuating borders to draw attention to an Element.
679* @param {<i>Number<i>} color (optional) The color of the border.
680* @param {<i>Number</i>} count (optional) How many ripples.
681* @param {<i>Float</i>} duration (optional) How long each ripple takes to expire
682*/
683YAHOO.ext.Actor.prototype.frame = function(color, count, duration){
684 color = color || "red";
685 count = count || 3;
686 duration = duration || .5;
687 var frameFn = function(callback){
688 var box = this.getBox();
689 var animFn = function(){
690 var proxy = this.createProxy({
691 tag:"div",
692 style:{
693 visbility:"hidden",
694 position:"absolute",
695 'z-index':"35000", // yee haw
696 border:"0px solid " + color
697 }
698 });
699 var scale = proxy.isBorderBox() ? 2 : 1;
700 proxy.animate({
701 top:{from:box.y, to:box.y - 20},
702 left:{from:box.x, to:box.x - 20},
703 borderWidth:{from:0, to:10},
704 opacity:{from:1, to:0},
705 height:{from:box.height, to:(box.height + (20*scale))},
706 width:{from:box.width, to:(box.width + (20*scale))}
707 }, duration, function(){
708 proxy.remove();
709 });
710 if(--count > 0){
711 animFn.defer((duration/2)*1000, this);
712 }else{
713 if(typeof callback == 'function'){
714 callback();
715 }
716 }
717 }
718 animFn.call(this);
719 }
720 this.addAsyncCall(frameFn, 0, null, this);
721};
722
723YAHOO.ext.Actor.Action = function(actor, method, args){
724 this.actor = actor;
725 this.method = method;
726 this.args = args;
727 }
728
729YAHOO.ext.Actor.Action.prototype = {
730 play : function(onComplete){
731 this.method.apply(this.actor || window, this.args);
732 onComplete();
733 }
734};
735
736
737YAHOO.ext.Actor.AsyncAction = function(actor, method, args, onIndex){
738 YAHOO.ext.Actor.AsyncAction.superclass.constructor.call(this, actor, method, args);
739 this.onIndex = onIndex;
740 this.originalCallback = this.args[onIndex];
741}
742YAHOO.extendX(YAHOO.ext.Actor.AsyncAction, YAHOO.ext.Actor.Action);
743
744YAHOO.ext.Actor.AsyncAction.prototype.play = function(onComplete){
745 var callbackArg = this.originalCallback ?
746 this.originalCallback.createSequence(onComplete) : onComplete;
747 this.args[this.onIndex] = callbackArg;
748 this.method.apply(this.actor, this.args);
749};
750
751
752YAHOO.ext.Actor.PauseAction = function(seconds){
753 this.seconds = seconds;
754};
755YAHOO.ext.Actor.PauseAction.prototype = {
756 play : function(onComplete){
757 setTimeout(onComplete, this.seconds * 1000);
758 }
759};
diff --git a/frontend/beta/js/YUI-extensions/anim/Animator.js b/frontend/beta/js/YUI-extensions/anim/Animator.js
new file mode 100644
index 0000000..ed250fb
--- a/dev/null
+++ b/frontend/beta/js/YUI-extensions/anim/Animator.js
@@ -0,0 +1,482 @@
1/**
2 * @class YAHOO.ext.Animator
3 * Provides support for syncing animations for multiple {@link YAHOO.ext.Actor}s.<br><br>
4* <br><br>This example can be seen in action <a href="http://www.jackslocum.com/yui/2006/08/19/a-splitbar-component-for-yahoo-ui/" target="_new">here</a>
5* by clicking on "Click here and I will point it out" at the end of the first paragraph.<br>
6 * <pre><code>
7var animator = new YAHOO.ext.Animator();
8var cursor = new YAHOO.ext.Actor('cursor-img', animator);
9var click = new YAHOO.ext.Actor('click-img', animator);
10var resize = new YAHOO.ext.Actor('resize-img', animator);
11
12// start capturing
13animator.startCapture();
14
15// these animations will be run in sequence
16cursor.show();
17cursor.moveTo(500,400);
18cursor.moveTo(20, getEl('navbar').getY()+10, true, .75);
19click.show();
20click.alignTo(cursor, 'tl', [-4, -4]);
21
22// Add an async function call, pass callback to argument 1
23animator.addAsyncCall(Blog.navbar.undockDelegate, 1);
24
25// pause .5 seconds
26animator.pause(.5);
27
28// again, these animations will be run in sequence
29click.hide(true, .7);
30cursor.alignTo('splitter', 'tr', [0, +100], true, 1);
31resize.alignTo('splitter', 'tr', [-12, +100]);
32
33// start sync block: these animations will run at the same time
34animator.beginSync();
35cursor.hide();
36resize.show();
37animator.endSync();
38
39// play the captured animation sequences, call myCallback when done
40animator.play(myCallback);
41 * </code></pre>
42 * @requires YAHOO.ext.Element
43 * @requires YAHOO.util.Dom
44 * @requires YAHOO.util.Event
45 * @requires YAHOO.util.CustomEvent
46 * @requires YAHOO.util.Anim
47 * @requires YAHOO.util.ColorAnim
48 * @requires YAHOO.util.Motion
49 * @constructor
50 * @param {String/HTMLElement} el The dom element or element id
51 * @param {<i>YAHOO.ext.Animator</i>} animator (optional) The Animator that will capture this Actor's actions
52 * @param {<i>Boolean</i>} selfCapture (optional) Whether this actor should capture it's own actions to support self playback without an animator (defaults to false)
53 */
54 YAHOO.ext.Animator = function(/*Actors...*/){
55 this.actors = [];
56 this.playlist = new YAHOO.ext.Animator.AnimSequence();
57 this.captureDelegate = this.capture.createDelegate(this);
58 this.playDelegate = this.play.createDelegate(this);
59 this.syncing = false;
60 this.stopping = false;
61 this.playing = false;
62 for(var i = 0; i < arguments.length; i++){
63 this.addActor(arguments[i]);
64 }
65 };
66
67 YAHOO.ext.Animator.prototype = {
68
69 capture : function(actor, action){
70 if(this.syncing){
71 if(!this.syncMap[actor.id]){
72 this.syncMap[actor.id] = new YAHOO.ext.Animator.AnimSequence();
73 }
74 this.syncMap[actor.id].add(action);
75 }else{
76 this.playlist.add(action);
77 }
78 },
79
80 /**
81 * Add an actor. The actor is also set to capturing = true.
82 * @param {YAHOO.ext.Actor} actor
83 */
84 addActor : function(actor){
85 actor.onCapture.subscribe(this.captureDelegate);
86 this.actors.push(actor);
87 },
88
89
90 /**
91 * Start capturing actions on the added actors.
92 * @param {<i>Boolean</i>} clearPlaylist Whether to also create a new playlist
93 */
94 startCapture : function(clearPlaylist){
95 for(var i = 0; i < this.actors.length; i++){
96 var a = this.actors[i];
97 if(!this.isCapturing(a)){
98 a.onCapture.subscribe(this.captureDelegate);
99 }
100 a.capturing = true;
101 }
102 if(clearPlaylist){
103 this.playlist = new YAHOO.ext.Animator.AnimSequence();
104 }
105 },
106
107 /**
108 * Checks whether this animator is listening to a specific actor.
109 * @param {YAHOO.ext.Actor} actor
110 */
111 isCapturing : function(actor){
112 var subscribers = actor.onCapture.subscribers;
113 if(subscribers){
114 for(var i = 0; i < subscribers.length; i++){
115 if(subscribers[i] && subscribers[i].contains(this.captureDelegate)){
116 return true;
117 }
118 }
119 }
120 return false;
121 },
122
123 /**
124 * Stop capturing on all added actors.
125 */
126 stopCapture : function(){
127 for(var i = 0; i < this.actors.length; i++){
128 var a = this.actors[i];
129 a.onCapture.unsubscribe(this.captureDelegate);
130 a.capturing = false;
131 }
132 },
133
134 /**
135 * Start a multi-actor sync block. By default all animations are run in sequence. While in the sync block
136 * each actor's own animations will still be sequenced, but all actors will animate at the same time.
137 */
138 beginSync : function(){
139 this.syncing = true;
140 this.syncMap = {};
141 },
142
143 /**
144 * End the multi-actor sync block
145 */
146 endSync : function(){
147 this.syncing = false;
148 var composite = new YAHOO.ext.Animator.CompositeSequence();
149 for(key in this.syncMap){
150 if(typeof this.syncMap[key] != 'function'){
151 composite.add(this.syncMap[key]);
152 }
153 }
154 this.playlist.add(composite);
155 this.syncMap = null;
156 },
157
158 /**
159 * Starts playback of the playlist, also stops any capturing. To start capturing again call {@link #startCapture}.
160 * @param {<i>Function</i>} oncomplete (optional) Callback to execute when playback has completed
161 */
162 play : function(oncomplete){
163 if(this.playing) return; // can't play the same animation twice at once
164 this.stopCapture();
165 this.playlist.play(oncomplete);
166 },
167
168 /**
169 * Stop at the next available stopping point
170 */
171 stop : function(){
172 this.playlist.stop();
173 },
174
175 /**
176 * Check if this animator is currently playing
177 */
178 isPlaying : function(){
179 return this.playlist.isPlaying();
180 },
181 /**
182 * Clear the playlist
183 */
184 clear : function(){
185 this.playlist = new YAHOO.ext.Animator.AnimSequence();
186 },
187
188 /**
189 * Add a function call to the playlist.
190 * @param {Function} fcn The function to call
191 * @param {<i>Array</i>} args The arguments to call the function with
192 * @param {<i>Object</i>} scope (optional) The scope of the function
193 */
194 addCall : function(fcn, args, scope){
195 this.playlist.add(new YAHOO.ext.Actor.Action(scope, fcn, args || []));
196 },
197
198 /**
199 * Add an async function call to the playlist.
200 * @param {Function} fcn The function to call
201 * @param {Number} callbackIndex The index of the callback parameter on the passed function. A CALLBACK IS REQUIRED.
202 * @param {<i>Array</i>} args The arguments to call the function with
203 * @param {<i>Object</i>} scope (optional) The scope of the function
204 */
205 addAsyncCall : function(fcn, callbackIndex, args, scope){
206 this.playlist.add(new YAHOO.ext.Actor.AsyncAction(scope, fcn, args || [], callbackIndex));
207 },
208
209 /**
210 * Add a pause to the playlist (in seconds)
211 * @param {Number} seconds The number of seconds to pause.
212 */
213 pause : function(seconds){
214 this.playlist.add(new YAHOO.ext.Actor.PauseAction(seconds));
215 }
216
217 };
218/**
219 * Static function to build a AnimatorComposite from a css selector (requires YAHOO.ext.Element.selectorFunction be defined)
220 * @param {String/Array} selector The css selector or an array of nodes to animate
221 * @method @static
222 */
223YAHOO.ext.Animator.select = function(selector){
224 var els;
225 if(typeof selector == 'string'){
226 els = YAHOO.ext.Element.selectorFunction(selector);
227 }else if(selector instanceof Array){
228 els = selector;
229 }else{
230 throw 'Invalid selector';
231 }
232 return new YAHOO.ext.AnimatorComposite(els);
233};
234var getActors = YAHOO.ext.Animator.select;
235
236/**
237 * @class YAHOO.ext.AnimatorComposite
238 * Composite class with synchronized animations. This is the class returned by getActors(selector) or YAHOO.ext.Animator.select().
239 */
240YAHOO.ext.AnimatorComposite = function(els){
241 this.animator = new YAHOO.ext.Animator();
242 this.addElements(els);
243 this.syncAnims = true;
244};
245YAHOO.ext.AnimatorComposite.prototype = {
246 isComposite: true,
247 /**
248 * Adds elements to this composite.
249 * @param {Array} els An array of elements to add
250 * @return {AnimatorComposite} this
251 */
252 addElements : function(els){
253 if(!els) return this;
254 var anim = this.animator;
255 for(var i = 0, len = els.length; i < len; i++) {
256 anim.addActor(new YAHOO.ext.Actor(els[i]));
257 }
258 anim.startCapture();
259 return this;
260 },
261 /**
262 * Operations called after sequence() will be performed one by one on each element in this composite.
263 * @return {AnimatorComposite} this
264 */
265 sequence : function(){
266 this.syncAnims = false;
267 return this;
268 },
269 /**
270 * Operations called after sync() will be performed at the same time on each element in this composite.
271 * @return {AnimatorComposite} this
272 */
273 sync : function(){
274 this.syncAnims = true;
275 return this;
276 },
277 invoke : function(fn, args){
278 var els = this.animator.actors;
279 if(this.syncAnims) this.animator.beginSync();
280 for(var i = 0, len = els.length; i < len; i++) {
281 YAHOO.ext.Actor.prototype[fn].apply(els[i], args);
282 }
283 if(this.syncAnims) this.animator.endSync();
284 return this;
285 },
286 /**
287 * Play the actions queued in this composite.
288 * @param {Function} callback (optional) callback is called when all animations have compelted
289 * @return {AnimatorComposite} this
290 */
291 play : function(callback){
292 this.animator.play(callback);
293 return this;
294 },
295 /**
296 * Clear all actions in the queue.
297 * @param {Function} callback (optional) callback is called when all animations have compelted
298 * @return {AnimatorComposite} this
299 */
300 reset : function(callback){
301 this.animator.startCapture(true);
302 return this;
303 },
304 /**
305 * Add a pause
306 * @param {Number} seconds
307 * @return {AnimatorComposite} this
308 */
309 pause : function(seconds){
310 this.animator.pause(seconds);
311 return this;
312 },
313 /**
314 * Get the YAHOO.ext.Animator that controls the animations for this composite.
315 * @return {YAHOO.ext.Animator}
316 */
317 getAnimator : function(){
318 return this.animator;
319 },
320 /**
321 * Calls the passed function passing (el, this, index) for each element in this composite.
322 * @param {Function} fn The function to call
323 * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
324 * @return {AnimatorComposite} this
325 */
326 each : function(fn, scope){
327 var els = this.animator.actors;
328 if(this.syncAnims) this.animator.beginSync();
329 for(var i = 0, len = els.length; i < len; i++){
330 fn.call(scope || els[i], els[i], this, i);
331 }
332 if(this.syncAnims) this.animator.endSync();
333 return this;
334 },
335 /**
336 * Add a function call to the playlist.
337 * @param {Function} fcn The function to call
338 * @param {<i>Array</i>} args (optional) The arguments to call the function with
339 * @param {<i>Object</i>} scope (optional) The scope of the function
340 * @return {AnimatorComposite} this
341 */
342 addCall : function(fcn, args, scope){
343 this.animator.addCall(fcn, args, scope);
344 return this;
345 },
346 /**
347 * Add an async function call to the playlist.
348 * @param {Function} fcn The function to call
349 * @param {Number} callbackIndex The index of the callback parameter on the passed function. <b>A CALLBACK IS REQUIRED</b>.
350 * @param {<i>Array</i>} args (optional) The arguments to call the function with
351 * @param {<i>Object</i>} scope (optional) The scope of the function
352 * @return {AnimatorComposite} this
353 */
354 addAsyncCall : function(fcn, callbackIndex, args, scope){
355 this.animator.addAsyncCall(fcn, callbackIndex, args, scope);
356 return this;
357 }
358};
359for(var fnName in YAHOO.ext.Actor.prototype){
360 if(typeof YAHOO.ext.Actor.prototype[fnName] == 'function'){
361 YAHOO.ext.CompositeElement.createCall(YAHOO.ext.AnimatorComposite.prototype, fnName);
362 }
363}
364
365
366YAHOO.ext.Animator.AnimSequence = function(){
367 this.actions = [];
368 this.nextDelegate = this.next.createDelegate(this);
369 this.playDelegate = this.play.createDelegate(this);
370 this.oncomplete = null;
371 this.playing = false;
372 this.stopping = false;
373 this.actionIndex = -1;
374 };
375
376 YAHOO.ext.Animator.AnimSequence.prototype = {
377
378 add : function(action){
379 this.actions.push(action);
380 },
381
382 next : function(){
383 if(this.stopping){
384 this.playing = false;
385 if(this.oncomplete){
386 this.oncomplete(this, false);
387 }
388 return;
389 }
390 var nextAction = this.actions[++this.actionIndex];
391 if(nextAction){
392 nextAction.play(this.nextDelegate);
393 }else{
394 this.playing = false;
395 if(this.oncomplete){
396 this.oncomplete(this, true);
397 }
398 }
399 },
400
401 play : function(oncomplete){
402 if(this.playing) return; // can't play the same sequence twice at once
403 this.oncomplete = oncomplete;
404 this.stopping = false;
405 this.playing = true;
406 this.actionIndex = -1;
407 this.next();
408 },
409
410 stop : function(){
411 this.stopping = true;
412 },
413
414 isPlaying : function(){
415 return this.playing;
416 },
417
418 clear : function(){
419 this.actions = [];
420 },
421
422 addCall : function(fcn, args, scope){
423 this.actions.push(new YAHOO.ext.Actor.Action(scope, fcn, args || []));
424 },
425
426 addAsyncCall : function(fcn, callbackIndex, args, scope){
427 this.actions.push(new YAHOO.ext.Actor.AsyncAction(scope, fcn, args || [], callbackIndex));
428 },
429
430 pause : function(seconds){
431 this.actions.push(new YAHOO.ext.Actor.PauseAction(seconds));
432 }
433
434 };
435
436YAHOO.ext.Animator.CompositeSequence = function(){
437 this.sequences = [];
438 this.completed = 0;
439 this.trackDelegate = this.trackCompletion.createDelegate(this);
440}
441
442YAHOO.ext.Animator.CompositeSequence.prototype = {
443 add : function(sequence){
444 this.sequences.push(sequence);
445 },
446
447 play : function(onComplete){
448 this.completed = 0;
449 if(this.sequences.length < 1){
450 if(onComplete)onComplete();
451 return;
452 }
453 this.onComplete = onComplete;
454 for(var i = 0; i < this.sequences.length; i++){
455 this.sequences[i].play(this.trackDelegate);
456 }
457 },
458
459 trackCompletion : function(){
460 ++this.completed;
461 if(this.completed >= this.sequences.length && this.onComplete){
462 this.onComplete();
463 }
464 },
465
466 stop : function(){
467 for(var i = 0; i < this.sequences.length; i++){
468 this.sequences[i].stop();
469 }
470 },
471
472 isPlaying : function(){
473 for(var i = 0; i < this.sequences.length; i++){
474 if(this.sequences[i].isPlaying()){
475 return true;
476 }
477 }
478 return false;
479 }
480};
481
482
diff --git a/frontend/beta/js/YUI-extensions/data/AbstractDataModel.js b/frontend/beta/js/YUI-extensions/data/AbstractDataModel.js
new file mode 100644
index 0000000..092ea75
--- a/dev/null
+++ b/frontend/beta/js/YUI-extensions/data/AbstractDataModel.js
@@ -0,0 +1,226 @@
1/**
2 * @class YAHOO.ext.grid.AbstractDataModel
3 * @extends YAHOO.ext.util.Observable
4 * This abstract class provides default implementations of the events required by the Grid.
5 It takes care of the creating the CustomEvents and provides some convenient methods for firing the events. <br><br>
6 * @constructor
7*/
8YAHOO.ext.grid.AbstractDataModel = function(){
9 /** Fires when a cell is updated - fireDirect sig: (this, rowIndex, columnIndex)
10 * @private
11 * @type YAHOO.util.CustomEvent
12 * @deprecated Use addListener instead of accessing directly
13 */
14 this.onCellUpdated = new YAHOO.util.CustomEvent('onCellUpdated');
15 /** Fires when all data needs to be revalidated - fireDirect sig: (thisd)
16 * @private
17 * @type YAHOO.util.CustomEvent
18 * @deprecated Use addListener instead of accessing directly
19 */
20 this.onTableDataChanged = new YAHOO.util.CustomEvent('onTableDataChanged');
21 /** Fires when rows are deleted - fireDirect sig: (this, firstRowIndex, lastRowIndex)
22 * @private
23 * @type YAHOO.util.CustomEvent
24 * @deprecated Use addListener instead of accessing directly
25 */
26 this.onRowsDeleted = new YAHOO.util.CustomEvent('onRowsDeleted');
27 /** Fires when a rows are inserted - fireDirect sig: (this, firstRowIndex, lastRowIndex)
28 * @private
29 * @type YAHOO.util.CustomEvent
30 * @deprecated Use addListener instead of accessing directly
31 */
32 this.onRowsInserted = new YAHOO.util.CustomEvent('onRowsInserted');
33 /** Fires when a rows are updated - fireDirect sig: (this, firstRowIndex, lastRowIndex)
34 * @private
35 * @type YAHOO.util.CustomEvent
36 * @deprecated Use addListener instead of accessing directly
37 */
38 this.onRowsUpdated = new YAHOO.util.CustomEvent('onRowsUpdated');
39 /** Fires when a sort has reordered the rows - fireDirect sig: (this, sortColumnIndex,
40 * @private
41 * sortDirection = 'ASC' or 'DESC')
42 * @type YAHOO.util.CustomEvent
43 * @deprecated Use addListener instead of accessing directly
44 */
45 this.onRowsSorted = new YAHOO.util.CustomEvent('onRowsSorted');
46
47 this.events = {
48 /**
49 * @event cellupdated
50 * Fires when a cell is updated
51 * @param {DataModel} this
52 * @param {Number} rowIndex
53 * @param {Number} columnIndex
54 */
55 'cellupdated' : this.onCellUpdated,
56 /**
57 * @event datachanged
58 * Fires when the entire data structure has changed
59 * @param {DataModel} this
60 */
61 'datachanged' : this.onTableDataChanged,
62 /**
63 * @event rowsdeleted
64 * Fires when a range of rows have been deleted
65 * @param {DataModel} this
66 * @param {Number} firstRowIndex
67 * @param {Number} lastRowIndex
68 */
69 'rowsdeleted' : this.onRowsDeleted,
70 /**
71 * @event rowsinserted
72 * Fires when a range of rows have been inserted
73 * @param {DataModel} this
74 * @param {Number} firstRowIndex
75 * @param {Number} lastRowIndex
76 */
77 'rowsinserted' : this.onRowsInserted,
78 /**
79 * @event rowsupdated
80 * Fires when a range of rows have been updated
81 * @param {DataModel} this
82 * @param {Number} firstRowIndex
83 * @param {Number} lastRowIndex
84 */
85 'rowsupdated' : this.onRowsUpdated,
86 /**
87 * @event rowssorted
88 * Fires when the data has been sorted
89 * @param {DataModel} this
90 */
91 'rowssorted' : this.onRowsSorted
92 };
93};
94
95YAHOO.ext.grid.AbstractDataModel.prototype = {
96
97 fireEvent : YAHOO.ext.util.Observable.prototype.fireEvent,
98 on : YAHOO.ext.util.Observable.prototype.on,
99 addListener : YAHOO.ext.util.Observable.prototype.addListener,
100 delayedListener : YAHOO.ext.util.Observable.prototype.delayedListener,
101 removeListener : YAHOO.ext.util.Observable.prototype.removeListener,
102 purgeListeners : YAHOO.ext.util.Observable.prototype.purgeListeners,
103 bufferedListener : YAHOO.ext.util.Observable.prototype.bufferedListener,
104
105 /**
106 * Notifies listeners that the value of the cell at [row, col] has been updated
107 * @deprecated
108 * @private
109 */
110 fireCellUpdated : function(row, col){
111 this.onCellUpdated.fireDirect(this, row, col);
112 },
113
114 /**
115 * Notifies listeners that all data for the grid may have changed - use as a last resort. This
116 * also wipes out all selections a user might have made.
117 * @deprecated
118 * @private
119 */
120 fireTableDataChanged : function(){
121 this.onTableDataChanged.fireDirect(this);
122 },
123
124 /**
125 * Notifies listeners that rows in the range [firstRow, lastRow], inclusive, have been deleted
126 * @deprecated
127 * @private
128 */
129 fireRowsDeleted : function(firstRow, lastRow){
130 this.onRowsDeleted.fireDirect(this, firstRow, lastRow);
131 },
132
133 /**
134 * Notifies listeners that rows in the range [firstRow, lastRow], inclusive, have been inserted
135 * @deprecated
136 * @private
137 */
138 fireRowsInserted : function(firstRow, lastRow){
139 this.onRowsInserted.fireDirect(this, firstRow, lastRow);
140 },
141
142 /**
143 * Notifies listeners that rows in the range [firstRow, lastRow], inclusive, have been updated
144 * @deprecated
145 * @private
146 */
147 fireRowsUpdated : function(firstRow, lastRow){
148 this.onRowsUpdated.fireDirect(this, firstRow, lastRow);
149 },
150
151 /**
152 * Notifies listeners that rows have been sorted and any indexes may be invalid
153 * @deprecated
154 * @private
155 */
156 fireRowsSorted : function(sortColumnIndex, sortDir, noRefresh){
157 this.onRowsSorted.fireDirect(this, sortColumnIndex, sortDir, noRefresh);
158 },
159
160 /**
161 * Empty interface method - Classes which extend AbstractDataModel should implement this method.
162 * See {@link YAHOO.ext.DefaultDataModel#sort} for an example implementation.
163 * @private
164 */
165 sort : function(sortInfo, columnIndex, direction, suppressEvent){
166
167 },
168
169 /**
170 * Interface method to supply info regarding the Grid's current sort state - if overridden,
171 * this should return an object like this {column: this.sortColumn, direction: this.sortDir}.
172 * @return {Object}
173 */
174 getSortState : function(){
175 return {column: this.sortColumn, direction: this.sortDir};
176 },
177
178 /**
179 * Empty interface method - Classes which extend AbstractDataModel should implement this method.
180 * See {@link YAHOO.ext.DefaultDataModel} for an example implementation.
181 * @private
182 */
183 getRowCount : function(){
184
185 },
186
187 /**
188 * Empty interface method - Classes which extend AbstractDataModel should implement this method to support virtual row counts.
189 * @private
190 */
191 getTotalRowCount : function(){
192 return this.getRowCount();
193 },
194
195
196 /**
197 * Empty interface method - Classes which extend AbstractDataModel should implement this method.
198 * See {@link YAHOO.ext.DefaultDataModel} for an example implementation.
199 * @private
200 */
201 getRowId : function(rowIndex){
202
203 },
204
205 /**
206 * Empty interface method - Classes which extend AbstractDataModel should implement this method.
207 * See {@link YAHOO.ext.DefaultDataModel} for an example implementation.
208 * @private
209 */
210 getValueAt : function(rowIndex, colIndex){
211
212 },
213
214 /**
215 * Empty interface method - Classes which extend AbstractDataModel should implement this method.
216 * See {@link YAHOO.ext.DefaultDataModel} for an example implementation.
217 * @private
218 */
219 setValueAt : function(value, rowIndex, colIndex){
220
221 },
222
223 isPaged : function(){
224 return false;
225 }
226};
diff --git a/frontend/beta/js/YUI-extensions/data/DefaultDataModel.js b/frontend/beta/js/YUI-extensions/data/DefaultDataModel.js
new file mode 100644
index 0000000..57a022a
--- a/dev/null
+++ b/frontend/beta/js/YUI-extensions/data/DefaultDataModel.js
@@ -0,0 +1,339 @@
1
2/**
3 * @class YAHOO.ext.grid.DefaultDataModel
4 * This is the default implementation of a DataModel used by the Grid. It works
5 * with multi-dimensional array based data. Using the event system in the base class
6 * {@link YAHOO.ext.grid.AbstractDataModel}, all updates to this DataModel are automatically
7 * reflected in the user interface.
8 * <br>Usage:<br>
9 * <pre><code>
10 * var myData = [
11 ["MSFT","Microsoft Corporation", "314,571.156", "32,187.000", "55000"],
12 ["ORCL", "Oracle Corporation", "62,615.266", "9,519.000", "40650"]
13 * ];
14 * var dataModel = new YAHOO.ext.grid.DefaultDataModel(myData);
15 * </code></pre>
16 * @extends YAHOO.ext.grid.AbstractDataModel
17 * @constructor
18 * @param {Array} data
19*/
20YAHOO.ext.grid.DefaultDataModel = function(data){
21 YAHOO.ext.grid.DefaultDataModel.superclass.constructor.call(this);
22 /**@private*/
23 this.data = data;
24};
25YAHOO.extendX(YAHOO.ext.grid.DefaultDataModel, YAHOO.ext.grid.AbstractDataModel, {
26 /**
27 * Returns the number of rows in the dataset
28 * @return {Number}
29 */
30 getRowCount : function(){
31 return this.data.length;
32 },
33
34 /**
35 * Returns the ID of the specified row. By default it return the value of the first column.
36 * Override to provide more advanced ID handling.
37 * @return {Number}
38 */
39 getRowId : function(rowIndex){
40 return this.data[rowIndex][0];
41 },
42
43 /**
44 * Returns the column data for the specified row.
45 * @return {Array}
46 */
47 getRow : function(rowIndex){
48 return this.data[rowIndex];
49 },
50
51 /**
52 * Returns the column data for the specified rows as a
53 * multi-dimensional array: rows[3][0] would give you the value of row 4, column 0.
54 * @param {Array} indexes The row indexes to fetch
55 * @return {Array}
56 */
57 getRows : function(indexes){
58 var data = this.data;
59 var r = [];
60 for(var i = 0; i < indexes.length; i++){
61 r.push(data[indexes[i]]);
62 }
63 return r;
64 },
65
66 /**
67 * Returns the value at the specified data position
68 * @param {Number} rowIndex
69 * @param {Number} colIndex
70 * @return {Object}
71 */
72 getValueAt : function(rowIndex, colIndex){
73 return this.data[rowIndex][colIndex];
74 },
75
76 /**
77 * Sets the specified value at the specified data position
78 * @param {Object} value The new value
79 * @param {Number} rowIndex
80 * @param {Number} colIndex
81 */
82 setValueAt: function(value, rowIndex, colIndex){
83 this.data[rowIndex][colIndex] = value;
84 this.fireCellUpdated(rowIndex, colIndex);
85 },
86
87 /**
88 * @private
89 * Removes the specified range of rows.
90 * @param {Number} startIndex
91 * @param {<i>Number</i>} endIndex (optional) Defaults to startIndex
92 */
93 removeRows: function(startIndex, endIndex){
94 endIndex = endIndex || startIndex;
95 this.data.splice(startIndex, endIndex-startIndex+1);
96 this.fireRowsDeleted(startIndex, endIndex);
97 },
98
99 /**
100 * Remove a row.
101 * @param {Number} index
102 */
103 removeRow: function(index){
104 this.data.splice(index, 1);
105 this.fireRowsDeleted(index, index);
106 },
107
108 /**
109 * @private
110 * Removes all rows.
111 */
112 removeAll: function(){
113 var count = this.getRowCount();
114 if(count > 0){
115 this.removeRows(0, count-1);
116 }
117 },
118
119 /**
120 * Query the DataModel rows by the filters defined in spec, for example...
121 * <pre><code>
122 * // column 1 starts with Jack, column 2 filtered by myFcn, column 3 equals 'Fred'
123 * dataModel.filter({1: /^Jack.+/i}, 2: myFcn, 3: 'Fred'});
124 * </code></pre>
125 * @param {Object} spec The spec is generally an object literal consisting of
126 * column index and filter type. The filter type can be a string/number (exact match),
127 * a regular expression to test using String.search() or a function to call. If it's a function,
128 * it will be called with the value for the specified column and an array of the all column
129 * values for that row: yourFcn(value, columnData). If it returns anything other than true,
130 * the row is not a match. If you have modified Object.prototype this method may fail.
131 * @param {Boolean} returnUnmatched True to return rows which <b>don't</b> match the query instead
132 * of rows that do match
133 * @return {Array} An array of row indexes that match
134 */
135 query: function(spec, returnUnmatched){
136 var d = this.data;
137 var r = [];
138 for(var i = 0; i < d.length; i++){
139 var row = d[i];
140 var isMatch = true;
141 for(var col in spec){
142 //if(typeof spec[col] != 'function'){
143 if(!isMatch) continue;
144 var filter = spec[col];
145 switch(typeof filter){
146 case 'string':
147 case 'number':
148 case 'boolean':
149 if(row[col] != filter){
150 isMatch = false;
151 }
152 break;
153 case 'function':
154 if(!filter(row[col], row)){
155 isMatch = false;
156 }
157 break;
158 case 'object':
159 if(filter instanceof RegExp){
160 if(String(row[col]).search(filter) === -1){
161 isMatch = false;
162 }
163 }
164 break;
165 }
166 //}
167 }
168 if(isMatch && !returnUnmatched){
169 r.push(i);
170 }else if(!isMatch && returnUnmatched){
171 r.push(i);
172 }
173 }
174 return r;
175 },
176
177 /**
178 * Filter the DataModel rows by the query defined in spec, see {@link #query} for more details
179 * on the query spec.
180 * @param {Object} query The query spec {@link #query}
181 * @return {Number} The number of rows removed
182 */
183 filter: function(query){
184 var matches = this.query(query, true);
185 var data = this.data;
186 // go thru the data setting matches to deleted
187 // while not disturbing row indexes
188 for(var i = 0; i < matches.length; i++){
189 data[matches[i]]._deleted = true;
190 }
191 for(var i = 0; i < data.length; i++){
192 while(data[i] && data[i]._deleted === true){
193 this.removeRow(i);
194 }
195 }
196 return matches.length;
197 },
198
199 /**
200 * Adds a row to the dataset.
201 * @param {Array} cellValues The array of values for the new row
202 * @return {Number} The index of the added row
203 */
204 addRow: function(cellValues){
205 this.data.push(cellValues);
206 var newIndex = this.data.length-1;
207 this.fireRowsInserted(newIndex, newIndex);
208 this.applySort();
209 return newIndex;
210 },
211
212 /**
213 * @private
214 * Adds a set of rows.
215 * @param {Array} rowData This should be an array of arrays like the constructor takes
216 */
217 addRows: function(rowData){
218 this.data = this.data.concat(rowData);
219 var firstIndex = this.data.length-rowData.length;
220 this.fireRowsInserted(firstIndex, firstIndex+rowData.length-1);
221 this.applySort();
222 },
223
224 /**
225 * Inserts a row a the specified location in the dataset.
226 * @param {Number} index The index where the row should be inserted
227 * @param {Array} cellValues The array of values for the new row
228 * @return {Number} The index the row was inserted in
229 */
230 insertRow: function(index, cellValues){
231 this.data.splice(index, 0, cellValues);
232 this.fireRowsInserted(index, index);
233 this.applySort();
234 return index;
235 },
236
237 /**
238 * @private
239 * Inserts a set of rows.
240 * @param {Number} index The index where the rows should be inserted
241 * @param {Array} rowData This should be an array of arrays like the constructor takes
242 */
243 insertRows: function(index, rowData){
244 /*
245 if(index == this.data.length){ // try these two first since they are faster
246 this.data = this.data.concat(rowData);
247 }else if(index == 0){
248 this.data = rowData.concat(this.data);
249 }else{
250 var newData = this.data.slice(0, index);
251 newData.concat(rowData);
252 newData.concat(this.data.slice(index));
253 this.data = newData;
254 }*/
255 var args = rowData.concat();
256 args.splice(0, 0, index, 0);
257 this.data.splice.apply(this.data, args);
258 this.fireRowsInserted(index, index+rowData.length-1);
259 this.applySort();
260 },
261
262 /**
263 * Applies the last used sort to the current data.
264 */
265 applySort: function(suppressEvent){
266 if(typeof this.sortColumn != 'undefined'){
267 this.sort(this.sortInfo, this.sortColumn, this.sortDir, suppressEvent);
268 }
269 },
270
271 /**
272 * Sets the default sort info. Note: this function does not actually apply the sort.
273 * @param {Function/Object} sortInfo A sort comparison function or null to use the default or A object that has a method getSortType(index) that returns a function like
274 * a grid column model.
275 * @param {Number} columnIndex The column index to sort by
276 * @param {String} direction The direction of the sort ('DESC' or 'ASC')
277 */
278 setDefaultSort: function(sortInfo, columnIndex, direction){
279 this.sortInfo = sortInfo;
280 this.sortColumn = columnIndex;
281 this.sortDir = direction;
282 },
283 /**
284 * Sorts the data by the specified column - Uses the sortType specified for the column in the passed columnModel.
285 * @param {Function/Object} sortInfo A sort comparison function or null to use the default or A object that has a method getSortType(index) that returns a function like
286 * a grid column model.
287 * @param {Number} columnIndex The column index to sort by
288 * @param {String} direction The direction of the sort ('DESC' or 'ASC')
289 */
290 sort: function(sortInfo, columnIndex, direction, suppressEvent){
291 // store these so we can maintain sorting when we load new data
292 this.sortInfo = sortInfo;
293 this.sortColumn = columnIndex;
294 this.sortDir = direction;
295
296 var dsc = (direction && direction.toUpperCase() == 'DESC');
297 var sortType = null;
298 if(sortInfo != null){
299 if(typeof sortInfo == 'function'){
300 sortType = sortInfo;
301 }else if(typeof sortInfo == 'object'){
302 sortType = sortInfo.getSortType(columnIndex);;
303 }
304 }
305 var fn = function(cells, cells2){
306 var v1 = sortType ? sortType(cells[columnIndex], cells) : cells[columnIndex];
307 var v2 = sortType ? sortType(cells2[columnIndex], cells2) : cells2[columnIndex];
308 if(v1 < v2)
309 return dsc ? +1 : -1;
310 if(v1 > v2)
311 return dsc ? -1 : +1;
312 return 0;
313 };
314 this.data.sort(fn);
315 if(!suppressEvent){
316 this.fireRowsSorted(columnIndex, direction);
317 }
318 },
319
320 /**
321 * Calls passed function with each rows data - if the function returns false it stops.
322 * @param {Function} fn
323 * @param {Object} scope (optional)
324 */
325 each: function(fn, scope){
326 var d = this.data;
327 for(var i = 0, len = d.length; i < len; i++){
328 if(fn.call(scope || window, d[i], i) === false) break;
329 }
330 }
331});
332
333/**
334 * Alias to YAHOO.ext.grid.DefaultColumnModel.sortTypes
335 * @static
336 */
337if(YAHOO.ext.grid.DefaultColumnModel){
338 YAHOO.ext.grid.DefaultDataModel.sortTypes = YAHOO.ext.grid.DefaultColumnModel.sortTypes;
339}
diff --git a/frontend/beta/js/YUI-extensions/data/JSONDataModel.js b/frontend/beta/js/YUI-extensions/data/JSONDataModel.js
new file mode 100644
index 0000000..ca48dce
--- a/dev/null
+++ b/frontend/beta/js/YUI-extensions/data/JSONDataModel.js
@@ -0,0 +1,81 @@
1
2/**
3 * @class YAHOO.ext.grid.JSONDataModel
4 * This is an implementation of a DataModel used by the Grid. It works
5 * with JSON data.
6 * <br>Example schema:
7 * <pre><code>
8 * var schema = {
9 * root: 'Results.Result',
10 * id: 'ASIN',
11 * fields: ['Author', 'Title', 'Manufacturer', 'ProductGroup']
12 * };
13 * </code></pre>
14 * @extends YAHOO.ext.grid.LoadableDataModel
15 * @constructor
16*/
17YAHOO.ext.grid.JSONDataModel = function(schema){
18 YAHOO.ext.grid.JSONDataModel.superclass.constructor.call(this, YAHOO.ext.grid.LoadableDataModel.JSON);
19 /**@private*/
20 this.schema = schema;
21};
22YAHOO.extendX(YAHOO.ext.grid.JSONDataModel, YAHOO.ext.grid.LoadableDataModel, {
23 /**
24 * Overrides loadData in LoadableDataModel to process JSON data
25 * @param {Object} data The JSON object to load
26 * @param {Function} callback
27 */
28 loadData : function(data, callback, keepExisting){
29 var idField = this.schema.id;
30 var fields = this.schema.fields;
31 try{
32 if(this.schema.totalProperty){
33 var v = parseInt(eval('data.' + this.schema.totalProperty), 10);
34 if(!isNaN(v)){
35 this.totalCount = v;
36 }
37 }
38 var rowData = [];
39 var root = eval('data.' + this.schema.root);
40 for(var i = 0; i < root.length; i++){
41 var node = root[i];
42 var colData = [];
43 colData.node = node;
44 colData.id = (typeof node[idField] != 'undefined' && node[idField] !== '' ? node[idField] : String(i));
45 for(var j = 0; j < fields.length; j++) {
46 var val = node[fields[j]];
47 if(typeof val == 'undefined'){
48 val = '';
49 }
50 if(this.preprocessors[j]){
51 val = this.preprocessors[j](val);
52 }
53 colData.push(val);
54 }
55 rowData.push(colData);
56 }
57 if(keepExisting !== true){
58 this.removeAll();
59 }
60 this.addRows(rowData);
61 if(typeof callback == 'function'){
62 callback(this, true);
63 }
64 this.fireLoadEvent();
65 }catch(e){
66 this.fireLoadException(e, null);
67 if(typeof callback == 'function'){
68 callback(this, false);
69 }
70 }
71 },
72
73 /**
74 * Overrides getRowId in DefaultDataModel to return the ID value of the specified node.
75 * @param {Number} rowIndex
76 * @return {Number}
77 */
78 getRowId : function(rowIndex){
79 return this.data[rowIndex].id;
80 }
81});
diff --git a/frontend/beta/js/YUI-extensions/data/LoadableDataModel.js b/frontend/beta/js/YUI-extensions/data/LoadableDataModel.js
new file mode 100644
index 0000000..07def44
--- a/dev/null
+++ b/frontend/beta/js/YUI-extensions/data/LoadableDataModel.js
@@ -0,0 +1,330 @@
1/**
2 * @class YAHOO.ext.grid.LoadableDataModel
3 * This class extends DefaultDataModel and adds the core functionality to load data remotely. Generally you will want to use one of it's subclasses.<br><br>
4 * @extends YAHOO.ext.grid.DefaultDataModel
5 * @constructor
6 * @param {String} dataType YAHOO.ext.grid.LoadableDataModel.XML, YAHOO.ext.grid.LoadableDataModel.TEXT or YAHOO.ext.grid.JSON
7*/
8YAHOO.ext.grid.LoadableDataModel = function(dataType){
9 YAHOO.ext.grid.LoadableDataModel.superclass.constructor.call(this, []);
10
11 /** Fires when a successful load is completed - fireDirect sig: (this)
12 * @type YAHOO.util.CustomEvent
13 * @deprecated Use addListener instead of accessing directly
14 * @private
15 */
16 this.onLoad = new YAHOO.util.CustomEvent('load');
17 /** Fires when a load fails - fireDirect sig: (this, errorMsg, responseObj)
18 * @type YAHOO.util.CustomEvent
19 * @deprecated Use addListener instead of accessing directly
20 * @private
21 */
22 this.onLoadException = new YAHOO.util.CustomEvent('loadException');
23 /**
24 * @event load
25 * Fires when new data has successfully been loaded
26 * @param {DataModel} this
27 */
28 this.events['load'] = this.onLoad;
29 /**
30 * @event beforeload
31 * Fires before a load takes place
32 * @param {DataModel} this
33 */
34 this.events['beforeload'] = new YAHOO.util.CustomEvent('beforeload');
35 /**
36 * @event loadexception
37 * Fires when there's an error loading data
38 * @param {DataModel} this
39 * @param {Exception} e The exception object or null
40 * @param {Object} response The Connect response object
41 */
42 this.events['loadexception'] = this.onLoadException;
43
44 /**@private*/
45 this.dataType = dataType;
46 /**@private*/
47 this.preprocessors = [];
48 /**@private*/
49 this.postprocessors = [];
50
51 // paging info
52 /** The active page @type Number*/
53 this.loadedPage = 1;
54 /** True to use remote sorting, initPaging automatically sets this to true @type Boolean */
55 this.remoteSort = false;
56 /** The number of records per page @type Number*/
57 this.pageSize = 0;
58 /** The script/page to call to provide paged/sorted data @type String*/
59 this.pageUrl = null;
60 /** An object of key/value pairs to be passed as parameters
61 * when loading pages/sorting @type Object*/
62 this.baseParams = {};
63 /** Maps named params to url parameters - Override to specify your own param names */
64 this.paramMap = {'page':'page', 'pageSize':'pageSize', 'sortColumn':'sortColumn', 'sortDir':'sortDir'};
65
66};
67YAHOO.extendX(YAHOO.ext.grid.LoadableDataModel, YAHOO.ext.grid.DefaultDataModel, {
68
69 /** @ignore */
70 setLoadedPage: function(pageNum, userCallback){
71 this.loadedPage = pageNum;
72 if(typeof userCallback == 'function'){
73 userCallback();
74 }
75 },
76
77 /** Returns true if this model uses paging @return Boolean */
78 isPaged: function(){
79 return this.pageSize > 0;
80 },
81
82 /** Returns the total number of records available, override if needed @return {Number} */
83 getTotalRowCount: function(){
84 return this.totalCount || this.getRowCount();
85 },
86
87 /** Returns the number of records per page @return Number */
88 getPageSize: function(){
89 return this.pageSize;
90 },
91
92 /** Returns the total number of pages available @return Number */
93 getTotalPages: function(){
94 if(this.getPageSize() == 0 || this.getTotalRowCount() == 0){
95 return 1;
96 }
97 return Math.ceil(this.getTotalRowCount()/this.getPageSize());
98 },
99
100 /** Initializes paging for this model.
101 * @param {String} url
102 * @param {Number} pageSize
103 * @param {Object} baseParams (optional) Object containing key/value pairs to add to all requests
104 */
105 initPaging: function(url, pageSize, baseParams){
106 this.pageUrl = url;
107 this.pageSize = pageSize;
108 this.remoteSort = true;
109 if(baseParams) this.baseParams = baseParams;
110 },
111
112 /** @ignore */
113 createParams: function(pageNum, sortColumn, sortDir){
114 var params = {}, map = this.paramMap;
115 for(var key in this.baseParams){
116 if(typeof this.baseParams[key] != 'function'){
117 params[key] = this.baseParams[key];
118 }
119 }
120 params[map['page']] = pageNum;
121 params[map['pageSize']] = this.getPageSize();
122 params[map['sortColumn']] = (typeof sortColumn == 'undefined' ? '' : sortColumn);
123 params[map['sortDir']] = sortDir || '';
124 return params;
125 },
126
127 /**
128 * Loads a page of data.
129 * @param {Number} pageNum Which page to load. The first page is 1.
130 * @param {Function} callback (optional) Optional callback when loading is complete
131 * @param {Boolean} keepExisting (optional) true to keep existing data and append the new data
132 */
133 loadPage: function(pageNum, callback, keepExisting){
134 var sort = this.getSortState();
135 var params = this.createParams(pageNum, sort.column, sort.direction);
136 this.load(this.pageUrl, params, this.setLoadedPage.createDelegate(this, [pageNum, callback]),
137 keepExisting ? (pageNum-1) * this.pageSize : null);
138 },
139
140 /** @ignore */
141 applySort: function(suppressEvent){
142 if(!this.remoteSort){
143 YAHOO.ext.grid.LoadableDataModel.superclass.applySort.apply(this, arguments);
144 }else if(!suppressEvent){
145 var sort = this.getSortState();
146 if(sort.column){
147 this.fireRowsSorted(sort.column, sort.direction, true);
148 }
149 }
150 },
151
152 /** @ignore */
153 resetPaging: function(){
154 this.loadedPage = 1;
155 },
156
157 /* Overridden sort method to use remote sorting if turned on */
158 sort: function(sortInfo, columnIndex, direction, suppressEvent){
159 if(!this.remoteSort){
160 YAHOO.ext.grid.LoadableDataModel.superclass.sort.apply(this, arguments);
161 }else{
162 this.sortInfo = sortInfo;
163 this.sortColumn = columnIndex;
164 this.sortDir = direction;
165 var params = this.createParams(this.loadedPage, columnIndex, direction);
166 this.load(this.pageUrl, params, this.fireRowsSorted.createDelegate(this, [columnIndex, direction, true]));
167 }
168 },
169
170 /**
171 * Initiates the loading of the data from the specified URL - Failed load attempts will
172 * fire the {@link #loadexception} event.
173 * @param {Object/String} url The url from which the data can be loaded
174 * @param {<i>String/Object</i>} params (optional) The parameters to pass as either a url encoded string "param1=1&amp;param2=2" or as an object {param1: 1, param2: 2}
175 * @param {<i>Function</i>} callback (optional) Callback when load is complete - called with signature (this, true for success, false for failure)
176 * @param {<i>Number</i>} insertIndex (optional) if present, loaded data is inserted at the specified index instead of overwriting existing data
177 */
178 load: function(url, params, callback, insertIndex){
179 this.fireEvent('beforeload', this);
180 if(params && typeof params != 'string'){ // must be object
181 var buf = [];
182 for(var key in params){
183 if(typeof params[key] != 'function'){
184 buf.push(encodeURIComponent(key), '=', encodeURIComponent(params[key]), '&');
185 }
186 }
187 delete buf[buf.length-1];
188 params = buf.join('');
189 }
190 var cb = {
191 success: this.processResponse,
192 failure: this.processException,
193 scope: this,
194 argument: {callback: callback, insertIndex: insertIndex}
195 };
196 var method = params ? 'POST' : 'GET';
197 this.transId = YAHOO.util.Connect.asyncRequest(method, url, cb, params);
198 },
199
200 /**@private*/
201 processResponse: function(response){
202 var cb = response.argument.callback;
203 var keepExisting = (typeof response.argument.insertIndex == 'number');
204 var insertIndex = response.argument.insertIndex;
205 switch(this.dataType){
206 case YAHOO.ext.grid.LoadableDataModel.XML:
207 this.loadData(response.responseXML, cb, keepExisting, insertIndex);
208 break;
209 case YAHOO.ext.grid.LoadableDataModel.JSON:
210 var rtext = response.responseText;
211 try { // this code is a modified version of Yahoo! UI DataSource JSON parsing
212 // Trim leading spaces
213 while(rtext.substring(0,1) == " ") {
214 rtext = rtext.substring(1, rtext.length);
215 }
216 // Invalid JSON response
217 if(rtext.indexOf("{") < 0) {
218 throw "Invalid JSON response";
219 }
220
221 // Empty (but not invalid) JSON response
222 if(rtext.indexOf("{}") === 0) {
223 this.loadData({}, response.argument.callback);
224 return;
225 }
226
227 // Turn the string into an object literal...
228 // ...eval is necessary here
229 var jsonObjRaw = eval("(" + rtext + ")");
230 if(!jsonObjRaw) {
231 throw "Error evaling JSON response";
232 }
233 this.loadData(jsonObjRaw, cb, keepExisting, insertIndex);
234 } catch(e) {
235 this.fireLoadException(e, response);
236 if(typeof cb == 'function'){
237 cb(this, false);
238 }
239 }
240 break;
241 case YAHOO.ext.grid.LoadableDataModel.TEXT:
242 this.loadData(response.responseText, cb, keepExisting, insertIndex);
243 break;
244 };
245 },
246
247 /**@private*/
248 processException: function(response){
249 this.fireLoadException(null, response);
250 if(typeof response.argument.callback == 'function'){
251 response.argument.callback(this, false);
252 }
253 },
254
255 fireLoadException: function(e, responseObj){
256 this.onLoadException.fireDirect(this, e, responseObj);
257 },
258
259 fireLoadEvent: function(){
260 this.fireEvent('load', this.loadedPage, this.getTotalPages());
261 },
262
263 /**
264 * Adds a preprocessor function to parse data before it is added to the Model - ie. Date.parse to parse dates.
265 * @param {Number} columnIndex
266 * @param {Function} fn
267 */
268 addPreprocessor: function(columnIndex, fn){
269 this.preprocessors[columnIndex] = fn;
270 },
271
272 /**
273 * Gets the preprocessor function for the specified column.
274 * @param {Number} columnIndex
275 * @return {Function}
276 */
277 getPreprocessor: function(columnIndex){
278 return this.preprocessors[columnIndex];
279 },
280
281 /**
282 * Removes a preprocessor function.
283 * @param {Number} columnIndex
284 */
285 removePreprocessor: function(columnIndex){
286 this.preprocessors[columnIndex] = null;
287 },
288
289 /**
290 * Adds a postprocessor function to format data before updating the underlying data source (ie. convert date to string before updating XML document).
291 * @param {Number} columnIndex
292 * @param {Function} fn
293 */
294 addPostprocessor: function(columnIndex, fn){
295 this.postprocessors[columnIndex] = fn;
296 },
297
298 /**
299 * Gets the postprocessor function for the specified column.
300 * @param {Number} columnIndex
301 * @return {Function}
302 */
303 getPostprocessor: function(columnIndex){
304 return this.postprocessors[columnIndex];
305 },
306
307 /**
308 * Removes a postprocessor function.
309 * @param {Number} columnIndex
310 */
311 removePostprocessor: function(columnIndex){
312 this.postprocessors[columnIndex] = null;
313 },
314 /**
315 * Empty interface method - Called to process the data returned by the XHR - Classes which extend LoadableDataModel should implement this method.
316 * See {@link YAHOO.ext.XMLDataModel} for an example implementation.
317 */
318 loadData: function(data, callback, keepExisting, insertIndex){
319
320 }
321});
322
323YAHOO.ext.grid.LoadableDataModel.XML = 'xml';
324YAHOO.ext.grid.LoadableDataModel.JSON = 'json';
325YAHOO.ext.grid.LoadableDataModel.TEXT = 'text';
326
327
328
329
330
diff --git a/frontend/beta/js/YUI-extensions/data/Tree.js b/frontend/beta/js/YUI-extensions/data/Tree.js
new file mode 100644
index 0000000..afa5b20
--- a/dev/null
+++ b/frontend/beta/js/YUI-extensions/data/Tree.js
@@ -0,0 +1,412 @@
1YAHOO.namespace('ext.data');
2
3/**
4 * @class YAHOO.ext.data.Tree
5 * @extends YAHOO.ext.util.Observable
6 * The class represents a tree data structure and bubbles all the events for it's nodes. The nodes
7 * in the tree have most standard DOM functionality.
8 * @constructor
9 * @param {Node} root (optional) The root node
10 */
11YAHOO.ext.data.Tree = function(root){
12 this.nodeHash = {};
13 this.root = null;
14 if(root){
15 this.setRootNode(root);
16 }
17 this.events = {
18 'append' : true,
19 'remove' : true,
20 'move' : true,
21 'insert' : true,
22 'beforeappend' : true,
23 'beforeremove' : true,
24 'beforemove' : true,
25 'beforeinsert' : true
26 };
27};
28
29YAHOO.extendX(YAHOO.ext.data.Tree, YAHOO.ext.util.Observable, {
30 pathSeparator: '/',
31
32 getRootNode : function(){
33 return this.root;
34 },
35
36 setRootNode : function(node){
37 this.root = node;
38 node.ownerTree = this;
39 node.isRoot = true;
40 return node;
41 },
42
43 getNodeById : function(id){
44 return this.nodeHash[id];
45 },
46
47 registerNode : function(node){
48 this.nodeHash[node.id] = node;
49 },
50
51 unregisterNode : function(node){
52 delete this.nodeHash[node.id];
53 },
54
55 toString : function(){
56 return '[Tree'+(this.id?' '+this.id:'')+']';
57 }
58});
59
60/**
61 * @class YAHOO.ext.tree.Node
62 * @extends YAHOO.ext.util.Observable
63 * @cfg {String} text The text for this node
64 * @cfg {String} id The id for this node
65 * @constructor
66 * @param {Object} attributes The attributes/config for the node
67 */
68YAHOO.ext.data.Node = function(attributes){
69 this.attributes = attributes || {};
70 this.leaf = this.attributes.leaf;
71 this.id = this.attributes.id;
72 if(!this.id){
73 this.id = YAHOO.util.Dom.generateId(null, 'ynode-');
74 this.attributes.id = this.id;
75 }
76
77 this.childNodes = [];
78 if(!this.childNodes.indexOf){ // indexOf is a must
79 this.childNodes.indexOf = function(o){
80 for(var i = 0, len = this.length; i < len; i++){
81 if(this[i] == o) return i;
82 }
83 return -1;
84 };
85 }
86 this.parentNode = null;
87 this.firstChild = null;
88 this.lastChild = null;
89 this.previousSibling = null;
90 this.nextSibling = null;
91
92 this.events = {
93 'append' : true,
94 'remove' : true,
95 'move' : true,
96 'insert' : true,
97 'beforeappend' : true,
98 'beforeremove' : true,
99 'beforemove' : true,
100 'beforeinsert' : true
101 };
102};
103
104YAHOO.extendX(YAHOO.ext.data.Node, YAHOO.ext.util.Observable, {
105 fireEvent : function(evtName){
106 // first do standard event for this node
107 if(YAHOO.ext.data.Node.superclass.fireEvent.apply(this, arguments) === false){
108 return false;
109 }
110 // then bubble it up to the tree if the event wasn't cancelled
111 if(this.ownerTree){
112 if(this.ownerTree.fireEvent.apply(this.ownerTree, arguments) === false){
113 return false;
114 }
115 }
116 return true;
117 },
118
119 isLeaf : function(){
120 return this.leaf === true;
121 },
122
123 setFirstChild : function(node){
124 this.firstChild = node;
125 },
126
127 setLastChild : function(node){
128 this.lastChild = node;
129 },
130
131 isLast : function(){
132 return (!this.parentNode ? true : this.parentNode.lastChild == this);
133 },
134
135 isFirst : function(){
136 return (!this.parentNode ? true : this.parentNode.firstChild == this);
137 },
138
139 hasChildNodes : function(){
140 return !this.isLeaf() && this.childNodes.length > 0;
141 },
142
143 appendChild : function(node){
144 var multi = false;
145 if(node instanceof Array){
146 multi = node;
147 }else if(arguments.length > 1){
148 multi = arguments;
149 }
150 // if passed an array or multiple args do them one by one
151 if(multi){
152 for(var i = 0, len = multi.length; i < len; i++) {
153 this.appendChild(multi[i]);
154 }
155 }else{
156 if(this.fireEvent('beforeappend', this.ownerTree, this, node) === false){
157 return false;
158 }
159 var index = this.childNodes.length;
160 var oldParent = node.parentNode;
161 // it's a move, make sure we move it cleanly
162 if(oldParent){
163 if(node.fireEvent('beforemove', node.getOwnerTree(), node, oldParent, this, index) === false){
164 return false;
165 }
166 oldParent.removeChild(node);
167 }
168 var index = this.childNodes.length;
169 if(index == 0){
170 this.setFirstChild(node);
171 }
172 this.childNodes.push(node);
173 node.parentNode = this;
174 var ps = this.childNodes[index-1];
175 if(ps){
176 node.previousSibling = ps;
177 ps.nextSibling = node;
178 }
179 this.setLastChild(node);
180 node.setOwnerTree(this.getOwnerTree());
181 this.fireEvent('append', this.ownerTree, this, node, index);
182 if(oldParent){
183 node.fireEvent('move', this.ownerTree, node, oldParent, this, index);
184 }
185 return node;
186 }
187 },
188
189 removeChild : function(node){
190 var index = this.childNodes.indexOf(node);
191 if(index == -1){
192 return false;
193 }
194 if(this.fireEvent('beforeremove', this.ownerTree, this, node) === false){
195 return false;
196 }
197
198 // remove it from childNodes collection
199 this.childNodes.splice(index, 1);
200
201 // update siblings
202 if(node.previousSibling){
203 node.previousSibling.nextSibling = node.nextSibling;
204 }
205 if(node.nextSibling){
206 node.nextSibling.previousSibling = node.previousSibling;
207 }
208
209 // update child refs
210 if(this.firstChild == node){
211 this.setFirstChild(node.nextSibling);
212 }
213 if(this.lastChild == node){
214 this.setLastChild(node.previousSibling);
215 }
216
217 node.setOwnerTree(null);
218 // clear any references from the node
219 node.parentNode = null;
220 node.previousSibling = null;
221 node.nextSibling = null;
222 this.fireEvent('remove', this.ownerTree, this, node);
223 return node;
224 },
225
226 insertBefore : function(node, refNode){
227 if(!refNode){ // like standard Dom, refNode can be null for append
228 return this.appendChild(node);
229 }
230 // nothing to do
231 if(node == refNode){
232 return false;
233 }
234
235 if(this.fireEvent('beforeinsert', this.ownerTree, this, node, refNode) === false){
236 return false;
237 }
238 var index = this.childNodes.indexOf(refNode);
239 var oldParent = node.parentNode;
240 var refIndex = index;
241
242 // when moving internally, indexes will change after remove
243 if(oldParent == this && this.childNodes.indexOf(node) < index){
244 refIndex--;
245 }
246
247 // it's a move, make sure we move it cleanly
248 if(oldParent){
249 if(node.fireEvent('beforemove', node.getOwnerTree(), node, oldParent, this, index, refNode) === false){
250 return false;
251 }
252 oldParent.removeChild(node);
253 }
254 if(refIndex == 0){
255 this.setFirstChild(node);
256 }
257 this.childNodes.splice(refIndex, 0, node);
258 node.parentNode = this;
259 var ps = this.childNodes[refIndex-1];
260 if(ps){
261 node.previousSibling = ps;
262 ps.nextSibling = node;
263 }
264 node.nextSibling = refNode;
265 node.setOwnerTree(this.getOwnerTree());
266 this.fireEvent('insert', this.ownerTree, this, node, refNode);
267 if(oldParent){
268 node.fireEvent('move', this.ownerTree, node, oldParent, this, refIndex, refNode);
269 }
270 return node;
271 },
272
273 item : function(index){
274 return this.childNodes[index];
275 },
276
277 replaceChild : function(newChild, oldChild){
278 this.insertBefore(newChild, oldChild);
279 this.removeChild(oldChild);
280 return oldChild;
281 },
282
283 indexOf : function(child){
284 return this.childNodes.indexOf(child);
285 },
286
287 getOwnerTree : function(){
288 // if it doesn't have one, look for one
289 if(!this.ownerTree){
290 var p = this;
291 while(p){
292 if(p.ownerTree){
293 this.ownerTree = p.ownerTree;
294 break;
295 }
296 p = p.parentNode;
297 }
298 }
299 return this.ownerTree;
300 },
301
302 setOwnerTree : function(tree){
303 // if it's move, we need to update everyone
304 if(tree != this.ownerTree){
305 if(this.ownerTree){
306 this.ownerTree.unregisterNode(this);
307 }
308 this.ownerTree = tree;
309 var cs = this.childNodes;
310 for(var i = 0, len = cs.length; i < len; i++) {
311 cs[i].setOwnerTree(tree);
312 }
313 if(tree){
314 tree.registerNode(this);
315 }
316 }
317 },
318
319 getPath : function(attr){
320 attr = attr || 'id';
321 var p = this.parentNode;
322 var b = [this.attributes[attr]];
323 while(p){
324 b.unshift(p.attributes[attr]);
325 p = p.parentNode;
326 }
327 var sep = this.getOwnerTree().pathSeparator;
328 return sep + b.join(sep);
329 },
330
331 bubble : function(fn, scope, args){
332 var p = this;
333 while(p){
334 if(fn.call(scope || p, args || p) === false){
335 break;
336 }
337 p = p.parentNode;
338 }
339 },
340
341 cascade : function(fn, scope, args){
342 if(fn.call(scope || this, args || this) !== false){
343 var cs = this.childNodes;
344 for(var i = 0, len = cs.length; i < len; i++) {
345 cs[i].cascade(fn, scope, args);
346 }
347 }
348 },
349
350 eachChild : function(fn, scope, args){
351 var cs = this.childNodes;
352 for(var i = 0, len = cs.length; i < len; i++) {
353 if(fn.call(scope || this, args || cs[i]) === false){
354 break;
355 }
356 }
357 },
358
359 findChild : function(attribute, value){
360 var cs = this.childNodes;
361 for(var i = 0, len = cs.length; i < len; i++) {
362 if(cs[i].attributes[attribute] == value){
363 return cs[i];
364 }
365 }
366 return null;
367 },
368
369 /**
370 * Sorts this nodes children using the supplied sort function
371 * @param {Function} fn
372 * @param {Object} scope
373 */
374 sort : function(fn, scope){
375 var cs = this.childNodes;
376 var len = cs.length;
377 if(len > 0){
378 var sortFn = scope ? function(){fn.apply(scope, arguments);} : fn;
379 cs.sort(sortFn);
380 for(var i = 0; i < len; i++){
381 var n = cs[i];
382 n.previousSibling = cs[i-1];
383 n.nextSibling = cs[i+1];
384 if(i == 0){
385 this.setFirstChild(n);
386 }
387 if(i == len-1){
388 this.setLastChild(n);
389 }
390 }
391 }
392 },
393
394 contains : function(node){
395 return node.isAncestor(this);
396 },
397
398 isAncestor : function(node){
399 var p = this.parentNode;
400 while(p){
401 if(p == node){
402 return true;
403 }
404 p = p.parentNode;
405 }
406 return false;
407 },
408
409 toString : function(){
410 return '[Node'+(this.id?' '+this.id:'')+']';
411 }
412});
diff --git a/frontend/beta/js/YUI-extensions/data/XMLDataModel.js b/frontend/beta/js/YUI-extensions/data/XMLDataModel.js
new file mode 100644
index 0000000..e312a9e
--- a/dev/null
+++ b/frontend/beta/js/YUI-extensions/data/XMLDataModel.js
@@ -0,0 +1,274 @@
1/**
2 * @class YAHOO.ext.grid.XMLDataModel
3 * This is an implementation of a DataModel used by the Grid. It works
4 * with XML data.
5 * <br>Example schema from Amazon search:
6 * <pre><code>
7 * var schema = {
8 * tagName: 'Item',
9 * id: 'ASIN',
10 * fields: ['Author', 'Title', 'Manufacturer', 'ProductGroup']
11 * };
12 * </code></pre>
13 * @extends YAHOO.ext.grid.LoadableDataModel
14 * @constructor
15 * @param {Object} schema The schema to use
16 * @param {XMLDocument} xml An XML document to load immediately
17*/
18YAHOO.ext.grid.XMLDataModel = function(schema, xml){
19 YAHOO.ext.grid.XMLDataModel.superclass.constructor.call(this, YAHOO.ext.grid.LoadableDataModel.XML);
20 /**@private*/
21 this.schema = schema;
22 this.xml = xml;
23 if(xml){
24 this.loadData(xml);
25 }
26 this.idSeed = 0;
27};
28YAHOO.extendX(YAHOO.ext.grid.XMLDataModel, YAHOO.ext.grid.LoadableDataModel, {
29
30 getDocument: function(){
31 return this.xml;
32 },
33
34 /**
35 * Overrides loadData in LoadableDataModel to process XML
36 * @param {XMLDocument} doc The document to load
37 * @param {<i>Function</i>} callback (optional) callback to call when loading is complete
38 * @param {<i>Boolean</i>} keepExisting (optional) true to keep existing data
39 * @param {<i>Number</i>} insertIndex (optional) if present, loaded data is inserted at the specified index instead of overwriting existing data
40 */
41 loadData: function(doc, callback, keepExisting, insertIndex){
42 this.xml = doc;
43 var idField = this.schema.id;
44 var fields = this.schema.fields;
45 if(this.schema.totalTag){
46 this.totalCount = null;
47 var totalNode = doc.getElementsByTagName(this.schema.totalTag);
48 if(totalNode && totalNode.item(0) && totalNode.item(0).firstChild) {
49 var v = parseInt(totalNode.item(0).firstChild.nodeValue, 10);
50 if(!isNaN(v)){
51 this.totalCount = v;
52 }
53 }
54 }
55 var rowData = [];
56 var nodes = doc.getElementsByTagName(this.schema.tagName);
57 if(nodes && nodes.length > 0) {
58 for(var i = 0; i < nodes.length; i++) {
59 var node = nodes.item(i);
60 var colData = [];
61 colData.node = node;
62 colData.id = this.getNamedValue(node, idField, String(++this.idSeed));
63 for(var j = 0; j < fields.length; j++) {
64 var val = this.getNamedValue(node, fields[j], "");
65 if(this.preprocessors[j]){
66 val = this.preprocessors[j](val);
67 }
68 colData.push(val);
69 }
70 rowData.push(colData);
71 }
72 }
73 if(keepExisting !== true){
74 YAHOO.ext.grid.XMLDataModel.superclass.removeAll.call(this);
75 }
76 if(typeof insertIndex != 'number'){
77 insertIndex = this.getRowCount();
78 }
79 YAHOO.ext.grid.XMLDataModel.superclass.insertRows.call(this, insertIndex, rowData);
80 if(typeof callback == 'function'){
81 callback(this, true);
82 }
83 this.fireLoadEvent();
84 },
85
86 /**
87 * Adds a row to this DataModel and syncs the XML document
88 * @param {String} id The id of the row, if null the next row index is used
89 * @param {Array} cellValues The cell values for this row
90 * @return {Number} The index of the new row (if the model is sorted this index may not be accurate)
91 */
92 addRow: function(id, cellValues){
93 var node = this.createNode(this.xml, id, cellValues);
94 cellValues.id = id || ++this.idSeed;
95 cellValues.node = node;
96 return YAHOO.ext.grid.XMLDataModel.superclass.addRow.call(this, cellValues);
97 },
98
99 /**
100 * Inserts a row into this DataModel and syncs the XML document
101 * @param {Number} index The index to insert the row
102 * @param {String} id The id of the row, if null the next row index is used
103 * @param {Array} cellValues The cell values for this row
104 * @return {Number} The index of the new row (if the model is sorted this index may not be accurate)
105 */
106 insertRow: function(index, id, cellValues){
107 var node = this.createNode(this.xml, id, cellValues);
108 cellValues.id = id || ++this.idSeed;
109 cellValues.node = node;
110 return YAHOO.ext.grid.XMLDataModel.superclass.insertRow.call(this, index, cellValues);
111 },
112
113 /**
114 * Removes the row from DataModel and syncs the XML document
115 * @param {Number} index The index of the row to remove
116 */
117 removeRow: function(index){
118 var node = this.data[index].node;
119 node.parentNode.removeChild(node);
120 YAHOO.ext.grid.XMLDataModel.superclass.removeRow.call(this, index, index);
121 },
122
123 getNode: function(rowIndex){
124 return this.data[rowIndex].node;
125 },
126
127 /**
128 * Override this method to define your own node creation routine for when new rows are added.
129 * By default this method clones the first node and sets the column values in the newly cloned node.
130 * In many instances this will not work and you will have to create the node manually.
131 * @param {XMLDocument} xmlDoc The xml document being used by this model
132 * @param {String/Number} id The row id
133 * @param {Array} colData The column data for the new node
134 * @return {XMLNode} The created node
135 */
136 createNode: function(xmlDoc, id, colData){
137 var template = this.data[0].node;
138 var newNode = template.cloneNode(true);
139 var fields = this.schema.fields;
140 for(var i = 0, len = fields.length; i < len; i++){
141 var nodeValue = colData[i];
142 if(this.postprocessors[i]){
143 nodeValue = this.postprocessors[i](nodeValue);
144 }
145 this.setNamedValue(newNode, fields[i], nodeValue);
146 }
147 if(id){
148 this.setNamedValue(newNode, this.schema.idField, id);
149 }
150 template.parentNode.appendChild(newNode);
151 return newNode;
152 },
153
154 /**
155 * @private
156 * Convenience function looks for value in attributes, then in children tags - also
157 * normalizes namespace matches (ie matches ns:tag, FireFox matches tag and not ns:tag).
158 */
159 getNamedValue: function(node, name, defaultValue){
160 if(!node || !name){
161 return defaultValue;
162 }
163 var nodeValue = defaultValue;
164 var attrNode = node.attributes.getNamedItem(name);
165 if(attrNode) {
166 nodeValue = attrNode.value;
167 } else {
168 var childNode = node.getElementsByTagName(name);
169 if(childNode && childNode.item(0) && childNode.item(0).firstChild) {
170 nodeValue = childNode.item(0).firstChild.nodeValue;
171 }else{
172 // try to strip namespace for FireFox
173 var index = name.indexOf(':');
174 if(index > 0){
175 return this.getNamedValue(node, name.substr(index+1), defaultValue);
176 }
177 }
178 }
179 return nodeValue;
180 },
181
182 /**
183 * @private
184 * Convenience function set a value in the underlying xml node.
185 */
186 setNamedValue: function(node, name, value){
187 if(!node || !name){
188 return;
189 }
190 var attrNode = node.attributes.getNamedItem(name);
191 if(attrNode) {
192 attrNode.value = value;
193 return;
194 }
195 var childNode = node.getElementsByTagName(name);
196 if(childNode && childNode.item(0) && childNode.item(0).firstChild) {
197 childNode.item(0).firstChild.nodeValue = value;
198 }else{
199 // try to strip namespace for FireFox
200 var index = name.indexOf(':');
201 if(index > 0){
202 this.setNamedValue(node, name.substr(index+1), value);
203 }
204 }
205 },
206
207 /**
208 * Overrides DefaultDataModel.setValueAt to update the underlying XML Document
209 * @param {Object} value The new value
210 * @param {Number} rowIndex
211 * @param {Number} colIndex
212 */
213 setValueAt: function(value, rowIndex, colIndex){
214 var node = this.data[rowIndex].node;
215 if(node){
216 var nodeValue = value;
217 if(this.postprocessors[colIndex]){
218 nodeValue = this.postprocessors[colIndex](value);
219 }
220 this.setNamedValue(node, this.schema.fields[colIndex], nodeValue);
221 }
222 YAHOO.ext.grid.XMLDataModel.superclass.setValueAt.call(this, value, rowIndex, colIndex);
223 },
224
225 /**
226 * Overrides getRowId in DefaultDataModel to return the ID value of the specified node.
227 * @param {Number} rowIndex
228 * @return {Number}
229 */
230 getRowId: function(rowIndex){
231 return this.data[rowIndex].id;
232 },
233
234 addRows : function(rowData){
235 for(var j = 0, len = rowData.length; j < len; j++){
236 var cellValues = rowData[j];
237 var id = ++this.idSeed;
238 var node = this.createNode(this.xml, id, cellValues);
239 cellValues.node=node;
240 cellValues.id = cellValues.id || id;
241 YAHOO.ext.grid.XMLDataModel.superclass.addRow.call(this,cellValues);
242 }
243 },
244
245 insertRows : function(index, rowData){
246 // copy original array so it is not reversed
247 rowData = rowData.slice(0).reverse();
248 for(var j = 0, len = rowData.length; j < len; j++){
249 var cellValues = rowData[j];
250 var id = ++this.idSeed;
251 var node = this.createNode(this.xml, id, cellValues);
252 cellValues.id = cellValues.id || id;
253 cellValues.node = node;
254 YAHOO.ext.grid.XMLDataModel.superclass.insertRow.call(this, index, cellValues);
255 }
256 }
257});
258
259YAHOO.ext.grid.XMLQueryDataModel = function(){
260 YAHOO.ext.grid.XMLQueryDataModel.superclass.constructor.apply(this, arguments);
261};
262YAHOO.extendX(YAHOO.ext.grid.XMLQueryDataModel, YAHOO.ext.grid.XMLDataModel, {
263 getNamedValue: function(node, name, defaultValue){
264 if(!node || !name){
265 return defaultValue;
266 }
267 var nodeValue = defaultValue;
268 var childNode = cssQuery(name, node);
269 if(childNode && childNode[0]) {
270 nodeValue = childNode[0].firstChild.nodeValue;
271 }
272 return nodeValue;
273 }
274});
diff --git a/frontend/beta/js/YUI-extensions/dd/DragSource.js b/frontend/beta/js/YUI-extensions/dd/DragSource.js
new file mode 100644
index 0000000..efee2d6
--- a/dev/null
+++ b/frontend/beta/js/YUI-extensions/dd/DragSource.js
@@ -0,0 +1,218 @@
1// kill drag drop dependency
2if(YAHOO.util.DragDrop){
3
4YAHOO.ext.dd.DragSource = function(el, config){
5 this.el = getEl(el);
6 this.dragData = {};
7
8 YAHOO.ext.util.Config.apply(this, config);
9
10 if(!this.proxy){
11 this.proxy = new YAHOO.ext.dd.StatusProxy();
12 }
13 this.el.on('mouseup', this.handleMouseUp);
14 YAHOO.ext.dd.DragSource.superclass.constructor.call(this, this.el.dom, this.ddGroup || this.group,
15 {dragElId : this.proxy.id, resizeFrame: false, isTarget: false, scroll: this.scroll === true});
16
17 this.dragging = false;
18};
19
20YAHOO.extendX(YAHOO.ext.dd.DragSource, YAHOO.util.DDProxy, {
21 dropAllowed : 'ydd-drop-ok',
22 dropNotAllowed : 'ydd-drop-nodrop',
23
24 getDragData : function(e){
25 return this.dragData;
26 },
27
28 onDragEnter : function(e, id){
29 var target = YAHOO.util.DragDropMgr.getDDById(id);
30 this.cachedTarget = target;
31 if(this.beforeDragEnter(target, e, id) !== false){
32 if(target.isNotifyTarget){
33 var status = target.notifyEnter(this, e, this.dragData);
34 this.proxy.setStatus(status);
35 }else{
36 this.proxy.setStatus(this.dropAllowed);
37 }
38
39 if(this.afterDragEnter){
40 this.afterDragEnter(target, e, id);
41 }
42 }
43 },
44
45 beforeDragEnter : function(target, e, id){
46 return true;
47 },
48
49 alignElWithMouse: function() {
50 YAHOO.ext.dd.DragSource.superclass.alignElWithMouse.apply(this, arguments);
51 this.proxy.sync();
52 },
53
54 onDragOver : function(e, id){
55 var target = this.cachedTarget || YAHOO.util.DragDropMgr.getDDById(id);
56 if(this.beforeDragOver(target, e, id) !== false){
57 if(target.isNotifyTarget){
58 var status = target.notifyOver(this, e, this.dragData);
59 this.proxy.setStatus(status);
60 }
61
62 if(this.afterDragOver){
63 this.afterDragOver(target, e, id);
64 }
65 }
66 },
67
68 beforeDragOver : function(target, e, id){
69 return true;
70 },
71
72 onDragOut : function(e, id){
73 var target = this.cachedTarget || YAHOO.util.DragDropMgr.getDDById(id);
74 if(this.beforeDragOut(target, e, id) !== false){
75 if(target.isNotifyTarget){
76 target.notifyOut(this, e, this.dragData);
77 }
78 this.proxy.reset();
79 if(this.afterDragOut){
80 this.afterDragOut(target, e, id);
81 }
82 }
83 this.cachedTarget = null;
84 },
85
86 beforeDragOut : function(target, e, id){
87 return true;
88 },
89
90
91 onDragDrop : function(e, id){
92 var target = this.cachedTarget || YAHOO.util.DragDropMgr.getDDById(id);
93 if(this.beforeDragDrop(target, e, id) !== false){
94 if(target.isNotifyTarget){
95 if(target.notifyDrop(this, e, this.dragData)){ // valid drop?
96 this.onValidDrop(target, e, id);
97 }else{
98 this.onInvalidDrop(target, e, id);
99 }
100 }else{
101 this.onValidDrop(target, e, id);
102 }
103
104 if(this.afterDragDrop){
105 this.afterDragDrop(target, e, id);
106 }
107 }
108 },
109
110 beforeDragDrop : function(target, e, id){
111 return true;
112 },
113
114 onValidDrop : function(target, e, id){
115 this.hideProxy();
116 },
117
118 getRepairXY : function(e, data){
119 return this.el.getXY();
120 },
121
122 onInvalidDrop : function(target, e, id){
123 this.beforeInvalidDrop(target, e, id);
124 if(this.cachedTarget){
125 if(this.cachedTarget.isNotifyTarget){
126 this.cachedTarget.notifyOut(this, e, this.dragData);
127 }
128 this.cacheTarget = null;
129 }
130 this.proxy.repair(this.getRepairXY(e, this.dragData), this.afterRepair, this);
131 if(this.afterInvalidDrop){
132 this.afterInvalidDrop(e, id);
133 }
134 },
135
136 afterRepair : function(){
137 this.el.highlight(this.hlColor || 'c3daf9');
138 this.dragging = false;
139 },
140
141 beforeInvalidDrop : function(target, e, id){
142 return true;
143 },
144
145 handleMouseDown : function(e){
146 if(this.dragging) {
147 return;
148 }
149 if(YAHOO.ext.QuickTips){
150 YAHOO.ext.QuickTips.disable();
151 }
152 var data = this.getDragData(e);
153 if(data && this.onBeforeDrag(data, e) !== false){
154 this.dragData = data;
155 this.proxy.stop();
156 YAHOO.ext.dd.DragSource.superclass.handleMouseDown.apply(this, arguments);
157 }
158 },
159
160 handleMouseUp : function(e){
161 if(YAHOO.ext.QuickTips){
162 YAHOO.ext.QuickTips.enable();
163 }
164 },
165
166 onBeforeDrag : function(data, e){
167 return true;
168 },
169
170 startDrag : function(e){
171 this.proxy.reset();
172 this.dragging = true;
173 this.proxy.update('');
174 this.onInitDrag(e);
175 this.proxy.show();
176 },
177
178 onInitDrag : function(e){
179 var clone = this.el.dom.cloneNode(true);
180 clone.id = YAHOO.util.Dom.generateId(); // prevent duplicate ids
181 this.proxy.update(clone);
182 return true;
183 },
184
185
186 getProxy : function(){
187 return this.proxy;
188 },
189
190 hideProxy : function(){
191 this.proxy.hide();
192 this.proxy.reset(true);
193 this.dragging = false;
194 },
195
196 triggerCacheRefresh : function(){
197 YAHOO.util.DDM.refreshCache(this.groups);
198 },
199
200 // override to prevent hiding
201 b4EndDrag: function(e) {
202 },
203
204 // override to prevent moving
205 endDrag : function(e){
206 this.onEndDrag(this.dragData, e);
207 },
208
209 onEndDrag : function(data, e){
210
211 },
212
213 // pin to cursor
214 autoOffset : function(x, y) {
215 this.setDelta(-12, -20);
216 }
217});
218}
diff --git a/frontend/beta/js/YUI-extensions/dd/DragZone.js b/frontend/beta/js/YUI-extensions/dd/DragZone.js
new file mode 100644
index 0000000..7a6edb6
--- a/dev/null
+++ b/frontend/beta/js/YUI-extensions/dd/DragZone.js
@@ -0,0 +1,64 @@
1// kill drag drop dependency
2if(YAHOO.util.DragDrop){
3/**
4 * @class YAHOO.ext.dd.DragZone
5 * @extends YAHOO.ext.dd.Source
6 * This class provides a container DD instance that proxies for multiple child node sources.<br />
7 * By default, this class requires that draggable child nodes are registered with
8 * {@link YAHOO.ext.dd.Registry}.
9 * @cfg {Boolean} containerScroll True to register this container with the Scrollmanager
10 * for auto scrolling during drag operations.
11 * @constructor
12 * @param {String/HTMLElement/Element} el The container element
13 * @param {Object} config
14 */
15YAHOO.ext.dd.DragZone = function(el, config){
16 YAHOO.ext.dd.DragZone.superclass.constructor.call(this, el, config);
17 if(this.containerScroll){
18 YAHOO.ext.dd.ScrollManager.register(this.el);
19 }
20};
21
22YAHOO.extendX(YAHOO.ext.dd.DragZone, YAHOO.ext.dd.DragSource, {
23 /**
24 * Called when a mousedown occurs in this container. Looks in {@link YAHOO.ext.dd.Registry}
25 * for a valid target to drag based on the mouse down. Override this method
26 * to provide your own lookup logic (e.g. finding a child by class name). Make sure your returned
27 * object has a "ddel" attribute (with an HTML Element) for other functions to work.
28 * @param {EventObject} e The mouse down event
29 * @return {Object} The dragData
30 */
31 getDragData : function(e){
32 return YAHOO.ext.dd.Registry.getHandleFromEvent(e);
33 },
34
35 /**
36 * Called once drag threshold has been reached to initialize the proxy element. By default, it clones the
37 * this.dragData.ddel
38 * @param {EventObject} e The current event
39 * @return {Boolean} true to continue the drag, false to cancel
40 */
41 onInitDrag : function(e){
42 this.proxy.update(this.dragData.ddel.cloneNode(true));
43 return true;
44 },
45
46 /**
47 * Called after a repair of an invalid drop. By default, highlights this.dragData.ddel
48 */
49 afterRepair : function(){
50 YAHOO.ext.Element.fly(this.dragData.ddel).highlight(this.hlColor || 'c3daf9');
51 this.dragging = false;
52 },
53
54 /**
55 * Called before a repair of an invalid drop to get the XY to animate to. By default returns
56 * the XY of this.dragData.ddel
57 * @param {EventObject} e The mouse up event
58 * @return {Array} The xy location (e.g. [100, 200])
59 */
60 getRepairXY : function(e){
61 return YAHOO.ext.Element.fly(this.dragData.ddel).getXY();
62 }
63});
64}
diff --git a/frontend/beta/js/YUI-extensions/dd/DropTarget.js b/frontend/beta/js/YUI-extensions/dd/DropTarget.js
new file mode 100644
index 0000000..30e59cd
--- a/dev/null
+++ b/frontend/beta/js/YUI-extensions/dd/DropTarget.js
@@ -0,0 +1,45 @@
1// kill drag drop dependency
2if(YAHOO.util.DragDrop){
3
4YAHOO.ext.dd.DropTarget = function(el, config){
5 this.el = getEl(el);
6
7 YAHOO.ext.util.Config.apply(this, config);
8
9 if(this.containerScroll){
10 YAHOO.ext.dd.ScrollManager.register(this.el);
11 }
12
13 YAHOO.ext.dd.DropTarget.superclass.constructor.call(this, this.el.dom, this.ddGroup || this.group,
14 {isTarget: true});
15
16};
17
18YAHOO.extendX(YAHOO.ext.dd.DropTarget, YAHOO.util.DDTarget, {
19 isTarget : true,
20 isNotifyTarget : true,
21 dropAllowed : 'ydd-drop-ok',
22 dropNotAllowed : 'ydd-drop-nodrop',
23
24 notifyEnter : function(dd, e, data){
25 if(this.overClass){
26 this.el.addClass(this.overClass);
27 }
28 return this.dropAllowed;
29 },
30
31 notifyOver : function(dd, e, data){
32 return this.dropAllowed;
33 },
34
35 notifyOut : function(dd, e, data){
36 if(this.overClass){
37 this.el.removeClass(this.overClass);
38 }
39 },
40
41 notifyDrop : function(dd, e, data){
42 return false;
43 }
44});
45}
diff --git a/frontend/beta/js/YUI-extensions/dd/DropZone.js b/frontend/beta/js/YUI-extensions/dd/DropZone.js
new file mode 100644
index 0000000..ce446fb
--- a/dev/null
+++ b/frontend/beta/js/YUI-extensions/dd/DropZone.js
@@ -0,0 +1,81 @@
1// kill drag drop dependency
2if(YAHOO.util.DragDrop){
3YAHOO.ext.dd.DropZone = function(el, config){
4 YAHOO.ext.dd.DropZone.superclass.constructor.call(this, el, config);
5};
6
7YAHOO.extendX(YAHOO.ext.dd.DropZone, YAHOO.ext.dd.DropTarget, {
8 getTargetFromEvent : function(e){
9 return YAHOO.ext.dd.Registry.getTargetFromEvent(e);
10 },
11
12 onNodeEnter : function(n, dd, e, data){
13
14 },
15
16 onNodeOver : function(n, dd, e, data){
17 return this.dropAllowed;
18 },
19
20 onNodeOut : function(n, dd, e, data){
21
22 },
23
24 onNodeDrop : function(n, dd, e, data){
25 return false;
26 },
27
28 onContainerOver : function(n, dd, e, data){
29 return this.dropNotAllowed;
30 },
31
32 onContainerDrop : function(n, dd, e, data){
33 return false;
34 },
35
36 notifyEnter : function(dd, e, data){
37 return this.dropNotAllowed;
38 },
39
40 notifyOver : function(dd, e, data){
41 var n = this.getTargetFromEvent(e);
42 if(!n){ // not over valid drop target
43 if(this.lastOverNode){
44 this.onNodeOut(this.lastOverNode, dd, e, data);
45 this.lastOverNode = null;
46 }
47 return this.onContainerOver(dd, e, data);
48 }
49 if(this.lastOverNode != n){
50 if(this.lastOverNode){
51 this.onNodeOut(this.lastOverNode, dd, e, data);
52 }
53 this.onNodeEnter(n, dd, e, data);
54 this.lastOverNode = n;
55 }
56 return this.onNodeOver(n, dd, e, data);
57 },
58
59 notifyOut : function(dd, e, data){
60 if(this.lastOverNode){
61 this.onNodeOut(this.lastOverNode, dd, e, data);
62 this.lastOverNode = null;
63 }
64 },
65
66 notifyDrop : function(dd, e, data){
67 if(this.lastOverNode){
68 this.onNodeOut(this.lastOverNode, dd, e, data);
69 this.lastOverNode = null;
70 }
71 var n = this.getTargetFromEvent(e);
72 return n ?
73 this.onNodeDrop(n, dd, e, data) :
74 this.onContainerDrop(n, dd, e, data);
75 },
76
77 triggerCacheRefresh : function(){
78 YAHOO.util.DDM.refreshCache(this.groups);
79 }
80});
81}
diff --git a/frontend/beta/js/YUI-extensions/dd/Registry.js b/frontend/beta/js/YUI-extensions/dd/Registry.js
new file mode 100644
index 0000000..983b874
--- a/dev/null
+++ b/frontend/beta/js/YUI-extensions/dd/Registry.js
@@ -0,0 +1,80 @@
1// kill drag drop dependency
2if(YAHOO.util.DragDrop){
3
4YAHOO.ext.dd.Registry = function(){
5 var elements = {};
6 var handles = {};
7 var autoIdSeed = 0;
8 var doc = document; // local reference for IE
9
10 var getId = function(el, autogen){
11 if(typeof el == 'string'){
12 return el;
13 }
14 var id = el.id;
15 if(!id && autogen !== false){
16 id = 'yddgen-' + (++autoIdSeed);
17 el.id = id;
18 }
19 return id;
20 };
21
22 return {
23 register : function(el, data){
24 data = data || {};
25 if(typeof el == 'string'){
26 el = doc.getElementById(el);
27 }
28 data.ddel = el;
29 elements[getId(el)] = data;
30 if(data.isHandle !== false){
31 handles[data.ddel.id] = data;
32 }
33 if(data.handles){
34 var hs = data.handles;
35 for(var i = 0, len = hs.length; i < len; i++){
36 handles[getId(hs[i])] = data;
37 }
38 }
39 },
40
41 unregister : function(el){
42 var id = getId(el, false);
43 var data = elements[id];
44 if(data){
45 delete elements[id];
46 if(data.handles){
47 var hs = data.handles;
48 for(var i = 0, len = hs.length; i < len; i++){
49 delete handles[getId(hs[i], false)];
50 }
51 }
52 }
53 },
54
55 getHandle : function(id){
56 if(typeof id != 'string'){ // must be element?
57 id = id.id;
58 }
59 return handles[id];
60 },
61
62 getHandleFromEvent : function(e){
63 var t = YAHOO.util.Event.getTarget(e);
64 return t ? handles[t.id] : null;
65 },
66
67 getTarget : function(id){
68 if(typeof id != 'string'){ // must be element?
69 id = id.id;
70 }
71 return elements[id];
72 },
73
74 getTargetFromEvent : function(e){
75 var t = YAHOO.util.Event.getTarget(e);
76 return t ? elements[t.id] || handles[t.id] : null;
77 }
78 };
79}();
80}
diff --git a/frontend/beta/js/YUI-extensions/dd/ScrollManager.js b/frontend/beta/js/YUI-extensions/dd/ScrollManager.js
new file mode 100644
index 0000000..615aadf
--- a/dev/null
+++ b/frontend/beta/js/YUI-extensions/dd/ScrollManager.js
@@ -0,0 +1,171 @@
1// kill dependency issue
2if(YAHOO.util.DragDrop){
3/**
4 * @class YAHOO.ext.dd.ScrollManager
5 * Provides automatic scrolling of overflow regions in the page during drag operations.<br><br>
6 * <b>Note: This class uses "Point Mode" and is untested in "Intersect Mode".</b>
7 * @singleton
8 */
9YAHOO.ext.dd.ScrollManager = function(){
10 var ddm = YAHOO.util.DragDropMgr;
11 var els = {};
12 var dragEl = null;
13 var proc = {};
14
15 var onStop = function(e){
16 dragEl = null;
17 clearProc();
18 };
19
20 var triggerRefresh = function(){
21 if(ddm.dragCurrent){
22 ddm.refreshCache(ddm.dragCurrent.groups);
23 }
24 }
25
26 var doScroll = function(){
27 if(ddm.dragCurrent){
28 var dds = YAHOO.ext.dd.ScrollManager;
29 if(!dds.animate || !YAHOO.util.Scroll){
30 if(proc.el.scroll(proc.dir, dds.increment)){
31 triggerRefresh();
32 }
33 }else{
34 proc.el.scroll(proc.dir, dds.increment, true, dds.animDuration, triggerRefresh);
35 }
36 }
37 };
38
39 var clearProc = function(){
40 if(proc.id){
41 clearInterval(proc.id);
42 }
43 proc.id = 0;
44 proc.el = null;
45 proc.dir = '';
46 };
47
48 var startProc = function(el, dir){
49 clearProc();
50 proc.el = el;
51 proc.dir = dir;
52 proc.id = setInterval(doScroll, YAHOO.ext.dd.ScrollManager.frequency);
53 };
54
55 var onFire = function(e, isDrop){
56 if(isDrop || !ddm.dragCurrent){ return; }
57 var dds = YAHOO.ext.dd.ScrollManager;
58 if(!dragEl || dragEl != ddm.dragCurrent){
59 dragEl = ddm.dragCurrent;
60 // refresh regions on drag start
61 dds.refreshCache();
62 }
63
64 var xy = YAHOO.util.Event.getXY(e);
65 var pt = new YAHOO.util.Point(xy[0], xy[1]);
66 for(var id in els){
67 var el = els[id], r = el._region;
68 if(r.contains(pt) && el.isScrollable()){
69 if(r.bottom - pt.y <= dds.thresh){
70 if(proc.el != el){
71 startProc(el, 'down');
72 }
73 return;
74 }else if(r.right - pt.x <= dds.thresh){
75 if(proc.el != el){
76 startProc(el, 'left');
77 }
78 return;
79 }else if(pt.y - r.top <= dds.thresh){
80 if(proc.el != el){
81 startProc(el, 'up');
82 }
83 return;
84 }else if(pt.x - r.left <= dds.thresh){
85 if(proc.el != el){
86 startProc(el, 'right');
87 }
88 return;
89 }
90 }
91 }
92 clearProc();
93 };
94
95 ddm.fireEvents = ddm.fireEvents.createSequence(onFire, ddm);
96 ddm.stopDrag = ddm.stopDrag.createSequence(onStop, ddm);
97
98 return {
99 /**
100 * Registers new overflow element(s) to auto scroll
101 * @param {String/HTMLElement/Element/Array} el The id of or the element to be scrolled or an array of either
102 */
103 register : function(el){
104 if(el instanceof Array){
105 for(var i = 0, len = el.length; i < len; i++) {
106 this.register(el[i]);
107 }
108 }else{
109 el = getEl(el);
110 els[el.id] = el;
111 }
112 },
113
114 /**
115 * Unregisters overflow element(s) so they are no longer scrolled
116 * @param {String/HTMLElement/Element/Array} el The id of or the element to be removed or an array of either
117 */
118 unregister : function(el){
119 if(el instanceof Array){
120 for(var i = 0, len = el.length; i < len; i++) {
121 this.unregister(el[i]);
122 }
123 }else{
124 el = getEl(el);
125 delete els[el.id];
126 }
127 },
128
129 /**
130 * The number of pixels from the edge of a container the pointer needs to be to
131 * trigger scrolling (defaults to 25)
132 * @type Number
133 */
134 thresh : 25,
135
136 /**
137 * The number of pixels to scroll in each scroll increment (defaults to 50)
138 * @type Number
139 */
140 increment : 100,
141
142 /**
143 * The frequency of scrolls in milliseconds (defaults to 500)
144 * @type Number
145 */
146 frequency : 500,
147
148 /**
149 * True to animate the scroll (defaults to true)
150 * @type Boolean
151 */
152 animate: true,
153
154 /**
155 * The animation duration in seconds -
156 * MUST BE less than YAHOO.ext.dd.ScrollManager.frequency! (defaults to .4)
157 * @type Number
158 */
159 animDuration: .4,
160
161 /**
162 * Manually trigger a cache refresh.
163 */
164 refreshCache : function(){
165 for(var id in els){
166 els[id]._region = els[id].getRegion();
167 }
168 }
169 }
170}();
171}
diff --git a/frontend/beta/js/YUI-extensions/dd/StatusProxy.js b/frontend/beta/js/YUI-extensions/dd/StatusProxy.js
new file mode 100644
index 0000000..97de4d9
--- a/dev/null
+++ b/frontend/beta/js/YUI-extensions/dd/StatusProxy.js
@@ -0,0 +1,110 @@
1YAHOO.ext.dd.StatusProxy = function(config){
2 YAHOO.ext.util.Config.apply(this, config);
3 this.id = this.id || YAHOO.util.Dom.generateId();
4 this.el = new YAHOO.ext.Layer({
5 dh: {
6 id: this.id, tag: 'div', cls: 'ydd-drag-proxy '+this.dropNotAllowed, children: [
7 {tag: 'div', cls: 'ydd-drop-icon'},
8 {tag: 'div', cls: 'ydd-drag-ghost'}
9 ]
10 },
11 shadow: !config || config.shadow !== false
12 });
13 /*this.el = YAHOO.ext.DomHelper.insertBefore(document.body.firstChild, {
14 id: this.id, tag: 'div', cls: 'ydd-drag-proxy '+this.dropNotAllowed, children: [
15 {tag: 'div', cls: 'ydd-drop-icon'},
16 {tag: 'div', cls: 'ydd-drag-ghost'}
17 ]
18 }, true);*/
19 this.ghost = getEl(this.el.dom.childNodes[1]);
20 this.dropStatus = this.dropNotAllowed;
21};
22
23YAHOO.ext.dd.StatusProxy.prototype = {
24 dropAllowed : 'ydd-drop-ok',
25 dropNotAllowed : 'ydd-drop-nodrop',
26 /**
27 * Updates the DD visual element to allow/not allow a drop
28 * @param {String} cssClass The css class for the new drop status indicator image
29 */
30 setStatus : function(cssClass){
31 cssClass = cssClass || this.dropNotAllowed;
32 if(this.dropStatus != cssClass){
33 this.el.replaceClass(this.dropStatus, cssClass);
34 this.dropStatus = cssClass;
35 }
36 },
37
38 reset : function(clearGhost){
39 this.el.dom.className = 'ydd-drag-proxy ' + this.dropNotAllowed;
40 this.dropStatus = this.dropNotAllowed;
41 if(clearGhost){
42 this.ghost.update('');
43 }
44 },
45
46 update : function(html){
47 if(typeof html == 'string'){
48 this.ghost.update(html);
49 }else{
50 this.ghost.update('');
51 html.style.margin = '0';
52 this.ghost.dom.appendChild(html);
53 }
54 },
55
56 getEl : function(){
57 return this.el;
58 },
59
60 getGhost : function(){
61 return this.ghost;
62 },
63
64 hide : function(clear){
65 this.el.hide();
66 if(clear){
67 this.reset(true);
68 }
69 },
70
71 stop : function(){
72 if(this.anim && this.anim.isAnimated()){
73 this.anim.stop();
74 }
75 },
76
77 show : function(){
78 this.el.show();
79 },
80
81 sync : function(){
82 this.el.syncLocalXY();
83 },
84
85 repair : function(xy, callback, scope){
86 this.callback = callback;
87 this.scope = scope;
88 if(xy && this.animRepair !== false && YAHOO.util.Anim){
89 this.el.addClass('ydd-drag-repair');
90 this.el.hideUnders(true);
91 if(!this.anim){
92 this.anim = new YAHOO.util.Motion(this.el.dom, {}, this.repairDuration || .5, YAHOO.util.Easing.easeOut);
93 this.anim.onComplete.subscribe(this.afterRepair, this, true);
94 }
95 this.anim.attributes = {points: {to:xy}};
96 this.anim.animate();
97 }else{
98 this.afterRepair();
99 }
100 },
101
102 afterRepair : function(){
103 this.hide(true);
104 if(typeof this.callback == 'function'){
105 this.callback.call(this.scope || this);
106 }
107 this.callback == null;
108 this.scope == null;
109 }
110};
diff --git a/frontend/beta/js/YUI-extensions/grid/AbstractColumnModel.js b/frontend/beta/js/YUI-extensions/grid/AbstractColumnModel.js
new file mode 100644
index 0000000..1f93590
--- a/dev/null
+++ b/frontend/beta/js/YUI-extensions/grid/AbstractColumnModel.js
@@ -0,0 +1,131 @@
1/**
2 * @class YAHOO.ext.grid.AbstractColumnModel
3 * @extends YAHOO.ext.util.Observable
4 * This abstract class defines the ColumnModel interface and provides default implementations of the events required by the Grid.
5 * @constructor
6*/
7YAHOO.ext.grid.AbstractColumnModel = function(){
8 // legacy events
9 this.onWidthChange = new YAHOO.util.CustomEvent('widthChanged');
10 this.onHeaderChange = new YAHOO.util.CustomEvent('headerChanged');
11 this.onHiddenChange = new YAHOO.util.CustomEvent('hiddenChanged');
12
13 this.events = {
14 /**
15 * @event widthchange
16 * Fires when the width of a column changes
17 * @param {ColumnModel} this
18 * @param {Number} columnIndex The column index
19 * @param {Number} newWidth The new width
20 */
21 'widthchange': this.onWidthChange,
22 /**
23 * @event headerchange
24 * Fires when the text of a header changes
25 * @param {ColumnModel} this
26 * @param {Number} columnIndex The column index
27 * @param {Number} newText The new header text
28 */
29 'headerchange': this.onHeaderChange,
30 /**
31 * @event hiddenchange
32 * Fires when a column is hidden or "unhidden"
33 * @param {ColumnModel} this
34 * @param {Number} columnIndex The column index
35 * @param {Number} hidden true if hidden, false otherwise
36 */
37 'hiddenchange': this.onHiddenChange
38 };
39};
40
41YAHOO.ext.grid.AbstractColumnModel.prototype = {
42 fireEvent : YAHOO.ext.util.Observable.prototype.fireEvent,
43 on : YAHOO.ext.util.Observable.prototype.on,
44 addListener : YAHOO.ext.util.Observable.prototype.addListener,
45 delayedListener : YAHOO.ext.util.Observable.prototype.delayedListener,
46 removeListener : YAHOO.ext.util.Observable.prototype.removeListener,
47 purgeListeners : YAHOO.ext.util.Observable.prototype.purgeListeners,
48 bufferedListener : YAHOO.ext.util.Observable.prototype.bufferedListener,
49
50 fireWidthChange : function(colIndex, newWidth){
51 this.onWidthChange.fireDirect(this, colIndex, newWidth);
52 },
53
54 fireHeaderChange : function(colIndex, newHeader){
55 this.onHeaderChange.fireDirect(this, colIndex, newHeader);
56 },
57
58 fireHiddenChange : function(colIndex, hidden){
59 this.onHiddenChange.fireDirect(this, colIndex, hidden);
60 },
61
62 /**
63 * Interface method - Returns the number of columns.
64 * @return {Number}
65 */
66 getColumnCount : function(){
67 return 0;
68 },
69
70 /**
71 * Interface method - Returns true if the specified column is sortable.
72 * @param {Number} col The column index
73 * @return {Boolean}
74 */
75 isSortable : function(col){
76 return false;
77 },
78
79 /**
80 * Interface method - Returns true if the specified column is hidden.
81 * @param {Number} col The column index
82 * @return {Boolean}
83 */
84 isHidden : function(col){
85 return false;
86 },
87
88 /**
89 * Interface method - Returns the sorting comparison function defined for the column (defaults to sortTypes.none).
90 * @param {Number} col The column index
91 * @return {Function}
92 */
93 getSortType : function(col){
94 return YAHOO.ext.grid.DefaultColumnModel.sortTypes.none;
95 },
96
97 /**
98 * Interface method - Returns the rendering (formatting) function defined for the column.
99 * @param {Number} col The column index
100 * @return {Function}
101 */
102 getRenderer : function(col){
103 return YAHOO.ext.grid.DefaultColumnModel.defaultRenderer;
104 },
105
106 /**
107 * Interface method - Returns the width for the specified column.
108 * @param {Number} col The column index
109 * @return {Number}
110 */
111 getColumnWidth : function(col){
112 return 0;
113 },
114
115 /**
116 * Interface method - Returns the total width of all columns.
117 * @return {Number}
118 */
119 getTotalWidth : function(){
120 return 0;
121 },
122
123 /**
124 * Interface method - Returns the header for the specified column.
125 * @param {Number} col The column index
126 * @return {String}
127 */
128 getColumnHeader : function(col){
129 return '';
130 }
131};
diff --git a/frontend/beta/js/YUI-extensions/grid/DefaultColumnModel.js b/frontend/beta/js/YUI-extensions/grid/DefaultColumnModel.js
new file mode 100644
index 0000000..fbdba26
--- a/dev/null
+++ b/frontend/beta/js/YUI-extensions/grid/DefaultColumnModel.js
@@ -0,0 +1,325 @@
1/**
2 * @class YAHOO.ext.grid.DefaultColumnModel
3 * @extends YAHOO.ext.grid.AbstractColumnModel
4 * This is the default implementation of a ColumnModel used by the Grid. It defines
5 * the columns in the grid.
6 * <br>Usage:<br>
7 <pre><code>
8 var sort = YAHOO.ext.grid.DefaultColumnModel.sortTypes;
9 var myColumns = [
10 {header: "Ticker", width: 60, sortable: true, sortType: sort.asUCString},
11 {header: "Company Name", width: 150, sortable: true, sortType: sort.asUCString},
12 {header: "Market Cap.", width: 100, sortable: true, sortType: sort.asFloat},
13 {header: "$ Sales", width: 100, sortable: true, sortType: sort.asFloat, renderer: money},
14 {header: "Employees", width: 100, sortable: true, sortType: sort.asFloat}
15 ];
16 var colModel = new YAHOO.ext.grid.DefaultColumnModel(myColumns);
17 </code></pre>
18 * @constructor
19 * @param {Object} config The config object
20*/
21YAHOO.ext.grid.DefaultColumnModel = function(config){
22 YAHOO.ext.grid.DefaultColumnModel.superclass.constructor.call(this);
23 /**
24 * The config passed into the constructor
25 */
26 this.config = config;
27
28 /**
29 * The width of columns which have no width specified (defaults to 100)
30 * @type Number
31 */
32 this.defaultWidth = 100;
33 /**
34 * Default sortable of columns which have no sortable specified (defaults to false)
35 * @type Boolean
36 */
37 this.defaultSortable = false;
38};
39YAHOO.extendX(YAHOO.ext.grid.DefaultColumnModel, YAHOO.ext.grid.AbstractColumnModel, {
40
41 /**
42 * Returns the number of columns.
43 * @return {Number}
44 */
45 getColumnCount : function(){
46 return this.config.length;
47 },
48
49 /**
50 * Returns true if the specified column is sortable.
51 * @param {Number} col The column index
52 * @return {Boolean}
53 */
54 isSortable : function(col){
55 if(typeof this.config[col].sortable == 'undefined'){
56 return this.defaultSortable;
57 }
58 return this.config[col].sortable;
59 },
60
61 /**
62 * Returns the sorting comparison function defined for the column (defaults to sortTypes.none).
63 * @param {Number} col The column index
64 * @return {Function}
65 */
66 getSortType : function(col){
67 if(!this.dataMap){
68 // build a lookup so we don't search every time
69 var map = [];
70 for(var i = 0, len = this.config.length; i < len; i++){
71 map[this.getDataIndex(i)] = i;
72 }
73 this.dataMap = map;
74 }
75 col = this.dataMap[col];
76 if(!this.config[col].sortType){
77 return YAHOO.ext.grid.DefaultColumnModel.sortTypes.none;
78 }
79 return this.config[col].sortType;
80 },
81
82 /**
83 * Sets the sorting comparison function for a column.
84 * @param {Number} col The column index
85 * @param {Function} fn
86 */
87 setSortType : function(col, fn){
88 this.config[col].sortType = fn;
89 },
90
91
92 /**
93 * Returns the rendering (formatting) function defined for the column.
94 * @param {Number} col The column index
95 * @return {Function}
96 */
97 getRenderer : function(col){
98 if(!this.config[col].renderer){
99 return YAHOO.ext.grid.DefaultColumnModel.defaultRenderer;
100 }
101 return this.config[col].renderer;
102 },
103
104 /**
105 * Sets the rendering (formatting) function for a column.
106 * @param {Number} col The column index
107 * @param {Function} fn
108 */
109 setRenderer : function(col, fn){
110 this.config[col].renderer = fn;
111 },
112
113 /**
114 * Returns the width for the specified column.
115 * @param {Number} col The column index
116 * @return {Number}
117 */
118 getColumnWidth : function(col){
119 return this.config[col].width || this.defaultWidth;
120 },
121
122 /**
123 * Sets the width for a column.
124 * @param {Number} col The column index
125 * @param {Number} width The new width
126 */
127 setColumnWidth : function(col, width, suppressEvent){
128 this.config[col].width = width;
129 this.totalWidth = null;
130 if(!suppressEvent){
131 this.onWidthChange.fireDirect(this, col, width);
132 }
133 },
134
135 /**
136 * Returns the total width of all columns.
137 * @param {Boolean} includeHidden True to include hidden column widths
138 * @return {Number}
139 */
140 getTotalWidth : function(includeHidden){
141 if(!this.totalWidth){
142 this.totalWidth = 0;
143 for(var i = 0; i < this.config.length; i++){
144 if(includeHidden || !this.isHidden(i)){
145 this.totalWidth += this.getColumnWidth(i);
146 }
147 }
148 }
149 return this.totalWidth;
150 },
151
152 /**
153 * Returns the header for the specified column.
154 * @param {Number} col The column index
155 * @return {String}
156 */
157 getColumnHeader : function(col){
158 return this.config[col].header;
159 },
160
161 /**
162 * Sets the header for a column.
163 * @param {Number} col The column index
164 * @param {String} header The new header
165 */
166 setColumnHeader : function(col, header){
167 this.config[col].header = header;
168 this.onHeaderChange.fireDirect(this, col, header);
169 },
170
171 /**
172 * Returns the tooltip for the specified column.
173 * @param {Number} col The column index
174 * @return {String}
175 */
176 getColumnTooltip : function(col){
177 return this.config[col].tooltip;
178 },
179 /**
180 * Sets the tooltip for a column.
181 * @param {Number} col The column index
182 * @param {String} tooltip The new tooltip
183 */
184 setColumnTooltip : function(col, header){
185 this.config[col].tooltip = tooltip;
186 },
187
188 /**
189 * Returns the dataIndex for the specified column.
190 * @param {Number} col The column index
191 * @return {Number}
192 */
193 getDataIndex : function(col){
194 if(typeof this.config[col].dataIndex != 'number'){
195 return col;
196 }
197 return this.config[col].dataIndex;
198 },
199
200 /**
201 * Sets the dataIndex for a column.
202 * @param {Number} col The column index
203 * @param {Number} dataIndex The new dataIndex
204 */
205 setDataIndex : function(col, dataIndex){
206 this.config[col].dataIndex = dataIndex;
207 },
208 /**
209 * Returns true if the cell is editable.
210 * @param {Number} colIndex The column index
211 * @param {Number} rowIndex The row index
212 * @return {Boolean}
213 */
214 isCellEditable : function(colIndex, rowIndex){
215 return this.config[colIndex].editable || (typeof this.config[colIndex].editable == 'undefined' && this.config[colIndex].editor);
216 },
217
218 /**
219 * Returns the editor defined for the cell/column.
220 * @param {Number} colIndex The column index
221 * @param {Number} rowIndex The row index
222 * @return {Object}
223 */
224 getCellEditor : function(colIndex, rowIndex){
225 return this.config[colIndex].editor;
226 },
227
228 /**
229 * Sets if a column is editable.
230 * @param {Number} col The column index
231 * @param {Boolean} editable True if the column is editable
232 */
233 setEditable : function(col, editable){
234 this.config[col].editable = editable;
235 },
236
237
238 /**
239 * Returns true if the column is hidden.
240 * @param {Number} colIndex The column index
241 * @return {Boolean}
242 */
243 isHidden : function(colIndex){
244 return this.config[colIndex].hidden;
245 },
246
247
248 /**
249 * Returns true if the column width cannot be changed
250 */
251 isFixed : function(colIndex){
252 return this.config[colIndex].fixed;
253 },
254
255 /**
256 * Returns true if the column cannot be resized
257 * @return {Boolean}
258 */
259 isResizable : function(colIndex){
260 return this.config[colIndex].resizable !== false;
261 },
262 /**
263 * Sets if a column is hidden.
264 * @param {Number} colIndex The column index
265 */
266 setHidden : function(colIndex, hidden){
267 this.config[colIndex].hidden = hidden;
268 this.totalWidth = null;
269 this.fireHiddenChange(colIndex, hidden);
270 },
271
272 /**
273 * Sets the editor for a column.
274 * @param {Number} col The column index
275 * @param {Object} editor The editor object
276 */
277 setEditor : function(col, editor){
278 this.config[col].editor = editor;
279 }
280});
281
282/**
283 * Defines the default sorting (casting?) comparison functions used when sorting data:
284 * <br>&nbsp;&nbsp;sortTypes.none - sorts data as it is without casting or parsing (the default)
285 * <br>&nbsp;&nbsp;sortTypes.asUCString - case insensitive string
286 * <br>&nbsp;&nbsp;sortTypes.asDate - attempts to parse data as a date
287 * <br>&nbsp;&nbsp;sortTypes.asFloat
288 * <br>&nbsp;&nbsp;sortTypes.asInt
289 * @static
290 */
291YAHOO.ext.grid.DefaultColumnModel.sortTypes = {
292 none : function(s) {
293 return s;
294 },
295
296 asUCString : function(s) {
297 return String(s).toUpperCase();
298 },
299
300 asDate : function(s) {
301 if(s instanceof Date){
302 return s.getTime();
303 }
304 return Date.parse(String(s));
305 },
306
307 asFloat : function(s) {
308 var val = parseFloat(String(s).replace(/,/g, ''));
309 if(isNaN(val)) val = 0;
310 return val;
311 },
312
313 asInt : function(s) {
314 var val = parseInt(String(s).replace(/,/g, ''));
315 if(isNaN(val)) val = 0;
316 return val;
317 }
318};
319
320YAHOO.ext.grid.DefaultColumnModel.defaultRenderer = function(value){
321 if(typeof value == 'string' && value.length < 1){
322 return '&#160;';
323 }
324 return value;
325}
diff --git a/frontend/beta/js/YUI-extensions/grid/EditorGrid.js b/frontend/beta/js/YUI-extensions/grid/EditorGrid.js
new file mode 100644
index 0000000..e7405a0
--- a/dev/null
+++ b/frontend/beta/js/YUI-extensions/grid/EditorGrid.js
@@ -0,0 +1,16 @@
1/**
2 * @class YAHOO.ext.grid.EditorGrid
3 * @extends YAHOO.ext.grid.Grid
4 * Shortcut class for creating and editable grid.
5 * @param {String/HTMLElement/YAHOO.ext.Element} container The element into which this grid will be rendered -
6 * The container MUST have some type of size defined for the grid to fill. The container will be
7 * automatically set to position relative if it isn't already.
8 * @param {Object} dataModel The data model to bind to
9 * @param {Object} colModel The column model with info about this grid's columns
10 */
11YAHOO.ext.grid.EditorGrid = function(container, dataModel, colModel){
12 YAHOO.ext.grid.EditorGrid.superclass.constructor.call(this, container, dataModel,
13 colModel, new YAHOO.ext.grid.EditorSelectionModel());
14 this.container.addClass('yeditgrid');
15};
16YAHOO.extendX(YAHOO.ext.grid.EditorGrid, YAHOO.ext.grid.Grid);
diff --git a/frontend/beta/js/YUI-extensions/grid/EditorSelectionModel.js b/frontend/beta/js/YUI-extensions/grid/EditorSelectionModel.js
new file mode 100644
index 0000000..c1cb240
--- a/dev/null
+++ b/frontend/beta/js/YUI-extensions/grid/EditorSelectionModel.js
@@ -0,0 +1,182 @@
1
2/**
3 @class YAHOO.ext.grid.EditorSelectionModel
4 * Extends {@link YAHOO.ext.grid.DefaultSelectionModel} to enable cell navigation. <br><br>
5 @extends YAHOO.ext.grid.DefaultSelectionModel
6 @constructor
7 */
8YAHOO.ext.grid.EditorSelectionModel = function(){
9 YAHOO.ext.grid.EditorSelectionModel.superclass.constructor.call(this);
10 /** Number of clicks to activate a cell (for editing) - valid values are 1 or 2
11 * @type Number */
12 this.clicksToActivateCell = 1;
13 this.events['cellactivate'] = new YAHOO.util.CustomEvent('cellactivate');
14};
15
16YAHOO.extendX(YAHOO.ext.grid.EditorSelectionModel, YAHOO.ext.grid.DefaultSelectionModel);
17
18YAHOO.ext.grid.EditorSelectionModel.prototype.disableArrowNavigation = false;
19YAHOO.ext.grid.EditorSelectionModel.prototype.controlForArrowNavigation = false;
20
21/** @ignore */
22YAHOO.ext.grid.EditorSelectionModel.prototype.initEvents = function(){
23 this.grid.addListener("cellclick", this.onCellClick, this, true);
24 this.grid.addListener("celldblclick", this.onCellDblClick, this, true);
25 this.grid.addListener("keydown", this.keyDown, this, true);
26};
27
28YAHOO.ext.grid.EditorSelectionModel.prototype.onCellClick = function(grid, rowIndex, colIndex){
29 if(this.clicksToActivateCell == 1){
30 var row = this.grid.getRow(rowIndex);
31 var cell = row.childNodes[colIndex];
32 if(cell){
33 this.activate(row, cell);
34 }
35 }
36};
37
38YAHOO.ext.grid.EditorSelectionModel.prototype.activate = function(row, cell){
39 this.fireEvent('cellactivate', this, row, cell);
40 this.grid.doEdit(row, cell);
41};
42
43YAHOO.ext.grid.EditorSelectionModel.prototype.onCellDblClick = function(grid, rowIndex, colIndex){
44 if(this.clicksToActivateCell == 2){
45 var row = this.grid.getRow(rowIndex);
46 var cell = row.childNodes[colIndex];
47 if(cell){
48 this.activate(row, cell);
49 }
50 }
51};
52
53/** @ignore */
54YAHOO.ext.grid.EditorSelectionModel.prototype.setRowState = function(row, selected){
55 YAHOO.ext.grid.EditorSelectionModel.superclass.setRowState.call(this, row, false, false);
56};
57/** @ignore */
58YAHOO.ext.grid.EditorSelectionModel.prototype.focusRow = function(row, selected){
59};
60
61YAHOO.ext.grid.EditorSelectionModel.prototype.getEditorCellAfter = function(cell, spanRows){
62 var g = this.grid;
63 var next = g.getCellAfter(cell);
64 while(next && !g.colModel.isCellEditable(next.columnIndex)){
65 next = g.getCellAfter(next);
66 }
67 if(!next && spanRows){
68 var row = g.getRowAfter(g.getRowFromChild(cell));
69 if(row){
70 next = g.getFirstCell(row);
71 if(!g.colModel.isCellEditable(next.columnIndex)){
72 next = this.getEditorCellAfter(next);
73 }
74 }
75 }
76 return next;
77};
78
79YAHOO.ext.grid.EditorSelectionModel.prototype.getEditorCellBefore = function(cell, spanRows){
80 var g = this.grid;
81 var prev = g.getCellBefore(cell);
82 while(prev && !g.colModel.isCellEditable(prev.columnIndex)){
83 prev = g.getCellBefore(prev);
84 }
85 if(!prev && spanRows){
86 var row = g.getRowBefore(g.getRowFromChild(cell));
87 if(row){
88 prev = g.getLastCell(row);
89 if(!g.colModel.isCellEditable(prev.columnIndex)){
90 prev = this.getEditorCellBefore(prev);
91 }
92 }
93 }
94 return prev;
95};
96
97YAHOO.ext.grid.EditorSelectionModel.prototype.allowArrowNav = function(e){
98 return (!this.disableArrowNavigation && (!this.controlForArrowNavigation || e.ctrlKey));
99}
100/** @ignore */
101YAHOO.ext.grid.EditorSelectionModel.prototype.keyDown = function(e){
102 var g = this.grid, cm = g.colModel, cell = g.getEditingCell();
103 if(!cell) return;
104 var newCell;
105 switch(e.browserEvent.keyCode){
106 case e.TAB:
107 if(e.shiftKey){
108 newCell = this.getEditorCellBefore(cell, true);
109 }else{
110 newCell = this.getEditorCellAfter(cell, true);
111 }
112 e.preventDefault();
113 break;
114 case e.DOWN:
115 if(this.allowArrowNav(e)){
116 var next = g.getRowAfter(g.getRowFromChild(cell));
117 if(next){
118 newCell = next.childNodes[cell.columnIndex];
119 }
120 }
121 break;
122 case e.UP:
123 if(this.allowArrowNav(e)){
124 var prev = g.getRowBefore(g.getRowFromChild(cell));
125 if(prev){
126 newCell = prev.childNodes[cell.columnIndex];
127 }
128 }
129 break;
130 case e.RETURN:
131 if(e.shiftKey){
132 var prev = g.getRowBefore(g.getRowFromChild(cell));
133 if(prev){
134 newCell = prev.childNodes[cell.columnIndex];
135 }
136 }else{
137 var next = g.getRowAfter(g.getRowFromChild(cell));
138 if(next){
139 newCell = next.childNodes[cell.columnIndex];
140 }
141 }
142 break;
143 case e.RIGHT:
144 if(this.allowArrowNav(e)){
145 newCell = this.getEditorCellAfter(cell);
146 }
147 break;
148 case e.LEFT:
149 if(this.allowArrowNav(e)){
150 newCell = this.getEditorCellBefore(cell);
151 }
152 break;
153 };
154 if(newCell){
155 this.activate(g.getRowFromChild(newCell), newCell);
156 e.stopEvent();
157 }
158};
159
160/**
161 * @class YAHOO.ext.grid.EditorAndSelectionModel
162 */
163YAHOO.ext.grid.EditorAndSelectionModel = function(){
164 YAHOO.ext.grid.EditorAndSelectionModel.superclass.constructor.call(this);
165 this.events['cellactivate'] = new YAHOO.util.CustomEvent('cellactivate');
166};
167
168YAHOO.extendX(YAHOO.ext.grid.EditorAndSelectionModel, YAHOO.ext.grid.DefaultSelectionModel);
169
170YAHOO.ext.grid.EditorAndSelectionModel.prototype.initEvents = function(){
171 YAHOO.ext.grid.EditorAndSelectionModel.superclass.initEvents.call(this);
172 this.grid.addListener("celldblclick", this.onCellDblClick, this, true);
173};
174
175YAHOO.ext.grid.EditorAndSelectionModel.prototype.onCellDblClick = function(grid, rowIndex, colIndex){
176 var row = this.grid.getRow(rowIndex);
177 var cell = row.childNodes[colIndex];
178 if(cell){
179 this.fireEvent('cellactivate', this, row, cell);
180 this.grid.doEdit(row, cell);
181 }
182};
diff --git a/frontend/beta/js/YUI-extensions/grid/Grid.js b/frontend/beta/js/YUI-extensions/grid/Grid.js
new file mode 100644
index 0000000..46d5de4
--- a/dev/null
+++ b/frontend/beta/js/YUI-extensions/grid/Grid.js
@@ -0,0 +1,965 @@
1/**
2 * @class YAHOO.ext.grid.Grid
3 * @extends YAHOO.ext.util.Observable
4 * This class represents the primary interface of a component based grid control.
5 * <br><br>Usage:<pre><code>
6 var grid = new YAHOO.ext.grid.Grid('my-container-id', dataModel, columnModel);
7 // set any options
8 grid.render();
9 // or using a config
10 var grid = new YAHOO.ext.grid.Grid('my-container-id', {
11 dataModel: myDataModel,
12 colModel: myColModel,
13 selModel: mySelectionModel,
14 autoSizeColumns: true,
15 monitorWindowResize: false,
16 trackMouseOver: true
17 }).render();
18 * </code></pre>
19 * <b>Common Problems:</b><br/>
20 * - Grid does not resize properly when going smaller: Setting overflow hidden on the container
21 * element will correct this<br/>
22 * - If you get el.style[camel]= NaNpx or -2px or something related, be certain you have given your container element
23 * dimensions. The grid adapts to your container's size, if your container has no size defined then the results
24 * are unpredictable.<br/>
25 * - Do not render the grid into an element with display:none. Try using visibility:hidden. Otherwise there is no way for the
26 * grid to calculate dimensions/offsets.<br/>
27 * @requires YAHOO.util.Dom
28 * @requires YAHOO.util.Event
29 * @requires YAHOO.util.CustomEvent
30 * @requires YAHOO.ext.Element
31 * @requires YAHOO.ext.util.Browser
32 * @requires YAHOO.ext.util.CSS
33 * @requires YAHOO.ext.SplitBar
34 * @requires YAHOO.ext.EventObject
35 * @constructor
36 * @param {String/HTMLElement/YAHOO.ext.Element} container The element into which this grid will be rendered -
37 * The container MUST have some type of size defined for the grid to fill. The container will be
38 * automatically set to position relative if it isn't already.
39 * @param {Object} config A config object that sets properties on this grid OR the data model to bind to
40 * @param {Object} colModel (optional) The column model with info about this grid's columns
41 * @param {Object} selectionModel (optional) The selection model for this grid (defaults to DefaultSelectionModel)
42 */
43YAHOO.ext.grid.Grid = function(container, config, colModel, selectionModel){
44 /** @private */
45 this.container = YAHOO.ext.Element.get(container);
46 this.container.update('');
47 this.container.setStyle('overflow', 'hidden');
48 this.id = this.container.id;
49 this.rows = [];
50 this.rowCount = 0;
51 this.fieldId = null;
52 var dataModel = config; // for legacy pre config support
53 this.dataModel = dataModel;
54 this.colModel = colModel;
55 this.selModel = selectionModel;
56 this.activeEditor = null;
57 this.editingCell = null;
58
59
60 if(typeof config == 'object' && !config.getRowCount){// must be config object
61 YAHOO.ext.util.Config.apply(this, config);
62 }
63
64 /** @private */
65 this.setValueDelegate = this.setCellValue.createDelegate(this);
66
67 /** @private */
68 this.events = {
69 // raw events
70 /**
71 * @event click
72 * The raw click event for the entire grid.
73 * @param {YAHOO.ext.EventObject} e
74 */
75 'click' : true,
76 /**
77 * @event dblclick
78 * The raw dblclick event for the entire grid.
79 * @param {YAHOO.ext.EventObject} e
80 */
81 'dblclick' : true,
82 /**
83 * @event mousedown
84 * The raw mousedown event for the entire grid.
85 * @param {YAHOO.ext.EventObject} e
86 */
87 'mousedown' : true,
88 /**
89 * @event mouseup
90 * The raw mouseup event for the entire grid.
91 * @param {YAHOO.ext.EventObject} e
92 */
93 'mouseup' : true,
94 /**
95 * @event mouseover
96 * The raw mouseover event for the entire grid.
97 * @param {YAHOO.ext.EventObject} e
98 */
99 'mouseover' : true,
100 /**
101 * @event mouseout
102 * The raw mouseout event for the entire grid.
103 * @param {YAHOO.ext.EventObject} e
104 */
105 'mouseout' : true,
106 /**
107 * @event keypress
108 * The raw keypress event for the entire grid.
109 * @param {YAHOO.ext.EventObject} e
110 */
111 'keypress' : true,
112 /**
113 * @event keydown
114 * The raw keydown event for the entire grid.
115 * @param {YAHOO.ext.EventObject} e
116 */
117 'keydown' : true,
118
119 // custom events
120
121 /**
122 * @event cellclick
123 * Fires when a cell is clicked
124 * @param {Grid} this
125 * @param {Number} rowIndex
126 * @param {Number} columnIndex
127 * @param {YAHOO.ext.EventObject} e
128 */
129 'cellclick' : true,
130 /**
131 * @event celldblclick
132 * Fires when a cell is double clicked
133 * @param {Grid} this
134 * @param {Number} rowIndex
135 * @param {Number} columnIndex
136 * @param {YAHOO.ext.EventObject} e
137 */
138 'celldblclick' : true,
139 /**
140 * @event rowclick
141 * Fires when a row is clicked
142 * @param {Grid} this
143 * @param {Number} rowIndex
144 * @param {YAHOO.ext.EventObject} e
145 */
146 'rowclick' : true,
147 /**
148 * @event rowdblclick
149 * Fires when a row is double clicked
150 * @param {Grid} this
151 * @param {Number} rowIndex
152 * @param {YAHOO.ext.EventObject} e
153 */
154 'rowdblclick' : true,
155 /**
156 * @event headerclick
157 * Fires when a header is clicked
158 * @param {Grid} this
159 * @param {Number} columnIndex
160 * @param {YAHOO.ext.EventObject} e
161 */
162 'headerclick' : true,
163 /**
164 * @event rowcontextmenu
165 * Fires when a row is right clicked
166 * @param {Grid} this
167 * @param {Number} rowIndex
168 * @param {YAHOO.ext.EventObject} e
169 */
170 'rowcontextmenu' : true,
171 /**
172 * @event cellcontextmenu
173 * Fires when a cell is right clicked
174 * @param {Grid} this
175 * @param {Number} rowIndex
176 * @param {Number} cellIndex
177 * @param {YAHOO.ext.EventObject} e
178 */
179 'cellcontextmenu' : true,
180 /**
181 * @event headercontextmenu
182 * Fires when a header is right clicked
183 * @param {Grid} this
184 * @param {Number} columnIndex
185 * @param {YAHOO.ext.EventObject} e
186 */
187 'headercontextmenu' : true,
188 /**
189 * @event beforeedit
190 * Fires before a cell is edited
191 * @param {Grid} this
192 * @param {Number} rowIndex
193 * @param {Number} columnIndex
194 */
195 'beforeedit' : true,
196 /**
197 * @event afteredit
198 * Fires after a cell is edited
199 * @param {Grid} this
200 * @param {Number} rowIndex
201 * @param {Number} columnIndex
202 */
203 'afteredit' : true,
204 /**
205 * @event bodyscroll
206 * Fires when the body element is scrolled
207 * @param {Number} scrollLeft
208 * @param {Number} scrollTop
209 */
210 'bodyscroll' : true,
211 /**
212 * @event columnresize
213 * Fires when the user resizes a column
214 * @param {Number} columnIndex
215 * @param {Number} newSize
216 */
217 'columnresize' : true,
218 /**
219 * @event startdrag
220 * Fires when row(s) start being dragged
221 * @param {Grid} this
222 * @param {YAHOO.ext.GridDD} dd The drag drop object
223 * @param {event} e The raw browser event
224 */
225 'startdrag' : true,
226 /**
227 * @event enddrag
228 * Fires when a drag operation is complete
229 * @param {Grid} this
230 * @param {YAHOO.ext.GridDD} dd The drag drop object
231 * @param {event} e The raw browser event
232 */
233 'enddrag' : true,
234 /**
235 * @event dragdrop
236 * Fires when dragged row(s) are dropped on a valid DD target
237 * @param {Grid} this
238 * @param {YAHOO.ext.GridDD} dd The drag drop object
239 * @param {String} targetId The target drag drop object
240 * @param {event} e The raw browser event
241 */
242 'dragdrop' : true,
243 /**
244 * @event dragover
245 * Fires while row(s) are being dragged. "targetId" is the id of the Yahoo.util.DD object the selected rows are being dragged over.
246 * @param {Grid} this
247 * @param {YAHOO.ext.GridDD} dd The drag drop object
248 * @param {String} targetId The target drag drop object
249 * @param {event} e The raw browser event
250 */
251 'dragover' : true,
252 /**
253 * @event dragenter
254 * Fires when the dragged row(s) first cross another DD target while being dragged
255 * @param {Grid} this
256 * @param {YAHOO.ext.GridDD} dd The drag drop object
257 * @param {String} targetId The target drag drop object
258 * @param {event} e The raw browser event
259 */
260 'dragenter' : true,
261 /**
262 * @event dragout
263 * Fires when the dragged row(s) leave another DD target while being dragged
264 * @param {Grid} this
265 * @param {YAHOO.ext.GridDD} dd The drag drop object
266 * @param {String} targetId The target drag drop object
267 * @param {event} e The raw browser event
268 */
269 'dragout' : true
270 };
271};
272
273YAHOO.ext.grid.Grid.prototype = {
274 /** The minimum width a column can be resized to. (Defaults to 25)
275 * @type Number */
276 minColumnWidth : 25,
277
278 /** True to automatically resize the columns to fit their content <b>on initial render</b>
279 * @type Boolean */
280 autoSizeColumns : false,
281
282 /** True to measure headers with column data when auto sizing columns
283 * @type Boolean */
284 autoSizeHeaders : false,
285
286 /**
287 * True to autoSize the grid when the window resizes - defaults to true
288 */
289 monitorWindowResize : true,
290
291 /** If autoSizeColumns is on, maxRowsToMeasure can be used to limit the number of
292 * rows measured to get a columns size - defaults to 0 (all rows).
293 * @type Number */
294 maxRowsToMeasure : 0,
295
296 /** True to highlight rows when the mouse is over (default is false)
297 * @type Boolean */
298 trackMouseOver : false,
299
300 /** True to enable drag and drop of rows
301 * @type Boolean */
302 enableDragDrop : false,
303
304 /** True to stripe the rows (default is true)
305 * @type Boolean */
306 stripeRows : true,
307 /** True to fit the height of the grid container to the height of the data (defaults to false)
308 * @type Boolean */
309 autoHeight : false,
310
311 /** True to fit the width of the grid container to the width of the columns (defaults to false)
312 * @type Boolean */
313 autoWidth : false,
314
315 /**
316 * The view used by the grid. This can be set before a call to render().
317 * Defaults to a YAHOO.ext.grid.GridView or PagedGridView depending on the data model.
318 * @type Object
319 */
320 view : null,
321
322 /** A regular expression defining tagNames
323 * allowed to have text selection (Defaults to <code>/INPUT|TEXTAREA|SELECT/i</code>) */
324 allowTextSelectionPattern : /INPUT|TEXTAREA|SELECT/i,
325
326 /**
327 * Called once after all setup has been completed and the grid is ready to be rendered.
328 * @return {YAHOO.ext.grid.Grid} this
329 */
330 render : function(){
331 if((!this.container.dom.offsetHeight || this.container.dom.offsetHeight < 20)
332 || this.container.getStyle('height') == 'auto'){
333 this.autoHeight = true;
334 }
335 if((!this.container.dom.offsetWidth || this.container.dom.offsetWidth < 20)){
336 this.autoWidth = true;
337 }
338 if(!this.view){
339 if(this.dataModel.isPaged()){
340 this.view = new YAHOO.ext.grid.PagedGridView();
341 }else{
342 this.view = new YAHOO.ext.grid.GridView();
343 }
344 }
345 this.view.init(this);
346 this.el = getEl(this.view.render(), true);
347 var c = this.container;
348 c.mon("click", this.onClick, this, true);
349 c.mon("dblclick", this.onDblClick, this, true);
350 c.mon("contextmenu", this.onContextMenu, this, true);
351 c.mon("selectstart", this.cancelTextSelection, this, true);
352 c.mon("mousedown", this.cancelTextSelection, this, true);
353 c.mon("mousedown", this.onMouseDown, this, true);
354 c.mon("mouseup", this.onMouseUp, this, true);
355 if(this.trackMouseOver){
356 this.el.mon("mouseover", this.onMouseOver, this, true);
357 this.el.mon("mouseout", this.onMouseOut, this, true);
358 }
359 c.mon("keypress", this.onKeyPress, this, true);
360 c.mon("keydown", this.onKeyDown, this, true);
361 this.init();
362 return this;
363 },
364
365 init : function(){
366 this.rows = this.el.dom.rows;
367 if(!this.disableSelection){
368 if(!this.selModel){
369 this.selModel = new YAHOO.ext.grid.DefaultSelectionModel(this);
370 }
371 this.selModel.init(this);
372 this.selModel.onSelectionChange.subscribe(this.updateField, this, true);
373 }else{
374 this.selModel = new YAHOO.ext.grid.DisableSelectionModel(this);
375 this.selModel.init(this);
376 }
377
378 if(this.enableDragDrop){
379 this.dd = new YAHOO.ext.grid.GridDD(this, this.container.dom);
380 }
381 },
382
383 /**
384 * Resets the grid for use with a new configuration and/or data and column models. After calling this function
385 * you will need to call render() again. Any listeners for this grid will be retained.
386 * Warning: any listeners manually attached (not through the grid) to the grid's container
387 * element will be removed.
388 * @param {Object} config Standard config object with properties to set on this grid
389 * @return {YAHOO.ext.grid.Grid} this
390 */
391 reset : function(config){
392 this.destroy(false, true);
393 YAHOO.ext.util.Config.apply(this, config);
394 return this;
395 },
396
397 /**
398 * Destroy this grid.
399 * @param {Boolean} removeEl True to remove the element
400 */
401 destroy : function(removeEl, keepListeners){
402 var c = this.container;
403 c.removeAllListeners();
404 this.view.destroy();
405 YAHOO.ext.EventManager.removeResizeListener(this.view.onWindowResize, this.view);
406 this.view = null;
407 this.colModel.purgeListeners();
408 if(!keepListeners){
409 this.purgeListeners();
410 }
411 c.update('');
412 if(removeEl === true){
413 c.remove();
414 }
415 },
416
417 /**
418 * Replace the current data model with a new one (experimental)
419 * @param {DataModel} dm The new data model
420 * @pram {Boolean} rerender true to render the grid rows from scratch
421 */
422 setDataModel : function(dm, rerender){
423 this.view.unplugDataModel(this.dataModel);
424 this.dataModel = dm;
425 this.view.plugDataModel(dm);
426 if(rerender){
427 dm.fireEvent('datachanged');
428 }
429 },
430
431 onMouseDown : function(e){
432 this.fireEvent('mousedown', e);
433 },
434
435 onMouseUp : function(e){
436 this.fireEvent('mouseup', e);
437 },
438
439 onMouseOver : function(e){
440 this.fireEvent('mouseover', e);
441 },
442
443 onMouseOut : function(e){
444 this.fireEvent('mouseout', e);
445 },
446
447 onKeyPress : function(e){
448 this.fireEvent('keypress', e);
449 },
450
451 onKeyDown : function(e){
452 this.fireEvent('keydown', e);
453 },
454
455 fireEvent : YAHOO.ext.util.Observable.prototype.fireEvent,
456 on : YAHOO.ext.util.Observable.prototype.on,
457 addListener : YAHOO.ext.util.Observable.prototype.addListener,
458 delayedListener : YAHOO.ext.util.Observable.prototype.delayedListener,
459 removeListener : YAHOO.ext.util.Observable.prototype.removeListener,
460 purgeListeners : YAHOO.ext.util.Observable.prototype.purgeListeners,
461 bufferedListener : YAHOO.ext.util.Observable.prototype.bufferedListener,
462
463 onClick : function(e){
464 this.fireEvent('click', e);
465 var target = e.getTarget();
466 var row = this.getRowFromChild(target);
467 var cell = this.getCellFromChild(target);
468 var header = this.getHeaderFromChild(target);
469 if(cell){
470 this.fireEvent('cellclick', this, row.rowIndex, cell.columnIndex, e);
471 }
472 if(row){
473 this.fireEvent('rowclick', this, row.rowIndex, e);
474 }
475 if(header){
476 this.fireEvent('headerclick', this, header.columnIndex, e);
477 }
478 },
479
480 onContextMenu : function(e){
481 var target = e.getTarget();
482 var row = this.getRowFromChild(target);
483 var cell = this.getCellFromChild(target);
484 var header = this.getHeaderFromChild(target);
485 if(cell){
486 this.fireEvent('cellcontextmenu', this, row.rowIndex, cell.columnIndex, e);
487 }
488 if(row){
489 this.fireEvent('rowcontextmenu', this, row.rowIndex, e);
490 }
491 if(header){
492 this.fireEvent('headercontextmenu', this, header.columnIndex, e);
493 }
494 e.preventDefault();
495 },
496
497 onDblClick : function(e){
498 this.fireEvent('dblclick', e);
499 var target = e.getTarget();
500 var row = this.getRowFromChild(target);
501 var cell = this.getCellFromChild(target);
502 if(row){
503 this.fireEvent('rowdblclick', this, row.rowIndex, e);
504 }
505 if(cell){
506 this.fireEvent('celldblclick', this, row.rowIndex, cell.columnIndex, e);
507 }
508 },
509
510 /**
511 * Starts editing the specified for the specified row/column
512 * @param {Number} rowIndex
513 * @param {Number} colIndex
514 */
515 startEditing : function(rowIndex, colIndex){
516 var row = this.rows[rowIndex];
517 var cell = row.childNodes[colIndex];
518 this.stopEditing();
519 setTimeout(this.doEdit.createDelegate(this, [row, cell]), 10);
520 },
521
522 /**
523 * Stops any active editing
524 */
525 stopEditing : function(){
526 if(this.activeEditor){
527 this.activeEditor.stopEditing();
528 }
529 },
530
531 /** @ignore */
532 doEdit : function(row, cell){
533 if(!row || !cell) return;
534 var cm = this.colModel;
535 var dm = this.dataModel;
536 var colIndex = cell.columnIndex;
537 var rowIndex = row.rowIndex;
538 if(cm.isCellEditable(colIndex, rowIndex)){
539 var ed = cm.getCellEditor(colIndex, rowIndex);
540 if(ed){
541 if(this.activeEditor){
542 this.activeEditor.stopEditing();
543 }
544 this.fireEvent('beforeedit', this, rowIndex, colIndex);
545 this.activeEditor = ed;
546 this.editingCell = cell;
547 this.view.ensureVisible(row, true);
548 try{
549 cell.focus();
550 }catch(e){}
551 ed.init(this, this.el.dom.parentNode, this.setValueDelegate);
552 var value = dm.getValueAt(rowIndex, cm.getDataIndex(colIndex));
553 // set timeout so firefox stops editing before starting a new edit
554 setTimeout(ed.startEditing.createDelegate(ed, [value, row, cell]), 1);
555 }
556 }
557 },
558
559 setCellValue : function(value, rowIndex, colIndex){
560 this.dataModel.setValueAt(value, rowIndex, this.colModel.getDataIndex(colIndex));
561 this.fireEvent('afteredit', this, rowIndex, colIndex);
562 },
563
564 /** @ignore Called when text selection starts or mousedown to prevent default */
565 cancelTextSelection : function(e){
566 var target = e.getTarget();
567 if(target && target != this.el.dom.parentNode && !this.allowTextSelectionPattern.test(target.tagName)){
568 e.preventDefault();
569 }
570 },
571
572 /**
573 * Causes the grid to manually recalculate it's dimensions. Generally this is done automatically,
574 * but if manual update is required this method will initiate it.
575 */
576 autoSize : function(){
577 this.view.updateWrapHeight();
578 this.view.adjustForScroll();
579 },
580
581 /**
582 * Scrolls the grid to the specified row
583 * @param {Number/HTMLElement} row The row object or index of the row
584 */
585 scrollTo : function(row){
586 if(typeof row == 'number'){
587 row = this.rows[row];
588 }
589 this.view.ensureVisible(row, true);
590 },
591
592 /** @private */
593 getEditingCell : function(){
594 return this.editingCell;
595 },
596
597 /**
598 * Binds this grid to the field with the specified id. Initially reads and parses the comma
599 * delimited ids in the field and selects those items. All selections made in the grid
600 * will be persisted to the field by their ids comma delimited.
601 * @param {String} The id of the field to bind to
602 */
603 bindToField : function(fieldId){
604 this.fieldId = fieldId;
605 this.readField();
606 },
607
608 /** @private */
609 updateField : function(){
610 if(this.fieldId){
611 var field = YAHOO.util.Dom.get(this.fieldId);
612 field.value = this.getSelectedRowIds().join(',');
613 }
614 },
615
616 /**
617 * Causes the grid to read and select the ids from the bound field - See {@link #bindToField}.
618 */
619 readField : function(){
620 if(this.fieldId){
621 var field = YAHOO.util.Dom.get(this.fieldId);
622 var values = field.value.split(',');
623 var rows = this.getRowsById(values);
624 this.selModel.selectRows(rows, false);
625 }
626 },
627
628 /**
629 * Returns the table row at the specified index
630 * @param {Number} index
631 * @return {HTMLElement}
632 */
633 getRow : function(index){
634 return this.rows[index];
635 },
636
637 /**
638 * Returns the rows that have the specified id(s). The id value for a row is provided
639 * by the DataModel. See {@link YAHOO.ext.grid.DefaultDataModel#getRowId}.
640 * @param {String/Array} An id to find or an array of ids
641 * @return {HtmlElement/Array} If one id was passed in, it returns one result.
642 * If an array of ids was specified, it returns an Array of HTMLElements
643 */
644 getRowsById : function(id){
645 var dm = this.dataModel;
646 if(!(id instanceof Array)){
647 for(var i = 0; i < this.rows.length; i++){
648 if(dm.getRowId(i) == id){
649 return this.rows[i];
650 }
651 }
652 return null;
653 }
654 var found = [];
655 var re = "^(?:";
656 for(var i = 0; i < id.length; i++){
657 re += id[i];
658 if(i != id.length-1) re += "|";
659 }
660 var regex = new RegExp(re + ")$");
661 for(var i = 0; i < this.rows.length; i++){
662 if(regex.test(dm.getRowId(i))){
663 found.push(this.rows[i]);
664 }
665 }
666 return found;
667 },
668
669 /**
670 * Returns the row that comes after the specified row - text nodes are skipped.
671 * @param {HTMLElement} row
672 * @return {HTMLElement}
673 */
674 getRowAfter : function(row){
675 return this.getSibling('next', row);
676 },
677
678 /**
679 * Returns the row that comes before the specified row - text nodes are skipped.
680 * @param {HTMLElement} row
681 * @return {HTMLElement}
682 */
683 getRowBefore : function(row){
684 return this.getSibling('previous', row);
685 },
686
687 /**
688 * Returns the cell that comes after the specified cell - text nodes are skipped.
689 * @param {HTMLElement} cell
690 * @param {Boolean} includeHidden
691 * @return {HTMLElement}
692 */
693 getCellAfter : function(cell, includeHidden){
694 var next = this.getSibling('next', cell);
695 if(next && !includeHidden && this.colModel.isHidden(next.columnIndex)){
696 return this.getCellAfter(next);
697 }
698 return next;
699 },
700
701 /**
702 * Returns the cell that comes before the specified cell - text nodes are skipped.
703 * @param {HTMLElement} cell
704 * @param {Boolean} includeHidden
705 * @return {HTMLElement}
706 */
707 getCellBefore : function(cell, includeHidden){
708 var prev = this.getSibling('previous', cell);
709 if(prev && !includeHidden && this.colModel.isHidden(prev.columnIndex)){
710 return this.getCellBefore(prev);
711 }
712 return prev;
713 },
714
715 /**
716 * Returns the last cell for the row - text nodes and hidden columns are skipped.
717 * @param {HTMLElement} row
718 * @param {Boolean} includeHidden
719 * @return {HTMLElement}
720 */
721 getLastCell : function(row, includeHidden){
722 var cell = this.getElement('previous', row.lastChild);
723 if(cell && !includeHidden && this.colModel.isHidden(cell.columnIndex)){
724 return this.getCellBefore(cell);
725 }
726 return cell;
727 },
728
729 /**
730 * Returns the first cell for the row - text nodes and hidden columns are skipped.
731 * @param {HTMLElement} row
732 * @param {Boolean} includeHidden
733 * @return {HTMLElement}
734 */
735 getFirstCell : function(row, includeHidden){
736 var cell = this.getElement('next', row.firstChild);
737 if(cell && !includeHidden && this.colModel.isHidden(cell.columnIndex)){
738 return this.getCellAfter(cell);
739 }
740 return cell;
741 },
742
743 /**
744 * @private
745 * Gets siblings, skipping text nodes
746 * @param {String} type The direction to walk: 'next' or 'previous'
747 * @param {HTMLElement} node
748 */
749 getSibling : function(type, node){
750 if(!node) return null;
751 type += 'Sibling';
752 var n = node[type];
753 while(n && n.nodeType != 1){
754 n = n[type];
755 }
756 return n;
757 },
758
759 /**
760 * Returns node if node is an HTMLElement else walks the siblings in direction looking for
761 * a node that is an element
762 * @param {String} direction The direction to walk: 'next' or 'previous'
763 * @private
764 */
765 getElement : function(direction, node){
766 if(!node || node.nodeType == 1) return node;
767 else return this.getSibling(direction, node);
768 },
769
770 /**
771 * @private
772 */
773 getElementFromChild : function(childEl, parentClass){
774 if(!childEl || (YAHOO.util.Dom.hasClass(childEl, parentClass))){
775 return childEl;
776 }
777 var p = childEl.parentNode;
778 var b = document.body;
779 while(p && p != b){
780 if(YAHOO.util.Dom.hasClass(p, parentClass)){
781 return p;
782 }
783 p = p.parentNode;
784 }
785 return null;
786 },
787
788 /**
789 * Returns the row that contains the specified child element.
790 * @param {HTMLElement} childEl
791 * @return {HTMLElement}
792 */
793 getRowFromChild : function(childEl){
794 return this.getElementFromChild(childEl, 'ygrid-row');
795 },
796
797 /**
798 * Returns the cell that contains the specified child element.
799 * @param {HTMLElement} childEl
800 * @return {HTMLElement}
801 */
802 getCellFromChild : function(childEl){
803 return this.getElementFromChild(childEl, 'ygrid-col');
804 },
805
806
807 /**
808 * Returns the header element that contains the specified child element.
809 * @param {HTMLElement} childEl
810 * @return {HTMLElement}
811 */
812 getHeaderFromChild : function(childEl){
813 return this.getElementFromChild(childEl, 'ygrid-hd');
814 },
815
816 /**
817 * Convenience method for getSelectionModel().getSelectedRows() -
818 * See <small>{@link YAHOO.ext.grid.DefaultSelectionModel#getSelectedRows}</small> for more details.
819 * @return {Array}
820 */
821 getSelectedRows : function(){
822 return this.selModel.getSelectedRows();
823 },
824
825 /**
826 * Convenience method for getSelectionModel().getSelectedRows()[0] -
827 * See <small>{@link YAHOO.ext.grid.DefaultSelectionModel#getSelectedRows}</small> for more details.
828 * @return {HTMLElement}
829 */
830 getSelectedRow : function(){
831 if(this.selModel.hasSelection()){
832 return this.selModel.getSelectedRows()[0];
833 }
834 return null;
835 },
836
837 /**
838 * Get the selected row indexes
839 * @return {Array} Array of indexes
840 */
841 getSelectedRowIndexes : function(){
842 var a = [];
843 var rows = this.selModel.getSelectedRows();
844 for(var i = 0; i < rows.length; i++) {
845 a[i] = rows[i].rowIndex;
846 }
847 return a;
848 },
849
850 /**
851 * Gets the first selected row or -1 if none are selected
852 * @return {Number}
853 */
854 getSelectedRowIndex : function(){
855 if(this.selModel.hasSelection()){
856 return this.selModel.getSelectedRows()[0].rowIndex;
857 }
858 return -1;
859 },
860
861 /**
862 * Convenience method for getSelectionModel().getSelectedRowIds()[0] -
863 * See <small>{@link YAHOO.ext.grid.DefaultSelectionModel#getSelectedRowIds}</small> for more details.
864 * @return {String}
865 */
866 getSelectedRowId : function(){
867 if(this.selModel.hasSelection()){
868 return this.selModel.getSelectedRowIds()[0];
869 }
870 return null;
871 },
872
873 /**
874 * Convenience method for getSelectionModel().getSelectedRowIds() -
875 * See <small>{@link YAHOO.ext.grid.DefaultSelectionModel#getSelectedRowIds}</small> for more details.
876 * @return {Array}
877 */
878 getSelectedRowIds : function(){
879 return this.selModel.getSelectedRowIds();
880 },
881
882 /**
883 * Convenience method for getSelectionModel().clearSelections() -
884 * See <small>{@link YAHOO.ext.grid.DefaultSelectionModel#clearSelections}</small> for more details.
885 */
886 clearSelections : function(){
887 this.selModel.clearSelections();
888 },
889
890
891 /**
892 * Convenience method for getSelectionModel().selectAll() -
893 * See <small>{@link YAHOO.ext.grid.DefaultSelectionModel#selectAll}</small> for more details.
894 */
895 selectAll : function(){
896 this.selModel.selectAll();
897 },
898
899
900 /**
901 * Convenience method for getSelectionModel().getCount() -
902 * See <small>{@link YAHOO.ext.grid.DefaultSelectionModel#getCount}</small> for more details.
903 * @return {Number}
904 */
905 getSelectionCount : function(){
906 return this.selModel.getCount();
907 },
908
909 /**
910 * Convenience method for getSelectionModel().hasSelection() -
911 * See <small>{@link YAHOO.ext.grid.DefaultSelectionModel#hasSelection}</small> for more details.
912 * @return {Boolean}
913 */
914 hasSelection : function(){
915 return this.selModel.hasSelection();
916 },
917
918 /**
919 * Returns the grid's SelectionModel.
920 * @return {SelectionModel}
921 */
922 getSelectionModel : function(){
923 if(!this.selModel){
924 this.selModel = new DefaultSelectionModel();
925 }
926 return this.selModel;
927 },
928
929 /**
930 * Returns the grid's DataModel.
931 * @return {DataModel}
932 */
933 getDataModel : function(){
934 return this.dataModel;
935 },
936
937 /**
938 * Returns the grid's ColumnModel.
939 * @return {ColumnModel}
940 */
941 getColumnModel : function(){
942 return this.colModel;
943 },
944
945 /**
946 * Returns the grid's GridView object.
947 * @return {GridView}
948 */
949 getView : function(){
950 return this.view;
951 },
952 /**
953 * Called to get grid's drag proxy text, by default returns this.ddText.
954 * @return {String}
955 */
956 getDragDropText : function(){
957 return this.ddText.replace('%0', this.selModel.getCount());
958 }
959};
960/**
961 * Configures the text is the drag proxy (defaults to "%0 selected row(s)").
962 * %0 is replaced with the number of selected rows.
963 * @type String
964 */
965YAHOO.ext.grid.Grid.prototype.ddText = "%0 selected row(s)";
diff --git a/frontend/beta/js/YUI-extensions/grid/GridDD.js b/frontend/beta/js/YUI-extensions/grid/GridDD.js
new file mode 100644
index 0000000..cdcaf39
--- a/dev/null
+++ b/frontend/beta/js/YUI-extensions/grid/GridDD.js
@@ -0,0 +1,101 @@
1
2// kill dependency issue
3if(YAHOO.util.DDProxy){
4/**
5 * @class YAHOO.ext.grid.GridDD
6 * Custom implementation of YAHOO.util.DDProxy used internally by the grid
7 * @extends YAHOO.util.DDProxy
8 */
9YAHOO.ext.grid.GridDD = function(grid, bwrap){
10 this.grid = grid;
11 var ddproxy = document.createElement('div');
12 ddproxy.id = grid.container.id + '-ddproxy';
13 ddproxy.className = 'ygrid-drag-proxy';
14 document.body.insertBefore(ddproxy, document.body.firstChild);
15 YAHOO.util.Dom.setStyle(ddproxy, 'opacity', .80);
16 var ddicon = document.createElement('span');
17 ddicon.className = 'ygrid-drop-icon ygrid-drop-nodrop';
18 ddproxy.appendChild(ddicon);
19 var ddtext = document.createElement('span');
20 ddtext.className = 'ygrid-drag-text';
21 ddtext.innerHTML = "&#160;";
22 ddproxy.appendChild(ddtext);
23
24 this.ddproxy = ddproxy;
25 this.ddtext = ddtext;
26 this.ddicon = ddicon;
27 YAHOO.util.Event.on(bwrap, 'click', this.handleClick, this, true);
28 YAHOO.ext.grid.GridDD.superclass.constructor.call(this, bwrap.id, 'GridDD',
29 {dragElId : ddproxy.id, resizeFrame: false});
30
31 this.unlockDelegate = grid.selModel.unlock.createDelegate(grid.selModel);
32};
33YAHOO.extendX(YAHOO.ext.grid.GridDD, YAHOO.util.DDProxy);
34
35YAHOO.ext.grid.GridDD.prototype.handleMouseDown = function(e){
36 var row = this.grid.getRowFromChild(YAHOO.util.Event.getTarget(e));
37 if(!row) return;
38 if(this.grid.selModel.isSelected(row)){
39 YAHOO.ext.grid.GridDD.superclass.handleMouseDown.call(this, e);
40 }else {
41 this.grid.selModel.unlock();
42 YAHOO.ext.EventObject.setEvent(e);
43 this.grid.selModel.rowClick(this.grid, row.rowIndex, YAHOO.ext.EventObject);
44 YAHOO.ext.grid.GridDD.superclass.handleMouseDown.call(this, e);
45 this.grid.selModel.lock();
46 }
47};
48
49YAHOO.ext.grid.GridDD.prototype.handleClick = function(e){
50 if(this.grid.selModel.isLocked()){
51 setTimeout(this.unlockDelegate, 1);
52 YAHOO.util.Event.stopEvent(e);
53 }
54};
55
56/**
57 * Updates the DD visual element to allow/not allow a drop
58 * @param {Boolean} dropStatus True if drop is allowed on the target
59 */
60YAHOO.ext.grid.GridDD.prototype.setDropStatus = function(dropStatus){
61 if(dropStatus === true){
62 YAHOO.util.Dom.replaceClass(this.ddicon, 'ygrid-drop-nodrop', 'ygrid-drop-ok');
63 }else{
64 YAHOO.util.Dom.replaceClass(this.ddicon, 'ygrid-drop-ok', 'ygrid-drop-nodrop');
65 }
66};
67
68YAHOO.ext.grid.GridDD.prototype.startDrag = function(e){
69 this.ddtext.innerHTML = this.grid.getDragDropText();
70 this.setDropStatus(false);
71 this.grid.selModel.lock();
72 this.grid.fireEvent('startdrag', this.grid, this, e);
73};
74
75YAHOO.ext.grid.GridDD.prototype.endDrag = function(e){
76 YAHOO.util.Dom.setStyle(this.ddproxy, 'visibility', 'hidden');
77 this.grid.fireEvent('enddrag', this.grid, this, e);
78};
79
80YAHOO.ext.grid.GridDD.prototype.autoOffset = function(iPageX, iPageY) {
81 this.setDelta(-12, -20);
82};
83
84YAHOO.ext.grid.GridDD.prototype.onDragEnter = function(e, id) {
85 this.setDropStatus(true);
86 this.grid.fireEvent('dragenter', this.grid, this, id, e);
87};
88
89YAHOO.ext.grid.GridDD.prototype.onDragDrop = function(e, id) {
90 this.grid.fireEvent('dragdrop', this.grid, this, id, e);
91};
92
93YAHOO.ext.grid.GridDD.prototype.onDragOver = function(e, id) {
94 this.grid.fireEvent('dragover', this.grid, this, id, e);
95};
96
97YAHOO.ext.grid.GridDD.prototype.onDragOut = function(e, id) {
98 this.setDropStatus(false);
99 this.grid.fireEvent('dragout', this.grid, this, id, e);
100};
101};
diff --git a/frontend/beta/js/YUI-extensions/grid/GridView.js b/frontend/beta/js/YUI-extensions/grid/GridView.js
new file mode 100644
index 0000000..dbd47e3
--- a/dev/null
+++ b/frontend/beta/js/YUI-extensions/grid/GridView.js
@@ -0,0 +1,790 @@
1/**
2 * @class YAHOO.ext.grid.GridView
3 * Default UI code used internally by the Grid. This is the object returned by {@link YAHOO.ext.grid.Grid#getView}.
4 * @constructor
5 */
6YAHOO.ext.grid.GridView = function(){
7 this.grid = null;
8 this.lastFocusedRow = null;
9 this.onScroll = new YAHOO.util.CustomEvent('onscroll');
10 this.adjustScrollTask = new YAHOO.ext.util.DelayedTask(this._adjustForScroll, this);
11 this.ensureVisibleTask = new YAHOO.ext.util.DelayedTask();
12};
13
14YAHOO.ext.grid.GridView.prototype = {
15 init: function(grid){
16 this.grid = grid;
17 },
18
19 fireScroll: function(scrollLeft, scrollTop){
20 this.onScroll.fireDirect(this.grid, scrollLeft, scrollTop);
21 },
22
23 /**
24 * @private
25 * Utility method that gets an array of the cell renderers
26 */
27 getColumnRenderers : function(){
28 var renderers = [];
29 var cm = this.grid.colModel;
30 var colCount = cm.getColumnCount();
31 for(var i = 0; i < colCount; i++){
32 renderers.push(cm.getRenderer(i));
33 }
34 return renderers;
35 },
36
37 buildIndexMap : function(){
38 var colToData = {};
39 var dataToCol = {};
40 var cm = this.grid.colModel;
41 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
42 var di = cm.getDataIndex(i);
43 colToData[i] = di;
44 dataToCol[di] = i;
45 }
46 return {'colToData': colToData, 'dataToCol': dataToCol};
47 },
48
49 getDataIndexes : function(){
50 if(!this.indexMap){
51 this.indexMap = this.buildIndexMap();
52 }
53 return this.indexMap.colToData;
54 },
55
56 getColumnIndexByDataIndex : function(dataIndex){
57 if(!this.indexMap){
58 this.indexMap = this.buildIndexMap();
59 }
60 return this.indexMap.dataToCol[dataIndex];
61 },
62
63 updateHeaders : function(){
64 var colModel = this.grid.colModel;
65 var hcells = this.headers;
66 var colCount = colModel.getColumnCount();
67 for(var i = 0; i < colCount; i++){
68 hcells[i].textNode.innerHTML = colModel.getColumnHeader(i);
69 }
70 },
71
72 adjustForScroll : function(disableDelay){
73 if(!disableDelay){
74 this.adjustScrollTask.delay(50);
75 }else{
76 this._adjustForScroll();
77 }
78 },
79
80 /**
81 * Returns the rowIndex/columnIndex of the cell found at the passed page coordinates
82 * @param {Number} x
83 * @param {Number} y
84 * @return {Array} [rowIndex, columnIndex]
85 */
86 getCellAtPoint : function(x, y){
87 var colIndex = null;
88 var rowIndex = null;
89
90 // translate page coordinates to local coordinates
91 var xy = YAHOO.util.Dom.getXY(this.wrap);
92 x = (x - xy[0]) + this.wrap.scrollLeft;
93 y = (y - xy[1]) + this.wrap.scrollTop;
94
95 var colModel = this.grid.colModel;
96 var pos = 0;
97 var colCount = colModel.getColumnCount();
98 for(var i = 0; i < colCount; i++){
99 if(colModel.isHidden(i)) continue;
100 var width = colModel.getColumnWidth(i);
101 if(x >= pos && x < pos+width){
102 colIndex = i;
103 break;
104 }
105 pos += width;
106 }
107 if(colIndex != null){
108 rowIndex = (y == 0 ? 0 : Math.floor(y / this.getRowHeight()));
109 if(rowIndex >= this.grid.dataModel.getRowCount()){
110 return null;
111 }
112 return [colIndex, rowIndex];
113 }
114 return null;
115 },
116
117 /** @private */
118 _adjustForScroll : function(){
119 this.forceScrollUpdate();
120 if(this.scrollbarMode == YAHOO.ext.grid.GridView.SCROLLBARS_OVERLAP){
121 var adjustment = 0;
122 if(this.wrap.clientWidth && this.wrap.clientWidth !== 0){
123 adjustment = this.wrap.offsetWidth - this.wrap.clientWidth;
124 }
125 this.hwrap.setWidth(this.wrap.offsetWidth-adjustment);
126 }else{
127 this.hwrap.setWidth(this.wrap.offsetWidth);
128 }
129 this.bwrap.setWidth(Math.max(this.grid.colModel.getTotalWidth(), this.wrap.clientWidth));
130 },
131
132 /**
133 * Focuses the specified row. The preferred way to scroll to a row is {@link #ensureVisible}.
134 * @param {Number/HTMLElement} row The index of a row or the row itself
135 */
136 focusRow : function(row){
137 if(typeof row == 'number'){
138 row = this.getBodyTable().childNodes[row];
139 }
140 if(!row) return;
141 var left = this.wrap.scrollLeft;
142 try{ // try catch for IE occasional focus bug
143 row.childNodes.item(0).hideFocus = true;
144 row.childNodes.item(0).focus();
145 }catch(e){}
146 this.ensureVisible(row);
147 this.wrap.scrollLeft = left;
148 this.handleScroll();
149 this.lastFocusedRow = row;
150 },
151
152 /**
153 * Scrolls the specified row into view. This call is automatically buffered (delayed), to disable
154 * the delay, pass true for disableDelay.
155 * @param {Number/HTMLElement} row The index of a row or the row itself
156 * @param {Boolean} disableDelay
157 */
158 ensureVisible : function(row, disableDelay){
159 if(!disableDelay){
160 this.ensureVisibleTask.delay(50, this._ensureVisible, this, [row]);
161 }else{
162 this._ensureVisible(row);
163 }
164 },
165
166 /** @ignore */
167 _ensureVisible : function(row){
168 if(typeof row == 'number'){
169 row = this.getBodyTable().childNodes[row];
170 }
171 if(!row) return;
172 var left = this.wrap.scrollLeft;
173 var rowTop = parseInt(row.offsetTop, 10); // parseInt for safari bug
174 var rowBottom = rowTop + row.offsetHeight;
175 var clientTop = parseInt(this.wrap.scrollTop, 10); // parseInt for safari bug
176 var clientBottom = clientTop + this.wrap.clientHeight;
177 if(rowTop < clientTop){
178 this.wrap.scrollTop = rowTop;
179 }else if(rowBottom > clientBottom){
180 this.wrap.scrollTop = rowBottom-this.wrap.clientHeight;
181 }
182 this.wrap.scrollLeft = left;
183 this.handleScroll();
184 },
185
186 updateColumns : function(){
187 this.grid.stopEditing();
188 var colModel = this.grid.colModel;
189 var hcols = this.headers;
190 var colCount = colModel.getColumnCount();
191 var pos = 0;
192 var totalWidth = colModel.getTotalWidth();
193 for(var i = 0; i < colCount; i++){
194 if(colModel.isHidden(i)) continue;
195 var width = colModel.getColumnWidth(i);
196 hcols[i].style.width = width + 'px';
197 hcols[i].style.left = pos + 'px';
198 hcols[i].split.style.left = (pos+width-3) + 'px';
199 this.setCSSWidth(i, width, pos);
200 pos += width;
201 }
202 this.lastWidth = totalWidth;
203 if(this.grid.autoWidth){
204 this.grid.container.setWidth(totalWidth+this.grid.container.getBorderWidth('lr'));
205 this.grid.autoSize();
206 }
207 this.bwrap.setWidth(Math.max(totalWidth, this.wrap.clientWidth));
208 if(!YAHOO.ext.util.Browser.isIE){ // fix scrolling prob in gecko and opera
209 this.wrap.scrollLeft = this.hwrap.dom.scrollLeft;
210 }
211 this.syncScroll();
212 this.forceScrollUpdate();
213 if(this.grid.autoHeight){
214 this.autoHeight();
215 this.updateWrapHeight();
216 }
217 },
218
219 setCSSWidth : function(colIndex, width, pos){
220 var selector = ["#" + this.grid.id + " .ygrid-col-" + colIndex, ".ygrid-col-" + colIndex];
221 YAHOO.ext.util.CSS.updateRule(selector, 'width', width + 'px');
222 if(typeof pos == 'number'){
223 YAHOO.ext.util.CSS.updateRule(selector, 'left', pos + 'px');
224 }
225 },
226
227 /**
228 * Set a css style for a column dynamically.
229 * @param {Number} colIndex The index of the column
230 * @param {String} name The css property name
231 * @param {String} value The css value
232 */
233 setCSSStyle : function(colIndex, name, value){
234 var selector = ["#" + this.grid.id + " .ygrid-col-" + colIndex, ".ygrid-col-" + colIndex];
235 YAHOO.ext.util.CSS.updateRule(selector, name, value);
236 },
237
238 handleHiddenChange : function(colModel, colIndex, hidden){
239 if(hidden){
240 this.hideColumn(colIndex);
241 }else{
242 this.unhideColumn(colIndex);
243 }
244 this.updateColumns();
245 },
246
247 hideColumn : function(colIndex){
248 var selector = ["#" + this.grid.id + " .ygrid-col-" + colIndex, ".ygrid-col-" + colIndex];
249 YAHOO.ext.util.CSS.updateRule(selector, 'position', 'absolute');
250 YAHOO.ext.util.CSS.updateRule(selector, 'visibility', 'hidden');
251
252 this.headers[colIndex].style.display = 'none';
253 this.headers[colIndex].split.style.display = 'none';
254 },
255
256 unhideColumn : function(colIndex){
257 var selector = ["#" + this.grid.id + " .ygrid-col-" + colIndex, ".ygrid-col-" + colIndex];
258 YAHOO.ext.util.CSS.updateRule(selector, 'position', '');
259 YAHOO.ext.util.CSS.updateRule(selector, 'visibility', 'visible');
260
261 this.headers[colIndex].style.display = '';
262 this.headers[colIndex].split.style.display = '';
263 },
264
265 getBodyTable : function(){
266 return this.bwrap.dom;
267 },
268
269 updateRowIndexes : function(firstRow, lastRow){
270 var stripeRows = this.grid.stripeRows;
271 var bt = this.getBodyTable();
272 var nodes = bt.childNodes;
273 firstRow = firstRow || 0;
274 lastRow = lastRow || nodes.length-1;
275 var re = /^(?:ygrid-row ygrid-row-alt|ygrid-row)/;
276 for(var rowIndex = firstRow; rowIndex <= lastRow; rowIndex++){
277 var node = nodes[rowIndex];
278 if(stripeRows && (rowIndex+1) % 2 == 0){
279 node.className = node.className.replace(re, 'ygrid-row ygrid-row-alt');
280 }else{
281 node.className = node.className.replace(re, 'ygrid-row');
282 }
283 node.rowIndex = rowIndex;
284 nodes[rowIndex].style.top = (rowIndex * this.rowHeight) + 'px';
285 }
286 },
287
288 insertRows : function(dataModel, firstRow, lastRow){
289 this.updateBodyHeight();
290 this.adjustForScroll(true);
291 var renderers = this.getColumnRenderers();
292 var dindexes = this.getDataIndexes();
293 var colCount = this.grid.colModel.getColumnCount();
294 var beforeRow = null;
295 var bt = this.getBodyTable();
296 if(firstRow < bt.childNodes.length){
297 beforeRow = bt.childNodes[firstRow];
298 }
299 for(var rowIndex = firstRow; rowIndex <= lastRow; rowIndex++){
300 var row = document.createElement('span');
301 row.className = 'ygrid-row';
302 row.style.top = (rowIndex * this.rowHeight) + 'px';
303 this.renderRow(dataModel, row, rowIndex, colCount, renderers, dindexes);
304 if(beforeRow){
305 bt.insertBefore(row, beforeRow);
306 }else{
307 bt.appendChild(row);
308 }
309 }
310 this.updateRowIndexes(firstRow);
311 this.adjustForScroll(true);
312 },
313
314 renderRow : function(dataModel, row, rowIndex, colCount, renderers, dindexes){
315 for(var colIndex = 0; colIndex < colCount; colIndex++){
316 var td = document.createElement('span');
317 td.className = 'ygrid-col ygrid-col-' + colIndex + (colIndex == colCount-1 ? ' ygrid-col-last' : '');
318 td.columnIndex = colIndex;
319 td.tabIndex = 0;
320 var span = document.createElement('span');
321 span.className = 'ygrid-cell-text';
322 td.appendChild(span);
323 var val = renderers[colIndex](dataModel.getValueAt(rowIndex, dindexes[colIndex]), rowIndex, colIndex, td, dataModel);
324 if(typeof val == 'undefined' || val === '') val = '&#160;';
325 span.innerHTML = val;
326 row.appendChild(td);
327 }
328 },
329
330 deleteRows : function(dataModel, firstRow, lastRow){
331 this.updateBodyHeight();
332 // first make sure they are deselected
333 this.grid.selModel.deselectRange(firstRow, lastRow);
334 var bt = this.getBodyTable();
335 var rows = []; // get references because the rowIndex will change
336 for(var rowIndex = firstRow; rowIndex <= lastRow; rowIndex++){
337 rows.push(bt.childNodes[rowIndex]);
338 }
339 for(var i = 0; i < rows.length; i++){
340 bt.removeChild(rows[i]);
341 rows[i] = null;
342 }
343 rows = null;
344 this.updateRowIndexes(firstRow);
345 this.adjustForScroll();
346 },
347
348 updateRows : function(dataModel, firstRow, lastRow){
349 var bt = this.getBodyTable();
350 var dindexes = this.getDataIndexes();
351 var renderers = this.getColumnRenderers();
352 var colCount = this.grid.colModel.getColumnCount();
353 for(var rowIndex = firstRow; rowIndex <= lastRow; rowIndex++){
354 var row = bt.rows[rowIndex];
355 var cells = row.childNodes;
356 for(var colIndex = 0; colIndex < colCount; colIndex++){
357 var td = cells[colIndex];
358 var val = renderers[colIndex](dataModel.getValueAt(rowIndex, dindexes[colIndex]), rowIndex, colIndex, td, dataModel);
359 if(typeof val == 'undefined' || val === '') val = '&#160;';
360 td.firstChild.innerHTML = val;
361 }
362 }
363 },
364
365 handleSort : function(dataModel, sortColumnIndex, sortDir, noRefresh){
366 varselectedRows;
367 this.grid.selModel.syncSelectionsToIds();
368 if(!noRefresh){
369 this.updateRows(dataModel, 0, dataModel.getRowCount()-1);
370 }
371 this.updateHeaderSortState();
372 selectedRows = this.grid.selModel.getSelectedRows();
373 if (selectedRows.length > 0) {
374 this.focusRow(selectedRows[0]);
375 }
376 },
377
378 syncScroll : function(){
379 this.hwrap.dom.scrollLeft = this.wrap.scrollLeft;
380 },
381
382 handleScroll : function(){
383 this.syncScroll();
384 this.fireScroll(this.wrap.scrollLeft, this.wrap.scrollTop);
385 this.grid.fireEvent('bodyscroll', this.wrap.scrollLeft, this.wrap.scrollTop);
386 },
387
388 getRowHeight : function(){
389 if(!this.rowHeight){
390 var rule = YAHOO.ext.util.CSS.getRule(["#" + this.grid.id + " .ygrid-row", ".ygrid-row"]);
391 if(rule && rule.style.height){
392 this.rowHeight = parseInt(rule.style.height, 10);
393 }else{
394 this.rowHeight = 21;
395 }
396 }
397 return this.rowHeight;
398 },
399
400 renderRows : function(dataModel){
401 this.grid.stopEditing();
402 if(this.grid.selModel){
403 this.grid.selModel.clearSelections();
404 }
405 var bt = this.getBodyTable();
406 bt.innerHTML = '';
407 this.rowHeight = this.getRowHeight();
408 this.insertRows(dataModel, 0, dataModel.getRowCount()-1);
409 },
410
411 updateCell : function(dataModel, rowIndex, dataIndex){
412 var colIndex = this.getColumnIndexByDataIndex(dataIndex);
413 if(typeof colIndex == 'undefined'){ // not present in grid
414 return;
415 }
416 var bt = this.getBodyTable();
417 var row = bt.childNodes[rowIndex];
418 var cell = row.childNodes[colIndex];
419 var renderer = this.grid.colModel.getRenderer(colIndex);
420 var val = renderer(dataModel.getValueAt(rowIndex, dataIndex), rowIndex, colIndex, cell, dataModel);
421 if(typeof val == 'undefined' || val === '') val = '&#160;';
422 cell.firstChild.innerHTML = val;
423 },
424
425 calcColumnWidth : function(colIndex, maxRowsToMeasure){
426 var maxWidth = 0;
427 var bt = this.getBodyTable();
428 var rows = bt.childNodes;
429 var stopIndex = Math.min(maxRowsToMeasure || rows.length, rows.length);
430 if(this.grid.autoSizeHeaders){
431 var h = this.headers[colIndex];
432 var curWidth = h.style.width;
433 h.style.width = this.grid.minColumnWidth+'px';
434 maxWidth = Math.max(maxWidth, h.scrollWidth);
435 h.style.width = curWidth;
436 }
437 for(var i = 0; i < stopIndex; i++){
438 var cell = rows[i].childNodes[colIndex].firstChild;
439 maxWidth = Math.max(maxWidth, cell.scrollWidth);
440 }
441 return maxWidth + /*margin for error in IE*/ 5;
442 },
443
444 /**
445 * Autofit a column to it's content.
446 * @param {Number} colIndex
447 * @param {Boolean} forceMinSize true to force the column to go smaller if possible
448 */
449 autoSizeColumn : function(colIndex, forceMinSize){
450 if(forceMinSize){
451 this.setCSSWidth(colIndex, this.grid.minColumnWidth);
452 }
453 var newWidth = this.calcColumnWidth(colIndex);
454 this.grid.colModel.setColumnWidth(colIndex,
455 Math.max(this.grid.minColumnWidth, newWidth));
456 this.grid.fireEvent('columnresize', colIndex, newWidth);
457 },
458
459 /**
460 * Autofits all columns to their content and then expands to fit any extra space in the grid
461 */
462 autoSizeColumns : function(){
463 var colModel = this.grid.colModel;
464 var colCount = colModel.getColumnCount();
465 var wrap = this.wrap;
466 for(var i = 0; i < colCount; i++){
467 this.setCSSWidth(i, this.grid.minColumnWidth);
468 colModel.setColumnWidth(i, this.calcColumnWidth(i, this.grid.maxRowsToMeasure), true);
469 }
470 if(colModel.getTotalWidth() < wrap.clientWidth){
471 var diff = Math.floor((wrap.clientWidth - colModel.getTotalWidth()) / colCount);
472 for(var i = 0; i < colCount; i++){
473 colModel.setColumnWidth(i, colModel.getColumnWidth(i) + diff, true);
474 }
475 }
476 this.updateColumns();
477 },
478
479 /**
480 * Autofits all columns to the grid's width proportionate with their current size
481 */
482 fitColumns : function(){
483 var cm = this.grid.colModel;
484 var colCount = cm.getColumnCount();
485 var cols = [];
486 var width = 0;
487 var i, w;
488 for (i = 0; i < colCount; i++){
489 if(!cm.isHidden(i) && !cm.isFixed(i)){
490 w = cm.getColumnWidth(i);
491 cols.push(i);
492 cols.push(w);
493 width += w;
494 }
495 }
496 var frac = (this.wrap.clientWidth - cm.getTotalWidth())/width;
497 while (cols.length){
498 w = cols.pop();
499 i = cols.pop();
500 cm.setColumnWidth(i, Math.floor(w + w*frac), true);
501 }
502 this.updateColumns();
503 },
504
505 onWindowResize : function(){
506 if(this.grid.monitorWindowResize){
507 this.adjustForScroll();
508 this.updateWrapHeight();
509 this.adjustForScroll();
510 }
511 },
512
513 updateWrapHeight : function(){
514 this.grid.container.beginMeasure();
515 this.autoHeight();
516 var box = this.grid.container.getSize(true);
517 this.wrapEl.setHeight(box.height-this.footerHeight-parseInt(this.wrap.offsetTop, 10));
518 this.pwrap.setSize(box.width, box.height);
519 this.grid.container.endMeasure();
520 },
521
522 forceScrollUpdate : function(){
523 var wrap = this.wrapEl;
524 wrap.setWidth(wrap.getWidth(true));
525 setTimeout(function(){ // set timeout so FireFox works
526 wrap.setWidth('');
527 }, 1);
528 },
529
530 updateHeaderSortState : function(){
531 var state = this.grid.dataModel.getSortState();
532 if(!state || typeof state.column == 'undefined') return;
533 var sortColumn = this.getColumnIndexByDataIndex(state.column);
534 var sortDir = state.direction;
535 for(var i = 0, len = this.headers.length; i < len; i++){
536 var h = this.headers[i];
537 if(i != sortColumn){
538 h.sortDesc.style.display = 'none';
539 h.sortAsc.style.display = 'none';
540 YAHOO.util.Dom.removeClass(h, 'ygrid-sort-col');
541 }else{
542 h.sortDesc.style.display = sortDir == 'DESC' ? 'block' : 'none';
543 h.sortAsc.style.display = sortDir == 'ASC' ? 'block' : 'none';
544 YAHOO.util.Dom.addClass(h, 'ygrid-sort-col');
545 }
546 }
547 },
548
549 unplugDataModel : function(dm){
550 dm.removeListener('cellupdated', this.updateCell, this);
551 dm.removeListener('datachanged', this.renderRows, this);
552 dm.removeListener('rowsdeleted', this.deleteRows, this);
553 dm.removeListener('rowsinserted', this.insertRows, this);
554 dm.removeListener('rowsupdated', this.updateRows, this);
555 dm.removeListener('rowssorted', this.handleSort, this);
556 },
557
558 plugDataModel : function(dm){
559 dm.on('cellupdated', this.updateCell, this, true);
560 dm.on('datachanged', this.renderRows, this, true);
561 dm.on('rowsdeleted', this.deleteRows, this, true);
562 dm.on('rowsinserted', this.insertRows, this, true);
563 dm.on('rowsupdated', this.updateRows, this, true);
564 dm.on('rowssorted', this.handleSort, this, true);
565 },
566
567 destroy : function(){
568 this.unplugDataModel(this.grid.dataModel);
569 var sp = this.splitters;
570 if(sp){
571 for(var i in sp){
572 if(sp[i] && typeof sp[i] != 'function'){
573 sp[i].destroy(true);
574 }
575 }
576 }
577 },
578
579 render : function(){
580 var grid = this.grid;
581 var container = grid.container.dom;
582 var dataModel = grid.dataModel;
583 this.plugDataModel(dataModel);
584
585 var colModel = grid.colModel;
586 colModel.onWidthChange.subscribe(this.updateColumns, this, true);
587 colModel.onHeaderChange.subscribe(this.updateHeaders, this, true);
588 colModel.onHiddenChange.subscribe(this.handleHiddenChange, this, true);
589
590 if(grid.monitorWindowResize === true){
591 YAHOO.ext.EventManager.onWindowResize(this.onWindowResize, this, true);
592 }
593 var autoSizeDelegate = this.autoSizeColumn.createDelegate(this);
594
595 var colCount = colModel.getColumnCount();
596
597 var dh = YAHOO.ext.DomHelper;
598 this.pwrap = dh.append(container,
599 {tag: 'div', cls: 'ygrid-positioner',
600 style: 'position:relative;width:100%;height:100%;left:0;top:0;overflow:hidden;'}, true);
601 var pos = this.pwrap.dom;
602
603 //create wrapper elements that handle offsets and scrolling
604 var wrap = dh.append(pos, {tag: 'div', cls: 'ygrid-wrap'});
605 this.wrap = wrap;
606 this.wrapEl = getEl(wrap, true);
607 YAHOO.ext.EventManager.on(wrap, 'scroll', this.handleScroll, this, true);
608
609 var hwrap = dh.append(pos, {tag: 'div', cls: 'ygrid-wrap-headers'});
610 this.hwrap = getEl(hwrap, true);
611
612 var bwrap = dh.append(wrap, {tag: 'div', cls: 'ygrid-wrap-body', id: container.id + '-body'});
613 this.bwrap = getEl(bwrap, true);
614 this.bwrap.setWidth(colModel.getTotalWidth());
615 bwrap.rows = bwrap.childNodes;
616
617 this.footerHeight = 0;
618 var foot = this.appendFooter(this.pwrap.dom);
619 if(foot){
620 this.footer = getEl(foot, true);
621 this.footerHeight = this.footer.getHeight();
622 }
623 this.updateWrapHeight();
624
625 var hrow = dh.append(hwrap, {tag: 'span', cls: 'ygrid-hrow'});
626 this.hrow = hrow;
627
628 if(!YAHOO.ext.util.Browser.isGecko){
629 // IE doesn't like iframes, we will leave this alone
630 var iframe = document.createElement('iframe');
631 iframe.className = 'ygrid-hrow-frame';
632 iframe.frameBorder = 0;
633 iframe.src = YAHOO.ext.SSL_SECURE_URL;
634 hwrap.appendChild(iframe);
635 }
636 this.headerCtrl = new YAHOO.ext.grid.HeaderController(this.grid);
637 this.headers = [];
638 this.cols = [];
639 this.splitters = [];
640
641 var htemplate = dh.createTemplate({
642 tag: 'span', cls: 'ygrid-hd ygrid-header-{0}', children: [{
643 tag: 'span',
644 cls: 'ygrid-hd-body',
645 html: '<table border="0" cellpadding="0" cellspacing="0" title="{2}">' +
646 '<tbody><tr><td><span>{1}</span></td>' +
647 '<td><span class="sort-desc"></span><span class="sort-asc"></span></td>' +
648 '</tr></tbody></table>'
649 }]
650 });
651 htemplate.compile();
652
653 var ruleBuf = [];
654
655 for(var i = 0; i < colCount; i++){
656 var hd = htemplate.append(hrow, [i, colModel.getColumnHeader(i), colModel.getColumnTooltip(i) || '']);
657 var spans = hd.getElementsByTagName('span');
658 hd.textNode = spans[1];
659 hd.sortDesc = spans[2];
660 hd.sortAsc = spans[3];
661 hd.columnIndex = i;
662 this.headers.push(hd);
663 if(colModel.isSortable(i)){
664 this.headerCtrl.register(hd);
665 }
666 var split = dh.append(hrow, {tag: 'span', cls: 'ygrid-hd-split'});
667 hd.split = split;
668
669 if(colModel.isResizable(i) && !colModel.isFixed(i)){
670 YAHOO.util.Event.on(split, 'dblclick', autoSizeDelegate.createCallback(i+0, true));
671 var sb = new YAHOO.ext.SplitBar(split, hd, null, YAHOO.ext.SplitBar.LEFT);
672 sb.columnIndex = i;
673 sb.minSize = grid.minColumnWidth;
674 sb.onMoved.subscribe(this.onColumnSplitterMoved, this, true);
675 YAHOO.util.Dom.addClass(sb.proxy, 'ygrid-column-sizer');
676 YAHOO.util.Dom.setStyle(sb.proxy, 'background-color', '');
677 sb.dd._resizeProxy = function(){
678 var el = this.getDragEl();
679 YAHOO.util.Dom.setStyle(el, 'height', (hwrap.clientHeight+wrap.clientHeight-2) +'px');
680 };
681 this.splitters[i] = sb;
682 }else{
683 split.style.cursor = 'default';
684 }
685 ruleBuf.push('#', container.id, ' .ygrid-col-', i, ' {\n}\n');
686 }
687
688 YAHOO.ext.util.CSS.createStyleSheet(ruleBuf.join(''));
689
690 if(grid.autoSizeColumns){
691 this.renderRows(dataModel);
692 this.autoSizeColumns();
693 }else{
694 this.updateColumns();
695 this.renderRows(dataModel);
696 }
697
698 for(var i = 0; i < colCount; i++){
699 if(colModel.isHidden(i)){
700 this.hideColumn(i);
701 }
702 }
703 this.updateHeaderSortState();
704 return this.bwrap;
705 },
706
707 onColumnSplitterMoved : function(splitter, newSize){
708 this.grid.colModel.setColumnWidth(splitter.columnIndex, newSize);
709 this.grid.fireEvent('columnresize', splitter.columnIndex, newSize);
710 },
711
712 appendFooter : function(parentEl){
713 return null;
714 },
715
716 autoHeight : function(){
717 if(this.grid.autoHeight){
718 var h = this.getBodyHeight();
719 var c = this.grid.container;
720 var total = h + (parseInt(this.wrap.offsetTop, 10)||0) +
721 this.footerHeight + c.getBorderWidth('tb') + c.getPadding('tb')
722 + (this.wrap.offsetHeight - this.wrap.clientHeight);
723 c.setHeight(total);
724
725 }
726 },
727
728 getBodyHeight : function(){
729 return this.grid.dataModel.getRowCount() * this.getRowHeight();;
730 },
731
732 updateBodyHeight : function(){
733 this.getBodyTable().style.height = this.getBodyHeight() + 'px';
734 if(this.grid.autoHeight){
735 this.autoHeight();
736 this.updateWrapHeight();
737 }
738 }
739};
740YAHOO.ext.grid.GridView.SCROLLBARS_UNDER = 0;
741YAHOO.ext.grid.GridView.SCROLLBARS_OVERLAP = 1;
742YAHOO.ext.grid.GridView.prototype.scrollbarMode = YAHOO.ext.grid.GridView.SCROLLBARS_UNDER;
743
744YAHOO.ext.grid.GridView.prototype.fitColumnsToContainer = YAHOO.ext.grid.GridView.prototype.fitColumns;
745
746YAHOO.ext.grid.HeaderController = function(grid){
747 this.grid = grid;
748 this.headers = [];
749};
750
751YAHOO.ext.grid.HeaderController.prototype = {
752 register : function(header){
753 this.headers.push(header);
754 YAHOO.ext.EventManager.on(header, 'selectstart', this.cancelTextSelection, this, true);
755 YAHOO.ext.EventManager.on(header, 'mousedown', this.cancelTextSelection, this, true);
756 YAHOO.ext.EventManager.on(header, 'mouseover', this.headerOver, this, true);
757 YAHOO.ext.EventManager.on(header, 'mouseout', this.headerOut, this, true);
758 YAHOO.ext.EventManager.on(header, 'click', this.headerClick, this, true);
759 },
760
761 headerClick : function(e){
762 var grid = this.grid, cm = grid.colModel, dm = grid.dataModel;
763 grid.stopEditing();
764 var header = grid.getHeaderFromChild(e.getTarget());
765 var state = dm.getSortState();
766 var direction = header.sortDir || 'ASC';
767 if(typeof state.column != 'undefined' &&
768 grid.getView().getColumnIndexByDataIndex(state.column) == header.columnIndex){
769 direction = (state.direction == 'ASC' ? 'DESC' : 'ASC');
770 }
771 header.sortDir = direction;
772 dm.sort(cm, cm.getDataIndex(header.columnIndex), direction);
773 },
774
775 headerOver : function(e){
776 var header = this.grid.getHeaderFromChild(e.getTarget());
777 YAHOO.util.Dom.addClass(header, 'ygrid-hd-over');
778 //YAHOO.ext.util.CSS.applyFirst(header, this.grid.id, '.ygrid-hd-over');
779 },
780
781 headerOut : function(e){
782 var header = this.grid.getHeaderFromChild(e.getTarget());
783 YAHOO.util.Dom.removeClass(header, 'ygrid-hd-over');
784 //YAHOO.ext.util.CSS.revertFirst(header, this.grid.id, '.ygrid-hd-over');
785 },
786
787 cancelTextSelection : function(e){
788 e.preventDefault();
789 }
790}; \ No newline at end of file
diff --git a/frontend/beta/js/YUI-extensions/grid/PagedGridView.js b/frontend/beta/js/YUI-extensions/grid/PagedGridView.js
new file mode 100644
index 0000000..ecaece2
--- a/dev/null
+++ b/frontend/beta/js/YUI-extensions/grid/PagedGridView.js
@@ -0,0 +1,194 @@
1/**
2 * @class YAHOO.ext.grid.PagedGridView
3 * @extends YAHOO.ext.grid.GridView
4 * Extends the default GridView to add a paging interface.
5 * @constructor
6 * This class is created for you automatically if your data model is set to use paging.
7 */
8YAHOO.ext.grid.PagedGridView = function(){
9 YAHOO.ext.grid.PagedGridView.superclass.constructor.call(this);
10 this.cursor = 1;
11};
12
13YAHOO.extendX(YAHOO.ext.grid.PagedGridView, YAHOO.ext.grid.GridView, {
14 appendFooter : function(parentEl){
15 var fwrap = document.createElement('div');
16 fwrap.className = 'ygrid-wrap-footer';
17 var fbody = document.createElement('span');
18 fbody.className = 'ygrid-footer';
19 fwrap.appendChild(fbody);
20 parentEl.appendChild(fwrap);
21 this.createPagingToolbar(fbody);
22 return fwrap;
23 },
24
25 createPagingToolbar : function(container){
26 var tb = new YAHOO.ext.Toolbar(container);
27 this.pageToolbar = tb;
28 this.first = tb.addButton({
29 tooltip: this.firstText,
30 className: 'ygrid-page-first',
31 disabled: true,
32 click: this.onClick.createDelegate(this, ['first'])
33 });
34 this.prev = tb.addButton({
35 tooltip: this.prevText,
36 className: 'ygrid-page-prev',
37 disabled: true,
38 click: this.onClick.createDelegate(this, ['prev'])
39 });
40 tb.addSeparator();
41 tb.add(this.beforePageText);
42 var pageBox = document.createElement('input');
43 pageBox.type = 'text';
44 pageBox.size = 3;
45 pageBox.value = '1';
46 pageBox.className = 'ygrid-page-number';
47 tb.add(pageBox);
48 this.field = getEl(pageBox, true);
49 this.field.mon('keydown', this.onEnter, this, true);
50 this.field.on('focus', function(){pageBox.select();});
51 this.afterTextEl = tb.addText(this.afterPageText.replace('%0', '1'));
52 this.field.setHeight(18);
53 tb.addSeparator();
54 this.next = tb.addButton({
55 tooltip: this.nextText,
56 className: 'ygrid-page-next',
57 disabled: true,
58 click: this.onClick.createDelegate(this, ['next'])
59 });
60 this.last = tb.addButton({
61 tooltip: this.lastText,
62 className: 'ygrid-page-last',
63 disabled: true,
64 click: this.onClick.createDelegate(this, ['last'])
65 });
66 tb.addSeparator();
67 this.loading = tb.addButton({
68 tooltip: this.refreshText,
69 className: 'ygrid-loading',
70 disabled: true,
71 click: this.onClick.createDelegate(this, ['refresh'])
72 });
73 this.onPageLoaded(1, this.grid.dataModel.getTotalPages());
74 },
75
76 /**
77 * Returns the toolbar used for paging so you can add new buttons.
78 * @return {YAHOO.ext.Toolbar}
79 */
80 getPageToolbar : function(){
81 return this.pageToolbar;
82 },
83
84 onPageLoaded : function(pageNum, totalPages){
85 this.cursor = pageNum;
86 this.lastPage = totalPages;
87 this.afterTextEl.innerHTML = this.afterPageText.replace('%0', totalPages);
88 this.field.dom.value = pageNum;
89 this.first.setDisabled(pageNum == 1);
90 this.prev.setDisabled(pageNum == 1);
91 this.next.setDisabled(pageNum == totalPages);
92 this.last.setDisabled(pageNum == totalPages);
93 this.loading.enable();
94 },
95
96 onLoadError : function(){
97 this.loading.enable();
98 },
99
100 onEnter : function(e){
101 if(e.browserEvent.keyCode == e.RETURN){
102 var v = this.field.dom.value;
103 if(!v){
104 this.field.dom.value = this.cursor;
105 return;
106 }
107 var pageNum = parseInt(v, 10);
108 if(isNaN(pageNum)){
109 this.field.dom.value = this.cursor;
110 return;
111 }
112 pageNum = Math.min(Math.max(1, pageNum), this.lastPage);
113 this.grid.dataModel.loadPage(pageNum);
114 e.stopEvent();
115 }
116 },
117
118 beforeLoad : function(){
119 this.grid.stopEditing();
120 if(this.loading){
121 this.loading.disable();
122 }
123 },
124
125 onClick : function(which){
126 switch(which){
127 case 'first':
128 this.grid.dataModel.loadPage(1);
129 break;
130 case 'prev':
131 this.grid.dataModel.loadPage(this.cursor -1);
132 break;
133 case 'next':
134 this.grid.dataModel.loadPage(this.cursor + 1);
135 break;
136 case 'last':
137 this.grid.dataModel.loadPage(this.lastPage);
138 break;
139 case 'refresh':
140 this.grid.dataModel.loadPage(this.cursor);
141 break;
142 }
143 },
144
145 unplugDataModel : function(dm){
146 dm.removeListener('beforeload', this.beforeLoad, this);
147 dm.removeListener('load', this.onPageLoaded, this);
148 dm.removeListener('loadexception', this.onLoadError, this);
149 YAHOO.ext.grid.PagedGridView.superclass.unplugDataModel.call(this, dm);
150 },
151
152 plugDataModel : function(dm){
153 dm.on('beforeload', this.beforeLoad, this, true);
154 dm.on('load', this.onPageLoaded, this, true);
155 dm.on('loadexception', this.onLoadError, this);
156 YAHOO.ext.grid.PagedGridView.superclass.plugDataModel.call(this, dm);
157 },
158
159 /**
160 * Customizable piece of the default paging text (defaults to "Page")
161 * @type String
162 */
163 beforePageText : "Page",
164 /**
165 * Customizable piece of the default paging text (defaults to "of %0")
166 * @type String
167 */
168 afterPageText : "of %0",
169 /**
170 * Customizable piece of the default paging text (defaults to "First Page")
171 * @type String
172 */
173 firstText : "First Page",
174 /**
175 * Customizable piece of the default paging text (defaults to "Previous Page")
176 * @type String
177 */
178 prevText : "Previous Page",
179 /**
180 * Customizable piece of the default paging text (defaults to "Next Page")
181 * @type String
182 */
183 nextText : "Next Page",
184 /**
185 * Customizable piece of the default paging text (defaults to "Last Page")
186 * @type String
187 */
188 lastText : "Last Page",
189 /**
190 * Customizable piece of the default paging text (defaults to "Refresh")
191 * @type String
192 */
193 refreshText : "Refresh"
194});
diff --git a/frontend/beta/js/YUI-extensions/grid/SelectionModel.js b/frontend/beta/js/YUI-extensions/grid/SelectionModel.js
new file mode 100644
index 0000000..6981440
--- a/dev/null
+++ b/frontend/beta/js/YUI-extensions/grid/SelectionModel.js
@@ -0,0 +1,445 @@
1/**
2 @class YAHOO.ext.grid.DefaultSelectionModel
3 * @extends YAHOO.ext.util.Observable
4 * The default SelectionModel used by {@link YAHOO.ext.grid.Grid}.
5 It supports multiple selections and keyboard selection/navigation. <br><br>
6 @constructor
7 */
8YAHOO.ext.grid.DefaultSelectionModel = function(){
9 this.selectedRows = [];
10 this.selectedRowIds = [];
11 this.lastSelectedRow = null;
12
13 this.onRowSelect = new YAHOO.util.CustomEvent('SelectionTable.rowSelected');
14 this.onSelectionChange = new YAHOO.util.CustomEvent('SelectionTable.selectionChanged');
15
16 this.events = {
17 /**
18 * @event selectionchange
19 * Fires when the selection changes
20 * @param {SelectionModel} this
21 * @param {Array} rows Array of row elements that are selected
22 * @param {String} ids Array of ids that are selected
23 */
24 'selectionchange' : this.onSelectionChange,
25 /**
26 * @event rowselect
27 * Fires when a row is selected or deselected
28 * @param {SelectionModel} this
29 * @param {HTMLElement} row The row element
30 * @param {Boolean} selected true if the row was selected, false if deselected
31 */
32 'rowselect' : this.onRowSelect
33 };
34
35 this.locked = false;
36};
37
38YAHOO.ext.grid.DefaultSelectionModel.prototype = {
39 /** @ignore Called by the grid automatically. Do not call directly. */
40 init : function(grid){
41 this.grid = grid;
42 this.initEvents();
43 },
44
45 /**
46 * Lock the selections
47 */
48 lock : function(){
49 this.locked = true;
50 },
51
52 /**
53 * Unlock the selections
54 */
55 unlock : function(){
56 this.locked = false;
57 },
58
59 /**
60 * Returns true if the selections are locked
61 * @return {Boolean}
62 */
63 isLocked : function(){
64 return this.locked;
65 },
66
67 /** @ignore */
68 initEvents : function(){
69 if(this.grid.trackMouseOver){
70 this.grid.addListener("mouseover", this.handleOver, this, true);
71 this.grid.addListener("mouseout", this.handleOut, this, true);
72 }
73 this.grid.addListener("rowclick", this.rowClick, this, true);
74 this.grid.addListener("keydown", this.keyDown, this, true);
75 },
76
77 fireEvent : YAHOO.ext.util.Observable.prototype.fireEvent,
78 on : YAHOO.ext.util.Observable.prototype.on,
79 addListener : YAHOO.ext.util.Observable.prototype.addListener,
80 delayedListener : YAHOO.ext.util.Observable.prototype.delayedListener,
81 removeListener : YAHOO.ext.util.Observable.prototype.removeListener,
82 purgeListeners : YAHOO.ext.util.Observable.prototype.purgeListeners,
83 bufferedListener : YAHOO.ext.util.Observable.prototype.bufferedListener,
84
85 /** @ignore Syncs selectedRows with the correct row by looking it up by id.
86 Used after a sort moves data around. */
87 syncSelectionsToIds : function(){
88 if(this.getCount() > 0){
89 var ids = this.selectedRowIds.concat();
90 this.clearSelections();
91 this.selectRowsById(ids, true);
92 }
93 },
94
95 /**
96 * Set the selected rows by their ID(s). IDs must match what is returned by the DataModel getRowId(index).
97 * @param {String/Array} id The id(s) to select
98 * @param {<i>Boolean</i>} keepExisting (optional) True to retain existing selections
99 */
100 selectRowsById : function(id, keepExisting){
101 var rows = this.grid.getRowsById(id);
102 if (!(rows instanceof Array)){
103 this.selectRow(rows, keepExisting);
104 return;
105 }
106 this.selectRows(rows, keepExisting);
107 },
108
109 /**
110 * Gets the number of selected rows.
111 * @return {Number}
112 */
113 getCount : function(){
114 return this.selectedRows.length;
115 },
116
117 /**
118 * Selects the first row in the grid.
119 */
120 selectFirstRow : function(){
121 for(var j = 0; j < this.grid.rows.length; j++){
122 if(this.isSelectable(this.grid.rows[j])){
123 this.focusRow(this.grid.rows[j]);
124 this.setRowState(this.grid.rows[j], true);
125 return;
126 }
127 }
128 },
129
130 /**
131 * Selects the row immediately following the last selected row.
132 * @param {<i>Boolean</i>} keepExisting (optional) True to retain existing selections
133 */
134 selectNext : function(keepExisting){
135 if(this.lastSelectedRow){
136 for(var j = (this.lastSelectedRow.rowIndex+1); j < this.grid.rows.length; j++){
137 var row = this.grid.rows[j];
138 if(this.isSelectable(row)){
139 this.focusRow(row);
140 this.setRowState(row, true, keepExisting);
141 return;
142 }
143 }
144 }
145 },
146
147 /**
148 * Selects the row that precedes the last selected row.
149 * @param {<i>Boolean</i>} keepExisting (optional) True to retain existing selections
150 */
151 selectPrevious : function(keepExisting){
152 if(this.lastSelectedRow){
153 for(var j = (this.lastSelectedRow.rowIndex-1); j >= 0; j--){
154 var row = this.grid.rows[j];
155 if(this.isSelectable(row)){
156 this.focusRow(row);
157 this.setRowState(row, true, keepExisting);
158 return;
159 }
160 }
161 }
162 },
163
164 /**
165 * Returns the selected rows.
166 * @return {Array} Array of DOM row elements
167 */
168 getSelectedRows : function(){
169 return this.selectedRows;
170 },
171
172 /**
173 * Returns the selected row ids.
174 * @return {Array} Array of String ids
175 */
176 getSelectedRowIds : function(){
177 return this.selectedRowIds;
178 },
179
180 /**
181 * Clears all selections.
182 */
183 clearSelections : function(){
184 if(this.isLocked()) return;
185 var oldSelections = this.selectedRows.concat();
186 for(var j = 0; j < oldSelections.length; j++){
187 this.setRowState(oldSelections[j], false);
188 }
189 this.selectedRows = [];
190 this.selectedRowIds = [];
191 },
192
193
194 /**
195 * Selects all rows.
196 */
197 selectAll : function(){
198 if(this.isLocked()) return;
199 this.selectedRows = [];
200 this.selectedRowIds = [];
201 for(var j = 0, len = this.grid.rows.length; j < len; j++){
202 this.setRowState(this.grid.rows[j], true, true);
203 }
204 },
205
206 /**
207 * Returns True if there is a selection.
208 * @return {Boolean}
209 */
210 hasSelection : function(){
211 return this.selectedRows.length > 0;
212 },
213
214 /**
215 * Returns True if the specified row is selected.
216 * @param {HTMLElement} row The row to check
217 * @return {Boolean}
218 */
219 isSelected : function(row){
220 return row && (row.selected === true || row.getAttribute('selected') == 'true');
221 },
222
223 /**
224 * Returns True if the specified row is selectable.
225 * @param {HTMLElement} row The row to check
226 * @return {Boolean}
227 */
228 isSelectable : function(row){
229 return row && row.getAttribute('selectable') != 'false';
230 },
231
232 /** @ignore */
233 rowClick : function(grid, rowIndex, e){
234 if(this.isLocked()) return;
235 var row = grid.getRow(rowIndex);
236 if(this.isSelectable(row)){
237 if(e.shiftKey && this.lastSelectedRow){
238 var lastIndex = this.lastSelectedRow.rowIndex;
239 this.selectRange(this.lastSelectedRow, row, e.ctrlKey);
240 this.lastSelectedRow = this.grid.el.dom.rows[lastIndex];
241 }else{
242 this.focusRow(row);
243 var rowState = e.ctrlKey ? !this.isSelected(row) : true;
244 this.setRowState(row, rowState, e.hasModifier());
245 }
246 }
247 },
248
249 /**
250 * Deprecated. Tries to focus the row and scroll it into view - Use grid.scrollTo or grid.getView().focusRow() instead.
251 * @deprecated
252 * @param {HTMLElement} row The row to focus
253 */
254 focusRow : function(row){
255 this.grid.view.focusRow(row);
256 },
257
258 /**
259 * Selects a row.
260 * @param {Number/HTMLElement} row The row or index of the row to select
261 * @param {<i>Boolean</i>} keepExisting (optional) True to retain existing selections
262 */
263 selectRow : function(row, keepExisting){
264 this.setRowState(this.getRow(row), true, keepExisting);
265 },
266
267 /**
268 * Selects multiple rows.
269 * @param {Array} rows Array of the rows or indexes of the row to select
270 * @param {<i>Boolean</i>} keepExisting (optional) True to retain existing selections
271 */
272 selectRows : function(rows, keepExisting){
273 if(!keepExisting){
274 this.clearSelections();
275 }
276 for(var i = 0; i < rows.length; i++){
277 this.selectRow(rows[i], true);
278 }
279 },
280
281 /**
282 * Deselects a row.
283 * @param {Number/HTMLElement} row The row or index of the row to deselect
284 */
285 deselectRow : function(row){
286 this.setRowState(this.getRow(row), false);
287 },
288
289 /** @ignore */
290 getRow : function(row){
291 if(typeof row == 'number'){
292 row = this.grid.rows[row];
293 }
294 return row;
295 },
296
297 /**
298 * Selects a range of rows. All rows in between startRow and endRow are also selected.
299 * @param {Number/HTMLElement} startRow The row or index of the first row in the range
300 * @param {Number/HTMLElement} endRow The row or index of the last row in the range
301 * @param {<i>Boolean</i>} keepExisting (optional) True to retain existing selections
302 */
303 selectRange : function(startRow, endRow, keepExisting){
304 startRow = this.getRow(startRow);
305 endRow = this.getRow(endRow);
306 this.setRangeState(startRow, endRow, true, keepExisting);
307 },
308
309 /**
310 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
311 * @param {Number/HTMLElement} startRow The row or index of the first row in the range
312 * @param {Number/HTMLElement} endRow The row or index of the last row in the range
313 */
314 deselectRange : function(startRow, endRow){
315 startRow = this.getRow(startRow);
316 endRow = this.getRow(endRow);
317 this.setRangeState(startRow, endRow, false, true);
318 },
319
320 /** @ignore */
321 setRowStateFromChild : function(childEl, selected, keepExisting){
322 var row = this.grid.getRowFromChild(childEl);
323 this.setRowState(row, selected, keepExisting);
324 },
325
326 /** @ignore */
327 setRangeState : function(startRow, endRow, selected, keepExisting){
328 if(this.isLocked()) return;
329 if(!keepExisting){
330 this.clearSelections();
331 }
332 var curRow = startRow;
333 while(curRow.rowIndex != endRow.rowIndex){
334 this.setRowState(curRow, selected, true);
335 curRow = (startRow.rowIndex < endRow.rowIndex ?
336 this.grid.getRowAfter(curRow) : this.grid.getRowBefore(curRow))
337 }
338 this.setRowState(endRow, selected, true);
339 },
340
341 /** @ignore */
342 setRowState : function(row, selected, keepExisting){
343 if(this.isLocked()) return;
344 if(this.isSelectable(row)){
345 if(selected){
346 if(!keepExisting){
347 this.clearSelections();
348 }
349 this.setRowClass(row, 'selected');
350 row.selected = true;
351 this.selectedRows.push(row);
352 this.selectedRowIds.push(this.grid.dataModel.getRowId(row.rowIndex));
353 this.lastSelectedRow = row;
354 }else{
355 this.setRowClass(row, '');
356 row.selected = false;
357 this._removeSelected(row);
358 }
359 this.fireEvent('rowselect', this, row, selected);
360 this.fireEvent('selectionchange', this, this.selectedRows, this.selectedRowIds);
361 }
362 },
363
364 /** @ignore */
365 handleOver : function(e){
366 var row = this.grid.getRowFromChild(e.getTarget());
367 if(this.isSelectable(row) && !this.isSelected(row)){
368 this.setRowClass(row, 'over');
369 }
370 },
371
372 /** @ignore */
373 handleOut : function(e){
374 var row = this.grid.getRowFromChild(e.getTarget());
375 if(this.isSelectable(row) && !this.isSelected(row)){
376 this.setRowClass(row, '');
377 }
378 },
379
380 /** @ignore */
381 keyDown : function(e){
382 if(e.browserEvent.keyCode == e.DOWN){
383 this.selectNext(e.shiftKey);
384 e.preventDefault();
385 }else if(e.browserEvent.keyCode == e.UP){
386 this.selectPrevious(e.shiftKey);
387 e.preventDefault();
388 }
389 },
390
391 /** @ignore */
392 setRowClass : function(row, cssClass){
393 if(this.isSelectable(row)){
394 if(cssClass == 'selected'){
395 YAHOO.util.Dom.removeClass(row, 'ygrid-row-over');
396 YAHOO.util.Dom.addClass(row, 'ygrid-row-selected');
397 }else if(cssClass == 'over'){
398 YAHOO.util.Dom.removeClass(row, 'ygrid-row-selected');
399 YAHOO.util.Dom.addClass(row, 'ygrid-row-over');
400 }else if(cssClass == ''){
401 YAHOO.util.Dom.removeClass(row, 'ygrid-row-selected');
402 YAHOO.util.Dom.removeClass(row, 'ygrid-row-over');
403 }
404 }
405 },
406
407 /** @ignore */
408 _removeSelected : function(row){
409 var sr = this.selectedRows;
410 for (var i = 0; i < sr.length; i++) {
411 if (sr[i] === row){
412 this.selectedRows.splice(i, 1);
413 this.selectedRowIds.splice(i, 1);
414 return;
415 }
416 }
417 }
418};
419
420/**
421 @class YAHOO.ext.grid.SingleSelectionModel
422 @extends YAHOO.ext.grid.DefaultSelectionModel
423 Allows only one row to be selected at a time.
424 @constructor
425 * Create new SingleSelectionModel
426 */
427YAHOO.ext.grid.SingleSelectionModel = function(){
428 YAHOO.ext.grid.SingleSelectionModel.superclass.constructor.call(this);
429};
430
431YAHOO.extendX(YAHOO.ext.grid.SingleSelectionModel, YAHOO.ext.grid.DefaultSelectionModel);
432
433/** @ignore */
434YAHOO.ext.grid.SingleSelectionModel.prototype.setRowState = function(row, selected){
435 YAHOO.ext.grid.SingleSelectionModel.superclass.setRowState.call(this, row, selected, false);
436};
437
438YAHOO.ext.grid.DisableSelectionModel = function(){
439 YAHOO.ext.grid.DisableSelectionModel.superclass.constructor.call(this);
440};
441
442YAHOO.extendX(YAHOO.ext.grid.DisableSelectionModel, YAHOO.ext.grid.DefaultSelectionModel);
443
444YAHOO.ext.grid.DisableSelectionModel.prototype.initEvents = function(){
445};
diff --git a/frontend/beta/js/YUI-extensions/grid/editor/CellEditor.js b/frontend/beta/js/YUI-extensions/grid/editor/CellEditor.js
new file mode 100644
index 0000000..7c51a48
--- a/dev/null
+++ b/frontend/beta/js/YUI-extensions/grid/editor/CellEditor.js
@@ -0,0 +1,91 @@
1/**
2 * @class YAHOO.ext.grid.CellEditor
3 * Base class for all EditorGrid editors
4 */
5YAHOO.ext.grid.CellEditor = function(element){
6 this.colIndex = null;
7 this.rowIndex = null;
8 this.grid = null;
9 this.editing = false;
10 this.originalValue = null;
11 this.element = getEl(element, true);
12 this.element.addClass('ygrid-editor');
13 this.element.dom.tabIndex = 1;
14 this.initialized = false;
15 this.callback = null;
16};
17
18YAHOO.ext.grid.CellEditor.prototype = {
19 init : function(grid, bodyElement, callback){
20 // there's no way for the grid to know if multiple columns
21 // share the same editor so it will try to initialize the
22 // same one over and over
23 if(this.initialized) return;
24 this.initialized = true;
25 this.callback = callback;
26 this.grid = grid;
27 bodyElement.appendChild(this.element.dom);
28 this.initEvents();
29 },
30
31 initEvents : function(){
32 var stopOnEnter = function(e){
33 if(e.browserEvent.keyCode == e.RETURN){
34 this.stopEditing(true);
35 }else if(e.browserEvent.keyCode == e.ESC){
36 this.setValue(this.originalValue);
37 this.stopEditing(true);
38 }
39 }
40 this.element.mon('keydown', stopOnEnter, this, true);
41 this.element.on('blur', this.stopEditing, this, true);
42 },
43
44 startEditing : function(value, row, cell){
45 this.originalValue = value;
46 this.rowIndex = row.rowIndex;
47 this.colIndex = cell.columnIndex;
48 this.cell = cell;
49 this.setValue(value);
50 var cellbox = getEl(cell, true).getBox();
51 this.fitToCell(cellbox);
52 this.editing = true;
53 this.show();
54 },
55
56 stopEditing : function(focusCell){
57 if(this.editing){
58 this.editing = false;
59 var newValue = this.getValue();
60 this.hide();
61 //if(focusCell){try{this.cell.focus();}catch(e){}}; // try to give the cell focus so keyboard nav still works
62 if(this.originalValue != newValue){
63 this.callback(newValue, this.rowIndex, this.colIndex);
64 }
65 }
66 },
67
68 setValue : function(value){
69 this.element.dom.value = value;
70 },
71
72 getValue : function(){
73 return this.element.dom.value;
74 },
75
76 fitToCell : function(box){
77 this.element.setBox(box, true);
78 },
79
80 show : function(){
81 this.element.show();
82 this.element.focus();
83 },
84
85 hide : function(){
86 try{
87 this.element.dom.blur();
88 }catch(e){}
89 this.element.hide();
90 }
91};
diff --git a/frontend/beta/js/YUI-extensions/grid/editor/CheckboxEditor.js b/frontend/beta/js/YUI-extensions/grid/editor/CheckboxEditor.js
new file mode 100644
index 0000000..681b847
--- a/dev/null
+++ b/frontend/beta/js/YUI-extensions/grid/editor/CheckboxEditor.js
@@ -0,0 +1,60 @@
1/**
2 * @class YAHOO.ext.grid.CheckboxEditor
3 * @extends YAHOO.ext.grid.CellEditor
4Provides a checkbox for editing boolean values. It currently has no configuration options.<br><br>
5For more information on using this editor, see <a href="http://www.jackslocum.com/yui/2006/09/10/adding-built-in-editing-support-to-the-yahoo-ui-extensions-grid/">this blog post</a>.
6* @constructor
7* Create a new CheckboxEditor
8 */
9YAHOO.ext.grid.CheckboxEditor = function(){
10 var div = document.createElement('span');
11 div.className = 'ygrid-editor ygrid-checkbox-editor';
12 var cb = document.createElement('input');
13 cb.type = 'checkbox';
14 cb.setAttribute('autocomplete', 'off');
15 div.appendChild(cb);
16 document.body.appendChild(div);
17 YAHOO.ext.grid.CheckboxEditor.superclass.constructor.call(this, div);
18 div.tabIndex = '';
19 cb.tabIndex = 1;
20 this.cb = getEl(cb, true);
21};
22
23YAHOO.extendX(YAHOO.ext.grid.CheckboxEditor, YAHOO.ext.grid.CellEditor);
24
25YAHOO.ext.grid.CheckboxEditor.prototype.fitToCell = function(box){
26 this.element.setBox(box, true);
27};
28
29YAHOO.ext.grid.CheckboxEditor.prototype.setValue = function(value){
30 this.cb.dom.checked = (value === true || value === 'true' || value === 1 || value === '1');
31};
32
33YAHOO.ext.grid.CheckboxEditor.prototype.getValue = function(){
34 return this.cb.dom.checked;
35};
36
37YAHOO.ext.grid.CheckboxEditor.prototype.show = function(){
38 this.element.show();
39 this.cb.focus();
40};
41
42YAHOO.ext.grid.CheckboxEditor.prototype.initEvents = function(){
43 var stopOnEnter = function(e){
44 if(e.browserEvent.keyCode == e.RETURN){
45 this.stopEditing(true);
46 }else if(e.browserEvent.keyCode == e.ESC){
47 this.setValue(this.originalValue);
48 this.stopEditing(true);
49 }
50 }
51 this.cb.mon('keydown', stopOnEnter, this, true);
52 this.cb.on('blur', this.stopEditing, this, true);
53};
54
55YAHOO.ext.grid.CheckboxEditor.prototype.hide = function(){
56 try{
57 this.cb.dom.blur();
58 }catch(e){}
59 this.element.hide();
60};
diff --git a/frontend/beta/js/YUI-extensions/grid/editor/DateEditor.js b/frontend/beta/js/YUI-extensions/grid/editor/DateEditor.js
new file mode 100644
index 0000000..303ad2b
--- a/dev/null
+++ b/frontend/beta/js/YUI-extensions/grid/editor/DateEditor.js
@@ -0,0 +1,268 @@
1/**
2 * @class YAHOO.ext.grid.DateEditor
3 * @extends YAHOO.ext.grid.CellEditor
4Provides a date editor field, and optionally a DatePicker. The DateEditor provides a method to override (showCalendar) if you don't want to use the built in DatePicker control. The reason I chose to use my own DatePicker control rather than the nice YUI Calendar component is my control was very easy to override events to make it work well with the grid. It's also only 5k compressed, while the YUI Calendar is 40k compressed. The DatePicker supports left/right keys to move months, up/down keys to move years and the mouse wheel to quickly go through the months. The DateEditor supports the following configuration options:
5<ul class="list">
6<li><i>format</i> - The date format for the editor. The format is identical to <a href="http://www.php.net/date">PHP date()</a> and text is allowed. Credit for that goes to <a style="font-weight:normal;" href="http://www.xaprb.com/blog/2006/05/14/javascript-date-formatting-benchmarks/">this fantastic date library</a>. This format is for the editor only and doesn't affect the rendering of the cell when not in edit mode. Your rendering function can use any date format it wants.</li>
7<li><i>minValue</i> - The minimum allowed date. Can be either a Javascript date object or a string date in the specified format.</li>
8<li><i>maxValue</i> - The maximum allowed date. Can be either a Javascript date object or a string date in the specified format.</li>
9<li><i>minText</i> - The tooltip to display when the date in the cell is before minValue.</li>
10<li><i>maxText</i> - The tooltip to display when the date in the cell is after maxValue.</li>
11<li><i>invalidText</i> - The text to display when the date in the field is invalid (for example: 02/31/06)</li>
12<li><i>disabledDays</i> - An array of days to disable, 0 based. For example, [0, 6] disables Sunday and Saturday.</li>
13<li><i>disabledDaysText</i> - The tooltip to display when the date in the cell (or DatePicker) falls on a disabled day.</li>
14<li><i>disabledDates</i> - An array of "dates" to disable, as strings. These strings will be used to build a dynamic regular expression so they are very powerful. For example, ["03/08/2003", "09/16/2003"] would disable those dates, but ["03/08", "09/16"] would disable them for every year. If you are using short years, you will want to use ^ to tell the regular expression to only match the beginning like ["^03/08"]. To disable March of 2006: ["03/../2006"] or every March ["^03"]. In order to support regular expressions, if you are using a date format that has "." in it, you will have to escape the dot when restricting dates. For example: ["03\\.08\\.03"].</li>
15<li><i>disabledDatesText</i> - The tooltip to display when the date in the cell (or DatePicker) falls on a disabled date.</li>
16<li><i>allowBlank</i> - True if the cell is allowed to be empty.</li>
17<li><i>blankText</i> - The tooltip (error message) to display when the cell is empty and is not allowed to be.</li>
18<li><i>validator</i> - Any custom validation function you want called. The function must return true if the data is valid or an error message otherwise.</li>
19<li><i>validationDelay</i> - The delay in milliseconds for validation. Each time the user types something the field is validated after a specified delay, setting this value allows you to customize that delay (for example, if your custom validation routine is slow).</li>
20</ul>
21For more information on using this editor, see <a href="http://www.jackslocum.com/yui/2006/09/10/adding-built-in-editing-support-to-the-yahoo-ui-extensions-grid/">this blog post</a>.
22* @constructor
23* Create a new DateEditor
24* @param {Object} config
25 */
26YAHOO.ext.grid.DateEditor = function(config){
27 var div = document.createElement('span');
28 div.className = 'ygrid-editor ygrid-editor-container';
29
30 var element = document.createElement('input');
31 element.type = 'text';
32 element.tabIndex = 1;
33 element.setAttribute('autocomplete', 'off');
34 div.appendChild(element);
35
36 var pick = document.createElement('span');
37 pick.className = 'pick-button';
38 div.appendChild(pick);
39
40 document.body.appendChild(div);
41
42 this.div = getEl(div, true);
43 this.element = getEl(element, true);
44 this.pick = getEl(pick, true);
45
46 this.colIndex = null;
47 this.rowIndex = null;
48 this.grid = null;
49 this.editing = false;
50 this.originalValue = null;
51 this.initialized = false;
52 this.callback = null;
53
54 this.cal = null;
55 this.mouseDownHandler = YAHOO.ext.EventManager.wrap(this.handleMouseDown, this, true);
56
57 YAHOO.ext.util.Config.apply(this, config);
58 if(typeof this.minValue == 'string') this.minValue = this.parseDate(this.minValue);
59 if(typeof this.maxValue == 'string') this.maxValue = this.parseDate(this.maxValue);
60 this.ddMatch = /ddnone/;
61 if(this.disabledDates){
62 var dd = this.disabledDates;
63 var re = "(?:";
64 for(var i = 0; i < dd.length; i++){
65 re += dd[i];
66 if(i != dd.length-1) re += "|";
67 }
68 this.ddMatch = new RegExp(re + ")");
69 }
70};
71
72YAHOO.ext.grid.DateEditor.prototype = {
73 init : function(grid, bodyElement, callback){
74 if(this.initialized) return;
75
76 this.initialized = true;
77 this.callback = callback;
78 this.grid = grid;
79 bodyElement.appendChild(this.div.dom);
80 this.initEvents();
81 },
82
83 initEvents : function(){
84 var stopOnEnter = function(e){
85 if(e.browserEvent.keyCode == e.RETURN){
86 this.stopEditing(true);
87 }else if(e.browserEvent.keyCode == e.ESC){
88 this.setValue(this.originalValue);
89 this.stopEditing(true);
90 }
91 }
92 this.element.mon('keydown', stopOnEnter, this, true);
93 var vtask = new YAHOO.ext.util.DelayedTask(this.validate, this);
94 this.element.mon('keyup', vtask.delay.createDelegate(vtask, [this.validationDelay]));
95 this.pick.on('click', this.showCalendar, this, true);
96 },
97
98 startEditing : function(value, row, cell){
99 this.originalValue = value;
100 this.rowIndex = row.rowIndex;
101 this.colIndex = cell.columnIndex;
102 this.cell = cell;
103 this.setValue(value);
104 this.validate();
105 var cellbox = getEl(cell, true).getBox();
106 this.div.setBox(cellbox, true);
107 this.element.setWidth(cellbox.width-this.pick.getWidth());
108 this.editing = true;
109 YAHOO.util.Event.on(document, "mousedown", this.mouseDownHandler);
110 this.show();
111 },
112
113 stopEditing : function(focusCell){
114 if(this.editing){
115 YAHOO.util.Event.removeListener(document, "mousedown", this.mouseDownHandler);
116 this.editing = false;
117 var newValue = this.getValue();
118 this.hide();
119 //if(focusCell){try{this.cell.focus();}catch(e){}}// try to give the cell focus so keyboard nav still works
120 if(this.originalValue != newValue){
121 this.callback(newValue, this.rowIndex, this.colIndex);
122 }
123 }
124 },
125
126 setValue : function(value){
127 this.element.dom.value = this.formatDate(value);
128 this.validate();
129 },
130
131 getValue : function(){
132 if(!this.validate()){
133 return this.originalValue;
134 }else{
135 var value = this.element.dom.value;
136 if(value.length < 1){
137 return value;
138 } else{
139 return this.parseDate(value);
140 }
141 }
142 },
143
144 show : function() {
145 this.div.show();
146 this.element.focus();
147 this.validate();
148 },
149
150 hide : function(){
151 try{
152 this.element.dom.blur();
153 }catch(e){}
154 this.div.hide();
155 },
156
157 validate : function(){
158 var dom = this.element.dom;
159 var value = dom.value;
160 if(value.length < 1){ // if it's blank
161 if(this.allowBlank){
162 dom.title = '';
163 this.element.removeClass('ygrid-editor-invalid');
164 return true;
165 }else{
166 dom.title = this.blankText;
167 this.element.addClass('ygrid-editor-invalid');
168 return false;
169 }
170 }
171 value = this.parseDate(value);
172 if(!value){
173 dom.title = this.invalidText.replace('%0', dom.value).replace('%1', this.format);
174 this.element.addClass('ygrid-editor-invalid');
175 return false;
176 }
177 var time = value.getTime();
178 if(this.minValue && time < this.minValue.getTime()){
179 dom.title = this.minText.replace('%0', this.formatDate(this.minValue));
180 this.element.addClass('ygrid-editor-invalid');
181 return false;
182 }
183 if(this.maxValue && time > this.maxValue.getTime()){
184 dom.title = this.maxText.replace('%0', this.formatDate(this.maxValue));
185 this.element.addClass('ygrid-editor-invalid');
186 return false;
187 }
188 if(this.disabledDays){
189 var day = value.getDay();
190 for(var i = 0; i < this.disabledDays.length; i++) {
191 if(day === this.disabledDays[i]){
192 dom.title = this.disabledDaysText;
193 this.element.addClass('ygrid-editor-invalid');
194 return false;
195 }
196 }
197 }
198 var fvalue = this.formatDate(value);
199 if(this.ddMatch.test(fvalue)){
200 dom.title = this.disabledDatesText.replace('%0', fvalue);
201 this.element.addClass('ygrid-editor-invalid');
202 return false;
203 }
204 var msg = this.validator(value);
205 if(msg !== true){
206 dom.title = msg;
207 this.element.addClass('ygrid-editor-invalid');
208 return false;
209 }
210 dom.title = '';
211 this.element.removeClass('ygrid-editor-invalid');
212 return true;
213 },
214
215 handleMouseDown : function(e){
216 var t = e.getTarget();
217 var dom = this.div.dom;
218 if(t != dom && !YAHOO.util.Dom.isAncestor(dom, t)){
219 this.stopEditing();
220 }
221 },
222
223 showCalendar : function(value){
224 if(this.cal == null){
225 this.cal = new YAHOO.ext.DatePicker(this.div.dom.parentNode.parentNode);
226 }
227 this.cal.minDate = this.minValue;
228 this.cal.maxDate = this.maxValue;
229 this.cal.disabledDatesRE = this.ddMatch;
230 this.cal.disabledDatesText = this.disabledDatesText;
231 this.cal.disabledDays = this.disabledDays;
232 this.cal.disabledDaysText = this.disabledDaysText;
233 this.cal.format = this.format;
234 if(this.minValue){
235 this.cal.minText = this.minText.replace('%0', this.formatDate(this.minValue));
236 }
237 if(this.maxValue){
238 this.cal.maxText = this.maxText.replace('%0', this.formatDate(this.maxValue));
239 }
240 var r = this.div.getRegion();
241 this.cal.show(r.left, r.bottom, this.getValue(), this.setValue.createDelegate(this));
242 },
243
244 parseDate : function(value){
245 if(!value || value instanceof Date) return value;
246 return Date.parseDate(value, this.format);
247 },
248
249 formatDate : function(date){
250 if(!date || !(date instanceof Date)) return date;
251 return date.format(this.format);
252 }
253};
254
255YAHOO.ext.grid.DateEditor.prototype.format = 'm/d/y';
256YAHOO.ext.grid.DateEditor.prototype.disabledDays = null;
257YAHOO.ext.grid.DateEditor.prototype.disabledDaysText = '';
258YAHOO.ext.grid.DateEditor.prototype.disabledDates = null;
259YAHOO.ext.grid.DateEditor.prototype.disabledDatesText = '';
260YAHOO.ext.grid.DateEditor.prototype.allowBlank = true;
261YAHOO.ext.grid.DateEditor.prototype.minValue = null;
262YAHOO.ext.grid.DateEditor.prototype.maxValue = null;
263YAHOO.ext.grid.DateEditor.prototype.minText = 'The date in this field must be after %0';
264YAHOO.ext.grid.DateEditor.prototype.maxText = 'The date in this field must be before %0';
265YAHOO.ext.grid.DateEditor.prototype.blankText = 'This field cannot be blank';
266YAHOO.ext.grid.DateEditor.prototype.invalidText = '%0 is not a valid date - it must be in the format %1';
267YAHOO.ext.grid.DateEditor.prototype.validationDelay = 200;
268YAHOO.ext.grid.DateEditor.prototype.validator = function(){return true;};
diff --git a/frontend/beta/js/YUI-extensions/grid/editor/NumberEditor.js b/frontend/beta/js/YUI-extensions/grid/editor/NumberEditor.js
new file mode 100644
index 0000000..f74d3d9
--- a/dev/null
+++ b/frontend/beta/js/YUI-extensions/grid/editor/NumberEditor.js
@@ -0,0 +1,166 @@
1/**
2 * @class YAHOO.ext.grid.NumberEditor
3 * @extends YAHOO.ext.grid.CellEditor
4Provides a masked editor for numeric values. Invalid keys are ignored. It supports the following configuration options:
5<ul class="list">
6<li><i>allowDecimals</i> - True if the cell can have decimal values.</li>
7<li><i>decimalSeparator</i> - Character(s) to allow as the decimal separator.</li>
8<li><i>decimalPrecision</i> - Set the maximum decimal precision.</li>
9<li><i>decimalPrecisionFcn</i> - Define the function to call to remove extra precision (ie. Math.floor, Math.round, Math.ceil or your own function).</li>
10<li><i>allowNegative</i> - True if the cell allows negative values.</li>
11<li><i>selectOnFocus</i> - True to select the text when the editor is activated.</li>
12<li><i>minValue</i> - The minimum value the cell will allow.</li>
13<li><i>maxValue</i> - The maximum value the cell will allow.</li>
14<li><i>minText</i> - The tooltip to display when the value in the cell is below the minimum.</li>
15<li><i>maxText</i> - The tooltip to display when the value in the cell is above the maximum.</li>
16<li><i>nanText</i> - The tooltip to display when the value in the cell is not a valid number (for example, negatives are allowed and the value in the cell is just "-" with no numbers).</li>
17<li><i>allowBlank</i> - True if the cell is allowed to be empty.</li>
18<li><i>blankText</i> - The tooltip (error message) to display when the cell is empty and is not allowed to be.</li>
19<li><i>validator</i> - Any custom validation function you want called. The function must return true if the data is valid or an error message otherwise.</li>
20<li><i>validationDelay</i> - The delay in milliseconds for validation. Each time the user types something the field is validated after a specified delay, setting this value allows you to customize that delay (for example, if your custom validation routine is slow).</li>
21</ul>
22For more information on using this editor, see <a href="http://www.jackslocum.com/yui/2006/09/10/adding-built-in-editing-support-to-the-yahoo-ui-extensions-grid/">this blog post</a>.
23* @constructor
24* Create a new NumberEditor
25* @param {Object} config
26 */
27YAHOO.ext.grid.NumberEditor = function(config){
28 var element = document.createElement('input');
29 element.type = 'text';
30 element.className = 'ygrid-editor ygrid-num-editor';
31 element.setAttribute('autocomplete', 'off');
32 document.body.appendChild(element);
33 YAHOO.ext.grid.NumberEditor.superclass.constructor.call(this, element);
34 YAHOO.ext.util.Config.apply(this, config);
35};
36YAHOO.extendX(YAHOO.ext.grid.NumberEditor, YAHOO.ext.grid.CellEditor);
37
38YAHOO.ext.grid.NumberEditor.prototype.initEvents = function(){
39 var stopOnEnter = function(e){
40 if(e.browserEvent.keyCode == e.RETURN){
41 this.stopEditing(true);
42 }else if(e.browserEvent.keyCode == e.ESC){
43 this.setValue(this.originalValue);
44 this.stopEditing(true);
45 }
46 };
47
48 var allowed = "0123456789";
49 if(this.allowDecimals){
50 allowed += this.decimalSeparator;
51 }
52 if(this.allowNegative){
53 allowed += '-';
54 }
55 var keyPress = function(e){
56 var c = e.getCharCode();
57 if(c != e.BACKSPACE && allowed.indexOf(String.fromCharCode(c)) === -1){
58 e.stopEvent();
59 }
60 };
61 this.element.mon('keydown', stopOnEnter, this, true);
62 var vtask = new YAHOO.ext.util.DelayedTask(this.validate, this);
63 this.element.mon('keyup', vtask.delay.createDelegate(vtask, [this.validationDelay]));
64 this.element.mon('keypress', keyPress, this, true);
65 this.element.on('blur', this.stopEditing, this, true);
66};
67
68YAHOO.ext.grid.NumberEditor.prototype.validate = function(){
69 var dom = this.element.dom;
70 var value = dom.value;
71 if(value.length < 1){ // if it's blank
72 if(this.allowBlank){
73 dom.title = '';
74 this.element.removeClass('ygrid-editor-invalid');
75 return true;
76 }else{
77 dom.title = this.blankText;
78 this.element.addClass('ygrid-editor-invalid');
79 return false;
80 }
81 }
82 if(value.search(/\d+/) === -1){
83 dom.title = this.nanText.replace('%0', value);
84 this.element.addClass('ygrid-editor-invalid');
85 return false;
86 }
87 var num = this.parseValue(value);
88 if(num < this.minValue){
89 dom.title = this.minText.replace('%0', this.minValue);
90 this.element.addClass('ygrid-editor-invalid');
91 return false;
92 }
93 if(num > this.maxValue){
94 dom.title = this.maxText.replace('%0', this.maxValue);
95 this.element.addClass('ygrid-editor-invalid');
96 return false;
97 }
98 var msg = this.validator(value);
99 if(msg !== true){
100 dom.title = msg;
101 this.element.addClass('ygrid-editor-invalid');
102 return false;
103 }
104 dom.title = '';
105 this.element.removeClass('ygrid-editor-invalid');
106 return true;
107};
108
109YAHOO.ext.grid.NumberEditor.prototype.show = function(){
110 this.element.dom.title = '';
111 YAHOO.ext.grid.NumberEditor.superclass.show.call(this);
112 if(this.selectOnFocus){
113 try{
114 this.element.dom.select();
115 }catch(e){}
116 }
117 this.validate(this.element.dom.value);
118};
119
120YAHOO.ext.grid.NumberEditor.prototype.getValue = function(){
121 if(!this.validate()){
122 return this.originalValue;
123 }else{
124 var value = this.element.dom.value;
125 if(value.length < 1){
126 return value;
127 } else{
128 return this.fixPrecision(this.parseValue(value));
129 }
130 }
131};
132YAHOO.ext.grid.NumberEditor.prototype.parseValue = function(value){
133 return parseFloat(new String(value).replace(this.decimalSeparator, '.'));
134};
135
136YAHOO.ext.grid.NumberEditor.prototype.fixPrecision = function(value){
137 if(!this.allowDecimals || this.decimalPrecision == -1 || isNaN(value) || value == 0 || !value){
138 return value;
139 }
140 // this should work but doesn't due to precision error in JS
141 // var scale = Math.pow(10, this.decimalPrecision);
142 // var fixed = this.decimalPrecisionFcn(value * scale);
143 // return fixed / scale;
144 //
145 // so here's our workaround:
146 var scale = Math.pow(10, this.decimalPrecision+1);
147 var fixed = this.decimalPrecisionFcn(value * scale);
148 fixed = this.decimalPrecisionFcn(fixed/10);
149 return fixed / (scale/10);
150};
151
152YAHOO.ext.grid.NumberEditor.prototype.allowBlank = true;
153YAHOO.ext.grid.NumberEditor.prototype.allowDecimals = true;
154YAHOO.ext.grid.NumberEditor.prototype.decimalSeparator = '.';
155YAHOO.ext.grid.NumberEditor.prototype.decimalPrecision = 2;
156YAHOO.ext.grid.NumberEditor.prototype.decimalPrecisionFcn = Math.floor;
157YAHOO.ext.grid.NumberEditor.prototype.allowNegative = true;
158YAHOO.ext.grid.NumberEditor.prototype.selectOnFocus = true;
159YAHOO.ext.grid.NumberEditor.prototype.minValue = Number.NEGATIVE_INFINITY;
160YAHOO.ext.grid.NumberEditor.prototype.maxValue = Number.MAX_VALUE;
161YAHOO.ext.grid.NumberEditor.prototype.minText = 'The minimum value for this field is %0';
162YAHOO.ext.grid.NumberEditor.prototype.maxText = 'The maximum value for this field is %0';
163YAHOO.ext.grid.NumberEditor.prototype.blankText = 'This field cannot be blank';
164YAHOO.ext.grid.NumberEditor.prototype.nanText = '%0 is not a valid number';
165YAHOO.ext.grid.NumberEditor.prototype.validationDelay = 100;
166YAHOO.ext.grid.NumberEditor.prototype.validator = function(){return true;};
diff --git a/frontend/beta/js/YUI-extensions/grid/editor/SelectEditor.js b/frontend/beta/js/YUI-extensions/grid/editor/SelectEditor.js
new file mode 100644
index 0000000..200b8e3
--- a/dev/null
+++ b/frontend/beta/js/YUI-extensions/grid/editor/SelectEditor.js
@@ -0,0 +1,37 @@
1/**
2 * @class YAHOO.ext.grid.SelectEditor
3 * @extends YAHOO.ext.grid.CellEditor
4Creates an editor out of an existing select field. You can create the select element through DOM in Javascript and pass it to the SelectEditor's constructor <b>or</b> an easier way is like this:
5<br><br>
6Define the select field in your document, giving it the ygrid-editor class.
7<pre><code>
8&lt;select id="light" class="ygrid-editor"&gt;
9 &lt;option value="Shade"&gt;Shade&lt;/option&gt;
10 &lt;option value="Mostly Shady"&gt;Mostly Shady&lt;/option&gt;
11 &lt;option value="Sun or Shade"&gt;Sun or Shade&lt;/option&gt;
12 &lt;option value="Mostly Sunny"&gt;Mostly Sunny&lt;/option&gt;
13 &lt;option value="Sunny"&gt;Sunny&lt;/option&gt;
14&lt;/select&gt;
15</code></pre>
16Create the SelectEditor object, passing in the id of your select field.
17<pre><code>
18var editor = new YAHOO.ext.grid.SelectEditor('light');
19</code></pre>
20For more information on using this editor, see <a href="http://www.jackslocum.com/yui/2006/09/10/adding-built-in-editing-support-to-the-yahoo-ui-extensions-grid/">this blog post</a>.
21* @constructor
22* Create a new SelectEditor
23* @param {HTMLElement/String} element
24 */
25YAHOO.ext.grid.SelectEditor = function(element){
26 element.hideFocus = true;
27 YAHOO.ext.grid.SelectEditor.superclass.constructor.call(this, element);
28 this.element.swallowEvent('click');
29};
30YAHOO.extendX(YAHOO.ext.grid.SelectEditor, YAHOO.ext.grid.CellEditor);
31
32YAHOO.ext.grid.SelectEditor.prototype.fitToCell = function(box){
33 if(YAHOO.ext.util.Browser.isGecko){
34 box.height -= 3;
35 }
36 this.element.setBox(box, true);
37};
diff --git a/frontend/beta/js/YUI-extensions/grid/editor/TextEditor.js b/frontend/beta/js/YUI-extensions/grid/editor/TextEditor.js
new file mode 100644
index 0000000..3c97acd
--- a/dev/null
+++ b/frontend/beta/js/YUI-extensions/grid/editor/TextEditor.js
@@ -0,0 +1,110 @@
1/**
2 * @class YAHOO.ext.grid.TextEditor
3 * @extends YAHOO.ext.grid.CellEditor
4Provides basic text editing for a cells and supports the following configuration options:
5<ul class="list">
6<li><i>allowBlank</i> - True if the cell is allowed to be empty.</li>
7<li><i>minLength</i> - The minimum length the cell will accept.</li>
8<li><i>maxLength</i> - The maximum length the cell will allow.</li>
9<li><i>minText</i> - The tooltip to display when the length of the value in the cell is below the minimum.</li>
10<li><i>maxText</i> - The tooltip to display when the length of the value in the cell is above the maximum.</li>
11<li><i>selectOnFocus</i> - True to select the text when the editor is activated.</li>
12<li><i>blankText</i> - The tooltip (error message) to display when the cell is empty and is not allowed to be.</li>
13<li><i>regex</i> - A regular expression to match if the value is valid. If the regex.test(value) returns false, the value is considered invalid.</li>
14<li><i>regexText</i> - The tooltip (error message) to display when regex does not match.</li>
15<li><i>validator</i> - Any custom validation function you want called. The function must return true if the data is valid or an error message otherwise.</li>
16<li><i>validationDelay</i> - The delay in milliseconds for validation. Each time the user types something the field is validated after a specified delay, setting this value allows you to customize that delay (for example, if your custom validation routine is slow).</li>
17</ul>
18For more information on using this editor, see <a href="http://www.jackslocum.com/yui/2006/09/10/adding-built-in-editing-support-to-the-yahoo-ui-extensions-grid/">this blog post</a>.
19* @constructor
20* Create a new TextEditor
21* @param {Object} config
22 */
23YAHOO.ext.grid.TextEditor = function(config){
24 var element = document.createElement('input');
25 element.type = 'text';
26 element.className = 'ygrid-editor ygrid-text-editor';
27 element.setAttribute('autocomplete', 'off');
28 document.body.appendChild(element);
29 YAHOO.ext.grid.TextEditor.superclass.constructor.call(this, element);
30 YAHOO.ext.util.Config.apply(this, config);
31};
32YAHOO.extendX(YAHOO.ext.grid.TextEditor, YAHOO.ext.grid.CellEditor);
33
34YAHOO.ext.grid.TextEditor.prototype.validate = function(){
35 var dom = this.element.dom;
36 var value = dom.value;
37 if(value.length < 1){ // if it's blank
38 if(this.allowBlank){
39 dom.title = '';
40 this.element.removeClass('ygrid-editor-invalid');
41 return true;
42 }else{
43 dom.title = this.blankText;
44 this.element.addClass('ygrid-editor-invalid');
45 return false;
46 }
47 }
48 if(value.length < this.minLength){
49 dom.title = this.minText.replace('%0', this.minLength);
50 this.element.addClass('ygrid-editor-invalid');
51 return false;
52 }
53 if(value.length > this.maxLength){
54 dom.title = this.maxText.replace('%0', this.maxLength);
55 this.element.addClass('ygrid-editor-invalid');
56 return false;
57 }
58 var msg = this.validator(value);
59 if(msg !== true){
60 dom.title = msg;
61 this.element.addClass('ygrid-editor-invalid');
62 return false;
63 }
64 if(this.regex && !this.regex.test(value)){
65 dom.title = this.regexText;
66 this.element.addClass('ygrid-editor-invalid');
67 return false;
68 }
69 dom.title = '';
70 this.element.removeClass('ygrid-editor-invalid');
71 return true;
72};
73
74YAHOO.ext.grid.TextEditor.prototype.initEvents = function(){
75 YAHOO.ext.grid.TextEditor.superclass.initEvents.call(this);
76 var vtask = new YAHOO.ext.util.DelayedTask(this.validate, this);
77 this.element.mon('keyup', vtask.delay.createDelegate(vtask, [this.validationDelay]));
78};
79
80YAHOO.ext.grid.TextEditor.prototype.show = function(){
81 this.element.dom.title = '';
82 YAHOO.ext.grid.TextEditor.superclass.show.call(this);
83 this.element.focus();
84 if(this.selectOnFocus){
85 try{
86 this.element.dom.select();
87 }catch(e){}
88 }
89 this.validate(this.element.dom.value);
90};
91
92YAHOO.ext.grid.TextEditor.prototype.getValue = function(){
93 if(!this.validate()){
94 return this.originalValue;
95 }else{
96 return this.element.dom.value;
97 }
98};
99
100YAHOO.ext.grid.TextEditor.prototype.allowBlank = true;
101YAHOO.ext.grid.TextEditor.prototype.minLength = 0;
102YAHOO.ext.grid.TextEditor.prototype.maxLength = Number.MAX_VALUE;
103YAHOO.ext.grid.TextEditor.prototype.minText = 'The minimum length for this field is %0';
104YAHOO.ext.grid.TextEditor.prototype.maxText = 'The maximum length for this field is %0';
105YAHOO.ext.grid.TextEditor.prototype.selectOnFocus = true;
106YAHOO.ext.grid.TextEditor.prototype.blankText = 'This field cannot be blank';
107YAHOO.ext.grid.TextEditor.prototype.validator = function(){return true;};
108YAHOO.ext.grid.TextEditor.prototype.validationDelay = 200;
109YAHOO.ext.grid.TextEditor.prototype.regex = null;
110YAHOO.ext.grid.TextEditor.prototype.regexText = '';
diff --git a/frontend/beta/js/YUI-extensions/layout/BasicLayoutRegion.js b/frontend/beta/js/YUI-extensions/layout/BasicLayoutRegion.js
new file mode 100644
index 0000000..b7ea273
--- a/dev/null
+++ b/frontend/beta/js/YUI-extensions/layout/BasicLayoutRegion.js
@@ -0,0 +1,265 @@
1/**
2 * @class YAHOO.ext.BasicLayoutRegion
3 * @extends YAHOO.ext.util.Observable
4 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
5 * and does not have a titlebar, tabs or any other features. All it does is size and position
6 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
7 */
8YAHOO.ext.BasicLayoutRegion = function(mgr, config, pos, skipConfig){
9 this.mgr = mgr;
10 this.position = pos;
11 this.events = {
12 /**
13 * @event beforeremove
14 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
15 * @param {YAHOO.ext.LayoutRegion} this
16 * @param {YAHOO.ext.ContentPanel} panel The panel
17 * @param {Object} e The cancel event object
18 */
19 'beforeremove' : true,
20 /**
21 * @event invalidated
22 * Fires when the layout for this region is changed.
23 * @param {YAHOO.ext.LayoutRegion} this
24 */
25 'invalidated' : true,
26 /**
27 * @event visibilitychange
28 * Fires when this region is shown or hidden
29 * @param {YAHOO.ext.LayoutRegion} this
30 * @param {Boolean} visibility true or false
31 */
32 'visibilitychange' : true,
33 /**
34 * @event paneladded
35 * Fires when a panel is added.
36 * @param {YAHOO.ext.LayoutRegion} this
37 * @param {YAHOO.ext.ContentPanel} panel The panel
38 */
39 'paneladded' : true,
40 /**
41 * @event panelremoved
42 * Fires when a panel is removed.
43 * @param {YAHOO.ext.LayoutRegion} this
44 * @param {YAHOO.ext.ContentPanel} panel The panel
45 */
46 'panelremoved' : true,
47 /**
48 * @event collapsed
49 * Fires when this region is collapsed.
50 * @param {YAHOO.ext.LayoutRegion} this
51 */
52 'collapsed' : true,
53 /**
54 * @event expanded
55 * Fires when this region is expanded.
56 * @param {YAHOO.ext.LayoutRegion} this
57 */
58 'expanded' : true,
59 /**
60 * @event panelactivated
61 * Fires when a panel is activated.
62 * @param {YAHOO.ext.LayoutRegion} this
63 * @param {YAHOO.ext.ContentPanel} panel The activated panel
64 */
65 'panelactivated' : true,
66 /**
67 * @event resized
68 * Fires when the user resizes this region.
69 * @param {YAHOO.ext.LayoutRegion} this
70 * @param {Number} newSize The new size (width for east/west, height for north/south)
71 */
72 'resized' : true
73 };
74 /** A collection of panels in this region. @type YAHOO.ext.util.MixedCollection */
75 this.panels = new YAHOO.ext.util.MixedCollection();
76 this.panels.getKey = this.getPanelId.createDelegate(this);
77 this.box = null;
78 this.activePanel = null;
79 if(skipConfig !== true){
80 this.applyConfig(config);
81 }
82};
83
84YAHOO.extendX(YAHOO.ext.BasicLayoutRegion, YAHOO.ext.util.Observable, {
85 getPanelId : function(p){
86 return p.getId();
87 },
88
89 applyConfig : function(config){
90 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
91 this.config = config;
92 },
93
94 /**
95 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
96 * the width, for horizontal (north, south) the height.
97 * @param {Number} newSize The new width or height
98 */
99 resizeTo : function(newSize){
100 if(this.activePanel){
101 var el = this.activePanel.getEl();
102 switch(this.position){
103 case 'east':
104 case 'west':
105 el.setWidth(newSize);
106 this.fireEvent('resized', this, newSize);
107 break;
108 case 'north':
109 case 'south':
110 el.setHeight(newSize);
111 this.fireEvent('resized', this, newSize);
112 break;
113 }
114 }
115 },
116
117 getBox : function(){
118 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
119 },
120
121 getMargins : function(){
122 return this.margins;
123 },
124
125 updateBox : function(box){
126 this.box = box;
127 var el = this.activePanel.getEl();
128 el.dom.style.left = box.x + 'px';
129 el.dom.style.top = box.y + 'px';
130 el.setSize(box.width, box.height);
131 },
132
133 /**
134 * Returns the container element for this region.
135 * @return {YAHOO.ext.Element}
136 */
137 getEl : function(){
138 return this.activePanel;
139 },
140
141 /**
142 * Returns true if this region is currently visible.
143 * @return {Boolean}
144 */
145 isVisible : function(){
146 return this.activePanel ? true : false;
147 },
148
149 setActivePanel : function(panel){
150 panel = this.getPanel(panel);
151 if(this.activePanel && this.activePanel != panel){
152 this.activePanel.setActiveState(false);
153 this.activePanel.getEl().setStyle({left:-10000,right:-10000});
154 }
155 this.activePanel = panel;
156 panel.setActiveState(true);
157 if(this.box){
158 panel.setSize(this.box.width, this.box.height);
159 }
160 this.fireEvent('panelactivated', this, panel);
161 this.fireEvent('invalidated');
162 },
163
164 /**
165 * Show the specified panel.
166 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
167 * @return {YAHOO.ext.ContentPanel} The shown panel or null
168 */
169 showPanel : function(panel){
170 if(panel = this.getPanel(panel)){
171 this.setActivePanel(panel);
172 }
173 return panel;
174 },
175
176 /**
177 * Get the active panel for this region.
178 * @return {YAHOO.ext.ContentPanel} The active panel or null
179 */
180 getActivePanel : function(){
181 return this.activePanel;
182 },
183
184 /**
185 * Add the passed ContentPanel(s)
186 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
187 * @return {YAHOO.ext.ContentPanel} The panel added (if only one was added)
188 */
189 add : function(panel){
190 if(arguments.length > 1){
191 for(var i = 0, len = arguments.length; i < len; i++) {
192 this.add(arguments[i]);
193 }
194 return null;
195 }
196 if(this.hasPanel(panel)){
197 this.showPanel(panel);
198 return panel;
199 }
200 panel.setRegion(this);
201 this.panels.add(panel);
202 panel.getEl().setStyle('position', 'absolute');
203 if(!panel.background){
204 this.setActivePanel(panel);
205 if(this.config.initialSize && this.panels.getCount()==1){
206 this.resizeTo(this.config.initialSize);
207 }
208 }
209 this.fireEvent('paneladded', this, panel);
210 return panel;
211 },
212
213 /**
214 * Returns true if the panel is in this region.
215 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
216 * @return {Boolean}
217 */
218 hasPanel : function(panel){
219 if(typeof panel == 'object'){ // must be panel obj
220 panel = panel.getId();
221 }
222 return this.getPanel(panel) ? true : false;
223 },
224
225 /**
226 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
227 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
228 * @param {Boolean} preservePanel Overrides the config preservePanel option
229 * @return {YAHOO.ext.ContentPanel} The panel that was removed
230 */
231 remove : function(panel, preservePanel){
232 panel = this.getPanel(panel);
233 if(!panel){
234 return null;
235 }
236 var e = {};
237 this.fireEvent('beforeremove', this, panel, e);
238 if(e.cancel === true){
239 return null;
240 }
241 var panelId = panel.getId();
242 this.panels.removeKey(panelId);
243 return panel;
244 },
245
246 /**
247 * Returns the panel specified or null if it's not in this region.
248 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
249 * @return {YAHOO.ext.ContentPanel}
250 */
251 getPanel : function(id){
252 if(typeof id == 'object'){ // must be panel obj
253 return id;
254 }
255 return this.panels.get(id);
256 },
257
258 /**
259 * Returns this regions position (north/south/east/west/center).
260 * @return {String}
261 */
262 getPosition: function(){
263 return this.position;
264 }
265});
diff --git a/frontend/beta/js/YUI-extensions/layout/BorderLayout.js b/frontend/beta/js/YUI-extensions/layout/BorderLayout.js
new file mode 100644
index 0000000..0529c24
--- a/dev/null
+++ b/frontend/beta/js/YUI-extensions/layout/BorderLayout.js
@@ -0,0 +1,281 @@
1/**
2 * @class YAHOO.ext.BorderLayout
3 * @extends YAHOO.ext.LayoutManager
4 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
5 * please see: <br><br>
6 * <a href="http://www.jackslocum.com/yui/2006/10/19/cross-browser-web-20-layouts-with-yahoo-ui/">Cross Browser Layouts - Part 1</a><br>
7 * <a href="http://www.jackslocum.com/yui/2006/10/28/cross-browser-web-20-layouts-part-2-ajax-feed-viewer-20/">Cross Browser Layouts - Part 2</a><br><br>
8 * Example:
9 <pre><code>
10 var layout = new YAHOO.ext.BorderLayout(document.body, {
11 north: {
12 initialSize: 25,
13 titlebar: false
14 },
15 west: {
16 split:true,
17 initialSize: 200,
18 minSize: 175,
19 maxSize: 400,
20 titlebar: true,
21 collapsible: true
22 },
23 east: {
24 split:true,
25 initialSize: 202,
26 minSize: 175,
27 maxSize: 400,
28 titlebar: true,
29 collapsible: true
30 },
31 south: {
32 split:true,
33 initialSize: 100,
34 minSize: 100,
35 maxSize: 200,
36 titlebar: true,
37 collapsible: true
38 },
39 center: {
40 titlebar: true,
41 autoScroll:true,
42 resizeTabs: true,
43 minTabWidth: 50,
44 preferredTabWidth: 150
45 }
46});
47
48// shorthand
49var CP = YAHOO.ext.ContentPanel;
50
51layout.beginUpdate();
52layout.add('north', new CP('north', 'North'));
53layout.add('south', new CP('south', {title: 'South', closable: true}));
54layout.add('west', new CP('west', {title: 'West'}));
55layout.add('east', new CP('autoTabs', {title: 'Auto Tabs', closable: true}));
56layout.add('center', new CP('center1', {title: 'Close Me', closable: true}));
57layout.add('center', new CP('center2', {title: 'Center Panel', closable: false}));
58layout.getRegion('center').showPanel('center1');
59layout.endUpdate();
60</code></pre>
61* @constructor
62* Create a new BorderLayout
63* @param {String/HTMLElement/Element} container The container this layout is bound to
64* @param {Object} config Configuration options
65 */
66YAHOO.ext.BorderLayout = function(container, config){
67 config = config || {};
68 YAHOO.ext.BorderLayout.superclass.constructor.call(this, container);
69 this.factory = config.factory || YAHOO.ext.BorderLayout.RegionFactory;
70 /**
71 * True to hide the center panel while performing layouts. This helps when the center region contains
72 * heavy components such as a yui-ext grid.
73 * @type Boolean
74 */
75 this.hideOnLayout = config.hideOnLayout || false;
76 for(var i = 0, len = this.factory.validRegions.length; i < len; i++) {
77 var target = this.factory.validRegions[i];
78 if(config[target]){
79 this.addRegion(target, config[target]);
80 }
81 }
82 //this.dragOverDelegate = YAHOO.ext.EventManager.wrap(this.onDragOver, this, true);
83};
84
85YAHOO.extendX(YAHOO.ext.BorderLayout, YAHOO.ext.LayoutManager, {
86 /**
87 * Creates and adds a new region if it doesn't already exist.
88 * @param {String} target The target region key (north, south, east, west or center).
89 * @param {Object} config The regions config object
90 * @return {BorderLayoutRegion} The new region
91 */
92 addRegion : function(target, config){
93 if(!this.regions[target]){
94 var r = this.factory.create(target, this, config);
95 this.regions[target] = r;
96 r.on('visibilitychange', this.layout, this, true);
97 r.on('paneladded', this.layout, this, true);
98 r.on('panelremoved', this.layout, this, true);
99 r.on('invalidated', this.layout, this, true);
100 r.on('resized', this.onRegionResized, this, true);
101 r.on('collapsed', this.onRegionCollapsed, this, true);
102 r.on('expanded', this.onRegionExpanded, this, true);
103 }
104 return this.regions[target];
105 },
106
107 /**
108 * Performs a layout update.
109 */
110 layout : function(){
111 if(this.updating) return;
112 //var bench = new YAHOO.ext.util.Bench();
113 //bench.start('Layout...');
114 var size = this.getViewSize();
115 var w = size.width, h = size.height;
116 var centerW = w, centerH = h, centerY = 0, centerX = 0;
117 var x = 0, y = 0;
118
119 var rs = this.regions;
120 var n = rs['north'], s = rs['south'], west = rs['west'], e = rs['east'], c = rs['center'];
121 if(this.hideOnLayout){
122 c.el.setStyle('display', 'none');
123 }
124 if(n && n.isVisible()){
125 var b = n.getBox();
126 var m = n.getMargins();
127 b.width = w - (m.left+m.right);
128 b.x = m.left;
129 b.y = m.top;
130 centerY = b.height + b.y + m.bottom;
131 centerH -= centerY;
132 n.updateBox(this.safeBox(b));
133 }
134 if(s && s.isVisible()){
135 var b = s.getBox();
136 var m = s.getMargins();
137 b.width = w - (m.left+m.right);
138 b.x = m.left;
139 var totalHeight = (b.height + m.top + m.bottom);
140 b.y = h - totalHeight + m.top;
141 centerH -= totalHeight;
142 s.updateBox(this.safeBox(b));
143 }
144 if(west && west.isVisible()){
145 var b = west.getBox();
146 var m = west.getMargins();
147 b.height = centerH - (m.top+m.bottom);
148 b.x = m.left;
149 b.y = centerY + m.top;
150 var totalWidth = (b.width + m.left + m.right);
151 centerX += totalWidth;
152 centerW -= totalWidth;
153 west.updateBox(this.safeBox(b));
154 }
155 if(e && e.isVisible()){
156 var b = e.getBox();
157 var m = e.getMargins();
158 b.height = centerH - (m.top+m.bottom);
159 var totalWidth = (b.width + m.left + m.right);
160 b.x = w - totalWidth + m.left;
161 b.y = centerY + m.top;
162 centerW -= totalWidth;
163 e.updateBox(this.safeBox(b));
164 }
165 if(c){
166 var m = c.getMargins();
167 var centerBox = {
168 x: centerX + m.left,
169 y: centerY + m.top,
170 width: centerW - (m.left+m.right),
171 height: centerH - (m.top+m.bottom)
172 };
173 if(this.hideOnLayout){
174 c.el.setStyle('display', 'block');
175 }
176 c.updateBox(this.safeBox(centerBox));
177 }
178 this.el.repaint();
179 this.fireEvent('layout', this);
180 //bench.stop();
181 //alert(bench.toString());
182 },
183
184 safeBox : function(box){
185 box.width = Math.max(0, box.width);
186 box.height = Math.max(0, box.height);
187 return box;
188 },
189
190 /**
191 * Adds a ContentPanel (or subclass) to this layout.
192 * @param {String} target The target region key (north, south, east, west or center).
193 * @param {YAHOO.ext.ContentPanel} panel The panel to add
194 * @return {YAHOO.ext.ContentPanel} The added panel
195 */
196 add : function(target, panel){
197 target = target.toLowerCase();
198 return this.regions[target].add(panel);
199 },
200
201 /**
202 * Adds a ContentPanel (or subclass) to this layout.
203 * @param {String} target The target region key (north, south, east, west or center).
204 * @param {Number/String/YAHOO.ext.ContentPanel} panel The index, id or panel to remove
205 * @return {YAHOO.ext.ContentPanel} The removed panel
206 */
207 remove : function(target, panel){
208 target = target.toLowerCase();
209 return this.regions[target].remove(panel);
210 },
211
212 /**
213 * Searches all regions for a panel with the specified id
214 * @param {String} panelId
215 * @return {YAHOO.ext.ContentPanel} The panel or null if it wasn't found
216 */
217 findPanel : function(panelId){
218 var rs = this.regions;
219 for(var target in rs){
220 if(typeof rs[target] != 'function'){
221 var p = rs[target].getPanel(panelId);
222 if(p){
223 return p;
224 }
225 }
226 }
227 return null;
228 },
229
230 /**
231 * Searches all regions for a panel with the specified id and activates (shows) it.
232 * @param {String/ContentPanel} panelId The panels id or the panel itself
233 * @return {YAHOO.ext.ContentPanel} The shown panel or null
234 */
235 showPanel : function(panelId) {
236 var rs = this.regions;
237 for(var target in rs){
238 var r = rs[target];
239 if(typeof r != 'function'){
240 if(r.hasPanel(panelId)){
241 return r.showPanel(panelId);
242 }
243 }
244 }
245 return null;
246 },
247
248 /**
249 * Restores this layouts state using YAHOO.ext.state.Manager or the state provided by the passed provider.
250 * @param {YAHOO.ext.state.Provider} provider (optional) An alternate state provider
251 */
252 restoreState : function(provider){
253 if(!provider){
254 provider = YAHOO.ext.state.Manager;
255 }
256 var sm = new YAHOO.ext.LayoutStateManager();
257 sm.init(this, provider);
258 }
259});
260
261YAHOO.ext.BorderLayout.RegionFactory = {};
262YAHOO.ext.BorderLayout.RegionFactory.validRegions = ['north','south','east','west','center'];
263YAHOO.ext.BorderLayout.RegionFactory.create = function(target, mgr, config){
264 target = target.toLowerCase();
265 if(config.lightweight || config.basic){
266 return new YAHOO.ext.BasicLayoutRegion(mgr, config, target);
267 }
268 switch(target){
269 case 'north':
270 return new YAHOO.ext.NorthLayoutRegion(mgr, config);
271 case 'south':
272 return new YAHOO.ext.SouthLayoutRegion(mgr, config);
273 case 'east':
274 return new YAHOO.ext.EastLayoutRegion(mgr, config);
275 case 'west':
276 return new YAHOO.ext.WestLayoutRegion(mgr, config);
277 case 'center':
278 return new YAHOO.ext.CenterLayoutRegion(mgr, config);
279 }
280 throw 'Layout region "'+target+'" not supported.';
281};
diff --git a/frontend/beta/js/YUI-extensions/layout/BorderLayoutRegions.js b/frontend/beta/js/YUI-extensions/layout/BorderLayoutRegions.js
new file mode 100644
index 0000000..9b4a09f
--- a/dev/null
+++ b/frontend/beta/js/YUI-extensions/layout/BorderLayoutRegions.js
@@ -0,0 +1,207 @@
1/*
2 * These classes are private internal classes
3 */
4YAHOO.ext.CenterLayoutRegion = function(mgr, config){
5 YAHOO.ext.CenterLayoutRegion.superclass.constructor.call(this, mgr, config, 'center');
6 this.visible = true;
7 this.minWidth = config.minWidth || 20;
8 this.minHeight = config.minHeight || 20;
9};
10
11YAHOO.extendX(YAHOO.ext.CenterLayoutRegion, YAHOO.ext.LayoutRegion, {
12 hide : function(){
13 // center panel can't be hidden
14 },
15
16 show : function(){
17 // center panel can't be hidden
18 },
19
20 getMinWidth: function(){
21 return this.minWidth;
22 },
23
24 getMinHeight: function(){
25 return this.minHeight;
26 }
27});
28
29
30YAHOO.ext.NorthLayoutRegion = function(mgr, config){
31 YAHOO.ext.NorthLayoutRegion.superclass.constructor.call(this, mgr, config, 'north', 'n-resize');
32 if(this.split){
33 this.split.placement = YAHOO.ext.SplitBar.TOP;
34 this.split.orientation = YAHOO.ext.SplitBar.VERTICAL;
35 this.split.el.addClass('ylayout-split-v');
36 }
37 if(typeof config.initialSize != 'undefined'){
38 this.el.setHeight(config.initialSize);
39 }
40};
41YAHOO.extendX(YAHOO.ext.NorthLayoutRegion, YAHOO.ext.SplitLayoutRegion, {
42 getBox : function(){
43 if(this.collapsed){
44 return this.collapsedEl.getBox();
45 }
46 var box = this.el.getBox();
47 if(this.split){
48 box.height += this.split.el.getHeight();
49 }
50 return box;
51 },
52
53 updateBox : function(box){
54 if(this.split && !this.collapsed){
55 box.height -= this.split.el.getHeight();
56 this.split.el.setLeft(box.x);
57 this.split.el.setTop(box.y+box.height);
58 this.split.el.setWidth(box.width);
59 }
60 if(this.collapsed){
61 this.el.setWidth(box.width);
62 var bodyWidth = box.width - this.el.getBorderWidth('rl');
63 this.bodyEl.setWidth(bodyWidth);
64 if(this.activePanel && this.panelSize){
65 this.activePanel.setSize(bodyWidth, this.panelSize.height);
66 }
67 }
68 YAHOO.ext.NorthLayoutRegion.superclass.updateBox.call(this, box);
69 }
70});
71
72YAHOO.ext.SouthLayoutRegion = function(mgr, config){
73 YAHOO.ext.SouthLayoutRegion.superclass.constructor.call(this, mgr, config, 'south', 's-resize');
74 if(this.split){
75 this.split.placement = YAHOO.ext.SplitBar.BOTTOM;
76 this.split.orientation = YAHOO.ext.SplitBar.VERTICAL;
77 this.split.el.addClass('ylayout-split-v');
78 }
79 if(typeof config.initialSize != 'undefined'){
80 this.el.setHeight(config.initialSize);
81 }
82};
83YAHOO.extendX(YAHOO.ext.SouthLayoutRegion, YAHOO.ext.SplitLayoutRegion, {
84 getBox : function(){
85 if(this.collapsed){
86 return this.collapsedEl.getBox();
87 }
88 var box = this.el.getBox();
89 if(this.split){
90 var sh = this.split.el.getHeight();
91 box.height += sh;
92 box.y -= sh;
93 }
94 return box;
95 },
96
97 updateBox : function(box){
98 if(this.split && !this.collapsed){
99 var sh = this.split.el.getHeight();
100 box.height -= sh;
101 box.y += sh;
102 this.split.el.setLeft(box.x);
103 this.split.el.setTop(box.y-sh);
104 this.split.el.setWidth(box.width);
105 }
106 if(this.collapsed){
107 this.el.setWidth(box.width);
108 var bodyWidth = box.width - this.el.getBorderWidth('rl');
109 this.bodyEl.setWidth(bodyWidth);
110 if(this.activePanel && this.panelSize){
111 this.activePanel.setSize(bodyWidth, this.panelSize.height);
112 }
113 }
114 YAHOO.ext.SouthLayoutRegion.superclass.updateBox.call(this, box);
115 }
116});
117
118YAHOO.ext.EastLayoutRegion = function(mgr, config){
119 YAHOO.ext.EastLayoutRegion.superclass.constructor.call(this, mgr, config, 'east', 'e-resize');
120 if(this.split){
121 this.split.placement = YAHOO.ext.SplitBar.RIGHT;
122 this.split.orientation = YAHOO.ext.SplitBar.HORIZONTAL;
123 this.split.el.addClass('ylayout-split-h');
124 }
125 if(typeof config.initialSize != 'undefined'){
126 this.el.setWidth(config.initialSize);
127 }
128};
129YAHOO.extendX(YAHOO.ext.EastLayoutRegion, YAHOO.ext.SplitLayoutRegion, {
130 getBox : function(){
131 if(this.collapsed){
132 return this.collapsedEl.getBox();
133 }
134 var box = this.el.getBox();
135 if(this.split){
136 var sw = this.split.el.getWidth();
137 box.width += sw;
138 box.x -= sw;
139 }
140 return box;
141 },
142
143 updateBox : function(box){
144 if(this.split && !this.collapsed){
145 var sw = this.split.el.getWidth();
146 box.width -= sw;
147 this.split.el.setLeft(box.x);
148 this.split.el.setTop(box.y);
149 this.split.el.setHeight(box.height);
150 box.x += sw;
151 }
152 if(this.collapsed){
153 this.el.setHeight(box.height);
154 var bodyHeight = this.config.titlebar ? box.height - (this.titleEl.getHeight()||0) : box.height;
155 bodyHeight -= this.el.getBorderWidth('tb');
156 this.bodyEl.setHeight(bodyHeight);
157 if(this.activePanel && this.panelSize){
158 this.activePanel.setSize(this.panelSize.width, bodyHeight);
159 }
160 }
161 YAHOO.ext.EastLayoutRegion.superclass.updateBox.call(this, box);
162 }
163});
164
165YAHOO.ext.WestLayoutRegion = function(mgr, config){
166 YAHOO.ext.WestLayoutRegion.superclass.constructor.call(this, mgr, config, 'west', 'w-resize');
167 if(this.split){
168 this.split.placement = YAHOO.ext.SplitBar.LEFT;
169 this.split.orientation = YAHOO.ext.SplitBar.HORIZONTAL;
170 this.split.el.addClass('ylayout-split-h');
171 }
172 if(typeof config.initialSize != 'undefined'){
173 this.el.setWidth(config.initialSize);
174 }
175};
176YAHOO.extendX(YAHOO.ext.WestLayoutRegion, YAHOO.ext.SplitLayoutRegion, {
177 getBox : function(){
178 if(this.collapsed){
179 return this.collapsedEl.getBox();
180 }
181 var box = this.el.getBox();
182 if(this.split){
183 box.width += this.split.el.getWidth();
184 }
185 return box;
186 },
187
188 updateBox : function(box){
189 if(this.split && !this.collapsed){
190 var sw = this.split.el.getWidth();
191 box.width -= sw;
192 this.split.el.setLeft(box.x+box.width);
193 this.split.el.setTop(box.y);
194 this.split.el.setHeight(box.height);
195 }
196 if(this.collapsed){
197 this.el.setHeight(box.height);
198 var bodyHeight = this.config.titlebar ? box.height - (this.titleEl.getHeight()||0) : box.height;
199 bodyHeight -= this.el.getBorderWidth('tb');
200 this.bodyEl.setHeight(bodyHeight);
201 if(this.activePanel && this.panelSize){
202 this.activePanel.setSize(this.panelSize.width, bodyHeight);
203 }
204 }
205 YAHOO.ext.WestLayoutRegion.superclass.updateBox.call(this, box);
206 }
207});
diff --git a/frontend/beta/js/YUI-extensions/layout/ContentPanels.js b/frontend/beta/js/YUI-extensions/layout/ContentPanels.js
new file mode 100644
index 0000000..7cfdde7
--- a/dev/null
+++ b/frontend/beta/js/YUI-extensions/layout/ContentPanels.js
@@ -0,0 +1,325 @@
1/**
2 * @class YAHOO.ext.ContentPanel
3 * @extends YAHOO.ext.util.Observable
4 * A basic ContentPanel element.
5 * @cfg {Boolean} fitToFrame True for this panel to manually adjust it's size when the region resizes (defaults to false)
6 * @cfg {Boolean/Object} autoCreate True to auto generate the DOM element for this panel, or a DomHelper config of the element to create
7 * @cfg {Boolean} closable True if the panel can be closed/removed
8 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
9 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if fitToFrame is true (instead of this panel's element)
10 * @cfg {Toolbar} toolbar A toolbar for this panel
11 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with fitToFrame)
12 * @cfg {String} title The title for this panel
13 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a fitToFrame (default is [0, 0])
14 * @constructor
15 * Create a new ContentPanel.
16 * @param {String/HTMLElement/Element} el The container element for this panel
17 * @param {String/Object} config A string to set only the title or a config object
18 * @param {String} content (optional) Set the HTML content for this panel
19 */
20YAHOO.ext.ContentPanel = function(el, config, content){
21 YAHOO.ext.ContentPanel.superclass.constructor.call(this);
22 this.el = getEl(el, true);
23 if(!this.el && config && config.autoCreate){
24 if(typeof config.autoCreate == 'object'){
25 if(!config.autoCreate.id){
26 config.autoCreate.id = el;
27 }
28 this.el = YAHOO.ext.DomHelper.append(document.body,
29 config.autoCreate, true);
30 }else{
31 this.el = YAHOO.ext.DomHelper.append(document.body,
32 {tag: 'div', cls: 'ylayout-inactive-content', id: el}, true);
33 }
34 }
35 this.closable = false;
36 this.loaded = false;
37 this.active = false;
38 if(typeof config == 'string'){
39 this.title = config;
40 }else{
41 YAHOO.ext.util.Config.apply(this, config);
42 }
43 if(this.resizeEl){
44 this.resizeEl = getEl(this.resizeEl, true);
45 }else{
46 this.resizeEl = this.el;
47 }
48 this.events = {
49 /**
50 * @event activate
51 * Fires when this panel is activated.
52 * @param {YAHOO.ext.ContentPanel} this
53 */
54 'activate' : new YAHOO.util.CustomEvent('activate'),
55 /**
56 * @event deactivate
57 * Fires when this panel is activated.
58 * @param {YAHOO.ext.ContentPanel} this
59 */
60 'deactivate' : new YAHOO.util.CustomEvent('deactivate')
61 };
62 if(this.autoScroll){
63 this.resizeEl.setStyle('overflow', 'auto');
64 }
65 if(content){
66 this.setContent(content);
67 }
68};
69
70YAHOO.extendX(YAHOO.ext.ContentPanel, YAHOO.ext.util.Observable, {
71 setRegion : function(region){
72 this.region = region;
73 if(region){
74 this.el.replaceClass('ylayout-inactive-content', 'ylayout-active-content');
75 }else{
76 this.el.replaceClass('ylayout-active-content', 'ylayout-inactive-content');
77 }
78 },
79
80 /**
81 * Returns the toolbar for this Panel if one was configured
82 * @return {YAHOO.ext.Toolbar}
83 */
84 getToolbar : function(){
85 return this.toolbar;
86 },
87
88 setActiveState : function(active){
89 this.active = active;
90 if(!active){
91 this.fireEvent('deactivate', this);
92 }else{
93 this.fireEvent('activate', this);
94 }
95 },
96 /**
97 * Updates this panel's element
98 * @param {String} content The new content
99 * @param {<i>Boolean</i>} loadScripts (optional) true to look for and process scripts
100 */
101 setContent : function(content, loadScripts){
102 this.el.update(content, loadScripts);
103 },
104
105 /**
106 * Get the {@link YAHOO.ext.UpdateManager} for this panel. Enables you to perform Ajax updates.
107 * @return {YAHOO.ext.UpdateManager} The UpdateManager
108 */
109 getUpdateManager : function(){
110 return this.el.getUpdateManager();
111 },
112
113 /**
114 * Set a URL to be used to load the content for this panel.
115 * @param {String/Function} url The url to load the content from or a function to call to get the url
116 * @param {<i>String/Object</i>} params (optional) The string params for the update call or an object of the params. See {@link YAHOO.ext.UpdateManager#update} for more details. (Defaults to null)
117 * @param {<i>Boolean</i>} loadOnce (optional) Whether to only load the content once. If this is false it makes the Ajax call every time this panel is activated. (Defaults to false)
118 * @return {YAHOO.ext.UpdateManager} The UpdateManager
119 */
120 setUrl : function(url, params, loadOnce){
121 if(this.refreshDelegate){
122 this.removeListener('activate', this.refreshDelegate);
123 }
124 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
125 this.on('activate', this._handleRefresh.createDelegate(this, [url, params, loadOnce]));
126 return this.el.getUpdateManager();
127 },
128
129 _handleRefresh : function(url, params, loadOnce){
130 if(!loadOnce || !this.loaded){
131 var updater = this.el.getUpdateManager();
132 updater.update(url, params, this._setLoaded.createDelegate(this));
133 }
134 },
135
136 _setLoaded : function(){
137 this.loaded = true;
138 },
139
140 /**
141 * Returns this panel's id
142 * @return {String}
143 */
144 getId : function(){
145 return this.el.id;
146 },
147
148 /**
149 * Returns this panel's element
150 * @return {YAHOO.ext.Element}
151 */
152 getEl : function(){
153 return this.el;
154 },
155
156 adjustForComponents : function(width, height){
157 if(this.toolbar){
158 var te = this.toolbar.getEl();
159 height -= te.getHeight();
160 te.setWidth(width);
161 }
162 if(this.adjustments){
163 width += this.adjustments[0];
164 height += this.adjustments[1];
165 }
166 return {'width': width, 'height': height};
167 },
168
169 setSize : function(width, height){
170 if(this.fitToFrame){
171 var size = this.adjustForComponents(width, height);
172 this.resizeEl.setSize(this.autoWidth ? 'auto' : size.width, size.height);
173 }
174 },
175
176 /**
177 * Returns this panel's title
178 * @return {String}
179 */
180 getTitle : function(){
181 return this.title;
182 },
183
184 /**
185 * Set this panel's title
186 * @param {String} title
187 */
188 setTitle : function(title){
189 this.title = title;
190 if(this.region){
191 this.region.updatePanelTitle(this, title);
192 }
193 },
194
195 /**
196 * Returns true is this panel was configured to be closable
197 * @return {Boolean}
198 */
199 isClosable : function(){
200 return this.closable;
201 },
202
203 beforeSlide : function(){
204 this.el.clip();
205 this.resizeEl.clip();
206 },
207
208 afterSlide : function(){
209 this.el.unclip();
210 this.resizeEl.unclip();
211 },
212
213 /**
214 * Force a content refresh from the URL specified in the setUrl() method.
215 * Will fail silently if the setUrl method has not been called.
216 * This does not activate the panel, just updates its content.
217 */
218 refresh : function(){
219 if(this.refreshDelegate){
220 this.loaded = false;
221 this.refreshDelegate();
222 }
223 },
224
225 /**
226 * Destroys this panel
227 */
228 destroy : function(){
229 this.el.removeAllListeners();
230 var tempEl = document.createElement('span');
231 tempEl.appendChild(this.el.dom);
232 tempEl.innerHTML = '';
233 this.el = null;
234 }
235});
236
237/**
238 * @class YAHOO.ext.GridPanel
239 * @extends YAHOO.ext.ContentPanel
240 * @constructor
241 * Create a new GridPanel.
242 * @param {YAHOO.ext.grid.Grid} grid The grid for this panel
243 * @param {String/Object} config A string to set only the title or a config object
244 */
245YAHOO.ext.GridPanel = function(grid, config){
246 this.wrapper = YAHOO.ext.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
247 {tag: 'div', cls: 'ylayout-grid-wrapper ylayout-inactive-content'}, true);
248 this.wrapper.dom.appendChild(grid.container.dom);
249 YAHOO.ext.GridPanel.superclass.constructor.call(this, this.wrapper, config);
250 if(this.toolbar){
251 this.toolbar.el.insertBefore(this.wrapper.dom.firstChild);
252 }
253 grid.monitorWindowResize = false; // turn off autosizing
254 grid.autoHeight = false;
255 grid.autoWidth = false;
256 this.grid = grid;
257 this.grid.container.replaceClass('ylayout-inactive-content', 'ylayout-component-panel');
258};
259
260YAHOO.extendX(YAHOO.ext.GridPanel, YAHOO.ext.ContentPanel, {
261 getId : function(){
262 return this.grid.id;
263 },
264
265 /**
266 * Returns the grid for this panel
267 * @return {YAHOO.ext.grid.Grid}
268 */
269 getGrid : function(){
270 return this.grid;
271 },
272
273 setSize : function(width, height){
274 var grid = this.grid;
275 var size = this.adjustForComponents(width, height);
276 grid.container.setSize(size.width, size.height);
277 grid.autoSize();
278 },
279
280 beforeSlide : function(){
281 this.grid.getView().wrapEl.clip();
282 },
283
284 afterSlide : function(){
285 this.grid.getView().wrapEl.unclip();
286 },
287
288 destroy : function(){
289 this.grid.getView().unplugDataModel(this.grid.getDataModel());
290 this.grid.container.removeAllListeners();
291 YAHOO.ext.GridPanel.superclass.destroy.call(this);
292 }
293});
294
295
296/**
297 * @class YAHOO.ext.NestedLayoutPanel
298 * @extends YAHOO.ext.ContentPanel
299 * @constructor
300 * Create a new NestedLayoutPanel.
301 * @param {YAHOO.ext.BorderLayout} layout The layout for this panel
302 * @param {String/Object} config A string to set only the title or a config object
303 */
304YAHOO.ext.NestedLayoutPanel = function(layout, config){
305 YAHOO.ext.NestedLayoutPanel.superclass.constructor.call(this, layout.getEl(), config);
306 layout.monitorWindowResize = false; // turn off autosizing
307 this.layout = layout;
308 this.layout.getEl().addClass('ylayout-nested-layout');
309};
310
311YAHOO.extendX(YAHOO.ext.NestedLayoutPanel, YAHOO.ext.ContentPanel, {
312 setSize : function(width, height){
313 var size = this.adjustForComponents(width, height);
314 this.layout.getEl().setSize(size.width, size.height);
315 this.layout.layout();
316 },
317
318 /**
319 * Returns the nested BorderLayout for this panel
320 * @return {YAHOO.ext.BorderLayout}
321 */
322 getLayout : function(){
323 return this.layout;
324 }
325});
diff --git a/frontend/beta/js/YUI-extensions/layout/LayoutManager.js b/frontend/beta/js/YUI-extensions/layout/LayoutManager.js
new file mode 100644
index 0000000..c59bf0e
--- a/dev/null
+++ b/frontend/beta/js/YUI-extensions/layout/LayoutManager.js
@@ -0,0 +1,135 @@
1/**
2 * @class YAHOO.ext.LayoutManager
3 * @extends YAHOO.ext.util.Observable
4 * Base class for layout managers.
5 */
6YAHOO.ext.LayoutManager = function(container){
7 YAHOO.ext.LayoutManager.superclass.constructor.call(this);
8 this.el = getEl(container, true);
9 // ie scrollbar fix
10 if(this.el.dom == document.body && YAHOO.ext.util.Browser.isIE){
11 document.body.scroll = 'no';
12 }
13 this.id = this.el.id;
14 this.el.addClass('ylayout-container');
15 /** false to disable window resize monitoring @type Boolean */
16 this.monitorWindowResize = true;
17 this.regions = {};
18 this.events = {
19 /**
20 * @event layout
21 * Fires when a layout is performed.
22 * @param {YAHOO.ext.LayoutManager} this
23 */
24 'layout' : new YAHOO.util.CustomEvent(),
25 /**
26 * @event regionresized
27 * Fires when the user resizes a region.
28 * @param {YAHOO.ext.LayoutRegion} region
29 * @param {Number} newSize The new size (width for east/west, height for north/south)
30 */
31 'regionresized' : new YAHOO.util.CustomEvent(),
32 /**
33 * @event regioncollapsed
34 * Fires when a region is collapsed.
35 * @param {YAHOO.ext.LayoutRegion} region
36 */
37 'regioncollapsed' : new YAHOO.util.CustomEvent(),
38 /**
39 * @event regionexpanded
40 * Fires when a region is expanded.
41 * @param {YAHOO.ext.LayoutRegion} region
42 */
43 'regionexpanded' : new YAHOO.util.CustomEvent()
44 };
45 this.updating = false;
46 YAHOO.ext.EventManager.onWindowResize(this.onWindowResize, this, true);
47};
48
49YAHOO.extendX(YAHOO.ext.LayoutManager, YAHOO.ext.util.Observable, {
50 /**
51 * Returns true if this layout is currently being updated
52 * @return {Boolean}
53 */
54 isUpdating : function(){
55 return this.updating;
56 },
57
58 /**
59 * Suspend the LayoutManager from doing auto-layouts while
60 * making multiple add or remove calls
61 */
62 beginUpdate : function(){
63 this.updating = true;
64 },
65
66 /**
67 * Restore auto-layouts and optionally disable the manager from performing a layout
68 * @param {Boolean} noLayout true to disable a layout update
69 */
70 endUpdate : function(noLayout){
71 this.updating = false;
72 if(!noLayout){
73 this.layout();
74 }
75 },
76
77 layout: function(){
78
79 },
80
81 onRegionResized : function(region, newSize){
82 this.fireEvent('regionresized', region, newSize);
83 this.layout();
84 },
85
86 onRegionCollapsed : function(region){
87 this.fireEvent('regioncollapsed', region);
88 },
89
90 onRegionExpanded : function(region){
91 this.fireEvent('regionexpanded', region);
92 },
93
94 /**
95 * Returns the size of the current view, This method normalizes document.body and element embedded layouts and
96 * performs box-model adjustments.
97 * @return {Object} The size as an object {width: (the width), height: (the height)}
98 */
99 getViewSize : function(){
100 var size;
101 if(this.el.dom != document.body){
102 this.el.beginMeasure();
103 size = this.el.getSize();
104 this.el.endMeasure();
105 }else{
106 size = {width: YAHOO.util.Dom.getViewportWidth(), height: YAHOO.util.Dom.getViewportHeight()};
107 }
108 size.width -= this.el.getBorderWidth('lr')-this.el.getPadding('lr');
109 size.height -= this.el.getBorderWidth('tb')-this.el.getPadding('tb');
110 return size;
111 },
112
113 /**
114 * Returns the element this layout is bound to.
115 * @return {YAHOO.ext.Element}
116 */
117 getEl : function(){
118 return this.el;
119 },
120
121 /**
122 * Returns the specified region.
123 * @param {String} target The region key
124 * @return {YAHOO.ext.LayoutRegion}
125 */
126 getRegion : function(target){
127 return this.regions[target.toLowerCase()];
128 },
129
130 onWindowResize : function(){
131 if(this.monitorWindowResize){
132 this.layout();
133 }
134 }
135});
diff --git a/frontend/beta/js/YUI-extensions/layout/LayoutRegion.js b/frontend/beta/js/YUI-extensions/layout/LayoutRegion.js
new file mode 100644
index 0000000..fa8a1b6
--- a/dev/null
+++ b/frontend/beta/js/YUI-extensions/layout/LayoutRegion.js
@@ -0,0 +1,496 @@
1/**
2 * @class YAHOO.ext.LayoutRegion
3 * @extends YAHOO.ext.util.Observable
4 * This class represents a region in a layout manager.
5 * @cfg {Boolean} collapsible False to disable collapsing (defaults to true)
6 * @cfg {Boolean} floatable False to disable floating (defaults to true)
7 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
8 * @cfg {Object} cmargins Margins for the element when collapsed (defaults to: north/south {top: 2, left: 0, right:0, bottom: 2} or east/west {top: 0, left: 2, right:2, bottom: 0})
9 * @cfg {String} tabPosition 'top' or 'bottom' (defaults to 'bottom')
10 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when only 1 panel (defaults to false)
11 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
12 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
13 * @cfg {String} title The title for the region (overrides panel titles)
14 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
15 * @cfg {Float} duration The duration of the expand/collapse animation in seconds
16 * @cfg {Float} slideDuration The duration of the slide out/in when collapsed in seconds
17 * @cfg {Boolean} autoHide False to disable disable autoHide when the mouse leaves the "floated" region (defaults to true)
18 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
19 * @cfg {Boolean} closeOnTabs True to place the close icon on the tabs instead of the region titlebar (defaults to false)
20 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
21 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
22 * the space available, similar to FireFox 1.5 tabs (defaults to false)
23 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
24 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
25 */
26YAHOO.ext.LayoutRegion = function(mgr, config, pos){
27 YAHOO.ext.LayoutRegion.superclass.constructor.call(this, mgr, config, pos, true);
28 var dh = YAHOO.ext.DomHelper;
29 /** This regions container element @type YAHOO.ext.Element */
30 this.el = dh.append(mgr.el.dom, {tag: 'div', cls: 'ylayout-panel ylayout-panel-' + this.position}, true);
31 /** This regions title element @type YAHOO.ext.Element */
32 this.titleEl = dh.append(this.el.dom, {tag: 'div', unselectable: 'on', cls: 'yunselectable ylayout-panel-hd ylayout-title-'+this.position, children:[
33 {tag: 'span', cls: 'yunselectable ylayout-panel-hd-text', unselectable: 'on', html: '&#160;'},
34 {tag: 'div', cls: 'yunselectable ylayout-panel-hd-tools', unselectable: 'on'}
35 ]}, true);
36 this.titleEl.enableDisplayMode();
37 /** This regions title text element @type HTMLElement */
38 this.titleTextEl = this.titleEl.dom.firstChild;
39 this.tools = getEl(this.titleEl.dom.childNodes[1], true);
40 this.closeBtn = this.createTool(this.tools.dom, 'ylayout-close');
41 this.closeBtn.enableDisplayMode();
42 this.closeBtn.on('click', this.closeClicked, this, true);
43 this.closeBtn.hide();
44 /** This regions body element @type YAHOO.ext.Element */
45 this.bodyEl = dh.append(this.el.dom, {tag: 'div', cls: 'ylayout-panel-body'}, true);
46 this.visible = false;
47 this.collapsed = false;
48 this.hide();
49 this.on('paneladded', this.validateVisibility, this, true);
50 this.on('panelremoved', this.validateVisibility, this, true);
51
52 this.applyConfig(config);
53};
54
55YAHOO.extendX(YAHOO.ext.LayoutRegion, YAHOO.ext.BasicLayoutRegion, {
56 applyConfig : function(config){
57 if(config.collapsible && this.position != 'center' && !this.collapsedEl){
58 var dh = YAHOO.ext.DomHelper;
59 this.collapseBtn = this.createTool(this.tools.dom, 'ylayout-collapse-'+this.position);
60 this.collapseBtn.mon('click', this.collapse, this, true);
61 /** This regions collapsed element @type YAHOO.ext.Element */
62 this.collapsedEl = dh.append(this.mgr.el.dom, {tag: 'div', cls: 'ylayout-collapsed ylayout-collapsed-'+this.position, children:[
63 {tag: 'div', cls: 'ylayout-collapsed-tools'}
64 ]}, true);
65 if(config.floatable !== false){
66 this.collapsedEl.addClassOnOver('ylayout-collapsed-over');
67 this.collapsedEl.mon('click', this.collapseClick, this, true);
68 }
69 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild, 'ylayout-expand-'+this.position);
70 this.expandBtn.mon('click', this.expand, this, true);
71 }
72 if(this.collapseBtn){
73 this.collapseBtn.setVisible(config.collapsible == true);
74 }
75 this.cmargins = config.cmargins || this.cmargins ||
76 (this.position == 'west' || this.position == 'east' ?
77 {top: 0, left: 2, right:2, bottom: 0} :
78 {top: 2, left: 0, right:0, bottom: 2});
79 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
80 this.bottomTabs = config.tabPosition != 'top';
81 this.autoScroll = config.autoScroll || false;
82 if(this.autoScroll){
83 this.bodyEl.setStyle('overflow', 'auto');
84 }else{
85 this.bodyEl.setStyle('overflow', 'hidden');
86 }
87 if((!config.titlebar && !config.title) || config.titlebar === false){
88 this.titleEl.hide();
89 }else{
90 this.titleEl.show();
91 if(config.title){
92 this.titleTextEl.innerHTML = config.title;
93 }
94 }
95 this.duration = config.duration || .30;
96 this.slideDuration = config.slideDuration || .45;
97 this.config = config;
98 if(config.collapsed){
99 this.collapse(true);
100 }
101 },
102 /**
103 * Returns true if this region is currently visible.
104 * @return {Boolean}
105 */
106 isVisible : function(){
107 return this.visible;
108 },
109
110 getBox : function(){
111 var b;
112 if(!this.collapsed){
113 b = this.el.getBox(false, true);
114 }else{
115 b = this.collapsedEl.getBox(false, true);
116 }
117 return b;
118 },
119
120 getMargins : function(){
121 return this.collapsed ? this.cmargins : this.margins;
122 },
123
124 highlight : function(){
125 this.el.addClass('ylayout-panel-dragover');
126 },
127
128 unhighlight : function(){
129 this.el.removeClass('ylayout-panel-dragover');
130 },
131
132 updateBox : function(box){
133 this.box = box;
134 if(!this.collapsed){
135 this.el.dom.style.left = box.x + 'px';
136 this.el.dom.style.top = box.y + 'px';
137 this.el.setSize(box.width, box.height);
138 var bodyHeight = this.titleEl.isVisible() ? box.height - (this.titleEl.getHeight()||0) : box.height;
139 bodyHeight -= this.el.getBorderWidth('tb');
140 bodyWidth = box.width - this.el.getBorderWidth('rl');
141 this.bodyEl.setHeight(bodyHeight);
142 this.bodyEl.setWidth(bodyWidth);
143 var tabHeight = bodyHeight;
144 if(this.tabs){
145 tabHeight = this.tabs.syncHeight(bodyHeight);
146 if(YAHOO.ext.util.Browser.isIE) this.tabs.el.repaint();
147 }
148 this.panelSize = {width: bodyWidth, height: tabHeight};
149 if(this.activePanel){
150 this.activePanel.setSize(bodyWidth, tabHeight);
151 }
152 }else{
153 this.collapsedEl.dom.style.left = box.x + 'px';
154 this.collapsedEl.dom.style.top = box.y + 'px';
155 this.collapsedEl.setSize(box.width, box.height);
156 }
157 if(this.tabs){
158 this.tabs.autoSizeTabs();
159 }
160 },
161
162 /**
163 * Returns the container element for this region.
164 * @return {YAHOO.ext.Element}
165 */
166 getEl : function(){
167 return this.el;
168 },
169
170 /**
171 * Hides this region.
172 */
173 hide : function(){
174 if(!this.collapsed){
175 this.el.dom.style.left = '-2000px';
176 this.el.hide();
177 }else{
178 this.collapsedEl.dom.style.left = '-2000px';
179 this.collapsedEl.hide();
180 }
181 this.visible = false;
182 this.fireEvent('visibilitychange', this, false);
183 },
184
185 /**
186 * Shows this region if it was previously hidden.
187 */
188 show : function(){
189 if(!this.collapsed){
190 this.el.show();
191 }else{
192 this.collapsedEl.show();
193 }
194 this.visible = true;
195 this.fireEvent('visibilitychange', this, true);
196 },
197
198 closeClicked : function(){
199 if(this.activePanel){
200 this.remove(this.activePanel);
201 }
202 },
203
204 collapseClick : function(e){
205 if(this.isSlid){
206 e.stopPropagation();
207 this.slideIn();
208 }else{
209 e.stopPropagation();
210 this.slideOut();
211 }
212 },
213
214 /**
215 * Collapses this region.
216 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
217 */
218 collapse : function(skipAnim){
219 if(this.collapsed) return;
220 this.collapsed = true;
221 if(this.split){
222 this.split.el.hide();
223 }
224 if(this.config.animate && skipAnim !== true){
225 this.fireEvent('invalidated', this);
226 this.animateCollapse();
227 }else{
228 this.el.setLocation(-20000,-20000);
229 this.el.hide();
230 this.collapsedEl.show();
231 this.fireEvent('collapsed', this);
232 this.fireEvent('invalidated', this);
233 }
234 },
235
236 animateCollapse : function(){
237 // overridden
238 },
239
240 /**
241 * Expand this region if it was previously collapsed.
242 * @param {YAHOO.ext.EventObject} e The event that triggered the expand (or null if calling manually)
243 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
244 */
245 expand : function(e, skipAnim){
246 if(e) e.stopPropagation();
247 if(!this.collapsed) return;
248 if(this.isSlid){
249 this.slideIn(this.expand.createDelegate(this));
250 return;
251 }
252 this.collapsed = false;
253 this.el.show();
254 if(this.config.animate && skipAnim !== true){
255 this.animateExpand();
256 }else{
257 if(this.split){
258 this.split.el.show();
259 }
260 this.collapsedEl.setLocation(-2000,-2000);
261 this.collapsedEl.hide();
262 this.fireEvent('invalidated', this);
263 this.fireEvent('expanded', this);
264 }
265 },
266
267 animateExpand : function(){
268 // overridden
269 },
270
271 initTabs : function(){
272 this.bodyEl.setStyle('overflow', 'hidden');
273 var ts = new YAHOO.ext.TabPanel(this.bodyEl.dom, this.bottomTabs);
274 if(this.config.hideTabs){
275 ts.stripWrap.setDisplayed(false);
276 }
277 this.tabs = ts;
278 ts.resizeTabs = this.config.resizeTabs === true;
279 ts.minTabWidth = this.config.minTabWidth || 40;
280 ts.maxTabWidth = this.config.maxTabWidth || 250;
281 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
282 ts.monitorResize = false;
283 ts.bodyEl.setStyle('overflow', this.config.autoScroll ? 'auto' : 'hidden');
284 this.panels.each(this.initPanelAsTab, this);
285 },
286
287 initPanelAsTab : function(panel){
288 var ti = this.tabs.addTab(panel.getEl().id, panel.getTitle(), null,
289 this.config.closeOnTab && panel.isClosable());
290 ti.on('activate', function(){
291 this.setActivePanel(panel);
292 }, this, true);
293 if(this.config.closeOnTab){
294 ti.on('beforeclose', function(t, e){
295 e.cancel = true;
296 this.remove(panel);
297 }, this, true);
298 }
299 return ti;
300 },
301
302 updatePanelTitle : function(panel, title){
303 if(this.activePanel == panel){
304 this.updateTitle(title);
305 }
306 if(this.tabs){
307 this.tabs.getTab(panel.getEl().id).setText(title);
308 }
309 },
310
311 updateTitle : function(title){
312 if(this.titleTextEl && !this.config.title){
313 this.titleTextEl.innerHTML = (typeof title != 'undefined' && title.length > 0 ? title : "&#160;");
314 }
315 },
316
317 setActivePanel : function(panel){
318 panel = this.getPanel(panel);
319 if(this.activePanel && this.activePanel != panel){
320 this.activePanel.setActiveState(false);
321 }
322 this.activePanel = panel;
323 panel.setActiveState(true);
324 if(this.panelSize){
325 panel.setSize(this.panelSize.width, this.panelSize.height);
326 }
327 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
328 this.updateTitle(panel.getTitle());
329 this.fireEvent('panelactivated', this, panel);
330 },
331
332 /**
333 * Show the specified panel.
334 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
335 * @return {YAHOO.ext.ContentPanel} The shown panel or null
336 */
337 showPanel : function(panel){
338 if(panel = this.getPanel(panel)){
339 if(this.tabs){
340 this.tabs.activate(panel.getEl().id);
341 }else{
342 this.setActivePanel(panel);
343 }
344 }
345 return panel;
346 },
347
348 /**
349 * Get the active panel for this region.
350 * @return {YAHOO.ext.ContentPanel} The active panel or null
351 */
352 getActivePanel : function(){
353 return this.activePanel;
354 },
355
356 validateVisibility : function(){
357 if(this.panels.getCount() < 1){
358 this.updateTitle('&#160;');
359 this.closeBtn.hide();
360 this.hide();
361 }else{
362 if(!this.isVisible()){
363 this.show();
364 }
365 }
366 },
367
368 /**
369 * Add the passed ContentPanel(s)
370 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
371 * @return {YAHOO.ext.ContentPanel} The panel added (if only one was added)
372 */
373 add : function(panel){
374 if(arguments.length > 1){
375 for(var i = 0, len = arguments.length; i < len; i++) {
376 this.add(arguments[i]);
377 }
378 return null;
379 }
380 if(this.hasPanel(panel)){
381 this.showPanel(panel);
382 return panel;
383 }
384 panel.setRegion(this);
385 this.panels.add(panel);
386 if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
387 this.bodyEl.dom.appendChild(panel.getEl().dom);
388 if(panel.background !== true){
389 this.setActivePanel(panel);
390 }
391 this.fireEvent('paneladded', this, panel);
392 return panel;
393 }
394 if(!this.tabs){
395 this.initTabs();
396 }else{
397 this.initPanelAsTab(panel);
398 }
399 if(panel.background !== true){
400 this.tabs.activate(panel.getEl().id);
401 }
402 this.fireEvent('paneladded', this, panel);
403 return panel;
404 },
405
406 /**
407 * Hides the tab for the specified panel.
408 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
409 */
410 hidePanel : function(panel){
411 if(this.tabs && (panel = this.getPanel(panel))){
412 this.tabs.hideTab(panel.getEl().id);
413 }
414 },
415
416 /**
417 * Unhides the tab for a previously hidden panel.
418 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
419 */
420 unhidePanel : function(panel){
421 if(this.tabs && (panel = this.getPanel(panel))){
422 this.tabs.unhideTab(panel.getEl().id);
423 }
424 },
425
426 clearPanels : function(){
427 while(this.panels.getCount() > 0){
428 this.remove(this.panels.first());
429 }
430 },
431
432 /**
433 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
434 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
435 * @param {Boolean} preservePanel Overrides the config preservePanel option
436 * @return {YAHOO.ext.ContentPanel} The panel that was removed
437 */
438 remove : function(panel, preservePanel){
439 panel = this.getPanel(panel);
440 if(!panel){
441 return null;
442 }
443 var e = {};
444 this.fireEvent('beforeremove', this, panel, e);
445 if(e.cancel === true){
446 return null;
447 }
448 preservePanel = (typeof preservePanel != 'undefined' ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
449 var panelId = panel.getId();
450 this.panels.removeKey(panelId);
451 if(preservePanel){
452 document.body.appendChild(panel.getEl().dom);
453 }
454 if(this.tabs){
455 this.tabs.removeTab(panel.getEl().id);
456 }else if (!preservePanel){
457 this.bodyEl.dom.removeChild(panel.getEl().dom);
458 }
459 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
460 var p = this.panels.first();
461 var tempEl = document.createElement('span'); // temp holder to keep IE from deleting the node
462 tempEl.appendChild(p.getEl().dom);
463 this.bodyEl.update('');
464 this.bodyEl.dom.appendChild(p.getEl().dom);
465 tempEl = null;
466 this.updateTitle(p.getTitle());
467 this.tabs = null;
468 this.bodyEl.setStyle('overflow', this.config.autoScroll ? 'auto' : 'hidden');
469 this.setActivePanel(p);
470 }
471 panel.setRegion(null);
472 if(this.activePanel == panel){
473 this.activePanel = null;
474 }
475 if(this.config.autoDestroy !== false && preservePanel !== true){
476 try{panel.destroy();}catch(e){}
477 }
478 this.fireEvent('panelremoved', this, panel);
479 return panel;
480 },
481
482 /**
483 * Returns the TabPanel component used by this region
484 * @return {YAHOO.ext.TabPanel}
485 */
486 getTabs : function(){
487 return this.tabs;
488 },
489
490 createTool : function(parentEl, className){
491 var btn = YAHOO.ext.DomHelper.append(parentEl, {tag: 'div', cls: 'ylayout-tools-button',
492 children: [{tag: 'div', cls: 'ylayout-tools-button-inner ' + className, html: '&#160;'}]}, true);
493 btn.addClassOnOver('ylayout-tools-button-over');
494 return btn;
495 }
496});
diff --git a/frontend/beta/js/YUI-extensions/layout/LayoutStateManager.js b/frontend/beta/js/YUI-extensions/layout/LayoutStateManager.js
new file mode 100644
index 0000000..ea22235
--- a/dev/null
+++ b/frontend/beta/js/YUI-extensions/layout/LayoutStateManager.js
@@ -0,0 +1,68 @@
1/*
2 * Private internal class for reading and applying state
3 */
4YAHOO.ext.LayoutStateManager = function(layout){
5 // default empty state
6 this.state = {
7 north: {},
8 south: {},
9 east: {},
10 west: {}
11 };
12};
13
14YAHOO.ext.LayoutStateManager.prototype = {
15 init : function(layout, provider){
16 this.provider = provider;
17 var state = provider.get(layout.id+'-layout-state');
18 if(state){
19 var wasUpdating = layout.isUpdating();
20 if(!wasUpdating){
21 layout.beginUpdate();
22 }
23 for(var key in state){
24 if(typeof state[key] != 'function'){
25 var rstate = state[key];
26 var r = layout.getRegion(key);
27 if(r && rstate){
28 if(rstate.size){
29 r.resizeTo(rstate.size);
30 }
31 if(rstate.collapsed == true){
32 r.collapse(true);
33 }else{
34 r.expand(null, true);
35 }
36 }
37 }
38 }
39 if(!wasUpdating){
40 layout.endUpdate();
41 }
42 this.state = state;
43 }
44 this.layout = layout;
45 layout.on('regionresized', this.onRegionResized, this, true);
46 layout.on('regioncollapsed', this.onRegionCollapsed, this, true);
47 layout.on('regionexpanded', this.onRegionExpanded, this, true);
48 },
49
50 storeState : function(){
51 this.provider.set(this.layout.id+'-layout-state', this.state);
52 },
53
54 onRegionResized : function(region, newSize){
55 this.state[region.getPosition()].size = newSize;
56 this.storeState();
57 },
58
59 onRegionCollapsed : function(region){
60 this.state[region.getPosition()].collapsed = true;
61 this.storeState();
62 },
63
64 onRegionExpanded : function(region){
65 this.state[region.getPosition()].collapsed = false;
66 this.storeState();
67 }
68};
diff --git a/frontend/beta/js/YUI-extensions/layout/SplitLayoutRegion.js b/frontend/beta/js/YUI-extensions/layout/SplitLayoutRegion.js
new file mode 100644
index 0000000..6b8ce9e
--- a/dev/null
+++ b/frontend/beta/js/YUI-extensions/layout/SplitLayoutRegion.js
@@ -0,0 +1,282 @@
1/**
2 * @class YAHOO.ext.SplitLayoutRegion
3 * @extends YAHOO.ext.LayoutRegion
4 * Adds a splitbar and other (private) useful functionality to a LayoutRegion
5 */
6YAHOO.ext.SplitLayoutRegion = function(mgr, config, pos, cursor){
7 this.cursor = cursor;
8 YAHOO.ext.SplitLayoutRegion.superclass.constructor.call(this, mgr, config, pos);
9 if(config.split){
10 this.hide();
11 }
12};
13
14YAHOO.extendX(YAHOO.ext.SplitLayoutRegion, YAHOO.ext.LayoutRegion, {
15 applyConfig : function(config){
16 YAHOO.ext.SplitLayoutRegion.superclass.applyConfig.call(this, config);
17 if(config.split){
18 if(!this.split){
19 var splitEl = YAHOO.ext.DomHelper.append(this.mgr.el.dom,
20 {tag: 'div', id: this.el.id + '-split', cls: 'ylayout-split ylayout-split-'+this.position, html: '&#160;'});
21 /** The SplitBar for this region @type YAHOO.ext.SplitBar */
22 this.split = new YAHOO.ext.SplitBar(splitEl, this.el);
23 this.split.onMoved.subscribe(this.onSplitMove, this, true);
24 this.split.useShim = config.useShim === true;
25 YAHOO.util.Dom.setStyle([this.split.el.dom, this.split.proxy], 'cursor', this.cursor);
26 this.split.getMaximumSize = this.getMaxSize.createDelegate(this);
27 }
28 if(typeof config.minSize != 'undefined'){
29 this.split.minSize = config.minSize;
30 }
31 if(typeof config.maxSize != 'undefined'){
32 this.split.maxSize = config.maxSize;
33 }
34 }
35 },
36
37 getMaxSize : function(){
38 var cmax = this.config.maxSize || 10000;
39 var center = this.mgr.getRegion('center');
40 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
41 },
42
43 onSplitMove : function(split, newSize){
44 this.fireEvent('resized', this, newSize);
45 },
46
47 /**
48 * Returns the SplitBar for this region.
49 * @return {YAHOO.ext.SplitBar}
50 */
51 getSplitBar : function(){
52 return this.split;
53 },
54
55 hide : function(){
56 if(this.split){
57 this.split.el.setLocation(-2000,-2000);
58 this.split.el.hide();
59 }
60 YAHOO.ext.SplitLayoutRegion.superclass.hide.call(this);
61 },
62
63 show : function(){
64 if(this.split){
65 this.split.el.show();
66 }
67 YAHOO.ext.SplitLayoutRegion.superclass.show.call(this);
68 },
69
70 beforeSlide: function(){
71 if(YAHOO.ext.util.Browser.isGecko){// firefox overflow auto bug workaround
72 this.bodyEl.clip();
73 if(this.tabs) this.tabs.bodyEl.clip();
74 if(this.activePanel){
75 this.activePanel.getEl().clip();
76
77 if(this.activePanel.beforeSlide){
78 this.activePanel.beforeSlide();
79 }
80 }
81 }
82 },
83
84 afterSlide : function(){
85 if(YAHOO.ext.util.Browser.isGecko){// firefox overflow auto bug workaround
86 this.bodyEl.unclip();
87 if(this.tabs) this.tabs.bodyEl.unclip();
88 if(this.activePanel){
89 this.activePanel.getEl().unclip();
90 if(this.activePanel.afterSlide){
91 this.activePanel.afterSlide();
92 }
93 }
94 }
95 },
96
97 slideOut : function(){
98 if(!this.slideEl){
99 this.slideEl = new YAHOO.ext.Actor(
100 YAHOO.ext.DomHelper.append(this.mgr.el.dom, {tag: 'div', cls:'ylayout-slider'}));
101 if(this.config.autoHide !== false){
102 var slideInTask = new YAHOO.ext.util.DelayedTask(this.slideIn, this);
103 this.slideEl.mon('mouseout', function(e){
104 var to = e.getRelatedTarget();
105 if(to && to != this.slideEl.dom && !YAHOO.util.Dom.isAncestor(this.slideEl.dom, to)){
106 slideInTask.delay(500);
107 }
108 }, this, true);
109 this.slideEl.mon('mouseover', function(e){
110 slideInTask.cancel();
111 }, this, true);
112 }
113 }
114 var sl = this.slideEl, c = this.collapsedEl, cm = this.cmargins;
115 this.isSlid = true;
116 this.snapshot = {
117 'left': this.el.getLeft(true),
118 'top': this.el.getTop(true),
119 'colbtn': this.collapseBtn.isVisible(),
120 'closebtn': this.closeBtn.isVisible()
121 };
122 this.collapseBtn.hide();
123 this.closeBtn.hide();
124 this.el.show();
125 this.el.setLeftTop(0,0);
126 sl.startCapture(true);
127 var size;
128 switch(this.position){
129 case 'west':
130 sl.setLeft(c.getRight(true));
131 sl.setTop(c.getTop(true));
132 size = this.el.getWidth();
133 break;
134 case 'east':
135 sl.setRight(this.mgr.getViewSize().width-c.getLeft(true));
136 sl.setTop(c.getTop(true));
137 size = this.el.getWidth();
138 break;
139 case 'north':
140 sl.setLeft(c.getLeft(true));
141 sl.setTop(c.getBottom(true));
142 size = this.el.getHeight();
143 break;
144 case 'south':
145 sl.setLeft(c.getLeft(true));
146 sl.setBottom(this.mgr.getViewSize().height-c.getTop(true));
147 size = this.el.getHeight();
148 break;
149 }
150 sl.dom.appendChild(this.el.dom);
151 YAHOO.util.Event.on(document.body, 'click', this.slideInIf, this, true);
152 sl.setSize(this.el.getWidth(), this.el.getHeight());
153 this.beforeSlide();
154 if(this.activePanel){
155 this.activePanel.setSize(this.bodyEl.getWidth(), this.bodyEl.getHeight());
156 }
157 sl.slideShow(this.getAnchor(), size, this.slideDuration, null, false);
158 sl.play(function(){
159 this.afterSlide();
160 }.createDelegate(this));
161 },
162
163 slideInIf : function(e){
164 var t = YAHOO.util.Event.getTarget(e);
165 if(!YAHOO.util.Dom.isAncestor(this.el.dom, t)){
166 this.slideIn();
167 }
168 },
169
170 slideIn : function(callback){
171 if(this.isSlid && !this.slideEl.playlist.isPlaying()){
172 YAHOO.util.Event.removeListener(document.body, 'click', this.slideInIf, this, true);
173 this.slideEl.startCapture(true);
174 this.slideEl.slideHide(this.getAnchor(), this.slideDuration, null);
175 this.beforeSlide();
176 this.slideEl.play(function(){
177 this.isSlid = false;
178 this.el.setPositioning(this.snapshot);
179 this.collapseBtn.setVisible(this.snapshot.colbtn);
180 this.closeBtn.setVisible(this.snapshot.closebtn);
181 this.afterSlide();
182 this.mgr.el.dom.appendChild(this.el.dom);
183 if(typeof callback == 'function'){
184 callback();
185 }
186 }.createDelegate(this));
187 }
188 },
189
190 animateExpand : function(){
191 var em = this.margins, cm = this.cmargins;
192 var c = this.collapsedEl, el = this.el;
193 var direction, distance;
194 switch(this.position){
195 case 'west':
196 direction = 'right';
197 el.setLeft(-(el.getWidth() + (em.right+em.left)));
198 el.setTop(c.getTop(true)-cm.top+em.top);
199 distance = el.getWidth() + (em.right+em.left);
200 break;
201 case 'east':
202 direction = 'left';
203 el.setLeft(this.mgr.getViewSize().width + em.left);
204 el.setTop(c.getTop(true)-cm.top+em.top);
205 distance = el.getWidth() + (em.right+em.left);
206 break;
207 case 'north':
208 direction = 'down';
209 el.setLeft(em.left);
210 el.setTop(-(el.getHeight() + (em.top+em.bottom)));
211 distance = el.getHeight() + (em.top+em.bottom);
212 break;
213 case 'south':
214 direction = 'up';
215 el.setLeft(em.left);
216 el.setTop(this.mgr.getViewSize().height + em.top);
217 distance = el.getHeight() + (em.top+em.bottom);
218 break;
219 }
220 this.beforeSlide();
221 el.setStyle('z-index', '100');
222 el.show();
223 c.setLocation(-2000,-2000);
224 c.hide();
225 el.move(direction, distance, true, this.duration, function(){
226 this.afterSlide();
227 el.setStyle('z-index', '');
228 if(this.split){
229 this.split.el.show();
230 }
231 this.fireEvent('invalidated', this);
232 this.fireEvent('expanded', this);
233 }.createDelegate(this), this.config.easing || YAHOO.util.Easing.easeOut);
234 },
235
236 animateCollapse : function(){
237 var em = this.margins, cm = this.cmargins;
238 var c = this.collapsedEl, el = this.el;
239 var direction, distance;
240 switch(this.position){
241 case 'west':
242 direction = 'left';
243 distance = el.getWidth() + (em.right+em.left);
244 break;
245 case 'east':
246 direction = 'right';
247 distance = el.getWidth() + (em.right+em.left);
248 break;
249 case 'north':
250 direction = 'up';
251 distance = el.getHeight() + (em.top+em.bottom);
252 break;
253 case 'south':
254 direction = 'down';
255 distance = el.getHeight() + (em.top+em.bottom);
256 break;
257 }
258 this.el.setStyle('z-index', '100');
259 this.beforeSlide();
260 this.el.move(direction, distance, true, this.duration, function(){
261 this.afterSlide();
262 this.el.setStyle('z-index', '');
263 this.el.setLocation(-20000,-20000);
264 this.el.hide();
265 this.collapsedEl.show();
266 this.fireEvent('collapsed', this);
267 }.createDelegate(this), YAHOO.util.Easing.easeIn);
268 },
269
270 getAnchor : function(){
271 switch(this.position){
272 case 'west':
273 return 'left';
274 case 'east':
275 return 'right';
276 case 'north':
277 return 'top';
278 case 'south':
279 return 'bottom';
280 }
281 }
282});
diff --git a/frontend/beta/js/YUI-extensions/tree/AsyncTreeNode.js b/frontend/beta/js/YUI-extensions/tree/AsyncTreeNode.js
new file mode 100644
index 0000000..5d48b00
--- a/dev/null
+++ b/frontend/beta/js/YUI-extensions/tree/AsyncTreeNode.js
@@ -0,0 +1,58 @@
1YAHOO.ext.tree.AsyncTreeNode = function(config){
2 this.loaded = false;
3 this.loading = false;
4 YAHOO.ext.tree.AsyncTreeNode.superclass.constructor.apply(this, arguments);
5 this.events['beforeload'] = true;
6 this.events['load'] = true;
7};
8YAHOO.extendX(YAHOO.ext.tree.AsyncTreeNode, YAHOO.ext.tree.TreeNode, {
9 expand : function(deep, anim, callback){
10 if(this.loading){ // if an async load is already running, waiting til it's done
11 var timer;
12 var f = function(){
13 if(!this.loading){ // done loading
14 clearInterval(timer);
15 this.expand(deep, anim, callback);
16 }
17 }.createDelegate(this);
18 timer = setInterval(f, 200);
19 }
20 if(!this.loaded){
21 if(this.fireEvent('beforeload', this) === false){
22 return;
23 }
24 this.loading = true;
25 this.ui.beforeLoad(this);
26 var loader = this.loader || this.attributes.loader || this.getOwnerTree().getLoader();
27 if(loader){
28 loader.load(this, this.loadComplete.createDelegate(this, [deep, anim, callback]));
29 return;
30 }
31 }
32 YAHOO.ext.tree.AsyncTreeNode.superclass.expand.call(this, deep, anim, callback);
33 },
34
35 isLoading : function(){
36 return this.loading;
37 },
38
39 loadComplete : function(deep, anim, callback){
40 this.loading = false;
41 this.loaded = true;
42 this.ui.afterLoad(this);
43 this.fireEvent('load', this);
44 this.expand(deep, anim, callback);
45 },
46
47 isLoaded : function(){
48 return this.loaded;
49 },
50
51 hasChildNodes : function(){
52 if(!this.isLeaf() && !this.loaded){
53 return true;
54 }else{
55 return YAHOO.ext.tree.AsyncTreeNode.superclass.hasChildNodes.call(this);
56 }
57 }
58});
diff --git a/frontend/beta/js/YUI-extensions/tree/TreeDragZone.js b/frontend/beta/js/YUI-extensions/tree/TreeDragZone.js
new file mode 100644
index 0000000..9b77b3c
--- a/dev/null
+++ b/frontend/beta/js/YUI-extensions/tree/TreeDragZone.js
@@ -0,0 +1,43 @@
1YAHOO.ext.tree.TreeDragZone = function(tree, config){
2 YAHOO.ext.tree.TreeDragZone.superclass.constructor.call(this, tree.getEl(), config);
3 this.tree = tree;
4};
5
6YAHOO.extendX(YAHOO.ext.tree.TreeDragZone, YAHOO.ext.dd.DragZone, {
7 ddGroup : 'TreeDD',
8
9 onBeforeDrag : function(data, e){
10 var n = data.node;
11 return n && n.draggable && !n.disabled;
12 },
13
14 onInitDrag : function(e){
15 var data = this.dragData;
16 this.tree.getSelectionModel().select(data.node);
17 this.proxy.update('');
18 data.node.ui.appendDDGhost(this.proxy.ghost.dom);
19 this.tree.fireEvent('startdrag', this.tree, data.node, e);
20 },
21
22 getRepairXY : function(e, data){
23 return data.node.ui.getDDRepairXY();
24 },
25
26 onEndDrag : function(data, e){
27 this.tree.fireEvent('enddrag', this.tree, data.node, e);
28 },
29
30 onValidDrop : function(dd, e, id){
31 this.tree.fireEvent('dragdrop', this.tree, this.dragData.node, dd, e);
32 this.hideProxy();
33 },
34
35 beforeInvalidDrop : function(e, id){
36 if(YAHOO.util.Anim){
37 // this scrolls the original position back into view
38 var sm = this.tree.getSelectionModel();
39 sm.clearSelections();
40 sm.select(this.dragData.node);
41 }
42 }
43});
diff --git a/frontend/beta/js/YUI-extensions/tree/TreeDropZone.js b/frontend/beta/js/YUI-extensions/tree/TreeDropZone.js
new file mode 100644
index 0000000..91c24e1
--- a/dev/null
+++ b/frontend/beta/js/YUI-extensions/tree/TreeDropZone.js
@@ -0,0 +1,228 @@
1YAHOO.ext.tree.TreeDropZone = function(tree, config){
2 this.allowParentInsert = false;
3 this.allowContainerDrop = false;
4 this.appendOnly = false;
5 YAHOO.ext.tree.TreeDropZone.superclass.constructor.call(this, tree.container, config);
6 this.tree = tree;
7 this.lastInsertClass = 'ytree-no-status';
8 this.dragOverData = {};
9};
10
11YAHOO.extendX(YAHOO.ext.tree.TreeDropZone, YAHOO.ext.dd.DropZone, {
12 ddGroup : 'TreeDD',
13
14 expandDelay : 1000,
15
16 expandNode : function(node){
17 if(node.hasChildNodes() && !node.isExpanded()){
18 node.expand(false, null, this.triggerCacheRefresh.createDelegate(this));
19 }
20 },
21
22 queueExpand : function(node){
23 this.expandProcId = this.expandNode.defer(this.expandDelay, this, [node]);
24 },
25
26 cancelExpand : function(){
27 if(this.expandProcId){
28 clearTimeout(this.expandProcId);
29 this.expandProcId = false;
30 }
31 },
32
33 isValidDropPoint : function(n, pt, dd, e, data){
34 if(!n || !data){ return false; }
35 var targetNode = n.node;
36 var dropNode = data.node;
37 // default drop rules
38 if(!(targetNode && targetNode.isTarget && pt)){
39 return false;
40 }
41 if(pt == 'append' && targetNode.allowChildren === false){
42 return false;
43 }
44 if((pt == 'above' || pt == 'below') && (targetNode.parentNode && targetNode.parentNode.allowChildren === false)){
45 return false;
46 }
47 if(dropNode && (targetNode == dropNode || dropNode.contains(targetNode))){
48 return false;
49 }
50 // reuse the object
51 var overEvent = this.dragOverData;
52 overEvent.tree = this.tree;
53 overEvent.target = targetNode;
54 overEvent.data = data;
55 overEvent.point = pt;
56 overEvent.source = dd;
57 overEvent.rawEvent = e;
58 overEvent.dropNode = dropNode;
59 overEvent.cancel = false;
60 var result = this.tree.fireEvent('nodedragover', overEvent);
61 return overEvent.cancel === false && result !== false;
62 },
63
64 getDropPoint : function(e, n, dd){
65 var tn = n.node;
66 if(tn.isRoot){
67 return tn.allowChildren !== false ? 'ap-pend' : false; // always append for root
68 }
69 var dragEl = n.ddel;
70 var t = YAHOO.util.Dom.getY(dragEl), b = t + dragEl.offsetHeight;
71 var y = YAHOO.util.Event.getPageY(e);
72 var noAppend = tn.allowChildren === false || tn.isLeaf();
73 if(this.appendOnly || tn.parentNode.allowChildren === false){
74 return noAppend ? false : 'append';
75 }
76 var noBelow = false;
77 if(!this.allowParentInsert){
78 noBelow = tn.hasChildNodes() && tn.isExpanded();
79 }
80 var q = (b - t) / (noAppend ? 2 : 3);
81 if(y >= t && y < t + q){
82 return 'above';
83 }else if(!noBelow && (noAppend || y >= b-q && y <= b)){
84 return 'below';
85 }else{
86 return 'append';
87 }
88 return false;
89 },
90
91 onNodeEnter : function(n, dd, e, data){
92 this.cancelExpand();
93 },
94
95 onNodeOver : function(n, dd, e, data){
96 var pt = this.getDropPoint(e, n, dd);
97 var node = n.node;
98
99 // auto node expand check
100 if(!this.expandProcId && pt == 'append' && node.hasChildNodes() && !n.node.isExpanded()){
101 this.queueExpand(node);
102 }else if(pt != 'append'){
103 this.cancelExpand();
104 }
105
106 // set the insert point style on the target node
107 var returnCls = this.dropNotAllowed;
108 if(this.isValidDropPoint(n, pt, dd, e, data)){
109 if(pt){
110 var el = n.ddel;
111 var cls, returnCls;
112 if(pt == 'above'){
113 returnCls = n.node.isFirst() ? 'ytree-drop-ok-above' : 'ytree-drop-ok-between';
114 cls = 'ytree-drag-insert-above';
115 }else if(pt == 'below'){
116 returnCls = n.node.isLast() ? 'ytree-drop-ok-below' : 'ytree-drop-ok-between';
117 cls = 'ytree-drag-insert-below';
118 }else{
119 returnCls = 'ytree-drop-ok-append';
120 cls = 'ytree-drag-append';
121 }
122 if(this.lastInsertClass != cls){
123 YAHOO.util.Dom.replaceClass(el, this.lastInsertClass, cls);
124 this.lastInsertClass = cls;
125 }
126 }
127 }
128 return returnCls;
129 },
130
131 onNodeOut : function(n, dd, e, data){
132 this.cancelExpand();
133 this.removeDropIndicators(n);
134 },
135
136 onNodeDrop : function(n, dd, e, data){
137 var point = this.getDropPoint(e, n, dd);
138 var targetNode = n.node;
139 targetNode.ui.startDrop();
140 if(!this.isValidDropPoint(n, point, dd, e, data)){
141 targetNode.ui.endDrop();
142 return false;
143 }
144 // first try to find the drop node
145 var dropNode = data.node || (dd.getTreeNode ? dd.getTreeNode(data, targetNode, point, e) : null);
146 var dropEvent = {
147 tree : this.tree,
148 target: targetNode,
149 data: data,
150 point: point,
151 source: dd,
152 rawEvent: e,
153 dropNode: dropNode,
154 cancel: dropNode ? false : true
155 };
156 var retval = this.tree.fireEvent('beforenodedrop', dropEvent);
157 if(retval === false || dropEvent.cancel === true || !dropEvent.dropNode){
158 targetNode.ui.endDrop();
159 return false;
160 }
161 if(point == 'append' && !targetNode.isExpanded()){
162 targetNode.expand(false, null, function(){
163 this.completeDrop(dropEvent);
164 }.createDelegate(this));
165 }else{
166 this.completeDrop(dropEvent);
167 }
168 return true;
169 },
170
171 completeDrop : function(de){
172 var ns = de.dropNode, p = de.point, t = de.target;
173 if(!(ns instanceof Array)){
174 ns = [ns];
175 }
176 var n;
177 for(var i = 0, len = ns.length; i < len; i++){
178 n = ns[i];
179 if(p == 'above'){
180 t.parentNode.insertBefore(n, t);
181 }else if(p == 'below'){
182 t.parentNode.insertBefore(n, t.nextSibling);
183 }else{
184 t.appendChild(n);
185 }
186 }
187 n.select(); // select and highlight the last insert
188 if(this.tree.hlDrop){
189 n.ui.highlight();
190 }
191 t.ui.endDrop();
192 this.tree.fireEvent('nodedrop', de);
193 },
194
195 afterNodeMoved : function(dd, data, e, targetNode, dropNode){
196 if(this.tree.hlDrop){
197 dropNode.select();
198 dropNode.ui.highlight();
199 }
200 this.tree.fireEvent('nodedrop', this.tree, targetNode, data, dd, e);
201 },
202
203 getTree : function(){
204 return this.tree;
205 },
206
207 removeDropIndicators : function(n){
208 if(n && n.ddel){
209 var el = n.ddel;
210 YAHOO.util.Dom.removeClass(el, 'ytree-drag-insert-above');
211 YAHOO.util.Dom.removeClass(el, 'ytree-drag-insert-below');
212 YAHOO.util.Dom.removeClass(el, 'ytree-drag-append');
213 this.lastInsertClass = '_noclass';
214 }
215 },
216
217 beforeDragDrop : function(target, e, id){
218 this.cancelExpand();
219 return true;
220 },
221
222 afterRepair : function(data){
223 if(data){
224 data.node.ui.highlight();
225 }
226 this.hideProxy();
227 }
228});
diff --git a/frontend/beta/js/YUI-extensions/tree/TreeFilter.js b/frontend/beta/js/YUI-extensions/tree/TreeFilter.js
new file mode 100644
index 0000000..9eeb274
--- a/dev/null
+++ b/frontend/beta/js/YUI-extensions/tree/TreeFilter.js
@@ -0,0 +1,105 @@
1/**
2 * This doesn't update the indent (lines) or expand collapse icons of the nodes
3 */
4YAHOO.ext.tree.TreeFilter = function(tree, config){
5 this.tree = tree;
6 this.filtered = {};
7 YAHOO.ext.util.Config.apply(this, config, {
8 clearBlank:false,
9 reverse:false,
10 autoClear:false,
11 remove:false
12 });
13};
14
15YAHOO.ext.tree.TreeFilter.prototype = {
16 /**
17 * Filter the data by a specific attribute.
18 * @param {String/RegExp} value Either string that the attribute value
19 * should start with or a RegExp to test against the attribute
20 * @param {String} attr (optional) The attribute passed in your node's attributes collection. Defaults to "text".
21 * @param {TreeNode} startNode (optional) The node to start the filter at.
22 */
23 filter : function(value, attr, startNode){
24 attr = attr || 'text';
25 var f;
26 if(typeof value == 'string'){
27 var vlen = value.length;
28 // auto clear empty filter
29 if(vlen == 0 && this.clearBlank){
30 this.clearFilter();
31 return;
32 }
33 value = value.toLowerCase();
34 f = function(n){
35 return n.attributes[attr].substr(0, vlen).toLowerCase() == value;
36 }
37 }else if(value.exec){ // regex?
38 f = function(n){
39 return value.test(n.attributes[attr]);
40 }
41 }else{
42 throw 'Illegal filter type, must be string or regex';
43 }
44 this.filterBy(f, null, startNode);
45 },
46
47 /**
48 * Filter by a function. The passed function will be called with each
49 * node in the tree (or from the startNode). If the function returns true, the node is kept
50 * otherwise it is filtered. If a node is filtered, it's children are also filtered.
51 * @param {Function} fn The filter function
52 * @param {Object} scope (optional) The scope of the function (defaults to the current node)
53 */
54 filterBy : function(fn, scope, startNode){
55 startNode = startNode || this.tree.root;
56 if(this.autoClear){
57 this.clearFilter();
58 }
59 var af = this.filtered, rv = this.reverse;
60 var f = function(n){
61 if(n == startNode){
62 return true;
63 }
64 if(af[n.id]){
65 return false;
66 }
67 var m = fn.call(scope || n, n);
68 if(!m || rv){
69 af[n.id] = n;
70 n.ui.hide();
71 return false;
72 }
73 return true;
74 }
75 startNode.cascade(f);
76 if(this.remove){
77 for(var id in af){
78 if(typeof id != 'function'){
79 var n = af[id];
80 if(n && n.parentNode){
81 n.parentNode.removeChild(n);
82 }
83 }
84 }
85 }
86 },
87
88 /**
89 * Clears the current filter. Note: with the "remove" option
90 * set a filter cannot be cleared.
91 */
92 clear : function(){
93 var t = this.tree;
94 var af = this.filtered;
95 for(var id in af){
96 if(typeof id != 'function'){
97 var n = af[id];
98 if(n){
99 n.ui.show();
100 }
101 }
102 }
103 this.filtered = {};
104 }
105};
diff --git a/frontend/beta/js/YUI-extensions/tree/TreeLoader.js b/frontend/beta/js/YUI-extensions/tree/TreeLoader.js
new file mode 100644
index 0000000..34989bd
--- a/dev/null
+++ b/frontend/beta/js/YUI-extensions/tree/TreeLoader.js
@@ -0,0 +1,107 @@
1YAHOO.ext.tree.TreeLoader = function(config){
2 this.baseParams = {};
3 this.requestMethod = 'POST';
4 YAHOO.ext.util.Config.apply(this, config);
5
6 this.events = {
7 'beforeload' : true,
8 'load' : true,
9 'loadexception' : true
10 };
11};
12
13YAHOO.extendX(YAHOO.ext.tree.TreeLoader, YAHOO.ext.util.Observable, {
14 load : function(node, callback){
15 if(node.attributes.children){ // preloaded json children
16 var cs = node.attributes.children;
17 for(var i = 0, len = cs.length; i < len; i++){
18 node.appendChild(this.createNode(cs[i]));
19 }
20 if(typeof callback == 'function'){
21 callback();
22 }
23 }else if(this.dataUrl){
24 this.requestData(node, callback);
25 }
26 },
27
28 getParams: function(node){
29 var buf = [], bp = this.baseParams;
30 for(var key in bp){
31 if(typeof bp[key] != 'function'){
32 buf.push(encodeURIComponent(key), '=', encodeURIComponent(bp[key]), '&');
33 }
34 }
35 buf.push('node=', encodeURIComponent(node.id));
36 return buf.join('');
37 },
38
39 requestData : function(node, callback){
40 if(this.fireEvent('beforeload', this, node, callback) !== false){
41 var params = this.getParams(node);
42 var cb = {
43 success: this.handleResponse,
44 failure: this.handleFailure,
45 scope: this,
46 argument: {callback: callback, node: node}
47 };
48 this.transId = YAHOO.util.Connect.asyncRequest(this.requestMethod, this.dataUrl, cb, params);
49 }else{
50 // if the load is cancelled, make sure we notify
51 // the node that we are done
52 if(typeof callback == 'function'){
53 callback();
54 }
55 }
56 },
57
58 isLoading : function(){
59 return this.transId ? true : false;
60 },
61
62 abort : function(){
63 if(this.isLoading()){
64 YAHOO.util.Connect.abort(this.transId);
65 }
66 },
67
68 createNode : function(attr){
69 if(this.applyLoader !== false){
70 attr.loader = this;
71 }
72 return(attr.leaf ?
73 new YAHOO.ext.tree.TreeNode(attr) :
74 new YAHOO.ext.tree.AsyncTreeNode(attr));
75 },
76
77 processResponse : function(response, node, callback){
78 var json = response.responseText;
79 try {
80 var o = eval('('+json+')');
81 for(var i = 0, len = o.length; i < len; i++){
82 node.appendChild(this.createNode(o[i]));
83 }
84 if(typeof callback == 'function'){
85 callback();
86 }
87 }catch(e){
88 this.handleFailure(response);
89 }
90 },
91
92 handleResponse : function(response){
93 this.transId = false;
94 var a = response.argument;
95 this.processResponse(response, a.node, a.callback);
96 this.fireEvent('load', this, a.node, response);
97 },
98
99 handleFailure : function(response){
100 this.transId = false;
101 var a = response.argument;
102 this.fireEvent('loadexception', this, a.node, response);
103 if(typeof a.callback == 'function'){
104 a.callback();
105 }
106 }
107});
diff --git a/frontend/beta/js/YUI-extensions/tree/TreeNode.js b/frontend/beta/js/YUI-extensions/tree/TreeNode.js
new file mode 100644
index 0000000..c676481
--- a/dev/null
+++ b/frontend/beta/js/YUI-extensions/tree/TreeNode.js
@@ -0,0 +1,300 @@
1/**
2 * @class YAHOO.ext.tree.TreeNode
3 * @extends YAHOO.ext.data.Node
4 * @cfg {Boolean} leaf true if this node is a leaf and does not have or cannot have children
5 * @cfg {Boolean} expanded true to start the node expanded
6 * @cfg {Boolean} draggable false to make this node undraggable if DD is on (default to true)
7 * @cfg {Boolean} isTarget false if this node cannot be drop on
8 * @cfg {Boolean} disabled true to start the node disabled
9 * @constructor
10 * @param {Object} attributes The attributes/config for the node
11 */
12YAHOO.ext.tree.TreeNode = function(attributes){
13 attributes = attributes || {};
14 if(typeof attributes == 'string'){
15 attributes = {text: attributes};
16 }
17 this.el = null;
18 this.childrenRendered = false;
19 this.rendered = false;
20 YAHOO.ext.tree.TreeNode.superclass.constructor.call(this, attributes);
21 this.expanded = attributes.expanded === true;
22 this.isTarget = attributes.isTarget !== false;
23 this.draggable = attributes.draggable !== false && attributes.allowDrag !== false;
24 this.allowChildren = attributes.allowChildren !== false && attributes.allowDrop !== false;
25 this.text = attributes.text;
26 this.disabled = attributes.disabled === true;
27
28 YAHOO.ext.util.Config.apply(this.events, {
29 'textchange' : true,
30 'beforeexpand' : true,
31 'beforecollapse' : true,
32 'expand' : true,
33 'disabledchange' : true,
34 'collapse' : true,
35 'beforeclick':true,
36 'click':true,
37 'dblclick':true,
38 'contentmenu':true,
39 'beforechildrenrendered':true
40 });
41
42 var uiClass = this.attributes.uiProvider || YAHOO.ext.tree.TreeNodeUI;
43 this.ui = new uiClass(this);
44};
45YAHOO.extendX(YAHOO.ext.tree.TreeNode, YAHOO.ext.data.Node, {
46 isExpanded : function(){
47 return this.expanded;
48 },
49
50 getUI : function(){
51 return this.ui;
52 },
53
54 setFirstChild : function(node){
55 var of = this.firstChild;
56 YAHOO.ext.tree.TreeNode.superclass.setFirstChild.call(this, node);
57 if(this.childrenRendered && of && node != of){
58 of.renderIndent(true, true);
59 }
60 if(this.rendered){
61 this.renderIndent(true, true);
62 }
63 },
64
65 setLastChild : function(node){
66 var ol = this.lastChild;
67 YAHOO.ext.tree.TreeNode.superclass.setLastChild.call(this, node);
68 if(this.childrenRendered && ol && node != ol){
69 ol.renderIndent(true, true);
70 }
71 if(this.rendered){
72 this.renderIndent(true, true);
73 }
74 },
75
76 // these methods are overridden to provide lazy rendering support
77 appendChild : function(){
78 var node = YAHOO.ext.tree.TreeNode.superclass.appendChild.apply(this, arguments);
79 if(node && this.childrenRendered){
80 node.render();
81 }
82 this.ui.updateExpandIcon();
83 return node;
84 },
85
86 removeChild : function(node){
87 this.ownerTree.getSelectionModel().unselect(node);
88 YAHOO.ext.tree.TreeNode.superclass.removeChild.apply(this, arguments);
89 // if it's been rendered remove dom node
90 if(this.childrenRendered){
91 node.ui.remove();
92 }
93 if(this.childNodes.length < 1){
94 this.collapse(false, false);
95 }else{
96 this.ui.updateExpandIcon();
97 }
98 return node;
99 },
100
101 insertBefore : function(node, refNode){
102 var newNode = YAHOO.ext.tree.TreeNode.superclass.insertBefore.apply(this, arguments);
103 if(newNode && refNode && this.childrenRendered){
104 node.render();
105 }
106 this.ui.updateExpandIcon();
107 return newNode;
108 },
109
110 setText : function(text){
111 var oldText = this.text;
112 this.text = text;
113 this.attributes.text = text;
114 if(this.rendered){ // event without subscribing
115 this.ui.onTextChange(this, text, oldText);
116 }
117 this.fireEvent('textchange', this, text, oldText);
118 },
119
120 select : function(){
121 this.getOwnerTree().getSelectionModel().select(this);
122 },
123
124 unselect : function(){
125 this.getOwnerTree().getSelectionModel().unselect(this);
126 },
127
128 isSelected : function(){
129 return this.getOwnerTree().getSelectionModel().isSelected(node);
130 },
131
132 expand : function(deep, anim, callback){
133 if(!this.expanded){
134 if(this.fireEvent('beforeexpand', this, deep, anim) === false){
135 return;
136 }
137 if(!this.childrenRendered){
138 this.renderChildren();
139 }
140 this.expanded = true;
141 if((this.getOwnerTree().animate && anim !== false) || anim){
142 this.ui.animExpand(function(){
143 this.fireEvent('expand', this);
144 if(typeof callback == 'function'){
145 callback(this);
146 }
147 if(deep === true){
148 this.expandChildNodes(true);
149 }
150 }.createDelegate(this));
151 return;
152 }else{
153 this.ui.expand();
154 this.fireEvent('expand', this);
155 if(typeof callback == 'function'){
156 callback(this);
157 }
158 }
159 }else{
160 if(typeof callback == 'function'){
161 callback(this);
162 }
163 }
164 if(deep === true){
165 this.expandChildNodes(true);
166 }
167 },
168
169 collapse : function(deep, anim){
170 if(this.expanded && (!this.isRoot || (this.isRoot && this.getOwnerTree().rootVisible))){
171 if(this.fireEvent('beforecollapse', this, deep, anim) === false){
172 return;
173 }
174 this.expanded = false;
175 if((this.getOwnerTree().animate && anim !== false) || anim){
176 this.ui.animCollapse(function(){
177 this.fireEvent('collapse', this);
178 if(deep === true){
179 this.collapseChildNodes(true);
180 }
181 }.createDelegate(this));
182 return;
183 }else{
184 this.ui.collapse();
185 this.fireEvent('collapse', this);
186 }
187 }
188 if(deep === true){
189 var cs = this.childNodes;
190 for(var i = 0, len = cs.length; i < len; i++) {
191 cs[i].collapse(true)
192 }
193 }
194 },
195
196 delayedExpand : function(delay){
197 if(!this.expandProcId){
198 this.expandProcId = this.expand.defer(delay, this);
199 }
200 },
201
202 cancelExpand : function(){
203 if(this.expandProcId){
204 clearTimeout(this.expandProcId);
205 }
206 this.expandProcId = false;
207 },
208
209 toggle : function(){
210 if(this.expanded){
211 this.collapse();
212 }else{
213 this.expand();
214 }
215 },
216
217 ensureVisible : function(){
218 if(this.parentNode){
219 this.parentNode.bubble(function(){
220 this.expand(false, false);
221 });
222 }
223 },
224
225 expandChildNodes : function(deep){
226 var cs = this.childNodes;
227 for(var i = 0, len = cs.length; i < len; i++) {
228 cs[i].expand(deep);
229 }
230 },
231
232 collapseChildNodes : function(deep){
233 var cs = this.childNodes;
234 for(var i = 0, len = cs.length; i < len; i++) {
235 cs[i].expand(deep);
236 }
237 },
238
239 disable : function(){
240 this.disabled = true;
241 this.unselect();
242 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
243 this.ui.onDisableChange(this, true);
244 }
245 this.fireEvent('disabledchange', this, true);
246 },
247
248 enable : function(){
249 this.disabled = false;
250 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
251 this.ui.onDisableChange(this, false);
252 }
253 this.fireEvent('disabledchange', this, false);
254 },
255
256 renderChildren : function(suppressEvent){
257 if(suppressEvent !== false){
258 this.fireEvent('beforechildrenrendered', this);
259 }
260 var cs = this.childNodes;
261 for(var i = 0, len = cs.length; i < len; i++){
262 cs[i].render(true);
263 }
264 this.childrenRendered = true;
265 },
266
267 sort : function(fn, scope){
268 YAHOO.ext.tree.TreeNode.superclass.sort.apply(this, arguments);
269 if(this.childrenRendered){
270 var cs = this.childNodes;
271 for(var i = 0, len = cs.length; i < len; i++){
272 cs[i].render(true);
273 }
274 }
275 },
276
277 render : function(bulkRender){
278 this.ui.render(bulkRender);
279 if(!this.rendered){
280 this.rendered = true;
281 if(this.expanded){
282 this.expanded = false;
283 this.expand(false, false);
284 }
285 }
286 },
287
288 renderIndent : function(deep, refresh){
289 if(refresh){
290 this.ui.childIndent = null;
291 }
292 this.ui.renderIndent();
293 if(deep === true && this.childrenRendered){
294 var cs = this.childNodes;
295 for(var i = 0, len = cs.length; i < len; i++){
296 cs[i].renderIndent(true, refresh);
297 }
298 }
299 }
300});
diff --git a/frontend/beta/js/YUI-extensions/tree/TreeNodeUI.js b/frontend/beta/js/YUI-extensions/tree/TreeNodeUI.js
new file mode 100644
index 0000000..80927f4
--- a/dev/null
+++ b/frontend/beta/js/YUI-extensions/tree/TreeNodeUI.js
@@ -0,0 +1,452 @@
1/**
2 * The TreeNode UI implementation is separate from the
3 * tree implementation. Unless you are customizing the tree UI,
4 * you should never have to use this directly.
5 */
6YAHOO.ext.tree.TreeNodeUI = function(node){
7 this.node = node;
8 this.rendered = false;
9 this.animating = false;
10};
11
12YAHOO.ext.tree.TreeNodeUI.prototype = {
13 emptyIcon : Ext.BLANK_IMAGE_URL,
14
15 removeChild : function(node){
16 if(this.rendered){
17 this.ctNode.removeChild(node.ui.getEl());
18 }
19 },
20
21 beforeLoad : function(){
22 YAHOO.util.Dom.addClass(this.elNode, 'ytree-node-loading');
23 },
24
25 afterLoad : function(){
26 YAHOO.util.Dom.removeClass(this.elNode, 'ytree-node-loading');
27 },
28
29 onTextChange : function(node, text, oldText){
30 if(this.rendered){
31 this.textNode.innerHTML = text;
32 }
33 },
34
35 onDisableChange : function(node, state){
36 this.disabled = state;
37 if(state){
38 YAHOO.util.Dom.addClass(this.elNode, 'ytree-node-disabled');
39 }else{
40 YAHOO.util.Dom.removeClass(this.elNode, 'ytree-node-disabled');
41 }
42 },
43
44 onSelectedChange : function(state){
45 if(state){
46 this.focus();
47 YAHOO.util.Dom.addClass(this.elNode, 'ytree-selected');
48 }else{
49 this.blur();
50 YAHOO.util.Dom.removeClass(this.elNode, 'ytree-selected');
51 }
52 },
53
54 onMove : function(tree, node, oldParent, newParent, index, refNode){
55 this.childIndent = null;
56 if(this.rendered){
57 var targetNode = newParent.ui.getContainer();
58 if(!targetNode){//target not rendered
59 this.holder = document.createElement('div');
60 this.holder.appendChild(this.wrap);
61 return;
62 }
63 var insertBefore = refNode ? refNode.ui.getEl() : null;
64 if(insertBefore){
65 targetNode.insertBefore(this.wrap, insertBefore);
66 }else{
67 targetNode.appendChild(this.wrap);
68 }
69 this.node.renderIndent(true);
70 }
71 },
72
73 remove : function(){
74 if(this.rendered){
75 this.holder = document.createElement('div');
76 this.holder.appendChild(this.wrap);
77 }
78 },
79
80 fireEvent : function(){
81 this.node.fireEvent.apply(this.node, arguments);
82 },
83
84 initEvents : function(){
85 this.node.on('move', this.onMove, this, true);
86 //this.node.on('hiddenchange', this.onHiddenChange, this, true);
87
88 // these were optimized out but a custom UI could use them
89 //this.node.on('remove', this.onChildRemoved, this, true);
90 //this.node.on('selectedstatechange', this.onSelectedChange, this, true);
91 //this.node.on('disabledchange', this.onDisableChange, this, true);
92 //this.node.on('textchange', this.onTextChange, this, true);
93
94 var E = YAHOO.util.Event;
95 var a = this.anchor;
96
97 var el = YAHOO.ext.Element.fly(a);
98
99 if(YAHOO.ext.util.Browser.isOpera){ // opera render bug ignores the CSS
100 el.setStyle('text-decoration', 'none');
101 }
102
103 el.mon('click', this.onClick, this, true);
104 el.mon('dblclick', this.onDblClick, this, true);
105 el.mon('contextmenu', this.onContextMenu, this, true);
106
107 //el.on('focus', function(){
108 // this.node.getOwnerTree().getSelectionModel().select(this.node);
109 //}, this, true);
110
111 var icon = YAHOO.ext.Element.fly(this.iconNode);
112 icon.mon('click', this.onClick, this, true);
113 icon.mon('dblclick', this.onDblClick, this, true);
114 icon.mon('contextmenu', this.onContextMenu, this, true);
115 E.on(this.ecNode, 'click', this.ecClick, this, true);
116
117 if(this.node.disabled){
118 YAHOO.util.Dom.addClass(this.elNode, 'ytree-node-disabled');
119 }
120 if(this.node.hidden){
121 YAHOO.util.Dom.addClass(this.elNode, 'ytree-node-disabled');
122 }
123 var dd = this.node.ownerTree.enableDD || this.node.ownerTree.enableDrag || this.node.ownerTree.enableDrop;
124 if(dd && (!this.node.isRoot || this.node.ownerTree.rootVisible)){
125 YAHOO.ext.dd.Registry.register(this.elNode, {
126 node: this.node,
127 handles: [this.iconNode, this.textNode],
128 isHandle: false
129 });
130 }
131 },
132
133 hide : function(){
134 if(this.rendered){
135 this.wrap.style.display = 'none';
136 }
137 },
138
139 show : function(){
140 if(this.rendered){
141 this.wrap.style.display = '';
142 }
143 },
144
145 onContextMenu : function(e){
146 e.preventDefault();
147 this.focus();
148 this.fireEvent('contextmenu', this.node, e);
149 },
150
151 onClick : function(e){
152 if(this.dropping){
153 return;
154 }
155 if(this.fireEvent('beforeclick', this.node, e) !== false){
156 if(!this.disabled && this.node.attributes.href){
157 this.focus();
158 this.fireEvent('click', this.node, e);
159 return;
160 }
161 e.preventDefault();
162 if(this.disabled){
163 return;
164 }
165 this.focus();
166 this.fireEvent('click', this.node, e);
167 }else{
168 e.stopEvent();
169 }
170 },
171
172 onDblClick : function(e){
173 e.preventDefault();
174 if(this.disabled){
175 return;
176 }
177 if(!this.animating && this.node.hasChildNodes()){
178 this.node.toggle();
179 }
180 this.fireEvent('dblclick', this.node, e);
181 },
182
183 ecClick : function(e){
184 if(!this.animating && this.node.hasChildNodes()){
185 this.node.toggle();
186 }
187 },
188
189 startDrop : function(){
190 this.dropping = true;
191 },
192
193 // delayed drop so the click event doesn't get fired on a drop
194 endDrop : function(){
195 setTimeout(function(){
196 this.dropping = false;
197 }.createDelegate(this), 50);
198 },
199
200 expand : function(){
201 this.updateExpandIcon();
202 this.ctNode.style.display = '';
203 },
204
205 focus : function(){
206 try{
207 this.anchor.focus();
208 }catch(e){}
209 },
210
211 blur : function(){
212 try{
213 this.anchor.blur();
214 }catch(e){}
215 },
216
217 animExpand : function(callback){
218 if(this.animating && this.anim){
219 this.anim.stop();
220 }
221 this.animating = true;
222 this.updateExpandIcon();
223 var ct = this.ctNode;
224 var cs = ct.style;
225 cs.position = 'absolute';
226 cs.visibility = 'hidden';
227 cs.display = '';
228 var h = ct.clientHeight;
229 cs.overflow = 'hidden';
230 cs.height = '1px';
231 cs.position = '';
232 cs.visibility = '';
233 var anim = new YAHOO.util.Anim(ct, {
234 height: {to: h}
235 }, this.node.ownerTree.duration || .25, YAHOO.util.Easing.easeOut);
236 anim.onComplete.subscribe(function(){
237 cs.overflow = '';
238 cs.height = '';
239 this.animating = false;
240 this.anim = null;
241 if(typeof callback == 'function'){
242 callback();
243 }
244 }, this, true);
245 this.anim = anim;
246 anim.animate();
247 },
248
249 highlight : function(){
250 var tree = this.node.getOwnerTree();
251 var hlColor = tree.hlColor || 'C3DAF9';
252 var hlBaseColor = tree.hlBaseColor || 'FFFFFF';
253 var anim = new YAHOO.util.ColorAnim(this.wrap, {
254 backgroundColor: {from: hlColor, to: hlBaseColor}
255 }, .75, YAHOO.util.Easing.easeNone);
256 anim.onComplete.subscribe(function(){
257 YAHOO.util.Dom.setStyle(this.wrap, 'background-color', '');
258 }, this, true);
259 anim.animate();
260 },
261
262 collapse : function(){
263 this.updateExpandIcon();
264 this.ctNode.style.display = 'none';
265 },
266
267 animCollapse : function(callback){
268 if(this.animating && this.anim){
269 this.anim.stop();
270 }
271 this.animating = true;
272 this.updateExpandIcon();
273 var ct = this.ctNode;
274 var cs = ct.style;
275 cs.height = ct.offsetHeight +'px';
276 cs.overflow = 'hidden';
277 var anim = new YAHOO.util.Anim(ct, {
278 height: {to: 1}
279 }, this.node.ownerTree.duration || .25, YAHOO.util.Easing.easeOut);
280 anim.onComplete.subscribe(function(){
281 cs.display = 'none';
282 cs.overflow = '';
283 cs.height = '';
284 this.animating = false;
285 this.anim = null;
286 if(typeof callback == 'function'){
287 callback();
288 }
289 }, this, true);
290 this.anim = anim;
291 anim.animate();
292 },
293
294 getContainer : function(){
295 return this.ctNode;
296 },
297
298 getEl : function(){
299 return this.wrap;
300 },
301
302 appendDDGhost : function(ghostNode){
303 ghostNode.appendChild(this.elNode.cloneNode(true));
304 },
305
306 getDDRepairXY : function(){
307 return YAHOO.util.Dom.getXY(this.iconNode);
308 },
309
310 onRender : function(){
311 this.render();
312 },
313
314 render : function(bulkRender){
315 var n = this.node;
316 var targetNode = n.parentNode ?
317 n.parentNode.ui.getContainer() : n.ownerTree.container.dom;
318 if(!this.rendered){
319 this.rendered = true;
320 var a = n.attributes;
321
322 // add some indent caching, this helps performance when rendering a large tree
323 this.indentMarkup = '';
324 if(n.parentNode){
325 this.indentMarkup = n.parentNode.ui.getChildIndent();
326 }
327
328 var buf = ['<li class="ytree-node"><div class="ytree-node-el ', n.attributes.cls,'">',
329 '<span class="ytree-node-indent">',this.indentMarkup,'</span>',
330 '<img src="', this.emptyIcon, '" class="ytree-ec-icon">',
331 '<img src="', a.icon || this.emptyIcon, '" class="ytree-node-icon',(a.icon ? ' ytree-node-inline-icon' : ''),'" unselectable="on">',
332 '<a href="',a.href ? a.href : '#','" tabIndex="1" ',
333 a.hrefTarget ? ' target="'+a.hrefTarget+'"' : '','><span unselectable="on">',n.text,'</span></a></div>',
334 '<ul class="ytree-node-ct" style="display:none;"></ul>',
335 '</li>'];
336
337 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
338 this.wrap = YAHOO.ext.DomHelper.insertHtml('beforeBegin',
339 n.nextSibling.ui.getEl(), buf.join(''));
340 }else{
341 this.wrap = YAHOO.ext.DomHelper.insertHtml('beforeEnd', targetNode, buf.join(''));
342 }
343 this.elNode = this.wrap.childNodes[0];
344 this.ctNode = this.wrap.childNodes[1];
345 var cs = this.elNode.childNodes;
346 this.indentNode = cs[0];
347 this.ecNode = cs[1];
348 this.iconNode = cs[2];
349 this.anchor = cs[3];
350 this.textNode = cs[3].firstChild;
351 if(a.qtip){
352 if(this.textNode.setAttributeNS){
353 this.textNode.setAttributeNS('y', 'qtip', a.qtip);
354 if(a.qtipTitle){
355 this.textNode.setAttributeNS('y', 'qtitle', a.qtipTitle);
356 }
357 }else{
358 this.textNode.setAttribute('y:qtip', a.qtip);
359 if(a.qtipTitle){
360 this.textNode.setAttribute('y:qtitle', a.qtipTitle);
361 }
362 }
363 }
364 this.initEvents();
365 //this.renderIndent(); cached above now instead call updateExpandIcon
366 this.updateExpandIcon();
367 }else{
368 if(bulkRender === true) {
369 targetNode.appendChild(this.wrap);
370 }
371 }
372 },
373
374 getAnchor : function(){
375 return this.anchor;
376 },
377
378 getTextEl : function(){
379 return this.textNode;
380 },
381
382 getIconEl : function(){
383 return this.iconNode;
384 },
385
386 updateExpandIcon : function(){
387 if(this.rendered){
388 var n = this.node;
389 var cls = n.isLast() ? "ytree-elbow-end" : "ytree-elbow";
390 var hasChild = n.hasChildNodes();
391 if(hasChild){
392 cls += n.expanded ? '-minus' : '-plus';
393 var c1 = n.expanded ? 'ytree-node-collapsed' : 'ytree-node-expanded';
394 var c2 = n.expanded ? 'ytree-node-expanded' : 'ytree-node-collapsed';
395 YAHOO.util.Dom.removeClass(this.elNode, 'ytree-node-leaf');
396 YAHOO.util.Dom.replaceClass(this.elNode, c1, c2);
397 }else{
398 YAHOO.util.Dom.replaceClass(this.elNode, 'ytree-node-expanded', 'ytree-node-leaf');
399 }
400 this.ecNode.className = 'ytree-ec-icon '+cls;
401 }
402 },
403
404 getChildIndent : function(){
405 if(!this.childIndent){
406 var buf = [];
407 var p = this.node;
408 while(p){
409 if(!p.isRoot || (p.isRoot && p.ownerTree.rootVisible)){
410 if(!p.isLast()) {
411 buf.unshift('<img src="'+this.emptyIcon+'" class="ytree-elbow-line">');
412 } else {
413 buf.unshift('<img src="'+this.emptyIcon+'" class="ytree-icon">');
414 }
415 }
416 p = p.parentNode;
417 }
418 this.childIndent = buf.join('');
419 }
420 return this.childIndent;
421 },
422
423 renderIndent : function(){
424 if(this.rendered){
425 var indent = '';
426 var p = this.node.parentNode;
427 if(p){
428 indent = p.ui.getChildIndent();
429 }
430 if(this.indentMarkup != indent){ // don't rerender if not required
431 this.indentNode.innerHTML = indent;
432 this.indentMarkup = indent;
433 }
434 this.updateExpandIcon();
435 }
436 }
437};
438
439YAHOO.ext.tree.RootTreeNodeUI = function(){
440 YAHOO.ext.tree.RootTreeNodeUI.superclass.constructor.apply(this, arguments);
441};
442YAHOO.extendX(YAHOO.ext.tree.RootTreeNodeUI, YAHOO.ext.tree.TreeNodeUI);
443YAHOO.ext.tree.RootTreeNodeUI.prototype.render = function(){
444 if(!this.rendered){
445 var targetNode = this.node.ownerTree.container.dom;
446 this.node.expanded = true;
447 targetNode.innerHTML = '<div class="ytree-root-node"></div>';
448 this.wrap = this.ctNode = targetNode.firstChild;
449 }
450};
451YAHOO.ext.tree.RootTreeNodeUI.prototype.collapse = function(){
452};
diff --git a/frontend/beta/js/YUI-extensions/tree/TreePanel.js b/frontend/beta/js/YUI-extensions/tree/TreePanel.js
new file mode 100644
index 0000000..202c0d0
--- a/dev/null
+++ b/frontend/beta/js/YUI-extensions/tree/TreePanel.js
@@ -0,0 +1,213 @@
1YAHOO.namespace('ext.tree');
2
3YAHOO.ext.tree.TreePanel = function(el, config){
4 YAHOO.ext.tree.TreePanel.superclass.constructor.call(this);
5 this.el = getEl(el);
6 this.id = this.el.id;
7 YAHOO.ext.util.Config.apply(this, config || {}, {
8 rootVisible : true,
9 lines : true,
10 enableDD : false,
11 hlDrop : true/*,
12 hlColor: null,
13 ddGroup : 'TreeDD'
14 hlBaseColor : 'FFFFFF'*/
15
16 });
17 YAHOO.ext.util.Config.apply(this.events, {
18 'beforeload' : true,
19 'load' : true,
20 'textchange' : true,
21 'beforeexpand' : true,
22 'beforecollapse' : true,
23 'expand' : true,
24 'collapse' : true,
25 'disabledchange' : true,
26 'beforeclick':true,
27 'click':true,
28 'dblclick':true,
29 'contentmenu':true,
30 'beforechildrenrendered':true,
31 /**
32 * @event startdrag
33 * Fires when a node starts being dragged
34 * @param {YAHOO.ext.tree.TreePanel} this
35 * @param {YAHOO.ext.tree.TreeNode} node
36 * @param {event} e The raw browser event
37 */
38 'startdrag' : true,
39 /**
40 * @event enddrag
41 * Fires when a drag operation is complete
42 * @param {YAHOO.ext.tree.TreePanel} this
43 * @param {YAHOO.ext.tree.TreeNode} node
44 * @param {event} e The raw browser event
45 */
46 'enddrag' : true,
47 /**
48 * @event dragdrop
49 * Fires when a dragged node is dropped on a valid DD target
50 * @param {YAHOO.ext.tree.TreePanel} this
51 * @param {YAHOO.ext.tree.TreeNode} node
52 * @param {DD} dd The dd it was dropped on
53 * @param {event} e The raw browser event
54 */
55 'dragdrop' : true,
56 /**
57 * @event beforenodedrop
58 * Fires when a DD object is dropped on a node in this tree for preprocessing. This event can cancel.
59 * @param {Object} dropEvent
60 */
61 'beforenodedrop' : true,
62 /**
63 * @event nodedrop
64 * Fires after a DD object is dropped on a node in this tree
65 * @param {Object} dropEvent
66 */
67 'nodedrop' : true,
68 /**
69 * @event nodedragover
70 * Fires when a tree node is being target
71 * @param {Object} dragOverEvent
72 */
73 'nodedragover' : true
74 });
75 if(this.singleExpand){
76 this.on('beforeexpand', this.restrictExpand, this, true);
77 }
78 // problem with safari and animation
79 // I am investigating
80 if(YAHOO.ext.util.Browser.isSafari){
81 this.animate = false;
82 }
83};
84YAHOO.extendX(YAHOO.ext.tree.TreePanel, YAHOO.ext.data.Tree, {
85 restrictExpand : function(node){
86 var p = node.parentNode;
87 if(p){
88 if(p.expandedChild && p.expandedChild.parentNode == p){
89 p.expandedChild.collapse();
90 }
91 p.expandedChild = node;
92 }
93 },
94
95 setRootNode : function(node){
96 YAHOO.ext.tree.TreePanel.superclass.setRootNode.call(this, node);
97 if(!this.rootVisible){
98 node.ui = new YAHOO.ext.tree.RootTreeNodeUI(node);
99 }
100 return node;
101 },
102
103 getEl : function(){
104 return this.el;
105 },
106
107 getLoader : function(){
108 return this.loader;
109 },
110
111 expandAll : function(){
112 this.root.expand(true);
113 },
114
115 collapseAll : function(){
116 this.root.collapse(true);
117 },
118
119 getSelectionModel : function(){
120 if(!this.selModel){
121 this.selModel = new YAHOO.ext.tree.DefaultSelectionModel();
122 }
123 return this.selModel;
124 },
125
126 expandPath : function(path, attr, callback){
127 attr = attr || 'id';
128 var keys = path.split(this.pathSeparator);
129 var curNode = this.root;
130 if(curNode.attributes[attr] != keys[1]){ // invalid root
131 if(callback){
132 callback(false, null);
133 }
134 return;
135 }
136 var index = 1;
137 var f = function(){
138 if(++index == keys.length){
139 if(callback){
140 callback(true, curNode);
141 }
142 return;
143 }
144 var c = curNode.findChild(attr, keys[index]);
145 if(!c){
146 if(callback){
147 callback(false, curNode);
148 }
149 return;
150 }
151 curNode = c;
152 c.expand(false, false, f);
153 }
154 curNode.expand(false, false, f);
155 },
156
157 selectPath : function(path, attr, callback){
158 attr = attr || 'id';
159 var keys = path.split(this.pathSeparator);
160 var v = keys.pop();
161 if(keys.length > 0){
162 var f = function(success, node){
163 if(success && node){
164 var n = node.findChild(attr, v);
165 if(n){
166 n.select();
167 if(callback){
168 callback(true, n);
169 }
170 }
171 }else{
172 if(callback){
173 callback(false, n);
174 }
175 }
176 };
177 this.expandPath(keys.join(this.pathSeparator), attr, f);
178 }else{
179 this.root.select();
180 if(callback){
181 callback(true, this.root);
182 }
183 }
184 },
185
186 render : function(){
187 this.container = this.el.createChild({tag:'ul',
188 cls:'ytree-root-ct ' +
189 (this.lines ? 'ytree-lines' : 'ytree-no-lines')});
190
191 if(this.containerScroll){
192 YAHOO.ext.dd.ScrollManager.register(this.el);
193 }
194
195 if((this.enableDD || this.enableDrop) && !this.dropZone){
196 this.dropZone = new YAHOO.ext.tree.TreeDropZone(this, this.dropConfig || {
197 ddGroup: this.ddGroup || 'TreeDD'
198 });
199 }
200 if((this.enableDD || this.enableDrag) && !this.dragZone){
201 this.dragZone = new YAHOO.ext.tree.TreeDragZone(this, this.dragConfig || {
202 ddGroup: this.ddGroup || 'TreeDD',
203 scroll: this.ddScroll
204 });
205 }
206 this.getSelectionModel().init(this);
207 this.root.render();
208 if(!this.rootVisible){
209 this.root.renderChildren();
210 }
211 return this;
212 }
213});
diff --git a/frontend/beta/js/YUI-extensions/tree/TreeSelectionModel.js b/frontend/beta/js/YUI-extensions/tree/TreeSelectionModel.js
new file mode 100644
index 0000000..4fed88e
--- a/dev/null
+++ b/frontend/beta/js/YUI-extensions/tree/TreeSelectionModel.js
@@ -0,0 +1,195 @@
1YAHOO.ext.tree.DefaultSelectionModel = function(){
2 this.selNode = null;
3
4 this.events = {
5 'selectionchange' : true
6 };
7};
8
9YAHOO.extendX(YAHOO.ext.tree.DefaultSelectionModel, YAHOO.ext.util.Observable, {
10 init : function(tree){
11 this.tree = tree;
12 tree.el.mon('keydown', this.onKeyDown, this, true);
13 tree.on('click', this.onNodeClick, this, true);
14 },
15
16 onNodeClick : function(node, e){
17 this.select(node);
18 },
19
20 select : function(node){
21 if(this.selNode && this.selNode != node){
22 this.selNode.ui.onSelectedChange(false);
23 }
24 this.selNode = node;
25 node.ui.onSelectedChange(true);
26 this.fireEvent('selectionchange', this, node);
27 return node;
28 },
29
30 unselect : function(node){
31 if(this.selNode == node){
32 this.clearSelections();
33 }
34 },
35
36 clearSelections : function(){
37 var n = this.selNode;
38 if(n){
39 n.ui.onSelectedChange(false);
40 this.selNode = null;
41 this.fireEvent('selectionchange', this, null);
42 }
43 return n;
44 },
45
46 getSelectedNode : function(){
47 return this.selNode;
48 },
49
50 isSelected : function(node){
51 return this.selNode == node;
52 },
53
54 onKeyDown : function(e){
55 var s = this.selNode || this.lastSelNode;
56 // undesirable, but required
57 var sm = this;
58 if(!s){
59 return;
60 }
61 var k = e.getKey();
62 //alert(k)
63 switch(k){
64 case e.DOWN:
65 e.preventDefault();
66 if(s.firstChild && s.isExpanded()){
67 this.select(s.firstChild, e);
68 }else if(s.nextSibling){
69 this.select(s.nextSibling, e);
70 }else if(s.parentNode){
71 s.parentNode.bubble(function(){
72 if(this.nextSibling){
73 sm.select(this.nextSibling, e);
74 return false;
75 }
76 });
77 }
78 break;
79 case e.UP:
80 e.preventDefault();
81 var ps = s.previousSibling;
82 if(ps){
83 if(!ps.isExpanded()){
84 this.select(ps, e);
85 }else{
86 var lc = ps.lastChild;
87 while(lc && lc.isExpanded()){
88 lc = lc.lastChild;
89 }
90 this.select(lc, e);
91 }
92 }else if(s.parentNode && (this.tree.rootVisible || !s.parentNode.isRoot)){
93 this.select(s.parentNode, e);
94 }
95 break;
96 case e.RIGHT:
97 e.preventDefault();
98 if(s.hasChildNodes()){
99 if(!s.isExpanded()){
100 s.expand();
101 }else if(s.firstChild){
102 this.select(s.firstChild, e);
103 }
104 }
105 break;
106 case e.LEFT:
107 e.preventDefault();
108 if(s.hasChildNodes() && s.isExpanded()){
109 s.collapse();
110 }else if(s.parentNode && (this.tree.rootVisible || s.parentNode != this.tree.getRootNode())){
111 this.select(s.parentNode, e);
112 }
113 break;
114 };
115 }
116});
117
118YAHOO.ext.tree.MultiSelectionModel = function(){
119 this.selNodes = [];
120 this.selMap = {};
121 this.events = {
122 'selectionchange' : true
123 };
124};
125
126YAHOO.extendX(YAHOO.ext.tree.MultiSelectionModel, YAHOO.ext.util.Observable, {
127 init : function(tree){
128 this.tree = tree;
129 tree.el.mon('keydown', this.onKeyDown, this, true);
130 tree.on('click', this.onNodeClick, this, true);
131 },
132
133 onNodeClick : function(node, e){
134 this.select(node, e, e.ctrlKey);
135 },
136
137 select : function(node, e, keepExisting){
138 if(keepExisting !== true){
139 this.clearSelections(true);
140 }
141 this.selNodes.push(node);
142 this.selMap[node.id] = node;
143 this.lastSelNode = node;
144 node.ui.onSelectedChange(true);
145 this.fireEvent('selectionchange', this, this.selNodes);
146 return node;
147 },
148
149 unselect : function(node){
150 if(this.selMap[node.id]){
151 node.ui.onSelectedChange(false);
152 var sn = this.selNodes;
153 var index = -1;
154 if(sn.indexOf){
155 index = sn.indexOf(node);
156 }else{
157 for(var i = 0, len = sn.length; i < len; i++){
158 if(sn[i] == node){
159 index = i;
160 break;
161 }
162 }
163 }
164 if(index != -1){
165 this.selNodes.splice(index, 1);
166 }
167 delete this.selMap[node.id];
168 this.fireEvent('selectionchange', this, this.selNodes);
169 }
170 },
171
172 clearSelections : function(suppressEvent){
173 var sn = this.selNodes;
174 if(sn.length > 0){
175 for(var i = 0, len = sn.length; i < len; i++){
176 sn[i].ui.onSelectedChange(false);
177 }
178 this.selNodes = [];
179 this.selMap = {};
180 if(suppressEvent !== true){
181 this.fireEvent('selectionchange', this, this.selNodes);
182 }
183 }
184 },
185
186 isSelected : function(node){
187 return this.selMap[node.id] ? true : false;
188 },
189
190 getSelectedNodes : function(){
191 return this.selNodes;
192 },
193
194 onKeyDown : YAHOO.ext.tree.DefaultSelectionModel.prototype.onKeyDown
195});
diff --git a/frontend/beta/js/YUI-extensions/tree/TreeSorter.js b/frontend/beta/js/YUI-extensions/tree/TreeSorter.js
new file mode 100644
index 0000000..9960703
--- a/dev/null
+++ b/frontend/beta/js/YUI-extensions/tree/TreeSorter.js
@@ -0,0 +1,49 @@
1YAHOO.ext.tree.TreeSorter = function(tree, config){
2 YAHOO.ext.util.Config.apply(this, config);
3 tree.on('beforechildrenrendered', this.doSort, this, true);
4 tree.on('append', this.updateSort, this, true);
5 tree.on('insert', this.updateSort, this, true);
6
7 var dsc = this.dir && this.dir.toLowerCase() == 'desc';
8 var p = this.property || 'text';
9 var sortType = this.sortType;
10 var fs = this.folderSort;
11 var cs = this.caseSensitive === true;
12
13 this.sortFn = function(n1, n2){
14 if(fs){
15 if(n1.leaf && !n2.leaf){
16 return 1;
17 }
18 if(!n1.leaf && n2.leaf){
19 return -1;
20 }
21 }
22 var v1 = sortType ? sortType(n1) : (cs ? n1[p] : n1[p].toUpperCase());
23 var v2 = sortType ? sortType(n2) : (cs ? n2[p] : n2[p].toUpperCase());
24 if(v1 < v2){
25 return dsc ? +1 : -1;
26 }else if(v1 > v2){
27 return dsc ? -1 : +1;
28 }else{
29 return 0;
30 }
31 };
32};
33
34YAHOO.ext.tree.TreeSorter.prototype = {
35 doSort : function(node){
36 node.sort(this.sortFn);
37 },
38
39 compareNodes : function(n1, n2){
40
41 return (n1.text.toUpperCase() > n2.text.toUpperCase() ? 1 : -1);
42 },
43
44 updateSort : function(tree, node){
45 if(node.childrenRendered){
46 this.doSort.defer(1, this, [node]);
47 }
48 }
49};
diff --git a/frontend/beta/js/YUI-extensions/widgets/BasicDialog.js b/frontend/beta/js/YUI-extensions/widgets/BasicDialog.js
new file mode 100644
index 0000000..3912568
--- a/dev/null
+++ b/frontend/beta/js/YUI-extensions/widgets/BasicDialog.js
@@ -0,0 +1,1046 @@
1/**
2 * @class YAHOO.ext.BasicDialog
3 * @extends YAHOO.ext.util.Observable
4 * Lightweight Dialog Class.
5 *
6 * The code below lists all configuration options along with the default value.
7 * If the default value is what you want you can leave it out:
8 * <pre><code>
9 var dlg = new YAHOO.ext.BasicDialog('element-id', {
10 autoCreate: false, (true to auto create from scratch, or DomHelper Object)
11 title: null, (title to set at config time)
12 width: (css),
13 height: (css),
14 x: 200, //(defaults to center screen if blank)
15 y: 500, //(defaults to center screen if blank)
16 animateTarget: null,// (no animation) This is the id or element to animate from
17 resizable: true,
18 minHeight: 80,
19 minWidth: 200,
20 modal: false,
21 autoScroll: true,
22 closable: true,
23 constraintoviewport: true,
24 draggable: true,
25 autoTabs: false, (if true searches child nodes for elements with class ydlg-tab and converts them to tabs)
26 tabTag: 'div', // the tag name of tab elements
27 proxyDrag: false, (drag a proxy element rather than the dialog itself)
28 fixedcenter: false,
29 shadow: false,
30 buttonAlign: 'right',
31 minButtonWidth: 75,
32 shim: false // true to create an iframe shim to
33 // keep selects from showing through
34 });
35 </code></pre>
36 * @constructor
37 * Create a new BasicDialog.
38 * @param {String/HTMLElement/YAHOO.ext.Element} el The id of or container element
39 * @param {Object} config configuration options
40 */
41YAHOO.ext.BasicDialog = function(el, config){
42 this.el = getEl(el);
43 var dh = YAHOO.ext.DomHelper;
44 if(!this.el && config && config.autoCreate){
45 if(typeof config.autoCreate == 'object'){
46 if(!config.autoCreate.id){
47 config.autoCreate.id = el;
48 }
49 this.el = dh.append(document.body,
50 config.autoCreate, true);
51 }else{
52 this.el = dh.append(document.body,
53 {tag: 'div', id: el}, true);
54 }
55 }
56 el = this.el;
57 el.setDisplayed(true);
58 el.hide = this.hideAction;
59 this.id = el.id;
60 el.addClass('ydlg');
61
62 YAHOO.ext.util.Config.apply(this, config);
63
64 this.proxy = el.createProxy('ydlg-proxy');
65 this.proxy.hide = this.hideAction;
66 this.proxy.setOpacity(.5);
67 this.proxy.hide();
68
69 if(config.width){
70 el.setWidth(config.width);
71 }
72 if(config.height){
73 el.setHeight(config.height);
74 }
75 this.size = el.getSize();
76 if(typeof config.x != 'undefined' && typeof config.y != 'undefined'){
77 this.xy = [config.x,config.y];
78 }else{
79 this.xy = el.getCenterXY(true);
80 }
81 // find the header, body and footer
82 var cn = el.dom.childNodes;
83 for(var i = 0, len = cn.length; i < len; i++) {
84 var node = cn[i];
85 if(node && node.nodeType == 1){
86 if(YAHOO.util.Dom.hasClass(node, 'ydlg-hd')){
87 this.header = getEl(node, true);
88 }else if(YAHOO.util.Dom.hasClass(node, 'ydlg-bd')){
89 this.body = getEl(node, true);
90 }else if(YAHOO.util.Dom.hasClass(node, 'ydlg-ft')){
91 /**
92 * The footer element
93 * @type YAHOO.ext.Element
94 */
95 this.footer = getEl(node, true);
96 }
97 }
98 }
99
100 if(!this.header){
101 /**
102 * The header element
103 * @type YAHOO.ext.Element
104 */
105 this.header = this.body ?
106 dh.insertBefore(this.body.dom, {tag: 'div', cls:'ydlg-hd'}, true) :
107 dh.append(el.dom, {tag: 'div', cls:'ydlg-hd'}, true);
108 }
109 if(this.title){
110 this.header.update(this.title);
111 }
112 // this element allows the dialog to be focused for keyboard event
113 this.focusEl = dh.append(el.dom, {tag: 'a', href:'#', cls:'ydlg-focus', tabIndex:'-1'}, true);
114 this.focusEl.swallowEvent('click', true);
115 if(!this.body){
116 /**
117 * The body element
118 * @type YAHOO.ext.Element
119 */
120 this.body = dh.append(el.dom, {tag: 'div', cls:'ydlg-bd'}, true);
121 }
122 // wrap the header for special rendering
123 var hl = dh.insertBefore(this.header.dom, {tag: 'div', cls:'ydlg-hd-left'});
124 var hr = dh.append(hl, {tag: 'div', cls:'ydlg-hd-right'});
125 hr.appendChild(this.header.dom);
126
127 // wrap the body and footer for special rendering
128 this.bwrap = dh.insertBefore(this.body.dom, {tag: 'div', cls:'ydlg-dlg-body'}, true);
129 this.bwrap.dom.appendChild(this.body.dom);
130 if(this.footer) this.bwrap.dom.appendChild(this.footer.dom);
131
132 this.bg = this.el.createChild({
133 tag: 'div', cls:'ydlg-bg',
134 html: '<div class="ydlg-bg-left"><div class="ydlg-bg-right"><div class="ydlg-bg-center">&#160;</div></div></div>'
135 });
136 this.centerBg = getEl(this.bg.dom.firstChild.firstChild.firstChild);
137
138
139 if(this.autoScroll !== false && !this.autoTabs){
140 this.body.setStyle('overflow', 'auto');
141 }
142 if(this.closable !== false){
143 this.el.addClass('ydlg-closable');
144 this.close = dh.append(el.dom, {tag: 'div', cls:'ydlg-close'}, true);
145 this.close.mon('click', this.closeClick, this, true);
146 this.close.addClassOnOver('ydlg-close-over');
147 }
148 if(this.resizable !== false){
149 this.el.addClass('ydlg-resizable');
150 this.resizer = new YAHOO.ext.Resizable(el, {
151 minWidth: this.minWidth || 80,
152 minHeight:this.minHeight || 80,
153 handles: 'all',
154 pinned: true
155 });
156 this.resizer.on('beforeresize', this.beforeResize, this, true);
157 this.resizer.on('resize', this.onResize, this, true);
158 }
159 if(this.draggable !== false){
160 el.addClass('ydlg-draggable');
161 if (!this.proxyDrag) {
162 var dd = new YAHOO.util.DD(el.dom.id, 'WindowDrag');
163 }
164 else {
165 var dd = new YAHOO.util.DDProxy(el.dom.id, 'WindowDrag', {dragElId: this.proxy.id});
166 }
167 dd.setHandleElId(this.header.id);
168 dd.endDrag = this.endMove.createDelegate(this);
169 dd.startDrag = this.startMove.createDelegate(this);
170 dd.onDrag = this.onDrag.createDelegate(this);
171 this.dd = dd;
172 }
173 if(this.modal){
174 this.mask = dh.append(document.body, {tag: 'div', cls:'ydlg-mask'}, true);
175 this.mask.enableDisplayMode('block');
176 this.mask.hide();
177 this.el.addClass('ydlg-modal');
178 }
179 if(this.shadow){
180 this.shadow = el.createProxy({tag: 'div', cls:'ydlg-shadow'});
181 this.shadow.setOpacity(.3);
182 this.shadow.setVisibilityMode(YAHOO.ext.Element.VISIBILITY);
183 this.shadow.setDisplayed('block');
184 this.shadow.hide = this.hideAction;
185 this.shadow.hide();
186 }else{
187 this.shadowOffset = 0;
188 }
189 // adding an iframe shim to FF kills the cursor on the PC, but is needed on the Mac
190 // where it (luckily) does not kill the cursor
191 if(!YAHOO.ext.util.Browser.isGecko || YAHOO.ext.util.Browser.isMac){
192 if(this.shim){
193 this.shim = this.el.createShim();
194 this.shim.hide = this.hideAction;
195 this.shim.hide();
196 }
197 }else{
198 this.shim = false;
199 }
200 if(this.autoTabs){
201 this.initTabs();
202 }
203 this.syncBodyHeight();
204 this.events = {
205 /**
206 * @event keydown
207 * Fires when a key is pressed
208 * @param {YAHOO.ext.BasicDialog} this
209 * @param {YAHOO.ext.EventObject} e
210 */
211 'keydown' : true,
212 /**
213 * @event move
214 * Fires when this dialog is moved by the user.
215 * @param {YAHOO.ext.BasicDialog} this
216 * @param {Number} x The new page X
217 * @param {Number} y The new page Y
218 */
219 'move' : true,
220 /**
221 * @event resize
222 * Fires when this dialog is resized by the user.
223 * @param {YAHOO.ext.BasicDialog} this
224 * @param {Number} width The new width
225 * @param {Number} height The new height
226 */
227 'resize' : true,
228 /**
229 * @event beforehide
230 * Fires before this dialog is hidden.
231 * @param {YAHOO.ext.BasicDialog} this
232 */
233 'beforehide' : true,
234 /**
235 * @event hide
236 * Fires when this dialog is hidden.
237 * @param {YAHOO.ext.BasicDialog} this
238 */
239 'hide' : true,
240 /**
241 * @event beforeshow
242 * Fires before this dialog is shown.
243 * @param {YAHOO.ext.BasicDialog} this
244 */
245 'beforeshow' : true,
246 /**
247 * @event show
248 * Fires when this dialog is shown.
249 * @param {YAHOO.ext.BasicDialog} this
250 */
251 'show' : true
252 };
253 el.mon('keydown', this.onKeyDown, this, true);
254 el.mon("mousedown", this.toFront, this, true);
255
256 YAHOO.ext.EventManager.onWindowResize(this.adjustViewport, this, true);
257 this.el.hide();
258 YAHOO.ext.DialogManager.register(this);
259};
260
261YAHOO.extendX(YAHOO.ext.BasicDialog, YAHOO.ext.util.Observable, {
262 shadowOffset: 3,
263 minHeight: 80,
264 minWidth: 200,
265 minButtonWidth: 75,
266 defaultButton: null,
267 buttonAlign: 'right',
268 /**
269 * Sets the dialog title.
270 * @param {String} text
271 * @return {YAHOO.ext.BasicDialog} this
272 */
273 setTitle : function(text){
274 this.header.update(text);
275 return this;
276 },
277
278 closeClick : function(){
279 this.hide();
280 },
281
282 /**
283 * Reinitializes the tabs component, clearing out old tabs and finding new ones.
284 * @return {YAHOO.ext.TabPanel} tabs The tabs component
285 */
286 initTabs : function(){
287 var tabs = this.getTabs();
288 while(tabs.getTab(0)){
289 tabs.removeTab(0);
290 }
291 var tabEls = YAHOO.util.Dom.getElementsByClassName('ydlg-tab', this.tabTag || 'div', this.el.dom);
292 if(tabEls.length > 0){
293 for(var i = 0, len = tabEls.length; i < len; i++) {
294 var tabEl = tabEls[i];
295 tabs.addTab(YAHOO.util.Dom.generateId(tabEl), tabEl.title);
296 tabEl.title = '';
297 }
298 tabs.activate(0);
299 }
300 return tabs;
301 },
302
303 beforeResize : function(){
304 this.resizer.minHeight = Math.max(this.minHeight, this.getHeaderFooterHeight(true)+40);
305 },
306
307 onResize : function(){
308 this.refreshSize();
309 this.syncBodyHeight();
310 this.adjustAssets();
311 this.fireEvent('resize', this, this.size.width, this.size.height);
312 },
313
314 onKeyDown : function(e){
315 if(this.isVisible()){
316 this.fireEvent('keydown', this, e);
317 }
318 },
319
320 /**
321 * Resizes the dialog.
322 * @param {Number} width
323 * @param {Number} height
324 * @return {YAHOO.ext.BasicDialog} this
325 */
326 resizeTo : function(width, height){
327 this.el.setSize(width, height);
328 this.size = {width: width, height: height};
329 this.syncBodyHeight();
330 if(this.fixedcenter){
331 this.center();
332 }
333 if(this.isVisible()){
334 this.constrainXY();
335 this.adjustAssets();
336 }
337 this.fireEvent('resize', this, width, height);
338 return this;
339 },
340
341
342 /**
343 * Resizes the dialog to fit the specified content size.
344 * @param {Number} width
345 * @param {Number} height
346 * @return {YAHOO.ext.BasicDialog} this
347 */
348 setContentSize : function(w, h){
349 h += this.getHeaderFooterHeight() + this.body.getMargins('tb');
350 w += this.body.getMargins('lr') + this.bwrap.getMargins('lr') + this.centerBg.getPadding('lr');
351 //if(!this.el.isBorderBox()){
352 h += this.body.getPadding('tb') + this.bwrap.getBorderWidth('tb') + this.body.getBorderWidth('tb') + this.el.getBorderWidth('tb');
353 w += this.body.getPadding('lr') + this.bwrap.getBorderWidth('lr') + this.body.getBorderWidth('lr') + this.bwrap.getPadding('lr') + this.el.getBorderWidth('lr');
354 //}
355 if(this.tabs){
356 h += this.tabs.stripWrap.getHeight() + this.tabs.bodyEl.getMargins('tb') + this.tabs.bodyEl.getPadding('tb');
357 w += this.tabs.bodyEl.getMargins('lr') + this.tabs.bodyEl.getPadding('lr');
358 }
359 this.resizeTo(w, h);
360 return this;
361 },
362
363 /**
364 * Adds a key listener for when this dialog is displayed
365 * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the following options:
366 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
367 * @param {Function} fn The function to call
368 * @param {Object} scope (optional) The scope of the function
369 * @return {YAHOO.ext.BasicDialog} this
370 */
371 addKeyListener : function(key, fn, scope){
372 var keyCode, shift, ctrl, alt;
373 if(typeof key == 'object' && !(key instanceof Array)){
374 keyCode = key['key'];
375 shift = key['shift'];
376 ctrl = key['ctrl'];
377 alt = key['alt'];
378 }else{
379 keyCode = key;
380 }
381 var handler = function(dlg, e){
382 if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) && (!alt || e.altKey)){
383 var k = e.getKey();
384 if(keyCode instanceof Array){
385 for(var i = 0, len = keyCode.length; i < len; i++){
386 if(keyCode[i] == k){
387 fn.call(scope || window, dlg, k, e);
388 return;
389 }
390 }
391 }else{
392 if(k == keyCode){
393 fn.call(scope || window, dlg, k, e);
394 }
395 }
396 }
397 };
398 this.on('keydown', handler);
399 return this;
400 },
401
402 /**
403 * Returns the TabPanel component (if autoTabs)
404 * @return {YAHOO.ext.TabPanel}
405 */
406 getTabs : function(){
407 if(!this.tabs){
408 this.el.addClass('ydlg-auto-tabs');
409 this.body.addClass(this.tabPosition == 'bottom' ? 'ytabs-bottom' : 'ytabs-top');
410 this.tabs = new YAHOO.ext.TabPanel(this.body.dom, this.tabPosition == 'bottom');
411 }
412 return this.tabs;
413 },
414
415 /**
416 * Adds a button.
417 * @param {String/Object} config A string becomes the button text, an object is expected to be a valid YAHOO.ext.DomHelper element config
418 * @param {Function} handler The function called when the button is clicked
419 * @param {Object} scope (optional) The scope of the handler function
420 * @return {YAHOO.ext.Button}
421 */
422 addButton : function(config, handler, scope){
423 var dh = YAHOO.ext.DomHelper;
424 if(!this.footer){
425 this.footer = dh.append(this.bwrap.dom, {tag: 'div', cls:'ydlg-ft'}, true);
426 }
427 if(!this.btnContainer){
428 var tb = this.footer.createChild({
429 tag:'div',
430 cls:'ydlg-btns ydlg-btns-'+this.buttonAlign,
431 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table>'
432 });
433 this.btnContainer = tb.dom.firstChild.firstChild.firstChild;
434 }
435 var bconfig = {
436 handler: handler,
437 scope: scope,
438 minWidth: this.minButtonWidth
439 };
440 if(typeof config == 'string'){
441 bconfig.text = config;
442 }else{
443 bconfig.dhconfig = config;
444 }
445 var btn = new YAHOO.ext.Button(
446 this.btnContainer.appendChild(document.createElement('td')),
447 bconfig
448 );
449 this.syncBodyHeight();
450 if(!this.buttons){
451 this.buttons = [];
452 }
453 this.buttons.push(btn);
454 return btn;
455 },
456
457 /**
458 * Sets the default button to be focused when the dialog is displayed
459 * @param {YAHOO.ext.BasicDialog.Button} btn The button object returned by addButton
460 * @return {YAHOO.ext.BasicDialog} this
461 */
462 setDefaultButton : function(btn){
463 this.defaultButton = btn;
464 return this;
465 },
466
467 getHeaderFooterHeight : function(safe){
468 var height = 0;
469 if(this.header){
470 height += this.header.getHeight();
471 }
472 if(this.footer){
473 var fm = this.footer.getMargins();
474 height += (this.footer.getHeight()+fm.top+fm.bottom);
475 }
476 height += this.bwrap.getPadding('tb')+this.bwrap.getBorderWidth('tb');
477 height += this.centerBg.getPadding('tb');
478 return height;
479 },
480
481 syncBodyHeight : function(){
482 var height = this.size.height - this.getHeaderFooterHeight(false);
483 this.body.setHeight(height-this.body.getMargins('tb'));
484 if(this.tabs){
485 this.tabs.syncHeight();
486 }
487 var hh = this.header.getHeight();
488 var h = this.size.height-hh;
489 this.centerBg.setHeight(h);
490 this.bwrap.setLeftTop(this.centerBg.getPadding('l'), hh+this.centerBg.getPadding('t'));
491 this.bwrap.setHeight(h-this.centerBg.getPadding('tb'));
492 this.bwrap.setWidth(this.el.getWidth(true)-this.centerBg.getPadding('lr'));
493 this.body.setWidth(this.bwrap.getWidth(true));
494 },
495
496 /**
497 * Restores the previous state of the dialog if YAHOO.ext.state is configured
498 * @return {YAHOO.ext.BasicDialog} this
499 */
500 restoreState : function(){
501 var box = YAHOO.ext.state.Manager.get(this.stateId || (this.el.id + '-state'));
502 if(box && box.width){
503 this.xy = [box.x, box.y];
504 this.resizeTo(box.width, box.height);
505 }
506 return this;
507 },
508
509 beforeShow : function(){
510 if(this.fixedcenter) {
511 this.xy = this.el.getCenterXY(true);
512 }
513 if(this.modal){
514 YAHOO.util.Dom.addClass(document.body, 'masked');
515 this.mask.setSize(YAHOO.util.Dom.getDocumentWidth(), YAHOO.util.Dom.getDocumentHeight());
516 this.mask.show();
517 }
518 this.constrainXY();
519 },
520
521 animShow : function(){
522 var b = getEl(this.animateTarget, true).getBox();
523 this.proxy.setSize(b.width, b.height);
524 this.proxy.setLocation(b.x, b.y);
525 this.proxy.show();
526 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height,
527 true, .35, this.showEl.createDelegate(this));
528 },
529
530 /**
531 * Shows the dialog.
532 * @param {String/HTMLElement/YAHOO.ext.Element} animateTarget (optional) Reset the animation target
533 * @return {YAHOO.ext.BasicDialog} this
534 */
535 show : function(animateTarget){
536 if (this.fireEvent('beforeshow', this) === false){
537 return;
538 }
539 if(this.syncHeightBeforeShow){
540 this.syncBodyHeight();
541 }
542 this.animateTarget = animateTarget || this.animateTarget;
543 if(!this.el.isVisible()){
544 this.beforeShow();
545 if(this.animateTarget){
546 this.animShow();
547 }else{
548 this.showEl();
549 }
550 }
551 return this;
552 },
553
554 showEl : function(){
555 this.proxy.hide();
556 this.el.setXY(this.xy);
557 this.el.show();
558 this.adjustAssets(true);
559 this.toFront();
560 this.focus();
561 this.fireEvent('show', this);
562 },
563
564 focus : function(){
565 if(this.defaultButton){
566 this.defaultButton.focus();
567 }else{
568 this.focusEl.focus();
569 }
570 },
571
572 constrainXY : function(){
573 if(this.constraintoviewport !== false){
574 if(!this.viewSize){
575 if(this.container){
576 var s = this.container.getSize();
577 this.viewSize = [s.width, s.height];
578 }else{
579 this.viewSize = [YAHOO.util.Dom.getViewportWidth(),
580 YAHOO.util.Dom.getViewportHeight()];
581 }
582 }
583 var x = this.xy[0], y = this.xy[1];
584 var w = this.size.width, h = this.size.height;
585 var vw = this.viewSize[0], vh = this.viewSize[1];
586 // only move it if it needs it
587 var moved = false;
588 // first validate right/bottom
589 if(x + w > vw){
590 x = vw - w;
591 moved = true;
592 }
593 if(y + h > vh){
594 y = vh - h;
595 moved = true;
596 }
597 // then make sure top/left isn't negative
598 if(x < 0){
599 x = 0;
600 moved = true;
601 }
602 if(y < 0){
603 y = 0;
604 moved = true;
605 }
606 if(moved){
607 // cache xy
608 this.xy = [x, y];
609 if(this.isVisible()){
610 this.el.setLocation(x, y);
611 this.adjustAssets();
612 }
613 }
614 }
615 },
616
617 onDrag : function(){
618 if(!this.proxyDrag){
619 this.xy = this.el.getXY();
620 this.adjustAssets();
621 }
622 },
623
624 adjustAssets : function(doShow){
625 var x = this.xy[0], y = this.xy[1];
626 var w = this.size.width, h = this.size.height;
627 if(doShow === true){
628 if(this.shadow){
629 this.shadow.show();
630 }
631 if(this.shim){
632 this.shim.show();
633 }
634 }
635 if(this.shadow && this.shadow.isVisible()){
636 this.shadow.setBounds(x + this.shadowOffset, y + this.shadowOffset, w, h);
637 }
638 if(this.shim && this.shim.isVisible()){
639 this.shim.setBounds(x, y, w, h);
640 }
641 },
642
643
644 adjustViewport : function(w, h){
645 if(!w || !h){
646 w = YAHOO.util.Dom.getViewportWidth();
647 h = YAHOO.util.Dom.getViewportHeight();
648 }
649 // cache the size
650 this.viewSize = [w, h];
651 if(this.modal && this.mask.isVisible()){
652 this.mask.setSize(w, h); // first make sure the mask isn't causing overflow
653 this.mask.setSize(YAHOO.util.Dom.getDocumentWidth(), YAHOO.util.Dom.getDocumentHeight());
654 }
655 if(this.isVisible()){
656 this.constrainXY();
657 }
658 },
659
660 /**
661 * Destroys this dialog
662 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
663 */
664 destroy : function(removeEl){
665 YAHOO.ext.EventManager.removeResizeListener(this.adjustViewport, this);
666 if(this.tabs){
667 this.tabs.destroy(removeEl);
668 }
669 if(this.shim){
670 this.shim.remove();
671 }
672 if(this.shadow){
673 this.shadow.remove();
674 }
675 if(this.proxy){
676 this.proxy.remove();
677 }
678 if(this.resizer){
679 this.resizer.destroy();
680 }
681 if(this.close){
682 this.close.removeAllListeners();
683 this.close.remove();
684 }
685 if(this.mask){
686 this.mask.remove();
687 }
688 if(this.dd){
689 this.dd.unreg();
690 }
691 if(this.buttons){
692 for(var i = 0, len = this.buttons.length; i < len; i++){
693 this.buttons[i].destroy();
694 }
695 }
696 this.el.removeAllListeners();
697 if(removeEl === true){
698 this.el.update('');
699 this.el.remove();
700 }
701 YAHOO.ext.DialogManager.unregister(this);
702 },
703
704 startMove : function(){
705 if(this.proxyDrag){
706 this.proxy.show();
707 }
708 if(this.constraintoviewport !== false){
709 this.dd.constrainTo(document.body, {right: this.shadowOffset, bottom: this.shadowOffset});
710 }
711 },
712
713 endMove : function(){
714 if(!this.proxyDrag){
715 YAHOO.util.DD.prototype.endDrag.apply(this.dd, arguments);
716 }else{
717 YAHOO.util.DDProxy.prototype.endDrag.apply(this.dd, arguments);
718 this.proxy.hide();
719 }
720 this.refreshSize();
721 this.adjustAssets();
722 this.fireEvent('move', this, this.xy[0], this.xy[1])
723 },
724
725 /**
726 * Brings this dialog to the front of any other visible dialogs
727 * @return {YAHOO.ext.BasicDialog} this
728 */
729 toFront : function(){
730 YAHOO.ext.DialogManager.bringToFront(this);
731 return this;
732 },
733
734 /**
735 * Sends this dialog to the back (under) of any other visible dialogs
736 * @return {YAHOO.ext.BasicDialog} this
737 */
738 toBack : function(){
739 YAHOO.ext.DialogManager.sendToBack(this);
740 return this;
741 },
742
743 /**
744 * Centers this dialog
745 * @return {YAHOO.ext.BasicDialog} this
746 */
747 center : function(){
748 var xy = this.el.getCenterXY(true);
749 this.moveTo(xy[0], xy[1]);
750 return this;
751 },
752
753 /**
754 * Moves the dialog to the specified point
755 * @param {Number} x
756 * @param {Number} y
757 * @return {YAHOO.ext.BasicDialog} this
758 */
759 moveTo : function(x, y){
760 this.xy = [x,y];
761 if(this.isVisible()){
762 this.el.setXY(this.xy);
763 this.adjustAssets();
764 }
765 return this;
766 },
767
768 /**
769 * Returns true if the dialog is visible
770 * @return {Boolean}
771 */
772 isVisible : function(){
773 return this.el.isVisible();
774 },
775
776 animHide : function(callback){
777 var b = getEl(this.animateTarget, true).getBox();
778 this.proxy.show();
779 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height);
780 this.el.hide();
781 this.proxy.setBounds(b.x, b.y, b.width, b.height, true, .35,
782 this.hideEl.createDelegate(this, [callback]));
783 },
784
785 /**
786 * Hides the dialog.
787 * @param {Function} callback (optional) Function to call when the dialog is hidden
788 * @return {YAHOO.ext.BasicDialog} this
789 */
790 hide : function(callback){
791 if (this.fireEvent('beforehide', this) === false)
792 return;
793
794 if(this.shadow){
795 this.shadow.hide();
796 }
797 if(this.shim) {
798 this.shim.hide();
799 }
800 if(this.animateTarget){
801 this.animHide(callback);
802 }else{
803 this.el.hide();
804 this.hideEl(callback);
805 }
806 return this;
807 },
808
809 hideEl : function(callback){
810 this.proxy.hide();
811 if(this.modal){
812 this.mask.hide();
813 YAHOO.util.Dom.removeClass(document.body, 'masked');
814 }
815 this.fireEvent('hide', this);
816 if(typeof callback == 'function'){
817 callback();
818 }
819 },
820
821 hideAction : function(){
822 this.setLeft('-10000px');
823 this.setTop('-10000px');
824 this.setStyle('visibility', 'hidden');
825 },
826
827 refreshSize : function(){
828 this.size = this.el.getSize();
829 this.xy = this.el.getXY();
830 YAHOO.ext.state.Manager.set(this.stateId || this.el.id + '-state', this.el.getBox());
831 },
832
833 setZIndex : function(index){
834 if(this.modal){
835 this.mask.setStyle('z-index', index);
836 }
837 if(this.shim){
838 this.shim.setStyle('z-index', ++index);
839 }
840 if(this.shadow){
841 this.shadow.setStyle('z-index', ++index);
842 }
843 this.el.setStyle('z-index', ++index);
844 if(this.proxy){
845 this.proxy.setStyle('z-index', ++index);
846 }
847 if(this.resizer){
848 this.resizer.proxy.setStyle('z-index', ++index);
849 }
850
851 this.lastZIndex = index;
852 },
853
854 /**
855 * Returns the element for this dialog
856 * @return {YAHOO.ext.Element}
857 */
858 getEl : function(){
859 return this.el;
860 }
861});
862
863/**
864 * @class YAHOO.ext.DialogManager
865 * Provides global access to BasicDialogs that have been created and
866 * support for z-indexing (layering) multiple open dialogs.
867 */
868YAHOO.ext.DialogManager = function(){
869 var list = {};
870 var accessList = [];
871 var front = null;
872
873 var sortDialogs = function(d1, d2){
874 return (!d1._lastAccess || d1._lastAccess < d2._lastAccess) ? -1 : 1;
875 };
876
877 var orderDialogs = function(){
878 accessList.sort(sortDialogs);
879 var seed = YAHOO.ext.DialogManager.zseed;
880 for(var i = 0, len = accessList.length; i < len; i++){
881 if(accessList[i]){
882 accessList[i].setZIndex(seed + (i*10));
883 }
884 }
885 };
886
887 return {
888 /**
889 * The starting z-index for BasicDialogs - defaults to 10000
890 * @type Number
891 */
892 zseed : 10000,
893
894
895 register : function(dlg){
896 list[dlg.id] = dlg;
897 accessList.push(dlg);
898 },
899
900 unregister : function(dlg){
901 delete list[dlg.id];
902 if(!accessList.indexOf){
903 for(var i = 0, len = accessList.length; i < len; i++){
904 accessList.splice(i, 1);
905 return;
906 }
907 }else{
908 var i = accessList.indexOf(dlg);
909 if(i != -1){
910 accessList.splice(i, 1);
911 }
912 }
913 },
914
915 /**
916 * Gets a registered dialog by id
917 * @param {String/Object} id The id of the dialog or a dialog
918 * @return {YAHOO.ext.BasicDialog}
919 */
920 get : function(id){
921 return typeof id == 'object' ? id : list[id];
922 },
923
924 /**
925 * Brings the specified dialog to the front
926 * @param {String/Object} dlg The id of the dialog or a dialog
927 * @return {YAHOO.ext.BasicDialog}
928 */
929 bringToFront : function(dlg){
930 dlg = this.get(dlg);
931 if(dlg != front){
932 front = dlg;
933 dlg._lastAccess = new Date().getTime();
934 orderDialogs();
935 }
936 return dlg;
937 },
938
939 /**
940 * Sends the specified dialog to the back
941 * @param {String/Object} dlg The id of the dialog or a dialog
942 * @return {YAHOO.ext.BasicDialog}
943 */
944 sendToBack : function(dlg){
945 dlg = this.get(dlg);
946 dlg._lastAccess = -(new Date().getTime());
947 orderDialogs();
948 return dlg;
949 }
950 };
951}();
952
953/**
954 * @class YAHOO.ext.LayoutDialog
955 * @extends YAHOO.ext.BasicDialog
956 * Dialog which provides adjustments for working with a layout in a Dialog.
957 * Add your neccessary layout config options to the dialogs config.<br>
958 * Example Usage (including a nested layout):
959 * <pre><code> if(!dialog){
960 dialog = new YAHOO.ext.LayoutDialog("download-dlg", {
961 modal: true,
962 width:600,
963 height:450,
964 shadow:true,
965 minWidth:500,
966 minHeight:350,
967 autoTabs:true,
968 proxyDrag:true,
969 // layout config merges with the dialog config
970 center:{
971 tabPosition: 'top',
972 alwaysShowTabs: true
973 }
974 });
975 dialog.addKeyListener(27, dialog.hide, dialog);
976 dialog.setDefaultButton(dialog.addButton('Close', dialog.hide, dialog));
977 dialog.addButton('Build It!', this.getDownload, this);
978
979 // we can even add nested layouts
980 var innerLayout = new YAHOO.ext.BorderLayout('dl-inner', {
981 east: {
982 initialSize: 200,
983 autoScroll:true,
984 split:true
985 },
986 center: {
987 autoScroll:true
988 }
989 });
990 innerLayout.beginUpdate();
991 innerLayout.add('east', new YAHOO.ext.ContentPanel('dl-details'));
992 innerLayout.add('center', new YAHOO.ext.ContentPanel('selection-panel'));
993 innerLayout.endUpdate(true);
994
995 // when doing updates to the top level layout in a dialog, you need to
996 // use dialog.beginUpdate()/endUpdate() instead of layout.beginUpdate()/endUpdate()
997 var layout = dialog.getLayout();
998 dialog.beginUpdate();
999 layout.add('center', new YAHOO.ext.ContentPanel('standard-panel',
1000 {title: 'Download the Source', fitToFrame:true}));
1001 layout.add('center', new YAHOO.ext.NestedLayoutPanel(innerLayout,
1002 {title: 'Build your own yui-ext.js'}));
1003 layout.getRegion('center').showPanel(sp);
1004 dialog.endUpdate();</code></pre>
1005 * @constructor
1006 * @param {String/HTMLElement/YAHOO.ext.Element} el The id of or container element
1007 * @param {Object} config configuration options
1008 */
1009YAHOO.ext.LayoutDialog = function(el, config){
1010 config.autoTabs = false;
1011 YAHOO.ext.LayoutDialog.superclass.constructor.call(this, el, config);
1012 this.body.setStyle({overflow:'hidden', position:'relative'});
1013 this.layout = new YAHOO.ext.BorderLayout(this.body.dom, config);
1014 this.layout.monitorWindowResize = false;
1015 this.el.addClass('ydlg-auto-layout');
1016 // fix case when center region overwrites center function
1017 this.center = YAHOO.ext.BasicDialog.prototype.center;
1018 this.on('show', this.layout.layout, this.layout, true);
1019};
1020YAHOO.extendX(YAHOO.ext.LayoutDialog, YAHOO.ext.BasicDialog, {
1021 /**
1022 * Ends update of the layout <strike>and resets display to none</strike>. Use standard beginUpdate/endUpdate on the layout.
1023 * @deprecated
1024 */
1025 endUpdate : function(){
1026 this.layout.endUpdate();
1027 },
1028 /**
1029 * Begins an update of the layout <strike>and sets display to block and visibility to hidden</strike>. Use standard beginUpdate/endUpdate on the layout.
1030 * @deprecated
1031 */
1032 beginUpdate : function(){
1033 this.layout.beginUpdate();
1034 },
1035 /**
1036 * Get the BorderLayout for this dialog
1037 * @return {YAHOO.ext.BorderLayout}
1038 */
1039 getLayout : function(){
1040 return this.layout;
1041 },
1042 syncBodyHeight : function(){
1043 YAHOO.ext.LayoutDialog.superclass.syncBodyHeight.call(this);
1044 if(this.layout)this.layout.layout();
1045 }
1046});
diff --git a/frontend/beta/js/YUI-extensions/widgets/Button.js b/frontend/beta/js/YUI-extensions/widgets/Button.js
new file mode 100644
index 0000000..5bf3dc3
--- a/dev/null
+++ b/frontend/beta/js/YUI-extensions/widgets/Button.js
@@ -0,0 +1,185 @@
1/**
2 * @class YAHOO.ext.Button
3 * @extends YAHOO.ext.util.Observable
4 * Simple Button class
5 * @cfg {String} text The button text
6 * @cfg {Function} handler A function called when the button is clicked (can be used instead of click event)
7 * @cfg {Object} scope The scope of the handler
8 * @cfg {Number} minWidth The minimum width for this button (used to give a set of buttons a common width)
9 * @constructor
10 * Create a new button
11 * @param {String/HTMLElement/Element} renderTo The element to append the button to
12 * @param {Object} config The config object
13 */
14YAHOO.ext.Button = function(renderTo, config){
15 YAHOO.ext.util.Config.apply(this, config);
16 this.events = {
17 /**
18 * @event click
19 * Fires when this button is clicked
20 * @param {Button} this
21 * @param {EventObject} e The click event
22 */
23 'click' : true
24 };
25 if(renderTo){
26 this.render(renderTo);
27 }
28};
29
30YAHOO.extendX(YAHOO.ext.Button, YAHOO.ext.util.Observable, {
31 render : function(renderTo){
32 var btn;
33 if(!this.dhconfig){
34 if(!YAHOO.ext.Button.buttonTemplate){
35 // hideous table template
36 YAHOO.ext.Button.buttonTemplate = new YAHOO.ext.DomHelper.Template('<a href="#" class="ybtn-focus"><table border="0" cellpadding="0" cellspacing="0" class="ybtn-wrap"><tbody><tr><td class="ybtn-left">&#160;</td><td class="ybtn-center" unselectable="on">{0}</td><td class="ybtn-right">&#160;</td></tr></tbody></table></a>');
37 }
38 btn = YAHOO.ext.Button.buttonTemplate.append(
39 getEl(renderTo).dom, [this.text], true);
40 this.tbl = getEl(btn.dom.firstChild, true);
41 }else{
42 btn = YAHOO.ext.DomHelper.append(this.footer.dom, this.dhconfig, true);
43 }
44 this.el = btn;
45 this.autoWidth();
46 btn.addClass('ybtn');
47 btn.mon('click', this.onClick, this, true);
48 btn.on('mouseover', this.onMouseOver, this, true);
49 btn.on('mouseout', this.onMouseOut, this, true);
50 btn.on('mousedown', this.onMouseDown, this, true);
51 btn.on('mouseup', this.onMouseUp, this, true);
52 },
53 /**
54 * Returns the buttons element
55 * @return {YAHOO.ext.Element}
56 */
57 getEl : function(){
58 return this.el;
59 },
60
61 /**
62 * Destroys this Button.
63 */
64 destroy : function(){
65 this.el.removeAllListeners();
66 this.purgeListeners();
67 this.el.update('');
68 this.el.remove();
69 },
70
71 autoWidth : function(){
72 if(this.tbl){
73 this.el.setWidth('auto');
74 this.tbl.setWidth('auto');
75 if(this.minWidth){
76 if(this.tbl.getWidth() < this.minWidth){
77 this.tbl.setWidth(this.minWidth);
78 }
79 }
80 this.el.setWidth(this.tbl.getWidth());
81 }
82 },
83 /**
84 * Sets this buttons click handler
85 * @param {Function} handler The function to call when the button is clicked
86 * @param {Object} scope (optional) Scope for the function passed above
87 */
88 setHandler : function(handler, scope){
89 this.handler = handler;
90 this.scope = scope;
91 },
92
93 /**
94 * Set this buttons text
95 * @param {String} text
96 */
97 setText : function(text){
98 this.text = text;
99 this.el.dom.firstChild.firstChild.firstChild.childNodes[1].innerHTML = text;
100 this.autoWidth();
101 },
102
103 /**
104 * Get the text for this button
105 * @return {String}
106 */
107 getText : function(){
108 return this.text;
109 },
110
111 /**
112 * Show this button
113 */
114 show: function(){
115 this.el.setStyle('display', '');
116 },
117
118 /**
119 * Hide this button
120 */
121 hide: function(){
122 this.el.setStyle('display', 'none');
123 },
124
125 /**
126 * Convenience function for boolean show/hide
127 * @param {Boolean} visible true to show/false to hide
128 */
129 setVisible: function(visible){
130 if(visible) {
131 this.show();
132 }else{
133 this.hide();
134 }
135 },
136
137 /**
138 * Focus the button
139 */
140 focus : function(){
141 this.el.focus();
142 },
143
144 /**
145 * Disable this button
146 */
147 disable : function(){
148 this.el.addClass('ybtn-disabled');
149 this.disabled = true;
150 },
151
152 /**
153 * Enable this button
154 */
155 enable : function(){
156 this.el.removeClass('ybtn-disabled');
157 this.disabled = false;
158 },
159
160 onClick : function(e){
161 e.preventDefault();
162 if(!this.disabled){
163 this.fireEvent('click', this, e);
164 if(this.handler){
165 this.handler.call(this.scope || this, this, e);
166 }
167 }
168 },
169 onMouseOver : function(e){
170 if(!this.disabled){
171 this.el.addClass('ybtn-over');
172 }
173 },
174 onMouseOut : function(e){
175 this.el.removeClass('ybtn-over');
176 },
177 onMouseDown : function(){
178 if(!this.disabled){
179 this.el.addClass('ybtn-click');
180 }
181 },
182 onMouseUp : function(){
183 this.el.removeClass('ybtn-click');
184 }
185});
diff --git a/frontend/beta/js/YUI-extensions/widgets/DatePicker.js b/frontend/beta/js/YUI-extensions/widgets/DatePicker.js
new file mode 100644
index 0000000..eb1e06f
--- a/dev/null
+++ b/frontend/beta/js/YUI-extensions/widgets/DatePicker.js
@@ -0,0 +1,344 @@
1YAHOO.ext.DatePicker = function(id, parentElement){
2 this.id = id;
3 this.selectedDate = new Date();
4 this.visibleDate = new Date();
5 this.element = null;
6 this.shadow = null;
7 this.callback = null;
8 this.buildControl(parentElement || document.body);
9 this.mouseDownHandler = YAHOO.ext.EventManager.wrap(this.handleMouseDown, this, true);
10 this.keyDownHandler = YAHOO.ext.EventManager.wrap(this.handleKeyDown, this, true);
11 this.wheelHandler = YAHOO.ext.EventManager.wrap(this.handleMouseWheel, this, true);
12};
13
14YAHOO.ext.DatePicker.prototype = {
15 show : function(x, y, value, callback){
16 this.hide();
17 this.selectedDate = value;
18 this.visibleDate = value;
19 this.callback = callback;
20 this.refresh();
21 this.element.show();
22 this.element.setXY(this.constrainToViewport ? this.constrainXY(x, y) : [x, y]);
23 this.shadow.show();
24 this.shadow.setRegion(this.element.getRegion());
25 this.element.dom.tabIndex = 1;
26 this.element.focus();
27 YAHOO.util.Event.on(document, "mousedown", this.mouseDownHandler);
28 YAHOO.util.Event.on(document, "keydown", this.keyDownHandler);
29 YAHOO.util.Event.on(document, "mousewheel", this.wheelHandler);
30 YAHOO.util.Event.on(document, "DOMMouseScroll", this.wheelHandler);
31 },
32
33 constrainXY : function(x, y){
34 var w = YAHOO.util.Dom.getViewportWidth();
35 var h = YAHOO.util.Dom.getViewportHeight();
36 var size = this.element.getSize();
37 return [
38 Math.min(w-size.width, x),
39 Math.min(h-size.height, y)
40 ];
41 },
42
43 hide : function(){
44 this.shadow.hide();
45 this.element.hide();
46 YAHOO.util.Event.removeListener(document, "mousedown", this.mouseDownHandler);
47 YAHOO.util.Event.removeListener(document, "keydown", this.keyDownHandler);
48 YAHOO.util.Event.removeListener(document, "mousewheel", this.wheelHandler);
49 YAHOO.util.Event.removeListener(document, "DOMMouseScroll", this.wheelHandler);
50 },
51
52 setSelectedDate : function(date){
53 this.selectedDate = date;
54 },
55
56 getSelectedDate : function(){
57 return this.selectedDate;
58 },
59
60 showPrevMonth : function(){
61 this.visibleDate = this.getPrevMonth(this.visibleDate);
62 this.refresh();
63 },
64
65 showNextMonth : function(){
66 this.visibleDate = this.getNextMonth(this.visibleDate);
67 this.refresh();
68 },
69
70 showPrevYear : function(){
71 var d = this.visibleDate;
72 this.visibleDate = new Date(d.getFullYear()-1, d.getMonth(), d.getDate());
73 this.refresh();
74 },
75
76 showNextYear : function(){
77 var d = this.visibleDate;
78 this.visibleDate = new Date(d.getFullYear()+1, d.getMonth(), d.getDate());
79 this.refresh();
80 },
81
82 handleMouseDown : function(e){
83 var target = e.getTarget();
84 if(target != this.element.dom && !YAHOO.util.Dom.isAncestor(this.element.dom, target)){
85 this.hide();
86 }
87 },
88
89 handleKeyDown : function(e){
90 switch(e.browserEvent.keyCode){
91 case e.LEFT:
92 this.showPrevMonth();
93 e.stopEvent();
94 break;
95 case e.RIGHT:
96 this.showNextMonth();
97 e.stopEvent();
98 break;
99 case e.DOWN:
100 this.showPrevYear();
101 e.stopEvent();
102 break;
103 case e.UP:
104 this.showNextYear();
105 e.stopEvent();
106 break;
107 }
108 },
109
110 handleMouseWheel : function(e){
111 var delta = e.getWheelDelta();
112 if(delta > 0){
113 this.showPrevMonth();
114 e.stopEvent();
115 } else if(delta < 0){
116 this.showNextMonth();
117 e.stopEvent();
118 }
119 },
120
121 handleClick : function(e){
122 var d = this.visibleDate;
123 var t = e.getTarget();
124 if(t && t.className){
125 var cls = t.className.split(' ')[0];
126 switch(cls){
127 case 'active':
128 this.handleSelection(new Date(d.getFullYear(), d.getMonth(), parseInt(t.innerHTML)));
129 break;
130 case 'prevday':
131 var p = this.getPrevMonth(d);
132 this.handleSelection(new Date(p.getFullYear(), p.getMonth(), parseInt(t.innerHTML)));
133 break;
134 case 'nextday':
135 var n = this.getNextMonth(d);
136 this.handleSelection(new Date(n.getFullYear(), n.getMonth(), parseInt(t.innerHTML)));
137 break;
138 case 'ypopcal-today':
139 this.handleSelection(new Date());
140 break;
141 case 'next-month':
142 this.showNextMonth();
143 break;
144 case 'prev-month':
145 this.showPrevMonth();
146 break;
147 }
148 }
149 e.stopEvent();
150 },
151
152 selectToday : function(){
153 this.handleSelection(new Date());
154 },
155
156 handleSelection: function(date){
157 this.selectedDate = date;
158 this.callback(date);
159 this.hide();
160 },
161
162 getPrevMonth : function(d){
163 var m = d.getMonth();var y = d.getFullYear();
164 return (m == 0 ? new Date(--y, 11, 1) : new Date(y, --m, 1));
165 },
166
167 getNextMonth : function(d){
168 var m = d.getMonth();var y = d.getFullYear();
169 return (m == 11 ? new Date(++y, 0, 1) : new Date(y, ++m, 1));
170 },
171
172 getDaysInMonth : function(m, y){
173 return (m == 1 || m == 3 || m == 5 || m == 7 || m == 8 || m == 10 || m == 12) ? 31 : (m == 4 || m == 6 || m == 9 || m == 11) ? 30 : this.isLeapYear(y) ? 29 : 28;
174 },
175
176 isLeapYear : function(y){
177 return (((y % 4) == 0) && ((y % 100) != 0) || ((y % 400) == 0));
178 },
179
180 clearTime : function(date){
181 if(date){
182 date.setHours(0);
183 date.setMinutes(0);
184 date.setSeconds(0);
185 date.setMilliseconds(0);
186 }
187 return date;
188 },
189
190 refresh : function(){
191 var d = this.visibleDate;
192 this.buildInnerCal(d);
193 this.calHead.update(this.monthNames[d.getMonth()] + ' ' + d.getFullYear());
194 if(this.element.isVisible()){
195 this.shadow.setRegion(this.element.getRegion());
196 }
197 }
198};
199
200/**
201 * This code is not pretty, but it is fast!
202 * @ignore
203 */
204YAHOO.ext.DatePicker.prototype.buildControl = function(parentElement){
205 var c = document.createElement('div');
206 c.style.position = 'absolute';
207 c.style.visibility = 'hidden';
208 document.body.appendChild(c);
209 var html = '<iframe id="'+this.id+'_shdw" frameborder="0" class="ypopcal-shadow" src="'+YAHOO.ext.SSL_SECURE_URL+'"></iframe>' +
210 '<div hidefocus="true" class="ypopcal" id="'+this.id+'">' +
211 '<table class="ypopcal-head" border=0 cellpadding=0 cellspacing=0><tbody><tr><td class="ypopcal-arrow"><div class="prev-month">&#160;</div></td><td class="ypopcal-month">&#160;</td><td class="ypopcal-arrow"><div class="next-month">&#160;</div></td></tr></tbody></table>' +
212 '<center><div class="ypopcal-inner">';
213 html += "<table border=0 cellspacing=0 class=\"ypopcal-table\"><thead><tr class=\"ypopcal-daynames\">";
214 var names = this.dayNames;
215 for(var i = 0; i < names.length; i++){
216 html += '<td>' + names[i].substr(0, 1) + '</td>';
217 }
218 html+= "</tr></thead><tbody><tr>";
219 for(var i = 0; i < 42; i++) {
220 if(i % 7 == 0 && i != 0){
221 html += '</tr><tr>';
222 }
223 html += "<td>&nbsp;</td>";
224 }
225 html += "</tr></tbody></table>";
226 html += '</div><button class="ypopcal-today">'+this.todayText+'</button></center></div>';
227 c.innerHTML = html;
228 this.shadow = getEl(c.childNodes[0], true);
229 this.shadow.enableDisplayMode('block');
230 this.element = getEl(c.childNodes[1], true);
231 this.element.enableDisplayMode('block');
232 document.body.appendChild(this.shadow.dom);
233 document.body.appendChild(this.element.dom);
234 document.body.removeChild(c);
235 this.element.on("selectstart", function(){return false;});
236 var tbody = this.element.dom.getElementsByTagName('tbody')[1];
237 this.cells = tbody.getElementsByTagName('td');
238 this.calHead = this.element.getChildrenByClassName('ypopcal-month', 'td')[0];
239 this.element.mon('mousedown', this.handleClick, this, true);
240};
241
242YAHOO.ext.DatePicker.prototype.buildInnerCal = function(dateVal){
243 var days = this.getDaysInMonth(dateVal.getMonth() + 1, dateVal.getFullYear());
244 var firstOfMonth = new Date(dateVal.getFullYear(), dateVal.getMonth(), 1);
245 var startingPos = firstOfMonth.getDay();
246 if(startingPos == 0) startingPos = 7;
247 var pm = this.getPrevMonth(dateVal);
248 var prevStart = this.getDaysInMonth(pm.getMonth()+1, pm.getFullYear())-startingPos;
249 var cells = this.cells;
250 days += startingPos;
251
252 // convert everything to numbers so it's fast
253 var day = 86400000;
254 var date = this.clearTime(new Date(pm.getFullYear(), pm.getMonth(), prevStart));
255 var today = this.clearTime(new Date()).getTime();
256 var sel = this.selectedDate ? this.clearTime(this.selectedDate).getTime() : today + 1; //today +1 will never match anything
257 var min = this.minDate ? this.clearTime(this.minDate).getTime() : Number.NEGATIVE_INFINITY;
258 var max = this.maxDate ? this.clearTime(this.maxDate).getTime() : Number.POSITIVE_INFINITY;
259 var ddMatch = this.disabledDatesRE;
260 var ddText = this.disabledDatesText;
261 var ddays = this.disabledDays;
262 var ddaysText = this.disabledDaysText;
263 var format = this.format;
264
265 var setCellClass = function(cal, cell, d){
266 cell.title = '';
267 var t = d.getTime();
268 if(t == today){
269 cell.className += ' today';
270 cell.title = cal.todayText;
271 }
272 if(t == sel){
273 cell.className += ' selected';
274 }
275 // disabling
276 if(t < min) {
277 cell.className = ' ypopcal-disabled';
278 cell.title = cal.minText;
279 return;
280 }
281 if(t > max) {
282 cell.className = ' ypopcal-disabled';
283 cell.title = cal.maxText;
284 return;
285 }
286 if(ddays){
287 var day = d.getDay();
288 for(var i = 0; i < ddays.length; i++) {
289 if(day === ddays[i]){
290 cell.title = ddaysText;
291 cell.className = ' ypopcal-disabled';
292 return;
293 }
294 }
295 }
296 if(ddMatch && format){
297 var fvalue = d.format(format);
298 if(ddMatch.test(fvalue)){
299 cell.title = ddText.replace('%0', fvalue);
300 cell.className = ' ypopcal-disabled';
301 return;
302 }
303 }
304 };
305
306 var i = 0;
307 for(; i < startingPos; i++) {
308 cells[i].innerHTML = (++prevStart);
309 date.setDate(date.getDate()+1);
310 cells[i].className = 'prevday';
311 setCellClass(this, cells[i], date);
312 }
313 for(; i < days; i++){
314 intDay = i - startingPos + 1;
315 cells[i].innerHTML = (intDay);
316 date.setDate(date.getDate()+1);
317 cells[i].className = 'active';
318 setCellClass(this, cells[i], date);
319 }
320 var extraDays = 0;
321 for(; i < 42; i++) {
322 cells[i].innerHTML = (++extraDays);
323 date.setDate(date.getDate()+1);
324 cells[i].className = 'nextday';
325 setCellClass(this, cells[i], date);
326 }
327};
328
329YAHOO.ext.DatePicker.prototype.todayText = "Today";
330YAHOO.ext.DatePicker.prototype.minDate = null;
331YAHOO.ext.DatePicker.prototype.maxDate = null;
332YAHOO.ext.DatePicker.prototype.minText = "This date is before the minimum date";
333YAHOO.ext.DatePicker.prototype.maxText = "This date is after the maximum date";
334YAHOO.ext.DatePicker.prototype.format = 'm/d/y';
335YAHOO.ext.DatePicker.prototype.disabledDays = null;
336YAHOO.ext.DatePicker.prototype.disabledDaysText = '';
337YAHOO.ext.DatePicker.prototype.disabledDatesRE = null;
338YAHOO.ext.DatePicker.prototype.disabledDatesText = '';
339YAHOO.ext.DatePicker.prototype.constrainToViewport = true;
340
341
342YAHOO.ext.DatePicker.prototype.monthNames = Date.monthNames;
343
344YAHOO.ext.DatePicker.prototype.dayNames = Date.dayNames;
diff --git a/frontend/beta/js/YUI-extensions/widgets/InlineEditor.js b/frontend/beta/js/YUI-extensions/widgets/InlineEditor.js
new file mode 100644
index 0000000..a498faa
--- a/dev/null
+++ b/frontend/beta/js/YUI-extensions/widgets/InlineEditor.js
@@ -0,0 +1,216 @@
1YAHOO.ext.InlineEditor = function(config, existingEl){
2 YAHOO.ext.util.Config.apply(this, config);
3 var dh = YAHOO.ext.DomHelper;
4 this.wrap = dh.append(this.container || document.body, {
5 tag:'div',
6 cls:'yinline-editor-wrap'
7 }, true);
8
9 this.textSizeEl = dh.append(document.body, {
10 tag: 'div',
11 cls: 'yinline-editor-sizer ' + (this.cls || '')
12 });
13 if(YAHOO.ext.util.Browser.isSafari){ // extra padding for safari's textboxes
14 this.textSizeEl.style.padding = '4px';
15 YAHOO.util.Dom.setStyle(this.textSizeEl, 'padding-right', '10px');
16 }
17
18 if(!YAHOO.ext.util.Browser.isGecko){ // no one else needs FireFox cursor fix
19 this.wrap.setStyle('overflow', 'hidden');
20 }
21
22 if(existingEl){
23 this.el = getEl(existingEl);
24 }
25 if(!this.el){
26 this.id = this.id || YAHOO.util.Dom.generateId();
27 if(!this.multiline){
28 this.el = this.wrap.createChild({
29 tag: 'input',
30 name: this.name || this.id,
31 id: this.id,
32 type: this.type || 'text',
33 autocomplete: 'off',
34 value: this.value || '',
35 cls: 'yinline-editor ' + (this.cls || ''),
36 maxlength: this.maxLength || ''
37 });
38 }else{
39 this.el = this.wrap.createChild({
40 tag: 'textarea',
41 name: this.name || this.id,
42 id: this.id,
43 html: this.value || '',
44 cls: 'yinline-editor yinline-editor-multiline ' + (this.cls || ''),
45 wrap: 'none'
46 });
47 }
48 }else{
49 this.wrap.dom.appendChild(this.el.dom);
50 }
51 this.el.addKeyMap([{
52 key: [10, 13],
53 fn: this.onEnter,
54 scope: this
55 },{
56 key: 27,
57 fn: this.onEsc,
58 scope: this
59 }]);
60 this.el.mon('keyup', this.onKeyUp, this, true);
61 this.el.on('blur', this.onBlur, this, true);
62 this.el.swallowEvent('keydown');
63 this.events = {
64 'startedit' : true,
65 'beforecomplete' : true,
66 'complete' : true
67 };
68 this.editing = false;
69 this.autoSizeTask = new YAHOO.ext.util.DelayedTask(this.autoSize, this);
70};
71
72YAHOO.extendX(YAHOO.ext.InlineEditor, YAHOO.ext.util.Observable, {
73 onEnter : function(k, e){
74 if(this.multiline && (e.ctrlKey || e.shiftKey)){
75 return;
76 }else{
77 this.completeEdit();
78 e.stopEvent();
79 }
80 },
81
82 onEsc : function(){
83 if(this.ignoreNoChange){
84 this.revert(true);
85 }else{
86 this.revert(false);
87 this.completeEdit();
88 }
89 },
90
91 onBlur : function(){
92 if(this.editing && this.completeOnBlur !== false){
93 this.completeEdit();
94 }
95 },
96
97 startEdit : function(el, value){
98 this.boundEl = YAHOO.util.Dom.get(el);
99 if(this.hideEl !== false){
100 this.boundEl.style.visibility = 'hidden';
101 }
102 var v = value || this.boundEl.innerHTML;
103 this.startValue = v;
104 this.setValue(v);
105 this.moveTo(YAHOO.util.Dom.getXY(this.boundEl));
106 this.editing = true;
107 if(YAHOO.ext.QuickTips){
108 YAHOO.ext.QuickTips.disable();
109 }
110 this.show.defer(10, this);
111 },
112
113 onKeyUp : function(e){
114 var k = e.getKey();
115 if(this.editing && (k < 33 || k > 40) && k != 27){
116 this.autoSizeTask.delay(50);
117 }
118 },
119
120 completeEdit : function(){
121 var v = this.getValue();
122 if(this.revertBlank !== false && v.length < 1){
123 v = this.startValue;
124 this.revert();
125 }
126 if(v == this.startValue && this.ignoreNoChange){
127 this.hide();
128 }
129 if(this.fireEvent('beforecomplete', this, v, this.startValue) !== false){
130 if(this.updateEl !== false && this.boundEl){
131 this.boundEl.innerHTML = v;
132 }
133 this.hide();
134 this.fireEvent('complete', this, v, this.startValue);
135 }
136 },
137
138 revert : function(hide){
139 this.setValue(this.startValue);
140 if(hide){
141 this.hide();
142 }
143 },
144
145 show : function(){
146 this.autoSize();
147 this.wrap.show();
148 this.el.focus();
149 if(this.selectOnEdit !== false){
150 this.el.dom.select();
151 }
152 },
153
154 hide : function(){
155 this.editing = false;
156 this.wrap.hide();
157 this.wrap.setLeftTop(-10000,-10000);
158 this.el.blur();
159 if(this.hideEl !== false){
160 this.boundEl.style.visibility = 'visible';
161 }
162 if(YAHOO.ext.QuickTips){
163 YAHOO.ext.QuickTips.enable();
164 }
165 },
166
167 setValue : function(v){
168 this.el.dom.value = v;
169 },
170
171 getValue : function(){
172 return this.el.dom.value;
173 },
174
175 autoSize : function(){
176 var el = this.el;
177 var wrap = this.wrap;
178 var v = el.dom.value;
179 var ts = this.textSizeEl;
180 if(v.length < 1){
181 ts.innerHTML = "&#160;&#160;";
182 }else{
183 v = v.replace(/[<> ]/g, '&#160;');
184 if(this.multiline){
185 v = v.replace(/\n/g, '<br />&#160;');
186 }
187 ts.innerHTML = v;
188 }
189 var ww = wrap.dom.offsetWidth;
190 var wh = wrap.dom.offsetHeight;
191 var w = ts.offsetWidth;
192 var h = ts.offsetHeight;
193 // lots of magic numbers in this block - wtf?
194 // the logic is to prevent the scrollbars from flashing
195 // in firefox. Updates the right element first
196 // so there's never overflow.
197 if(ww > w+4){
198 el.setWidth(w+4);
199 wrap.setWidth(w+8);
200 }else{
201 wrap.setWidth(w+8);
202 el.setWidth(w+4);
203 }
204 if(wh > h+4){
205 el.setHeight(h);
206 wrap.setHeight(h+4);
207 }else{
208 wrap.setHeight(h+4);
209 el.setHeight(h);
210 }
211 },
212
213 moveTo : function(xy){
214 this.wrap.setXY(xy);
215 }
216});
diff --git a/frontend/beta/js/YUI-extensions/widgets/MessageBox.js b/frontend/beta/js/YUI-extensions/widgets/MessageBox.js
new file mode 100644
index 0000000..01b168d
--- a/dev/null
+++ b/frontend/beta/js/YUI-extensions/widgets/MessageBox.js
@@ -0,0 +1,230 @@
1YAHOO.ext.MessageBox = function(){
2 var dlg, opt, mask;
3 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
4 var buttons, activeTextEl, bwidth;
5
6 var handleButton = function(button){
7 if(typeof opt.fn == 'function'){
8 if(opt.fn.call(opt.scope||window, button, activeTextEl.dom.value) !== false){
9 dlg.hide();
10 }
11 }else{
12 dlg.hide();
13 }
14 };
15 var updateButtons = function(b){
16 var width = 0;
17 if(!b){
18 buttons['ok'].hide();
19 buttons['cancel'].hide();
20 buttons['yes'].hide();
21 buttons['no'].hide();
22 return width;
23 }
24 for(var k in buttons){
25 if(typeof buttons[k] != 'function'){
26 if(b[k]){
27 buttons[k].show();
28 buttons[k].setText(typeof b[k] == 'string' ? b[k] : YAHOO.ext.MessageBox.buttonText[k]);
29 width += buttons[k].el.getWidth()+15;
30 }else{
31 buttons[k].hide();
32 }
33 }
34 }
35 return width;
36 };
37
38 return {
39 getDialog : function(){
40 if(!dlg){
41 dlg = new YAHOO.ext.BasicDialog('mb-dlg', {
42 autoCreate : true,
43 shadow: true,
44 draggable: true,
45 resizable:false,
46 constraintoviewport:true,
47 fixedcenter:true,
48 shim:true,
49 modal: true,
50 width:400, height:100,
51 buttonAlign:'center',
52 closeClick : function(){
53 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
54 handleButton('no');
55 }else{
56 handleButton('cancel');
57 }
58 }
59 });
60 dlg.closeClick = function(){
61 alert('wtf');
62 };
63 mask = dlg.mask;
64 dlg.addKeyListener(27, dlg.hide, dlg);
65 buttons = {};
66 buttons['ok'] = dlg.addButton(this.buttonText['ok'], handleButton.createCallback('ok'));
67 buttons['yes'] = dlg.addButton(this.buttonText['yes'], handleButton.createCallback('yes'));
68 buttons['no'] = dlg.addButton(this.buttonText['no'], handleButton.createCallback('no'));
69 buttons['cancel'] = dlg.addButton(this.buttonText['cancel'], handleButton.createCallback('cancel'));
70 bodyEl = dlg.body.createChild({
71 tag:'div',
72 html:'<span class="ext-mb-text"></span><br /><input type="text" class="ext-mb-input"><textarea class="ext-mb-textarea"></textarea><div class="ext-mb-progress-wrap"><div class="ext-mb-progress"><div class="ext-mb-progress-bar">&#160;</div></div></div>'
73 });
74 msgEl = bodyEl.dom.firstChild;
75 textboxEl = getEl(bodyEl.dom.childNodes[2]);
76 textboxEl.enableDisplayMode();
77 textboxEl.addKeyListener([10,13], function(){
78 if(dlg.isVisible() && opt && opt.buttons){
79 if(opt.buttons.ok){
80 handleButton('ok');
81 }else if(opt.buttons.yes){
82 handleButton('yes');
83 }
84 }
85 });
86 textareaEl = getEl(bodyEl.dom.childNodes[3]);
87 textareaEl.enableDisplayMode();
88 progressEl = getEl(bodyEl.dom.childNodes[4]);
89 progressEl.enableDisplayMode();
90 pp = getEl(progressEl.dom.firstChild.firstChild);
91 }
92 return dlg;
93 },
94
95 updateText : function(text){
96 if(!dlg.isVisible() && !opt.width){
97 dlg.resizeTo(this.maxWidth, 100); // resize first so content is never clipped from previous shows
98 }
99 msgEl.innerHTML = text;
100 var w = Math.max(Math.min(opt.width || msgEl.offsetWidth, this.maxWidth),
101 Math.max(opt.minWidth || this.minWidth, bwidth));
102 if(opt.prompt){
103 activeTextEl.setWidth(w);
104 }
105 dlg.setContentSize(w, bodyEl.getHeight());
106 },
107
108 updateProgress : function(value, text){
109 if(text){
110 this.updateText(text);
111 }
112 pp.setWidth(value*progressEl.dom.firstChild.offsetWidth);
113 },
114
115 isVisible : function(){
116 return dlg && dlg.isVisible();
117 },
118
119 hide : function(){
120 if(this.isVisible()){
121 dlg.hide();
122 }
123 },
124
125 show : function(options){
126 var d = this.getDialog();
127 opt = options;
128 d.setTitle(opt.title || '&#160;');
129 d.close.setDisplayed(opt.closable !== false);
130 activeTextEl = textboxEl;
131 opt.prompt = opt.prompt || (opt.multiline ? true : false)
132 if(opt.prompt){
133 if(opt.multiline){
134 textboxEl.hide();
135 textareaEl.show();
136 textareaEl.setHeight(typeof opt.multiline == 'number' ?
137 opt.multiline : this.defaultTextHeight);
138 activeTextEl = textareaEl;
139 }else{
140 textboxEl.show();
141 textareaEl.hide();
142 }
143 }else{
144 textboxEl.hide();
145 textareaEl.hide();
146 }
147 progressEl.setDisplayed(opt.progress === true);
148 this.updateProgress(0);
149 activeTextEl.dom.value = opt.value || '';
150 if(opt.prompt){
151 dlg.setDefaultButton(activeTextEl);
152 }else{
153 var bs = opt.buttons;
154 var db = null;
155 if(bs && bs.ok){
156 db = buttons['ok'];
157 }else if(bs && bs.yes){
158 db = buttons['yes'];
159 }
160 dlg.setDefaultButton(db);
161 }
162 bwidth = updateButtons(opt.buttons);
163 this.updateText(opt.msg);
164 d.modal = opt.modal !== false;
165 d.mask = opt.modal !== false ? mask : false;
166 d.animateTarget = null;
167 d.show(options.animEl);
168 },
169
170 progress : function(title, msg){
171 this.show({
172 title : title,
173 msg : msg,
174 buttons: false,
175 progress:true,
176 closable:false
177 });
178 },
179
180 alert : function(title, msg, fn, scope){
181 this.show({
182 title : title,
183 msg : msg,
184 buttons: this.OK,
185 fn: fn,
186 scope : scope
187 });
188 },
189
190 confirm : function(title, msg, fn, scope){
191 this.show({
192 title : title,
193 msg : msg,
194 buttons: this.YESNO,
195 fn: fn,
196 scope : scope
197 });
198 },
199
200 prompt : function(title, msg, fn, scope, multiline){
201 this.show({
202 title : title,
203 msg : msg,
204 buttons: this.OKCANCEL,
205 fn: fn,
206 minWidth:250,
207 scope : scope,
208 prompt:true,
209 multiline: multiline
210 });
211 },
212
213 OK : {ok:true},
214 YESNO : {yes:true, no:true},
215 OKCANCEL : {ok:true, cancel:true},
216 YESNOCANCEL : {yes:true, no:true, cancel:true},
217
218 defaultTextHeight:75,
219 maxWidth : 500,
220 minWidth : 100,
221 buttonText : {
222 ok : 'OK',
223 cancel : 'Cancel',
224 yes : 'Yes',
225 no : 'No'
226 }
227 };
228}();
229
230YAHOO.ext.Msg = YAHOO.ext.MessageBox;
diff --git a/frontend/beta/js/YUI-extensions/widgets/QuickTips.js b/frontend/beta/js/YUI-extensions/widgets/QuickTips.js
new file mode 100644
index 0000000..6658574
--- a/dev/null
+++ b/frontend/beta/js/YUI-extensions/widgets/QuickTips.js
@@ -0,0 +1,311 @@
1/**
2 * @class YAHOO.ext.QuickTips
3 * @singleton
4 */
5YAHOO.ext.QuickTips = function(){
6 var el, tipBody, tipTitle, tm, cfg, close, tagEls = {}, reader, esc, anim, removeCls = null;
7 var ce, bd, xy;
8 var visible = false, disabled = true, inited = false;
9 var showProc = hideProc = dismissProc = 1, locks = [];
10 var E = YAHOO.util.Event, dd;
11
12 var onOver = function(e){
13 if(disabled){
14 return;
15 }
16 var t = E.getTarget(e);
17 if(!t){
18 return;
19 }
20 if(ce && t == ce.el){
21 clearTimeout(hideProc);
22 return;
23 }
24 if(t && tagEls[t.id]){
25 tagEls[t.id].el = t;
26 showProc = show.defer(tm.showDelay, tm, [tagEls[t.id]]);
27 return;
28 }
29 var ttp = reader.getAttribute(t, cfg.attribute);
30 if(!ttp && tm.interceptTitles && t.title){
31 ttp = t.title;
32 t.title = '';
33 if(reader.useNS){
34 t.setAttributeNS('y', 'qtip', ttp);
35 }else{
36 t.setAttribute('qtip', ttp);
37 }
38 }
39 if(ttp){
40 xy = E.getXY(e);
41 xy[0] += 12; xy[1] += 20;
42 showProc = show.defer(tm.showDelay, tm, [{
43 el: t,
44 text: ttp,
45 width: reader.getAttribute(t, cfg.width),
46 autoHide: reader.getAttribute(t, cfg.hide) != 'user',
47 title: reader.getAttribute(t, cfg.title),
48 cls: reader.getAttribute(t, cfg.cls)
49 }]);
50 }
51 };
52
53 var onOut = function(e){
54 clearTimeout(showProc);
55 var t = E.getTarget(e);
56 if(t && ce && ce.el == t && (tm.autoHide && ce.autoHide !== false)){
57 hideProc = setTimeout(hide, tm.hideDelay);
58 }
59 };
60
61 var onMove = function(e){
62 if(disabled){
63 return;
64 }
65 xy = E.getXY(e);
66 xy[0] += 12; xy[1] += 20;
67 if(tm.trackMouse && ce){
68 el.setXY(xy);
69 }
70 };
71
72 var onDown = function(e){
73 clearTimeout(showProc);
74 clearTimeout(hideProc);
75 if(!e.within(el)){
76 if(tm.hideOnClick && ce && ce.autoHide !== false){
77 hide();
78 tm.disable();
79 }
80 }
81 };
82
83 var onUp = function(e){
84 tm.enable();
85 }
86
87 var show = function(o){
88 if(disabled){
89 return;
90 }
91 clearTimeout(dismissProc);
92 stopAnim();
93 ce = o;
94 if(removeCls){ // in case manually hidden
95 el.removeClass(removeCls);
96 removeCls = null;
97 }
98 if(ce.cls){
99 el.addClass(ce.cls);
100 removeCls = ce.cls;
101 }
102 if(ce.title){
103 tipTitleText.update(ce.title);
104 tipTitle.show();
105 }else{
106 tipTitle.hide();
107 }
108 tipBody.update(o.text);
109 if(!ce.width){
110 if(tipBody.dom.style.width){
111 tipBody.dom.style.width = '';
112 }
113 if(tipBody.dom.offsetWidth > tm.maxWidth){
114 tipBody.setWidth(tm.maxWidth);
115 }
116 }else{
117 tipBody.setWidth(ce.width);
118 }
119 if(!ce.autoHide){
120 close.setDisplayed(true);
121 if(dd){
122 dd.unlock();
123 }
124 }else{
125 close.setDisplayed(false);
126 if(dd){
127 dd.lock();
128 }
129 }
130 if(xy){
131 el.setXY(xy);
132 }
133 if(tm.animate){
134 anim.attributes = {opacity:{to:1}};
135 el.setOpacity(.1);
136 el.setStyle('visibility', 'visible');
137 anim.animateX(afterShow);
138 }else{
139 afterShow();
140 }
141 };
142
143 var afterShow = function(){
144 if(ce){
145 el.show();
146 esc.enable();
147 if(tm.autoDismiss && ce.autoHide !== false){
148 dismissProc = setTimeout(hide, tm.autoDismissDelay);
149 }
150 }
151 }
152
153 var hide = function(noanim){
154 clearTimeout(dismissProc);
155 clearTimeout(hideProc);
156 ce = null;
157 if(el.isVisible()){
158 esc.disable();
159 stopAnim();
160 if(noanim !== true && tm.animate){
161 anim.attributes = {opacity:{to:.1}};
162 el.beforeAction();
163 anim.animateX(afterHide);
164 }else{
165 afterHide();
166 }
167 }
168 };
169
170 var afterHide = function(){
171 el.hide();
172 if(removeCls){
173 el.removeClass(removeCls);
174 removeCls = null;
175 }
176 }
177
178 var stopAnim = function(){
179 if(anim && anim.isAnimated()){
180 anim.stop();
181 }
182 }
183
184 return {
185 init : function(){
186 if(YAHOO.ext.util.Browser.isIE && !YAHOO.ext.util.Browser.isIE7){
187 return;
188 }
189 tm = YAHOO.ext.QuickTips;
190 cfg = tm.tagConfig;
191 reader = new YAHOO.ext.CustomTagReader(cfg.namespace);
192 if(!inited){
193 el = new YAHOO.ext.Layer({cls:'ytip', shadow:true, useDisplay: false});
194 el.update('<div class="ytip-hd-left"><div class="ytip-hd-right"><div class="ytip-hd"></div></div></div>');
195 tipTitle = getEl(el.dom.firstChild);
196 tipTitleText = getEl(el.dom.firstChild.firstChild.firstChild);
197 tipTitle.enableDisplayMode('block');
198 tipBody = el.createChild({tag:'div', cls:'ytip-bd'});
199 close = el.createChild({tag:'div', cls:'ytip-close'});
200 close.on('click', hide);
201 d = getEl(document);
202 d.mon('mousedown', onDown);
203 d.on('mouseup', onUp);
204 d.on('mouseover', onOver);
205 d.on('mouseout', onOut);
206 d.on('mousemove', onMove);
207 esc = d.addKeyListener(27, hide);
208 esc.disable();
209 if(tm.animate){
210 anim = new YAHOO.util.Anim(el.dom, {}, .1);
211 }
212 if(YAHOO.util.DD){
213 dd = el.initDD('default', null, {
214 onDrag : function(){
215 el.sync();
216 }
217 });
218 dd.setHandleElId(tipTitleText.id);
219 dd.lock();
220 }
221 inited = true;
222 }
223 this.scan(document.body);
224 this.enable();
225 },
226
227 tips : function(config){
228 var cs = config instanceof Array ? config : arguments;
229 for(var i = 0, len = cs.length; i < len; i++) {
230 var c = cs[i];
231 var target = c.target;
232 if(target){
233 if(target instanceof Array){
234 for(var j = 0, jlen = target.length; j < jlen; j++){
235 tagEls[target[j]] = c;
236 }
237 }else{
238 tagEls[target] = c;
239 }
240 }
241 }
242 },
243
244 enable : function(){
245 if(inited){
246 locks.pop();
247 if(locks.length < 1){
248 disabled = false;
249 }
250 }
251 },
252
253 disable : function(){
254 disabled = true;
255 clearTimeout(showProc);
256 clearTimeout(hideProc);
257 clearTimeout(dismissProc);
258 if(ce){
259 hide(true);
260 }
261 locks.push(1);
262 },
263
264 scan : function(toScan){
265 toScan = toScan.dom ? toScan.dom : YAHOO.util.Dom.get(toScan);
266 var found = [];
267 reader.eachElement(cfg.tag, toScan, function(el){
268 var t = reader.getAttribute(el, cfg.target);
269 if(t){
270 found.push({
271 target: t.indexOf(',') != -1 ? t.split(',') : t,
272 text: el.innerHTML,
273 autoHide: reader.getAttribute(el, cfg.hide) != 'user',
274 width: reader.getAttribute(el, cfg.width),
275 title: reader.getAttribute(el, cfg.title),
276 cls: reader.getAttribute(el, cfg.cls)
277 });
278 }
279 el.parentNode.removeChild(el);
280 });
281 this.tips(found);
282 },
283
284 tagConfig : {
285 namespace : 'y',
286 tag : 'qtip',
287 attribute : 'qtip',
288 width : 'width',
289 target : 'target',
290 title : 'qtitle',
291 hide : 'hide',
292 cls : 'qclass'
293 },
294
295 maxWidth : 300,
296 interceptTitles : true,
297 trackMouse : false,
298 hideOnClick : true,
299 showDelay : 500,
300 hideDelay : 200,
301 autoHide : true,
302 autoDismiss : true,
303 autoDismissDelay : 5000,
304 /**
305 * True to turn on fade animation. Defaults to true
306 * except in IE7 (ClearType/scrollbar flicker issues in IE7 with filters).
307 * @type Boolean
308 */
309 animate : YAHOO.util.Anim && !YAHOO.ext.util.Browser.isIE7
310 }
311}();
diff --git a/frontend/beta/js/YUI-extensions/widgets/Resizable.js b/frontend/beta/js/YUI-extensions/widgets/Resizable.js
new file mode 100644
index 0000000..6944683
--- a/dev/null
+++ b/frontend/beta/js/YUI-extensions/widgets/Resizable.js
@@ -0,0 +1,586 @@
1/**
2 * @class YAHOO.ext.Resizable
3 * @extends YAHOO.ext.util.Observable
4 * <p>Applies drag handles to an element to make it resizable. The drag handles are inserted into the element
5 * and positioned absolute. Some elements, such as a textarea or image, don't support this. To overcome that, you can wrap
6 * the textarea in a div and set "resizeChild" to true (or the id of the textarea), <b>or</b> set wrap:true in your config and
7 * the element will be wrapped for you automatically.</p><br/>
8 * Here's a Resizable with every possible config option and it's default value:
9<pre><code>
10var resizer = new YAHOO.ext.Resizable('element-id', {
11 resizeChild : false,
12 adjustments : [0, 0],
13 minWidth : 5,
14 minHeight : 5,
15 maxWidth : 10000,
16 maxHeight : 10000,
17 enabled : true,
18 wrap: false, // true to wrap the element
19 width: null, // initial size
20 height: null, // initial size
21 animate : false,
22 duration : .35,
23 dynamic : false,
24 handles : false,
25 multiDirectional : false,
26 disableTrackOver : false,
27 easing : YAHOO.util.Easing ? YAHOO.util.Easing.easeOutStrong : null,
28 widthIncrement : 0,
29 heightIncrement : 0,
30 pinned : false,
31 width : null,
32 height : null,
33 preserveRatio : false,
34 transparent: false,
35 minX: 0,
36 minY: 0,
37 draggable: false
38});
39resizer.on('resize', myHandler);
40</code></pre>
41* <p>
42 * To hide a particular handle, set it's display to none in CSS, or through script:<br>
43 * resizer.east.setDisplayed(false);
44 * </p>
45 * @constructor
46 * Create a new resizable component
47 * @param {String/HTMLElement/YAHOO.ext.Element} el The id or element to resize
48 * @param {Object} config configuration options
49 */
50YAHOO.ext.Resizable = function(el, config){
51 this.el = getEl(el);
52
53 if(config && config.wrap){
54 config.resizeChild = this.el;
55 this.el = this.el.wrap(typeof config.wrap == 'object' ? config.wrap : null);
56 this.el.id = this.el.dom.id = config.resizeChild.id + '-rzwrap';
57 this.el.setStyle('overflow', 'hidden');
58 this.el.setPositioning(config.resizeChild.getPositioning());
59 config.resizeChild.clearPositioning();
60 if(!config.width || !config.height){
61 var csize = config.resizeChild.getSize();
62 //csize.width -= config.adjustments[0];
63 //csize.height -= config.adjustments[1];
64 this.el.setSize(csize.width, csize.height);
65 }
66 if(config.pinned && !config.adjustments){
67 config.adjustments = 'auto';
68 }
69 }
70
71 this.proxy = this.el.createProxy({tag: 'div', cls: 'yresizable-proxy', id: this.el.id + '-rzproxy'})
72 this.proxy.unselectable();
73
74 // the overlay traps mouse events while dragging and fixes iframe issue
75 this.overlay = this.el.createProxy({tag: 'div', cls: 'yresizable-overlay', html: '&#160;'});
76 this.overlay.unselectable();
77 this.overlay.enableDisplayMode('block');
78 this.overlay.mon('mousemove', this.onMouseMove, this, true);
79 this.overlay.mon('mouseup', this.onMouseUp, this, true);
80
81 YAHOO.ext.util.Config.apply(this, config, {
82 /** True to resizeSize the first child or id/element to resize @type YAHOO.ext.Element */
83 resizeChild : false,
84 /** String "auto" or an array [width, height] with values to be <b>added</b> to the resize operation's new size. @type Array/String */
85 adjustments : [0, 0],
86 /** The minimum width for the element @type Number */
87 minWidth : 5,
88 /** The minimum height for the element @type Number */
89 minHeight : 5,
90 /** The maximum width for the element @type Number */
91 maxWidth : 10000,
92 /** The maximum height for the element @type Number */
93 maxHeight : 10000,
94 /** false to disable resizing @type Boolean */
95 enabled : true,
96 /** True to animate the resize (not compatible with dynamic sizing) @type Boolean */
97 animate : false,
98 /** Animation duration @type Float */
99 duration : .35,
100 /** True to resize the element while dragging instead of using a proxy @type Boolean */
101 dynamic : false,
102 // these 3 are only available at config time
103 /** String consisting of the resize handles to display. Valid handles are
104 * n (north), s (south) e (east), w (west), ne (northeast), nw (northwest), se (southeast), sw (southwest)
105 * and all (which applies them all). If this is blank it defaults to "e,s,se". Handles can be delimited using
106 * a space, comma or semi-colon. This is only applied at config time. @type String*/
107 handles : false,
108 multiDirectional : false,
109 /** true to disable mouse tracking. This is only applied at config time. @type Boolean*/
110 disableTrackOver : false,
111 /** Animation easing @type YAHOO.util.Easing */
112 easing : YAHOO.util.Easing ? YAHOO.util.Easing.easeOutStrong : null,
113 /** The increment to snap the width resize in pixels (dynamic must be true) @type Number */
114 widthIncrement : 0,
115 /** The increment to snap the height resize in pixels (dynamic must be true) @type Number */
116 heightIncrement : 0,
117 /** true to pin the resize handles. This is only applied at config time. @type Boolean*/
118 pinned : false,
119 /** The initial width for the element @type Number */
120 width : null,
121 /** The initial height for the element @type Number */
122 height : null,
123 /** true to preserve the initial size ratio. @type Boolean*/
124 preserveRatio : false,
125 /** true for transparent handles. This is only applied at config time. @type Boolean*/
126 transparent: false,
127 /** The minimum allowed page X for the element (only used for west resizing, defaults to 0) @type Number */
128 minX: 0,
129 /** The minimum allowed page Y for the element (only used for north resizing, defaults to 0) @type Number */
130 minY: 0,
131 /** convenience to initialize drag drop. @type Boolean*/
132 draggable: false
133 });
134
135 if(this.pinned){
136 this.disableTrackOver = true;
137 this.el.addClass('yresizable-pinned');
138 }
139 // if the element isn't positioned, make it relative
140 var position = this.el.getStyle('position');
141 if(position != 'absolute' && position != 'fixed'){
142 this.el.setStyle('position', 'relative');
143 }
144 if(!this.handles){ // no handles passed, must be legacy style
145 this.handles = 's,e,se';
146 if(this.multiDirectional){
147 this.handles += ',n,w';
148 }
149 }
150 if(this.handles == 'all'){
151 this.handles = 'n s e w ne nw se sw';
152 }
153 var hs = this.handles.split(/\s*?[,;]\s*?| /);
154 var ps = YAHOO.ext.Resizable.positions;
155 for(var i = 0, len = hs.length; i < len; i++){
156 if(hs[i] && ps[hs[i]]){
157 var pos = ps[hs[i]];
158 this[pos] = new YAHOO.ext.Resizable.Handle(this, pos, this.disableTrackOver, this.transparent);
159 }
160 }
161 // legacy
162 this.corner = this.southeast;
163
164 this.activeHandle = null;
165
166 if(this.resizeChild){
167 if(typeof this.resizeChild == 'boolean'){
168 this.resizeChild = YAHOO.ext.Element.get(this.el.dom.firstChild, true);
169 }else{
170 this.resizeChild = YAHOO.ext.Element.get(this.resizeChild, true);
171 }
172 }
173
174 if(this.adjustments == 'auto'){
175 var rc = this.resizeChild;
176 var hw = this.west, he = this.east, hn = this.north, hs = this.south;
177 if(rc && (hw || hn)){
178 rc.setRelativePositioned();
179 rc.setLeft(hw ? hw.el.getWidth() : 0);
180 rc.setTop(hn ? hn.el.getHeight() : 0);
181 }
182 this.adjustments = [
183 (he ? -he.el.getWidth() : 0) + (hw ? -hw.el.getWidth() : 0),
184 (hn ? -hn.el.getHeight() : 0) + (hs ? -hs.el.getHeight() : 0) -1
185 ];
186 }
187
188 if(this.draggable){
189 this.dd = this.dynamic ?
190 this.el.initDD(null) : this.el.initDDProxy(null, {dragElId: this.proxy.id});
191 this.dd.setHandleElId(this.resizeChild ? this.resizeChild.id : this.el.id);
192 }
193
194 // public events
195 this.events = {
196 /**
197 * @event beforeresize
198 * Fired before resize is allowed. Set enabled to false to cancel resize.
199 * @param {YAHOO.ext.Resizable} this
200 * @param {YAHOO.ext.EventObject} e The mousedown event
201 */
202 'beforeresize' : new YAHOO.util.CustomEvent(),
203 /**
204 * @event resize
205 * Fired after a resize.
206 * @param {YAHOO.ext.Resizable} this
207 * @param {Number} width The new width
208 * @param {Number} height The new height
209 * @param {YAHOO.ext.EventObject} e The mouseup event
210 */
211 'resize' : new YAHOO.util.CustomEvent()
212 };
213
214 if(this.width !== null && this.height !== null){
215 this.resizeTo(this.width, this.height);
216 }else{
217 this.updateChildSize();
218 }
219};
220
221YAHOO.extendX(YAHOO.ext.Resizable, YAHOO.ext.util.Observable, {
222 /**
223 * Perform a manual resize
224 * @param {Number} width
225 * @param {Number} height
226 */
227 resizeTo : function(width, height){
228 this.el.setSize(width, height);
229 this.updateChildSize();
230 this.fireEvent('resize', this, width, height, null);
231 },
232
233 startSizing : function(e){
234 this.fireEvent('beforeresize', this, e);
235 if(this.enabled){ // 2nd enabled check in case disabled before beforeresize handler
236 this.resizing = true;
237 this.startBox = this.el.getBox();
238 this.startPoint = e.getXY();
239 this.offsets = [(this.startBox.x + this.startBox.width) - this.startPoint[0],
240 (this.startBox.y + this.startBox.height) - this.startPoint[1]];
241 this.proxy.setBox(this.startBox);
242
243 this.overlay.setSize(YAHOO.util.Dom.getDocumentWidth(), YAHOO.util.Dom.getDocumentHeight());
244 this.overlay.show();
245
246 if(!this.dynamic){
247 this.proxy.show();
248 }
249 }
250 },
251
252 onMouseDown : function(handle, e){
253 if(this.enabled){
254 e.stopEvent();
255 this.activeHandle = handle;
256 this.overlay.setStyle('cursor', handle.el.getStyle('cursor'));
257 this.startSizing(e);
258 }
259 },
260
261 onMouseUp : function(e){
262 var size = this.resizeElement();
263 this.resizing = false;
264 this.handleOut();
265 this.overlay.hide();
266 this.fireEvent('resize', this, size.width, size.height, e);
267 },
268
269 updateChildSize : function(){
270 if(this.resizeChild){
271 var el = this.el;
272 var child = this.resizeChild;
273 var adj = this.adjustments;
274 if(el.dom.offsetWidth){
275 var b = el.getSize(true);
276 child.setSize(b.width+adj[0], b.height+adj[1]);
277 }
278 // Second call here for IE
279 // The first call enables instant resizing and
280 // the second call corrects scroll bars if they
281 // exist
282 if(YAHOO.ext.util.Browser.isIE){
283 setTimeout(function(){
284 if(el.dom.offsetWidth){
285 var b = el.getSize(true);
286 child.setSize(b.width+adj[0], b.height+adj[1]);
287 }
288 }, 10);
289 }
290 }
291 },
292
293 snap : function(value, inc, min){
294 if(!inc || !value) return value;
295 var newValue = value;
296 var m = value % inc;
297 if(m > 0){
298 if(m > (inc/2)){
299 newValue = value + (inc-m);
300 }else{
301 newValue = value - m;
302 }
303 }
304 return Math.max(min, newValue);
305 },
306
307 resizeElement : function(){
308 var box = this.proxy.getBox();
309 //box.width = this.snap(box.width, this.widthIncrement);
310 //box.height = this.snap(box.height, this.heightIncrement);
311 //if(this.multiDirectional){
312 this.el.setBox(box, false, this.animate, this.duration, null, this.easing);
313 //}else{
314 // this.el.setSize(box.width, box.height, this.animate, this.duration, null, this.easing);
315 //}
316 this.updateChildSize();
317 this.proxy.hide();
318 return box;
319 },
320
321 constrain : function(v, diff, m, mx){
322 if(v - diff < m){
323 diff = v - m;
324 }else if(v - diff > mx){
325 diff = mx - v;
326 }
327 return diff;
328 },
329
330 onMouseMove : function(e){
331 if(this.enabled){
332 try{// try catch so if something goes wrong the user doesn't get hung
333
334 //var curXY = this.startPoint;
335 var curSize = this.curSize || this.startBox;
336 var x = this.startBox.x, y = this.startBox.y;
337 var ox = x, oy = y;
338 var w = curSize.width, h = curSize.height;
339 var ow = w, oh = h;
340 var mw = this.minWidth, mh = this.minHeight;
341 var mxw = this.maxWidth, mxh = this.maxHeight;
342 var wi = this.widthIncrement;
343 var hi = this.heightIncrement;
344
345 var eventXY = e.getXY();
346 var diffX = -(this.startPoint[0] - Math.max(this.minX, eventXY[0]));
347 var diffY = -(this.startPoint[1] - Math.max(this.minY, eventXY[1]));
348
349 var pos = this.activeHandle.position;
350
351 switch(pos){
352 case 'east':
353 w += diffX;
354 w = Math.min(Math.max(mw, w), mxw);
355 break;
356 case 'south':
357 h += diffY;
358 h = Math.min(Math.max(mh, h), mxh);
359 break;
360 case 'southeast':
361 w += diffX;
362 h += diffY;
363 w = Math.min(Math.max(mw, w), mxw);
364 h = Math.min(Math.max(mh, h), mxh);
365 break;
366 case 'north':
367 diffY = this.constrain(h, diffY, mh, mxh);
368 y += diffY;
369 h -= diffY;
370 break;
371 case 'west':
372 diffX = this.constrain(w, diffX, mw, mxw);
373 x += diffX;
374 w -= diffX;
375 break;
376 case 'northeast':
377 w += diffX;
378 w = Math.min(Math.max(mw, w), mxw);
379 diffY = this.constrain(h, diffY, mh, mxh);
380 y += diffY;
381 h -= diffY;
382 break;
383 case 'northwest':
384 diffX = this.constrain(w, diffX, mw, mxw);
385 diffY = this.constrain(h, diffY, mh, mxh);
386 y += diffY;
387 h -= diffY;
388 x += diffX;
389 w -= diffX;
390 break;
391 case 'southwest':
392 diffX = this.constrain(w, diffX, mw, mxw);
393 h += diffY;
394 h = Math.min(Math.max(mh, h), mxh);
395 x += diffX;
396 w -= diffX;
397 break;
398 }
399
400 var sw = this.snap(w, wi, mw);
401 var sh = this.snap(h, hi, mh);
402 if(sw != w || sh != h){
403 switch(pos){
404 case 'northeast':
405 y -= sh - h;
406 break;
407 case 'north':
408 y -= sh - h;
409 break;
410 case 'southwest':
411 x -= sw - w;
412 break;
413 case 'west':
414 x -= sw - w;
415 break;
416 case 'northwest':
417 x -= sw - w;
418 y -= sh - h;
419 break;
420 }
421 w = sw;
422 h = sh;
423 }
424
425 if(this.preserveRatio){
426 switch(pos){
427 case 'southeast':
428 case 'east':
429 h = oh * (w/ow);
430 h = Math.min(Math.max(mh, h), mxh);
431 w = ow * (h/oh);
432 break;
433 case 'south':
434 w = ow * (h/oh);
435 w = Math.min(Math.max(mw, w), mxw);
436 h = oh * (w/ow);
437 break;
438 case 'northeast':
439 w = ow * (h/oh);
440 w = Math.min(Math.max(mw, w), mxw);
441 h = oh * (w/ow);
442 break;
443 case 'north':
444 var tw = w;
445 w = ow * (h/oh);
446 w = Math.min(Math.max(mw, w), mxw);
447 h = oh * (w/ow);
448 x += (tw - w) / 2;
449 break;
450 case 'southwest':
451 h = oh * (w/ow);
452 h = Math.min(Math.max(mh, h), mxh);
453 var tw = w;
454 w = ow * (h/oh);
455 x += tw - w;
456 break;
457 case 'west':
458 var th = h;
459 h = oh * (w/ow);
460 h = Math.min(Math.max(mh, h), mxh);
461 y += (th - h) / 2;
462 var tw = w;
463 w = ow * (h/oh);
464 x += tw - w;
465 break;
466 case 'northwest':
467 var tw = w;
468 var th = h;
469 h = oh * (w/ow);
470 h = Math.min(Math.max(mh, h), mxh);
471 w = ow * (h/oh);
472 y += th - h;
473 x += tw - w;
474 break;
475
476 }
477 }
478 this.proxy.setBounds(x, y, w, h);
479 if(this.dynamic){
480 this.resizeElement();
481 }
482 }catch(e){}
483 }
484 },
485
486 handleOver : function(){
487 if(this.enabled){
488 this.el.addClass('yresizable-over');
489 }
490 },
491
492 handleOut : function(){
493 if(!this.resizing){
494 this.el.removeClass('yresizable-over');
495 }
496 },
497
498 /**
499 * Returns the element this component is bound to.
500 * @return {YAHOO.ext.Element}
501 */
502 getEl : function(){
503 return this.el;
504 },
505
506 /**
507 * Returns the resizeChild element (or null).
508 * @return {YAHOO.ext.Element}
509 */
510 getResizeChild : function(){
511 return this.resizeChild;
512 },
513
514 /**
515 * Destroys this resizable. If the element was wrapped and
516 * removeEl is not true then the wrap remains.
517 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
518 */
519 destroy : function(removeEl){
520 this.proxy.remove();
521 this.overlay.removeAllListeners();
522 this.overlay.remove();
523 var ps = YAHOO.ext.Resizable.positions;
524 for(var k in ps){
525 if(typeof ps[k] != 'function' && this[ps[k]]){
526 var h = this[ps[k]];
527 h.el.removeAllListeners();
528 h.el.remove();
529 }
530 }
531 if(removeEl){
532 this.el.update('');
533 this.el.remove();
534 }
535 }
536});
537
538// hash to map config positions to true positions
539YAHOO.ext.Resizable.positions = {
540 n: 'north', s: 'south', e: 'east', w: 'west', se: 'southeast', sw: 'southwest', nw: 'northwest', ne: 'northeast'
541};
542
543
544YAHOO.ext.Resizable.Handle = function(rz, pos, disableTrackOver, transparent){
545 if(!this.tpl){
546 // only initialize the template if resizable is used
547 var tpl = YAHOO.ext.DomHelper.createTemplate(
548 {tag: 'div', cls: 'yresizable-handle yresizable-handle-{0}', html: '&#160;'}
549 );
550 tpl.compile();
551 YAHOO.ext.Resizable.Handle.prototype.tpl = tpl;
552 }
553 this.position = pos;
554 this.rz = rz;
555 this.el = this.tpl.append(rz.el.dom, [this.position], true);
556 this.el.unselectable();
557 if(transparent){
558 this.el.setOpacity(0);
559 }
560 this.el.mon('mousedown', this.onMouseDown, this, true);
561 if(!disableTrackOver){
562 this.el.mon('mouseover', this.onMouseOver, this, true);
563 this.el.mon('mouseout', this.onMouseOut, this, true);
564 }
565};
566
567YAHOO.ext.Resizable.Handle.prototype = {
568 afterResize : function(rz){
569 // do nothing
570 },
571
572 onMouseDown : function(e){
573 this.rz.onMouseDown(this, e);
574 },
575
576 onMouseOver : function(e){
577 this.rz.handleOver(this, e);
578 },
579
580 onMouseOut : function(e){
581 this.rz.handleOut(this, e);
582 }
583};
584
585
586
diff --git a/frontend/beta/js/YUI-extensions/widgets/SplitBar.js b/frontend/beta/js/YUI-extensions/widgets/SplitBar.js
new file mode 100644
index 0000000..855d138
--- a/dev/null
+++ b/frontend/beta/js/YUI-extensions/widgets/SplitBar.js
@@ -0,0 +1,468 @@
1/*
2 * splitbar.js, version .7
3 * Copyright(c) 2006, Jack Slocum.
4 * Code licensed under the BSD License
5 */
6if(YAHOO.util.DragDropMgr){
7 YAHOO.util.DragDropMgr.clickTimeThresh = 350;
8}
9/**
10 * @class YAHOO.ext.SplitBar
11 * @extends YAHOO.ext.util.Observable
12 * Creates draggable splitter bar functionality from two elements.
13 * <br><br>
14 * Usage:
15 * <pre><code>
16var split = new YAHOO.ext.SplitBar('elementToDrag', 'elementToSize',
17 YAHOO.ext.SplitBar.HORIZONTAL, YAHOO.ext.SplitBar.LEFT);
18split.setAdapter(new YAHOO.ext.SplitBar.AbsoluteLayoutAdapter("container"));
19split.minSize = 100;
20split.maxSize = 600;
21split.animate = true;
22split.onMoved.subscribe(splitterMoved);
23</code></pre>
24 * @requires YAHOO.ext.Element
25 * @requires YAHOO.util.Dom
26 * @requires YAHOO.util.Event
27 * @requires YAHOO.util.CustomEvent
28 * @requires YAHOO.util.DDProxy
29 * @requires YAHOO.util.Anim (optional) to support animation
30 * @requires YAHOO.util.Easing (optional) to support animation
31 * @constructor
32 * Create a new SplitBar
33 * @param {String/HTMLElement/Element} dragElement The element to be dragged and act as the SplitBar.
34 * @param {String/HTMLElement/Element} resizingElement The element to be resized based on where the SplitBar element is dragged
35 * @param {Number} orientation (optional) Either YAHOO.ext.SplitBar.HORIZONTAL or YAHOO.ext.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
36 * @param {Number} placement (optional) Either YAHOO.ext.SplitBar.LEFT or YAHOO.ext.SplitBar.RIGHT for horizontal or
37 YAHOO.ext.SplitBar.TOP or YAHOO.ext.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the intial position
38 position of the SplitBar).
39 */
40YAHOO.ext.SplitBar = function(dragElement, resizingElement, orientation, placement, existingProxy){
41
42 /** @private */
43 this.el = YAHOO.ext.Element.get(dragElement, true);
44 this.el.dom.unselectable = 'on';
45 /** @private */
46 this.resizingEl = YAHOO.ext.Element.get(resizingElement, true);
47
48 /**
49 * @private
50 * The orientation of the split. Either YAHOO.ext.SplitBar.HORIZONTAL or YAHOO.ext.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
51 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
52 * @type Number
53 */
54 this.orientation = orientation || YAHOO.ext.SplitBar.HORIZONTAL;
55
56 /**
57 * The minimum size of the resizing element. (Defaults to 0)
58 * @type Number
59 */
60 this.minSize = 0;
61
62 /**
63 * The maximum size of the resizing element. (Defaults to 2000)
64 * @type Number
65 */
66 this.maxSize = 2000;
67
68 this.onMoved = new YAHOO.util.CustomEvent("SplitBarMoved", this);
69
70 /**
71 * Whether to animate the transition to the new size
72 * @type Boolean
73 */
74 this.animate = false;
75
76 /**
77 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
78 * @type Boolean
79 */
80 this.useShim = false;
81
82 /** @private */
83 this.shim = null;
84
85 if(!existingProxy){
86 /** @private */
87 this.proxy = YAHOO.ext.SplitBar.createProxy(this.orientation);
88 }else{
89 this.proxy = getEl(existingProxy).dom;
90 }
91 /** @private */
92 this.dd = new YAHOO.util.DDProxy(this.el.dom.id, "SplitBars", {dragElId : this.proxy.id});
93
94 /** @private */
95 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
96
97 /** @private */
98 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
99
100 /** @private */
101 this.dragSpecs = {};
102
103 /**
104 * @private The adapter to use to positon and resize elements
105 */
106 this.adapter = new YAHOO.ext.SplitBar.BasicLayoutAdapter();
107 this.adapter.init(this);
108
109 if(this.orientation == YAHOO.ext.SplitBar.HORIZONTAL){
110 /** @private */
111 this.placement = placement || (this.el.getX() > this.resizingEl.getX() ? YAHOO.ext.SplitBar.LEFT : YAHOO.ext.SplitBar.RIGHT);
112 this.el.setStyle('cursor', 'e-resize');
113 }else{
114 /** @private */
115 this.placement = placement || (this.el.getY() > this.resizingEl.getY() ? YAHOO.ext.SplitBar.TOP : YAHOO.ext.SplitBar.BOTTOM);
116 this.el.setStyle('cursor', 'n-resize');
117 }
118
119 this.events = {
120 /**
121 * @event resize
122 * Fires when the splitter is moved (alias for moved)
123 * @param {YAHOO.ext.SplitBar} this
124 * @param {Number} newSize the new width or height
125 */
126 'resize' : this.onMoved,
127 /**
128 * @event moved
129 * Fires when the splitter is moved
130 * @param {YAHOO.ext.SplitBar} this
131 * @param {Number} newSize the new width or height
132 */
133 'moved' : this.onMoved,
134 /**
135 * @event beforeresize
136 * Fires before the splitter is dragged
137 * @param {YAHOO.ext.SplitBar} this
138 */
139 'beforeresize' : new YAHOO.util.CustomEvent('beforeresize')
140 }
141}
142
143YAHOO.extendX(YAHOO.ext.SplitBar, YAHOO.ext.util.Observable, {
144 onStartProxyDrag : function(x, y){
145 this.fireEvent('beforeresize', this);
146 if(this.useShim){
147 if(!this.shim){
148 this.shim = YAHOO.ext.SplitBar.createShim();
149 }
150 this.shim.setVisible(true);
151 }
152 YAHOO.util.Dom.setStyle(this.proxy, 'display', 'block');
153 var size = this.adapter.getElementSize(this);
154 this.activeMinSize = this.getMinimumSize();;
155 this.activeMaxSize = this.getMaximumSize();;
156 var c1 = size - this.activeMinSize;
157 var c2 = Math.max(this.activeMaxSize - size, 0);
158 if(this.orientation == YAHOO.ext.SplitBar.HORIZONTAL){
159 this.dd.resetConstraints();
160 this.dd.setXConstraint(
161 this.placement == YAHOO.ext.SplitBar.LEFT ? c1 : c2,
162 this.placement == YAHOO.ext.SplitBar.LEFT ? c2 : c1
163 );
164 this.dd.setYConstraint(0, 0);
165 }else{
166 this.dd.resetConstraints();
167 this.dd.setXConstraint(0, 0);
168 this.dd.setYConstraint(
169 this.placement == YAHOO.ext.SplitBar.TOP ? c1 : c2,
170 this.placement == YAHOO.ext.SplitBar.TOP ? c2 : c1
171 );
172 }
173 this.dragSpecs.startSize = size;
174 this.dragSpecs.startPoint = [x, y];
175
176 YAHOO.util.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
177 },
178
179 /**
180 * @private Called after the drag operation by the DDProxy
181 */
182 onEndProxyDrag : function(e){
183 YAHOO.util.Dom.setStyle(this.proxy, 'display', 'none');
184 var endPoint = YAHOO.util.Event.getXY(e);
185 if(this.useShim){
186 this.shim.setVisible(false);
187 }
188 var newSize;
189 if(this.orientation == YAHOO.ext.SplitBar.HORIZONTAL){
190 newSize = this.dragSpecs.startSize +
191 (this.placement == YAHOO.ext.SplitBar.LEFT ?
192 endPoint[0] - this.dragSpecs.startPoint[0] :
193 this.dragSpecs.startPoint[0] - endPoint[0]
194 );
195 }else{
196 newSize = this.dragSpecs.startSize +
197 (this.placement == YAHOO.ext.SplitBar.TOP ?
198 endPoint[1] - this.dragSpecs.startPoint[1] :
199 this.dragSpecs.startPoint[1] - endPoint[1]
200 );
201 }
202 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
203 if(newSize != this.dragSpecs.startSize){
204 this.adapter.setElementSize(this, newSize);
205 this.onMoved.fireDirect(this, newSize);
206 }
207 },
208
209 /**
210 * Get the adapter this SplitBar uses
211 * @return The adapter object
212 */
213 getAdapter : function(){
214 return this.adapter;
215 },
216
217 /**
218 * Set the adapter this SplitBar uses
219 * @param {Object} adapter A SplitBar adapter object
220 */
221 setAdapter : function(adapter){
222 this.adapter = adapter;
223 this.adapter.init(this);
224 },
225
226 /**
227 * Gets the minimum size for the resizing element
228 * @return {Number} The minimum size
229 */
230 getMinimumSize : function(){
231 return this.minSize;
232 },
233
234 /**
235 * Sets the minimum size for the resizing element
236 * @param {Number} minSize The minimum size
237 */
238 setMinimumSize : function(minSize){
239 this.minSize = minSize;
240 },
241
242 /**
243 * Gets the maximum size for the resizing element
244 * @return {Number} The maximum size
245 */
246 getMaximumSize : function(){
247 return this.maxSize;
248 },
249
250 /**
251 * Sets the maximum size for the resizing element
252 * @param {Number} maxSize The maximum size
253 */
254 setMaximumSize : function(maxSize){
255 this.maxSize = maxSize;
256 },
257
258 /**
259 * Sets the initialize size for the resizing element
260 * @param {Number} size The initial size
261 */
262 setCurrentSize : function(size){
263 var oldAnimate = this.animate;
264 this.animate = false;
265 this.adapter.setElementSize(this, size);
266 this.animate = oldAnimate;
267 },
268
269 /**
270 * Destroy this splitbar.
271 * @param {Boolean} removeEl True to remove the element
272 */
273 destroy : function(removeEl){
274 if(this.shim){
275 this.shim.remove();
276 }
277 this.dd.unreg();
278 this.proxy.parentNode.removeChild(this.proxy);
279 if(removeEl){
280 this.el.remove();
281 }
282 }
283});
284
285/**
286 * @private static Create the shim to drag over iframes
287 */
288YAHOO.ext.SplitBar.createShim = function(){
289 var shim = document.createElement('div');
290 shim.unselectable = 'on';
291 YAHOO.util.Dom.generateId(shim, 'split-shim');
292 YAHOO.util.Dom.setStyle(shim, 'width', '100%');
293 YAHOO.util.Dom.setStyle(shim, 'height', '100%');
294 YAHOO.util.Dom.setStyle(shim, 'position', 'absolute');
295 YAHOO.util.Dom.setStyle(shim, 'background', 'white');
296 YAHOO.util.Dom.setStyle(shim, 'z-index', 11000);
297 window.document.body.appendChild(shim);
298 var shimEl = YAHOO.ext.Element.get(shim);
299 shimEl.setOpacity(.01);
300 shimEl.setXY([0, 0]);
301 return shimEl;
302};
303
304/**
305 * @private static Create our own proxy element element. So it will be the same same size on all browsers, we won't use borders. Instead we use a background color.
306 */
307YAHOO.ext.SplitBar.createProxy = function(orientation){
308 var proxy = document.createElement('div');
309 proxy.unselectable = 'on';
310 YAHOO.util.Dom.generateId(proxy, 'split-proxy');
311 YAHOO.util.Dom.setStyle(proxy, 'position', 'absolute');
312 YAHOO.util.Dom.setStyle(proxy, 'visibility', 'hidden');
313 YAHOO.util.Dom.setStyle(proxy, 'z-index', 11001);
314 YAHOO.util.Dom.setStyle(proxy, 'background-color', "#aaa");
315 if(orientation == YAHOO.ext.SplitBar.HORIZONTAL){
316 YAHOO.util.Dom.setStyle(proxy, 'cursor', 'e-resize');
317 }else{
318 YAHOO.util.Dom.setStyle(proxy, 'cursor', 'n-resize');
319 }
320 // the next 2 fix IE abs position div height problem
321 YAHOO.util.Dom.setStyle(proxy, 'line-height', '0px');
322 YAHOO.util.Dom.setStyle(proxy, 'font-size', '0px');
323 window.document.body.appendChild(proxy);
324 return proxy;
325};
326
327/**
328 * @class YAHOO.ext.SplitBar.BasicLayoutAdapter
329 * Default Adapter. It assumes the splitter and resizing element are not positioned
330 * elements and only gets/sets the width of the element. Generally used for table based layouts.
331 */
332YAHOO.ext.SplitBar.BasicLayoutAdapter = function(){
333};
334
335YAHOO.ext.SplitBar.BasicLayoutAdapter.prototype = {
336 // do nothing for now
337 init : function(s){
338
339 },
340 /**
341 * Called before drag operations to get the current size of the resizing element.
342 * @param {YAHOO.ext.SplitBar} s The SplitBar using this adapter
343 */
344 getElementSize : function(s){
345 if(s.orientation == YAHOO.ext.SplitBar.HORIZONTAL){
346 return s.resizingEl.getWidth();
347 }else{
348 return s.resizingEl.getHeight();
349 }
350 },
351
352 /**
353 * Called after drag operations to set the size of the resizing element.
354 * @param {YAHOO.ext.SplitBar} s The SplitBar using this adapter
355 * @param {Number} newSize The new size to set
356 * @param {Function} onComplete A function to be invoke when resizing is complete
357 */
358 setElementSize : function(s, newSize, onComplete){
359 if(s.orientation == YAHOO.ext.SplitBar.HORIZONTAL){
360 if(!YAHOO.util.Anim || !s.animate){
361 s.resizingEl.setWidth(newSize);
362 if(onComplete){
363 onComplete(s, newSize);
364 }
365 }else{
366 s.resizingEl.setWidth(newSize, true, .1, onComplete, YAHOO.util.Easing.easeOut);
367 }
368 }else{
369
370 if(!YAHOO.util.Anim || !s.animate){
371 s.resizingEl.setHeight(newSize);
372 if(onComplete){
373 onComplete(s, newSize);
374 }
375 }else{
376 s.resizingEl.setHeight(newSize, true, .1, onComplete, YAHOO.util.Easing.easeOut);
377 }
378 }
379 }
380};
381
382/**
383 *@class YAHOO.ext.SplitBar.AbsoluteLayoutAdapter
384 * @extends YAHOO.ext.SplitBar.BasicLayoutAdapter
385 * Adapter that moves the splitter element to align with the resized sizing element.
386 * Used with an absolute positioned SplitBar.
387 * @param {String/HTMLElement/Element} container The container that wraps around the absolute positioned content. If it's
388 * document.body, make sure you assign an id to the body element.
389 */
390YAHOO.ext.SplitBar.AbsoluteLayoutAdapter = function(container){
391 this.basic = new YAHOO.ext.SplitBar.BasicLayoutAdapter();
392 this.container = getEl(container);
393}
394
395YAHOO.ext.SplitBar.AbsoluteLayoutAdapter.prototype = {
396 init : function(s){
397 this.basic.init(s);
398 //YAHOO.util.Event.on(window, 'resize', this.moveSplitter.createDelegate(this, [s]));
399 },
400
401 getElementSize : function(s){
402 return this.basic.getElementSize(s);
403 },
404
405 setElementSize : function(s, newSize, onComplete){
406 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
407 },
408
409 moveSplitter : function(s){
410 var yes = YAHOO.ext.SplitBar;
411 switch(s.placement){
412 case yes.LEFT:
413 s.el.setX(s.resizingEl.getRight());
414 break;
415 case yes.RIGHT:
416 s.el.setStyle('right', (this.container.getWidth() - s.resizingEl.getLeft()) + 'px');
417 break;
418 case yes.TOP:
419 s.el.setY(s.resizingEl.getBottom());
420 break;
421 case yes.BOTTOM:
422 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
423 break;
424 }
425 }
426};
427
428/**
429 * Orientation constant - Create a vertical SplitBar
430 * @static
431 * @type Number
432 */
433YAHOO.ext.SplitBar.VERTICAL = 1;
434
435/**
436 * Orientation constant - Create a horizontal SplitBar
437 * @static
438 * @type Number
439 */
440YAHOO.ext.SplitBar.HORIZONTAL = 2;
441
442/**
443 * Placement constant - The resizing element is to the left of the splitter element
444 * @static
445 * @type Number
446 */
447YAHOO.ext.SplitBar.LEFT = 1;
448
449/**
450 * Placement constant - The resizing element is to the right of the splitter element
451 * @static
452 * @type Number
453 */
454YAHOO.ext.SplitBar.RIGHT = 2;
455
456/**
457 * Placement constant - The resizing element is positioned above the splitter element
458 * @static
459 * @type Number
460 */
461YAHOO.ext.SplitBar.TOP = 3;
462
463/**
464 * Placement constant - The resizing element is positioned under splitter element
465 * @static
466 * @type Number
467 */
468YAHOO.ext.SplitBar.BOTTOM = 4;
diff --git a/frontend/beta/js/YUI-extensions/widgets/TabPanel.js b/frontend/beta/js/YUI-extensions/widgets/TabPanel.js
new file mode 100644
index 0000000..25fd142
--- a/dev/null
+++ b/frontend/beta/js/YUI-extensions/widgets/TabPanel.js
@@ -0,0 +1,756 @@
1/**
2 * @class YAHOO.ext.TabPanel
3 * @extends YAHOO.ext.util.Observable
4 * Creates a lightweight TabPanel component using Yahoo! UI.
5 * <br><br>
6 * Usage:
7 * <pre><code>
8 <font color="#008000">// basic tabs 1, built from existing content</font>
9 var tabs = new YAHOO.ext.TabPanel('tabs1');
10 tabs.addTab('script', "View Script");
11 tabs.addTab('markup', "View Markup");
12 tabs.activate('script');
13
14 <font color="#008000">// more advanced tabs, built from javascript</font>
15 var jtabs = new YAHOO.ext.TabPanel('jtabs');
16 jtabs.addTab('jtabs-1', "Normal Tab", "My content was added during construction.");
17
18 <font color="#008000">// set up the UpdateManager</font>
19 var tab2 = jtabs.addTab('jtabs-2', "Ajax Tab 1");
20 var updater = tab2.getUpdateManager();
21 updater.setDefaultUrl('ajax1.htm');
22 tab2.onActivate.subscribe(updater.refresh, updater, true);
23
24 <font color="#008000">// Use setUrl for Ajax loading</font>
25 var tab3 = jtabs.addTab('jtabs-3', "Ajax Tab 2");
26 tab3.setUrl('ajax2.htm', null, true);
27
28 <font color="#008000">// Disabled tab</font>
29 var tab4 = jtabs.addTab('tabs1-5', "Disabled Tab", "Can't see me cause I'm disabled");
30 tab4.disable();
31
32 jtabs.activate('jtabs-1');
33}
34 * </code></pre>
35 * @requires YAHOO.ext.Element
36 * @requires YAHOO.ext.UpdateManager
37 * @requires YAHOO.util.Dom
38 * @requires YAHOO.util.Event
39 * @requires YAHOO.util.CustomEvent
40 * @requires YAHOO.util.Connect (optional)
41 * @constructor
42 * Create new TabPanel.
43 * @param {String/HTMLElement/Element} container The id, DOM element or YAHOO.ext.Element container where this TabPanel is to be rendered.
44 * @param {Boolean} config Config object to set any properties for this TabPanel or true to render the tabs on the bottom.
45 */
46YAHOO.ext.TabPanel = function(container, config){
47 /**
48 * The container element for this TabPanel.
49 * @type YAHOO.ext.Element
50 */
51 this.el = getEl(container, true);
52 /** The position of the tabs. Can be 'top' or 'bottom' @type String */
53 this.tabPosition = 'top';
54 this.currentTabWidth = 0;
55 /** The minimum width of a tab (ignored if resizeTabs is not true). @type Number */
56 this.minTabWidth = 40;
57 /** The maximum width of a tab (ignored if resizeTabs is not true). @type Number */
58 this.maxTabWidth = 250;
59 /** The preferred (default) width of a tab (ignored if resizeTabs is not true). @type Number */
60 this.preferredTabWidth = 175;
61 /** Set this to true to enable dynamic tab resizing. @type Boolean */
62 this.resizeTabs = false;
63 /** Set this to true to turn on window resizing monitoring (ignored if resizeTabs is not true). @type Boolean */
64 this.monitorResize = true;
65
66 if(config){
67 if(typeof config == 'boolean'){
68 this.tabPosition = config ? 'bottom' : 'top';
69 }else{
70 YAHOO.ext.util.Config.apply(this, config);
71 }
72 }
73 if(this.tabPosition == 'bottom'){
74 this.bodyEl = getEl(this.createBody(this.el.dom));
75 this.el.addClass('ytabs-bottom');
76 }
77 this.stripWrap = getEl(this.createStrip(this.el.dom), true);
78 this.stripEl = getEl(this.createStripList(this.stripWrap.dom), true);
79 this.stripBody = getEl(this.stripWrap.dom.firstChild.firstChild, true);
80 if(YAHOO.ext.util.Browser.isIE){
81 YAHOO.util.Dom.setStyle(this.stripWrap.dom.firstChild, 'overflow-x', 'hidden');
82 }
83 if(this.tabPosition != 'bottom'){
84 /** The body element that contains TabPaneItem bodies.
85 * @type YAHOO.ext.Element
86 */
87 this.bodyEl = getEl(this.createBody(this.el.dom));
88 this.el.addClass('ytabs-top');
89 }
90 this.items = [];
91
92 this.bodyEl.setStyle('position', 'relative');
93
94 // add indexOf to array if it isn't present
95 if(!this.items.indexOf){
96 this.items.indexOf = function(o){
97 for(var i = 0, len = this.length; i < len; i++){
98 if(this[i] == o) return i;
99 }
100 return -1;
101 }
102 }
103 this.active = null;
104 this.onTabChange = new YAHOO.util.CustomEvent('TabItem.onTabChange');
105 this.activateDelegate = this.activate.createDelegate(this);
106
107 this.events = {
108 /**
109 * @event tabchange
110 * Fires when the active tab changes
111 * @param {YAHOO.ext.TabPanel} this
112 * @param {YAHOO.ext.TabPanelItem} activePanel The new active tab
113 */
114 'tabchange': this.onTabChange,
115 /**
116 * @event beforetabchange
117 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
118 * @param {YAHOO.ext.TabPanel} this
119 * @param {Object} e Set cancel to true on this object to cancel the tab change
120 * @param {YAHOO.ext.TabPanelItem} tab The tab being changed to
121 */
122 'beforetabchange' : new YAHOO.util.CustomEvent('beforechange')
123 };
124
125 YAHOO.ext.EventManager.onWindowResize(this.onResize, this, true);
126 this.cpad = this.el.getPadding('lr');
127 this.hiddenCount = 0;
128}
129
130YAHOO.ext.TabPanel.prototype = {
131 fireEvent : YAHOO.ext.util.Observable.prototype.fireEvent,
132 on : YAHOO.ext.util.Observable.prototype.on,
133 addListener : YAHOO.ext.util.Observable.prototype.addListener,
134 delayedListener : YAHOO.ext.util.Observable.prototype.delayedListener,
135 removeListener : YAHOO.ext.util.Observable.prototype.removeListener,
136 purgeListeners : YAHOO.ext.util.Observable.prototype.purgeListeners,
137 /**
138 * Creates a new TabPanelItem by looking for an existing element with the provided id - if it's not found it creates one.
139 * @param {String} id The id of the div to use <b>or create</b>
140 * @param {String} text The text for the tab
141 * @param {<i>String</i>} content (optional) Content to put in the TabPanelItem body
142 * @param {<i>Boolean</i>} closable (optional) True to create a close icon on the tab
143 * @return {YAHOO.ext.TabPanelItem} The created TabPanelItem
144 */
145 addTab : function(id, text, content, closable){
146 var item = new YAHOO.ext.TabPanelItem(this, id, text, closable);
147 this.addTabItem(item);
148 if(content){
149 item.setContent(content);
150 }
151 return item;
152 },
153
154 /**
155 * Returns the TabPanelItem with the specified id/index
156 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
157 * @return {YAHOO.ext.TabPanelItem}
158 */
159 getTab : function(id){
160 return this.items[id];
161 },
162
163 /**
164 * Hides the TabPanelItem with the specified id/index
165 * @param {String/Number} id The id or index of the TabPanelItem to hide.
166 */
167 hideTab : function(id){
168 var t = this.items[id];
169 if(!t.isHidden()){
170 t.setHidden(true);
171 this.hiddenCount++;
172 this.autoSizeTabs();
173 }
174 },
175
176 /**
177 * "Unhides" the TabPanelItem with the specified id/index
178 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
179 */
180 unhideTab : function(id){
181 var t = this.items[id];
182 if(t.isHidden()){
183 t.setHidden(false);
184 this.hiddenCount--;
185 this.autoSizeTabs();
186 }
187 },
188
189 /**
190 * Add an existing TabPanelItem.
191 * @param {YAHOO.ext.TabPanelItem} item The TabPanelItem to add
192 */
193 addTabItem : function(item){
194 this.items[item.id] = item;
195 this.items.push(item);
196 if(this.resizeTabs){
197 item.setWidth(this.currentTabWidth || this.preferredTabWidth)
198 this.autoSizeTabs();
199 }else{
200 item.autoSize();
201 }
202 },
203
204 /**
205 * Remove a TabPanelItem.
206 * @param {String/Number} id The id or index of the TabPanelItem to remove.
207 */
208 removeTab : function(id){
209 var items = this.items;
210 var tab = items[id];
211 if(!tab) return;
212 var index = items.indexOf(tab);
213 if(this.active == tab && items.length > 1){
214 var newTab = this.getNextAvailable(index);
215 if(newTab)newTab.activate();
216 }
217 this.stripEl.dom.removeChild(tab.pnode.dom);
218 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
219 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
220 }
221 items.splice(index, 1);
222 delete this.items[tab.id];
223 tab.fireEvent('close', tab);
224 tab.purgeListeners();
225 this.autoSizeTabs();
226 },
227
228 getNextAvailable : function(start){
229 var items = this.items;
230 var index = start;
231 // look for a next tab that will slide over to
232 // replace the one being removed
233 while(index < items.length){
234 var item = items[++index];
235 if(item && !item.isHidden()){
236 return item;
237 }
238 }
239 // if one isn't found select the previous tab (on the left)
240 var index = start;
241 while(index >= 0){
242 var item = items[--index];
243 if(item && !item.isHidden()){
244 return item;
245 }
246 }
247 return null;
248 },
249
250 /**
251 * Disable a TabPanelItem. <b>It cannot be the active tab, if it is this call is ignored.</b>.
252 * @param {String/Number} id The id or index of the TabPanelItem to disable.
253 */
254 disableTab : function(id){
255 var tab = this.items[id];
256 if(tab && this.active != tab){
257 tab.disable();
258 }
259 },
260
261 /**
262 * Enable a TabPanelItem that is disabled.
263 * @param {String/Number} id The id or index of the TabPanelItem to enable.
264 */
265 enableTab : function(id){
266 var tab = this.items[id];
267 tab.enable();
268 },
269
270 /**
271 * Activate a TabPanelItem. The currently active will be deactivated.
272 * @param {String/Number} id The id or index of the TabPanelItem to activate.
273 */
274 activate : function(id){
275 var tab = this.items[id];
276 if(tab == this.active){
277 return tab;
278 }
279 var e = {};
280 this.fireEvent('beforetabchange', this, e, tab);
281 if(e.cancel !== true && !tab.disabled){
282 if(this.active){
283 this.active.hide();
284 }
285 this.active = this.items[id];
286 this.active.show();
287 this.onTabChange.fireDirect(this, this.active);
288 }
289 return tab;
290 },
291
292 /**
293 * Get the active TabPanelItem
294 * @return {YAHOO.ext.TabPanelItem} The active TabPanelItem or null if none are active.
295 */
296 getActiveTab : function(){
297 return this.active;
298 },
299
300 /**
301 * Updates the tab body element to fit the height of the container element
302 * for overflow scrolling
303 * @param {Number} targetHeight (optional) Override the starting height from the elements height
304 */
305 syncHeight : function(targetHeight){
306 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth('tb')-this.el.getPadding('tb');
307 var bm = this.bodyEl.getMargins();
308 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
309 this.bodyEl.setHeight(newHeight);
310 return newHeight;
311 },
312
313 onResize : function(){
314 if(this.monitorResize){
315 this.autoSizeTabs();
316 }
317 },
318
319 /**
320 * Disables tab resizing while tabs are being added (if resizeTabs is false this does nothing)
321 */
322 beginUpdate : function(){
323 this.updating = true;
324 },
325
326 /**
327 * Stops an update and resizes the tabs (if resizeTabs is false this does nothing)
328 */
329 endUpdate : function(){
330 this.updating = false;
331 this.autoSizeTabs();
332 },
333
334 /**
335 * Manual call to resize the tabs (if resizeTabs is false this does nothing)
336 */
337 autoSizeTabs : function(){
338 var count = this.items.length;
339 var vcount = count - this.hiddenCount;
340 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) return;
341 var w = Math.max(this.el.getWidth() - this.cpad, 10);
342 var availWidth = Math.floor(w / vcount);
343 var b = this.stripBody;
344 if(b.getWidth() > w){
345 var tabs = this.items;
346 this.setTabWidth(Math.max(availWidth, this.minTabWidth));
347 if(availWidth < this.minTabWidth){
348 /*if(!this.sleft){ // incomplete scrolling code
349 this.createScrollButtons();
350 }
351 this.showScroll();
352 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
353 }
354 }else{
355 if(this.currentTabWidth < this.preferredTabWidth){
356 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth));
357 }
358 }
359 },
360
361 /**
362 * Returns the number of tabs
363 * @return {Number}
364 */
365 getCount : function(){
366 return this.items.length;
367 },
368
369 /**
370 * Resizes all the tabs to the passed width
371 * @param {Number} The new width
372 */
373 setTabWidth : function(width){
374 this.currentTabWidth = width;
375 for(var i = 0, len = this.items.length; i < len; i++) {
376 if(!this.items[i].isHidden())this.items[i].setWidth(width);
377 }
378 },
379
380 /**
381 * Destroys this TabPanel
382 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well
383 */
384 destroy : function(removeEl){
385 YAHOO.ext.EventManager.removeResizeListener(this.onResize, this);
386 for(var i = 0, len = this.items.length; i < len; i++){
387 this.items[i].purgeListeners();
388 }
389 if(removeEl === true){
390 this.el.update('');
391 this.el.remove();
392 }
393 }
394};
395
396/**
397* @class YAHOO.ext.TabPanelItem
398* @extends YAHOO.ext.util.Observable
399*/
400YAHOO.ext.TabPanelItem = function(tabPanel, id, text, closable){
401 /**
402 * The TabPanel this TabPanelItem belongs to
403 * @type YAHOO.ext.TabPanel
404 */
405 this.tabPanel = tabPanel;
406 /**
407 * The id for this TabPanelItem
408 * @type String
409 */
410 this.id = id;
411 /** @private */
412 this.disabled = false;
413 /** @private */
414 this.text = text;
415 /** @private */
416 this.loaded = false;
417 this.closable = closable;
418
419 /**
420 * The body element for this TabPanelItem
421 * @type YAHOO.ext.Element
422 */
423 this.bodyEl = getEl(tabPanel.createItemBody(tabPanel.bodyEl.dom, id));
424 this.bodyEl.setVisibilityMode(YAHOO.ext.Element.VISIBILITY);
425 this.bodyEl.setStyle('display', 'block');
426 this.bodyEl.setStyle('zoom', '1');
427 this.hideAction();
428
429 var els = tabPanel.createStripElements(tabPanel.stripEl.dom, text, closable);
430 /** @private */
431 this.el = getEl(els.el, true);
432 this.inner = getEl(els.inner, true);
433 this.textEl = getEl(this.el.dom.firstChild.firstChild.firstChild, true);
434 this.pnode = getEl(els.el.parentNode, true);
435 this.el.mon('click', this.onTabClick, this, true);
436 /** @private */
437 if(closable){
438 var c = getEl(els.close, true);
439 c.dom.title = this.closeText;
440 c.addClassOnOver('close-over');
441 c.mon('click', this.closeClick, this, true);
442 }
443
444 // these two are now private and deprecated
445 this.onActivate = new YAHOO.util.CustomEvent('TabItem.onActivate');
446 this.onDeactivate = new YAHOO.util.CustomEvent('TabItem.onDeactivate');
447
448 this.events = {
449 /**
450 * @event activate
451 * Fires when this tab becomes the active tab
452 * @param {YAHOO.ext.TabPanel} tabPanel
453 * @param {YAHOO.ext.TabPanelItem} this
454 */
455 'activate': this.onActivate,
456 /**
457 * @event beforeclose
458 * Fires before this tab is closed. To cancal the close, set cancel to true on e. (e.cancel = true)
459 * @param {YAHOO.ext.TabPanelItem} this
460 * @param {Object} e Set cancel to true on this object to cancel the close.
461 */
462 'beforeclose': new YAHOO.util.CustomEvent('beforeclose'),
463 /**
464 * @event close
465 * Fires when this tab is closed
466 * @param {YAHOO.ext.TabPanelItem} this
467 */
468 'close': new YAHOO.util.CustomEvent('close'),
469 /**
470 * @event deactivate
471 * Fires when this tab is no longer the active tab
472 * @param {YAHOO.ext.TabPanel} tabPanel
473 * @param {YAHOO.ext.TabPanelItem} this
474 */
475 'deactivate' : this.onDeactivate
476 };
477 this.hidden = false;
478};
479
480YAHOO.ext.TabPanelItem.prototype = {
481 fireEvent : YAHOO.ext.util.Observable.prototype.fireEvent,
482 on : YAHOO.ext.util.Observable.prototype.on,
483 addListener : YAHOO.ext.util.Observable.prototype.addListener,
484 delayedListener : YAHOO.ext.util.Observable.prototype.delayedListener,
485 removeListener : YAHOO.ext.util.Observable.prototype.removeListener,
486 purgeListeners : function(){
487 YAHOO.ext.util.Observable.prototype.purgeListeners.call(this);
488 this.el.removeAllListeners();
489 },
490 /**
491 * Show this TabPanelItem - this <b>does not</b> deactivate the currently active TabPanelItem.
492 */
493 show : function(){
494 this.pnode.addClass('on');
495 this.showAction();
496 if(YAHOO.ext.util.Browser.isOpera){
497 this.tabPanel.stripWrap.repaint();
498 }
499 this.onActivate.fireDirect(this.tabPanel, this);
500 },
501
502 /**
503 * Returns true if this tab is the active tab
504 * @return {Boolean}
505 */
506 isActive : function(){
507 return this.tabPanel.getActiveTab() == this;
508 },
509
510 /**
511 * Hide this TabPanelItem - if you don't activate another TabPanelItem this could look odd.
512 */
513 hide : function(){
514 this.pnode.removeClass('on');
515 this.hideAction();
516 this.onDeactivate.fireDirect(this.tabPanel, this);
517 },
518
519 hideAction : function(){
520 this.bodyEl.setStyle('position', 'absolute');
521 this.bodyEl.setLeft('-20000px');
522 this.bodyEl.setTop('-20000px');
523 this.bodyEl.hide();
524 },
525
526 showAction : function(){
527 this.bodyEl.setStyle('position', 'relative');
528 this.bodyEl.setTop('');
529 this.bodyEl.setLeft('');
530 this.bodyEl.show();
531 this.tabPanel.el.repaint.defer(1);
532 },
533
534 /**
535 * Set the tooltip (title attribute) for the tab
536 * @param {String} tooltip
537 */
538 setTooltip : function(text){
539 this.textEl.dom.title = text;
540 },
541
542 onTabClick : function(e){
543 e.preventDefault();
544 this.tabPanel.activate(this.id);
545 },
546
547 getWidth : function(){
548 return this.inner.getWidth();
549 },
550
551 setWidth : function(width){
552 var iwidth = width - this.pnode.getPadding("lr");
553 this.inner.setWidth(iwidth);
554 this.textEl.setWidth(iwidth-this.inner.getPadding('lr'));
555 this.pnode.setWidth(width);
556 },
557
558 setHidden : function(hidden){
559 this.hidden = hidden;
560 this.pnode.setStyle('display', hidden ? 'none' : '');
561 },
562
563 /**
564 * Returns true if this tab is "hidden"
565 * @return {Boolean}
566 */
567 isHidden : function(){
568 return this.hidden;
569 },
570
571 /**
572 * Returns the text for this tab
573 * @return {String}
574 */
575 getText : function(){
576 return this.text;
577 },
578
579 autoSize : function(){
580 this.el.beginMeasure();
581 this.textEl.setWidth(1);
582 this.setWidth(this.textEl.dom.scrollWidth+this.pnode.getPadding("lr")+this.inner.getPadding('lr'));
583 this.el.endMeasure();
584 },
585
586 /**
587 * Sets the text for the tab (Note: this also sets the tooltip)
588 * @param {String} text
589 */
590 setText : function(text){
591 this.text = text;
592 this.textEl.update(text);
593 this.textEl.dom.title = text;
594 if(!this.tabPanel.resizeTabs){
595 this.autoSize();
596 }
597 },
598 /**
599 * Activate this TabPanelItem - this <b>does</b> deactivate the currently active TabPanelItem.
600 */
601 activate : function(){
602 this.tabPanel.activate(this.id);
603 },
604
605 /**
606 * Disable this TabPanelItem - this call is ignore if this is the active TabPanelItem.
607 */
608 disable : function(){
609 if(this.tabPanel.active != this){
610 this.disabled = true;
611 this.pnode.addClass('disabled');
612 }
613 },
614
615 /**
616 * Enable this TabPanelItem if it was previously disabled.
617 */
618 enable : function(){
619 this.disabled = false;
620 this.pnode.removeClass('disabled');
621 },
622
623 /**
624 * Set the content for this TabPanelItem.
625 * @param {String} content The content
626 * @param {Boolean} loadScripts true to look for and load scripts
627 */
628 setContent : function(content, loadScripts){
629 this.bodyEl.update(content, loadScripts);
630 },
631
632 /**
633 * Get the {@link YAHOO.ext.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
634 * @return {YAHOO.ext.UpdateManager} The UpdateManager
635 */
636 getUpdateManager : function(){
637 return this.bodyEl.getUpdateManager();
638 },
639
640 /**
641 * Set a URL to be used to load the content for this TabPanelItem.
642 * @param {String/Function} url The url to load the content from or a function to call to get the url
643 * @param {<i>String/Object</i>} params (optional) The string params for the update call or an object of the params. See {@link YAHOO.ext.UpdateManager#update} for more details. (Defaults to null)
644 * @param {<i>Boolean</i>} loadOnce (optional) Whether to only load the content once. If this is false it makes the Ajax call every time this TabPanelItem is activated. (Defaults to false)
645 * @return {YAHOO.ext.UpdateManager} The UpdateManager
646 */
647 setUrl : function(url, params, loadOnce){
648 if(this.refreshDelegate){
649 this.onActivate.unsubscribe(this.refreshDelegate);
650 }
651 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
652 this.onActivate.subscribe(this.refreshDelegate);
653 return this.bodyEl.getUpdateManager();
654 },
655
656 /** @private */
657 _handleRefresh : function(url, params, loadOnce){
658 if(!loadOnce || !this.loaded){
659 var updater = this.bodyEl.getUpdateManager();
660 updater.update(url, params, this._setLoaded.createDelegate(this));
661 }
662 },
663
664 /**
665 * Force a content refresh from the URL specified in the setUrl() method.
666 * Will fail silently if the setUrl method has not been called.
667 * This does not activate the panel, just updates its content.
668 */
669 refresh : function(){
670 if(this.refreshDelegate){
671 this.loaded = false;
672 this.refreshDelegate();
673 }
674 },
675
676 /** @private */
677 _setLoaded : function(){
678 this.loaded = true;
679 },
680
681 /** @private */
682 closeClick : function(e){
683 var e = {};
684 this.fireEvent('beforeclose', this, e);
685 if(e.cancel !== true){
686 this.tabPanel.removeTab(this.id);
687 }
688 },
689 /**
690 * The text displayed in the tooltip for the close icon.
691 * @type String
692 */
693 closeText : 'Close this tab'
694};
695
696/** @private */
697YAHOO.ext.TabPanel.prototype.createStrip = function(container){
698 var strip = document.createElement('div');
699 strip.className = 'ytab-wrap';
700 container.appendChild(strip);
701 return strip;
702};
703/** @private */
704YAHOO.ext.TabPanel.prototype.createStripList = function(strip){
705 // div wrapper for retard IE
706 strip.innerHTML = '<div class="ytab-strip-wrap"><table class="ytab-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr></tr></tbody></table></div>';
707 return strip.firstChild.firstChild.firstChild.firstChild;
708};
709/** @private */
710YAHOO.ext.TabPanel.prototype.createBody = function(container){
711 var body = document.createElement('div');
712 YAHOO.util.Dom.generateId(body, 'tab-body');
713 YAHOO.util.Dom.addClass(body, 'yui-ext-tabbody');
714 container.appendChild(body);
715 return body;
716};
717/** @private */
718YAHOO.ext.TabPanel.prototype.createItemBody = function(bodyEl, id){
719 var body = YAHOO.util.Dom.get(id);
720 if(!body){
721 body = document.createElement('div');
722 body.id = id;
723 }
724 YAHOO.util.Dom.addClass(body, 'yui-ext-tabitembody');
725 bodyEl.insertBefore(body, bodyEl.firstChild);
726 return body;
727};
728/** @private */
729YAHOO.ext.TabPanel.prototype.createStripElements = function(stripEl, text, closable){
730 var td = document.createElement('td');
731 stripEl.appendChild(td);
732 if(closable){
733 td.className = "ytab-closable";
734 if(!this.closeTpl){
735 this.closeTpl = new YAHOO.ext.Template(
736 '<a href="#" class="ytab-right"><span class="ytab-left"><em class="ytab-inner">' +
737 '<span unselectable="on" title="{text}" class="ytab-text">{text}</span>' +
738 '<div unselectable="on" class="close-icon">&#160;</div></em></span></a>'
739 );
740 }
741 var el = this.closeTpl.overwrite(td, {'text': text});
742 var close = el.getElementsByTagName('div')[0];
743 var inner = el.getElementsByTagName('em')[0];
744 return {'el': el, 'close': close, 'inner': inner};
745 } else {
746 if(!this.tabTpl){
747 this.tabTpl = new YAHOO.ext.Template(
748 '<a href="#" class="ytab-right"><span class="ytab-left"><em class="ytab-inner">' +
749 '<span unselectable="on" title="{text}" class="ytab-text">{text}</span></em></span></a>'
750 );
751 }
752 var el = this.tabTpl.overwrite(td, {'text': text});
753 var inner = el.getElementsByTagName('em')[0];
754 return {'el': el, 'inner': inner};
755 }
756};
diff --git a/frontend/beta/js/YUI-extensions/widgets/TaskPanel.js b/frontend/beta/js/YUI-extensions/widgets/TaskPanel.js
new file mode 100644
index 0000000..e69de29
--- a/dev/null
+++ b/frontend/beta/js/YUI-extensions/widgets/TaskPanel.js
diff --git a/frontend/beta/js/YUI-extensions/widgets/TemplateView.js b/frontend/beta/js/YUI-extensions/widgets/TemplateView.js
new file mode 100644
index 0000000..2100205
--- a/dev/null
+++ b/frontend/beta/js/YUI-extensions/widgets/TemplateView.js
@@ -0,0 +1,766 @@
1/**
2 * @class YAHOO.ext.View
3 * @extends YAHOO.ext.util.Observable
4 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
5 * This class also supports single and multi selection modes. <br>
6 * Create a data model bound view:
7<pre><code>
8var dataModel = new YAHOO.ext.grid.XMLDataModel(...);
9var view = new YAHOO.ext.View('my-element',
10 '&lt;div id="{0}"&gt;{2} - {1}&lt;/div&gt;', // auto create template
11 dataModel, {
12 singleSelect: true,
13 selectedClass: 'ydataview-selected'
14 });
15
16// listen for node click?
17view.on('click', function(vw, index, node, e){
18 alert('Node "' + node.id + '" at index: ' + index + ' was clicked.');
19});
20
21// load XML data
22dataModel.load('foobar.xml');
23</code></pre>
24For an example of creating a JSON/UpdateManager view, see {@link YAHOO.ext.JsonView}.
25 * <br><br>
26 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
27 * IE's limited insertion support with tables and Opera's faulty event bubbling.</b>
28 * @constructor
29 * Create a new View
30 * @param {String/HTMLElement/Element} container The container element where the view is to be rendered.
31 * @param {String/DomHelper.Template} tpl The rendering template or a string to create a template with
32 * @param {DataModel} dataModel The bound data model
33 * @param {Object} config The config object
34*/
35YAHOO.ext.View = function(container, tpl, dataModel, config){
36 this.el = getEl(container, true);
37 this.nodes = this.el.dom.childNodes;
38 if(typeof tpl == 'string'){
39 tpl = new YAHOO.ext.Template(tpl);
40 }
41 tpl.compile();
42 /**
43 * The template used by this View
44 * @type {YAHOO.ext.DomHelper.Template}
45 */
46 this.tpl = tpl;
47 this.setDataModel(dataModel);
48 var CE = YAHOO.util.CustomEvent;
49 /** @private */
50 this.events = {
51 /**
52 * @event beforeclick
53 * Fires before a click is processed. Returns false to cancel the default action.
54 * @param {YAHOO.ext.View} this
55 * @param {Number} index The index of the target node
56 * @param {HTMLElement} node The target node
57 * @param {YAHOO.ext.EventObject} e The raw event object
58 */
59 'beforeclick' : true,
60 /**
61 * @event click
62 * Fires when a template node is clicked.
63 * @param {YAHOO.ext.View} this
64 * @param {Number} index The index of the target node
65 * @param {HTMLElement} node The target node
66 * @param {YAHOO.ext.EventObject} e The raw event object
67 */
68 'click' : true,
69 /**
70 * @event dblclick
71 * Fires when a template node is double clicked.
72 * @param {YAHOO.ext.View} this
73 * @param {Number} index The index of the target node
74 * @param {HTMLElement} node The target node
75 * @param {YAHOO.ext.EventObject} e The raw event object
76 */
77 'dblclick' : true,
78 /**
79 * @event contextmenu
80 * Fires when a template node is right clicked.
81 * @param {YAHOO.ext.View} this
82 * @param {Number} index The index of the target node
83 * @param {HTMLElement} node The target node
84 * @param {YAHOO.ext.EventObject} e The raw event object
85 */
86 'contextmenu' : true,
87 /**
88 * @event selectionchange
89 * Fires when the selected nodes change.
90 * @param {YAHOO.ext.View} this
91 * @param {Array} selections Array of the selected nodes
92 */
93 'selectionchange' : true,
94
95 /**
96 * @event beforeselect
97 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
98 * @param {YAHOO.ext.View} this
99 * @param {HTMLElement} node The node to be selected
100 * @param {Array} selections Array of currently selected nodes
101 */
102 'beforeselect' : true
103 };
104 this.el.mon("click", this.onClick, this, true);
105 this.el.mon("dblclick", this.onDblClick, this, true);
106 this.el.mon("contextmenu", this.onContextMenu, this, true);
107
108 /**
109 * The css class to add to selected nodes
110 * @type {YAHOO.ext.DomHelper.Template}
111 */
112 this.selectedClass = 'ydataview-selected';
113
114 this.emptyText = '';
115
116 this.selections = [];
117
118 this.lastSelection = null;
119
120 /**
121 * The root property in the loaded json object that contains the data
122 * @type {String}
123 */
124 this.jsonRoot = null;
125 YAHOO.ext.util.Config.apply(this, config);
126 if(this.renderUpdates || this.jsonRoot){
127 var um = this.el.getUpdateManager();
128 um.setRenderer(this);
129 }
130};
131
132YAHOO.extendX(YAHOO.ext.View, YAHOO.ext.util.Observable, {
133 /**
134 * Returns the element this view is bound to.
135 * @return {YAHOO.ext.Element}
136 */
137 getEl : function(){
138 return this.el;
139 },
140
141 render : function(el, response){
142 this.clearSelections();
143 this.el.update('');
144 var o;
145 try{
146 o = YAHOO.ext.util.JSON.decode(response.responseText);
147 if(this.jsonRoot){
148 o = eval('o.' + this.jsonRoot);
149 }
150 }catch(e){}
151 /**
152 * The current json data or null
153 */
154 this.jsonData = o;
155 this.beforeRender();
156 this.refresh();
157 },
158
159 beforeRender : function(){
160
161 },
162
163 /**
164 * Refreshes the view.
165 */
166 refresh : function(){
167 this.clearSelections();
168 this.el.update('');
169 this.html = [];
170 if(this.renderUpdates || this.jsonRoot){
171 var o = this.jsonData;
172 if(o){
173 for(var i = 0, len = o.length; i < len; i++) {
174 this.renderEach(o[i]);
175 }
176 }
177 }else{
178 this.dataModel.each(this.renderEach, this);
179 }
180 var strHtml;
181 if(this.html.length > 0){
182 strHtml = this.html.join('');
183 }else{
184 strHtml = this.emptyText;
185 }
186 this.el.update(strHtml);
187 this.html = null;
188 this.nodes = this.el.dom.childNodes;
189 this.updateIndexes(0);
190 },
191
192 /**
193 * Function to override to reformat the data that is sent to
194 * the template for each node.
195 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
196 * a JSON object for an UpdateManager bound view).
197 * @param {Number} index The index of the data within the data model
198 */
199 prepareData : function(data, index){
200 return data;
201 },
202
203 renderEach : function(data){
204 this.html[this.html.length] = this.tpl.applyTemplate(this.prepareData(data));
205 },
206
207 /**
208 * Refresh an individual node.
209 * @param {Number} index
210 */
211 refreshNode : function(index){
212 this.refreshNodes(index, index);
213 },
214
215 refreshNodes : function(dm, startIndex, endIndex){
216 this.clearSelections();
217 var dm = this.dataModel;
218 var ns = this.nodes;
219 for(var i = startIndex; i <= endIndex; i++){
220 var d = this.prepareData(dm.getRow(i), i);
221 if(i < ns.length-1){
222 var old = ns[i];
223 this.tpl.insertBefore(old, d);
224 this.el.dom.removeChild(old);
225 }else{
226 this.tpl.append(this.el.dom, d);
227 }
228 }
229 this.updateIndexes(startIndex, endIndex);
230 },
231
232 deleteNodes : function(dm, startIndex, endIndex){
233 this.clearSelections();
234 if(startIndex == 0 && endIndex >= this.nodes.length-1){
235 this.el.update('');
236 }else{
237 var el = this.el.dom;
238 for(var i = startIndex; i <= endIndex; i++){
239 el.removeChild(this.nodes[startIndex]);
240 }
241 this.updateIndexes(startIndex);
242 }
243 },
244
245 insertNodes : function(dm, startIndex, endIndex){
246 if(this.nodes.length == 0){
247 this.refresh();
248 }else{
249 this.clearSelections();
250 var t = this.tpl;
251 var before = this.nodes[startIndex];
252 var dm = this.dataModel;
253 if(before){
254 for(var i = startIndex; i <= endIndex; i++){
255 t.insertBefore(before, this.prepareData(dm.getRow(i), i));
256 }
257 }else{
258 var el = this.el.dom;
259 for(var i = startIndex; i <= endIndex; i++){
260 t.append(el, this.prepareData(dm.getRow(i), i));
261 }
262 }
263 this.updateIndexes(startIndex);
264 }
265 },
266
267 updateIndexes : function(dm, startIndex, endIndex){
268 var ns = this.nodes;
269 startIndex = startIndex || 0;
270 endIndex = endIndex || ns.length-1;
271 for(var i = startIndex; i <= endIndex; i++){
272 ns[i].nodeIndex = i;
273 }
274 },
275
276 /**
277 * Changes the data model this view uses and refresh the view.
278 * @param {DataModel} dataModel
279 */
280 setDataModel : function(dm){
281 if(!dm) return;
282 this.unplugDataModel(this.dataModel);
283 this.dataModel = dm;
284 dm.on('cellupdated', this.refreshNode, this, true);
285 dm.on('datachanged', this.refresh, this, true);
286 dm.on('rowsdeleted', this.deleteNodes, this, true);
287 dm.on('rowsinserted', this.insertNodes, this, true);
288 dm.on('rowsupdated', this.refreshNodes, this, true);
289 dm.on('rowssorted', this.refresh, this, true);
290 this.refresh();
291 },
292
293 /**
294 * Unplug the data model and stop updates.
295 * @param {DataModel} dataModel
296 */
297 unplugDataModel : function(dm){
298 if(!dm) return;
299 dm.removeListener('cellupdated', this.refreshNode, this);
300 dm.removeListener('datachanged', this.refresh, this);
301 dm.removeListener('rowsdeleted', this.deleteNodes, this);
302 dm.removeListener('rowsinserted', this.insertNodes, this);
303 dm.removeListener('rowsupdated', this.refreshNodes, this);
304 dm.removeListener('rowssorted', this.refresh, this);
305 this.dataModel = null;
306 },
307
308 /**
309 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
310 * @param {HTMLElement} node
311 * @return {HTMLElement} The template node
312 */
313 findItemFromChild : function(node){
314 var el = this.el.dom;
315 if(!node || node.parentNode == el){
316 return node;
317 }
318 var p = node.parentNode;
319 while(p && p != el){
320 if(p.parentNode == el){
321 return p;
322 }
323 p = p.parentNode;
324 }
325 return null;
326 },
327
328 /** @ignore */
329 onClick : function(e){
330 var item = this.findItemFromChild(e.getTarget());
331 if(item){
332 var index = this.indexOf(item);
333 if(this.onItemClick(item, index, e) !== false){
334 this.fireEvent('click', this, index, item, e);
335 }
336 }else{
337 this.clearSelections();
338 }
339 },
340
341 /** @ignore */
342 onContextMenu : function(e){
343 var item = this.findItemFromChild(e.getTarget());
344 if(item){
345 this.fireEvent('contextmenu', this, this.indexOf(item), item, e);
346 }
347 },
348
349 /** @ignore */
350 onDblClick : function(e){
351 var item = this.findItemFromChild(e.getTarget());
352 if(item){
353 this.fireEvent('dblclick', this, this.indexOf(item), item, e);
354 }
355 },
356
357 onItemClick : function(item, index, e){
358 if(this.fireEvent('beforeclick', this, index, item, e) !== false){
359 if(this.multiSelect || this.singleSelect){
360 if(this.multiSelect && e.shiftKey && this.lastSelection){
361 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
362 }else{
363 this.select(item, this.multiSelect && e.ctrlKey);
364 this.lastSelection = item;
365 }
366 e.preventDefault();
367 }
368 return true;
369 }else{
370 return false;
371 }
372 },
373
374 /**
375 * Get the number of selected nodes.
376 * @return {Number}
377 */
378 getSelectionCount : function(){
379 return this.selections.length;
380 },
381
382 /**
383 * Get the currently selected nodes.
384 * @return {Array} An array of HTMLElements
385 */
386 getSelectedNodes : function(){
387 return this.selections;
388 },
389
390 /**
391 * Get the indexes of the selected nodes.
392 * @return {Array}
393 */
394 getSelectedIndexes : function(){
395 var indexes = [];
396 for(var i = 0, len = this.selections.length; i < len; i++) {
397 indexes.push(this.selections[i].nodeIndex);
398 }
399 return indexes;
400 },
401
402 /**
403 * Clear all selections
404 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
405 */
406 clearSelections : function(suppressEvent){
407 if(this.multiSelect || this.singleSelect){
408 YAHOO.util.Dom.removeClass(this.selections, this.selectedClass);
409 this.selections = [];
410 if(!suppressEvent){
411 this.fireEvent('selectionchange', this, this.selections);
412 }
413 }
414 },
415
416 /**
417 * Returns true if the passed node is selected
418 * @param {HTMLElement/Number} node The node or node index
419 * @return {Boolean}
420 */
421 isSelected : function(node){
422 node = this.getNode(node);
423 var s = this.selections;
424 if(s.length < 1){
425 return false;
426 }
427 if(s.indexOf){
428 return s.indexOf(node) !== -1;
429 }else{
430 for(var i = 0, len = s.length; i < len; i++){
431 if (s[i] == node){
432 return true;
433 }
434 }
435 return false;
436 }
437 },
438
439 /**
440 * Selects nodes.
441 * @param {Array/HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node, id of a template node or an array of any of those to select
442 * @param {Boolean} keepExisting (optional) true to keep existing selections
443 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
444 */
445 select : function(nodeInfo, keepExisting, suppressEvent){
446 if(!keepExisting){
447 this.clearSelections(true);
448 }
449 if(nodeInfo instanceof Array){
450 for(var i = 0, len = nodeInfo.length; i < len; i++) {
451 this.select(nodeInfo[i], true, true);
452 }
453 }else{
454 var node = this.getNode(nodeInfo);
455 if(node && !this.isSelected(node)){
456 if(this.fireEvent('beforeselect', this, node, this.selections) !== false){
457 YAHOO.util.Dom.addClass(node, this.selectedClass);
458 this.selections.push(node);
459 }
460 }
461 }
462 if(!suppressEvent){
463 this.fireEvent('selectionchange', this, this.selections);
464 }
465 },
466
467 /**
468 * Gets a template node.
469 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
470 * @return {HTMLElement} The node or null if it wasn't found
471 */
472 getNode : function(nodeInfo){
473 if(typeof nodeInfo == 'object'){
474 return nodeInfo;
475 }else if(typeof nodeInfo == 'string'){
476 return document.getElementById(nodeInfo);
477 }else if(typeof nodeInfo == 'number'){
478 return this.nodes[nodeInfo];
479 }
480 return null;
481 },
482
483 /**
484 * Gets a range template nodes.
485 * @param {Number} startIndex
486 * @param {Number} endIndex
487 * @return {Array} An array of nodes
488 */
489 getNodes : function(start, end){
490 var ns = this.nodes;
491 start = start || 0;
492 end = typeof end == 'undefined' ? ns.length-1 : end;
493 var nodes = [];
494 if(start <= end){
495 for(var i = start; i <= end; i++) {
496 nodes.push(ns[i]);
497 }
498 }else{
499 for(var i = start; i >= end; i--) {
500 nodes.push(ns[i]);
501 }
502 }
503 return nodes;
504 },
505
506 /**
507 * Finds the index of the passed node
508 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
509 * @return {Number} The index of the node or -1
510 */
511 indexOf : function(node){
512 node = this.getNode(node);
513 if(typeof node.nodeIndex == 'number'){
514 return node.nodeIndex;
515 }
516 var ns = this.nodes;
517 for(var i = 0, len = ns.length; i < len; i++) {
518 if(ns[i] == node){
519 return i;
520 }
521 }
522 return -1;
523 }
524});
525
526/**
527 * @class YAHOO.ext.JsonView
528 * @extends YAHOO.ext.View
529 * Shortcut class to create a JSON + UpdateManager template view. Usage:
530<pre><code>
531var view = new YAHOO.ext.JsonView('my-element',
532 '&lt;div id="{id}"&gt;{foo} - {bar}&lt;/div&gt;', // auto create template
533 { multiSelect: true, jsonRoot: 'data' });
534
535// listen for node click?
536view.on('click', function(vw, index, node, e){
537 alert('Node "' + node.id + '" at index: ' + index + ' was clicked.');
538});
539
540// direct load of JSON data
541view.load('foobar.php');
542
543
544// Example from my blog list
545var tpl = new YAHOO.ext.Template(
546 '&lt;div class="entry"&gt;' +
547 '&lt;a class="entry-title" href="{link}"&gt;{title}&lt;/a&gt;' +
548 '&lt;h4&gt;{date} by {author} | {comments} Comments&lt;/h4&gt;{description}' +
549 '&lt;/div&gt;&lt;hr /&gt;'
550);
551
552var moreView = new YAHOO.ext.JsonView('entry-list', tpl, {
553 jsonRoot: 'posts'
554});
555moreView.on('beforerender', this.sortEntries, this, true);
556moreView.load({
557 url:'/blog/get-posts.php',
558 params: 'allposts=true',
559 text:'Loading Blog Entries...'
560});
561</code></pre>
562 * @constructor
563 * Create a new JsonView
564 * @param {String/HTMLElement/Element} container The container element where the view is to be rendered.
565 * @param {DomHelper.Template} tpl The rendering template
566 * @param {Object} config The config object
567 */
568YAHOO.ext.JsonView = function(container, tpl, config){
569 var cfg = config || {};
570 cfg.renderUpdates = true;
571 YAHOO.ext.JsonView.superclass.constructor.call(this, container, tpl, null, cfg);
572 /**
573 * @event beforerender
574 * Fires before rendering of the downloaded json data.
575 * @param {YAHOO.ext.View} this
576 * @param {Object} data The json data loaded
577 */
578 this.events['beforerender'] = true;
579 /**
580 * @event load
581 * Fires when data is loaded.
582 * @param {YAHOO.ext.View} this
583 * @param {Object} data The json data loaded
584 * @param {Object} response The raw Connect response object
585 */
586 this.events['load'] = true;
587 /**
588 * @event loadexception
589 * Fires when loading fails.
590 * @param {YAHOO.ext.View} this
591 * @param {Object} response The raw Connect response object
592 */
593 this.events['loadexception'] = true;
594 this.el.getUpdateManager().on('update', this.onLoad, this, true);
595 this.el.getUpdateManager().on('failure', this.onLoadException, this, true);
596};
597YAHOO.extendX(YAHOO.ext.JsonView, YAHOO.ext.View, {
598 /**
599 * Performs an async request, loading the JSON from the response. If params are specified it uses POST, otherwise it uses GET.
600 * @param {Object/String/Function} url The url for this request or a function to call to get the url or a config object containing any of the following options:
601<pre><code>
602view.load({
603 url: 'your-url.php',<br/>
604 params: {param1: 'foo', param2: 'bar'}, // or a URL encoded string<br/>
605 callback: yourFunction,<br/>
606 scope: yourObject, //(optional scope) <br/>
607 discardUrl: false, <br/>
608 nocache: false,<br/>
609 text: 'Loading...',<br/>
610 timeout: 30,<br/>
611 scripts: false<br/>
612});
613</code></pre>
614 * The only required property is url. The optional properties nocache, text and scripts
615 * are shorthand for disableCaching, indicatorText and loadScripts and are used to set their associated property on this UpdateManager instance.
616 * @param {<i>String/Object</i>} params (optional) The parameters to pass as either a url encoded string "param1=1&amp;param2=2" or an object {param1: 1, param2: 2}
617 * @param {<i>Function</i>} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
618 * @param {<i>Boolean</i>} discardUrl (optional) By default when you execute an update the defaultUrl is changed to the last used url. If true, it will not store the url.
619 */
620 load : function(){
621 var um = this.el.getUpdateManager();
622 um.update.apply(um, arguments);
623 },
624
625 /**
626 * Get the number of records in the current JSON dataset
627 * @return {Number}
628 */
629 getCount : function(){
630 return this.jsonData ? this.jsonData.length : 0;
631 },
632
633 /**
634 * Returns the JSON object for the specified node(s)
635 * @param {HTMLElement/Array} node The node or an array of nodes
636 * @return {Object/Array} If you pass in an array, you get an array back, otherwise
637 * you get the JSON object for the node
638 */
639 getNodeData : function(node){
640 if(node instanceof Array){
641 var data = [];
642 for(var i = 0, len = node.length; i < len; i++){
643 data.push(this.getNodeData(node[i]));
644 }
645 return data;
646 }
647 return this.jsonData[this.indexOf(node)] || null;
648 },
649
650 beforeRender : function(){
651 this.snapshot = this.jsonData;
652 if(this.sortInfo){
653 this.sort.apply(this, this.sortInfo);
654 }
655 this.fireEvent('beforerender', this, this.jsonData);
656 },
657
658 onLoad : function(el, o){
659 this.fireEvent('load', this, this.jsonData, o);
660 },
661
662 onLoadException : function(el, o){
663 this.fireEvent('loadexception', this, o);
664 },
665
666 /**
667 * Filter the data by a specific property.
668 * @param {String} property A property on your JSON objects
669 * @param {String/RegExp} value Either string that the property values
670 * should start with or a RegExp to test against the property
671 */
672 filter : function(property, value){
673 if(this.jsonData){
674 var data = [];
675 var ss = this.snapshot;
676 if(typeof value == 'string'){
677 var vlen = value.length;
678 if(vlen == 0){
679 this.clearFilter();
680 return;
681 }
682 value = value.toLowerCase();
683 for(var i = 0, len = ss.length; i < len; i++){
684 var o = ss[i];
685 if(o[property].substr(0, vlen).toLowerCase() == value){
686 data.push(o);
687 }
688 }
689 }else if(value.exec){ // regex?
690 for(var i = 0, len = ss.length; i < len; i++){
691 var o = ss[i];
692 if(value.test(o[property])){
693 data.push(o);
694 }
695 }
696 }else{
697 return;
698 }
699 this.jsonData = data;
700 this.refresh();
701 }
702 },
703
704 /**
705 * Filter by a function. The passed function will be called with each
706 * object in the current dataset. If the function returns true, the value is kept
707 * otherwise it is filtered.
708 * @param {Function} fn
709 * @param {Object} scope (optional) The scope of the function (defaults to this JsonView)
710 */
711 filterBy : function(fn, scope){
712 if(this.jsonData){
713 var data = [];
714 var ss = this.snapshot;
715 for(var i = 0, len = ss.length; i < len; i++){
716 var o = ss[i];
717 if(fn.call(scope|| this, o)){
718 data.push(o);
719 }
720 }
721 this.jsonData = data;
722 this.refresh();
723 }
724 },
725
726 /**
727 * Clears the current filter.
728 */
729 clearFilter : function(){
730 if(this.snapshot && this.jsonData != this.snapshot){
731 this.jsonData = this.snapshot;
732 this.refresh();
733 }
734 },
735
736
737 /**
738 * Sorts the data for this view and refreshes it.
739 * @param {String} property A property on your JSON objects to sort on
740 * @param {String} direction (optional) desc or asc (defaults to asc)
741 * @param {Function} sortType (optional) A function to call to convert the data to a sortable value.
742 */
743 sort : function(property, dir, sortType){
744 this.sortInfo = Array.prototype.slice.call(arguments, 0);
745 if(this.jsonData){
746 var p = property;
747 var dsc = dir && dir.toLowerCase() == 'desc';
748 var f = function(o1, o2){
749 var v1 = sortType ? sortType(o1[p]) : o1[p];
750 var v2 = sortType ? sortType(o2[p]) : o2[p];;
751 if(v1 < v2){
752 return dsc ? +1 : -1;
753 }else if(v1 > v2){
754 return dsc ? -1 : +1;
755 }else{
756 return 0;
757 }
758 };
759 this.jsonData.sort(f);
760 this.refresh();
761 if(this.jsonData != this.snapshot){
762 this.snapshot.sort(f);
763 }
764 }
765 }
766});
diff --git a/frontend/beta/js/YUI-extensions/widgets/Toolbar.js b/frontend/beta/js/YUI-extensions/widgets/Toolbar.js
new file mode 100644
index 0000000..7c14753
--- a/dev/null
+++ b/frontend/beta/js/YUI-extensions/widgets/Toolbar.js
@@ -0,0 +1,296 @@
1/**
2 * @class YAHOO.ext.Toolbar
3 * Basic Toolbar used by the Grid to create the paging toolbar. This class is reusable but functionality
4 * is limited. Look for more functionality in a future version.
5 * @constructor
6 * @param {String/HTMLElement/Element} container
7 * @param {Array} buttons (optional) array of button configs or elements to add
8 */
9 YAHOO.ext.Toolbar = function(container, buttons){
10 this.el = getEl(container, true);
11 var div = document.createElement('div');
12 div.className = 'ytoolbar';
13 var tb = document.createElement('table');
14 tb.border = 0;
15 tb.cellPadding = 0;
16 tb.cellSpacing = 0;
17 div.appendChild(tb);
18 var tbody = document.createElement('tbody');
19 tb.appendChild(tbody);
20 var tr = document.createElement('tr');
21 tbody.appendChild(tr);
22 this.el.dom.appendChild(div);
23 this.tr = tr;
24 if(buttons){
25 this.add.apply(this, buttons);
26 }
27};
28
29YAHOO.ext.Toolbar.prototype = {
30 /**
31 * Adds element(s) to the toolbar - this function takes a variable number of
32 * arguments of mixed type and adds them to the toolbar...
33 *
34 * @param {Mixed} arg If arg is a ToolbarButton, it is added. If arg is a string, it is wrapped
35 * in a ytb-text element and added unless the text is "separator" in which case a separator
36 * is added. Otherwise, it is assumed the element is an HTMLElement and it is added directly.
37 */
38 add : function(){
39 for(var i = 0; i < arguments.length; i++){
40 var el = arguments[i];
41 var td = document.createElement('td');
42 this.tr.appendChild(td);
43 if(el instanceof YAHOO.ext.ToolbarButton){
44 el.init(td);
45 }else if(el instanceof Array){
46 this.addButton(el);
47 }else if(typeof el == 'string'){
48 var span = document.createElement('span');
49 if(el == 'separator'){
50 span.className = 'ytb-sep';
51 }else{
52 span.innerHTML = el;
53 span.className = 'ytb-text';
54 }
55 td.appendChild(span);
56 }else if(typeof el == 'object' && el.nodeType){ // must be element?
57 td.appendChild(el);
58 }else if(typeof el == 'object'){ // must be button config?
59 this.addButton(el);
60 }
61 }
62 },
63
64 /**
65 * Returns the element for this toolbar
66 * @return {YAHOO.ext.Element}
67 */
68 getEl : function(){
69 return this.el;
70 },
71
72 /**
73 * Adds a separator
74 */
75 addSeparator : function(){
76 var td = document.createElement('td');
77 this.tr.appendChild(td);
78 var span = document.createElement('span');
79 span.className = 'ytb-sep';
80 td.appendChild(span);
81 },
82
83 /**
84 * Add a button (or buttons), see {@link YAHOO.ext.ToolbarButton} for more info on the config
85 * @param {Object/Array} config A button config or array of configs
86 * @return {YAHOO.ext.ToolbarButton/Array}
87 */
88 addButton : function(config){
89 if(config instanceof Array){
90 var buttons = [];
91 for(var i = 0, len = config.length; i < len; i++) {
92 buttons.push(this.addButton(config[i]));
93 }
94 return buttons;
95 }
96 var b = config;
97 if(!(config instanceof YAHOO.ext.ToolbarButton)){
98 b = new YAHOO.ext.ToolbarButton(config);
99 }
100 this.add(b);
101 return b;
102 },
103
104 /**
105 * Adds text to the toolbar
106 * @param {String} text The text to add
107 * @return {HTMLElement} The span element created which you can use to update the text.
108 */
109 addText : function(text){
110 var td = document.createElement('td');
111 this.tr.appendChild(td);
112 var span = document.createElement('span');
113 span.className = 'ytb-text';
114 span.innerHTML = text;
115 td.appendChild(span);
116 return span;
117 },
118
119 /**
120 * Inserts a button (or buttons) at the specified index
121 * @param {Number} index The index where the buttons are to be inserted
122 * @param {Object/Array} config A button config or array of configs
123 * @return {YAHOO.ext.ToolbarButton/Array}
124 */
125 insertButton : function(index, config){
126 if(config instanceof Array){
127 var buttons = [];
128 for(var i = 0, len = config.length; i < len; i++) {
129 buttons.push(this.insertButton(index + i, config[i]));
130 }
131 return buttons;
132 }
133 var b = new YAHOO.ext.ToolbarButton(config);
134 var td = document.createElement('td');
135 var nextSibling = this.tr.childNodes[index];
136 if (nextSibling)
137 this.tr.insertBefore(td, nextSibling);
138 else
139 this.tr.appendChild(td);
140 b.init(td);
141 return b;
142 }
143};
144
145/**
146 * @class YAHOO.ext.ToolbarButton
147 * A toolbar button. The config has the following options:
148 * <ul>
149 * <li>className - The CSS class for the button. Use this to attach a background image for an icon.</li>
150 * <li>text - The button's text</li>
151 * <li>tooltip - The buttons tooltip text</li>
152 * <li>click - function to call when the button is clicked</li>
153 * <li>mouseover - function to call when the mouse moves over the button</li>
154 * <li>mouseout - function to call when the mouse moves off the button</li>
155 * <li>scope - The scope of the above event handlers</li>
156 * <li></li>
157 * <li></li>
158 * @constructor
159 * @param {Object} config
160 */
161YAHOO.ext.ToolbarButton = function(config){
162 YAHOO.ext.util.Config.apply(this, config);
163};
164
165YAHOO.ext.ToolbarButton.prototype = {
166 /** @private */
167 init : function(appendTo){
168 var element = document.createElement('span');
169 element.className = 'ytb-button';
170 if(this.id){
171 element.id = this.id;
172 }
173 this.setDisabled(this.disabled === true);
174 var inner = document.createElement('span');
175 inner.className = 'ytb-button-inner ' + (this.className || this.cls);
176 inner.unselectable = 'on';
177 if(this.tooltip){
178 element.setAttribute('title', this.tooltip);
179 }
180 if(this.style){
181 YAHOO.ext.DomHelper.applyStyles(inner, this.style);
182 }
183 element.appendChild(inner);
184 appendTo.appendChild(element);
185 this.el = getEl(element, true);
186 this.el.unselectable();
187 inner.innerHTML = (this.text ? this.text : '&#160;');
188 this.inner = inner;
189 this.el.mon('click', this.onClick, this, true);
190 this.el.mon('mouseover', this.onMouseOver, this, true);
191 this.el.mon('mouseout', this.onMouseOut, this, true);
192 },
193
194 /**
195 * Sets this buttons click handler
196 * @param {Function} click The function to call when the button is clicked
197 * @param {Object} scope (optional) Scope for the function passed above
198 */
199 setHandler : function(click, scope){
200 this.click = click;
201 this.scope = scope;
202 },
203
204 /**
205 * Set this buttons text
206 * @param {String} text
207 */
208 setText : function(text){
209 this.inner.innerHTML = text;
210 },
211
212 /**
213 * Set this buttons tooltip text
214 * @param {String} text
215 */
216 setTooltip : function(text){
217 this.el.dom.title = text;
218 },
219
220 /**
221 * Show this button
222 */
223 show: function(){
224 this.el.dom.parentNode.style.display = '';
225 },
226
227 /**
228 * Hide this button
229 */
230 hide: function(){
231 this.el.dom.parentNode.style.display = 'none';
232 },
233
234 /**
235 * Disable this button
236 */
237 disable : function(){
238 this.disabled = true;
239 if(this.el){
240 this.el.addClass('ytb-button-disabled');
241 }
242 },
243
244 /**
245 * Enable this button
246 */
247 enable : function(){
248 this.disabled = false;
249 if(this.el){
250 this.el.removeClass('ytb-button-disabled');
251 }
252 },
253
254 /**
255 * Returns true if this button is disabled.
256 * @return {Boolean}
257 */
258 isDisabled : function(){
259 return this.disabled === true;
260 },
261
262 setDisabled : function(disabled){
263 if(disabled){
264 this.disable();
265 }else{
266 this.enable();
267 }
268 },
269
270 /** @private */
271 onClick : function(){
272 if(!this.disabled && this.click){
273 this.click.call(this.scope || window, this);
274 }
275 },
276
277 /** @private */
278 onMouseOver : function(){
279 if(!this.disabled){
280 this.el.addClass('ytb-button-over');
281 if(this.mouseover){
282 this.mouseover.call(this.scope || window, this);
283 }
284 }
285 },
286
287 /** @private */
288 onMouseOut : function(){
289 this.el.removeClass('ytb-button-over');
290 if(!this.disabled){
291 if(this.mouseout){
292 this.mouseout.call(this.scope || window, this);
293 }
294 }
295 }
296};
diff --git a/frontend/beta/js/YUI-extensions/yutil.js b/frontend/beta/js/YUI-extensions/yutil.js
new file mode 100644
index 0000000..a815397
--- a/dev/null
+++ b/frontend/beta/js/YUI-extensions/yutil.js
@@ -0,0 +1,637 @@
1YAHOO.namespace('ext', 'ext.util', 'ext.grid', 'ext.dd', 'ext.tree', 'ext.data', 'ext.form');
2if(typeof Ext == 'undefined'){
3 Ext = YAHOO.ext;
4}
5YAHOO.ext.Strict = (document.compatMode == 'CSS1Compat');
6YAHOO.ext.SSL_SECURE_URL = 'javascript:false';
7YAHOO.ext.BLANK_IMAGE_URL = 'http:/'+'/www.yui-ext.com/blog/images/s.gif';
8
9// for old browsers
10window.undefined = undefined;
11/**
12 * @class Function
13 * These functions are available on every Function object (any javascript function).
14 */
15 //
16 /**
17 * Creates a callback that passes arguments[0], arguments[1], arguments[2], ...
18 * Call directly on any function. Example: <code>myFunction.createCallback(myarg, myarg2)</code>
19 * Will create a function that is bound to those 2 args.
20 * @return {Function} The new function
21*/
22Function.prototype.createCallback = function(/*args...*/){
23 // make args available, in function below
24 var args = arguments;
25 var method = this;
26 return function() {
27 return method.apply(window, args);
28 };
29};
30
31/**
32 * Creates a delegate (callback) that sets the scope to obj.
33 * Call directly on any function. Example: <code>this.myFunction.createDelegate(this)</code>
34 * Will create a function that is automatically scoped to this.
35 * @param {Object} obj (optional) The object for which the scope is set
36 * @param {<i>Array</i>} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
37 * @param {<i>Boolean/Number</i>} appendArgs (optional) if True args are appended to call args instead of overriding,
38 * if a number the args are inserted at the specified position
39 * @return {Function} The new function
40 */
41Function.prototype.createDelegate = function(obj, args, appendArgs){
42 var method = this;
43 return function() {
44 var callArgs = args || arguments;
45 if(appendArgs === true){
46 callArgs = Array.prototype.slice.call(arguments, 0);
47 callArgs = callArgs.concat(args);
48 }else if(typeof appendArgs == 'number'){
49 callArgs = Array.prototype.slice.call(arguments, 0); // copy arguments first
50 var applyArgs = [appendArgs, 0].concat(args); // create method call params
51 Array.prototype.splice.apply(callArgs, applyArgs); // splice them in
52 }
53 return method.apply(obj || window, callArgs);
54 };
55};
56
57/**
58 * Calls this function after the number of millseconds specified.
59 * @param {Number} millis The number of milliseconds for the setTimeout call
60 * @param {Object} obj (optional) The object for which the scope is set
61 * @param {<i>Array</i>} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
62 * @param {<i>Boolean/Number</i>} appendArgs (optional) if True args are appended to call args instead of overriding,
63 * if a number the args are inserted at the specified position
64 * @return {Number} The timeout id that can be used with clearTimeout
65 */
66Function.prototype.defer = function(millis, obj, args, appendArgs){
67 return setTimeout(this.createDelegate(obj, args, appendArgs), millis);
68};
69/**
70 * Create a combined function call sequence of the original function + the passed function.
71 * The resulting function returns the results of the original function.
72 * The passed fcn is called with the parameters of the original function
73 * @param {Function} fcn The function to sequence
74 * @param {<i>Object</i>} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
75 * @return {Function} The new function
76 */
77Function.prototype.createSequence = function(fcn, scope){
78 if(typeof fcn != 'function'){
79 return this;
80 }
81 var method = this;
82 return function() {
83 var retval = method.apply(this || window, arguments);
84 fcn.apply(scope || this || window, arguments);
85 return retval;
86 };
87};
88
89/*
90 * IE will leak if this isn't here
91 */
92YAHOO.util.Event.on(window, 'unload', function(){
93 var p = Function.prototype;
94 delete p.createSequence;
95 delete p.defer;
96 delete p.createDelegate;
97 delete p.createCallback;
98 delete p.createInterceptor;
99});
100
101/**
102 * Creates an interceptor function. The passed fcn is called before the original one. If it returns false, the original one is not called.
103 * The resulting function returns the results of the original function.
104 * The passed fcn is called with the parameters of the original function.
105 * @addon
106 * @param {Function} fcn The function to call before the original
107 * @param {<i>Object</i>} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
108 * @return {Function} The new function
109 */
110Function.prototype.createInterceptor = function(fcn, scope){
111 if(typeof fcn != 'function'){
112 return this;
113 }
114 var method = this;
115 return function() {
116 fcn.target = this;
117 fcn.method = method;
118 if(fcn.apply(scope || this || window, arguments) === false){
119 return;
120 }
121 return method.apply(this || window, arguments);;
122 };
123};
124
125/**
126 * @class YAHOO.ext.util.Browser
127 * @singleton
128 */
129YAHOO.ext.util.Browser = new function(){
130 var ua = navigator.userAgent.toLowerCase();
131 /** @type Boolean */
132 this.isOpera = (ua.indexOf('opera') > -1);
133 /** @type Boolean */
134 this.isSafari = (ua.indexOf('webkit') > -1);
135 /** @type Boolean */
136 this.isIE = (window.ActiveXObject);
137 /** @type Boolean */
138 this.isIE7 = (ua.indexOf('msie 7') > -1);
139 /** @type Boolean */
140 this.isGecko = !this.isSafari && (ua.indexOf('gecko') > -1);
141
142 if(ua.indexOf("windows") != -1 || ua.indexOf("win32") != -1){
143 /** @type Boolean */
144 this.isWindows = true;
145 }else if(ua.indexOf("macintosh") != -1){
146 /** @type Boolean */
147 this.isMac = true;
148 }
149 if(this.isIE && !this.isIE7){
150 try{
151 document.execCommand("BackgroundImageCache", false, true);
152 }catch(e){}
153 }
154}();
155
156 /**
157 * Enable custom handler signature and event cancelling. Using fireDirect() instead of fire() calls the subscribed event handlers
158 * with the exact parameters passed to fireDirect, instead of the usual (eventType, args[], obj). IMO this is more intuitive
159 * and promotes cleaner code. Also, if an event handler returns false, it is returned by fireDirect and no other handlers will be called.<br>
160 * Example:<br><br><pre><code>
161 * if(beforeUpdateEvent.fireDirect(myArg, myArg2) !== false){
162 * // do update
163 * }</code></pre>
164 */
165YAHOO.util.CustomEvent.prototype.fireDirect = function(){
166 var len=this.subscribers.length;
167 for (var i=0; i<len; ++i) {
168 var s = this.subscribers[i];
169 if(s){
170 var scope = (s.override) ? s.obj : this.scope;
171 if(s.fn.apply(scope, arguments) === false){
172 return false;
173 }
174 }
175 }
176 return true;
177};
178
179/**
180 * @class YAHOO-
181 * Additional functionality for the global YAHOO object.
182 * @singleton
183 */
184/**
185 * Prints all arguments to a resizable, movable, scrolling region without
186 * the need to include separate js or css. Double click it to hide it.
187 * @param {Mixed} arg1
188 * @param {Mixed} arg2
189 * @param {Mixed} etc
190 * @static
191 */
192YAHOO.print = function(arg1, arg2, etc){
193 if(!YAHOO.ext._console){
194 var cs = YAHOO.ext.DomHelper.insertBefore(document.body.firstChild,
195 {tag: 'div',style:'width:250px;height:350px;overflow:auto;border:3px solid #c3daf9;' +
196 'background:white;position:absolute;right:5px;top:5px;' +
197 'font:normal 8pt arial,verdana,helvetica;z-index:50000;padding:5px;'}, true);
198 if(YAHOO.ext.Resizable){
199 new YAHOO.ext.Resizable(cs, {
200 transparent:true,
201 handles: 'all',
202 pinned:true,
203 adjustments: [0,0],
204 wrap:true,
205 draggable:(YAHOO.util.DD ? true : false)
206 });
207 }
208 cs.on('dblclick', cs.hide);
209 YAHOO.ext._console = cs;
210 }
211 var m = '';
212 for(var i = 0, len = arguments.length; i < len; i++) {
213 m += (i == 0 ? '' : ', ') + arguments[i];
214 }
215 m += '<hr noshade style="color:#eeeeee;" size="1">'
216 var d = YAHOO.ext._console.dom;
217 d.innerHTML = m + d.innerHTML;
218 d.scrollTop = 0;
219 YAHOO.ext._console.show();
220};
221
222/**
223 * Applies the passed C#/DomHelper style format (e.g. "The variable {0} is equal to {1}") before calling {@link YAHOO#print}
224 * @param {String} format
225 * @param {Mixed} arg1
226 * @param {Mixed} arg2
227 * @param {Mixed} etc
228 * @static
229 */
230YAHOO.printf = function(format, arg1, arg2, etc){
231 var args = Array.prototype.slice.call(arguments, 1);
232 YAHOO.print(format.replace(
233 /\{\{[^{}]*\}\}|\{(\d+)(,\s*([\w.]+))?\}/g,
234 function(m, a1, a2, a3) {
235 if (m.chatAt == '{') {
236 return m.slice(1, -1);
237 }
238 var rpl = args[a1];
239 if (a3) {
240 var f = eval(a3);
241 rpl = f(rpl);
242 }
243 return rpl ? rpl : '';
244 }));
245}
246
247YAHOO._timers = {};
248/**
249 * If a timer with specified name doesn't exist it is started. If one exists and reset is not true
250 * it prints the ellapsed time since the start using YAHOO.printf.
251 * @param {String} name
252 * @param {Boolean} reset true to reset an existing timer
253 */
254YAHOO.timer = function(name, reset){
255 var t = new Date().getTime();
256 if(YAHOO._timers[name] && !reset){
257 YAHOO.printf("{0} : {1} ms", name, t-YAHOO._timers[name]);
258 }else{
259 YAHOO._timers[name] = t;
260 }
261}
262/**
263 * Extends one class with another class and optionally overrides members with the passed literal. This class
264 * also adds the function "override()" to the class that can be used to override
265 * members on an instance.
266 * @param {Object} subclass The class inheriting the functionality
267 * @param {Object} superclass The class being extended
268 * @param {Object} overrides (optional) A literal with members
269 * @static
270 */
271YAHOO.extendX = function(subclass, superclass, overrides){
272 YAHOO.extend(subclass, superclass);
273 subclass.override = function(o){
274 YAHOO.override(subclass, o);
275 };
276 if(!subclass.prototype.override){
277 subclass.prototype.override = function(o){
278 for(var method in o){
279 this[method] = o[method];
280 }
281 };
282 }
283 if(overrides){
284 subclass.override(overrides);
285 }
286};
287
288/**
289 * Creates namespaces but does not assume YAHOO is the root.
290 * @param {String} namespace1
291 * @param {String} namespace2
292 * @param {String} etc
293 * @static
294 */
295YAHOO.namespaceX = function(){
296 var a = arguments, len = a.length, i;
297 YAHOO.namespace.apply(YAHOO, a);
298 for(i = 0; i < len; i++){
299 var p = a[i].split('.')[0];
300 if(p != 'YAHOO' && YAHOO[p]){
301 eval(p + ' = YAHOO.' + p);
302 delete YAHOO[p];
303 }
304 }
305};
306
307YAHOO.override = function(origclass, overrides){
308 if(overrides){
309 var p = origclass.prototype;
310 for(var method in overrides){
311 p[method] = overrides[method];
312 }
313 }
314};
315
316/**
317 * @class YAHOO.ext.util.DelayedTask
318 * Provides a convenient method of performing setTimeout where a new
319 * timeout cancels the old timeout. An example would be performing validation on a keypress.
320 * You can use this class to buffer
321 * the keypress events for a certain number of milliseconds, and perform only if they stop
322 * for that amount of time.
323 * @constructor The parameters to this constructor serve as defaults and are not required.
324 * @param {<i>Function</i>} fn (optional) The default function to timeout
325 * @param {<i>Object</i>} scope (optional) The default scope of that timeout
326 * @param {<i>Array</i>} args (optional) The default Array of arguments
327 */
328YAHOO.ext.util.DelayedTask = function(fn, scope, args){
329 var timeoutId = null;
330
331 /**
332 * Cancels any pending timeout and queues a new one
333 * @param {Number} delay The milliseconds to delay
334 * @param {Function} newFn (optional) Overrides function passed to constructor
335 * @param {Object} newScope (optional) Overrides scope passed to constructor
336 * @param {Array} newArgs (optional) Overrides args passed to constructor
337 */
338 this.delay = function(delay, newFn, newScope, newArgs){
339 if(timeoutId){
340 clearTimeout(timeoutId);
341 }
342 fn = newFn || fn;
343 scope = newScope || scope;
344 args = newArgs || args;
345 timeoutId = setTimeout(fn.createDelegate(scope, args), delay);
346 };
347
348 /**
349 * Cancel the last queued timeout
350 */
351 this.cancel = function(){
352 if(timeoutId){
353 clearTimeout(timeoutId);
354 timeoutId = null;
355 }
356 };
357};
358
359/**
360 * @class YAHOO.ext.util.Observable
361 * Abstract base class that provides a common interface for publishing events. Subclasses are expected to
362 * to have a property "events" with all the events defined.<br>
363 * For example:
364 * <pre><code>
365 var Employee = function(name){
366 this.name = name;
367 this.events = {
368 'fired' : new YAHOO.util.CustomEvent('fired'),
369 'quit' : true // lazy initialize the CustomEvent
370 }
371 }
372 YAHOO.extend(Employee, YAHOO.ext.util.Observable);
373</code></pre>
374 */
375YAHOO.ext.util.Observable = function(){};
376YAHOO.ext.util.Observable.prototype = {
377 /**
378 * Fires the specified event with the passed parameters (minus the event name).
379 * @param {String} eventName
380 * @param {Object...} args Variable number of parameters are passed to handlers
381 * @return {Boolean} returns false if any of the handlers return false otherwise it returns true
382 */
383 fireEvent : function(){
384 var ce = this.events[arguments[0].toLowerCase()];
385 if(typeof ce == 'object'){
386 return ce.fireDirect.apply(ce, Array.prototype.slice.call(arguments, 1));
387 }else{
388 return true;
389 }
390 },
391 /**
392 * Appends an event handler to this component
393 * @param {String} eventName The type of event to listen for
394 * @param {Function} handler The method the event invokes
395 * @param {<i>Object</i>} scope (optional) The scope (this object) for the handler
396 * @param {<i>boolean</i>} override (optional) If true, scope becomes the scope
397 */
398 addListener : function(eventName, fn, scope, override){
399 eventName = eventName.toLowerCase();
400 var ce = this.events[eventName];
401 if(!ce){
402 // added for a better message when subscribing to wrong event
403 throw 'You are trying to listen for an event that does not exist: "' + eventName + '".';
404 }
405 if(typeof ce == 'boolean'){
406 ce = new YAHOO.util.CustomEvent(eventName);
407 this.events[eventName] = ce;
408 }
409 ce.subscribe(fn, scope, override);
410 },
411
412 /**
413 * Appends an event handler to this component that is delayed the specified number of milliseconds. This
414 * is useful for events that modify the DOM and need to wait for the browser to catch up.
415 * @param {String} eventName The type of event to listen for
416 * @param {Function} handler The method the event invokes
417 * @param {<i>Object</i>} scope (optional) The scope (this object) for the handler
418 * @param {<i>Number</i>} delay (optional) The number of milliseconds to delay (defaults to 1 millisecond)
419 * @return {Function} The wrapped function that was created (can be used to remove the listener)
420 */
421 delayedListener : function(eventName, fn, scope, delay){
422 var newFn = function(){
423 setTimeout(fn.createDelegate(scope, arguments), delay || 1);
424 }
425 this.addListener(eventName, newFn);
426 return newFn;
427 },
428
429 /**
430 * Appends an event handler to this component that is buffered. If the event is triggered more than once
431 * in the specified time-frame, only the last one actually fires.
432 * @param {String} eventName The type of event to listen for
433 * @param {Function} handler The method the event invokes
434 * @param {<i>Object</i>} scope (optional) The scope (this object) for the handler
435 * @param {<i>Number</i>} millis (optional) The number of milliseconds to buffer (defaults to 250)
436 * @return {Function} The wrapped function that was created (can be used to remove the listener)
437 */
438 bufferedListener : function(eventName, fn, scope, millis){
439 var task = new YAHOO.ext.util.DelayedTask();
440 var newFn = function(){
441 task.delay(millis || 250, fn, scope, Array.prototype.slice.call(arguments, 0));
442 }
443 this.addListener(eventName, newFn);
444 return newFn;
445 },
446
447 /**
448 * Removes a listener
449 * @param {String} eventName The type of event to listen for
450 * @param {Function} handler The handler to remove
451 * @param {<i>Object</i>} scope (optional) The scope (this object) for the handler
452 */
453 removeListener : function(eventName, fn, scope){
454 var ce = this.events[eventName.toLowerCase()];
455 if(typeof ce == 'object'){
456 ce.unsubscribe(fn, scope);
457 }
458 },
459
460 /**
461 * Removes all listeners for this object
462 */
463 purgeListeners : function(){
464 for(var evt in this.events){
465 if(typeof this.events[evt] == 'object'){
466 this.events[evt].unsubscribeAll();
467 }
468 }
469 }
470};
471/**
472 * Appends an event handler to this element (shorthand for addListener)
473 * @param {String} eventName The type of event to listen for
474 * @param {Function} handler The method the event invokes
475 * @param {<i>Object</i>} scope (optional) The scope (this object) for the handler
476 * @param {<i>boolean</i>} override (optional) If true, scope becomes the scope
477 * @method
478 */
479YAHOO.ext.util.Observable.prototype.on = YAHOO.ext.util.Observable.prototype.addListener;
480
481/**
482 * Starts capture on the specified Observable. All events will be passed
483 * to the supplied function with the event name + standard signature of the event
484 * <b>before</b> the event is fired. If the supplied function returns false,
485 * the event will not fire.
486 * @param {Observable} o The Observable to capture
487 * @param {Function} fn The function to call
488 * @param {Object} scope (optional) The scope (this object) for the fn
489 * @static
490 */
491YAHOO.ext.util.Observable.capture = function(o, fn, scope){
492 o.fireEvent = o.fireEvent.createInterceptor(fn, scope);
493};
494
495/**
496 * Removes <b>all</b> added captures from the Observable.
497 * @param {Observable} o The Observable to release
498 * @static
499 */
500YAHOO.ext.util.Observable.releaseCapture = function(o){
501 o.fireEvent = YAHOO.ext.util.Observable.prototype.fireEvent;
502};
503
504/**
505 * @class YAHOO.ext.util.Config
506 * Class with one useful method
507 * @singleton
508 */
509YAHOO.ext.util.Config = {
510 /**
511 * Copies all the properties of config to obj.
512 * @param {Object} obj The receiver of the properties
513 * @param {Object} config The source of the properties
514 * @param {Object} defaults A different object that will also be applied for default values
515 * @return {Object} returns obj
516 */
517 apply : function(obj, config, defaults){
518 if(defaults){
519 this.apply(obj, defaults);
520 }
521 if(config){
522 for(var prop in config){
523 obj[prop] = config[prop];
524 }
525 }
526 return obj;
527 }
528};
529
530if(!String.escape){
531 String.escape = function(string) {
532 return string.replace(/('|\\)/g, "\\$1");
533 };
534};
535
536String.leftPad = function (val, size, ch) {
537 var result = new String(val);
538 if (ch == null) {
539 ch = " ";
540 }
541 while (result.length < size) {
542 result = ch + result;
543 }
544 return result;
545};
546
547// workaround for Safari anim duration speed problems
548if(YAHOO.util.AnimMgr && YAHOO.ext.util.Browser.isSafari){
549 YAHOO.util.AnimMgr.fps = 500;
550}
551
552// add ability for callbacks instead of events for animations
553if(YAHOO.util.Anim){
554 YAHOO.util.Anim.prototype.animateX = function(callback, scope){
555 var f = function(){
556 this.onComplete.unsubscribe(f);
557 if(typeof callback == 'function'){
558 callback.call(scope || this, this);
559 }
560 };
561 this.onComplete.subscribe(f, this, true);
562 this.animate();
563 };
564}
565
566// workaround for Safari 1.3 not supporting hasOwnProperty
567if(YAHOO.util.Connect && YAHOO.ext.util.Browser.isSafari){
568 YAHOO.util.Connect.setHeader = function(o){
569 for(var prop in this._http_header){
570 // if(this._http_header.hasOwnProperty(prop)){
571 if(typeof this._http_header[prop] != 'function'){
572 o.conn.setRequestHeader(prop, this._http_header[prop]);
573 }
574 }
575 delete this._http_header;
576 this._http_header = {};
577 this._has_http_headers = false;
578 };
579}
580/**
581 * A simple enhancement to drag drop that allows you to constrain the movement of the
582 * DD or DDProxy object to a particular element.<br /><br />
583 *
584 * Usage:
585 <pre><code>
586 var dd = new YAHOO.util.DDProxy("dragDiv1", "proxytest",
587 { dragElId: "existingProxyDiv" });
588 dd.startDrag = function(){
589 this.constrainTo('parent-id');
590 };
591 </code></pre>
592 * Or you can initalize it using the {@link YAHOO.ext.Element} object:
593 <pre><code>
594 getEl('dragDiv1').initDDProxy('proxytest', {dragElId: "existingProxyDiv"}, {
595 startDrag : function(){
596 this.constrainTo('parent-id');
597 }
598 });
599 </code></pre>
600 */
601if(YAHOO.util.DragDrop){
602 /**
603 * Provides default constraint padding to "constrainTo" elements (defaults to {left: 0, right:0, top:0, bottom:0}).
604 * @type Object
605 */
606 YAHOO.util.DragDrop.prototype.defaultPadding = {left:0, right:0, top:0, bottom:0};
607
608 /**
609 * Initializes the drag drop object's constraints to restrict movement to a certain element.
610 * @param {String/HTMLElement/Element} constrainTo The element to constrain to.
611 * @param {Object/Number} pad (optional) Pad provides a way to specify "padding" of the constraints,
612 * and can be either a number for symmetrical padding (4 would be equal to {left:4, right:4, top:4, bottom:4}) or
613 * an object containing the sides to pad. For example: {right:10, bottom:10}
614 * @param {Boolean} inContent (optional) Constrain the draggable in the content box of the element (inside padding and borders)
615 */
616 YAHOO.util.DragDrop.prototype.constrainTo = function(constrainTo, pad, inContent){
617 if(typeof pad == 'number'){
618 pad = {left: pad, right:pad, top:pad, bottom:pad};
619 }
620 pad = pad || this.defaultPadding;
621 var b = getEl(this.getEl()).getBox();
622 var ce = getEl(constrainTo);
623 var c = ce.dom == document.body ? { x: 0, y: 0,
624 width: YAHOO.util.Dom.getViewportWidth(),
625 height: YAHOO.util.Dom.getViewportHeight()} : ce.getBox(inContent || false);
626 var topSpace = b.y - c.y;
627 var leftSpace = b.x - c.x;
628
629 this.resetConstraints();
630 this.setXConstraint(leftSpace - (pad.left||0), // left
631 c.width - leftSpace - b.width - (pad.right||0) //right
632 );
633 this.setYConstraint(topSpace - (pad.top||0), //top
634 c.height - topSpace - b.height - (pad.bottom||0) //bottom
635 );
636 }
637}
diff --git a/frontend/beta/js/YUI/animation.js b/frontend/beta/js/YUI/animation.js
new file mode 100644
index 0000000..333f946
--- a/dev/null
+++ b/frontend/beta/js/YUI/animation.js
@@ -0,0 +1,1272 @@
1/*
2Copyright (c) 2006, Yahoo! Inc. All rights reserved.
3Code licensed under the BSD License:
4http://developer.yahoo.net/yui/license.txt
5version: 0.12.0
6*/
7
8/**
9 * The animation module provides allows effects to be added to HTMLElements.
10 * @module animation
11 */
12
13/**
14 *
15 * Base animation class that provides the interface for building animated effects.
16 * <p>Usage: var myAnim = new YAHOO.util.Anim(el, { width: { from: 10, to: 100 } }, 1, YAHOO.util.Easing.easeOut);</p>
17 * @class Anim
18 * @namespace YAHOO.util
19 * @requires YAHOO.util.AnimMgr
20 * @requires YAHOO.util.Easing
21 * @requires YAHOO.util.Dom
22 * @requires YAHOO.util.Event
23 * @requires YAHOO.util.CustomEvent
24 * @constructor
25 * @param {String | HTMLElement} el Reference to the element that will be animated
26 * @param {Object} attributes The attribute(s) to be animated.
27 * Each attribute is an object with at minimum a "to" or "by" member defined.
28 * Additional optional members are "from" (defaults to current value), "units" (defaults to "px").
29 * All attribute names use camelCase.
30 * @param {Number} duration (optional, defaults to 1 second) Length of animation (frames or seconds), defaults to time-based
31 * @param {Function} method (optional, defaults to YAHOO.util.Easing.easeNone) Computes the values that are applied to the attributes per frame (generally a YAHOO.util.Easing method)
32 */
33
34YAHOO.util.Anim = function(el, attributes, duration, method) {
35 if (el) {
36 this.init(el, attributes, duration, method);
37 }
38};
39
40YAHOO.util.Anim.prototype = {
41 /**
42 * Provides a readable name for the Anim instance.
43 * @method toString
44 * @return {String}
45 */
46 toString: function() {
47 var el = this.getEl();
48 var id = el.id || el.tagName;
49 return ("Anim " + id);
50 },
51
52 patterns: { // cached for performance
53 noNegatives: /width|height|opacity|padding/i, // keep at zero or above
54 offsetAttribute: /^((width|height)|(top|left))$/, // use offsetValue as default
55 defaultUnit: /width|height|top$|bottom$|left$|right$/i, // use 'px' by default
56 offsetUnit: /\d+(em|%|en|ex|pt|in|cm|mm|pc)$/i // IE may return these, so convert these to offset
57 },
58
59 /**
60 * Returns the value computed by the animation's "method".
61 * @method doMethod
62 * @param {String} attr The name of the attribute.
63 * @param {Number} start The value this attribute should start from for this animation.
64 * @param {Number} end The value this attribute should end at for this animation.
65 * @return {Number} The Value to be applied to the attribute.
66 */
67 doMethod: function(attr, start, end) {
68 return this.method(this.currentFrame, start, end - start, this.totalFrames);
69 },
70
71 /**
72 * Applies a value to an attribute.
73 * @method setAttribute
74 * @param {String} attr The name of the attribute.
75 * @param {Number} val The value to be applied to the attribute.
76 * @param {String} unit The unit ('px', '%', etc.) of the value.
77 */
78 setAttribute: function(attr, val, unit) {
79 if ( this.patterns.noNegatives.test(attr) ) {
80 val = (val > 0) ? val : 0;
81 }
82
83 YAHOO.util.Dom.setStyle(this.getEl(), attr, val + unit);
84 },
85
86 /**
87 * Returns current value of the attribute.
88 * @method getAttribute
89 * @param {String} attr The name of the attribute.
90 * @return {Number} val The current value of the attribute.
91 */
92 getAttribute: function(attr) {
93 var el = this.getEl();
94 var val = YAHOO.util.Dom.getStyle(el, attr);
95
96 if (val !== 'auto' && !this.patterns.offsetUnit.test(val)) {
97 return parseFloat(val);
98 }
99
100 var a = this.patterns.offsetAttribute.exec(attr) || [];
101 var pos = !!( a[3] ); // top or left
102 var box = !!( a[2] ); // width or height
103
104 // use offsets for width/height and abs pos top/left
105 if ( box || (YAHOO.util.Dom.getStyle(el, 'position') == 'absolute' && pos) ) {
106 val = el['offset' + a[0].charAt(0).toUpperCase() + a[0].substr(1)];
107 } else { // default to zero for other 'auto'
108 val = 0;
109 }
110
111 return val;
112 },
113
114 /**
115 * Returns the unit to use when none is supplied.
116 * @method getDefaultUnit
117 * @param {attr} attr The name of the attribute.
118 * @return {String} The default unit to be used.
119 */
120 getDefaultUnit: function(attr) {
121 if ( this.patterns.defaultUnit.test(attr) ) {
122 return 'px';
123 }
124
125 return '';
126 },
127
128 /**
129 * Sets the actual values to be used during the animation.
130 * @method setRuntimeAttribute
131 * Should only be needed for subclass use.
132 * @param {Object} attr The attribute object
133 * @private
134 */
135 setRuntimeAttribute: function(attr) {
136 var start;
137 var end;
138 var attributes = this.attributes;
139
140 this.runtimeAttributes[attr] = {};
141
142 var isset = function(prop) {
143 return (typeof prop !== 'undefined');
144 };
145
146 if ( !isset(attributes[attr]['to']) && !isset(attributes[attr]['by']) ) {
147 return false; // note return; nothing to animate to
148 }
149
150 start = ( isset(attributes[attr]['from']) ) ? attributes[attr]['from'] : this.getAttribute(attr);
151
152 // To beats by, per SMIL 2.1 spec
153 if ( isset(attributes[attr]['to']) ) {
154 end = attributes[attr]['to'];
155 } else if ( isset(attributes[attr]['by']) ) {
156 if (start.constructor == Array) {
157 end = [];
158 for (var i = 0, len = start.length; i < len; ++i) {
159 end[i] = start[i] + attributes[attr]['by'][i];
160 }
161 } else {
162 end = start + attributes[attr]['by'];
163 }
164 }
165
166 this.runtimeAttributes[attr].start = start;
167 this.runtimeAttributes[attr].end = end;
168
169 // set units if needed
170 this.runtimeAttributes[attr].unit = ( isset(attributes[attr].unit) ) ? attributes[attr]['unit'] : this.getDefaultUnit(attr);
171 },
172
173 /**
174 * Constructor for Anim instance.
175 * @method init
176 * @param {String | HTMLElement} el Reference to the element that will be animated
177 * @param {Object} attributes The attribute(s) to be animated.
178 * Each attribute is an object with at minimum a "to" or "by" member defined.
179 * Additional optional members are "from" (defaults to current value), "units" (defaults to "px").
180 * All attribute names use camelCase.
181 * @param {Number} duration (optional, defaults to 1 second) Length of animation (frames or seconds), defaults to time-based
182 * @param {Function} method (optional, defaults to YAHOO.util.Easing.easeNone) Computes the values that are applied to the attributes per frame (generally a YAHOO.util.Easing method)
183 */
184 init: function(el, attributes, duration, method) {
185 /**
186 * Whether or not the animation is running.
187 * @property isAnimated
188 * @private
189 * @type Boolean
190 */
191 var isAnimated = false;
192
193 /**
194 * A Date object that is created when the animation begins.
195 * @property startTime
196 * @private
197 * @type Date
198 */
199 var startTime = null;
200
201 /**
202 * The number of frames this animation was able to execute.
203 * @property actualFrames
204 * @private
205 * @type Int
206 */
207 var actualFrames = 0;
208
209 /**
210 * The element to be animated.
211 * @property el
212 * @private
213 * @type HTMLElement
214 */
215 el = YAHOO.util.Dom.get(el);
216
217 /**
218 * The collection of attributes to be animated.
219 * Each attribute must have at least a "to" or "by" defined in order to animate.
220 * If "to" is supplied, the animation will end with the attribute at that value.
221 * If "by" is supplied, the animation will end at that value plus its starting value.
222 * If both are supplied, "to" is used, and "by" is ignored.
223 * Optional additional member include "from" (the value the attribute should start animating from, defaults to current value), and "unit" (the units to apply to the values).
224 * @property attributes
225 * @type Object
226 */
227 this.attributes = attributes || {};
228
229 /**
230 * The length of the animation. Defaults to "1" (second).
231 * @property duration
232 * @type Number
233 */
234 this.duration = duration || 1;
235
236 /**
237 * The method that will provide values to the attribute(s) during the animation.
238 * Defaults to "YAHOO.util.Easing.easeNone".
239 * @property method
240 * @type Function
241 */
242 this.method = method || YAHOO.util.Easing.easeNone;
243
244 /**
245 * Whether or not the duration should be treated as seconds.
246 * Defaults to true.
247 * @property useSeconds
248 * @type Boolean
249 */
250 this.useSeconds = true; // default to seconds
251
252 /**
253 * The location of the current animation on the timeline.
254 * In time-based animations, this is used by AnimMgr to ensure the animation finishes on time.
255 * @property currentFrame
256 * @type Int
257 */
258 this.currentFrame = 0;
259
260 /**
261 * The total number of frames to be executed.
262 * In time-based animations, this is used by AnimMgr to ensure the animation finishes on time.
263 * @property totalFrames
264 * @type Int
265 */
266 this.totalFrames = YAHOO.util.AnimMgr.fps;
267
268
269 /**
270 * Returns a reference to the animated element.
271 * @method getEl
272 * @return {HTMLElement}
273 */
274 this.getEl = function() { return el; };
275
276 /**
277 * Checks whether the element is currently animated.
278 * @method isAnimated
279 * @return {Boolean} current value of isAnimated.
280 */
281 this.isAnimated = function() {
282 return isAnimated;
283 };
284
285 /**
286 * Returns the animation start time.
287 * @method getStartTime
288 * @return {Date} current value of startTime.
289 */
290 this.getStartTime = function() {
291 return startTime;
292 };
293
294 this.runtimeAttributes = {};
295
296
297
298 /**
299 * Starts the animation by registering it with the animation manager.
300 * @method animate
301 */
302 this.animate = function() {
303 if ( this.isAnimated() ) { return false; }
304
305 this.currentFrame = 0;
306
307 this.totalFrames = ( this.useSeconds ) ? Math.ceil(YAHOO.util.AnimMgr.fps * this.duration) : this.duration;
308
309 YAHOO.util.AnimMgr.registerElement(this);
310 };
311
312 /**
313 * Stops the animation. Normally called by AnimMgr when animation completes.
314 * @method stop
315 * @param {Boolean} finish (optional) If true, animation will jump to final frame.
316 */
317 this.stop = function(finish) {
318 if (finish) {
319 this.currentFrame = this.totalFrames;
320 this._onTween.fire();
321 }
322 YAHOO.util.AnimMgr.stop(this);
323 };
324
325 var onStart = function() {
326 this.onStart.fire();
327
328 this.runtimeAttributes = {};
329 for (var attr in this.attributes) {
330 this.setRuntimeAttribute(attr);
331 }
332
333 isAnimated = true;
334 actualFrames = 0;
335 startTime = new Date();
336 };
337
338 /**
339 * Feeds the starting and ending values for each animated attribute to doMethod once per frame, then applies the resulting value to the attribute(s).
340 * @private
341 */
342
343 var onTween = function() {
344 var data = {
345 duration: new Date() - this.getStartTime(),
346 currentFrame: this.currentFrame
347 };
348
349 data.toString = function() {
350 return (
351 'duration: ' + data.duration +
352 ', currentFrame: ' + data.currentFrame
353 );
354 };
355
356 this.onTween.fire(data);
357
358 var runtimeAttributes = this.runtimeAttributes;
359
360 for (var attr in runtimeAttributes) {
361 this.setAttribute(attr, this.doMethod(attr, runtimeAttributes[attr].start, runtimeAttributes[attr].end), runtimeAttributes[attr].unit);
362 }
363
364 actualFrames += 1;
365 };
366
367 var onComplete = function() {
368 var actual_duration = (new Date() - startTime) / 1000 ;
369
370 var data = {
371 duration: actual_duration,
372 frames: actualFrames,
373 fps: actualFrames / actual_duration
374 };
375
376 data.toString = function() {
377 return (
378 'duration: ' + data.duration +
379 ', frames: ' + data.frames +
380 ', fps: ' + data.fps
381 );
382 };
383
384 isAnimated = false;
385 actualFrames = 0;
386 this.onComplete.fire(data);
387 };
388
389 /**
390 * Custom event that fires after onStart, useful in subclassing
391 * @private
392 */
393 this._onStart = new YAHOO.util.CustomEvent('_start', this, true);
394
395 /**
396 * Custom event that fires when animation begins
397 * Listen via subscribe method (e.g. myAnim.onStart.subscribe(someFunction)
398 * @event onStart
399 */
400 this.onStart = new YAHOO.util.CustomEvent('start', this);
401
402 /**
403 * Custom event that fires between each frame
404 * Listen via subscribe method (e.g. myAnim.onTween.subscribe(someFunction)
405 * @event onTween
406 */
407 this.onTween = new YAHOO.util.CustomEvent('tween', this);
408
409 /**
410 * Custom event that fires after onTween
411 * @private
412 */
413 this._onTween = new YAHOO.util.CustomEvent('_tween', this, true);
414
415 /**
416 * Custom event that fires when animation ends
417 * Listen via subscribe method (e.g. myAnim.onComplete.subscribe(someFunction)
418 * @event onComplete
419 */
420 this.onComplete = new YAHOO.util.CustomEvent('complete', this);
421 /**
422 * Custom event that fires after onComplete
423 * @private
424 */
425 this._onComplete = new YAHOO.util.CustomEvent('_complete', this, true);
426
427 this._onStart.subscribe(onStart);
428 this._onTween.subscribe(onTween);
429 this._onComplete.subscribe(onComplete);
430 }
431};
432
433/**
434 * Handles animation queueing and threading.
435 * Used by Anim and subclasses.
436 * @class AnimMgr
437 * @namespace YAHOO.util
438 */
439YAHOO.util.AnimMgr = new function() {
440 /**
441 * Reference to the animation Interval.
442 * @property thread
443 * @private
444 * @type Int
445 */
446 var thread = null;
447
448 /**
449 * The current queue of registered animation objects.
450 * @property queue
451 * @private
452 * @type Array
453 */
454 var queue = [];
455
456 /**
457 * The number of active animations.
458 * @property tweenCount
459 * @private
460 * @type Int
461 */
462 var tweenCount = 0;
463
464 /**
465 * Base frame rate (frames per second).
466 * Arbitrarily high for better x-browser calibration (slower browsers drop more frames).
467 * @property fps
468 * @type Int
469 *
470 */
471 this.fps = 200;
472
473 /**
474 * Interval delay in milliseconds, defaults to fastest possible.
475 * @property delay
476 * @type Int
477 *
478 */
479 this.delay = 1;
480
481 /**
482 * Adds an animation instance to the animation queue.
483 * All animation instances must be registered in order to animate.
484 * @method registerElement
485 * @param {object} tween The Anim instance to be be registered
486 */
487 this.registerElement = function(tween) {
488 queue[queue.length] = tween;
489 tweenCount += 1;
490 tween._onStart.fire();
491 this.start();
492 };
493
494 /**
495 * removes an animation instance from the animation queue.
496 * All animation instances must be registered in order to animate.
497 * @method unRegister
498 * @param {object} tween The Anim instance to be be registered
499 * @param {Int} index The index of the Anim instance
500 * @private
501 */
502 this.unRegister = function(tween, index) {
503 tween._onComplete.fire();
504 index = index || getIndex(tween);
505 if (index != -1) { queue.splice(index, 1); }
506
507 tweenCount -= 1;
508 if (tweenCount <= 0) { this.stop(); }
509 };
510
511 /**
512 * Starts the animation thread.
513 * Only one thread can run at a time.
514 * @method start
515 */
516 this.start = function() {
517 if (thread === null) { thread = setInterval(this.run, this.delay); }
518 };
519
520 /**
521 * Stops the animation thread or a specific animation instance.
522 * @method stop
523 * @param {object} tween A specific Anim instance to stop (optional)
524 * If no instance given, Manager stops thread and all animations.
525 */
526 this.stop = function(tween) {
527 if (!tween) {
528 clearInterval(thread);
529 for (var i = 0, len = queue.length; i < len; ++i) {
530 if (queue[i].isAnimated()) {
531 this.unRegister(tween, i);
532 }
533 }
534 queue = [];
535 thread = null;
536 tweenCount = 0;
537 }
538 else {
539 this.unRegister(tween);
540 }
541 };
542
543 /**
544 * Called per Interval to handle each animation frame.
545 * @method run
546 */
547 this.run = function() {
548 for (var i = 0, len = queue.length; i < len; ++i) {
549 var tween = queue[i];
550 if ( !tween || !tween.isAnimated() ) { continue; }
551
552 if (tween.currentFrame < tween.totalFrames || tween.totalFrames === null)
553 {
554 tween.currentFrame += 1;
555
556 if (tween.useSeconds) {
557 correctFrame(tween);
558 }
559 tween._onTween.fire();
560 }
561 else { YAHOO.util.AnimMgr.stop(tween, i); }
562 }
563 };
564
565 var getIndex = function(anim) {
566 for (var i = 0, len = queue.length; i < len; ++i) {
567 if (queue[i] == anim) {
568 return i; // note return;
569 }
570 }
571 return -1;
572 };
573
574 /**
575 * On the fly frame correction to keep animation on time.
576 * @method correctFrame
577 * @private
578 * @param {Object} tween The Anim instance being corrected.
579 */
580 var correctFrame = function(tween) {
581 var frames = tween.totalFrames;
582 var frame = tween.currentFrame;
583 var expected = (tween.currentFrame * tween.duration * 1000 / tween.totalFrames);
584 var elapsed = (new Date() - tween.getStartTime());
585 var tweak = 0;
586
587 if (elapsed < tween.duration * 1000) { // check if falling behind
588 tweak = Math.round((elapsed / expected - 1) * tween.currentFrame);
589 } else { // went over duration, so jump to end
590 tweak = frames - (frame + 1);
591 }
592 if (tweak > 0 && isFinite(tweak)) { // adjust if needed
593 if (tween.currentFrame + tweak >= frames) {// dont go past last frame
594 tweak = frames - (frame + 1);
595 }
596
597 tween.currentFrame += tweak;
598 }
599 };
600};
601/**
602 * Used to calculate Bezier splines for any number of control points.
603 * @class Bezier
604 * @namespace YAHOO.util
605 *
606 */
607YAHOO.util.Bezier = new function()
608{
609 /**
610 * Get the current position of the animated element based on t.
611 * Each point is an array of "x" and "y" values (0 = x, 1 = y)
612 * At least 2 points are required (start and end).
613 * First point is start. Last point is end.
614 * Additional control points are optional.
615 * @method getPosition
616 * @param {Array} points An array containing Bezier points
617 * @param {Number} t A number between 0 and 1 which is the basis for determining current position
618 * @return {Array} An array containing int x and y member data
619 */
620 this.getPosition = function(points, t)
621 {
622 var n = points.length;
623 var tmp = [];
624
625 for (var i = 0; i < n; ++i){
626 tmp[i] = [points[i][0], points[i][1]]; // save input
627 }
628
629 for (var j = 1; j < n; ++j) {
630 for (i = 0; i < n - j; ++i) {
631 tmp[i][0] = (1 - t) * tmp[i][0] + t * tmp[parseInt(i + 1, 10)][0];
632 tmp[i][1] = (1 - t) * tmp[i][1] + t * tmp[parseInt(i + 1, 10)][1];
633 }
634 }
635
636 return [ tmp[0][0], tmp[0][1] ];
637
638 };
639};
640/**
641 * Anim subclass for color transitions.
642 * <p>Usage: <code>var myAnim = new Y.ColorAnim(el, { backgroundColor: { from: '#FF0000', to: '#FFFFFF' } }, 1, Y.Easing.easeOut);</code> Color values can be specified with either 112233, #112233,
643 * [255,255,255], or rgb(255,255,255)</p>
644 * @class ColorAnim
645 * @namespace YAHOO.util
646 * @requires YAHOO.util.Anim
647 * @requires YAHOO.util.AnimMgr
648 * @requires YAHOO.util.Easing
649 * @requires YAHOO.util.Bezier
650 * @requires YAHOO.util.Dom
651 * @requires YAHOO.util.Event
652 * @constructor
653 * @extends YAHOO.util.Anim
654 * @param {HTMLElement | String} el Reference to the element that will be animated
655 * @param {Object} attributes The attribute(s) to be animated.
656 * Each attribute is an object with at minimum a "to" or "by" member defined.
657 * Additional optional members are "from" (defaults to current value), "units" (defaults to "px").
658 * All attribute names use camelCase.
659 * @param {Number} duration (optional, defaults to 1 second) Length of animation (frames or seconds), defaults to time-based
660 * @param {Function} method (optional, defaults to YAHOO.util.Easing.easeNone) Computes the values that are applied to the attributes per frame (generally a YAHOO.util.Easing method)
661 */
662(function() {
663 YAHOO.util.ColorAnim = function(el, attributes, duration, method) {
664 YAHOO.util.ColorAnim.superclass.constructor.call(this, el, attributes, duration, method);
665 };
666
667 YAHOO.extend(YAHOO.util.ColorAnim, YAHOO.util.Anim);
668
669 // shorthand
670 var Y = YAHOO.util;
671 var superclass = Y.ColorAnim.superclass;
672 var proto = Y.ColorAnim.prototype;
673
674 proto.toString = function() {
675 var el = this.getEl();
676 var id = el.id || el.tagName;
677 return ("ColorAnim " + id);
678 };
679
680 proto.patterns.color = /color$/i;
681 proto.patterns.rgb = /^rgb\(([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\)$/i;
682 proto.patterns.hex = /^#?([0-9A-F]{2})([0-9A-F]{2})([0-9A-F]{2})$/i;
683 proto.patterns.hex3 = /^#?([0-9A-F]{1})([0-9A-F]{1})([0-9A-F]{1})$/i;
684 proto.patterns.transparent = /^transparent|rgba\(0, 0, 0, 0\)$/; // need rgba for safari
685
686 /**
687 * Attempts to parse the given string and return a 3-tuple.
688 * @method parseColor
689 * @param {String} s The string to parse.
690 * @return {Array} The 3-tuple of rgb values.
691 */
692 proto.parseColor = function(s) {
693 if (s.length == 3) { return s; }
694
695 var c = this.patterns.hex.exec(s);
696 if (c && c.length == 4) {
697 return [ parseInt(c[1], 16), parseInt(c[2], 16), parseInt(c[3], 16) ];
698 }
699
700 c = this.patterns.rgb.exec(s);
701 if (c && c.length == 4) {
702 return [ parseInt(c[1], 10), parseInt(c[2], 10), parseInt(c[3], 10) ];
703 }
704
705 c = this.patterns.hex3.exec(s);
706 if (c && c.length == 4) {
707 return [ parseInt(c[1] + c[1], 16), parseInt(c[2] + c[2], 16), parseInt(c[3] + c[3], 16) ];
708 }
709
710 return null;
711 };
712
713 proto.getAttribute = function(attr) {
714 var el = this.getEl();
715 if ( this.patterns.color.test(attr) ) {
716 var val = YAHOO.util.Dom.getStyle(el, attr);
717
718 if (this.patterns.transparent.test(val)) { // bgcolor default
719 var parent = el.parentNode; // try and get from an ancestor
720 val = Y.Dom.getStyle(parent, attr);
721
722 while (parent && this.patterns.transparent.test(val)) {
723 parent = parent.parentNode;
724 val = Y.Dom.getStyle(parent, attr);
725 if (parent.tagName.toUpperCase() == 'HTML') {
726 val = '#fff';
727 }
728 }
729 }
730 } else {
731 val = superclass.getAttribute.call(this, attr);
732 }
733
734 return val;
735 };
736
737 proto.doMethod = function(attr, start, end) {
738 var val;
739
740 if ( this.patterns.color.test(attr) ) {
741 val = [];
742 for (var i = 0, len = start.length; i < len; ++i) {
743 val[i] = superclass.doMethod.call(this, attr, start[i], end[i]);
744 }
745
746 val = 'rgb('+Math.floor(val[0])+','+Math.floor(val[1])+','+Math.floor(val[2])+')';
747 }
748 else {
749 val = superclass.doMethod.call(this, attr, start, end);
750 }
751
752 return val;
753 };
754
755 proto.setRuntimeAttribute = function(attr) {
756 superclass.setRuntimeAttribute.call(this, attr);
757
758 if ( this.patterns.color.test(attr) ) {
759 var attributes = this.attributes;
760 var start = this.parseColor(this.runtimeAttributes[attr].start);
761 var end = this.parseColor(this.runtimeAttributes[attr].end);
762 // fix colors if going "by"
763 if ( typeof attributes[attr]['to'] === 'undefined' && typeof attributes[attr]['by'] !== 'undefined' ) {
764 end = this.parseColor(attributes[attr].by);
765
766 for (var i = 0, len = start.length; i < len; ++i) {
767 end[i] = start[i] + end[i];
768 }
769 }
770
771 this.runtimeAttributes[attr].start = start;
772 this.runtimeAttributes[attr].end = end;
773 }
774 };
775})();/*
776TERMS OF USE - EASING EQUATIONS
777Open source under the BSD License.
778Copyright 2001 Robert Penner All rights reserved.
779
780Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
781
782 * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
783 * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
784 * Neither the name of the author nor the names of contributors may be used to endorse or promote products derived from this software without specific prior written permission.
785
786THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
787*/
788
789/**
790 * Singleton that determines how an animation proceeds from start to end.
791 * @class Easing
792 * @namespace YAHOO.util
793*/
794
795YAHOO.util.Easing = {
796
797 /**
798 * Uniform speed between points.
799 * @method easeNone
800 * @param {Number} t Time value used to compute current value
801 * @param {Number} b Starting value
802 * @param {Number} c Delta between start and end values
803 * @param {Number} d Total length of animation
804 * @return {Number} The computed value for the current animation frame
805 */
806 easeNone: function (t, b, c, d) {
807 return c*t/d + b;
808 },
809
810 /**
811 * Begins slowly and accelerates towards end. (quadratic)
812 * @method easeIn
813 * @param {Number} t Time value used to compute current value
814 * @param {Number} b Starting value
815 * @param {Number} c Delta between start and end values
816 * @param {Number} d Total length of animation
817 * @return {Number} The computed value for the current animation frame
818 */
819 easeIn: function (t, b, c, d) {
820 return c*(t/=d)*t + b;
821 },
822
823 /**
824 * Begins quickly and decelerates towards end. (quadratic)
825 * @method easeOut
826 * @param {Number} t Time value used to compute current value
827 * @param {Number} b Starting value
828 * @param {Number} c Delta between start and end values
829 * @param {Number} d Total length of animation
830 * @return {Number} The computed value for the current animation frame
831 */
832 easeOut: function (t, b, c, d) {
833 return -c *(t/=d)*(t-2) + b;
834 },
835
836 /**
837 * Begins slowly and decelerates towards end. (quadratic)
838 * @method easeBoth
839 * @param {Number} t Time value used to compute current value
840 * @param {Number} b Starting value
841 * @param {Number} c Delta between start and end values
842 * @param {Number} d Total length of animation
843 * @return {Number} The computed value for the current animation frame
844 */
845 easeBoth: function (t, b, c, d) {
846 if ((t/=d/2) < 1) return c/2*t*t + b;
847 return -c/2 * ((--t)*(t-2) - 1) + b;
848 },
849
850 /**
851 * Begins slowly and accelerates towards end. (quartic)
852 * @method easeInStrong
853 * @param {Number} t Time value used to compute current value
854 * @param {Number} b Starting value
855 * @param {Number} c Delta between start and end values
856 * @param {Number} d Total length of animation
857 * @return {Number} The computed value for the current animation frame
858 */
859 easeInStrong: function (t, b, c, d) {
860 return c*(t/=d)*t*t*t + b;
861 },
862
863 /**
864 * Begins quickly and decelerates towards end. (quartic)
865 * @method easeOutStrong
866 * @param {Number} t Time value used to compute current value
867 * @param {Number} b Starting value
868 * @param {Number} c Delta between start and end values
869 * @param {Number} d Total length of animation
870 * @return {Number} The computed value for the current animation frame
871 */
872 easeOutStrong: function (t, b, c, d) {
873 return -c * ((t=t/d-1)*t*t*t - 1) + b;
874 },
875
876 /**
877 * Begins slowly and decelerates towards end. (quartic)
878 * @method easeBothStrong
879 * @param {Number} t Time value used to compute current value
880 * @param {Number} b Starting value
881 * @param {Number} c Delta between start and end values
882 * @param {Number} d Total length of animation
883 * @return {Number} The computed value for the current animation frame
884 */
885 easeBothStrong: function (t, b, c, d) {
886 if ((t/=d/2) < 1) return c/2*t*t*t*t + b;
887 return -c/2 * ((t-=2)*t*t*t - 2) + b;
888 },
889
890 /**
891 * Snap in elastic effect.
892 * @method elasticIn
893 * @param {Number} t Time value used to compute current value
894 * @param {Number} b Starting value
895 * @param {Number} c Delta between start and end values
896 * @param {Number} d Total length of animation
897 * @param {Number} p Period (optional)
898 * @return {Number} The computed value for the current animation frame
899 */
900
901 elasticIn: function (t, b, c, d, a, p) {
902 if (t==0) return b; if ((t/=d)==1) return b+c; if (!p) p=d*.3;
903 if (!a || a < Math.abs(c)) { a=c; var s=p/4; }
904 else var s = p/(2*Math.PI) * Math.asin (c/a);
905 return -(a*Math.pow(2,10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )) + b;
906 },
907
908 /**
909 * Snap out elastic effect.
910 * @method elasticOut
911 * @param {Number} t Time value used to compute current value
912 * @param {Number} b Starting value
913 * @param {Number} c Delta between start and end values
914 * @param {Number} d Total length of animation
915 * @param {Number} p Period (optional)
916 * @return {Number} The computed value for the current animation frame
917 */
918 elasticOut: function (t, b, c, d, a, p) {
919 if (t==0) return b; if ((t/=d)==1) return b+c; if (!p) p=d*.3;
920 if (!a || a < Math.abs(c)) { a=c; var s=p/4; }
921 else var s = p/(2*Math.PI) * Math.asin (c/a);
922 return a*Math.pow(2,-10*t) * Math.sin( (t*d-s)*(2*Math.PI)/p ) + c + b;
923 },
924
925 /**
926 * Snap both elastic effect.
927 * @method elasticBoth
928 * @param {Number} t Time value used to compute current value
929 * @param {Number} b Starting value
930 * @param {Number} c Delta between start and end values
931 * @param {Number} d Total length of animation
932 * @param {Number} p Period (optional)
933 * @return {Number} The computed value for the current animation frame
934 */
935 elasticBoth: function (t, b, c, d, a, p) {
936 if (t==0) return b; if ((t/=d/2)==2) return b+c; if (!p) p=d*(.3*1.5);
937 if (!a || a < Math.abs(c)) { a=c; var s=p/4; }
938 else var s = p/(2*Math.PI) * Math.asin (c/a);
939 if (t < 1) return -.5*(a*Math.pow(2,10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )) + b;
940 return a*Math.pow(2,-10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )*.5 + c + b;
941 },
942
943 /**
944 * Backtracks slightly, then reverses direction and moves to end.
945 * @method backIn
946 * @param {Number} t Time value used to compute current value
947 * @param {Number} b Starting value
948 * @param {Number} c Delta between start and end values
949 * @param {Number} d Total length of animation
950 * @param {Number} s Overshoot (optional)
951 * @return {Number} The computed value for the current animation frame
952 */
953 backIn: function (t, b, c, d, s) {
954 if (typeof s == 'undefined') s = 1.70158;
955 return c*(t/=d)*t*((s+1)*t - s) + b;
956 },
957
958 /**
959 * Overshoots end, then reverses and comes back to end.
960 * @method backOut
961 * @param {Number} t Time value used to compute current value
962 * @param {Number} b Starting value
963 * @param {Number} c Delta between start and end values
964 * @param {Number} d Total length of animation
965 * @param {Number} s Overshoot (optional)
966 * @return {Number} The computed value for the current animation frame
967 */
968 backOut: function (t, b, c, d, s) {
969 if (typeof s == 'undefined') s = 1.70158;
970 return c*((t=t/d-1)*t*((s+1)*t + s) + 1) + b;
971 },
972
973 /**
974 * Backtracks slightly, then reverses direction, overshoots end,
975 * then reverses and comes back to end.
976 * @method backBoth
977 * @param {Number} t Time value used to compute current value
978 * @param {Number} b Starting value
979 * @param {Number} c Delta between start and end values
980 * @param {Number} d Total length of animation
981 * @param {Number} s Overshoot (optional)
982 * @return {Number} The computed value for the current animation frame
983 */
984 backBoth: function (t, b, c, d, s) {
985 if (typeof s == 'undefined') s = 1.70158;
986 if ((t/=d/2) < 1) return c/2*(t*t*(((s*=(1.525))+1)*t - s)) + b;
987 return c/2*((t-=2)*t*(((s*=(1.525))+1)*t + s) + 2) + b;
988 },
989
990 /**
991 * Bounce off of start.
992 * @method bounceIn
993 * @param {Number} t Time value used to compute current value
994 * @param {Number} b Starting value
995 * @param {Number} c Delta between start and end values
996 * @param {Number} d Total length of animation
997 * @return {Number} The computed value for the current animation frame
998 */
999 bounceIn: function (t, b, c, d) {
1000 return c - YAHOO.util.Easing.bounceOut(d-t, 0, c, d) + b;
1001 },
1002
1003 /**
1004 * Bounces off end.
1005 * @method bounceOut
1006 * @param {Number} t Time value used to compute current value
1007 * @param {Number} b Starting value
1008 * @param {Number} c Delta between start and end values
1009 * @param {Number} d Total length of animation
1010 * @return {Number} The computed value for the current animation frame
1011 */
1012 bounceOut: function (t, b, c, d) {
1013 if ((t/=d) < (1/2.75)) {
1014 return c*(7.5625*t*t) + b;
1015 } else if (t < (2/2.75)) {
1016 return c*(7.5625*(t-=(1.5/2.75))*t + .75) + b;
1017 } else if (t < (2.5/2.75)) {
1018 return c*(7.5625*(t-=(2.25/2.75))*t + .9375) + b;
1019 } else {
1020 return c*(7.5625*(t-=(2.625/2.75))*t + .984375) + b;
1021 }
1022 },
1023
1024 /**
1025 * Bounces off start and end.
1026 * @method bounceBoth
1027 * @param {Number} t Time value used to compute current value
1028 * @param {Number} b Starting value
1029 * @param {Number} c Delta between start and end values
1030 * @param {Number} d Total length of animation
1031 * @return {Number} The computed value for the current animation frame
1032 */
1033 bounceBoth: function (t, b, c, d) {
1034 if (t < d/2) return YAHOO.util.Easing.bounceIn(t*2, 0, c, d) * .5 + b;
1035 return YAHOO.util.Easing.bounceOut(t*2-d, 0, c, d) * .5 + c*.5 + b;
1036 }
1037};
1038
1039/**
1040 * Anim subclass for moving elements along a path defined by the "points"
1041 * member of "attributes". All "points" are arrays with x, y coordinates.
1042 * <p>Usage: <code>var myAnim = new YAHOO.util.Motion(el, { points: { to: [800, 800] } }, 1, YAHOO.util.Easing.easeOut);</code></p>
1043 * @class Motion
1044 * @namespace YAHOO.util
1045 * @requires YAHOO.util.Anim
1046 * @requires YAHOO.util.AnimMgr
1047 * @requires YAHOO.util.Easing
1048 * @requires YAHOO.util.Bezier
1049 * @requires YAHOO.util.Dom
1050 * @requires YAHOO.util.Event
1051 * @requires YAHOO.util.CustomEvent
1052 * @constructor
1053 * @extends YAHOO.util.Anim
1054 * @param {String | HTMLElement} el Reference to the element that will be animated
1055 * @param {Object} attributes The attribute(s) to be animated.
1056 * Each attribute is an object with at minimum a "to" or "by" member defined.
1057 * Additional optional members are "from" (defaults to current value), "units" (defaults to "px").
1058 * All attribute names use camelCase.
1059 * @param {Number} duration (optional, defaults to 1 second) Length of animation (frames or seconds), defaults to time-based
1060 * @param {Function} method (optional, defaults to YAHOO.util.Easing.easeNone) Computes the values that are applied to the attributes per frame (generally a YAHOO.util.Easing method)
1061 */
1062(function() {
1063 YAHOO.util.Motion = function(el, attributes, duration, method) {
1064 if (el) { // dont break existing subclasses not using YAHOO.extend
1065 YAHOO.util.Motion.superclass.constructor.call(this, el, attributes, duration, method);
1066 }
1067 };
1068
1069 YAHOO.extend(YAHOO.util.Motion, YAHOO.util.ColorAnim);
1070
1071 // shorthand
1072 var Y = YAHOO.util;
1073 var superclass = Y.Motion.superclass;
1074 var proto = Y.Motion.prototype;
1075
1076 proto.toString = function() {
1077 var el = this.getEl();
1078 var id = el.id || el.tagName;
1079 return ("Motion " + id);
1080 };
1081
1082 proto.patterns.points = /^points$/i;
1083
1084 proto.setAttribute = function(attr, val, unit) {
1085 if ( this.patterns.points.test(attr) ) {
1086 unit = unit || 'px';
1087 superclass.setAttribute.call(this, 'left', val[0], unit);
1088 superclass.setAttribute.call(this, 'top', val[1], unit);
1089 } else {
1090 superclass.setAttribute.call(this, attr, val, unit);
1091 }
1092 };
1093
1094 proto.getAttribute = function(attr) {
1095 if ( this.patterns.points.test(attr) ) {
1096 var val = [
1097 superclass.getAttribute.call(this, 'left'),
1098 superclass.getAttribute.call(this, 'top')
1099 ];
1100 } else {
1101 val = superclass.getAttribute.call(this, attr);
1102 }
1103
1104 return val;
1105 };
1106
1107 proto.doMethod = function(attr, start, end) {
1108 var val = null;
1109
1110 if ( this.patterns.points.test(attr) ) {
1111 var t = this.method(this.currentFrame, 0, 100, this.totalFrames) / 100;
1112 val = Y.Bezier.getPosition(this.runtimeAttributes[attr], t);
1113 } else {
1114 val = superclass.doMethod.call(this, attr, start, end);
1115 }
1116 return val;
1117 };
1118
1119 proto.setRuntimeAttribute = function(attr) {
1120 if ( this.patterns.points.test(attr) ) {
1121 var el = this.getEl();
1122 var attributes = this.attributes;
1123 var start;
1124 var control = attributes['points']['control'] || [];
1125 var end;
1126 var i, len;
1127
1128 if (control.length > 0 && !(control[0] instanceof Array) ) { // could be single point or array of points
1129 control = [control];
1130 } else { // break reference to attributes.points.control
1131 var tmp = [];
1132 for (i = 0, len = control.length; i< len; ++i) {
1133 tmp[i] = control[i];
1134 }
1135 control = tmp;
1136 }
1137
1138 if (Y.Dom.getStyle(el, 'position') == 'static') { // default to relative
1139 Y.Dom.setStyle(el, 'position', 'relative');
1140 }
1141
1142 if ( isset(attributes['points']['from']) ) {
1143 Y.Dom.setXY(el, attributes['points']['from']); // set position to from point
1144 }
1145 else { Y.Dom.setXY( el, Y.Dom.getXY(el) ); } // set it to current position
1146
1147 start = this.getAttribute('points'); // get actual top & left
1148
1149 // TO beats BY, per SMIL 2.1 spec
1150 if ( isset(attributes['points']['to']) ) {
1151 end = translateValues.call(this, attributes['points']['to'], start);
1152
1153 var pageXY = Y.Dom.getXY(this.getEl());
1154 for (i = 0, len = control.length; i < len; ++i) {
1155 control[i] = translateValues.call(this, control[i], start);
1156 }
1157
1158
1159 } else if ( isset(attributes['points']['by']) ) {
1160 end = [ start[0] + attributes['points']['by'][0], start[1] + attributes['points']['by'][1] ];
1161
1162 for (i = 0, len = control.length; i < len; ++i) {
1163 control[i] = [ start[0] + control[i][0], start[1] + control[i][1] ];
1164 }
1165 }
1166
1167 this.runtimeAttributes[attr] = [start];
1168
1169 if (control.length > 0) {
1170 this.runtimeAttributes[attr] = this.runtimeAttributes[attr].concat(control);
1171 }
1172
1173 this.runtimeAttributes[attr][this.runtimeAttributes[attr].length] = end;
1174 }
1175 else {
1176 superclass.setRuntimeAttribute.call(this, attr);
1177 }
1178 };
1179
1180 var translateValues = function(val, start) {
1181 var pageXY = Y.Dom.getXY(this.getEl());
1182 val = [ val[0] - pageXY[0] + start[0], val[1] - pageXY[1] + start[1] ];
1183
1184 return val;
1185 };
1186
1187 var isset = function(prop) {
1188 return (typeof prop !== 'undefined');
1189 };
1190})();
1191/**
1192 * Anim subclass for scrolling elements to a position defined by the "scroll"
1193 * member of "attributes". All "scroll" members are arrays with x, y scroll positions.
1194 * <p>Usage: <code>var myAnim = new YAHOO.util.Scroll(el, { scroll: { to: [0, 800] } }, 1, YAHOO.util.Easing.easeOut);</code></p>
1195 * @class Scroll
1196 * @namespace YAHOO.util
1197 * @requires YAHOO.util.Anim
1198 * @requires YAHOO.util.AnimMgr
1199 * @requires YAHOO.util.Easing
1200 * @requires YAHOO.util.Bezier
1201 * @requires YAHOO.util.Dom
1202 * @requires YAHOO.util.Event
1203 * @requires YAHOO.util.CustomEvent
1204 * @extends YAHOO.util.Anim
1205 * @constructor
1206 * @param {String or HTMLElement} el Reference to the element that will be animated
1207 * @param {Object} attributes The attribute(s) to be animated.
1208 * Each attribute is an object with at minimum a "to" or "by" member defined.
1209 * Additional optional members are "from" (defaults to current value), "units" (defaults to "px").
1210 * All attribute names use camelCase.
1211 * @param {Number} duration (optional, defaults to 1 second) Length of animation (frames or seconds), defaults to time-based
1212 * @param {Function} method (optional, defaults to YAHOO.util.Easing.easeNone) Computes the values that are applied to the attributes per frame (generally a YAHOO.util.Easing method)
1213 */
1214(function() {
1215 YAHOO.util.Scroll = function(el, attributes, duration, method) {
1216 if (el) { // dont break existing subclasses not using YAHOO.extend
1217 YAHOO.util.Scroll.superclass.constructor.call(this, el, attributes, duration, method);
1218 }
1219 };
1220
1221 YAHOO.extend(YAHOO.util.Scroll, YAHOO.util.ColorAnim);
1222
1223 // shorthand
1224 var Y = YAHOO.util;
1225 var superclass = Y.Scroll.superclass;
1226 var proto = Y.Scroll.prototype;
1227
1228 proto.toString = function() {
1229 var el = this.getEl();
1230 var id = el.id || el.tagName;
1231 return ("Scroll " + id);
1232 };
1233
1234 proto.doMethod = function(attr, start, end) {
1235 var val = null;
1236
1237 if (attr == 'scroll') {
1238 val = [
1239 this.method(this.currentFrame, start[0], end[0] - start[0], this.totalFrames),
1240 this.method(this.currentFrame, start[1], end[1] - start[1], this.totalFrames)
1241 ];
1242
1243 } else {
1244 val = superclass.doMethod.call(this, attr, start, end);
1245 }
1246 return val;
1247 };
1248
1249 proto.getAttribute = function(attr) {
1250 var val = null;
1251 var el = this.getEl();
1252
1253 if (attr == 'scroll') {
1254 val = [ el.scrollLeft, el.scrollTop ];
1255 } else {
1256 val = superclass.getAttribute.call(this, attr);
1257 }
1258
1259 return val;
1260 };
1261
1262 proto.setAttribute = function(attr, val, unit) {
1263 var el = this.getEl();
1264
1265 if (attr == 'scroll') {
1266 el.scrollLeft = val[0];
1267 el.scrollTop = val[1];
1268 } else {
1269 superclass.setAttribute.call(this, attr, val, unit);
1270 }
1271 };
1272})();
diff --git a/frontend/beta/js/YUI/autocomplete.js b/frontend/beta/js/YUI/autocomplete.js
new file mode 100644
index 0000000..a5722cc
--- a/dev/null
+++ b/frontend/beta/js/YUI/autocomplete.js
@@ -0,0 +1,3066 @@
1/*
2Copyright (c) 2006, Yahoo! Inc. All rights reserved.
3Code licensed under the BSD License:
4http://developer.yahoo.com/yui/license.txt
5version: 0.12.0
6*/
7
8 /**
9 * The AutoComplete control provides the front-end logic for text-entry suggestion and
10 * completion functionality.
11 *
12 * @module autocomplete
13 * @requires yahoo, dom, event, datasource
14 * @optional animation, connection, json
15 * @namespace YAHOO.widget
16 * @title AutoComplete Widget
17 */
18
19/****************************************************************************/
20/****************************************************************************/
21/****************************************************************************/
22
23/**
24 * The AutoComplete class provides the customizable functionality of a plug-and-play DHTML
25 * auto completion widget. Some key features:
26 * <ul>
27 * <li>Navigate with up/down arrow keys and/or mouse to pick a selection</li>
28 * <li>The drop down container can "roll down" or "fly out" via configurable
29 * animation</li>
30 * <li>UI look-and-feel customizable through CSS, including container
31 * attributes, borders, position, fonts, etc</li>
32 * </ul>
33 *
34 * @class AutoComplete
35 * @constructor
36 * @param elInput {HTMLElement} DOM element reference of an input field
37 * @param elInput {String} String ID of an input field
38 * @param elContainer {HTMLElement} DOM element reference of an existing DIV
39 * @param elContainer {String} String ID of an existing DIV
40 * @param oDataSource {Object} Instance of YAHOO.widget.DataSource for query/results
41 * @param oConfigs {Object} (optional) Object literal of configuration params
42 */
43YAHOO.widget.AutoComplete = function(elInput,elContainer,oDataSource,oConfigs) {
44 if(elInput && elContainer && oDataSource) {
45 // Validate DataSource
46 if (oDataSource && (oDataSource instanceof YAHOO.widget.DataSource)) {
47 this.dataSource = oDataSource;
48 }
49 else {
50 return;
51 }
52
53 // Validate input element
54 if(YAHOO.util.Dom.inDocument(elInput)) {
55 if(typeof elInput == "string") {
56 this._sName = "instance" + YAHOO.widget.AutoComplete._nIndex + " " + elInput;
57 this._oTextbox = document.getElementById(elInput);
58 }
59 else {
60 this._sName = (elInput.id) ?
61 "instance" + YAHOO.widget.AutoComplete._nIndex + " " + elInput.id:
62 "instance" + YAHOO.widget.AutoComplete._nIndex;
63 this._oTextbox = elInput;
64 }
65 }
66 else {
67 return;
68 }
69
70 // Validate container element
71 if(YAHOO.util.Dom.inDocument(elContainer)) {
72 if(typeof elContainer == "string") {
73 this._oContainer = document.getElementById(elContainer);
74 }
75 else {
76 this._oContainer = elContainer;
77 }
78 if(this._oContainer.style.display == "none") {
79 }
80 }
81 else {
82 return;
83 }
84
85 // Set any config params passed in to override defaults
86 if (typeof oConfigs == "object") {
87 for(var sConfig in oConfigs) {
88 if (sConfig) {
89 this[sConfig] = oConfigs[sConfig];
90 }
91 }
92 }
93
94 // Initialization sequence
95 this._initContainer();
96 this._initProps();
97 this._initList();
98 this._initContainerHelpers();
99
100 // Set up events
101 var oSelf = this;
102 var oTextbox = this._oTextbox;
103 // Events are actually for the content module within the container
104 var oContent = this._oContainer._oContent;
105
106 // Dom events
107 YAHOO.util.Event.addListener(oTextbox,"keyup",oSelf._onTextboxKeyUp,oSelf);
108 YAHOO.util.Event.addListener(oTextbox,"keydown",oSelf._onTextboxKeyDown,oSelf);
109 YAHOO.util.Event.addListener(oTextbox,"focus",oSelf._onTextboxFocus,oSelf);
110 YAHOO.util.Event.addListener(oTextbox,"blur",oSelf._onTextboxBlur,oSelf);
111 YAHOO.util.Event.addListener(oContent,"mouseover",oSelf._onContainerMouseover,oSelf);
112 YAHOO.util.Event.addListener(oContent,"mouseout",oSelf._onContainerMouseout,oSelf);
113 YAHOO.util.Event.addListener(oContent,"scroll",oSelf._onContainerScroll,oSelf);
114 YAHOO.util.Event.addListener(oContent,"resize",oSelf._onContainerResize,oSelf);
115 if(oTextbox.form) {
116 YAHOO.util.Event.addListener(oTextbox.form,"submit",oSelf._onFormSubmit,oSelf);
117 }
118 YAHOO.util.Event.addListener(oTextbox,"keypress",oSelf._onTextboxKeyPress,oSelf);
119
120 // Custom events
121 this.textboxFocusEvent = new YAHOO.util.CustomEvent("textboxFocus", this);
122 this.textboxKeyEvent = new YAHOO.util.CustomEvent("textboxKey", this);
123 this.dataRequestEvent = new YAHOO.util.CustomEvent("dataRequest", this);
124 this.dataReturnEvent = new YAHOO.util.CustomEvent("dataReturn", this);
125 this.dataErrorEvent = new YAHOO.util.CustomEvent("dataError", this);
126 this.containerExpandEvent = new YAHOO.util.CustomEvent("containerExpand", this);
127 this.typeAheadEvent = new YAHOO.util.CustomEvent("typeAhead", this);
128 this.itemMouseOverEvent = new YAHOO.util.CustomEvent("itemMouseOver", this);
129 this.itemMouseOutEvent = new YAHOO.util.CustomEvent("itemMouseOut", this);
130 this.itemArrowToEvent = new YAHOO.util.CustomEvent("itemArrowTo", this);
131 this.itemArrowFromEvent = new YAHOO.util.CustomEvent("itemArrowFrom", this);
132 this.itemSelectEvent = new YAHOO.util.CustomEvent("itemSelect", this);
133 this.unmatchedItemSelectEvent = new YAHOO.util.CustomEvent("unmatchedItemSelect", this);
134 this.selectionEnforceEvent = new YAHOO.util.CustomEvent("selectionEnforce", this);
135 this.containerCollapseEvent = new YAHOO.util.CustomEvent("containerCollapse", this);
136 this.textboxBlurEvent = new YAHOO.util.CustomEvent("textboxBlur", this);
137
138 // Finish up
139 oTextbox.setAttribute("autocomplete","off");
140 YAHOO.widget.AutoComplete._nIndex++;
141 }
142 // Required arguments were not found
143 else {
144 }
145};
146
147/////////////////////////////////////////////////////////////////////////////
148//
149// Public member variables
150//
151/////////////////////////////////////////////////////////////////////////////
152
153/**
154 * The DataSource object that encapsulates the data used for auto completion.
155 * This object should be an inherited object from YAHOO.widget.DataSource.
156 *
157 * @property dataSource
158 * @type Object
159 */
160YAHOO.widget.AutoComplete.prototype.dataSource = null;
161
162/**
163 * Number of characters that must be entered before querying for results. A negative value
164 * effectively turns off the widget. A value of 0 allows queries of null or empty string
165 * values.
166 *
167 * @property minQueryLength
168 * @type Number
169 * @default 1
170 */
171YAHOO.widget.AutoComplete.prototype.minQueryLength = 1;
172
173/**
174 * Maximum number of results to display in results container.
175 *
176 * @property maxResultsDisplayed
177 * @type Number
178 * @default 10
179 */
180YAHOO.widget.AutoComplete.prototype.maxResultsDisplayed = 10;
181
182/**
183 * Number of seconds to delay before submitting a query request. If a query
184 * request is received before a previous one has completed its delay, the
185 * previous request is cancelled and the new request is set to the delay.
186 *
187 * @property queryDelay
188 * @type Number
189 * @default 0.5
190 */
191YAHOO.widget.AutoComplete.prototype.queryDelay = 0.5;
192
193/**
194 * Class name of a highlighted item within results container.
195 *
196 * @property highlighClassName
197 * @type String
198 * @default "yui-ac-highlight"
199 */
200YAHOO.widget.AutoComplete.prototype.highlightClassName = "yui-ac-highlight";
201
202/**
203 * Class name of a pre-highlighted item within results container.
204 *
205 * @property prehighlightClassName
206 * @type String
207 */
208YAHOO.widget.AutoComplete.prototype.prehighlightClassName = null;
209
210/**
211 * Query delimiter. A single character separator for multiple delimited
212 * selections. Multiple delimiter characteres may be defined as an array of
213 * strings. A null value or empty string indicates that query results cannot
214 * be delimited. This feature is not recommended if you need forceSelection to
215 * be true.
216 *
217 * @property delimChar
218 * @type String | String[]
219 */
220YAHOO.widget.AutoComplete.prototype.delimChar = null;
221
222/**
223 * Whether or not the first item in results container should be automatically highlighted
224 * on expand.
225 *
226 * @property autoHighlight
227 * @type Boolean
228 * @default true
229 */
230YAHOO.widget.AutoComplete.prototype.autoHighlight = true;
231
232/**
233 * Whether or not the input field should be automatically updated
234 * with the first query result as the user types, auto-selecting the substring
235 * that the user has not typed.
236 *
237 * @property typeAhead
238 * @type Boolean
239 * @default false
240 */
241YAHOO.widget.AutoComplete.prototype.typeAhead = false;
242
243/**
244 * Whether or not to animate the expansion/collapse of the results container in the
245 * horizontal direction.
246 *
247 * @property animHoriz
248 * @type Boolean
249 * @default false
250 */
251YAHOO.widget.AutoComplete.prototype.animHoriz = false;
252
253/**
254 * Whether or not to animate the expansion/collapse of the results container in the
255 * vertical direction.
256 *
257 * @property animVert
258 * @type Boolean
259 * @default true
260 */
261YAHOO.widget.AutoComplete.prototype.animVert = true;
262
263/**
264 * Speed of container expand/collapse animation, in seconds..
265 *
266 * @property animSpeed
267 * @type Number
268 * @default 0.3
269 */
270YAHOO.widget.AutoComplete.prototype.animSpeed = 0.3;
271
272/**
273 * Whether or not to force the user's selection to match one of the query
274 * results. Enabling this feature essentially transforms the input field into a
275 * &lt;select&gt; field. This feature is not recommended with delimiter character(s)
276 * defined.
277 *
278 * @property forceSelection
279 * @type Boolean
280 * @default false
281 */
282YAHOO.widget.AutoComplete.prototype.forceSelection = false;
283
284/**
285 * Whether or not to allow browsers to cache user-typed input in the input
286 * field. Disabling this feature will prevent the widget from setting the
287 * autocomplete="off" on the input field. When autocomplete="off"
288 * and users click the back button after form submission, user-typed input can
289 * be prefilled by the browser from its cache. This caching of user input may
290 * not be desired for sensitive data, such as credit card numbers, in which
291 * case, implementers should consider setting allowBrowserAutocomplete to false.
292 *
293 * @property allowBrowserAutocomplete
294 * @type Boolean
295 * @default true
296 */
297YAHOO.widget.AutoComplete.prototype.allowBrowserAutocomplete = true;
298
299/**
300 * Whether or not the results container should always be displayed.
301 * Enabling this feature displays the container when the widget is instantiated
302 * and prevents the toggling of the container to a collapsed state.
303 *
304 * @property alwaysShowContainer
305 * @type Boolean
306 * @default false
307 */
308YAHOO.widget.AutoComplete.prototype.alwaysShowContainer = false;
309
310/**
311 * Whether or not to use an iFrame to layer over Windows form elements in
312 * IE. Set to true only when the results container will be on top of a
313 * &lt;select&gt; field in IE and thus exposed to the IE z-index bug (i.e.,
314 * 5.5 < IE < 7).
315 *
316 * @property useIFrame
317 * @type Boolean
318 * @default false
319 */
320YAHOO.widget.AutoComplete.prototype.useIFrame = false;
321
322/**
323 * Whether or not the results container should have a shadow.
324 *
325 * @property useShadow
326 * @type Boolean
327 * @default false
328 */
329YAHOO.widget.AutoComplete.prototype.useShadow = false;
330
331/////////////////////////////////////////////////////////////////////////////
332//
333// Public methods
334//
335/////////////////////////////////////////////////////////////////////////////
336
337 /**
338 * Public accessor to the unique name of the AutoComplete instance.
339 *
340 * @method toString
341 * @return {String} Unique name of the AutoComplete instance.
342 */
343YAHOO.widget.AutoComplete.prototype.toString = function() {
344 return "AutoComplete " + this._sName;
345};
346
347 /**
348 * Returns true if container is in an expanded state, false otherwise.
349 *
350 * @method isContainerOpen
351 * @return {Boolean} Returns true if container is in an expanded state, false otherwise.
352 */
353YAHOO.widget.AutoComplete.prototype.isContainerOpen = function() {
354 return this._bContainerOpen;
355};
356
357/**
358 * Public accessor to the internal array of DOM &lt;li&gt; elements that
359 * display query results within the results container.
360 *
361 * @method getListItems
362 * @return {HTMLElement[]} Array of &lt;li&gt; elements within the results container.
363 */
364YAHOO.widget.AutoComplete.prototype.getListItems = function() {
365 return this._aListItems;
366};
367
368/**
369 * Public accessor to the data held in an &lt;li&gt; element of the
370 * results container.
371 *
372 * @method getListItemData
373 * @return {Object | Array} Object or array of result data or null
374 */
375YAHOO.widget.AutoComplete.prototype.getListItemData = function(oListItem) {
376 if(oListItem._oResultData) {
377 return oListItem._oResultData;
378 }
379 else {
380 return false;
381 }
382};
383
384/**
385 * Sets HTML markup for the results container header. This markup will be
386 * inserted within a &lt;div&gt; tag with a class of "ac_hd".
387 *
388 * @method setHeader
389 * @param sHeader {String} HTML markup for results container header.
390 */
391YAHOO.widget.AutoComplete.prototype.setHeader = function(sHeader) {
392 if(sHeader) {
393 if(this._oContainer._oContent._oHeader) {
394 this._oContainer._oContent._oHeader.innerHTML = sHeader;
395 this._oContainer._oContent._oHeader.style.display = "block";
396 }
397 }
398 else {
399 this._oContainer._oContent._oHeader.innerHTML = "";
400 this._oContainer._oContent._oHeader.style.display = "none";
401 }
402};
403
404/**
405 * Sets HTML markup for the results container footer. This markup will be
406 * inserted within a &lt;div&gt; tag with a class of "ac_ft".
407 *
408 * @method setFooter
409 * @param sFooter {String} HTML markup for results container footer.
410 */
411YAHOO.widget.AutoComplete.prototype.setFooter = function(sFooter) {
412 if(sFooter) {
413 if(this._oContainer._oContent._oFooter) {
414 this._oContainer._oContent._oFooter.innerHTML = sFooter;
415 this._oContainer._oContent._oFooter.style.display = "block";
416 }
417 }
418 else {
419 this._oContainer._oContent._oFooter.innerHTML = "";
420 this._oContainer._oContent._oFooter.style.display = "none";
421 }
422};
423
424/**
425 * Sets HTML markup for the results container body. This markup will be
426 * inserted within a &lt;div&gt; tag with a class of "ac_bd".
427 *
428 * @method setBody
429 * @param sHeader {String} HTML markup for results container body.
430 */
431YAHOO.widget.AutoComplete.prototype.setBody = function(sBody) {
432 if(sBody) {
433 if(this._oContainer._oContent._oBody) {
434 this._oContainer._oContent._oBody.innerHTML = sBody;
435 this._oContainer._oContent._oBody.style.display = "block";
436 this._oContainer._oContent.style.display = "block";
437 }
438 }
439 else {
440 this._oContainer._oContent._oBody.innerHTML = "";
441 this._oContainer._oContent.style.display = "none";
442 }
443 this._maxResultsDisplayed = 0;
444};
445
446/**
447 * Overridable method that converts a result item object into HTML markup
448 * for display. Return data values are accessible via the oResultItem object,
449 * and the key return value will always be oResultItem[0]. Markup will be
450 * displayed within &lt;li&gt; element tags in the container.
451 *
452 * @method formatResult
453 * @param oResultItem {Object} Result item representing one query result. Data is held in an array.
454 * @param sQuery {String} The current query string.
455 * @return {String} HTML markup of formatted result data.
456 */
457YAHOO.widget.AutoComplete.prototype.formatResult = function(oResultItem, sQuery) {
458 var sResult = oResultItem[0];
459 if(sResult) {
460 return sResult;
461 }
462 else {
463 return "";
464 }
465};
466
467/**
468 * Overridable method called before container expands allows implementers to access data
469 * and DOM elements.
470 *
471 * @method doBeforeExpandContainer
472 * @return {Boolean} Return true to continue expanding container, false to cancel the expand.
473 */
474YAHOO.widget.AutoComplete.prototype.doBeforeExpandContainer = function(oResultItem, sQuery) {
475 return true;
476};
477
478/**
479 * Makes query request to the DataSource.
480 *
481 * @method sendQuery
482 * @param sQuery {String} Query string.
483 */
484YAHOO.widget.AutoComplete.prototype.sendQuery = function(sQuery) {
485 this._sendQuery(sQuery);
486};
487
488/////////////////////////////////////////////////////////////////////////////
489//
490// Public events
491//
492/////////////////////////////////////////////////////////////////////////////
493
494/**
495 * Fired when the input field receives focus.
496 *
497 * @event textboxFocusEvent
498 * @param oSelf {Object} The AutoComplete instance.
499 */
500YAHOO.widget.AutoComplete.prototype.textboxFocusEvent = null;
501
502/**
503 * Fired when the input field receives key input.
504 *
505 * @event textboxKeyEvent
506 * @param oSelf {Object} The AutoComplete instance.
507 * @param nKeycode {Number} The keycode number.
508 */
509YAHOO.widget.AutoComplete.prototype.textboxKeyEvent = null;
510
511/**
512 * Fired when the AutoComplete instance makes a query to the DataSource.
513 *
514 * @event dataRequestEvent
515 * @param oSelf {Object} The AutoComplete instance.
516 * @param sQuery {String} The query string.
517 */
518YAHOO.widget.AutoComplete.prototype.dataRequestEvent = null;
519
520/**
521 * Fired when the AutoComplete instance receives query results from the data
522 * source.
523 *
524 * @event dataReturnEvent
525 * @param oSelf {Object} The AutoComplete instance.
526 * @param sQuery {String} The query string.
527 * @param aResults {Array} Results array.
528 */
529YAHOO.widget.AutoComplete.prototype.dataReturnEvent = null;
530
531/**
532 * Fired when the AutoComplete instance does not receive query results from the
533 * DataSource due to an error.
534 *
535 * @event dataErrorEvent
536 * @param oSelf {Object} The AutoComplete instance.
537 * @param sQuery {String} The query string.
538 */
539YAHOO.widget.AutoComplete.prototype.dataErrorEvent = null;
540
541/**
542 * Fired when the results container is expanded.
543 *
544 * @event containerExpandEvent
545 * @param oSelf {Object} The AutoComplete instance.
546 */
547YAHOO.widget.AutoComplete.prototype.containerExpandEvent = null;
548
549/**
550 * Fired when the input field has been prefilled by the type-ahead
551 * feature.
552 *
553 * @event typeAheadEvent
554 * @param oSelf {Object} The AutoComplete instance.
555 * @param sQuery {String} The query string.
556 * @param sPrefill {String} The prefill string.
557 */
558YAHOO.widget.AutoComplete.prototype.typeAheadEvent = null;
559
560/**
561 * Fired when result item has been moused over.
562 *
563 * @event itemMouseOverEvent
564 * @param oSelf {Object} The AutoComplete instance.
565 * @param elItem {HTMLElement} The &lt;li&gt element item moused to.
566 */
567YAHOO.widget.AutoComplete.prototype.itemMouseOverEvent = null;
568
569/**
570 * Fired when result item has been moused out.
571 *
572 * @event itemMouseOutEvent
573 * @param oSelf {Object} The AutoComplete instance.
574 * @param elItem {HTMLElement} The &lt;li&gt; element item moused from.
575 */
576YAHOO.widget.AutoComplete.prototype.itemMouseOutEvent = null;
577
578/**
579 * Fired when result item has been arrowed to.
580 *
581 * @event itemArrowToEvent
582 * @param oSelf {Object} The AutoComplete instance.
583 * @param elItem {HTMLElement} The &lt;li&gt; element item arrowed to.
584 */
585YAHOO.widget.AutoComplete.prototype.itemArrowToEvent = null;
586
587/**
588 * Fired when result item has been arrowed away from.
589 *
590 * @event itemArrowFromEvent
591 * @param oSelf {Object} The AutoComplete instance.
592 * @param elItem {HTMLElement} The &lt;li&gt; element item arrowed from.
593 */
594YAHOO.widget.AutoComplete.prototype.itemArrowFromEvent = null;
595
596/**
597 * Fired when an item is selected via mouse click, ENTER key, or TAB key.
598 *
599 * @event itemSelectEvent
600 * @param oSelf {Object} The AutoComplete instance.
601 * @param elItem {HTMLElement} The selected &lt;li&gt; element item.
602 * @param oData {Object} The data returned for the item, either as an object,
603 * or mapped from the schema into an array.
604 */
605YAHOO.widget.AutoComplete.prototype.itemSelectEvent = null;
606
607/**
608 * Fired when a user selection does not match any of the displayed result items.
609 * Note that this event may not behave as expected when delimiter characters
610 * have been defined.
611 *
612 * @event unmatchedItemSelectEvent
613 * @param oSelf {Object} The AutoComplete instance.
614 * @param sQuery {String} The user-typed query string.
615 */
616YAHOO.widget.AutoComplete.prototype.unmatchedItemSelectEvent = null;
617
618/**
619 * Fired if forceSelection is enabled and the user's input has been cleared
620 * because it did not match one of the returned query results.
621 *
622 * @event selectionEnforceEvent
623 * @param oSelf {Object} The AutoComplete instance.
624 */
625YAHOO.widget.AutoComplete.prototype.selectionEnforceEvent = null;
626
627/**
628 * Fired when the results container is collapsed.
629 *
630 * @event containerCollapseEvent
631 * @param oSelf {Object} The AutoComplete instance.
632 */
633YAHOO.widget.AutoComplete.prototype.containerCollapseEvent = null;
634
635/**
636 * Fired when the input field loses focus.
637 *
638 * @event textboxBlurEvent
639 * @param oSelf {Object} The AutoComplete instance.
640 */
641YAHOO.widget.AutoComplete.prototype.textboxBlurEvent = null;
642
643/////////////////////////////////////////////////////////////////////////////
644//
645// Private member variables
646//
647/////////////////////////////////////////////////////////////////////////////
648
649/**
650 * Internal class variable to index multiple AutoComplete instances.
651 *
652 * @property _nIndex
653 * @type Number
654 * @default 0
655 * @private
656 */
657YAHOO.widget.AutoComplete._nIndex = 0;
658
659/**
660 * Name of AutoComplete instance.
661 *
662 * @property _sName
663 * @type String
664 * @private
665 */
666YAHOO.widget.AutoComplete.prototype._sName = null;
667
668/**
669 * Text input field DOM element.
670 *
671 * @property _oTextbox
672 * @type HTMLElement
673 * @private
674 */
675YAHOO.widget.AutoComplete.prototype._oTextbox = null;
676
677/**
678 * Whether or not the input field is currently in focus. If query results come back
679 * but the user has already moved on, do not proceed with auto complete behavior.
680 *
681 * @property _bFocused
682 * @type Boolean
683 * @private
684 */
685YAHOO.widget.AutoComplete.prototype._bFocused = true;
686
687/**
688 * Animation instance for container expand/collapse.
689 *
690 * @property _oAnim
691 * @type Boolean
692 * @private
693 */
694YAHOO.widget.AutoComplete.prototype._oAnim = null;
695
696/**
697 * Container DOM element.
698 *
699 * @property _oContainer
700 * @type HTMLElement
701 * @private
702 */
703YAHOO.widget.AutoComplete.prototype._oContainer = null;
704
705/**
706 * Whether or not the results container is currently open.
707 *
708 * @property _bContainerOpen
709 * @type Boolean
710 * @private
711 */
712YAHOO.widget.AutoComplete.prototype._bContainerOpen = false;
713
714/**
715 * Whether or not the mouse is currently over the results
716 * container. This is necessary in order to prevent clicks on container items
717 * from being text input field blur events.
718 *
719 * @property _bOverContainer
720 * @type Boolean
721 * @private
722 */
723YAHOO.widget.AutoComplete.prototype._bOverContainer = false;
724
725/**
726 * Array of &lt;li&gt; elements references that contain query results within the
727 * results container.
728 *
729 * @property _aListItems
730 * @type Array
731 * @private
732 */
733YAHOO.widget.AutoComplete.prototype._aListItems = null;
734
735/**
736 * Number of &lt;li&gt; elements currently displayed in results container.
737 *
738 * @property _nDisplayedItems
739 * @type Number
740 * @private
741 */
742YAHOO.widget.AutoComplete.prototype._nDisplayedItems = 0;
743
744/**
745 * Internal count of &lt;li&gt; elements displayed and hidden in results container.
746 *
747 * @property _maxResultsDisplayed
748 * @type Number
749 * @private
750 */
751YAHOO.widget.AutoComplete.prototype._maxResultsDisplayed = 0;
752
753/**
754 * Current query string
755 *
756 * @property _sCurQuery
757 * @type String
758 * @private
759 */
760YAHOO.widget.AutoComplete.prototype._sCurQuery = null;
761
762/**
763 * Past queries this session (for saving delimited queries).
764 *
765 * @property _sSavedQuery
766 * @type String
767 * @private
768 */
769YAHOO.widget.AutoComplete.prototype._sSavedQuery = null;
770
771/**
772 * Pointer to the currently highlighted &lt;li&gt; element in the container.
773 *
774 * @property _oCurItem
775 * @type HTMLElement
776 * @private
777 */
778YAHOO.widget.AutoComplete.prototype._oCurItem = null;
779
780/**
781 * Whether or not an item has been selected since the container was populated
782 * with results. Reset to false by _populateList, and set to true when item is
783 * selected.
784 *
785 * @property _bItemSelected
786 * @type Boolean
787 * @private
788 */
789YAHOO.widget.AutoComplete.prototype._bItemSelected = false;
790
791/**
792 * Key code of the last key pressed in textbox.
793 *
794 * @property _nKeyCode
795 * @type Number
796 * @private
797 */
798YAHOO.widget.AutoComplete.prototype._nKeyCode = null;
799
800/**
801 * Delay timeout ID.
802 *
803 * @property _nDelayID
804 * @type Number
805 * @private
806 */
807YAHOO.widget.AutoComplete.prototype._nDelayID = -1;
808
809/**
810 * Src to iFrame used when useIFrame = true. Supports implementations over SSL
811 * as well.
812 *
813 * @property _iFrameSrc
814 * @type String
815 * @private
816 */
817YAHOO.widget.AutoComplete.prototype._iFrameSrc = "javascript:false;";
818
819/**
820 * For users typing via certain IMEs, queries must be triggered by intervals,
821 * since key events yet supported across all browsers for all IMEs.
822 *
823 * @property _queryInterval
824 * @type Object
825 * @private
826 */
827YAHOO.widget.AutoComplete.prototype._queryInterval = null;
828
829/**
830 * Internal tracker to last known textbox value, used to determine whether or not
831 * to trigger a query via interval for certain IME users.
832 *
833 * @event _sLastTextboxValue
834 * @type String
835 * @private
836 */
837YAHOO.widget.AutoComplete.prototype._sLastTextboxValue = null;
838
839/////////////////////////////////////////////////////////////////////////////
840//
841// Private methods
842//
843/////////////////////////////////////////////////////////////////////////////
844
845/**
846 * Updates and validates latest public config properties.
847 *
848 * @method __initProps
849 * @private
850 */
851YAHOO.widget.AutoComplete.prototype._initProps = function() {
852 // Correct any invalid values
853 var minQueryLength = this.minQueryLength;
854 if(isNaN(minQueryLength) || (minQueryLength < 1)) {
855 minQueryLength = 1;
856 }
857 var maxResultsDisplayed = this.maxResultsDisplayed;
858 if(isNaN(this.maxResultsDisplayed) || (this.maxResultsDisplayed < 1)) {
859 this.maxResultsDisplayed = 10;
860 }
861 var queryDelay = this.queryDelay;
862 if(isNaN(this.queryDelay) || (this.queryDelay < 0)) {
863 this.queryDelay = 0.5;
864 }
865 var aDelimChar = (this.delimChar) ? this.delimChar : null;
866 if(aDelimChar) {
867 if(typeof aDelimChar == "string") {
868 this.delimChar = [aDelimChar];
869 }
870 else if(aDelimChar.constructor != Array) {
871 this.delimChar = null;
872 }
873 }
874 var animSpeed = this.animSpeed;
875 if((this.animHoriz || this.animVert) && YAHOO.util.Anim) {
876 if(isNaN(animSpeed) || (animSpeed < 0)) {
877 animSpeed = 0.3;
878 }
879 if(!this._oAnim ) {
880 oAnim = new YAHOO.util.Anim(this._oContainer._oContent, {}, this.animSpeed);
881 this._oAnim = oAnim;
882 }
883 else {
884 this._oAnim.duration = animSpeed;
885 }
886 }
887 if(this.forceSelection && this.delimChar) {
888 }
889};
890
891/**
892 * Initializes the results container helpers if they are enabled and do
893 * not exist
894 *
895 * @method _initContainerHelpers
896 * @private
897 */
898YAHOO.widget.AutoComplete.prototype._initContainerHelpers = function() {
899 if(this.useShadow && !this._oContainer._oShadow) {
900 var oShadow = document.createElement("div");
901 oShadow.className = "yui-ac-shadow";
902 this._oContainer._oShadow = this._oContainer.appendChild(oShadow);
903 }
904 if(this.useIFrame && !this._oContainer._oIFrame) {
905 var oIFrame = document.createElement("iframe");
906 oIFrame.src = this._iFrameSrc;
907 oIFrame.frameBorder = 0;
908 oIFrame.scrolling = "no";
909 oIFrame.style.position = "absolute";
910 oIFrame.style.width = "100%";
911 oIFrame.style.height = "100%";
912 oIFrame.tabIndex = -1;
913 this._oContainer._oIFrame = this._oContainer.appendChild(oIFrame);
914 }
915};
916
917/**
918 * Initializes the results container once at object creation
919 *
920 * @method _initContainer
921 * @private
922 */
923YAHOO.widget.AutoComplete.prototype._initContainer = function() {
924 if(!this._oContainer._oContent) {
925 // The oContent div helps size the iframe and shadow properly
926 var oContent = document.createElement("div");
927 oContent.className = "yui-ac-content";
928 oContent.style.display = "none";
929 this._oContainer._oContent = this._oContainer.appendChild(oContent);
930
931 var oHeader = document.createElement("div");
932 oHeader.className = "yui-ac-hd";
933 oHeader.style.display = "none";
934 this._oContainer._oContent._oHeader = this._oContainer._oContent.appendChild(oHeader);
935
936 var oBody = document.createElement("div");
937 oBody.className = "yui-ac-bd";
938 this._oContainer._oContent._oBody = this._oContainer._oContent.appendChild(oBody);
939
940 var oFooter = document.createElement("div");
941 oFooter.className = "yui-ac-ft";
942 oFooter.style.display = "none";
943 this._oContainer._oContent._oFooter = this._oContainer._oContent.appendChild(oFooter);
944 }
945 else {
946 }
947};
948
949/**
950 * Clears out contents of container body and creates up to
951 * YAHOO.widget.AutoComplete#maxResultsDisplayed &lt;li&gt; elements in an
952 * &lt;ul&gt; element.
953 *
954 * @method _initList
955 * @private
956 */
957YAHOO.widget.AutoComplete.prototype._initList = function() {
958 this._aListItems = [];
959 while(this._oContainer._oContent._oBody.hasChildNodes()) {
960 var oldListItems = this.getListItems();
961 if(oldListItems) {
962 for(var oldi = oldListItems.length-1; oldi >= 0; i--) {
963 oldListItems[oldi] = null;
964 }
965 }
966 this._oContainer._oContent._oBody.innerHTML = "";
967 }
968
969 var oList = document.createElement("ul");
970 oList = this._oContainer._oContent._oBody.appendChild(oList);
971 for(var i=0; i<this.maxResultsDisplayed; i++) {
972 var oItem = document.createElement("li");
973 oItem = oList.appendChild(oItem);
974 this._aListItems[i] = oItem;
975 this._initListItem(oItem, i);
976 }
977 this._maxResultsDisplayed = this.maxResultsDisplayed;
978};
979
980/**
981 * Initializes each &lt;li&gt; element in the container list.
982 *
983 * @method _initListItem
984 * @param oItem {HTMLElement} The &lt;li&gt; DOM element.
985 * @param nItemIndex {Number} The index of the element.
986 * @private
987 */
988YAHOO.widget.AutoComplete.prototype._initListItem = function(oItem, nItemIndex) {
989 var oSelf = this;
990 oItem.style.display = "none";
991 oItem._nItemIndex = nItemIndex;
992
993 oItem.mouseover = oItem.mouseout = oItem.onclick = null;
994 YAHOO.util.Event.addListener(oItem,"mouseover",oSelf._onItemMouseover,oSelf);
995 YAHOO.util.Event.addListener(oItem,"mouseout",oSelf._onItemMouseout,oSelf);
996 YAHOO.util.Event.addListener(oItem,"click",oSelf._onItemMouseclick,oSelf);
997};
998
999/**
1000 * Enables interval detection for Korean IME support.
1001 *
1002 * @method _onIMEDetected
1003 * @param oSelf {Object} The AutoComplete instance.
1004 * @private
1005 */
1006YAHOO.widget.AutoComplete.prototype._onIMEDetected = function(oSelf) {
1007 oSelf._enableIntervalDetection();
1008};
1009
1010/**
1011 * Enables query triggers based on text input detection by intervals (rather
1012 * than by key events).
1013 *
1014 * @method _enableIntervalDetection
1015 * @private
1016 */
1017YAHOO.widget.AutoComplete.prototype._enableIntervalDetection = function() {
1018 var currValue = this._oTextbox.value;
1019 var lastValue = this._sLastTextboxValue;
1020 if(currValue != lastValue) {
1021 this._sLastTextboxValue = currValue;
1022 this._sendQuery(currValue);
1023 }
1024};
1025
1026/**
1027 * Cancels text input detection by intervals.
1028 *
1029 * @method _cancelIntervalDetection
1030 * @param oSelf {Object} The AutoComplete instance.
1031 * @private
1032 */
1033YAHOO.widget.AutoComplete.prototype._cancelIntervalDetection = function(oSelf) {
1034 if(oSelf._queryInterval) {
1035 clearInterval(oSelf._queryInterval);
1036 }
1037};
1038
1039/**
1040 * Whether or not key is functional or should be ignored. Note that the right
1041 * arrow key is NOT an ignored key since it triggers queries for certain intl
1042 * charsets.
1043 *
1044 * @method _isIgnoreKey
1045 * @param nKeycode {Number} Code of key pressed.
1046 * @return {Boolean} True if key should be ignored, false otherwise.
1047 * @private
1048 */
1049YAHOO.widget.AutoComplete.prototype._isIgnoreKey = function(nKeyCode) {
1050 if ((nKeyCode == 9) || (nKeyCode == 13) || // tab, enter
1051 (nKeyCode == 16) || (nKeyCode == 17) || // shift, ctl
1052 (nKeyCode >= 18 && nKeyCode <= 20) || // alt,pause/break,caps lock
1053 (nKeyCode == 27) || // esc
1054 (nKeyCode >= 33 && nKeyCode <= 35) || // page up,page down,end
1055 (nKeyCode >= 36 && nKeyCode <= 38) || // home,left,up
1056 (nKeyCode == 40) || // down
1057 (nKeyCode >= 44 && nKeyCode <= 45)) { // print screen,insert
1058 return true;
1059 }
1060 return false;
1061};
1062
1063/**
1064 * Makes query request to the DataSource.
1065 *
1066 * @method _sendQuery
1067 * @param sQuery {String} Query string.
1068 * @private
1069 */
1070YAHOO.widget.AutoComplete.prototype._sendQuery = function(sQuery) {
1071 // Widget has been effectively turned off
1072 if(this.minQueryLength == -1) {
1073 this._toggleContainer(false);
1074 return;
1075 }
1076 // Delimiter has been enabled
1077 var aDelimChar = (this.delimChar) ? this.delimChar : null;
1078 if(aDelimChar) {
1079 // Loop through all possible delimiters and find the latest one
1080 // A " " may be a false positive if they are defined as delimiters AND
1081 // are used to separate delimited queries
1082 var nDelimIndex = -1;
1083 for(var i = aDelimChar.length-1; i >= 0; i--) {
1084 var nNewIndex = sQuery.lastIndexOf(aDelimChar[i]);
1085 if(nNewIndex > nDelimIndex) {
1086 nDelimIndex = nNewIndex;
1087 }
1088 }
1089 // If we think the last delimiter is a space (" "), make sure it is NOT
1090 // a false positive by also checking the char directly before it
1091 if(aDelimChar[i] == " ") {
1092 for (var j = aDelimChar.length-1; j >= 0; j--) {
1093 if(sQuery[nDelimIndex - 1] == aDelimChar[j]) {
1094 nDelimIndex--;
1095 break;
1096 }
1097 }
1098 }
1099 // A delimiter has been found so extract the latest query
1100 if (nDelimIndex > -1) {
1101 var nQueryStart = nDelimIndex + 1;
1102 // Trim any white space from the beginning...
1103 while(sQuery.charAt(nQueryStart) == " ") {
1104 nQueryStart += 1;
1105 }
1106 // ...and save the rest of the string for later
1107 this._sSavedQuery = sQuery.substring(0,nQueryStart);
1108 // Here is the query itself
1109 sQuery = sQuery.substr(nQueryStart);
1110 }
1111 else if(sQuery.indexOf(this._sSavedQuery) < 0){
1112 this._sSavedQuery = null;
1113 }
1114 }
1115
1116 // Don't search queries that are too short
1117 if (sQuery && (sQuery.length < this.minQueryLength) || (!sQuery && this.minQueryLength > 0)) {
1118 if (this._nDelayID != -1) {
1119 clearTimeout(this._nDelayID);
1120 }
1121 this._toggleContainer(false);
1122 return;
1123 }
1124
1125 sQuery = encodeURIComponent(sQuery);
1126 this._nDelayID = -1; // Reset timeout ID because request has been made
1127 this.dataRequestEvent.fire(this, sQuery);
1128 this.dataSource.getResults(this._populateList, sQuery, this);
1129};
1130
1131/**
1132 * Populates the array of &lt;li&gt; elements in the container with query
1133 * results. This method is passed to YAHOO.widget.DataSource#getResults as a
1134 * callback function so results from the DataSource instance are returned to the
1135 * AutoComplete instance.
1136 *
1137 * @method _populateList
1138 * @param sQuery {String} The query string.
1139 * @param aResults {Array} An array of query result objects from the DataSource.
1140 * @param oSelf {Object} The AutoComplete instance.
1141 * @private
1142 */
1143YAHOO.widget.AutoComplete.prototype._populateList = function(sQuery, aResults, oSelf) {
1144 if(aResults === null) {
1145 oSelf.dataErrorEvent.fire(oSelf, sQuery);
1146 }
1147 if (!oSelf._bFocused || !aResults) {
1148 return;
1149 }
1150
1151 var isOpera = (navigator.userAgent.toLowerCase().indexOf("opera") != -1);
1152 var contentStyle = oSelf._oContainer._oContent.style;
1153 contentStyle.width = (!isOpera) ? null : "";
1154 contentStyle.height = (!isOpera) ? null : "";
1155
1156 var sCurQuery = decodeURIComponent(sQuery);
1157 oSelf._sCurQuery = sCurQuery;
1158 oSelf._bItemSelected = false;
1159
1160 if(oSelf._maxResultsDisplayed != oSelf.maxResultsDisplayed) {
1161 oSelf._initList();
1162 }
1163
1164 var nItems = Math.min(aResults.length,oSelf.maxResultsDisplayed);
1165 oSelf._nDisplayedItems = nItems;
1166 if (nItems > 0) {
1167 oSelf._initContainerHelpers();
1168 var aItems = oSelf._aListItems;
1169
1170 // Fill items with data
1171 for(var i = nItems-1; i >= 0; i--) {
1172 var oItemi = aItems[i];
1173 var oResultItemi = aResults[i];
1174 oItemi.innerHTML = oSelf.formatResult(oResultItemi, sCurQuery);
1175 oItemi.style.display = "list-item";
1176 oItemi._sResultKey = oResultItemi[0];
1177 oItemi._oResultData = oResultItemi;
1178
1179 }
1180
1181 // Empty out remaining items if any
1182 for(var j = aItems.length-1; j >= nItems ; j--) {
1183 var oItemj = aItems[j];
1184 oItemj.innerHTML = null;
1185 oItemj.style.display = "none";
1186 oItemj._sResultKey = null;
1187 oItemj._oResultData = null;
1188 }
1189
1190 if(oSelf.autoHighlight) {
1191 // Go to the first item
1192 var oFirstItem = aItems[0];
1193 oSelf._toggleHighlight(oFirstItem,"to");
1194 oSelf.itemArrowToEvent.fire(oSelf, oFirstItem);
1195 oSelf._typeAhead(oFirstItem,sQuery);
1196 }
1197 else {
1198 oSelf._oCurItem = null;
1199 }
1200
1201 // Expand the container
1202 var ok = oSelf.doBeforeExpandContainer(oSelf._oTextbox, oSelf._oContainer, sQuery, aResults);
1203 oSelf._toggleContainer(ok);
1204 }
1205 else {
1206 oSelf._toggleContainer(false);
1207 }
1208 oSelf.dataReturnEvent.fire(oSelf, sQuery, aResults);
1209};
1210
1211/**
1212 * When forceSelection is true and the user attempts
1213 * leave the text input box without selecting an item from the query results,
1214 * the user selection is cleared.
1215 *
1216 * @method _clearSelection
1217 * @private
1218 */
1219YAHOO.widget.AutoComplete.prototype._clearSelection = function() {
1220 var sValue = this._oTextbox.value;
1221 var sChar = (this.delimChar) ? this.delimChar[0] : null;
1222 var nIndex = (sChar) ? sValue.lastIndexOf(sChar, sValue.length-2) : -1;
1223 if(nIndex > -1) {
1224 this._oTextbox.value = sValue.substring(0,nIndex);
1225 }
1226 else {
1227 this._oTextbox.value = "";
1228 }
1229 this._sSavedQuery = this._oTextbox.value;
1230
1231 // Fire custom event
1232 this.selectionEnforceEvent.fire(this);
1233};
1234
1235/**
1236 * Whether or not user-typed value in the text input box matches any of the
1237 * query results.
1238 *
1239 * @method _textMatchesOption
1240 * @return {Boolean} True if user-input text matches a result, false otherwise.
1241 * @private
1242 */
1243YAHOO.widget.AutoComplete.prototype._textMatchesOption = function() {
1244 var foundMatch = false;
1245
1246 for(var i = this._nDisplayedItems-1; i >= 0 ; i--) {
1247 var oItem = this._aListItems[i];
1248 var sMatch = oItem._sResultKey.toLowerCase();
1249 if (sMatch == this._sCurQuery.toLowerCase()) {
1250 foundMatch = true;
1251 break;
1252 }
1253 }
1254 return(foundMatch);
1255};
1256
1257/**
1258 * Updates in the text input box with the first query result as the user types,
1259 * selecting the substring that the user has not typed.
1260 *
1261 * @method _typeAhead
1262 * @param oItem {HTMLElement} The &lt;li&gt; element item whose data populates the input field.
1263 * @param sQuery {String} Query string.
1264 * @private
1265 */
1266YAHOO.widget.AutoComplete.prototype._typeAhead = function(oItem, sQuery) {
1267 // Don't update if turned off
1268 if (!this.typeAhead) {
1269 return;
1270 }
1271
1272 var oTextbox = this._oTextbox;
1273 var sValue = this._oTextbox.value; // any saved queries plus what user has typed
1274
1275 // Don't update with type-ahead if text selection is not supported
1276 if(!oTextbox.setSelectionRange && !oTextbox.createTextRange) {
1277 return;
1278 }
1279
1280 // Select the portion of text that the user has not typed
1281 var nStart = sValue.length;
1282 this._updateValue(oItem);
1283 var nEnd = oTextbox.value.length;
1284 this._selectText(oTextbox,nStart,nEnd);
1285 var sPrefill = oTextbox.value.substr(nStart,nEnd);
1286 this.typeAheadEvent.fire(this,sQuery,sPrefill);
1287};
1288
1289/**
1290 * Selects text in the input field.
1291 *
1292 * @method _selectText
1293 * @param oTextbox {HTMLElement} Text input box element in which to select text.
1294 * @param nStart {Number} Starting index of text string to select.
1295 * @param nEnd {Number} Ending index of text selection.
1296 * @private
1297 */
1298YAHOO.widget.AutoComplete.prototype._selectText = function(oTextbox, nStart, nEnd) {
1299 if (oTextbox.setSelectionRange) { // For Mozilla
1300 oTextbox.setSelectionRange(nStart,nEnd);
1301 }
1302 else if (oTextbox.createTextRange) { // For IE
1303 var oTextRange = oTextbox.createTextRange();
1304 oTextRange.moveStart("character", nStart);
1305 oTextRange.moveEnd("character", nEnd-oTextbox.value.length);
1306 oTextRange.select();
1307 }
1308 else {
1309 oTextbox.select();
1310 }
1311};
1312
1313/**
1314 * Syncs results container with its helpers.
1315 *
1316 * @method _toggleContainerHelpers
1317 * @param bShow {Boolean} True if container is expanded, false if collapsed
1318 * @private
1319 */
1320YAHOO.widget.AutoComplete.prototype._toggleContainerHelpers = function(bShow) {
1321 var bFireEvent = false;
1322 var width = this._oContainer._oContent.offsetWidth + "px";
1323 var height = this._oContainer._oContent.offsetHeight + "px";
1324
1325 if(this.useIFrame && this._oContainer._oIFrame) {
1326 bFireEvent = true;
1327 if(bShow) {
1328 this._oContainer._oIFrame.style.width = width;
1329 this._oContainer._oIFrame.style.height = height;
1330 }
1331 else {
1332 this._oContainer._oIFrame.style.width = 0;
1333 this._oContainer._oIFrame.style.height = 0;
1334 }
1335 }
1336 if(this.useShadow && this._oContainer._oShadow) {
1337 bFireEvent = true;
1338 if(bShow) {
1339 this._oContainer._oShadow.style.width = width;
1340 this._oContainer._oShadow.style.height = height;
1341 }
1342 else {
1343 this._oContainer._oShadow.style.width = 0;
1344 this._oContainer._oShadow.style.height = 0;
1345 }
1346 }
1347};
1348
1349/**
1350 * Animates expansion or collapse of the container.
1351 *
1352 * @method _toggleContainer
1353 * @param bShow {Boolean} True if container should be expanded, false if container should be collapsed
1354 * @private
1355 */
1356YAHOO.widget.AutoComplete.prototype._toggleContainer = function(bShow) {
1357 var oContainer = this._oContainer;
1358
1359 // Implementer has container always open so don't mess with it
1360 if(this.alwaysShowContainer && this._bContainerOpen) {
1361 return;
1362 }
1363
1364 // Clear contents of container
1365 if(!bShow) {
1366 this._oContainer._oContent.scrollTop = 0;
1367 var aItems = this._aListItems;
1368
1369 if(aItems && (aItems.length > 0)) {
1370 for(var i = aItems.length-1; i >= 0 ; i--) {
1371 aItems[i].style.display = "none";
1372 }
1373 }
1374
1375 if (this._oCurItem) {
1376 this._toggleHighlight(this._oCurItem,"from");
1377 }
1378
1379 this._oCurItem = null;
1380 this._nDisplayedItems = 0;
1381 this._sCurQuery = null;
1382 }
1383
1384 // Container is already closed
1385 if (!bShow && !this._bContainerOpen) {
1386 oContainer._oContent.style.display = "none";
1387 return;
1388 }
1389
1390 // If animation is enabled...
1391 var oAnim = this._oAnim;
1392 if (oAnim && oAnim.getEl() && (this.animHoriz || this.animVert)) {
1393 // If helpers need to be collapsed, do it right away...
1394 // but if helpers need to be expanded, wait until after the container expands
1395 if(!bShow) {
1396 this._toggleContainerHelpers(bShow);
1397 }
1398
1399 if(oAnim.isAnimated()) {
1400 oAnim.stop();
1401 }
1402
1403 // Clone container to grab current size offscreen
1404 var oClone = oContainer._oContent.cloneNode(true);
1405 oContainer.appendChild(oClone);
1406 oClone.style.top = "-9000px";
1407 oClone.style.display = "block";
1408
1409 // Current size of the container is the EXPANDED size
1410 var wExp = oClone.offsetWidth;
1411 var hExp = oClone.offsetHeight;
1412
1413 // Calculate COLLAPSED sizes based on horiz and vert anim
1414 var wColl = (this.animHoriz) ? 0 : wExp;
1415 var hColl = (this.animVert) ? 0 : hExp;
1416
1417 // Set animation sizes
1418 oAnim.attributes = (bShow) ?
1419 {width: { to: wExp }, height: { to: hExp }} :
1420 {width: { to: wColl}, height: { to: hColl }};
1421
1422 // If opening anew, set to a collapsed size...
1423 if(bShow && !this._bContainerOpen) {
1424 oContainer._oContent.style.width = wColl+"px";
1425 oContainer._oContent.style.height = hColl+"px";
1426 }
1427 // Else, set it to its last known size.
1428 else {
1429 oContainer._oContent.style.width = wExp+"px";
1430 oContainer._oContent.style.height = hExp+"px";
1431 }
1432
1433 oContainer.removeChild(oClone);
1434 oClone = null;
1435
1436 var oSelf = this;
1437 var onAnimComplete = function() {
1438 // Finish the collapse
1439 oAnim.onComplete.unsubscribeAll();
1440
1441 if(bShow) {
1442 oSelf.containerExpandEvent.fire(oSelf);
1443 }
1444 else {
1445 oContainer._oContent.style.display = "none";
1446 oSelf.containerCollapseEvent.fire(oSelf);
1447 }
1448 oSelf._toggleContainerHelpers(bShow);
1449 };
1450
1451 // Display container and animate it
1452 oContainer._oContent.style.display = "block";
1453 oAnim.onComplete.subscribe(onAnimComplete);
1454 oAnim.animate();
1455 this._bContainerOpen = bShow;
1456 }
1457 // Else don't animate, just show or hide
1458 else {
1459 if(bShow) {
1460 oContainer._oContent.style.display = "block";
1461 this.containerExpandEvent.fire(this);
1462 }
1463 else {
1464 oContainer._oContent.style.display = "none";
1465 this.containerCollapseEvent.fire(this);
1466 }
1467 this._toggleContainerHelpers(bShow);
1468 this._bContainerOpen = bShow;
1469 }
1470
1471};
1472
1473/**
1474 * Toggles the highlight on or off for an item in the container, and also cleans
1475 * up highlighting of any previous item.
1476 *
1477 * @method _toggleHighlight
1478 * @param oNewItem {HTMLElement} The &lt;li&gt; element item to receive highlight behavior.
1479 * @param sType {String} Type "mouseover" will toggle highlight on, and "mouseout" will toggle highlight off.
1480 * @private
1481 */
1482YAHOO.widget.AutoComplete.prototype._toggleHighlight = function(oNewItem, sType) {
1483 var sHighlight = this.highlightClassName;
1484 if(this._oCurItem) {
1485 // Remove highlight from old item
1486 YAHOO.util.Dom.removeClass(this._oCurItem, sHighlight);
1487 }
1488
1489 if((sType == "to") && sHighlight) {
1490 // Apply highlight to new item
1491 YAHOO.util.Dom.addClass(oNewItem, sHighlight);
1492 this._oCurItem = oNewItem;
1493 }
1494};
1495
1496/**
1497 * Toggles the pre-highlight on or off for an item in the container.
1498 *
1499 * @method _togglePrehighlight
1500 * @param oNewItem {HTMLElement} The &lt;li&gt; element item to receive highlight behavior.
1501 * @param sType {String} Type "mouseover" will toggle highlight on, and "mouseout" will toggle highlight off.
1502 * @private
1503 */
1504YAHOO.widget.AutoComplete.prototype._togglePrehighlight = function(oNewItem, sType) {
1505 if(oNewItem == this._oCurItem) {
1506 return;
1507 }
1508
1509 var sPrehighlight = this.prehighlightClassName;
1510 if((sType == "mouseover") && sPrehighlight) {
1511 // Apply prehighlight to new item
1512 YAHOO.util.Dom.addClass(oNewItem, sPrehighlight);
1513 }
1514 else {
1515 // Remove prehighlight from old item
1516 YAHOO.util.Dom.removeClass(oNewItem, sPrehighlight);
1517 }
1518};
1519
1520/**
1521 * Updates the text input box value with selected query result. If a delimiter
1522 * has been defined, then the value gets appended with the delimiter.
1523 *
1524 * @method _updateValue
1525 * @param oItem {HTMLElement} The &lt;li&gt; element item with which to update the value.
1526 * @private
1527 */
1528YAHOO.widget.AutoComplete.prototype._updateValue = function(oItem) {
1529 var oTextbox = this._oTextbox;
1530 var sDelimChar = (this.delimChar) ? (this.delimChar[0] || this.delimChar) : null;
1531 var sSavedQuery = this._sSavedQuery;
1532 var sResultKey = oItem._sResultKey;
1533 oTextbox.focus();
1534
1535 // First clear text field
1536 oTextbox.value = "";
1537 // Grab data to put into text field
1538 if(sDelimChar) {
1539 if(sSavedQuery) {
1540 oTextbox.value = sSavedQuery;
1541 }
1542 oTextbox.value += sResultKey + sDelimChar;
1543 if(sDelimChar != " ") {
1544 oTextbox.value += " ";
1545 }
1546 }
1547 else { oTextbox.value = sResultKey; }
1548
1549 // scroll to bottom of textarea if necessary
1550 if(oTextbox.type == "textarea") {
1551 oTextbox.scrollTop = oTextbox.scrollHeight;
1552 }
1553
1554 // move cursor to end
1555 var end = oTextbox.value.length;
1556 this._selectText(oTextbox,end,end);
1557
1558 this._oCurItem = oItem;
1559};
1560
1561/**
1562 * Selects a result item from the container
1563 *
1564 * @method _selectItem
1565 * @param oItem {HTMLElement} The selected &lt;li&gt; element item.
1566 * @private
1567 */
1568YAHOO.widget.AutoComplete.prototype._selectItem = function(oItem) {
1569 this._bItemSelected = true;
1570 this._updateValue(oItem);
1571 this._cancelIntervalDetection(this);
1572 this.itemSelectEvent.fire(this, oItem, oItem._oResultData);
1573 this._toggleContainer(false);
1574};
1575
1576/**
1577 * For values updated by type-ahead, the right arrow key jumps to the end
1578 * of the textbox, otherwise the container is closed.
1579 *
1580 * @method _jumpSelection
1581 * @private
1582 */
1583YAHOO.widget.AutoComplete.prototype._jumpSelection = function() {
1584 if(!this.typeAhead) {
1585 return;
1586 }
1587 else {
1588 this._toggleContainer(false);
1589 }
1590};
1591
1592/**
1593 * Triggered by up and down arrow keys, changes the current highlighted
1594 * &lt;li&gt; element item. Scrolls container if necessary.
1595 *
1596 * @method _moveSelection
1597 * @param nKeyCode {Number} Code of key pressed.
1598 * @private
1599 */
1600YAHOO.widget.AutoComplete.prototype._moveSelection = function(nKeyCode) {
1601 if(this._bContainerOpen) {
1602 // Determine current item's id number
1603 var oCurItem = this._oCurItem;
1604 var nCurItemIndex = -1;
1605
1606 if (oCurItem) {
1607 nCurItemIndex = oCurItem._nItemIndex;
1608 }
1609
1610 var nNewItemIndex = (nKeyCode == 40) ?
1611 (nCurItemIndex + 1) : (nCurItemIndex - 1);
1612
1613 // Out of bounds
1614 if (nNewItemIndex < -2 || nNewItemIndex >= this._nDisplayedItems) {
1615 return;
1616 }
1617
1618 if (oCurItem) {
1619 // Unhighlight current item
1620 this._toggleHighlight(oCurItem, "from");
1621 this.itemArrowFromEvent.fire(this, oCurItem);
1622 }
1623 if (nNewItemIndex == -1) {
1624 // Go back to query (remove type-ahead string)
1625 if(this.delimChar && this._sSavedQuery) {
1626 if (!this._textMatchesOption()) {
1627 this._oTextbox.value = this._sSavedQuery;
1628 }
1629 else {
1630 this._oTextbox.value = this._sSavedQuery + this._sCurQuery;
1631 }
1632 }
1633 else {
1634 this._oTextbox.value = this._sCurQuery;
1635 }
1636 this._oCurItem = null;
1637 return;
1638 }
1639 if (nNewItemIndex == -2) {
1640 // Close container
1641 this._toggleContainer(false);
1642 return;
1643 }
1644
1645 var oNewItem = this._aListItems[nNewItemIndex];
1646
1647 // Scroll the container if necessary
1648 var oContent = this._oContainer._oContent;
1649 var scrollOn = ((YAHOO.util.Dom.getStyle(oContent,"overflow") == "auto") ||
1650 (YAHOO.util.Dom.getStyle(oContent,"overflowY") == "auto"));
1651 if(scrollOn && (nNewItemIndex > -1) &&
1652 (nNewItemIndex < this._nDisplayedItems)) {
1653 // User is keying down
1654 if(nKeyCode == 40) {
1655 // Bottom of selected item is below scroll area...
1656 if((oNewItem.offsetTop+oNewItem.offsetHeight) > (oContent.scrollTop + oContent.offsetHeight)) {
1657 // Set bottom of scroll area to bottom of selected item
1658 oContent.scrollTop = (oNewItem.offsetTop+oNewItem.offsetHeight) - oContent.offsetHeight;
1659 }
1660 // Bottom of selected item is above scroll area...
1661 else if((oNewItem.offsetTop+oNewItem.offsetHeight) < oContent.scrollTop) {
1662 // Set top of selected item to top of scroll area
1663 oContent.scrollTop = oNewItem.offsetTop;
1664
1665 }
1666 }
1667 // User is keying up
1668 else {
1669 // Top of selected item is above scroll area
1670 if(oNewItem.offsetTop < oContent.scrollTop) {
1671 // Set top of scroll area to top of selected item
1672 this._oContainer._oContent.scrollTop = oNewItem.offsetTop;
1673 }
1674 // Top of selected item is below scroll area
1675 else if(oNewItem.offsetTop > (oContent.scrollTop + oContent.offsetHeight)) {
1676 // Set bottom of selected item to bottom of scroll area
1677 this._oContainer._oContent.scrollTop = (oNewItem.offsetTop+oNewItem.offsetHeight) - oContent.offsetHeight;
1678 }
1679 }
1680 }
1681
1682 this._toggleHighlight(oNewItem, "to");
1683 this.itemArrowToEvent.fire(this, oNewItem);
1684 if(this.typeAhead) {
1685 this._updateValue(oNewItem);
1686 }
1687 }
1688};
1689
1690/////////////////////////////////////////////////////////////////////////////
1691//
1692// Private event handlers
1693//
1694/////////////////////////////////////////////////////////////////////////////
1695
1696/**
1697 * Handles &lt;li&gt; element mouseover events in the container.
1698 *
1699 * @method _onItemMouseover
1700 * @param v {HTMLEvent} The mouseover event.
1701 * @param oSelf {Object} The AutoComplete instance.
1702 * @private
1703 */
1704YAHOO.widget.AutoComplete.prototype._onItemMouseover = function(v,oSelf) {
1705 if(oSelf.prehighlightClassName) {
1706 oSelf._togglePrehighlight(this,"mouseover");
1707 }
1708 else {
1709 oSelf._toggleHighlight(this,"to");
1710 }
1711
1712 oSelf.itemMouseOverEvent.fire(oSelf, this);
1713};
1714
1715/**
1716 * Handles &lt;li&gt; element mouseout events in the container.
1717 *
1718 * @method _onItemMouseout
1719 * @param v {HTMLEvent} The mouseout event.
1720 * @param oSelf {Object} The AutoComplete instance.
1721 * @private
1722 */
1723YAHOO.widget.AutoComplete.prototype._onItemMouseout = function(v,oSelf) {
1724 if(oSelf.prehighlightClassName) {
1725 oSelf._togglePrehighlight(this,"mouseout");
1726 }
1727 else {
1728 oSelf._toggleHighlight(this,"from");
1729 }
1730
1731 oSelf.itemMouseOutEvent.fire(oSelf, this);
1732};
1733
1734/**
1735 * Handles &lt;li&gt; element click events in the container.
1736 *
1737 * @method _onItemMouseclick
1738 * @param v {HTMLEvent} The click event.
1739 * @param oSelf {Object} The AutoComplete instance.
1740 * @private
1741 */
1742YAHOO.widget.AutoComplete.prototype._onItemMouseclick = function(v,oSelf) {
1743 // In case item has not been moused over
1744 oSelf._toggleHighlight(this,"to");
1745 oSelf._selectItem(this);
1746};
1747
1748/**
1749 * Handles container mouseover events.
1750 *
1751 * @method _onContainerMouseover
1752 * @param v {HTMLEvent} The mouseover event.
1753 * @param oSelf {Object} The AutoComplete instance.
1754 * @private
1755 */
1756YAHOO.widget.AutoComplete.prototype._onContainerMouseover = function(v,oSelf) {
1757 oSelf._bOverContainer = true;
1758};
1759
1760/**
1761 * Handles container mouseout events.
1762 *
1763 * @method _onContainerMouseout
1764 * @param v {HTMLEvent} The mouseout event.
1765 * @param oSelf {Object} The AutoComplete instance.
1766 * @private
1767 */
1768YAHOO.widget.AutoComplete.prototype._onContainerMouseout = function(v,oSelf) {
1769 oSelf._bOverContainer = false;
1770 // If container is still active
1771 if(oSelf._oCurItem) {
1772 oSelf._toggleHighlight(oSelf._oCurItem,"to");
1773 }
1774};
1775
1776/**
1777 * Handles container scroll events.
1778 *
1779 * @method _onContainerScroll
1780 * @param v {HTMLEvent} The scroll event.
1781 * @param oSelf {Object} The AutoComplete instance.
1782 * @private
1783 */
1784YAHOO.widget.AutoComplete.prototype._onContainerScroll = function(v,oSelf) {
1785 oSelf._oTextbox.focus();
1786};
1787
1788/**
1789 * Handles container resize events.
1790 *
1791 * @method _onContainerResize
1792 * @param v {HTMLEvent} The resize event.
1793 * @param oSelf {Object} The AutoComplete instance.
1794 * @private
1795 */
1796YAHOO.widget.AutoComplete.prototype._onContainerResize = function(v,oSelf) {
1797 oSelf._toggleContainerHelpers(oSelf._bContainerOpen);
1798};
1799
1800/**
1801 * Handles textbox keydown events of functional keys, mainly for UI behavior.
1802 *
1803 * @method _onTextboxKeyDown
1804 * @param v {HTMLEvent} The keydown event.
1805 * @param oSelf {object} The AutoComplete instance.
1806 * @private
1807 */
1808YAHOO.widget.AutoComplete.prototype._onTextboxKeyDown = function(v,oSelf) {
1809 var nKeyCode = v.keyCode;
1810
1811 switch (nKeyCode) {
1812 case 9: // tab
1813 if(oSelf.delimChar && (oSelf._nKeyCode != nKeyCode)) {
1814 if(oSelf._bContainerOpen) {
1815 YAHOO.util.Event.stopEvent(v);
1816 }
1817 }
1818 // select an item or clear out
1819 if(oSelf._oCurItem) {
1820 oSelf._selectItem(oSelf._oCurItem);
1821 }
1822 else {
1823 oSelf._toggleContainer(false);
1824 }
1825 break;
1826 case 13: // enter
1827 if(oSelf._nKeyCode != nKeyCode) {
1828 if(oSelf._bContainerOpen) {
1829 YAHOO.util.Event.stopEvent(v);
1830 }
1831 }
1832 if(oSelf._oCurItem) {
1833 oSelf._selectItem(oSelf._oCurItem);
1834 }
1835 else {
1836 oSelf._toggleContainer(false);
1837 }
1838 break;
1839 case 27: // esc
1840 oSelf._toggleContainer(false);
1841 return;
1842 case 39: // right
1843 oSelf._jumpSelection();
1844 break;
1845 case 38: // up
1846 YAHOO.util.Event.stopEvent(v);
1847 oSelf._moveSelection(nKeyCode);
1848 break;
1849 case 40: // down
1850 YAHOO.util.Event.stopEvent(v);
1851 oSelf._moveSelection(nKeyCode);
1852 break;
1853 default:
1854 break;
1855 }
1856};
1857
1858/**
1859 * Handles textbox keypress events.
1860 * @method _onTextboxKeyPress
1861 * @param v {HTMLEvent} The keypress event.
1862 * @param oSelf {Object} The AutoComplete instance.
1863 * @private
1864 */
1865YAHOO.widget.AutoComplete.prototype._onTextboxKeyPress = function(v,oSelf) {
1866 var nKeyCode = v.keyCode;
1867
1868 //Expose only to Mac browsers, where stopEvent is ineffective on keydown events (bug 790337)
1869 var isMac = (navigator.userAgent.toLowerCase().indexOf("mac") != -1);
1870 if(isMac) {
1871 switch (nKeyCode) {
1872 case 9: // tab
1873 if(oSelf.delimChar && (oSelf._nKeyCode != nKeyCode)) {
1874 if(oSelf._bContainerOpen) {
1875 YAHOO.util.Event.stopEvent(v);
1876 }
1877 }
1878 break;
1879 case 13: // enter
1880 if(oSelf._nKeyCode != nKeyCode) {
1881 if(oSelf._bContainerOpen) {
1882 YAHOO.util.Event.stopEvent(v);
1883 }
1884 }
1885 break;
1886 case 38: // up
1887 case 40: // down
1888 YAHOO.util.Event.stopEvent(v);
1889 break;
1890 default:
1891 break;
1892 }
1893 }
1894
1895 //TODO: (?) limit only to non-IE, non-Mac-FF for Korean IME support (bug 811948)
1896 // Korean IME detected
1897 else if(nKeyCode == 229) {
1898 oSelf._queryInterval = setInterval(function() { oSelf._onIMEDetected(oSelf); },500);
1899 }
1900};
1901
1902/**
1903 * Handles textbox keyup events that trigger queries.
1904 *
1905 * @method _onTextboxKeyUp
1906 * @param v {HTMLEvent} The keyup event.
1907 * @param oSelf {Object} The AutoComplete instance.
1908 * @private
1909 */
1910YAHOO.widget.AutoComplete.prototype._onTextboxKeyUp = function(v,oSelf) {
1911 // Check to see if any of the public properties have been updated
1912 oSelf._initProps();
1913
1914 var nKeyCode = v.keyCode;
1915 oSelf._nKeyCode = nKeyCode;
1916 var sText = this.value; //string in textbox
1917
1918 // Filter out chars that don't trigger queries
1919 if (oSelf._isIgnoreKey(nKeyCode) || (sText.toLowerCase() == oSelf._sCurQuery)) {
1920 return;
1921 }
1922 else {
1923 oSelf.textboxKeyEvent.fire(oSelf, nKeyCode);
1924 }
1925
1926 // Set timeout on the request
1927 if (oSelf.queryDelay > 0) {
1928 var nDelayID =
1929 setTimeout(function(){oSelf._sendQuery(sText);},(oSelf.queryDelay * 1000));
1930
1931 if (oSelf._nDelayID != -1) {
1932 clearTimeout(oSelf._nDelayID);
1933 }
1934
1935 oSelf._nDelayID = nDelayID;
1936 }
1937 else {
1938 // No delay so send request immediately
1939 oSelf._sendQuery(sText);
1940 }
1941};
1942
1943/**
1944 * Handles text input box receiving focus.
1945 *
1946 * @method _onTextboxFocus
1947 * @param v {HTMLEvent} The focus event.
1948 * @param oSelf {Object} The AutoComplete instance.
1949 * @private
1950 */
1951YAHOO.widget.AutoComplete.prototype._onTextboxFocus = function (v,oSelf) {
1952 oSelf._oTextbox.setAttribute("autocomplete","off");
1953 oSelf._bFocused = true;
1954 oSelf.textboxFocusEvent.fire(oSelf);
1955};
1956
1957/**
1958 * Handles text input box losing focus.
1959 *
1960 * @method _onTextboxBlur
1961 * @param v {HTMLEvent} The focus event.
1962 * @param oSelf {Object} The AutoComplete instance.
1963 * @private
1964 */
1965YAHOO.widget.AutoComplete.prototype._onTextboxBlur = function (v,oSelf) {
1966 // Don't treat as a blur if it was a selection via mouse click
1967 if(!oSelf._bOverContainer || (oSelf._nKeyCode == 9)) {
1968 // Current query needs to be validated
1969 if(!oSelf._bItemSelected) {
1970 if(!oSelf._bContainerOpen || (oSelf._bContainerOpen && !oSelf._textMatchesOption())) {
1971 if(oSelf.forceSelection) {
1972 oSelf._clearSelection();
1973 }
1974 else {
1975 oSelf.unmatchedItemSelectEvent.fire(oSelf, oSelf._sCurQuery);
1976 }
1977 }
1978 }
1979
1980 if(oSelf._bContainerOpen) {
1981 oSelf._toggleContainer(false);
1982 }
1983 oSelf._cancelIntervalDetection(oSelf);
1984 oSelf._bFocused = false;
1985 oSelf.textboxBlurEvent.fire(oSelf);
1986 }
1987};
1988
1989/**
1990 * Handles form submission event.
1991 *
1992 * @method _onFormSubmit
1993 * @param v {HTMLEvent} The submit event.
1994 * @param oSelf {Object} The AutoComplete instance.
1995 * @private
1996 */
1997YAHOO.widget.AutoComplete.prototype._onFormSubmit = function(v,oSelf) {
1998 if(oSelf.allowBrowserAutocomplete) {
1999 oSelf._oTextbox.setAttribute("autocomplete","on");
2000 }
2001 else {
2002 oSelf._oTextbox.setAttribute("autocomplete","off");
2003 }
2004};
2005/****************************************************************************/
2006/****************************************************************************/
2007/****************************************************************************/
2008
2009/**
2010 * The DataSource classes manages sending a request and returning response from a live
2011 * database. Supported data include local JavaScript arrays and objects and databases
2012 * accessible via XHR connections. Supported response formats include JavaScript arrays,
2013 * JSON, XML, and flat-file textual data.
2014 *
2015 * @class DataSource
2016 * @constructor
2017 */
2018YAHOO.widget.DataSource = function() {
2019 /* abstract class */
2020};
2021
2022
2023/////////////////////////////////////////////////////////////////////////////
2024//
2025// Public constants
2026//
2027/////////////////////////////////////////////////////////////////////////////
2028
2029/**
2030 * Error message for null data responses.
2031 *
2032 * @property ERROR_DATANULL
2033 * @type String
2034 * @static
2035 * @final
2036 */
2037YAHOO.widget.DataSource.ERROR_DATANULL = "Response data was null";
2038
2039/**
2040 * Error message for data responses with parsing errors.
2041 *
2042 * @property ERROR_DATAPARSE
2043 * @type String
2044 * @static
2045 * @final
2046 */
2047YAHOO.widget.DataSource.ERROR_DATAPARSE = "Response data could not be parsed";
2048
2049
2050/////////////////////////////////////////////////////////////////////////////
2051//
2052// Public member variables
2053//
2054/////////////////////////////////////////////////////////////////////////////
2055
2056/**
2057 * Max size of the local cache. Set to 0 to turn off caching. Caching is
2058 * useful to reduce the number of server connections. Recommended only for data
2059 * sources that return comprehensive results for queries or when stale data is
2060 * not an issue.
2061 *
2062 * @property maxCacheEntries
2063 * @type Number
2064 * @default 15
2065 */
2066YAHOO.widget.DataSource.prototype.maxCacheEntries = 15;
2067
2068/**
2069 * Use this to equate cache matching with the type of matching done by your live
2070 * data source. If caching is on and queryMatchContains is true, the cache
2071 * returns results that "contain" the query string. By default,
2072 * queryMatchContains is set to false, meaning the cache only returns results
2073 * that "start with" the query string.
2074 *
2075 * @property queryMatchContains
2076 * @type Boolean
2077 * @default false
2078 */
2079YAHOO.widget.DataSource.prototype.queryMatchContains = false;
2080
2081/**
2082 * Enables query subset matching. If caching is on and queryMatchSubset is
2083 * true, substrings of queries will return matching cached results. For
2084 * instance, if the first query is for "abc" susequent queries that start with
2085 * "abc", like "abcd", will be queried against the cache, and not the live data
2086 * source. Recommended only for DataSources that return comprehensive results
2087 * for queries with very few characters.
2088 *
2089 * @property queryMatchSubset
2090 * @type Boolean
2091 * @default false
2092 *
2093 */
2094YAHOO.widget.DataSource.prototype.queryMatchSubset = false;
2095
2096/**
2097 * Enables query case-sensitivity matching. If caching is on and
2098 * queryMatchCase is true, queries will only return results for case-sensitive
2099 * matches.
2100 *
2101 * @property queryMatchCase
2102 * @type Boolean
2103 * @default false
2104 */
2105YAHOO.widget.DataSource.prototype.queryMatchCase = false;
2106
2107
2108/////////////////////////////////////////////////////////////////////////////
2109//
2110// Public methods
2111//
2112/////////////////////////////////////////////////////////////////////////////
2113
2114 /**
2115 * Public accessor to the unique name of the DataSource instance.
2116 *
2117 * @method toString
2118 * @return {String} Unique name of the DataSource instance
2119 */
2120YAHOO.widget.DataSource.prototype.toString = function() {
2121 return "DataSource " + this._sName;
2122};
2123
2124/**
2125 * Retrieves query results, first checking the local cache, then making the
2126 * query request to the live data source as defined by the function doQuery.
2127 *
2128 * @method getResults
2129 * @param oCallbackFn {HTMLFunction} Callback function defined by oParent object to which to return results.
2130 * @param sQuery {String} Query string.
2131 * @param oParent {Object} The object instance that has requested data.
2132 */
2133YAHOO.widget.DataSource.prototype.getResults = function(oCallbackFn, sQuery, oParent) {
2134
2135 // First look in cache
2136 var aResults = this._doQueryCache(oCallbackFn,sQuery,oParent);
2137
2138 // Not in cache, so get results from server
2139 if(aResults.length === 0) {
2140 this.queryEvent.fire(this, oParent, sQuery);
2141 this.doQuery(oCallbackFn, sQuery, oParent);
2142 }
2143};
2144
2145/**
2146 * Abstract method implemented by subclasses to make a query to the live data
2147 * source. Must call the callback function with the response returned from the
2148 * query. Populates cache (if enabled).
2149 *
2150 * @method doQuery
2151 * @param oCallbackFn {HTMLFunction} Callback function implemented by oParent to which to return results.
2152 * @param sQuery {String} Query string.
2153 * @param oParent {Object} The object instance that has requested data.
2154 */
2155YAHOO.widget.DataSource.prototype.doQuery = function(oCallbackFn, sQuery, oParent) {
2156 /* override this */
2157};
2158
2159/**
2160 * Flushes cache.
2161 *
2162 * @method flushCache
2163 */
2164YAHOO.widget.DataSource.prototype.flushCache = function() {
2165 if(this._aCache) {
2166 this._aCache = [];
2167 }
2168 if(this._aCacheHelper) {
2169 this._aCacheHelper = [];
2170 }
2171 this.cacheFlushEvent.fire(this);
2172};
2173
2174/////////////////////////////////////////////////////////////////////////////
2175//
2176// Public events
2177//
2178/////////////////////////////////////////////////////////////////////////////
2179
2180/**
2181 * Fired when a query is made to the live data source.
2182 *
2183 * @event queryEvent
2184 * @param oSelf {Object} The DataSource instance.
2185 * @param oParent {Object} The requesting object.
2186 * @param sQuery {String} The query string.
2187 */
2188YAHOO.widget.DataSource.prototype.queryEvent = null;
2189
2190/**
2191 * Fired when a query is made to the local cache.
2192 *
2193 * @event cacheQueryEvent
2194 * @param oSelf {Object} The DataSource instance.
2195 * @param oParent {Object} The requesting object.
2196 * @param sQuery {String} The query string.
2197 */
2198YAHOO.widget.DataSource.prototype.cacheQueryEvent = null;
2199
2200/**
2201 * Fired when data is retrieved from the live data source.
2202 *
2203 * @event getResultsEvent
2204 * @param oSelf {Object} The DataSource instance.
2205 * @param oParent {Object} The requesting object.
2206 * @param sQuery {String} The query string.
2207 * @param aResults {Object[]} Array of result objects.
2208 */
2209YAHOO.widget.DataSource.prototype.getResultsEvent = null;
2210
2211/**
2212 * Fired when data is retrieved from the local cache.
2213 *
2214 * @event getCachedResultsEvent
2215 * @param oSelf {Object} The DataSource instance.
2216 * @param oParent {Object} The requesting object.
2217 * @param sQuery {String} The query string.
2218 * @param aResults {Object[]} Array of result objects.
2219 */
2220YAHOO.widget.DataSource.prototype.getCachedResultsEvent = null;
2221
2222/**
2223 * Fired when an error is encountered with the live data source.
2224 *
2225 * @event dataErrorEvent
2226 * @param oSelf {Object} The DataSource instance.
2227 * @param oParent {Object} The requesting object.
2228 * @param sQuery {String} The query string.
2229 * @param sMsg {String} Error message string
2230 */
2231YAHOO.widget.DataSource.prototype.dataErrorEvent = null;
2232
2233/**
2234 * Fired when the local cache is flushed.
2235 *
2236 * @event cacheFlushEvent
2237 * @param oSelf {Object} The DataSource instance
2238 */
2239YAHOO.widget.DataSource.prototype.cacheFlushEvent = null;
2240
2241/////////////////////////////////////////////////////////////////////////////
2242//
2243// Private member variables
2244//
2245/////////////////////////////////////////////////////////////////////////////
2246
2247/**
2248 * Internal class variable to index multiple DataSource instances.
2249 *
2250 * @property _nIndex
2251 * @type Number
2252 * @private
2253 * @static
2254 */
2255YAHOO.widget.DataSource._nIndex = 0;
2256
2257/**
2258 * Name of DataSource instance.
2259 *
2260 * @property _sName
2261 * @type String
2262 * @private
2263 */
2264YAHOO.widget.DataSource.prototype._sName = null;
2265
2266/**
2267 * Local cache of data result objects indexed chronologically.
2268 *
2269 * @property _aCache
2270 * @type Object[]
2271 * @private
2272 */
2273YAHOO.widget.DataSource.prototype._aCache = null;
2274
2275
2276/////////////////////////////////////////////////////////////////////////////
2277//
2278// Private methods
2279//
2280/////////////////////////////////////////////////////////////////////////////
2281
2282/**
2283 * Initializes DataSource instance.
2284 *
2285 * @method _init
2286 * @private
2287 */
2288YAHOO.widget.DataSource.prototype._init = function() {
2289 // Validate and initialize public configs
2290 var maxCacheEntries = this.maxCacheEntries;
2291 if(isNaN(maxCacheEntries) || (maxCacheEntries < 0)) {
2292 maxCacheEntries = 0;
2293 }
2294 // Initialize local cache
2295 if(maxCacheEntries > 0 && !this._aCache) {
2296 this._aCache = [];
2297 }
2298
2299 this._sName = "instance" + YAHOO.widget.DataSource._nIndex;
2300 YAHOO.widget.DataSource._nIndex++;
2301
2302 this.queryEvent = new YAHOO.util.CustomEvent("query", this);
2303 this.cacheQueryEvent = new YAHOO.util.CustomEvent("cacheQuery", this);
2304 this.getResultsEvent = new YAHOO.util.CustomEvent("getResults", this);
2305 this.getCachedResultsEvent = new YAHOO.util.CustomEvent("getCachedResults", this);
2306 this.dataErrorEvent = new YAHOO.util.CustomEvent("dataError", this);
2307 this.cacheFlushEvent = new YAHOO.util.CustomEvent("cacheFlush", this);
2308};
2309
2310/**
2311 * Adds a result object to the local cache, evicting the oldest element if the
2312 * cache is full. Newer items will have higher indexes, the oldest item will have
2313 * index of 0.
2314 *
2315 * @method _addCacheElem
2316 * @param oResult {Object} Data result object, including array of results.
2317 * @private
2318 */
2319YAHOO.widget.DataSource.prototype._addCacheElem = function(oResult) {
2320 var aCache = this._aCache;
2321 // Don't add if anything important is missing.
2322 if(!aCache || !oResult || !oResult.query || !oResult.results) {
2323 return;
2324 }
2325
2326 // If the cache is full, make room by removing from index=0
2327 if(aCache.length >= this.maxCacheEntries) {
2328 aCache.shift();
2329 }
2330
2331 // Add to cache, at the end of the array
2332 aCache.push(oResult);
2333};
2334
2335/**
2336 * Queries the local cache for results. If query has been cached, the callback
2337 * function is called with the results, and the cached is refreshed so that it
2338 * is now the newest element.
2339 *
2340 * @method _doQueryCache
2341 * @param oCallbackFn {HTMLFunction} Callback function defined by oParent object to which to return results.
2342 * @param sQuery {String} Query string.
2343 * @param oParent {Object} The object instance that has requested data.
2344 * @return aResults {Object[]} Array of results from local cache if found, otherwise null.
2345 * @private
2346 */
2347YAHOO.widget.DataSource.prototype._doQueryCache = function(oCallbackFn, sQuery, oParent) {
2348 var aResults = [];
2349 var bMatchFound = false;
2350 var aCache = this._aCache;
2351 var nCacheLength = (aCache) ? aCache.length : 0;
2352 var bMatchContains = this.queryMatchContains;
2353
2354 // If cache is enabled...
2355 if((this.maxCacheEntries > 0) && aCache && (nCacheLength > 0)) {
2356 this.cacheQueryEvent.fire(this, oParent, sQuery);
2357 // If case is unimportant, normalize query now instead of in loops
2358 if(!this.queryMatchCase) {
2359 var sOrigQuery = sQuery;
2360 sQuery = sQuery.toLowerCase();
2361 }
2362
2363 // Loop through each cached element's query property...
2364 for(var i = nCacheLength-1; i >= 0; i--) {
2365 var resultObj = aCache[i];
2366 var aAllResultItems = resultObj.results;
2367 // If case is unimportant, normalize match key for comparison
2368 var matchKey = (!this.queryMatchCase) ?
2369 encodeURIComponent(resultObj.query).toLowerCase():
2370 encodeURIComponent(resultObj.query);
2371
2372 // If a cached match key exactly matches the query...
2373 if(matchKey == sQuery) {
2374 // Stash all result objects into aResult[] and stop looping through the cache.
2375 bMatchFound = true;
2376 aResults = aAllResultItems;
2377
2378 // The matching cache element was not the most recent,
2379 // so now we need to refresh the cache.
2380 if(i != nCacheLength-1) {
2381 // Remove element from its original location
2382 aCache.splice(i,1);
2383 // Add element as newest
2384 this._addCacheElem(resultObj);
2385 }
2386 break;
2387 }
2388 // Else if this query is not an exact match and subset matching is enabled...
2389 else if(this.queryMatchSubset) {
2390 // Loop through substrings of each cached element's query property...
2391 for(var j = sQuery.length-1; j >= 0 ; j--) {
2392 var subQuery = sQuery.substr(0,j);
2393
2394 // If a substring of a cached sQuery exactly matches the query...
2395 if(matchKey == subQuery) {
2396 bMatchFound = true;
2397
2398 // Go through each cached result object to match against the query...
2399 for(var k = aAllResultItems.length-1; k >= 0; k--) {
2400 var aRecord = aAllResultItems[k];
2401 var sKeyIndex = (this.queryMatchCase) ?
2402 encodeURIComponent(aRecord[0]).indexOf(sQuery):
2403 encodeURIComponent(aRecord[0]).toLowerCase().indexOf(sQuery);
2404
2405 // A STARTSWITH match is when the query is found at the beginning of the key string...
2406 if((!bMatchContains && (sKeyIndex === 0)) ||
2407 // A CONTAINS match is when the query is found anywhere within the key string...
2408 (bMatchContains && (sKeyIndex > -1))) {
2409 // Stash a match into aResults[].
2410 aResults.unshift(aRecord);
2411 }
2412 }
2413
2414 // Add the subset match result set object as the newest element to cache,
2415 // and stop looping through the cache.
2416 resultObj = {};
2417 resultObj.query = sQuery;
2418 resultObj.results = aResults;
2419 this._addCacheElem(resultObj);
2420 break;
2421 }
2422 }
2423 if(bMatchFound) {
2424 break;
2425 }
2426 }
2427 }
2428
2429 // If there was a match, send along the results.
2430 if(bMatchFound) {
2431 this.getCachedResultsEvent.fire(this, oParent, sOrigQuery, aResults);
2432 oCallbackFn(sOrigQuery, aResults, oParent);
2433 }
2434 }
2435 return aResults;
2436};
2437
2438
2439/****************************************************************************/
2440/****************************************************************************/
2441/****************************************************************************/
2442
2443/**
2444 * Implementation of YAHOO.widget.DataSource using XML HTTP requests that return
2445 * query results.
2446 *
2447 * @class DS_XHR
2448 * @extends YAHOO.widget.DataSource
2449 * @requires connection
2450 * @constructor
2451 * @param sScriptURI {String} Absolute or relative URI to script that returns query
2452 * results as JSON, XML, or delimited flat-file data.
2453 * @param aSchema {String[]} Data schema definition of results.
2454 * @param oConfigs {Object} (optional) Object literal of config params.
2455 */
2456YAHOO.widget.DS_XHR = function(sScriptURI, aSchema, oConfigs) {
2457 // Set any config params passed in to override defaults
2458 if(typeof oConfigs == "object") {
2459 for(var sConfig in oConfigs) {
2460 this[sConfig] = oConfigs[sConfig];
2461 }
2462 }
2463
2464 // Initialization sequence
2465 if(!aSchema || (aSchema.constructor != Array)) {
2466 return;
2467 }
2468 else {
2469 this.schema = aSchema;
2470 }
2471 this.scriptURI = sScriptURI;
2472 this._init();
2473};
2474
2475YAHOO.widget.DS_XHR.prototype = new YAHOO.widget.DataSource();
2476
2477/////////////////////////////////////////////////////////////////////////////
2478//
2479// Public constants
2480//
2481/////////////////////////////////////////////////////////////////////////////
2482
2483/**
2484 * JSON data type.
2485 *
2486 * @property TYPE_JSON
2487 * @type Number
2488 * @static
2489 * @final
2490 */
2491YAHOO.widget.DS_XHR.TYPE_JSON = 0;
2492
2493/**
2494 * XML data type.
2495 *
2496 * @property TYPE_XML
2497 * @type Number
2498 * @static
2499 * @final
2500 */
2501YAHOO.widget.DS_XHR.TYPE_XML = 1;
2502
2503/**
2504 * Flat-file data type.
2505 *
2506 * @property TYPE_FLAT
2507 * @type Number
2508 * @static
2509 * @final
2510 */
2511YAHOO.widget.DS_XHR.TYPE_FLAT = 2;
2512
2513/**
2514 * Error message for XHR failure.
2515 *
2516 * @property ERROR_DATAXHR
2517 * @type String
2518 * @static
2519 * @final
2520 */
2521YAHOO.widget.DS_XHR.ERROR_DATAXHR = "XHR response failed";
2522
2523/////////////////////////////////////////////////////////////////////////////
2524//
2525// Public member variables
2526//
2527/////////////////////////////////////////////////////////////////////////////
2528
2529/**
2530 * Alias to YUI Connection Manager. Allows implementers to specify their own
2531 * subclasses of the YUI Connection Manager utility.
2532 *
2533 * @property connMgr
2534 * @type Object
2535 * @default YAHOO.util.Connect
2536 */
2537YAHOO.widget.DS_XHR.prototype.connMgr = YAHOO.util.Connect;
2538
2539/**
2540 * Number of milliseconds the XHR connection will wait for a server response. A
2541 * a value of zero indicates the XHR connection will wait forever. Any value
2542 * greater than zero will use the Connection utility's Auto-Abort feature.
2543 *
2544 * @property connTimeout
2545 * @type Number
2546 * @default 0
2547 */
2548YAHOO.widget.DS_XHR.prototype.connTimeout = 0;
2549
2550/**
2551 * Absolute or relative URI to script that returns query results. For instance,
2552 * queries will be sent to &#60;scriptURI&#62;?&#60;scriptQueryParam&#62;=userinput
2553 *
2554 * @property scriptURI
2555 * @type String
2556 */
2557YAHOO.widget.DS_XHR.prototype.scriptURI = null;
2558
2559/**
2560 * Query string parameter name sent to scriptURI. For instance, queries will be
2561 * sent to &#60;scriptURI&#62;?&#60;scriptQueryParam&#62;=userinput
2562 *
2563 * @property scriptQueryParam
2564 * @type String
2565 * @default "query"
2566 */
2567YAHOO.widget.DS_XHR.prototype.scriptQueryParam = "query";
2568
2569/**
2570 * String of key/value pairs to append to requests made to scriptURI. Define
2571 * this string when you want to send additional query parameters to your script.
2572 * When defined, queries will be sent to
2573 * &#60;scriptURI&#62;?&#60;scriptQueryParam&#62;=userinput&#38;&#60;scriptQueryAppend&#62;
2574 *
2575 * @property scriptQueryAppend
2576 * @type String
2577 * @default ""
2578 */
2579YAHOO.widget.DS_XHR.prototype.scriptQueryAppend = "";
2580
2581/**
2582 * XHR response data type. Other types that may be defined are YAHOO.widget.DS_XHR.TYPE_XML
2583 * and YAHOO.widget.DS_XHR.TYPE_FLAT.
2584 *
2585 * @property responseType
2586 * @type String
2587 * @default YAHOO.widget.DS_XHR.TYPE_JSON
2588 */
2589YAHOO.widget.DS_XHR.prototype.responseType = YAHOO.widget.DS_XHR.TYPE_JSON;
2590
2591/**
2592 * String after which to strip results. If the results from the XHR are sent
2593 * back as HTML, the gzip HTML comment appears at the end of the data and should
2594 * be ignored.
2595 *
2596 * @property responseStripAfter
2597 * @type String
2598 * @default "\n&#60;!-"
2599 */
2600YAHOO.widget.DS_XHR.prototype.responseStripAfter = "\n<!-";
2601
2602/////////////////////////////////////////////////////////////////////////////
2603//
2604// Public methods
2605//
2606/////////////////////////////////////////////////////////////////////////////
2607
2608/**
2609 * Queries the live data source defined by scriptURI for results. Results are
2610 * passed back to a callback function.
2611 *
2612 * @method doQuery
2613 * @param oCallbackFn {HTMLFunction} Callback function defined by oParent object to which to return results.
2614 * @param sQuery {String} Query string.
2615 * @param oParent {Object} The object instance that has requested data.
2616 */
2617YAHOO.widget.DS_XHR.prototype.doQuery = function(oCallbackFn, sQuery, oParent) {
2618 var isXML = (this.responseType == YAHOO.widget.DS_XHR.TYPE_XML);
2619 var sUri = this.scriptURI+"?"+this.scriptQueryParam+"="+sQuery;
2620 if(this.scriptQueryAppend.length > 0) {
2621 sUri += "&" + this.scriptQueryAppend;
2622 }
2623 var oResponse = null;
2624
2625 var oSelf = this;
2626 /*
2627 * Sets up ajax request callback
2628 *
2629 * @param {object} oReq HTTPXMLRequest object
2630 * @private
2631 */
2632 var responseSuccess = function(oResp) {
2633 // Response ID does not match last made request ID.
2634 if(!oSelf._oConn || (oResp.tId != oSelf._oConn.tId)) {
2635 oSelf.dataErrorEvent.fire(oSelf, oParent, sQuery, YAHOO.widget.DataSource.ERROR_DATANULL);
2636 return;
2637 }
2638//DEBUG
2639for(var foo in oResp) {
2640}
2641 if(!isXML) {
2642 oResp = oResp.responseText;
2643 }
2644 else {
2645 oResp = oResp.responseXML;
2646 }
2647 if(oResp === null) {
2648 oSelf.dataErrorEvent.fire(oSelf, oParent, sQuery, YAHOO.widget.DataSource.ERROR_DATANULL);
2649 return;
2650 }
2651
2652 var aResults = oSelf.parseResponse(sQuery, oResp, oParent);
2653 var resultObj = {};
2654 resultObj.query = decodeURIComponent(sQuery);
2655 resultObj.results = aResults;
2656 if(aResults === null) {
2657 oSelf.dataErrorEvent.fire(oSelf, oParent, sQuery, YAHOO.widget.DataSource.ERROR_DATAPARSE);
2658 aResults = [];
2659 }
2660 else {
2661 oSelf.getResultsEvent.fire(oSelf, oParent, sQuery, aResults);
2662 oSelf._addCacheElem(resultObj);
2663 }
2664 oCallbackFn(sQuery, aResults, oParent);
2665 };
2666
2667 var responseFailure = function(oResp) {
2668 oSelf.dataErrorEvent.fire(oSelf, oParent, sQuery, YAHOO.widget.DS_XHR.ERROR_DATAXHR);
2669 return;
2670 };
2671
2672 var oCallback = {
2673 success:responseSuccess,
2674 failure:responseFailure
2675 };
2676
2677 if(!isNaN(this.connTimeout) && this.connTimeout > 0) {
2678 oCallback.timeout = this.connTimeout;
2679 }
2680
2681 if(this._oConn) {
2682 this.connMgr.abort(this._oConn);
2683 }
2684
2685 oSelf._oConn = this.connMgr.asyncRequest("GET", sUri, oCallback, null);
2686};
2687
2688/**
2689 * Parses raw response data into an array of result objects. The result data key
2690 * is always stashed in the [0] element of each result object.
2691 *
2692 * @method parseResponse
2693 * @param sQuery {String} Query string.
2694 * @param oResponse {Object} The raw response data to parse.
2695 * @param oParent {Object} The object instance that has requested data.
2696 * @returns {Object[]} Array of result objects.
2697 */
2698YAHOO.widget.DS_XHR.prototype.parseResponse = function(sQuery, oResponse, oParent) {
2699 var aSchema = this.schema;
2700 var aResults = [];
2701 var bError = false;
2702
2703 // Strip out comment at the end of results
2704 var nEnd = ((this.responseStripAfter !== "") && (oResponse.indexOf)) ?
2705 oResponse.indexOf(this.responseStripAfter) : -1;
2706 if(nEnd != -1) {
2707 oResponse = oResponse.substring(0,nEnd);
2708 }
2709
2710 switch (this.responseType) {
2711 case YAHOO.widget.DS_XHR.TYPE_JSON:
2712 var jsonList;
2713 // Divert KHTML clients from JSON lib
2714 if(window.JSON && (navigator.userAgent.toLowerCase().indexOf('khtml')== -1)) {
2715 // Use the JSON utility if available
2716 var jsonObjParsed = JSON.parse(oResponse);
2717 if(!jsonObjParsed) {
2718 bError = true;
2719 break;
2720 }
2721 else {
2722 try {
2723 // eval is necessary here since aSchema[0] is of unknown depth
2724 jsonList = eval("jsonObjParsed." + aSchema[0]);
2725 }
2726 catch(e) {
2727 bError = true;
2728 break;
2729 }
2730 }
2731 }
2732 else {
2733 // Parse the JSON response as a string
2734 try {
2735 // Trim leading spaces
2736 while (oResponse.substring(0,1) == " ") {
2737 oResponse = oResponse.substring(1, oResponse.length);
2738 }
2739
2740 // Invalid JSON response
2741 if(oResponse.indexOf("{") < 0) {
2742 bError = true;
2743 break;
2744 }
2745
2746 // Empty (but not invalid) JSON response
2747 if(oResponse.indexOf("{}") === 0) {
2748 break;
2749 }
2750
2751 // Turn the string into an object literal...
2752 // ...eval is necessary here
2753 var jsonObjRaw = eval("(" + oResponse + ")");
2754 if(!jsonObjRaw) {
2755 bError = true;
2756 break;
2757 }
2758
2759 // Grab the object member that contains an array of all reponses...
2760 // ...eval is necessary here since aSchema[0] is of unknown depth
2761 jsonList = eval("(jsonObjRaw." + aSchema[0]+")");
2762 }
2763 catch(e) {
2764 bError = true;
2765 break;
2766 }
2767 }
2768
2769 if(!jsonList) {
2770 bError = true;
2771 break;
2772 }
2773
2774 if(jsonList.constructor != Array) {
2775 jsonList = [jsonList];
2776 }
2777
2778 // Loop through the array of all responses...
2779 for(var i = jsonList.length-1; i >= 0 ; i--) {
2780 var aResultItem = [];
2781 var jsonResult = jsonList[i];
2782 // ...and loop through each data field value of each response
2783 for(var j = aSchema.length-1; j >= 1 ; j--) {
2784 // ...and capture data into an array mapped according to the schema...
2785 var dataFieldValue = jsonResult[aSchema[j]];
2786 if(!dataFieldValue) {
2787 dataFieldValue = "";
2788 }
2789 aResultItem.unshift(dataFieldValue);
2790 }
2791 // If schema isn't well defined, pass along the entire result object
2792 if(aResultItem.length == 1) {
2793 aResultItem.push(jsonResult);
2794 }
2795 // Capture the array of data field values in an array of results
2796 aResults.unshift(aResultItem);
2797 }
2798 break;
2799 case YAHOO.widget.DS_XHR.TYPE_XML:
2800 // Get the collection of results
2801 var xmlList = oResponse.getElementsByTagName(aSchema[0]);
2802 if(!xmlList) {
2803 bError = true;
2804 break;
2805 }
2806 // Loop through each result
2807 for(var k = xmlList.length-1; k >= 0 ; k--) {
2808 var result = xmlList.item(k);
2809 var aFieldSet = [];
2810 // Loop through each data field in each result using the schema
2811 for(var m = aSchema.length-1; m >= 1 ; m--) {
2812 var sValue = null;
2813 // Values may be held in an attribute...
2814 var xmlAttr = result.attributes.getNamedItem(aSchema[m]);
2815 if(xmlAttr) {
2816 sValue = xmlAttr.value;
2817 }
2818 // ...or in a node
2819 else{
2820 var xmlNode = result.getElementsByTagName(aSchema[m]);
2821 if(xmlNode && xmlNode.item(0) && xmlNode.item(0).firstChild) {
2822 sValue = xmlNode.item(0).firstChild.nodeValue;
2823 }
2824 else {
2825 sValue = "";
2826 }
2827 }
2828 // Capture the schema-mapped data field values into an array
2829 aFieldSet.unshift(sValue);
2830 }
2831 // Capture each array of values into an array of results
2832 aResults.unshift(aFieldSet);
2833 }
2834 break;
2835 case YAHOO.widget.DS_XHR.TYPE_FLAT:
2836 if(oResponse.length > 0) {
2837 // Delete the last line delimiter at the end of the data if it exists
2838 var newLength = oResponse.length-aSchema[0].length;
2839 if(oResponse.substr(newLength) == aSchema[0]) {
2840 oResponse = oResponse.substr(0, newLength);
2841 }
2842 var aRecords = oResponse.split(aSchema[0]);
2843 for(var n = aRecords.length-1; n >= 0; n--) {
2844 aResults[n] = aRecords[n].split(aSchema[1]);
2845 }
2846 }
2847 break;
2848 default:
2849 break;
2850 }
2851 sQuery = null;
2852 oResponse = null;
2853 oParent = null;
2854 if(bError) {
2855 return null;
2856 }
2857 else {
2858 return aResults;
2859 }
2860};
2861
2862/////////////////////////////////////////////////////////////////////////////
2863//
2864// Private member variables
2865//
2866/////////////////////////////////////////////////////////////////////////////
2867
2868/**
2869 * XHR connection object.
2870 *
2871 * @property _oConn
2872 * @type Object
2873 * @private
2874 */
2875YAHOO.widget.DS_XHR.prototype._oConn = null;
2876
2877
2878/****************************************************************************/
2879/****************************************************************************/
2880/****************************************************************************/
2881
2882/**
2883 * Implementation of YAHOO.widget.DataSource using a native Javascript function as
2884 * its live data source.
2885 *
2886 * @class DS_JSFunction
2887 * @constructor
2888 * @extends YAHOO.widget.DataSource
2889 * @param oFunction {String} In-memory Javascript function that returns query results as an array of objects.
2890 * @param oConfigs {Object} (optional) Object literal of config params.
2891 */
2892YAHOO.widget.DS_JSFunction = function(oFunction, oConfigs) {
2893 // Set any config params passed in to override defaults
2894 if(typeof oConfigs == "object") {
2895 for(var sConfig in oConfigs) {
2896 this[sConfig] = oConfigs[sConfig];
2897 }
2898 }
2899
2900 // Initialization sequence
2901 if(!oFunction || (oFunction.constructor != Function)) {
2902 return;
2903 }
2904 else {
2905 this.dataFunction = oFunction;
2906 this._init();
2907 }
2908};
2909
2910YAHOO.widget.DS_JSFunction.prototype = new YAHOO.widget.DataSource();
2911
2912/////////////////////////////////////////////////////////////////////////////
2913//
2914// Public member variables
2915//
2916/////////////////////////////////////////////////////////////////////////////
2917
2918/**
2919 * In-memory Javascript function that returns query results.
2920 *
2921 * @property dataFunction
2922 * @type HTMLFunction
2923 */
2924YAHOO.widget.DS_JSFunction.prototype.dataFunction = null;
2925
2926/////////////////////////////////////////////////////////////////////////////
2927//
2928// Public methods
2929//
2930/////////////////////////////////////////////////////////////////////////////
2931
2932/**
2933 * Queries the live data source defined by function for results. Results are
2934 * passed back to a callback function.
2935 *
2936 * @method doQuery
2937 * @param oCallbackFn {HTMLFunction} Callback function defined by oParent object to which to return results.
2938 * @param sQuery {String} Query string.
2939 * @param oParent {Object} The object instance that has requested data.
2940 */
2941YAHOO.widget.DS_JSFunction.prototype.doQuery = function(oCallbackFn, sQuery, oParent) {
2942 var oFunction = this.dataFunction;
2943 var aResults = [];
2944
2945 aResults = oFunction(sQuery);
2946 if(aResults === null) {
2947 this.dataErrorEvent.fire(this, oParent, sQuery, YAHOO.widget.DataSource.ERROR_DATANULL);
2948 return;
2949 }
2950
2951 var resultObj = {};
2952 resultObj.query = decodeURIComponent(sQuery);
2953 resultObj.results = aResults;
2954 this._addCacheElem(resultObj);
2955
2956 this.getResultsEvent.fire(this, oParent, sQuery, aResults);
2957 oCallbackFn(sQuery, aResults, oParent);
2958 return;
2959};
2960
2961/****************************************************************************/
2962/****************************************************************************/
2963/****************************************************************************/
2964
2965/**
2966 * Implementation of YAHOO.widget.DataSource using a native Javascript array as
2967 * its live data source.
2968 *
2969 * @class DS_JSArray
2970 * @constructor
2971 * @extends YAHOO.widget.DataSource
2972 * @param aData {String[]} In-memory Javascript array of simple string data.
2973 * @param oConfigs {Object} (optional) Object literal of config params.
2974 */
2975YAHOO.widget.DS_JSArray = function(aData, oConfigs) {
2976 // Set any config params passed in to override defaults
2977 if(typeof oConfigs == "object") {
2978 for(var sConfig in oConfigs) {
2979 this[sConfig] = oConfigs[sConfig];
2980 }
2981 }
2982
2983 // Initialization sequence
2984 if(!aData || (aData.constructor != Array)) {
2985 return;
2986 }
2987 else {
2988 this.data = aData;
2989 this._init();
2990 }
2991};
2992
2993YAHOO.widget.DS_JSArray.prototype = new YAHOO.widget.DataSource();
2994
2995/////////////////////////////////////////////////////////////////////////////
2996//
2997// Public member variables
2998//
2999/////////////////////////////////////////////////////////////////////////////
3000
3001/**
3002 * In-memory Javascript array of strings.
3003 *
3004 * @property data
3005 * @type Array
3006 */
3007YAHOO.widget.DS_JSArray.prototype.data = null;
3008
3009/////////////////////////////////////////////////////////////////////////////
3010//
3011// Public methods
3012//
3013/////////////////////////////////////////////////////////////////////////////
3014
3015/**
3016 * Queries the live data source defined by data for results. Results are passed
3017 * back to a callback function.
3018 *
3019 * @method doQuery
3020 * @param oCallbackFn {HTMLFunction} Callback function defined by oParent object to which to return results.
3021 * @param sQuery {String} Query string.
3022 * @param oParent {Object} The object instance that has requested data.
3023 */
3024YAHOO.widget.DS_JSArray.prototype.doQuery = function(oCallbackFn, sQuery, oParent) {
3025 var aData = this.data; // the array
3026 var aResults = []; // container for results
3027 var bMatchFound = false;
3028 var bMatchContains = this.queryMatchContains;
3029 if(sQuery) {
3030 if(!this.queryMatchCase) {
3031 sQuery = sQuery.toLowerCase();
3032 }
3033
3034 // Loop through each element of the array...
3035 // which can be a string or an array of strings
3036 for(var i = aData.length-1; i >= 0; i--) {
3037 var aDataset = [];
3038
3039 if(aData[i]) {
3040 if(aData[i].constructor == String) {
3041 aDataset[0] = aData[i];
3042 }
3043 else if(aData[i].constructor == Array) {
3044 aDataset = aData[i];
3045 }
3046 }
3047
3048 if(aDataset[0] && (aDataset[0].constructor == String)) {
3049 var sKeyIndex = (this.queryMatchCase) ?
3050 encodeURIComponent(aDataset[0]).indexOf(sQuery):
3051 encodeURIComponent(aDataset[0]).toLowerCase().indexOf(sQuery);
3052
3053 // A STARTSWITH match is when the query is found at the beginning of the key string...
3054 if((!bMatchContains && (sKeyIndex === 0)) ||
3055 // A CONTAINS match is when the query is found anywhere within the key string...
3056 (bMatchContains && (sKeyIndex > -1))) {
3057 // Stash a match into aResults[].
3058 aResults.unshift(aDataset);
3059 }
3060 }
3061 }
3062 }
3063
3064 this.getResultsEvent.fire(this, oParent, sQuery, aResults);
3065 oCallbackFn(sQuery, aResults, oParent);
3066};
diff --git a/frontend/beta/js/YUI/calendar.js b/frontend/beta/js/YUI/calendar.js
new file mode 100644
index 0000000..3593551
--- a/dev/null
+++ b/frontend/beta/js/YUI/calendar.js
@@ -0,0 +1,4239 @@
1/*
2Copyright (c) 2006, Yahoo! Inc. All rights reserved.
3Code licensed under the BSD License:
4http://developer.yahoo.net/yui/license.txt
5version 0.12.0
6*/
7
8/**
9* Config is a utility used within an Object to allow the implementer to maintain a list of local configuration properties and listen for changes to those properties dynamically using CustomEvent. The initial values are also maintained so that the configuration can be reset at any given point to its initial state.
10* @class YAHOO.util.Config
11* @constructor
12 * @param {Object} ownerThe owner Object to which this Config Object belongs
13*/
14YAHOO.util.Config = function(owner) {
15 if (owner) {
16 this.init(owner);
17 }
18};
19
20YAHOO.util.Config.prototype = {
21
22 /**
23 * Object reference to the owner of this Config Object
24 * @property owner
25 * @type Object
26 */
27 owner : null,
28
29 /**
30 * Boolean flag that specifies whether a queue is currently being executed
31 * @property queueInProgress
32 * @type Boolean
33 */
34 queueInProgress : false,
35
36
37 /**
38 * Validates that the value passed in is a Boolean.
39 * @method checkBoolean
40 * @param {Object} valThe value to validate
41 * @return {Boolean}true, if the value is valid
42 */
43 checkBoolean: function(val) {
44 if (typeof val == 'boolean') {
45 return true;
46 } else {
47 return false;
48 }
49 },
50
51 /**
52 * Validates that the value passed in is a number.
53 * @method checkNumber
54 * @param {Object} valThe value to validate
55 * @return {Boolean}true, if the value is valid
56 */
57 checkNumber: function(val) {
58 if (isNaN(val)) {
59 return false;
60 } else {
61 return true;
62 }
63 }
64};
65
66
67/**
68* Initializes the configuration Object and all of its local members.
69* @method init
70 * @param {Object} ownerThe owner Object to which this Config Object belongs
71*/
72YAHOO.util.Config.prototype.init = function(owner) {
73
74 this.owner = owner;
75
76 /**
77 * Object reference to the owner of this Config Object
78 * @event configChangedEvent
79 */
80 this.configChangedEvent = new YAHOO.util.CustomEvent("configChanged");
81
82 this.queueInProgress = false;
83
84 /* Private Members */
85
86 /**
87 * Maintains the local collection of configuration property objects and their specified values
88 * @property config
89 * @private
90 * @type Object
91 */
92 var config = {};
93
94 /**
95 * Maintains the local collection of configuration property objects as they were initially applied.
96 * This object is used when resetting a property.
97 * @property initialConfig
98 * @private
99 * @type Object
100 */
101 var initialConfig = {};
102
103 /**
104 * Maintains the local, normalized CustomEvent queue
105 * @property eventQueue
106 * @private
107 * @type Object
108 */
109 var eventQueue = [];
110
111 /**
112 * Fires a configuration property event using the specified value.
113 * @method fireEvent
114 * @private
115 * @param {String} key The configuration property's name
116 * @param {value} Object The value of the correct type for the property
117 */
118 var fireEvent = function( key, value ) {
119 key = key.toLowerCase();
120
121 var property = config[key];
122
123 if (typeof property != 'undefined' && property.event) {
124 property.event.fire(value);
125 }
126 };
127 /* End Private Members */
128
129 /**
130 * Adds a property to the Config Object's private config hash.
131 * @method addProperty
132 * @param {String} keyThe configuration property's name
133 * @param {Object} propertyObjectThe Object containing all of this property's arguments
134 */
135 this.addProperty = function( key, propertyObject ) {
136 key = key.toLowerCase();
137
138 config[key] = propertyObject;
139
140 propertyObject.event = new YAHOO.util.CustomEvent(key);
141 propertyObject.key = key;
142
143 if (propertyObject.handler) {
144 propertyObject.event.subscribe(propertyObject.handler, this.owner, true);
145 }
146
147 this.setProperty(key, propertyObject.value, true);
148
149 if (! propertyObject.suppressEvent) {
150 this.queueProperty(key, propertyObject.value);
151 }
152 };
153
154 /**
155 * Returns a key-value configuration map of the values currently set in the Config Object.
156 * @method getConfig
157 * @return {Object} The current config, represented in a key-value map
158 */
159 this.getConfig = function() {
160 var cfg = {};
161
162 for (var prop in config) {
163 var property = config[prop];
164 if (typeof property != 'undefined' && property.event) {
165 cfg[prop] = property.value;
166 }
167 }
168
169 return cfg;
170 };
171
172 /**
173 * Returns the value of specified property.
174 * @method getProperty
175 * @param {String} keyThe name of the property
176 * @return {Object} The value of the specified property
177 */
178 this.getProperty = function(key) {
179 key = key.toLowerCase();
180
181 var property = config[key];
182 if (typeof property != 'undefined' && property.event) {
183 return property.value;
184 } else {
185 return undefined;
186 }
187 };
188
189 /**
190 * Resets the specified property's value to its initial value.
191 * @method resetProperty
192 * @param {String} keyThe name of the property
193 * @return {Boolean} True is the property was reset, false if not
194 */
195 this.resetProperty = function(key) {
196 key = key.toLowerCase();
197
198 var property = config[key];
199 if (typeof property != 'undefined' && property.event) {
200 if (initialConfig[key] && initialConfig[key] != 'undefined'){
201 this.setProperty(key, initialConfig[key]);
202 }
203 return true;
204 } else {
205 return false;
206 }
207 };
208
209 /**
210 * Sets the value of a property. If the silent property is passed as true, the property's event will not be fired.
211 * @method setProperty
212 * @param {String} key The name of the property
213 * @param {String} value The value to set the property to
214 * @param {Boolean} silentWhether the value should be set silently, without firing the property event.
215 * @return {Boolean} True, if the set was successful, false if it failed.
216 */
217 this.setProperty = function(key, value, silent) {
218 key = key.toLowerCase();
219
220 if (this.queueInProgress && ! silent) {
221 this.queueProperty(key,value); // Currently running through a queue...
222 return true;
223 } else {
224 var property = config[key];
225 if (typeof property != 'undefined' && property.event) {
226 if (property.validator && ! property.validator(value)) { // validator
227 return false;
228 } else {
229 property.value = value;
230 if (! silent) {
231 fireEvent(key, value);
232 this.configChangedEvent.fire([key, value]);
233 }
234 return true;
235 }
236 } else {
237 return false;
238 }
239 }
240 };
241
242 /**
243 * Sets the value of a property and queues its event to execute. If the event is already scheduled to execute, it is
244 * moved from its current position to the end of the queue.
245 * @method queueProperty
246 * @param {String} keyThe name of the property
247 * @param {String} valueThe value to set the property to
248 * @return {Boolean} true, if the set was successful, false if it failed.
249 */
250 this.queueProperty = function(key, value) {
251 key = key.toLowerCase();
252
253 var property = config[key];
254
255 if (typeof property != 'undefined' && property.event) {
256 if (typeof value != 'undefined' && property.validator && ! property.validator(value)) { // validator
257 return false;
258 } else {
259
260 if (typeof value != 'undefined') {
261 property.value = value;
262 } else {
263 value = property.value;
264 }
265
266 var foundDuplicate = false;
267
268 for (var i=0;i<eventQueue.length;i++) {
269 var queueItem = eventQueue[i];
270
271 if (queueItem) {
272 var queueItemKey = queueItem[0];
273 var queueItemValue = queueItem[1];
274
275 if (queueItemKey.toLowerCase() == key) {
276 // found a dupe... push to end of queue, null current item, and break
277 eventQueue[i] = null;
278 eventQueue.push([key, (typeof value != 'undefined' ? value : queueItemValue)]);
279 foundDuplicate = true;
280 break;
281 }
282 }
283 }
284
285 if (! foundDuplicate && typeof value != 'undefined') { // this is a refire, or a new property in the queue
286 eventQueue.push([key, value]);
287 }
288 }
289
290 if (property.supercedes) {
291 for (var s=0;s<property.supercedes.length;s++) {
292 var supercedesCheck = property.supercedes[s];
293
294 for (var q=0;q<eventQueue.length;q++) {
295 var queueItemCheck = eventQueue[q];
296
297 if (queueItemCheck) {
298 var queueItemCheckKey = queueItemCheck[0];
299 var queueItemCheckValue = queueItemCheck[1];
300
301 if ( queueItemCheckKey.toLowerCase() == supercedesCheck.toLowerCase() ) {
302 eventQueue.push([queueItemCheckKey, queueItemCheckValue]);
303 eventQueue[q] = null;
304 break;
305 }
306 }
307 }
308 }
309 }
310
311 return true;
312 } else {
313 return false;
314 }
315 };
316
317 /**
318 * Fires the event for a property using the property's current value.
319 * @method refireEvent
320 * @param {String} keyThe name of the property
321 */
322 this.refireEvent = function(key) {
323 key = key.toLowerCase();
324
325 var property = config[key];
326 if (typeof property != 'undefined' && property.event && typeof property.value != 'undefined') {
327 if (this.queueInProgress) {
328 this.queueProperty(key);
329 } else {
330 fireEvent(key, property.value);
331 }
332 }
333 };
334
335 /**
336 * Applies a key-value Object literal to the configuration, replacing any existing values, and queueing the property events.
337 * Although the values will be set, fireQueue() must be called for their associated events to execute.
338 * @method applyConfig
339 * @param {Object} userConfigThe configuration Object literal
340 * @param {Boolean} init When set to true, the initialConfig will be set to the userConfig passed in, so that calling a reset will reset the properties to the passed values.
341 */
342 this.applyConfig = function(userConfig, init) {
343 if (init) {
344 initialConfig = userConfig;
345 }
346 for (var prop in userConfig) {
347 this.queueProperty(prop, userConfig[prop]);
348 }
349 };
350
351 /**
352 * Refires the events for all configuration properties using their current values.
353 * @method refresh
354 */
355 this.refresh = function() {
356 for (var prop in config) {
357 this.refireEvent(prop);
358 }
359 };
360
361 /**
362 * Fires the normalized list of queued property change events
363 * @method fireQueue
364 */
365 this.fireQueue = function() {
366 this.queueInProgress = true;
367 for (var i=0;i<eventQueue.length;i++) {
368 var queueItem = eventQueue[i];
369 if (queueItem) {
370 var key = queueItem[0];
371 var value = queueItem[1];
372
373 var property = config[key];
374 property.value = value;
375
376 fireEvent(key,value);
377 }
378 }
379
380 this.queueInProgress = false;
381 eventQueue = [];
382 };
383
384 /**
385 * Subscribes an external handler to the change event for any given property.
386 * @method subscribeToConfigEvent
387 * @param {String} key The property name
388 * @param {Function} handler The handler function to use subscribe to the property's event
389 * @param {Object} obj The Object to use for scoping the event handler (see CustomEvent documentation)
390 * @param {Boolean} overrideOptional. If true, will override "this" within the handler to map to the scope Object passed into the method.
391 * @return {Boolean} True, if the subscription was successful, otherwise false.
392 */
393 this.subscribeToConfigEvent = function(key, handler, obj, override) {
394 key = key.toLowerCase();
395
396 var property = config[key];
397 if (typeof property != 'undefined' && property.event) {
398 if (! YAHOO.util.Config.alreadySubscribed(property.event, handler, obj)) {
399 property.event.subscribe(handler, obj, override);
400 }
401 return true;
402 } else {
403 return false;
404 }
405 };
406
407 /**
408 * Unsubscribes an external handler from the change event for any given property.
409 * @method unsubscribeFromConfigEvent
410 * @param {String} key The property name
411 * @param {Function} handler The handler function to use subscribe to the property's event
412 * @param {Object} obj The Object to use for scoping the event handler (see CustomEvent documentation)
413 * @return {Boolean} True, if the unsubscription was successful, otherwise false.
414 */
415 this.unsubscribeFromConfigEvent = function(key, handler, obj) {
416 key = key.toLowerCase();
417
418 var property = config[key];
419 if (typeof property != 'undefined' && property.event) {
420 return property.event.unsubscribe(handler, obj);
421 } else {
422 return false;
423 }
424 };
425
426 /**
427 * Returns a string representation of the Config object
428 * @method toString
429 * @return {String}The Config object in string format.
430 */
431 this.toString = function() {
432 var output = "Config";
433 if (this.owner) {
434 output += " [" + this.owner.toString() + "]";
435 }
436 return output;
437 };
438
439 /**
440 * Returns a string representation of the Config object's current CustomEvent queue
441 * @method outputEventQueue
442 * @return {String}The string list of CustomEvents currently queued for execution
443 */
444 this.outputEventQueue = function() {
445 var output = "";
446 for (var q=0;q<eventQueue.length;q++) {
447 var queueItem = eventQueue[q];
448 if (queueItem) {
449 output += queueItem[0] + "=" + queueItem[1] + ", ";
450 }
451 }
452 return output;
453 };
454};
455
456/**
457* Checks to determine if a particular function/Object pair are already subscribed to the specified CustomEvent
458* @method YAHOO.util.Config.alreadySubscribed
459* @static
460 * @param {YAHOO.util.CustomEvent} evtThe CustomEvent for which to check the subscriptions
461 * @param {Function} fnThe function to look for in the subscribers list
462 * @param {Object} objThe execution scope Object for the subscription
463 * @return {Boolean}true, if the function/Object pair is already subscribed to the CustomEvent passed in
464*/
465YAHOO.util.Config.alreadySubscribed = function(evt, fn, obj) {
466 for (var e=0;e<evt.subscribers.length;e++) {
467 var subsc = evt.subscribers[e];
468 if (subsc && subsc.obj == obj && subsc.fn == fn) {
469 return true;
470 }
471 }
472 return false;
473};
474
475/**
476* YAHOO.widget.DateMath is used for simple date manipulation. The class is a static utility
477* used for adding, subtracting, and comparing dates.
478* @class YAHOO.widget.DateMath
479*/
480YAHOO.widget.DateMath = {
481 /**
482 * Constant field representing Day
483 * @property DAY
484 * @static
485 * @final
486 * @type String
487 */
488 DAY : "D",
489
490 /**
491 * Constant field representing Week
492 * @property WEEK
493 * @static
494 * @final
495 * @type String
496 */
497 WEEK : "W",
498
499 /**
500 * Constant field representing Year
501 * @property YEAR
502 * @static
503 * @final
504 * @type String
505 */
506 YEAR : "Y",
507
508 /**
509 * Constant field representing Month
510 * @property MONTH
511 * @static
512 * @final
513 * @type String
514 */
515 MONTH : "M",
516
517 /**
518 * Constant field representing one day, in milliseconds
519 * @property ONE_DAY_MS
520 * @static
521 * @final
522 * @type Number
523 */
524 ONE_DAY_MS : 1000*60*60*24,
525
526 /**
527 * Adds the specified amount of time to the this instance.
528 * @method add
529 * @param {Date} dateThe JavaScript Date object to perform addition on
530 * @param {String} fieldThe field constant to be used for performing addition.
531 * @param {Number} amountThe number of units (measured in the field constant) to add to the date.
532 * @return {Date} The resulting Date object
533 */
534 add : function(date, field, amount) {
535 var d = new Date(date.getTime());
536 switch (field) {
537 case this.MONTH:
538 var newMonth = date.getMonth() + amount;
539 var years = 0;
540
541
542 if (newMonth < 0) {
543 while (newMonth < 0) {
544 newMonth += 12;
545 years -= 1;
546 }
547 } else if (newMonth > 11) {
548 while (newMonth > 11) {
549 newMonth -= 12;
550 years += 1;
551 }
552 }
553
554 d.setMonth(newMonth);
555 d.setFullYear(date.getFullYear() + years);
556 break;
557 case this.DAY:
558 d.setDate(date.getDate() + amount);
559 break;
560 case this.YEAR:
561 d.setFullYear(date.getFullYear() + amount);
562 break;
563 case this.WEEK:
564 d.setDate(date.getDate() + (amount * 7));
565 break;
566 }
567 return d;
568 },
569
570 /**
571 * Subtracts the specified amount of time from the this instance.
572 * @method subtract
573 * @param {Date} dateThe JavaScript Date object to perform subtraction on
574 * @param {Number} fieldThe this field constant to be used for performing subtraction.
575 * @param {Number} amountThe number of units (measured in the field constant) to subtract from the date.
576 * @return {Date} The resulting Date object
577 */
578 subtract : function(date, field, amount) {
579 return this.add(date, field, (amount*-1));
580 },
581
582 /**
583 * Determines whether a given date is before another date on the calendar.
584 * @method before
585 * @param {Date} date The Date object to compare with the compare argument
586 * @param {Date} compareToThe Date object to use for the comparison
587 * @return {Boolean} true if the date occurs before the compared date; false if not.
588 */
589 before : function(date, compareTo) {
590 var ms = compareTo.getTime();
591 if (date.getTime() < ms) {
592 return true;
593 } else {
594 return false;
595 }
596 },
597
598 /**
599 * Determines whether a given date is after another date on the calendar.
600 * @method after
601 * @param {Date} date The Date object to compare with the compare argument
602 * @param {Date} compareToThe Date object to use for the comparison
603 * @return {Boolean} true if the date occurs after the compared date; false if not.
604 */
605 after : function(date, compareTo) {
606 var ms = compareTo.getTime();
607 if (date.getTime() > ms) {
608 return true;
609 } else {
610 return false;
611 }
612 },
613
614 /**
615 * Determines whether a given date is between two other dates on the calendar.
616 * @method between
617 * @param {Date} date The date to check for
618 * @param {Date} dateBeginThe start of the range
619 * @param {Date} dateEnd The end of the range
620 * @return {Boolean} true if the date occurs between the compared dates; false if not.
621 */
622 between : function(date, dateBegin, dateEnd) {
623 if (this.after(date, dateBegin) && this.before(date, dateEnd)) {
624 return true;
625 } else {
626 return false;
627 }
628 },
629
630 /**
631 * Retrieves a JavaScript Date object representing January 1 of any given year.
632 * @method getJan1
633 * @param {Number} calendarYear The calendar year for which to retrieve January 1
634 * @return {Date}January 1 of the calendar year specified.
635 */
636 getJan1 : function(calendarYear) {
637 return new Date(calendarYear,0,1);
638 },
639
640 /**
641 * Calculates the number of days the specified date is from January 1 of the specified calendar year.
642 * Passing January 1 to this function would return an offset value of zero.
643 * @method getDayOffset
644 * @param {Date} dateThe JavaScript date for which to find the offset
645 * @param {Number} calendarYearThe calendar year to use for determining the offset
646 * @return {Number}The number of days since January 1 of the given year
647 */
648 getDayOffset : function(date, calendarYear) {
649 var beginYear = this.getJan1(calendarYear); // Find the start of the year. This will be in week 1.
650
651 // Find the number of days the passed in date is away from the calendar year start
652 var dayOffset = Math.ceil((date.getTime()-beginYear.getTime()) / this.ONE_DAY_MS);
653 return dayOffset;
654 },
655
656 /**
657 * Calculates the week number for the given date. This function assumes that week 1 is the
658 * week in which January 1 appears, regardless of whether the week consists of a full 7 days.
659 * The calendar year can be specified to help find what a the week number would be for a given
660 * date if the date overlaps years. For instance, a week may be considered week 1 of 2005, or
661 * week 53 of 2004. Specifying the optional calendarYear allows one to make this distinction
662 * easily.
663 * @method getWeekNumber
664 * @param {Date} dateThe JavaScript date for which to find the week number
665 * @param {Number} calendarYearOPTIONAL - The calendar year to use for determining the week number. Default is
666 * the calendar year of parameter "date".
667 * @param {Number} weekStartsOnOPTIONAL - The integer (0-6) representing which day a week begins on. Default is 0 (for Sunday).
668 * @return {Number}The week number of the given date.
669 */
670 getWeekNumber : function(date, calendarYear) {
671 date = this.clearTime(date);
672 var nearestThurs = new Date(date.getTime() + (4 * this.ONE_DAY_MS) - ((date.getDay()) * this.ONE_DAY_MS));
673
674 var jan1 = new Date(nearestThurs.getFullYear(),0,1);
675 var dayOfYear = ((nearestThurs.getTime() - jan1.getTime()) / this.ONE_DAY_MS) - 1;
676
677 var weekNum = Math.ceil((dayOfYear)/ 7);
678 return weekNum;
679 },
680
681 /**
682 * Determines if a given week overlaps two different years.
683 * @method isYearOverlapWeek
684 * @param {Date} weekBeginDateThe JavaScript Date representing the first day of the week.
685 * @return {Boolean}true if the date overlaps two different years.
686 */
687 isYearOverlapWeek : function(weekBeginDate) {
688 var overlaps = false;
689 var nextWeek = this.add(weekBeginDate, this.DAY, 6);
690 if (nextWeek.getFullYear() != weekBeginDate.getFullYear()) {
691 overlaps = true;
692 }
693 return overlaps;
694 },
695
696 /**
697 * Determines if a given week overlaps two different months.
698 * @method isMonthOverlapWeek
699 * @param {Date} weekBeginDateThe JavaScript Date representing the first day of the week.
700 * @return {Boolean}true if the date overlaps two different months.
701 */
702 isMonthOverlapWeek : function(weekBeginDate) {
703 var overlaps = false;
704 var nextWeek = this.add(weekBeginDate, this.DAY, 6);
705 if (nextWeek.getMonth() != weekBeginDate.getMonth()) {
706 overlaps = true;
707 }
708 return overlaps;
709 },
710
711 /**
712 * Gets the first day of a month containing a given date.
713 * @method findMonthStart
714 * @param {Date} dateThe JavaScript Date used to calculate the month start
715 * @return {Date} The JavaScript Date representing the first day of the month
716 */
717 findMonthStart : function(date) {
718 var start = new Date(date.getFullYear(), date.getMonth(), 1);
719 return start;
720 },
721
722 /**
723 * Gets the last day of a month containing a given date.
724 * @method findMonthEnd
725 * @param {Date} dateThe JavaScript Date used to calculate the month end
726 * @return {Date} The JavaScript Date representing the last day of the month
727 */
728 findMonthEnd : function(date) {
729 var start = this.findMonthStart(date);
730 var nextMonth = this.add(start, this.MONTH, 1);
731 var end = this.subtract(nextMonth, this.DAY, 1);
732 return end;
733 },
734
735 /**
736 * Clears the time fields from a given date, effectively setting the time to midnight.
737 * @method clearTime
738 * @param {Date} dateThe JavaScript Date for which the time fields will be cleared
739 * @return {Date} The JavaScript Date cleared of all time fields
740 */
741 clearTime : function(date) {
742 date.setHours(12,0,0,0);
743 return date;
744 }
745};
746
747/**
748* The Calendar component is a UI control that enables users to choose one or more dates from a graphical calendar presented in a one-month ("one-up") or two-month ("two-up") interface. Calendars are generated entirely via script and can be navigated without any page refreshes.
749* @module Calendar
750* @title Calendar Widget
751* @namespace YAHOO.widget
752* @requires yahoo,dom,event
753*/
754
755/**
756* Calendar is the base class for the Calendar widget. In its most basic
757* implementation, it has the ability to render a calendar widget on the page
758* that can be manipulated to select a single date, move back and forth between
759* months and years.
760* <p>To construct the placeholder for the calendar widget, the code is as
761* follows:
762 *<xmp>
763 * <div id="cal1Container"></div>
764 *</xmp>
765* Note that the table can be replaced with any kind of element.
766* </p>
767* @namespace YAHOO.widget
768* @class Calendar
769* @constructor
770 * @param {String} id The id of the table element that will represent the calendar widget
771 * @param {String} containerIdThe id of the container div element that will wrap the calendar table
772 * @param {Object} config The configuration object containing the Calendar's arguments
773*/
774YAHOO.widget.Calendar = function(id, containerId, config) {
775 this.init(id, containerId, config);
776};
777
778/**
779* The path to be used for images loaded for the Calendar
780* @property YAHOO.widget.Calendar.IMG_ROOT
781* @static
782* @type String
783*/
784YAHOO.widget.Calendar.IMG_ROOT = (window.location.href.toLowerCase().indexOf("https") === 0 ? "https://a248.e.akamai.net/sec.yimg.com/i/" : "http://us.i1.yimg.com/us.yimg.com/i/");
785
786/**
787* Type constant used for renderers to represent an individual date (M/D/Y)
788* @property YAHOO.widget.Calendar.DATE
789* @static
790* @final
791* @type String
792*/
793YAHOO.widget.Calendar.DATE = "D";
794
795/**
796* Type constant used for renderers to represent an individual date across any year (M/D)
797* @property YAHOO.widget.Calendar.MONTH_DAY
798* @static
799* @final
800* @type String
801*/
802YAHOO.widget.Calendar.MONTH_DAY = "MD";
803
804/**
805* Type constant used for renderers to represent a weekday
806* @property YAHOO.widget.Calendar.WEEKDAY
807* @static
808* @final
809* @type String
810*/
811YAHOO.widget.Calendar.WEEKDAY = "WD";
812
813/**
814* Type constant used for renderers to represent a range of individual dates (M/D/Y-M/D/Y)
815* @property YAHOO.widget.Calendar.RANGE
816* @static
817* @final
818* @type String
819*/
820YAHOO.widget.Calendar.RANGE = "R";
821
822/**
823* Type constant used for renderers to represent a month across any year
824* @property YAHOO.widget.Calendar.MONTH
825* @static
826* @final
827* @type String
828*/
829YAHOO.widget.Calendar.MONTH = "M";
830
831/**
832* Constant that represents the total number of date cells that are displayed in a given month
833* @property YAHOO.widget.Calendar.DISPLAY_DAYS
834* @static
835* @final
836* @type Number
837*/
838YAHOO.widget.Calendar.DISPLAY_DAYS = 42;
839
840/**
841* Constant used for halting the execution of the remainder of the render stack
842* @property YAHOO.widget.Calendar.STOP_RENDER
843* @static
844* @final
845* @type String
846*/
847YAHOO.widget.Calendar.STOP_RENDER = "S";
848
849YAHOO.widget.Calendar.prototype = {
850
851 /**
852 * The configuration object used to set up the calendars various locale and style options.
853 * @property Config
854 * @private
855 * @deprecated Configuration properties should be set by calling Calendar.cfg.setProperty.
856 * @type Object
857 */
858 Config : null,
859
860 /**
861 * The parent CalendarGroup, only to be set explicitly by the parent group
862 * @property parent
863 * @type CalendarGroup
864 */
865 parent : null,
866
867 /**
868 * The index of this item in the parent group
869 * @property index
870 * @type Number
871 */
872 index : -1,
873
874 /**
875 * The collection of calendar table cells
876 * @property cells
877 * @type HTMLTableCellElement[]
878 */
879 cells : null,
880
881 /**
882 * The collection of calendar cell dates that is parallel to the cells collection. The array contains dates field arrays in the format of [YYYY, M, D].
883 * @property cellDates
884 * @type Array[](Number[])
885 */
886 cellDates : null,
887
888 /**
889 * The id that uniquely identifies this calendar. This id should match the id of the placeholder element on the page.
890 * @property id
891 * @type String
892 */
893 id : null,
894
895 /**
896 * The DOM element reference that points to this calendar's container element. The calendar will be inserted into this element when the shell is rendered.
897 * @property oDomContainer
898 * @type HTMLElement
899 */
900 oDomContainer : null,
901
902 /**
903 * A Date object representing today's date.
904 * @property today
905 * @type Date
906 */
907 today : null,
908
909 /**
910 * The list of render functions, along with required parameters, used to render cells.
911 * @property renderStack
912 * @type Array[]
913 */
914 renderStack : null,
915
916 /**
917 * A copy of the initial render functions created before rendering.
918 * @property _renderStack
919 * @private
920 * @type Array
921 */
922 _renderStack : null,
923
924 /**
925 * A Date object representing the month/year that the calendar is initially set to
926 * @property _pageDate
927 * @private
928 * @type Date
929 */
930 _pageDate : null,
931
932 /**
933 * The private list of initially selected dates.
934 * @property _selectedDates
935 * @private
936 * @type Array
937 */
938 _selectedDates : null,
939
940 /**
941 * A map of DOM event handlers to attach to cells associated with specific CSS class names
942 * @property domEventMap
943 * @type Object
944 */
945 domEventMap : null
946};
947
948
949
950/**
951* Initializes the Calendar widget.
952* @method init
953 * @param {String} id The id of the table element that will represent the calendar widget
954 * @param {String} containerIdThe id of the container div element that will wrap the calendar table
955 * @param {Object} config The configuration object containing the Calendar's arguments
956*/
957YAHOO.widget.Calendar.prototype.init = function(id, containerId, config) {
958 this.initEvents();
959 this.today = new Date();
960 YAHOO.widget.DateMath.clearTime(this.today);
961
962 this.id = id;
963 this.oDomContainer = document.getElementById(containerId);
964
965 /**
966 * The Config object used to hold the configuration variables for the Calendar
967 * @property cfg
968 * @type YAHOO.util.Config
969 */
970 this.cfg = new YAHOO.util.Config(this);
971
972 /**
973 * The local object which contains the Calendar's options
974 * @property Options
975 * @type Object
976 */
977 this.Options = {};
978
979 /**
980 * The local object which contains the Calendar's locale settings
981 * @property Locale
982 * @type Object
983 */
984 this.Locale = {};
985
986 this.initStyles();
987
988 YAHOO.util.Dom.addClass(this.oDomContainer, this.Style.CSS_CONTAINER);
989 YAHOO.util.Dom.addClass(this.oDomContainer, this.Style.CSS_SINGLE);
990
991 this.cellDates = [];
992 this.cells = [];
993 this.renderStack = [];
994 this._renderStack = [];
995
996 this.setupConfig();
997
998 if (config) {
999 this.cfg.applyConfig(config, true);
1000 }
1001
1002 this.cfg.fireQueue();
1003};
1004
1005/**
1006* Renders the built-in IFRAME shim for the IE6 and below
1007* @method configIframe
1008*/
1009YAHOO.widget.Calendar.prototype.configIframe = function(type, args, obj) {
1010 var useIframe = args[0];
1011
1012 if (YAHOO.util.Dom.inDocument(this.oDomContainer)) {
1013 if (useIframe) {
1014 var pos = YAHOO.util.Dom.getStyle(this.oDomContainer, "position");
1015
1016 if (this.browser == "ie" && (pos == "absolute" || pos == "relative")) {
1017 if (! YAHOO.util.Dom.inDocument(this.iframe)) {
1018 this.iframe = document.createElement("iframe");
1019 this.iframe.src = "javascript:false;";
1020 YAHOO.util.Dom.setStyle(this.iframe, "opacity", "0");
1021 this.oDomContainer.insertBefore(this.iframe, this.oDomContainer.firstChild);
1022 }
1023 }
1024 } else {
1025 if (this.iframe) {
1026 if (this.iframe.parentNode) {
1027 this.iframe.parentNode.removeChild(this.iframe);
1028 }
1029 this.iframe = null;
1030 }
1031 }
1032 }
1033};
1034
1035/**
1036* Default handler for the "title" property
1037* @method configTitle
1038*/
1039YAHOO.widget.Calendar.prototype.configTitle = function(type, args, obj) {
1040 var title = args[0];
1041 var close = this.cfg.getProperty("close");
1042
1043 var titleDiv;
1044
1045 if (title && title !== "") {
1046 titleDiv = YAHOO.util.Dom.getElementsByClassName(YAHOO.widget.CalendarGroup.CSS_2UPTITLE, "div", this.oDomContainer)[0] || document.createElement("div");
1047 titleDiv.className = YAHOO.widget.CalendarGroup.CSS_2UPTITLE;
1048 titleDiv.innerHTML = title;
1049 this.oDomContainer.insertBefore(titleDiv, this.oDomContainer.firstChild);
1050 YAHOO.util.Dom.addClass(this.oDomContainer, "withtitle");
1051 } else {
1052 titleDiv = YAHOO.util.Dom.getElementsByClassName(YAHOO.widget.CalendarGroup.CSS_2UPTITLE, "div", this.oDomContainer)[0] || null;
1053
1054 if (titleDiv) {
1055 YAHOO.util.Event.purgeElement(titleDiv);
1056 this.oDomContainer.removeChild(titleDiv);
1057 }
1058 if (! close) {
1059 YAHOO.util.Dom.removeClass(this.oDomContainer, "withtitle");
1060 }
1061 }
1062};
1063
1064/**
1065* Default handler for the "close" property
1066* @method configClose
1067*/
1068YAHOO.widget.Calendar.prototype.configClose = function(type, args, obj) {
1069 var close = args[0];
1070 var title = this.cfg.getProperty("title");
1071
1072 var linkClose;
1073
1074 if (close === true) {
1075 linkClose = YAHOO.util.Dom.getElementsByClassName("link-close", "a", this.oDomContainer)[0] || document.createElement("a");
1076 linkClose.href = "javascript:void(null);";
1077 linkClose.className = "link-close";
1078 YAHOO.util.Event.addListener(linkClose, "click", this.hide, this, true);
1079 var imgClose = document.createElement("img");
1080 imgClose.src = YAHOO.widget.Calendar.IMG_ROOT + "us/my/bn/x_d.gif";
1081 imgClose.className = YAHOO.widget.CalendarGroup.CSS_2UPCLOSE;
1082 linkClose.appendChild(imgClose);
1083 this.oDomContainer.appendChild(linkClose);
1084 YAHOO.util.Dom.addClass(this.oDomContainer, "withtitle");
1085 } else {
1086 linkClose = YAHOO.util.Dom.getElementsByClassName("link-close", "a", this.oDomContainer)[0] || null;
1087
1088 if (linkClose) {
1089 YAHOO.util.Event.purgeElement(linkClose);
1090 this.oDomContainer.removeChild(linkClose);
1091 }
1092 if (! title || title === "") {
1093 YAHOO.util.Dom.removeClass(this.oDomContainer, "withtitle");
1094 }
1095 }
1096};
1097
1098/**
1099* Initializes Calendar's built-in CustomEvents
1100* @method initEvents
1101*/
1102YAHOO.widget.Calendar.prototype.initEvents = function() {
1103
1104 /**
1105 * Fired before a selection is made
1106 * @event beforeSelectEvent
1107 */
1108 this.beforeSelectEvent = new YAHOO.util.CustomEvent("beforeSelect");
1109
1110 /**
1111 * Fired when a selection is made
1112 * @event selectEvent
1113 * @param {Array}Array of Date field arrays in the format [YYYY, MM, DD].
1114 */
1115 this.selectEvent = new YAHOO.util.CustomEvent("select");
1116
1117 /**
1118 * Fired before a selection is made
1119 * @event beforeDeselectEvent
1120 */
1121 this.beforeDeselectEvent = new YAHOO.util.CustomEvent("beforeDeselect");
1122
1123 /**
1124 * Fired when a selection is made
1125 * @event deselectEvent
1126 * @param {Array}Array of Date field arrays in the format [YYYY, MM, DD].
1127 */
1128 this.deselectEvent = new YAHOO.util.CustomEvent("deselect");
1129
1130 /**
1131 * Fired when the Calendar page is changed
1132 * @event changePageEvent
1133 */
1134 this.changePageEvent = new YAHOO.util.CustomEvent("changePage");
1135
1136 /**
1137 * Fired before the Calendar is rendered
1138 * @event beforeRenderEvent
1139 */
1140 this.beforeRenderEvent = new YAHOO.util.CustomEvent("beforeRender");
1141
1142 /**
1143 * Fired when the Calendar is rendered
1144 * @event renderEvent
1145 */
1146 this.renderEvent = new YAHOO.util.CustomEvent("render");
1147
1148 /**
1149 * Fired when the Calendar is reset
1150 * @event resetEvent
1151 */
1152 this.resetEvent = new YAHOO.util.CustomEvent("reset");
1153
1154 /**
1155 * Fired when the Calendar is cleared
1156 * @event clearEvent
1157 */
1158 this.clearEvent = new YAHOO.util.CustomEvent("clear");
1159
1160 this.beforeSelectEvent.subscribe(this.onBeforeSelect, this, true);
1161 this.selectEvent.subscribe(this.onSelect, this, true);
1162 this.beforeDeselectEvent.subscribe(this.onBeforeDeselect, this, true);
1163 this.deselectEvent.subscribe(this.onDeselect, this, true);
1164 this.changePageEvent.subscribe(this.onChangePage, this, true);
1165 this.renderEvent.subscribe(this.onRender, this, true);
1166 this.resetEvent.subscribe(this.onReset, this, true);
1167 this.clearEvent.subscribe(this.onClear, this, true);
1168};
1169
1170
1171/**
1172* The default event function that is attached to a date link within a calendar cell
1173* when the calendar is rendered.
1174* @method doSelectCell
1175 * @param {DOMEvent} eThe event
1176 * @param {Calendar} calA reference to the calendar passed by the Event utility
1177*/
1178YAHOO.widget.Calendar.prototype.doSelectCell = function(e, cal) {
1179 var target = YAHOO.util.Event.getTarget(e);
1180
1181 var cell,index,d,date;
1182
1183 while (target.tagName.toLowerCase() != "td" && ! YAHOO.util.Dom.hasClass(target, cal.Style.CSS_CELL_SELECTABLE)) {
1184 target = target.parentNode;
1185 if (target.tagName.toLowerCase() == "html") {
1186 return;
1187 }
1188 }
1189
1190 cell = target;
1191
1192 if (YAHOO.util.Dom.hasClass(cell, cal.Style.CSS_CELL_SELECTABLE)) {
1193 index = cell.id.split("cell")[1];
1194 d = cal.cellDates[index];
1195 date = new Date(d[0],d[1]-1,d[2]);
1196
1197 var link;
1198
1199 if (cal.Options.MULTI_SELECT) {
1200 link = cell.getElementsByTagName("a")[0];
1201 if (link) {
1202 link.blur();
1203 }
1204
1205 var cellDate = cal.cellDates[index];
1206 var cellDateIndex = cal._indexOfSelectedFieldArray(cellDate);
1207
1208 if (cellDateIndex > -1) {
1209 cal.deselectCell(index);
1210 } else {
1211 cal.selectCell(index);
1212 }
1213
1214 } else {
1215 link = cell.getElementsByTagName("a")[0];
1216 if (link) {
1217 link.blur();
1218 }
1219 cal.selectCell(index);
1220 }
1221 }
1222};
1223
1224/**
1225* The event that is executed when the user hovers over a cell
1226* @method doCellMouseOver
1227 * @param {DOMEvent} eThe event
1228 * @param {Calendar} calA reference to the calendar passed by the Event utility
1229*/
1230YAHOO.widget.Calendar.prototype.doCellMouseOver = function(e, cal) {
1231 var target;
1232 if (e) {
1233 target = YAHOO.util.Event.getTarget(e);
1234 } else {
1235 target = this;
1236 }
1237
1238 while (target.tagName.toLowerCase() != "td") {
1239 target = target.parentNode;
1240 if (target.tagName.toLowerCase() == "html") {
1241 return;
1242 }
1243 }
1244
1245 if (YAHOO.util.Dom.hasClass(target, cal.Style.CSS_CELL_SELECTABLE)) {
1246 YAHOO.util.Dom.addClass(target, cal.Style.CSS_CELL_HOVER);
1247 }
1248};
1249
1250/**
1251* The event that is executed when the user moves the mouse out of a cell
1252* @method doCellMouseOut
1253 * @param {DOMEvent} eThe event
1254 * @param {Calendar} calA reference to the calendar passed by the Event utility
1255*/
1256YAHOO.widget.Calendar.prototype.doCellMouseOut = function(e, cal) {
1257 var target;
1258 if (e) {
1259 target = YAHOO.util.Event.getTarget(e);
1260 } else {
1261 target = this;
1262 }
1263
1264 while (target.tagName.toLowerCase() != "td") {
1265 target = target.parentNode;
1266 if (target.tagName.toLowerCase() == "html") {
1267 return;
1268 }
1269 }
1270
1271 if (YAHOO.util.Dom.hasClass(target, cal.Style.CSS_CELL_SELECTABLE)) {
1272 YAHOO.util.Dom.removeClass(target, cal.Style.CSS_CELL_HOVER);
1273 }
1274};
1275
1276YAHOO.widget.Calendar.prototype.setupConfig = function() {
1277
1278 /**
1279 * The month/year representing the current visible Calendar date (mm/yyyy)
1280 * @config pagedate
1281 * @type String
1282 * @default today's date
1283 */
1284 this.cfg.addProperty("pagedate", { value:new Date(), handler:this.configPageDate } );
1285
1286 /**
1287 * The date or range of dates representing the current Calendar selection
1288 * @config selected
1289 * @type String
1290 * @default []
1291 */
1292 this.cfg.addProperty("selected", { value:[], handler:this.configSelected } );
1293
1294 /**
1295 * The title to display above the Calendar's month header
1296 * @config title
1297 * @type String
1298 * @default ""
1299 */
1300 this.cfg.addProperty("title", { value:"", handler:this.configTitle } );
1301
1302 /**
1303 * Whether or not a close button should be displayed for this Calendar
1304 * @config close
1305 * @type Boolean
1306 * @default false
1307 */
1308 this.cfg.addProperty("close", { value:false, handler:this.configClose } );
1309
1310 /**
1311 * Whether or not an iframe shim should be placed under the Calendar to prevent select boxes from bleeding through in Internet Explorer 6 and below.
1312 * @config iframe
1313 * @type Boolean
1314 * @default true
1315 */
1316 this.cfg.addProperty("iframe", { value:true, handler:this.configIframe, validator:this.cfg.checkBoolean } );
1317
1318 /**
1319 * The minimum selectable date in the current Calendar (mm/dd/yyyy)
1320 * @config mindate
1321 * @type String
1322 * @default null
1323 */
1324 this.cfg.addProperty("mindate", { value:null, handler:this.configMinDate } );
1325
1326 /**
1327 * The maximum selectable date in the current Calendar (mm/dd/yyyy)
1328 * @config maxdate
1329 * @type String
1330 * @default null
1331 */
1332 this.cfg.addProperty("maxdate", { value:null, handler:this.configMaxDate } );
1333
1334
1335 // Options properties
1336
1337 /**
1338 * True if the Calendar should allow multiple selections. False by default.
1339 * @config MULTI_SELECT
1340 * @type Boolean
1341 * @default false
1342 */
1343 this.cfg.addProperty("MULTI_SELECT",{ value:false, handler:this.configOptions, validator:this.cfg.checkBoolean } );
1344
1345 /**
1346 * The weekday the week begins on. Default is 0 (Sunday).
1347 * @config START_WEEKDAY
1348 * @type number
1349 * @default 0
1350 */
1351 this.cfg.addProperty("START_WEEKDAY",{ value:0, handler:this.configOptions, validator:this.cfg.checkNumber } );
1352
1353 /**
1354 * True if the Calendar should show weekday labels. True by default.
1355 * @config SHOW_WEEKDAYS
1356 * @type Boolean
1357 * @default true
1358 */
1359 this.cfg.addProperty("SHOW_WEEKDAYS",{ value:true, handler:this.configOptions, validator:this.cfg.checkBoolean } );
1360
1361 /**
1362 * True if the Calendar should show week row headers. False by default.
1363 * @config SHOW_WEEK_HEADER
1364 * @type Boolean
1365 * @default false
1366 */
1367 this.cfg.addProperty("SHOW_WEEK_HEADER",{ value:false, handler:this.configOptions, validator:this.cfg.checkBoolean } );
1368
1369 /**
1370 * True if the Calendar should show week row footers. False by default.
1371 * @config SHOW_WEEK_FOOTER
1372 * @type Boolean
1373 * @default false
1374 */
1375 this.cfg.addProperty("SHOW_WEEK_FOOTER",{ value:false, handler:this.configOptions, validator:this.cfg.checkBoolean } );
1376
1377 /**
1378 * True if the Calendar should suppress weeks that are not a part of the current month. False by default.
1379 * @config HIDE_BLANK_WEEKS
1380 * @type Boolean
1381 * @default false
1382 */
1383 this.cfg.addProperty("HIDE_BLANK_WEEKS",{ value:false, handler:this.configOptions, validator:this.cfg.checkBoolean } );
1384
1385 /**
1386 * The image that should be used for the left navigation arrow.
1387 * @config NAV_ARROW_LEFT
1388 * @type String
1389 * @default YAHOO.widget.Calendar.IMG_ROOT + "us/tr/callt.gif"
1390 */
1391 this.cfg.addProperty("NAV_ARROW_LEFT",{ value:YAHOO.widget.Calendar.IMG_ROOT + "us/tr/callt.gif", handler:this.configOptions } );
1392
1393 /**
1394 * The image that should be used for the left navigation arrow.
1395 * @config NAV_ARROW_RIGHT
1396 * @type String
1397 * @default YAHOO.widget.Calendar.IMG_ROOT + "us/tr/calrt.gif"
1398 */
1399 this.cfg.addProperty("NAV_ARROW_RIGHT",{ value:YAHOO.widget.Calendar.IMG_ROOT + "us/tr/calrt.gif", handler:this.configOptions } );
1400
1401 // Locale properties
1402
1403 /**
1404 * The short month labels for the current locale.
1405 * @config MONTHS_SHORT
1406 * @type String[]
1407 * @default ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
1408 */
1409 this.cfg.addProperty("MONTHS_SHORT",{ value:["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"], handler:this.configLocale } );
1410
1411 /**
1412 * The long month labels for the current locale.
1413 * @config MONTHS_LONG
1414 * @type String[]
1415 * @default ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"
1416 */
1417 this.cfg.addProperty("MONTHS_LONG", { value:["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"], handler:this.configLocale } );
1418
1419 /**
1420 * The 1-character weekday labels for the current locale.
1421 * @config WEEKDAYS_1CHAR
1422 * @type String[]
1423 * @default ["S", "M", "T", "W", "T", "F", "S"]
1424 */
1425 this.cfg.addProperty("WEEKDAYS_1CHAR",{ value:["S", "M", "T", "W", "T", "F", "S"], handler:this.configLocale } );
1426
1427 /**
1428 * The short weekday labels for the current locale.
1429 * @config WEEKDAYS_SHORT
1430 * @type String[]
1431 * @default ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"]
1432 */
1433 this.cfg.addProperty("WEEKDAYS_SHORT",{ value:["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"], handler:this.configLocale } );
1434
1435 /**
1436 * The medium weekday labels for the current locale.
1437 * @config WEEKDAYS_MEDIUM
1438 * @type String[]
1439 * @default ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"]
1440 */
1441 this.cfg.addProperty("WEEKDAYS_MEDIUM",{ value:["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"], handler:this.configLocale } );
1442
1443 /**
1444 * The long weekday labels for the current locale.
1445 * @config WEEKDAYS_LONG
1446 * @type String[]
1447 * @default ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"]
1448 */
1449 this.cfg.addProperty("WEEKDAYS_LONG",{ value:["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"], handler:this.configLocale } );
1450
1451 /**
1452 * Refreshes the locale values used to build the Calendar.
1453 * @method refreshLocale
1454 * @private
1455 */
1456 var refreshLocale = function() {
1457 this.cfg.refireEvent("LOCALE_MONTHS");
1458 this.cfg.refireEvent("LOCALE_WEEKDAYS");
1459 };
1460
1461 this.cfg.subscribeToConfigEvent("START_WEEKDAY", refreshLocale, this, true);
1462 this.cfg.subscribeToConfigEvent("MONTHS_SHORT", refreshLocale, this, true);
1463 this.cfg.subscribeToConfigEvent("MONTHS_LONG", refreshLocale, this, true);
1464 this.cfg.subscribeToConfigEvent("WEEKDAYS_1CHAR", refreshLocale, this, true);
1465 this.cfg.subscribeToConfigEvent("WEEKDAYS_SHORT", refreshLocale, this, true);
1466 this.cfg.subscribeToConfigEvent("WEEKDAYS_MEDIUM", refreshLocale, this, true);
1467 this.cfg.subscribeToConfigEvent("WEEKDAYS_LONG", refreshLocale, this, true);
1468
1469 /**
1470 * The setting that determines which length of month labels should be used. Possible values are "short" and "long".
1471 * @config LOCALE_MONTHS
1472 * @type String
1473 * @default "long"
1474 */
1475 this.cfg.addProperty("LOCALE_MONTHS",{ value:"long", handler:this.configLocaleValues } );
1476
1477 /**
1478 * The setting that determines which length of weekday labels should be used. Possible values are "1char", "short", "medium", and "long".
1479 * @config LOCALE_WEEKDAYS
1480 * @type String
1481 * @default "short"
1482 */
1483 this.cfg.addProperty("LOCALE_WEEKDAYS",{ value:"short", handler:this.configLocaleValues } );
1484
1485 /**
1486 * The value used to delimit individual dates in a date string passed to various Calendar functions.
1487 * @config DATE_DELIMITER
1488 * @type String
1489 * @default ","
1490 */
1491 this.cfg.addProperty("DATE_DELIMITER", { value:",", handler:this.configLocale } );
1492
1493 /**
1494 * The value used to delimit date fields in a date string passed to various Calendar functions.
1495 * @config DATE_FIELD_DELIMITER
1496 * @type String
1497 * @default "/"
1498 */
1499 this.cfg.addProperty("DATE_FIELD_DELIMITER",{ value:"/", handler:this.configLocale } );
1500
1501 /**
1502 * The value used to delimit date ranges in a date string passed to various Calendar functions.
1503 * @config DATE_RANGE_DELIMITER
1504 * @type String
1505 * @default "-"
1506 */
1507 this.cfg.addProperty("DATE_RANGE_DELIMITER",{ value:"-", handler:this.configLocale } );
1508
1509 /**
1510 * The position of the month in a month/year date string
1511 * @config MY_MONTH_POSITION
1512 * @type Number
1513 * @default 1
1514 */
1515 this.cfg.addProperty("MY_MONTH_POSITION",{ value:1, handler:this.configLocale, validator:this.cfg.checkNumber } );
1516
1517 /**
1518 * The position of the year in a month/year date string
1519 * @config MY_YEAR_POSITION
1520 * @type Number
1521 * @default 2
1522 */
1523 this.cfg.addProperty("MY_YEAR_POSITION",{ value:2, handler:this.configLocale, validator:this.cfg.checkNumber } );
1524
1525 /**
1526 * The position of the month in a month/day date string
1527 * @config MD_MONTH_POSITION
1528 * @type Number
1529 * @default 1
1530 */
1531 this.cfg.addProperty("MD_MONTH_POSITION",{ value:1, handler:this.configLocale, validator:this.cfg.checkNumber } );
1532
1533 /**
1534 * The position of the day in a month/year date string
1535 * @config MD_DAY_POSITION
1536 * @type Number
1537 * @default 2
1538 */
1539 this.cfg.addProperty("MD_DAY_POSITION", { value:2, handler:this.configLocale, validator:this.cfg.checkNumber } );
1540
1541 /**
1542 * The position of the month in a month/day/year date string
1543 * @config MDY_MONTH_POSITION
1544 * @type Number
1545 * @default 1
1546 */
1547 this.cfg.addProperty("MDY_MONTH_POSITION",{ value:1, handler:this.configLocale, validator:this.cfg.checkNumber } );
1548
1549 /**
1550 * The position of the day in a month/day/year date string
1551 * @config MDY_DAY_POSITION
1552 * @type Number
1553 * @default 2
1554 */
1555 this.cfg.addProperty("MDY_DAY_POSITION",{ value:2, handler:this.configLocale, validator:this.cfg.checkNumber } );
1556
1557 /**
1558 * The position of the year in a month/day/year date string
1559 * @config MDY_YEAR_POSITION
1560 * @type Number
1561 * @default 3
1562 */
1563 this.cfg.addProperty("MDY_YEAR_POSITION",{ value:3, handler:this.configLocale, validator:this.cfg.checkNumber } );
1564};
1565
1566/**
1567* The default handler for the "pagedate" property
1568* @method configPageDate
1569*/
1570YAHOO.widget.Calendar.prototype.configPageDate = function(type, args, obj) {
1571 var val = args[0];
1572 var month, year, aMonthYear;
1573
1574 if (val) {
1575 if (val instanceof Date) {
1576 val = YAHOO.widget.DateMath.findMonthStart(val);
1577 this.cfg.setProperty("pagedate", val, true);
1578 if (! this._pageDate) {
1579 this._pageDate = this.cfg.getProperty("pagedate");
1580 }
1581 return;
1582 } else {
1583 aMonthYear = val.split(this.cfg.getProperty("DATE_FIELD_DELIMITER"));
1584 month = parseInt(aMonthYear[this.cfg.getProperty("MY_MONTH_POSITION")-1], 10)-1;
1585 year = parseInt(aMonthYear[this.cfg.getProperty("MY_YEAR_POSITION")-1], 10);
1586 }
1587 } else {
1588 month = this.today.getMonth();
1589 year = this.today.getFullYear();
1590 }
1591
1592 this.cfg.setProperty("pagedate", new Date(year, month, 1), true);
1593 if (! this._pageDate) {
1594 this._pageDate = this.cfg.getProperty("pagedate");
1595 }
1596};
1597
1598/**
1599* The default handler for the "mindate" property
1600* @method configMinDate
1601*/
1602YAHOO.widget.Calendar.prototype.configMinDate = function(type, args, obj) {
1603 var val = args[0];
1604 if (typeof val == 'string') {
1605 val = this._parseDate(val);
1606 this.cfg.setProperty("mindate", new Date(val[0],(val[1]-1),val[2]));
1607 }
1608};
1609
1610/**
1611* The default handler for the "maxdate" property
1612* @method configMaxDate
1613*/
1614YAHOO.widget.Calendar.prototype.configMaxDate = function(type, args, obj) {
1615 var val = args[0];
1616 if (typeof val == 'string') {
1617 val = this._parseDate(val);
1618 this.cfg.setProperty("maxdate", new Date(val[0],(val[1]-1),val[2]));
1619 }
1620};
1621
1622/**
1623* The default handler for the "selected" property
1624* @method configSelected
1625*/
1626YAHOO.widget.Calendar.prototype.configSelected = function(type, args, obj) {
1627 var selected = args[0];
1628
1629 if (selected) {
1630 if (typeof selected == 'string') {
1631 this.cfg.setProperty("selected", this._parseDates(selected), true);
1632 }
1633 }
1634 if (! this._selectedDates) {
1635 this._selectedDates = this.cfg.getProperty("selected");
1636 }
1637};
1638
1639/**
1640* The default handler for all configuration options properties
1641* @method configOptions
1642*/
1643YAHOO.widget.Calendar.prototype.configOptions = function(type, args, obj) {
1644 type = type.toUpperCase();
1645 var val = args[0];
1646 this.Options[type] = val;
1647};
1648
1649/**
1650* The default handler for all configuration locale properties
1651* @method configLocale
1652*/
1653YAHOO.widget.Calendar.prototype.configLocale = function(type, args, obj) {
1654 type = type.toUpperCase();
1655 var val = args[0];
1656 this.Locale[type] = val;
1657
1658 this.cfg.refireEvent("LOCALE_MONTHS");
1659 this.cfg.refireEvent("LOCALE_WEEKDAYS");
1660
1661};
1662
1663/**
1664* The default handler for all configuration locale field length properties
1665* @method configLocaleValues
1666*/
1667YAHOO.widget.Calendar.prototype.configLocaleValues = function(type, args, obj) {
1668 type = type.toUpperCase();
1669 var val = args[0];
1670
1671 switch (type) {
1672 case "LOCALE_MONTHS":
1673 switch (val) {
1674 case "short":
1675 this.Locale.LOCALE_MONTHS = this.cfg.getProperty("MONTHS_SHORT").concat();
1676 break;
1677 case "long":
1678 this.Locale.LOCALE_MONTHS = this.cfg.getProperty("MONTHS_LONG").concat();
1679 break;
1680 }
1681 break;
1682 case "LOCALE_WEEKDAYS":
1683 switch (val) {
1684 case "1char":
1685 this.Locale.LOCALE_WEEKDAYS = this.cfg.getProperty("WEEKDAYS_1CHAR").concat();
1686 break;
1687 case "short":
1688 this.Locale.LOCALE_WEEKDAYS = this.cfg.getProperty("WEEKDAYS_SHORT").concat();
1689 break;
1690 case "medium":
1691 this.Locale.LOCALE_WEEKDAYS = this.cfg.getProperty("WEEKDAYS_MEDIUM").concat();
1692 break;
1693 case "long":
1694 this.Locale.LOCALE_WEEKDAYS = this.cfg.getProperty("WEEKDAYS_LONG").concat();
1695 break;
1696 }
1697
1698 var START_WEEKDAY = this.cfg.getProperty("START_WEEKDAY");
1699
1700 if (START_WEEKDAY > 0) {
1701 for (var w=0;w<START_WEEKDAY;++w) {
1702 this.Locale.LOCALE_WEEKDAYS.push(this.Locale.LOCALE_WEEKDAYS.shift());
1703 }
1704 }
1705 break;
1706 }
1707};
1708
1709/**
1710* Defines the style constants for the Calendar
1711* @method initStyles
1712*/
1713YAHOO.widget.Calendar.prototype.initStyles = function() {
1714
1715 /**
1716 * Collection of Style constants for the Calendar
1717 * @property Style
1718 */
1719 this.Style = {
1720 /**
1721 * @property Style.CSS_ROW_HEADER
1722 */
1723 CSS_ROW_HEADER: "calrowhead",
1724 /**
1725 * @property Style.CSS_ROW_FOOTER
1726 */
1727 CSS_ROW_FOOTER: "calrowfoot",
1728 /**
1729 * @property Style.CSS_CELL
1730 */
1731 CSS_CELL : "calcell",
1732 /**
1733 * @property Style.CSS_CELL_SELECTED
1734 */
1735 CSS_CELL_SELECTED : "selected",
1736 /**
1737 * @property Style.CSS_CELL_SELECTABLE
1738 */
1739 CSS_CELL_SELECTABLE : "selectable",
1740 /**
1741 * @property Style.CSS_CELL_RESTRICTED
1742 */
1743 CSS_CELL_RESTRICTED : "restricted",
1744 /**
1745 * @property Style.CSS_CELL_TODAY
1746 */
1747 CSS_CELL_TODAY : "today",
1748 /**
1749 * @property Style.CSS_CELL_OOM
1750 */
1751 CSS_CELL_OOM : "oom",
1752 /**
1753 * @property Style.CSS_CELL_OOB
1754 */
1755 CSS_CELL_OOB : "previous",
1756 /**
1757 * @property Style.CSS_HEADER
1758 */
1759 CSS_HEADER : "calheader",
1760 /**
1761 * @property Style.CSS_HEADER_TEXT
1762 */
1763 CSS_HEADER_TEXT : "calhead",
1764 /**
1765 * @property Style.CSS_WEEKDAY_CELL
1766 */
1767 CSS_WEEKDAY_CELL : "calweekdaycell",
1768 /**
1769 * @property Style.CSS_WEEKDAY_ROW
1770 */
1771 CSS_WEEKDAY_ROW : "calweekdayrow",
1772 /**
1773 * @property Style.CSS_FOOTER
1774 */
1775 CSS_FOOTER : "calfoot",
1776 /**
1777 * @property Style.CSS_CALENDAR
1778 */
1779 CSS_CALENDAR : "yui-calendar",
1780 /**
1781 * @property Style.CSS_SINGLE
1782 */
1783 CSS_SINGLE : "single",
1784 /**
1785 * @property Style.CSS_CONTAINER
1786 */
1787 CSS_CONTAINER : "yui-calcontainer",
1788 /**
1789 * @property Style.CSS_NAV_LEFT
1790 */
1791 CSS_NAV_LEFT : "calnavleft",
1792 /**
1793 * @property Style.CSS_NAV_RIGHT
1794 */
1795 CSS_NAV_RIGHT : "calnavright",
1796 /**
1797 * @property Style.CSS_CELL_TOP
1798 */
1799 CSS_CELL_TOP : "calcelltop",
1800 /**
1801 * @property Style.CSS_CELL_LEFT
1802 */
1803 CSS_CELL_LEFT : "calcellleft",
1804 /**
1805 * @property Style.CSS_CELL_RIGHT
1806 */
1807 CSS_CELL_RIGHT : "calcellright",
1808 /**
1809 * @property Style.CSS_CELL_BOTTOM
1810 */
1811 CSS_CELL_BOTTOM : "calcellbottom",
1812 /**
1813 * @property Style.CSS_CELL_HOVER
1814 */
1815 CSS_CELL_HOVER : "calcellhover",
1816 /**
1817 * @property Style.CSS_CELL_HIGHLIGHT1
1818 */
1819 CSS_CELL_HIGHLIGHT1 : "highlight1",
1820 /**
1821 * @property Style.CSS_CELL_HIGHLIGHT2
1822 */
1823 CSS_CELL_HIGHLIGHT2 : "highlight2",
1824 /**
1825 * @property Style.CSS_CELL_HIGHLIGHT3
1826 */
1827 CSS_CELL_HIGHLIGHT3 : "highlight3",
1828 /**
1829 * @property Style.CSS_CELL_HIGHLIGHT4
1830 */
1831 CSS_CELL_HIGHLIGHT4 : "highlight4"
1832 };
1833};
1834
1835/**
1836* Builds the date label that will be displayed in the calendar header or
1837* footer, depending on configuration.
1838* @method buildMonthLabel
1839 * @return {String}The formatted calendar month label
1840*/
1841YAHOO.widget.Calendar.prototype.buildMonthLabel = function() {
1842 var text = this.Locale.LOCALE_MONTHS[this.cfg.getProperty("pagedate").getMonth()] + " " + this.cfg.getProperty("pagedate").getFullYear();
1843 return text;
1844};
1845
1846/**
1847* Builds the date digit that will be displayed in calendar cells
1848* @method buildDayLabel
1849 * @param {Date} workingDateThe current working date
1850 * @return {String}The formatted day label
1851*/
1852YAHOO.widget.Calendar.prototype.buildDayLabel = function(workingDate) {
1853 var day = workingDate.getDate();
1854 return day;
1855};
1856
1857/**
1858* Renders the calendar header.
1859* @method renderHeader
1860 * @param {Array} htmlThe current working HTML array
1861* @return {Array} The current working HTML array
1862*/
1863YAHOO.widget.Calendar.prototype.renderHeader = function(html) {
1864 var colSpan = 7;
1865
1866 if (this.cfg.getProperty("SHOW_WEEK_HEADER")) {
1867 colSpan += 1;
1868 }
1869
1870 if (this.cfg.getProperty("SHOW_WEEK_FOOTER")) {
1871 colSpan += 1;
1872 }
1873
1874 html[html.length] = "<thead>";
1875 html[html.length] = "<tr>";
1876 html[html.length] = '<th colspan="' + colSpan + '" class="' + this.Style.CSS_HEADER_TEXT + '">';
1877 html[html.length] = '<div class="' + this.Style.CSS_HEADER + '">';
1878
1879 var renderLeft, renderRight = false;
1880
1881 if (this.parent) {
1882 if (this.index === 0) {
1883 renderLeft = true;
1884 }
1885 if (this.index == (this.parent.cfg.getProperty("pages") -1)) {
1886 renderRight = true;
1887 }
1888 } else {
1889 renderLeft = true;
1890 renderRight = true;
1891 }
1892
1893 var cal = this.parent || this;
1894
1895 if (renderLeft) {
1896 html[html.length] = '<a class="' + this.Style.CSS_NAV_LEFT + '" style="background-image:url(' + this.cfg.getProperty("NAV_ARROW_LEFT") + ')">&#160;</a>';
1897 }
1898
1899 html[html.length] = this.buildMonthLabel();
1900
1901 if (renderRight) {
1902 html[html.length] = '<a class="' + this.Style.CSS_NAV_RIGHT + '" style="background-image:url(' + this.cfg.getProperty("NAV_ARROW_RIGHT") + ')">&#160;</a>';
1903 }
1904
1905
1906 html[html.length] = '</div>';
1907 html[html.length] = '</th>';
1908 html[html.length] = '</tr>';
1909
1910 if (this.cfg.getProperty("SHOW_WEEKDAYS")) {
1911 html = this.buildWeekdays(html);
1912 }
1913
1914 html[html.length] = '</thead>';
1915
1916 return html;
1917};
1918
1919/**
1920* Renders the Calendar's weekday headers.
1921* @method buildWeekdays
1922 * @param {Array} htmlThe current working HTML array
1923* @return {Array} The current working HTML array
1924*/
1925YAHOO.widget.Calendar.prototype.buildWeekdays = function(html) {
1926
1927 html[html.length] = '<tr class="' + this.Style.CSS_WEEKDAY_ROW + '">';
1928
1929 if (this.cfg.getProperty("SHOW_WEEK_HEADER")) {
1930 html[html.length] = '<th>&#160;</th>';
1931 }
1932
1933 for(var i=0;i<this.Locale.LOCALE_WEEKDAYS.length;++i) {
1934 html[html.length] = '<th class="calweekdaycell">' + this.Locale.LOCALE_WEEKDAYS[i] + '</th>';
1935 }
1936
1937 if (this.cfg.getProperty("SHOW_WEEK_FOOTER")) {
1938 html[html.length] = '<th>&#160;</th>';
1939 }
1940
1941 html[html.length] = '</tr>';
1942
1943 return html;
1944};
1945
1946/**
1947* Renders the calendar body.
1948* @method renderBody
1949 * @param {Date} workingDateThe current working Date being used for the render process
1950 * @param {Array} htmlThe current working HTML array
1951* @return {Array} The current working HTML array
1952*/
1953YAHOO.widget.Calendar.prototype.renderBody = function(workingDate, html) {
1954
1955 var startDay = this.cfg.getProperty("START_WEEKDAY");
1956
1957 this.preMonthDays = workingDate.getDay();
1958 if (startDay > 0) {
1959 this.preMonthDays -= startDay;
1960 }
1961 if (this.preMonthDays < 0) {
1962 this.preMonthDays += 7;
1963 }
1964
1965 this.monthDays = YAHOO.widget.DateMath.findMonthEnd(workingDate).getDate();
1966 this.postMonthDays = YAHOO.widget.Calendar.DISPLAY_DAYS-this.preMonthDays-this.monthDays;
1967
1968 workingDate = YAHOO.widget.DateMath.subtract(workingDate, YAHOO.widget.DateMath.DAY, this.preMonthDays);
1969
1970 var useDate,weekNum,weekClass;
1971 useDate = this.cfg.getProperty("pagedate");
1972
1973 html[html.length] = '<tbody class="m' + (useDate.getMonth()+1) + '">';
1974
1975 var i = 0;
1976
1977 var tempDiv = document.createElement("div");
1978 var cell = document.createElement("td");
1979 tempDiv.appendChild(cell);
1980
1981 var jan1 = new Date(useDate.getFullYear(),0,1);
1982
1983 var cal = this.parent || this;
1984
1985 for (var r=0;r<6;r++) {
1986
1987 weekNum = YAHOO.widget.DateMath.getWeekNumber(workingDate, useDate.getFullYear(), startDay);
1988
1989 weekClass = "w" + weekNum;
1990
1991 if (r !== 0 && this.isDateOOM(workingDate) && this.cfg.getProperty("HIDE_BLANK_WEEKS") === true) {
1992 break;
1993 } else {
1994
1995 html[html.length] = '<tr class="' + weekClass + '">';
1996
1997 if (this.cfg.getProperty("SHOW_WEEK_HEADER")) { html = this.renderRowHeader(weekNum, html); }
1998
1999 for (var d=0;d<7;d++){ // Render actual days
2000
2001 var cellRenderers = [];
2002
2003 this.clearElement(cell);
2004
2005 YAHOO.util.Dom.addClass(cell, "calcell");
2006
2007 cell.id = this.id + "_cell" + i;
2008
2009 cell.innerHTML = i;
2010
2011 var renderer = null;
2012
2013 if (workingDate.getFullYear()== this.today.getFullYear() &&
2014 workingDate.getMonth() == this.today.getMonth() &&
2015 workingDate.getDate() == this.today.getDate()) {
2016 cellRenderers[cellRenderers.length]=cal.renderCellStyleToday;
2017 }
2018
2019 this.cellDates[this.cellDates.length]=[workingDate.getFullYear(),workingDate.getMonth()+1,workingDate.getDate()]; // Add this date to cellDates
2020
2021 if (this.isDateOOM(workingDate)) {
2022 cellRenderers[cellRenderers.length]=cal.renderCellNotThisMonth;
2023 } else {
2024
2025 YAHOO.util.Dom.addClass(cell, "wd" + workingDate.getDay());
2026 YAHOO.util.Dom.addClass(cell, "d" + workingDate.getDate());
2027
2028 for (var s=0;s<this.renderStack.length;++s) {
2029
2030 var rArray = this.renderStack[s];
2031 var type = rArray[0];
2032
2033 var month;
2034 var day;
2035 var year;
2036
2037 switch (type) {
2038 case YAHOO.widget.Calendar.DATE:
2039 month = rArray[1][1];
2040 day = rArray[1][2];
2041 year = rArray[1][0];
2042
2043 if (workingDate.getMonth()+1 == month && workingDate.getDate() == day && workingDate.getFullYear() == year) {
2044 renderer = rArray[2];
2045 this.renderStack.splice(s,1);
2046 }
2047 break;
2048 case YAHOO.widget.Calendar.MONTH_DAY:
2049 month = rArray[1][0];
2050 day = rArray[1][1];
2051
2052 if (workingDate.getMonth()+1 == month && workingDate.getDate() == day) {
2053 renderer = rArray[2];
2054 this.renderStack.splice(s,1);
2055 }
2056 break;
2057 case YAHOO.widget.Calendar.RANGE:
2058 var date1 = rArray[1][0];
2059 var date2 = rArray[1][1];
2060
2061 var d1month = date1[1];
2062 var d1day = date1[2];
2063 var d1year = date1[0];
2064
2065 var d1 = new Date(d1year, d1month-1, d1day);
2066
2067 var d2month = date2[1];
2068 var d2day = date2[2];
2069 var d2year = date2[0];
2070
2071 var d2 = new Date(d2year, d2month-1, d2day);
2072
2073 if (workingDate.getTime() >= d1.getTime() && workingDate.getTime() <= d2.getTime()) {
2074 renderer = rArray[2];
2075
2076 if (workingDate.getTime()==d2.getTime()) {
2077 this.renderStack.splice(s,1);
2078 }
2079 }
2080 break;
2081 case YAHOO.widget.Calendar.WEEKDAY:
2082
2083 var weekday = rArray[1][0];
2084 if (workingDate.getDay()+1 == weekday) {
2085 renderer = rArray[2];
2086 }
2087 break;
2088 case YAHOO.widget.Calendar.MONTH:
2089
2090 month = rArray[1][0];
2091 if (workingDate.getMonth()+1 == month) {
2092 renderer = rArray[2];
2093 }
2094 break;
2095 }
2096
2097 if (renderer) {
2098 cellRenderers[cellRenderers.length]=renderer;
2099 }
2100 }
2101
2102 }
2103
2104 if (this._indexOfSelectedFieldArray([workingDate.getFullYear(),workingDate.getMonth()+1,workingDate.getDate()]) > -1) {
2105 cellRenderers[cellRenderers.length]=cal.renderCellStyleSelected;
2106 }
2107
2108 var mindate = this.cfg.getProperty("mindate");
2109 var maxdate = this.cfg.getProperty("maxdate");
2110
2111 if (mindate) {
2112 mindate = YAHOO.widget.DateMath.clearTime(mindate);
2113 }
2114 if (maxdate) {
2115 maxdate = YAHOO.widget.DateMath.clearTime(maxdate);
2116 }
2117
2118 if (
2119 (mindate && (workingDate.getTime() < mindate.getTime())) ||
2120 (maxdate && (workingDate.getTime() > maxdate.getTime()))
2121 ) {
2122 cellRenderers[cellRenderers.length]=cal.renderOutOfBoundsDate;
2123 } else {
2124 cellRenderers[cellRenderers.length]=cal.styleCellDefault;
2125 cellRenderers[cellRenderers.length]=cal.renderCellDefault;
2126 }
2127
2128
2129
2130 for (var x=0;x<cellRenderers.length;++x) {
2131 var ren = cellRenderers[x];
2132 if (ren.call((this.parent || this),workingDate,cell) == YAHOO.widget.Calendar.STOP_RENDER) {
2133 break;
2134 }
2135 }
2136
2137 workingDate.setTime(workingDate.getTime() + YAHOO.widget.DateMath.ONE_DAY_MS);
2138
2139 if (i >= 0 && i <= 6) {
2140 YAHOO.util.Dom.addClass(cell, this.Style.CSS_CELL_TOP);
2141 }
2142 if ((i % 7) === 0) {
2143 YAHOO.util.Dom.addClass(cell, this.Style.CSS_CELL_LEFT);
2144 }
2145 if (((i+1) % 7) === 0) {
2146 YAHOO.util.Dom.addClass(cell, this.Style.CSS_CELL_RIGHT);
2147 }
2148
2149 var postDays = this.postMonthDays;
2150 if (postDays >= 7 && this.cfg.getProperty("HIDE_BLANK_WEEKS")) {
2151 var blankWeeks = Math.floor(postDays/7);
2152 for (var p=0;p<blankWeeks;++p) {
2153 postDays -= 7;
2154 }
2155 }
2156
2157 if (i >= ((this.preMonthDays+postDays+this.monthDays)-7)) {
2158 YAHOO.util.Dom.addClass(cell, this.Style.CSS_CELL_BOTTOM);
2159 }
2160
2161 html[html.length] = tempDiv.innerHTML;
2162
2163 i++;
2164 }
2165
2166 if (this.cfg.getProperty("SHOW_WEEK_FOOTER")) { html = this.renderRowFooter(weekNum, html); }
2167
2168 html[html.length] = '</tr>';
2169 }
2170 }
2171
2172 html[html.length] = '</tbody>';
2173
2174 return html;
2175};
2176
2177/**
2178* Renders the calendar footer. In the default implementation, there is
2179* no footer.
2180* @method renderFooter
2181 * @param {Array} htmlThe current working HTML array
2182* @return {Array} The current working HTML array
2183*/
2184YAHOO.widget.Calendar.prototype.renderFooter = function(html) { return html; };
2185
2186/**
2187* Renders the calendar after it has been configured. The render() method has a specific call chain that will execute
2188* when the method is called: renderHeader, renderBody, renderFooter.
2189* Refer to the documentation for those methods for information on
2190* individual render tasks.
2191* @method render
2192*/
2193YAHOO.widget.Calendar.prototype.render = function() {
2194 this.beforeRenderEvent.fire();
2195
2196 // Find starting day of the current month
2197 var workingDate = YAHOO.widget.DateMath.findMonthStart(this.cfg.getProperty("pagedate"));
2198
2199 this.resetRenderers();
2200 this.cellDates.length = 0;
2201
2202 YAHOO.util.Event.purgeElement(this.oDomContainer, true);
2203
2204 var html = [];
2205
2206 html[html.length] = '<table cellSpacing="0" class="' + this.Style.CSS_CALENDAR + ' y' + workingDate.getFullYear() + '" id="' + this.id + '">';
2207 html = this.renderHeader(html);
2208 html = this.renderBody(workingDate, html);
2209 html = this.renderFooter(html);
2210 html[html.length] = '</table>';
2211
2212 this.oDomContainer.innerHTML = html.join("\n");
2213
2214 this.applyListeners();
2215 this.cells = this.oDomContainer.getElementsByTagName("td");
2216
2217 this.cfg.refireEvent("title");
2218 this.cfg.refireEvent("close");
2219 this.cfg.refireEvent("iframe");
2220
2221 this.renderEvent.fire();
2222};
2223
2224/**
2225* Applies the Calendar's DOM listeners to applicable elements.
2226* @method applyListeners
2227*/
2228YAHOO.widget.Calendar.prototype.applyListeners = function() {
2229
2230 var root = this.oDomContainer;
2231 var cal = this.parent || this;
2232
2233 var linkLeft, linkRight;
2234
2235 linkLeft = YAHOO.util.Dom.getElementsByClassName(this.Style.CSS_NAV_LEFT, "a", root);
2236 linkRight = YAHOO.util.Dom.getElementsByClassName(this.Style.CSS_NAV_RIGHT, "a", root);
2237
2238 if (linkLeft) {
2239 this.linkLeft = linkLeft[0];
2240 YAHOO.util.Event.addListener(this.linkLeft, "mousedown", cal.previousMonth, cal, true);
2241 }
2242
2243 if (linkRight) {
2244 this.linkRight = linkRight[0];
2245 YAHOO.util.Event.addListener(this.linkRight, "mousedown", cal.nextMonth, cal, true);
2246 }
2247
2248 if (this.domEventMap) {
2249 var el,elements;
2250 for (var cls in this.domEventMap) {
2251 if (this.domEventMap.hasOwnProperty(cls)) {
2252 var items = this.domEventMap[cls];
2253
2254 if (! (items instanceof Array)) {
2255 items = [items];
2256 }
2257
2258 for (var i=0;i<items.length;i++){
2259 var item = items[i];
2260 elements = YAHOO.util.Dom.getElementsByClassName(cls, item.tag, this.oDomContainer);
2261
2262 for (var c=0;c<elements.length;c++) {
2263 el = elements[c];
2264 YAHOO.util.Event.addListener(el, item.event, item.handler, item.scope, item.correct );
2265 }
2266 }
2267 }
2268 }
2269 }
2270
2271 YAHOO.util.Event.addListener(this.oDomContainer, "click", this.doSelectCell, this);
2272 YAHOO.util.Event.addListener(this.oDomContainer, "mouseover", this.doCellMouseOver, this);
2273 YAHOO.util.Event.addListener(this.oDomContainer, "mouseout", this.doCellMouseOut, this);
2274};
2275
2276/**
2277* Retrieves the Date object for the specified Calendar cell
2278* @method getDateByCellId
2279 * @param {String} idThe id of the cell
2280* @return {Date} The Date object for the specified Calendar cell
2281*/
2282YAHOO.widget.Calendar.prototype.getDateByCellId = function(id) {
2283 var date = this.getDateFieldsByCellId(id);
2284 return new Date(date[0],date[1]-1,date[2]);
2285};
2286
2287/**
2288* Retrieves the Date object for the specified Calendar cell
2289* @method getDateFieldsByCellId
2290 * @param {String} idThe id of the cell
2291 * @return {Array}The array of Date fields for the specified Calendar cell
2292*/
2293YAHOO.widget.Calendar.prototype.getDateFieldsByCellId = function(id) {
2294 id = id.toLowerCase().split("_cell")[1];
2295 id = parseInt(id, 10);
2296 return this.cellDates[id];
2297};
2298
2299// BEGIN BUILT-IN TABLE CELL RENDERERS
2300
2301/**
2302* Renders a cell that falls before the minimum date or after the maximum date.
2303* widget class.
2304* @method renderOutOfBoundsDate
2305 * @param {Date} workingDate The current working Date object being used to generate the calendar
2306 * @param {HTMLTableCellElement} cell The current working cell in the calendar
2307* @return {String} YAHOO.widget.Calendar.STOP_RENDER if rendering should stop with this style, null or nothing if rendering
2308 * should not be terminated
2309*/
2310YAHOO.widget.Calendar.prototype.renderOutOfBoundsDate = function(workingDate, cell) {
2311 YAHOO.util.Dom.addClass(cell, this.Style.CSS_CELL_OOB);
2312 cell.innerHTML = workingDate.getDate();
2313 return YAHOO.widget.Calendar.STOP_RENDER;
2314};
2315
2316/**
2317* Renders the row header for a week.
2318* @method renderRowHeader
2319 * @param {Number} weekNumThe week number of the current row
2320 * @param {Array} cellThe current working HTML array
2321*/
2322YAHOO.widget.Calendar.prototype.renderRowHeader = function(weekNum, html) {
2323 html[html.length] = '<th class="calrowhead">' + weekNum + '</th>';
2324 return html;
2325};
2326
2327/**
2328* Renders the row footer for a week.
2329* @method renderRowFooter
2330 * @param {Number} weekNumThe week number of the current row
2331 * @param {Array} cellThe current working HTML array
2332*/
2333YAHOO.widget.Calendar.prototype.renderRowFooter = function(weekNum, html) {
2334 html[html.length] = '<th class="calrowfoot">' + weekNum + '</th>';
2335 return html;
2336};
2337
2338/**
2339* Renders a single standard calendar cell in the calendar widget table.
2340* All logic for determining how a standard default cell will be rendered is
2341* encapsulated in this method, and must be accounted for when extending the
2342* widget class.
2343* @method renderCellDefault
2344 * @param {Date} workingDate The current working Date object being used to generate the calendar
2345 * @param {HTMLTableCellElement} cell The current working cell in the calendar
2346*/
2347YAHOO.widget.Calendar.prototype.renderCellDefault = function(workingDate, cell) {
2348 cell.innerHTML = '<a href="javascript:void(null);" >' + this.buildDayLabel(workingDate) + "</a>";
2349};
2350
2351/**
2352* Styles a selectable cell.
2353* @method styleCellDefault
2354 * @param {Date} workingDate The current working Date object being used to generate the calendar
2355 * @param {HTMLTableCellElement} cell The current working cell in the calendar
2356*/
2357YAHOO.widget.Calendar.prototype.styleCellDefault = function(workingDate, cell) {
2358 YAHOO.util.Dom.addClass(cell, this.Style.CSS_CELL_SELECTABLE);
2359};
2360
2361
2362/**
2363* Renders a single standard calendar cell using the CSS hightlight1 style
2364* @method renderCellStyleHighlight1
2365 * @param {Date} workingDate The current working Date object being used to generate the calendar
2366 * @param {HTMLTableCellElement} cell The current working cell in the calendar
2367*/
2368YAHOO.widget.Calendar.prototype.renderCellStyleHighlight1 = function(workingDate, cell) {
2369 YAHOO.util.Dom.addClass(cell, this.Style.CSS_CELL_HIGHLIGHT1);
2370};
2371
2372/**
2373* Renders a single standard calendar cell using the CSS hightlight2 style
2374* @method renderCellStyleHighlight2
2375 * @param {Date} workingDate The current working Date object being used to generate the calendar
2376 * @param {HTMLTableCellElement} cell The current working cell in the calendar
2377*/
2378YAHOO.widget.Calendar.prototype.renderCellStyleHighlight2 = function(workingDate, cell) {
2379 YAHOO.util.Dom.addClass(cell, this.Style.CSS_CELL_HIGHLIGHT2);
2380};
2381
2382/**
2383* Renders a single standard calendar cell using the CSS hightlight3 style
2384* @method renderCellStyleHighlight3
2385 * @param {Date} workingDate The current working Date object being used to generate the calendar
2386 * @param {HTMLTableCellElement} cell The current working cell in the calendar
2387*/
2388YAHOO.widget.Calendar.prototype.renderCellStyleHighlight3 = function(workingDate, cell) {
2389 YAHOO.util.Dom.addClass(cell, this.Style.CSS_CELL_HIGHLIGHT3);
2390};
2391
2392/**
2393* Renders a single standard calendar cell using the CSS hightlight4 style
2394* @method renderCellStyleHighlight4
2395 * @param {Date} workingDate The current working Date object being used to generate the calendar
2396 * @param {HTMLTableCellElement} cell The current working cell in the calendar
2397*/
2398YAHOO.widget.Calendar.prototype.renderCellStyleHighlight4 = function(workingDate, cell) {
2399 YAHOO.util.Dom.addClass(cell, this.Style.CSS_CELL_HIGHLIGHT4);
2400};
2401
2402/**
2403* Applies the default style used for rendering today's date to the current calendar cell
2404* @method renderCellStyleToday
2405 * @param {Date} workingDate The current working Date object being used to generate the calendar
2406 * @param {HTMLTableCellElement} cell The current working cell in the calendar
2407*/
2408YAHOO.widget.Calendar.prototype.renderCellStyleToday = function(workingDate, cell) {
2409 YAHOO.util.Dom.addClass(cell, this.Style.CSS_CELL_TODAY);
2410};
2411
2412/**
2413* Applies the default style used for rendering selected dates to the current calendar cell
2414* @method renderCellStyleSelected
2415 * @param {Date} workingDate The current working Date object being used to generate the calendar
2416 * @param {HTMLTableCellElement} cell The current working cell in the calendar
2417* @return {String} YAHOO.widget.Calendar.STOP_RENDER if rendering should stop with this style, null or nothing if rendering
2418 * should not be terminated
2419*/
2420YAHOO.widget.Calendar.prototype.renderCellStyleSelected = function(workingDate, cell) {
2421 YAHOO.util.Dom.addClass(cell, this.Style.CSS_CELL_SELECTED);
2422};
2423
2424/**
2425* Applies the default style used for rendering dates that are not a part of the current
2426* month (preceding or trailing the cells for the current month)
2427* @method renderCellNotThisMonth
2428 * @param {Date} workingDate The current working Date object being used to generate the calendar
2429 * @param {HTMLTableCellElement} cell The current working cell in the calendar
2430* @return {String} YAHOO.widget.Calendar.STOP_RENDER if rendering should stop with this style, null or nothing if rendering
2431 * should not be terminated
2432*/
2433YAHOO.widget.Calendar.prototype.renderCellNotThisMonth = function(workingDate, cell) {
2434 YAHOO.util.Dom.addClass(cell, this.Style.CSS_CELL_OOM);
2435 cell.innerHTML=workingDate.getDate();
2436 return YAHOO.widget.Calendar.STOP_RENDER;
2437};
2438
2439/**
2440* Renders the current calendar cell as a non-selectable "black-out" date using the default
2441* restricted style.
2442* @method renderBodyCellRestricted
2443 * @param {Date} workingDate The current working Date object being used to generate the calendar
2444 * @param {HTMLTableCellElement} cell The current working cell in the calendar
2445* @return {String} YAHOO.widget.Calendar.STOP_RENDER if rendering should stop with this style, null or nothing if rendering
2446 * should not be terminated
2447*/
2448YAHOO.widget.Calendar.prototype.renderBodyCellRestricted = function(workingDate, cell) {
2449 YAHOO.util.Dom.addClass(cell, this.Style.CSS_CELL);
2450 YAHOO.util.Dom.addClass(cell, this.Style.CSS_CELL_RESTRICTED);
2451 cell.innerHTML=workingDate.getDate();
2452 return YAHOO.widget.Calendar.STOP_RENDER;
2453};
2454
2455// END BUILT-IN TABLE CELL RENDERERS
2456
2457// BEGIN MONTH NAVIGATION METHODS
2458
2459/**
2460* Adds the designated number of months to the current calendar month, and sets the current
2461* calendar page date to the new month.
2462* @method addMonths
2463 * @param {Number} countThe number of months to add to the current calendar
2464*/
2465YAHOO.widget.Calendar.prototype.addMonths = function(count) {
2466 this.cfg.setProperty("pagedate", YAHOO.widget.DateMath.add(this.cfg.getProperty("pagedate"), YAHOO.widget.DateMath.MONTH, count));
2467 this.resetRenderers();
2468 this.changePageEvent.fire();
2469};
2470
2471/**
2472* Subtracts the designated number of months from the current calendar month, and sets the current
2473* calendar page date to the new month.
2474* @method subtractMonths
2475 * @param {Number} countThe number of months to subtract from the current calendar
2476*/
2477YAHOO.widget.Calendar.prototype.subtractMonths = function(count) {
2478 this.cfg.setProperty("pagedate", YAHOO.widget.DateMath.subtract(this.cfg.getProperty("pagedate"), YAHOO.widget.DateMath.MONTH, count));
2479 this.resetRenderers();
2480 this.changePageEvent.fire();
2481};
2482
2483/**
2484* Adds the designated number of years to the current calendar, and sets the current
2485* calendar page date to the new month.
2486* @method addYears
2487 * @param {Number} countThe number of years to add to the current calendar
2488*/
2489YAHOO.widget.Calendar.prototype.addYears = function(count) {
2490 this.cfg.setProperty("pagedate", YAHOO.widget.DateMath.add(this.cfg.getProperty("pagedate"), YAHOO.widget.DateMath.YEAR, count));
2491 this.resetRenderers();
2492 this.changePageEvent.fire();
2493};
2494
2495/**
2496* Subtcats the designated number of years from the current calendar, and sets the current
2497* calendar page date to the new month.
2498* @method subtractYears
2499 * @param {Number} countThe number of years to subtract from the current calendar
2500*/
2501YAHOO.widget.Calendar.prototype.subtractYears = function(count) {
2502 this.cfg.setProperty("pagedate", YAHOO.widget.DateMath.subtract(this.cfg.getProperty("pagedate"), YAHOO.widget.DateMath.YEAR, count));
2503 this.resetRenderers();
2504 this.changePageEvent.fire();
2505};
2506
2507/**
2508* Navigates to the next month page in the calendar widget.
2509* @method nextMonth
2510*/
2511YAHOO.widget.Calendar.prototype.nextMonth = function() {
2512 this.addMonths(1);
2513};
2514
2515/**
2516* Navigates to the previous month page in the calendar widget.
2517* @method previousMonth
2518*/
2519YAHOO.widget.Calendar.prototype.previousMonth = function() {
2520 this.subtractMonths(1);
2521};
2522
2523/**
2524* Navigates to the next year in the currently selected month in the calendar widget.
2525* @method nextYear
2526*/
2527YAHOO.widget.Calendar.prototype.nextYear = function() {
2528 this.addYears(1);
2529};
2530
2531/**
2532* Navigates to the previous year in the currently selected month in the calendar widget.
2533* @method previousYear
2534*/
2535YAHOO.widget.Calendar.prototype.previousYear = function() {
2536 this.subtractYears(1);
2537};
2538
2539// END MONTH NAVIGATION METHODS
2540
2541// BEGIN SELECTION METHODS
2542
2543/**
2544* Resets the calendar widget to the originally selected month and year, and
2545* sets the calendar to the initial selection(s).
2546* @method reset
2547*/
2548YAHOO.widget.Calendar.prototype.reset = function() {
2549 this.cfg.resetProperty("selected");
2550 this.cfg.resetProperty("pagedate");
2551 this.resetEvent.fire();
2552};
2553
2554/**
2555* Clears the selected dates in the current calendar widget and sets the calendar
2556* to the current month and year.
2557* @method clear
2558*/
2559YAHOO.widget.Calendar.prototype.clear = function() {
2560 this.cfg.setProperty("selected", []);
2561 this.cfg.setProperty("pagedate", new Date(this.today.getTime()));
2562 this.clearEvent.fire();
2563};
2564
2565/**
2566* Selects a date or a collection of dates on the current calendar. This method, by default,
2567* does not call the render method explicitly. Once selection has completed, render must be
2568* called for the changes to be reflected visually.
2569* @method select
2570 * @param {String/Date/Date[]} dateThe date string of dates to select in the current calendar. Valid formats are
2571 * individual date(s) (12/24/2005,12/26/2005) or date range(s) (12/24/2005-1/1/2006).
2572 * Multiple comma-delimited dates can also be passed to this method (12/24/2005,12/11/2005-12/13/2005).
2573 * This method can also take a JavaScript Date object or an array of Date objects.
2574 * @return {Date[]} Array of JavaScript Date objects representing all individual dates that are currently selected.
2575*/
2576YAHOO.widget.Calendar.prototype.select = function(date) {
2577 this.beforeSelectEvent.fire();
2578
2579 var selected = this.cfg.getProperty("selected");
2580 var aToBeSelected = this._toFieldArray(date);
2581
2582 for (var a=0;a<aToBeSelected.length;++a) {
2583 var toSelect = aToBeSelected[a]; // For each date item in the list of dates we're trying to select
2584 if (this._indexOfSelectedFieldArray(toSelect) == -1) { // not already selected?
2585 selected[selected.length]=toSelect;
2586 }
2587 }
2588
2589 if (this.parent) {
2590 this.parent.cfg.setProperty("selected", selected);
2591 } else {
2592 this.cfg.setProperty("selected", selected);
2593 }
2594
2595 this.selectEvent.fire(aToBeSelected);
2596
2597 return this.getSelectedDates();
2598};
2599
2600/**
2601* Selects a date on the current calendar by referencing the index of the cell that should be selected.
2602* This method is used to easily select a single cell (usually with a mouse click) without having to do
2603* a full render. The selected style is applied to the cell directly.
2604* @method selectCell
2605 * @param {Number} cellIndexThe index of the cell to select in the current calendar.
2606 * @return {Date[]}Array of JavaScript Date objects representing all individual dates that are currently selected.
2607*/
2608YAHOO.widget.Calendar.prototype.selectCell = function(cellIndex) {
2609 this.beforeSelectEvent.fire();
2610
2611 var selected = this.cfg.getProperty("selected");
2612
2613 var cell = this.cells[cellIndex];
2614 var cellDate = this.cellDates[cellIndex];
2615
2616 var dCellDate = this._toDate(cellDate);
2617
2618 var selectDate = cellDate.concat();
2619
2620 selected[selected.length] = selectDate;
2621
2622 if (this.parent) {
2623 this.parent.cfg.setProperty("selected", selected);
2624 } else {
2625 this.cfg.setProperty("selected", selected);
2626 }
2627
2628 this.renderCellStyleSelected(dCellDate,cell);
2629
2630 this.selectEvent.fire([selectDate]);
2631
2632 this.doCellMouseOut.call(cell, null, this);
2633
2634 return this.getSelectedDates();
2635};
2636
2637/**
2638* Deselects a date or a collection of dates on the current calendar. This method, by default,
2639* does not call the render method explicitly. Once deselection has completed, render must be
2640* called for the changes to be reflected visually.
2641* @method deselect
2642 * @param {String/Date/Date[]} dateThe date string of dates to deselect in the current calendar. Valid formats are
2643 * individual date(s) (12/24/2005,12/26/2005) or date range(s) (12/24/2005-1/1/2006).
2644 * Multiple comma-delimited dates can also be passed to this method (12/24/2005,12/11/2005-12/13/2005).
2645 * This method can also take a JavaScript Date object or an array of Date objects.
2646 * @return {Date[]} Array of JavaScript Date objects representing all individual dates that are currently selected.
2647*/
2648YAHOO.widget.Calendar.prototype.deselect = function(date) {
2649 this.beforeDeselectEvent.fire();
2650
2651 var selected = this.cfg.getProperty("selected");
2652
2653 var aToBeSelected = this._toFieldArray(date);
2654
2655 for (var a=0;a<aToBeSelected.length;++a) {
2656 var toSelect = aToBeSelected[a]; // For each date item in the list of dates we're trying to select
2657 var index = this._indexOfSelectedFieldArray(toSelect);
2658
2659 if (index != -1) {
2660 selected.splice(index,1);
2661 }
2662 }
2663
2664 if (this.parent) {
2665 this.parent.cfg.setProperty("selected", selected);
2666 } else {
2667 this.cfg.setProperty("selected", selected);
2668 }
2669
2670 this.deselectEvent.fire(aToBeSelected);
2671
2672 return this.getSelectedDates();
2673};
2674
2675/**
2676* Deselects a date on the current calendar by referencing the index of the cell that should be deselected.
2677* This method is used to easily deselect a single cell (usually with a mouse click) without having to do
2678* a full render. The selected style is removed from the cell directly.
2679* @method deselectCell
2680 * @param {Number} cellIndexThe index of the cell to deselect in the current calendar.
2681 * @return {Date[]}Array of JavaScript Date objects representing all individual dates that are currently selected.
2682*/
2683YAHOO.widget.Calendar.prototype.deselectCell = function(i) {
2684 this.beforeDeselectEvent.fire();
2685
2686 var selected = this.cfg.getProperty("selected");
2687
2688 var cell = this.cells[i];
2689 var cellDate = this.cellDates[i];
2690 var cellDateIndex = this._indexOfSelectedFieldArray(cellDate);
2691
2692 var dCellDate = this._toDate(cellDate);
2693
2694 var selectDate = cellDate.concat();
2695
2696 if (cellDateIndex > -1) {
2697 if (this.cfg.getProperty("pagedate").getMonth() == dCellDate.getMonth() &&
2698 this.cfg.getProperty("pagedate").getFullYear() == dCellDate.getFullYear()) {
2699 YAHOO.util.Dom.removeClass(cell, this.Style.CSS_CELL_SELECTED);
2700 }
2701
2702 selected.splice(cellDateIndex, 1);
2703 }
2704
2705
2706 if (this.parent) {
2707 this.parent.cfg.setProperty("selected", selected);
2708 } else {
2709 this.cfg.setProperty("selected", selected);
2710 }
2711
2712 this.deselectEvent.fire(selectDate);
2713 return this.getSelectedDates();
2714};
2715
2716/**
2717* Deselects all dates on the current calendar.
2718* @method deselectAll
2719 * @return {Date[]} Array of JavaScript Date objects representing all individual dates that are currently selected.
2720 * Assuming that this function executes properly, the return value should be an empty array.
2721 * However, the empty array is returned for the sake of being able to check the selection status
2722 * of the calendar.
2723*/
2724YAHOO.widget.Calendar.prototype.deselectAll = function() {
2725 this.beforeDeselectEvent.fire();
2726
2727 var selected = this.cfg.getProperty("selected");
2728 var count = selected.length;
2729 var sel = selected.concat();
2730
2731 if (this.parent) {
2732 this.parent.cfg.setProperty("selected", []);
2733 } else {
2734 this.cfg.setProperty("selected", []);
2735 }
2736
2737 if (count > 0) {
2738 this.deselectEvent.fire(sel);
2739 }
2740
2741 return this.getSelectedDates();
2742};
2743
2744// END SELECTION METHODS
2745
2746// BEGIN TYPE CONVERSION METHODS
2747
2748/**
2749* Converts a date (either a JavaScript Date object, or a date string) to the internal data structure
2750* used to represent dates: [[yyyy,mm,dd],[yyyy,mm,dd]].
2751* @method _toFieldArray
2752* @private
2753 * @param {String/Date/Date[]} dateThe date string of dates to deselect in the current calendar. Valid formats are
2754 * individual date(s) (12/24/2005,12/26/2005) or date range(s) (12/24/2005-1/1/2006).
2755 * Multiple comma-delimited dates can also be passed to this method (12/24/2005,12/11/2005-12/13/2005).
2756 * This method can also take a JavaScript Date object or an array of Date objects.
2757 * @return {Array[](Number[])}Array of date field arrays
2758*/
2759YAHOO.widget.Calendar.prototype._toFieldArray = function(date) {
2760 var returnDate = [];
2761
2762 if (date instanceof Date) {
2763 returnDate = [[date.getFullYear(), date.getMonth()+1, date.getDate()]];
2764 } else if (typeof date == 'string') {
2765 returnDate = this._parseDates(date);
2766 } else if (date instanceof Array) {
2767 for (var i=0;i<date.length;++i) {
2768 var d = date[i];
2769 returnDate[returnDate.length] = [d.getFullYear(),d.getMonth()+1,d.getDate()];
2770 }
2771 }
2772
2773 return returnDate;
2774};
2775
2776/**
2777* Converts a date field array [yyyy,mm,dd] to a JavaScript Date object.
2778* @method _toDate
2779* @private
2780 * @param {Number[]} dateFieldArrayThe date field array to convert to a JavaScript Date.
2781 * @return {Date}JavaScript Date object representing the date field array
2782*/
2783YAHOO.widget.Calendar.prototype._toDate = function(dateFieldArray) {
2784 if (dateFieldArray instanceof Date) {
2785 return dateFieldArray;
2786 } else {
2787 return new Date(dateFieldArray[0],dateFieldArray[1]-1,dateFieldArray[2]);
2788 }
2789};
2790
2791// END TYPE CONVERSION METHODS
2792
2793// BEGIN UTILITY METHODS
2794
2795/**
2796* Converts a date field array [yyyy,mm,dd] to a JavaScript Date object.
2797* @method _fieldArraysAreEqual
2798* @private
2799 * @param {Number[]} array1The first date field array to compare
2800 * @param {Number[]} array2The first date field array to compare
2801 * @return {Boolean}The boolean that represents the equality of the two arrays
2802*/
2803YAHOO.widget.Calendar.prototype._fieldArraysAreEqual = function(array1, array2) {
2804 var match = false;
2805
2806 if (array1[0]==array2[0]&&array1[1]==array2[1]&&array1[2]==array2[2]) {
2807 match=true;
2808 }
2809
2810 return match;
2811};
2812
2813/**
2814* Gets the index of a date field array [yyyy,mm,dd] in the current list of selected dates.
2815 * @method_indexOfSelectedFieldArray
2816* @private
2817 * @param {Number[]} findThe date field array to search for
2818 * @return {Number} The index of the date field array within the collection of selected dates.
2819 * -1 will be returned if the date is not found.
2820*/
2821YAHOO.widget.Calendar.prototype._indexOfSelectedFieldArray = function(find) {
2822 var selected = -1;
2823 var seldates = this.cfg.getProperty("selected");
2824
2825 for (var s=0;s<seldates.length;++s) {
2826 var sArray = seldates[s];
2827 if (find[0]==sArray[0]&&find[1]==sArray[1]&&find[2]==sArray[2]) {
2828 selected = s;
2829 break;
2830 }
2831 }
2832
2833 return selected;
2834};
2835
2836/**
2837* Determines whether a given date is OOM (out of month).
2838 * @methodisDateOOM
2839 * @param {Date} dateThe JavaScript Date object for which to check the OOM status
2840 * @return {Boolean}true if the date is OOM
2841*/
2842YAHOO.widget.Calendar.prototype.isDateOOM = function(date) {
2843 var isOOM = false;
2844 if (date.getMonth() != this.cfg.getProperty("pagedate").getMonth()) {
2845 isOOM = true;
2846 }
2847 return isOOM;
2848};
2849
2850// END UTILITY METHODS
2851
2852// BEGIN EVENT HANDLERS
2853
2854/**
2855* Event executed before a date is selected in the calendar widget.
2856* @deprecated Event handlers for this event should be susbcribed to beforeSelectEvent.
2857*/
2858YAHOO.widget.Calendar.prototype.onBeforeSelect = function() {
2859 if (this.cfg.getProperty("MULTI_SELECT") === false) {
2860 if (this.parent) {
2861 this.parent.callChildFunction("clearAllBodyCellStyles", this.Style.CSS_CELL_SELECTED);
2862 this.parent.deselectAll();
2863 } else {
2864 this.clearAllBodyCellStyles(this.Style.CSS_CELL_SELECTED);
2865 this.deselectAll();
2866 }
2867 }
2868};
2869
2870/**
2871* Event executed when a date is selected in the calendar widget.
2872 * @param {Array} selectedAn array of date field arrays representing which date or dates were selected. Example: [ [2006,8,6],[2006,8,7],[2006,8,8] ]
2873* @deprecated Event handlers for this event should be susbcribed to selectEvent.
2874*/
2875YAHOO.widget.Calendar.prototype.onSelect = function(selected) { };
2876
2877/**
2878* Event executed before a date is deselected in the calendar widget.
2879* @deprecated Event handlers for this event should be susbcribed to beforeDeselectEvent.
2880*/
2881YAHOO.widget.Calendar.prototype.onBeforeDeselect = function() { };
2882
2883/**
2884* Event executed when a date is deselected in the calendar widget.
2885 * @param {Array} selectedAn array of date field arrays representing which date or dates were deselected. Example: [ [2006,8,6],[2006,8,7],[2006,8,8] ]
2886* @deprecated Event handlers for this event should be susbcribed to deselectEvent.
2887*/
2888YAHOO.widget.Calendar.prototype.onDeselect = function(deselected) { };
2889
2890/**
2891* Event executed when the user navigates to a different calendar page.
2892* @deprecated Event handlers for this event should be susbcribed to changePageEvent.
2893*/
2894YAHOO.widget.Calendar.prototype.onChangePage = function() {
2895 this.render();
2896};
2897
2898/**
2899* Event executed when the calendar widget is rendered.
2900* @deprecated Event handlers for this event should be susbcribed to renderEvent.
2901*/
2902YAHOO.widget.Calendar.prototype.onRender = function() { };
2903
2904/**
2905* Event executed when the calendar widget is reset to its original state.
2906* @deprecated Event handlers for this event should be susbcribed to resetEvemt.
2907*/
2908YAHOO.widget.Calendar.prototype.onReset = function() { this.render(); };
2909
2910/**
2911* Event executed when the calendar widget is completely cleared to the current month with no selections.
2912* @deprecated Event handlers for this event should be susbcribed to clearEvent.
2913*/
2914YAHOO.widget.Calendar.prototype.onClear = function() { this.render(); };
2915
2916/**
2917* Validates the calendar widget. This method has no default implementation
2918* and must be extended by subclassing the widget.
2919 * @returnShould return true if the widget validates, and false if
2920* it doesn't.
2921* @type Boolean
2922*/
2923YAHOO.widget.Calendar.prototype.validate = function() { return true; };
2924
2925// END EVENT HANDLERS
2926
2927// BEGIN DATE PARSE METHODS
2928
2929/**
2930* Converts a date string to a date field array
2931* @private
2932 * @param {String} sDate Date string. Valid formats are mm/dd and mm/dd/yyyy.
2933 * @return A date field array representing the string passed to the method
2934* @type Array[](Number[])
2935*/
2936YAHOO.widget.Calendar.prototype._parseDate = function(sDate) {
2937 var aDate = sDate.split(this.Locale.DATE_FIELD_DELIMITER);
2938 var rArray;
2939
2940 if (aDate.length == 2) {
2941 rArray = [aDate[this.Locale.MD_MONTH_POSITION-1],aDate[this.Locale.MD_DAY_POSITION-1]];
2942 rArray.type = YAHOO.widget.Calendar.MONTH_DAY;
2943 } else {
2944 rArray = [aDate[this.Locale.MDY_YEAR_POSITION-1],aDate[this.Locale.MDY_MONTH_POSITION-1],aDate[this.Locale.MDY_DAY_POSITION-1]];
2945 rArray.type = YAHOO.widget.Calendar.DATE;
2946 }
2947
2948 for (var i=0;i<rArray.length;i++) {
2949 rArray[i] = parseInt(rArray[i], 10);
2950 }
2951
2952 return rArray;
2953};
2954
2955/**
2956* Converts a multi or single-date string to an array of date field arrays
2957* @private
2958 * @param {String} sDates Date string with one or more comma-delimited dates. Valid formats are mm/dd, mm/dd/yyyy, mm/dd/yyyy-mm/dd/yyyy
2959 * @return An array of date field arrays
2960* @type Array[](Number[])
2961*/
2962YAHOO.widget.Calendar.prototype._parseDates = function(sDates) {
2963 var aReturn = [];
2964
2965 var aDates = sDates.split(this.Locale.DATE_DELIMITER);
2966
2967 for (var d=0;d<aDates.length;++d) {
2968 var sDate = aDates[d];
2969
2970 if (sDate.indexOf(this.Locale.DATE_RANGE_DELIMITER) != -1) {
2971 // This is a range
2972 var aRange = sDate.split(this.Locale.DATE_RANGE_DELIMITER);
2973
2974 var dateStart = this._parseDate(aRange[0]);
2975 var dateEnd = this._parseDate(aRange[1]);
2976
2977 var fullRange = this._parseRange(dateStart, dateEnd);
2978 aReturn = aReturn.concat(fullRange);
2979 } else {
2980 // This is not a range
2981 var aDate = this._parseDate(sDate);
2982 aReturn.push(aDate);
2983 }
2984 }
2985 return aReturn;
2986};
2987
2988/**
2989* Converts a date range to the full list of included dates
2990* @private
2991 * @param {Number[]} startDateDate field array representing the first date in the range
2992 * @param {Number[]} endDate Date field array representing the last date in the range
2993 * @return An array of date field arrays
2994* @type Array[](Number[])
2995*/
2996YAHOO.widget.Calendar.prototype._parseRange = function(startDate, endDate) {
2997 var dStart = new Date(startDate[0],startDate[1]-1,startDate[2]);
2998 var dCurrent = YAHOO.widget.DateMath.add(new Date(startDate[0],startDate[1]-1,startDate[2]),YAHOO.widget.DateMath.DAY,1);
2999 var dEnd = new Date(endDate[0], endDate[1]-1, endDate[2]);
3000
3001 var results = [];
3002 results.push(startDate);
3003 while (dCurrent.getTime() <= dEnd.getTime()) {
3004 results.push([dCurrent.getFullYear(),dCurrent.getMonth()+1,dCurrent.getDate()]);
3005 dCurrent = YAHOO.widget.DateMath.add(dCurrent,YAHOO.widget.DateMath.DAY,1);
3006 }
3007 return results;
3008};
3009
3010// END DATE PARSE METHODS
3011
3012// BEGIN RENDERER METHODS
3013
3014/**
3015* Resets the render stack of the current calendar to its original pre-render value.
3016*/
3017YAHOO.widget.Calendar.prototype.resetRenderers = function() {
3018 this.renderStack = this._renderStack.concat();
3019};
3020
3021/**
3022* Clears the inner HTML, CSS class and style information from the specified cell.
3023* @method clearElement
3024 * @param {HTMLTableCellElement}The cell to clear
3025*/
3026YAHOO.widget.Calendar.prototype.clearElement = function(cell) {
3027 cell.innerHTML = "&#160;";
3028 cell.className="";
3029};
3030
3031/**
3032* Adds a renderer to the render stack. The function reference passed to this method will be executed
3033* when a date cell matches the conditions specified in the date string for this renderer.
3034* @method addRenderer
3035 * @param {String} sDates A date string to associate with the specified renderer. Valid formats
3036 * include date (12/24/2005), month/day (12/24), and range (12/1/2004-1/1/2005)
3037 * @param {Function} fnRenderThe function executed to render cells that match the render rules for this renderer.
3038*/
3039YAHOO.widget.Calendar.prototype.addRenderer = function(sDates, fnRender) {
3040 var aDates = this._parseDates(sDates);
3041 for (var i=0;i<aDates.length;++i) {
3042 var aDate = aDates[i];
3043
3044 if (aDate.length == 2) { // this is either a range or a month/day combo
3045 if (aDate[0] instanceof Array) { // this is a range
3046 this._addRenderer(YAHOO.widget.Calendar.RANGE,aDate,fnRender);
3047 } else { // this is a month/day combo
3048 this._addRenderer(YAHOO.widget.Calendar.MONTH_DAY,aDate,fnRender);
3049 }
3050 } else if (aDate.length == 3) {
3051 this._addRenderer(YAHOO.widget.Calendar.DATE,aDate,fnRender);
3052 }
3053 }
3054};
3055
3056/**
3057* The private method used for adding cell renderers to the local render stack.
3058* This method is called by other methods that set the renderer type prior to the method call.
3059* @method _addRenderer
3060* @private
3061 * @param {String} type The type string that indicates the type of date renderer being added.
3062 * Values are YAHOO.widget.Calendar.DATE, YAHOO.widget.Calendar.MONTH_DAY, YAHOO.widget.Calendar.WEEKDAY,
3063 * YAHOO.widget.Calendar.RANGE, YAHOO.widget.Calendar.MONTH
3064 * @param {Array} aDates An array of dates used to construct the renderer. The format varies based
3065 * on the renderer type
3066 * @param {Function} fnRenderThe function executed to render cells that match the render rules for this renderer.
3067*/
3068YAHOO.widget.Calendar.prototype._addRenderer = function(type, aDates, fnRender) {
3069 var add = [type,aDates,fnRender];
3070 this.renderStack.unshift(add);
3071 this._renderStack = this.renderStack.concat();
3072};
3073
3074/**
3075* Adds a month to the render stack. The function reference passed to this method will be executed
3076* when a date cell matches the month passed to this method.
3077* @method addMonthRenderer
3078 * @param {Number} month The month (1-12) to associate with this renderer
3079 * @param {Function} fnRenderThe function executed to render cells that match the render rules for this renderer.
3080*/
3081YAHOO.widget.Calendar.prototype.addMonthRenderer = function(month, fnRender) {
3082 this._addRenderer(YAHOO.widget.Calendar.MONTH,[month],fnRender);
3083};
3084
3085/**
3086* Adds a weekday to the render stack. The function reference passed to this method will be executed
3087* when a date cell matches the weekday passed to this method.
3088* @method addWeekdayRenderer
3089 * @param {Number} weekday The weekday (0-6) to associate with this renderer
3090 * @param {Function} fnRenderThe function executed to render cells that match the render rules for this renderer.
3091*/
3092YAHOO.widget.Calendar.prototype.addWeekdayRenderer = function(weekday, fnRender) {
3093 this._addRenderer(YAHOO.widget.Calendar.WEEKDAY,[weekday],fnRender);
3094};
3095
3096// END RENDERER METHODS
3097
3098// BEGIN CSS METHODS
3099
3100/**
3101* Removes all styles from all body cells in the current calendar table.
3102* @method clearAllBodyCellStyles
3103 * @param {style} The CSS class name to remove from all calendar body cells
3104*/
3105YAHOO.widget.Calendar.prototype.clearAllBodyCellStyles = function(style) {
3106 for (var c=0;c<this.cells.length;++c) {
3107 YAHOO.util.Dom.removeClass(this.cells[c],style);
3108 }
3109};
3110
3111// END CSS METHODS
3112
3113// BEGIN GETTER/SETTER METHODS
3114/**
3115* Sets the calendar's month explicitly
3116* @method setMonth
3117 * @param {Number} month The numeric month, from 0 (January) to 11 (December)
3118*/
3119YAHOO.widget.Calendar.prototype.setMonth = function(month) {
3120 var current = this.cfg.getProperty("pagedate");
3121 current.setMonth(month);
3122 this.cfg.setProperty("pagedate", current);
3123};
3124
3125/**
3126* Sets the calendar's year explicitly.
3127* @method setYear
3128 * @param {Number} year The numeric 4-digit year
3129*/
3130YAHOO.widget.Calendar.prototype.setYear = function(year) {
3131 var current = this.cfg.getProperty("pagedate");
3132 current.setFullYear(year);
3133 this.cfg.setProperty("pagedate", current);
3134};
3135
3136/**
3137* Gets the list of currently selected dates from the calendar.
3138* @method getSelectedDates
3139* @return {Date[]} An array of currently selected JavaScript Date objects.
3140*/
3141YAHOO.widget.Calendar.prototype.getSelectedDates = function() {
3142 var returnDates = [];
3143 var selected = this.cfg.getProperty("selected");
3144
3145 for (var d=0;d<selected.length;++d) {
3146 var dateArray = selected[d];
3147
3148 var date = new Date(dateArray[0],dateArray[1]-1,dateArray[2]);
3149 returnDates.push(date);
3150 }
3151
3152 returnDates.sort( function(a,b) { return a-b; } );
3153 return returnDates;
3154};
3155
3156/// END GETTER/SETTER METHODS ///
3157
3158/**
3159* Hides the Calendar's outer container from view.
3160* @method hide
3161*/
3162YAHOO.widget.Calendar.prototype.hide = function() {
3163 this.oDomContainer.style.display = "none";
3164};
3165
3166/**
3167* Shows the Calendar's outer container.
3168* @method show
3169*/
3170YAHOO.widget.Calendar.prototype.show = function() {
3171 this.oDomContainer.style.display = "block";
3172};
3173
3174/**
3175* Returns a string representing the current browser.
3176* @property browser
3177* @type String
3178*/
3179YAHOO.widget.Calendar.prototype.browser = function() {
3180 var ua = navigator.userAgent.toLowerCase();
3181 if (ua.indexOf('opera')!=-1) { // Opera (check first in case of spoof)
3182 return 'opera';
3183 } else if (ua.indexOf('msie 7')!=-1) { // IE7
3184 return 'ie7';
3185 } else if (ua.indexOf('msie') !=-1) { // IE
3186 return 'ie';
3187 } else if (ua.indexOf('safari')!=-1) { // Safari (check before Gecko because it includes "like Gecko")
3188 return 'safari';
3189 } else if (ua.indexOf('gecko') != -1) { // Gecko
3190 return 'gecko';
3191 } else {
3192 return false;
3193 }
3194 }();
3195/**
3196* Returns a string representation of the object.
3197* @method toString
3198 * @return {String}A string representation of the Calendar object.
3199*/
3200YAHOO.widget.Calendar.prototype.toString = function() {
3201 return "Calendar " + this.id;
3202};
3203
3204/**
3205* @namespace YAHOO.widget
3206* @class Calendar_Core
3207* @extends YAHOO.widget.Calendar
3208* @deprecated The old Calendar_Core class is no longer necessary.
3209*/
3210YAHOO.widget.Calendar_Core = YAHOO.widget.Calendar;
3211
3212YAHOO.widget.Cal_Core = YAHOO.widget.Calendar;
3213
3214/**
3215* YAHOO.widget.CalendarGroup is a special container class for YAHOO.widget.Calendar. This class facilitates
3216* the ability to have multi-page calendar views that share a single dataset and are
3217* dependent on each other.
3218*
3219* The calendar group instance will refer to each of its elements using a 0-based index.
3220* For example, to construct the placeholder for a calendar group widget with id "cal1" and
3221* containerId of "cal1Container", the markup would be as follows:
3222 *<xmp>
3223 * <div id="cal1Container_0"></div>
3224 * <div id="cal1Container_1"></div>
3225 *</xmp>
3226* The tables for the calendars ("cal1_0" and "cal1_1") will be inserted into those containers.
3227* @namespace YAHOO.widget
3228* @class CalendarGroup
3229* @constructor
3230 * @param {String} id The id of the table element that will represent the calendar widget
3231 * @param {String} containerIdThe id of the container div element that will wrap the calendar table
3232 * @param {Object} config The configuration object containing the Calendar's arguments
3233*/
3234YAHOO.widget.CalendarGroup = function(id, containerId, config) {
3235 if (arguments.length > 0) {
3236 this.init(id, containerId, config);
3237 }
3238};
3239
3240/**
3241* Initializes the calendar group. All subclasses must call this method in order for the
3242* group to be initialized properly.
3243* @method init
3244 * @param {String} id The id of the table element that will represent the calendar widget
3245 * @param {String} containerIdThe id of the container div element that will wrap the calendar table
3246 * @param {Object} config The configuration object containing the Calendar's arguments
3247*/
3248YAHOO.widget.CalendarGroup.prototype.init = function(id, containerId, config) {
3249 this.initEvents();
3250 this.initStyles();
3251
3252 /**
3253 * The collection of Calendar pages contained within the CalendarGroup
3254 * @property pages
3255 * @type YAHOO.widget.Calendar[]
3256 */
3257 this.pages = [];
3258
3259 /**
3260 * The unique id associated with the CalendarGroup
3261 * @property id
3262 * @type String
3263 */
3264 this.id = id;
3265
3266 /**
3267 * The unique id associated with the CalendarGroup container
3268 * @property containerId
3269 * @type String
3270 */
3271 this.containerId = containerId;
3272
3273 /**
3274 * The outer containing element for the CalendarGroup
3275 * @property oDomContainer
3276 * @type HTMLElement
3277 */
3278 this.oDomContainer = document.getElementById(containerId);
3279
3280 YAHOO.util.Dom.addClass(this.oDomContainer, YAHOO.widget.CalendarGroup.CSS_CONTAINER);
3281 YAHOO.util.Dom.addClass(this.oDomContainer, YAHOO.widget.CalendarGroup.CSS_MULTI_UP);
3282
3283 /**
3284 * The Config object used to hold the configuration variables for the CalendarGroup
3285 * @property cfg
3286 * @type YAHOO.util.Config
3287 */
3288 this.cfg = new YAHOO.util.Config(this);
3289
3290 /**
3291 * The local object which contains the CalendarGroup's options
3292 * @property Options
3293 * @type Object
3294 */
3295 this.Options = {};
3296
3297 /**
3298 * The local object which contains the CalendarGroup's locale settings
3299 * @property Locale
3300 * @type Object
3301 */
3302 this.Locale = {};
3303
3304 this.setupConfig();
3305
3306 if (config) {
3307 this.cfg.applyConfig(config, true);
3308 }
3309
3310 this.cfg.fireQueue();
3311
3312 // OPERA HACK FOR MISWRAPPED FLOATS
3313 if (this.browser == "opera"){
3314 var fixWidth = function() {
3315 var startW = this.oDomContainer.offsetWidth;
3316 var w = 0;
3317 for (var p=0;p<this.pages.length;++p) {
3318 var cal = this.pages[p];
3319 w += cal.oDomContainer.offsetWidth;
3320 }
3321 if (w > 0) {
3322 this.oDomContainer.style.width = w + "px";
3323 }
3324 };
3325 this.renderEvent.subscribe(fixWidth,this,true);
3326 }
3327};
3328
3329
3330YAHOO.widget.CalendarGroup.prototype.setupConfig = function() {
3331 /**
3332 * The number of pages to include in the CalendarGroup. This value can only be set once, in the CalendarGroup's constructor arguments.
3333 * @config pages
3334 * @type Number
3335 * @default 2
3336 */
3337 this.cfg.addProperty("pages", { value:2, validator:this.cfg.checkNumber, handler:this.configPages } );
3338
3339 /**
3340 * The month/year representing the current visible Calendar date (mm/yyyy)
3341 * @config pagedate
3342 * @type String
3343 * @default today's date
3344 */
3345 this.cfg.addProperty("pagedate", { value:new Date(), handler:this.configPageDate } );
3346
3347 /**
3348 * The date or range of dates representing the current Calendar selection
3349 * @config selected
3350 * @type String
3351 * @default []
3352 */
3353 this.cfg.addProperty("selected", { value:[], handler:this.delegateConfig } );
3354
3355 /**
3356 * The title to display above the CalendarGroup's month header
3357 * @config title
3358 * @type String
3359 * @default ""
3360 */
3361 this.cfg.addProperty("title", { value:"", handler:this.configTitle } );
3362
3363 /**
3364 * Whether or not a close button should be displayed for this CalendarGroup
3365 * @config close
3366 * @type Boolean
3367 * @default false
3368 */
3369 this.cfg.addProperty("close", { value:false, handler:this.configClose } );
3370
3371 /**
3372 * Whether or not an iframe shim should be placed under the Calendar to prevent select boxes from bleeding through in Internet Explorer 6 and below.
3373 * @config iframe
3374 * @type Boolean
3375 * @default true
3376 */
3377 this.cfg.addProperty("iframe", { value:true, handler:this.delegateConfig, validator:this.cfg.checkBoolean } );
3378
3379 /**
3380 * The minimum selectable date in the current Calendar (mm/dd/yyyy)
3381 * @config mindate
3382 * @type String
3383 * @default null
3384 */
3385 this.cfg.addProperty("mindate", { value:null, handler:this.delegateConfig } );
3386
3387 /**
3388 * The maximum selectable date in the current Calendar (mm/dd/yyyy)
3389 * @config maxdate
3390 * @type String
3391 * @default null
3392 */
3393 this.cfg.addProperty("maxdate", { value:null, handler:this.delegateConfig } );
3394
3395 // Options properties
3396
3397 /**
3398 * True if the Calendar should allow multiple selections. False by default.
3399 * @config MULTI_SELECT
3400 * @type Boolean
3401 * @default false
3402 */
3403 this.cfg.addProperty("MULTI_SELECT",{ value:false, handler:this.delegateConfig, validator:this.cfg.checkBoolean } );
3404
3405 /**
3406 * The weekday the week begins on. Default is 0 (Sunday).
3407 * @config START_WEEKDAY
3408 * @type number
3409 * @default 0
3410 */
3411 this.cfg.addProperty("START_WEEKDAY",{ value:0, handler:this.delegateConfig, validator:this.cfg.checkNumber } );
3412
3413 /**
3414 * True if the Calendar should show weekday labels. True by default.
3415 * @config SHOW_WEEKDAYS
3416 * @type Boolean
3417 * @default true
3418 */
3419 this.cfg.addProperty("SHOW_WEEKDAYS",{ value:true, handler:this.delegateConfig, validator:this.cfg.checkBoolean } );
3420
3421 /**
3422 * True if the Calendar should show week row headers. False by default.
3423 * @config SHOW_WEEK_HEADER
3424 * @type Boolean
3425 * @default false
3426 */
3427 this.cfg.addProperty("SHOW_WEEK_HEADER",{ value:false, handler:this.delegateConfig, validator:this.cfg.checkBoolean } );
3428
3429 /**
3430 * True if the Calendar should show week row footers. False by default.
3431 * @config SHOW_WEEK_FOOTER
3432 * @type Boolean
3433 * @default false
3434 */
3435 this.cfg.addProperty("SHOW_WEEK_FOOTER",{ value:false, handler:this.delegateConfig, validator:this.cfg.checkBoolean } );
3436
3437 /**
3438 * True if the Calendar should suppress weeks that are not a part of the current month. False by default.
3439 * @config HIDE_BLANK_WEEKS
3440 * @type Boolean
3441 * @default false
3442 */
3443 this.cfg.addProperty("HIDE_BLANK_WEEKS",{ value:false, handler:this.delegateConfig, validator:this.cfg.checkBoolean } );
3444
3445 /**
3446 * The image that should be used for the left navigation arrow.
3447 * @config NAV_ARROW_LEFT
3448 * @type String
3449 * @default YAHOO.widget.Calendar.IMG_ROOT + "us/tr/callt.gif"
3450 */
3451 this.cfg.addProperty("NAV_ARROW_LEFT",{ value:YAHOO.widget.Calendar.IMG_ROOT + "us/tr/callt.gif", handler:this.delegateConfig } );
3452
3453 /**
3454 * The image that should be used for the left navigation arrow.
3455 * @config NAV_ARROW_RIGHT
3456 * @type String
3457 * @default YAHOO.widget.Calendar.IMG_ROOT + "us/tr/calrt.gif"
3458 */
3459 this.cfg.addProperty("NAV_ARROW_RIGHT",{ value:YAHOO.widget.Calendar.IMG_ROOT + "us/tr/calrt.gif", handler:this.delegateConfig } );
3460
3461 // Locale properties
3462
3463 /**
3464 * The short month labels for the current locale.
3465 * @config MONTHS_SHORT
3466 * @type String[]
3467 * @default ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
3468 */
3469 this.cfg.addProperty("MONTHS_SHORT",{ value:["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"], handler:this.delegateConfig } );
3470
3471 /**
3472 * The long month labels for the current locale.
3473 * @config MONTHS_LONG
3474 * @type String[]
3475 * @default ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"
3476 */
3477 this.cfg.addProperty("MONTHS_LONG", { value:["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"], handler:this.delegateConfig } );
3478
3479 /**
3480 * The 1-character weekday labels for the current locale.
3481 * @config WEEKDAYS_1CHAR
3482 * @type String[]
3483 * @default ["S", "M", "T", "W", "T", "F", "S"]
3484 */
3485 this.cfg.addProperty("WEEKDAYS_1CHAR",{ value:["S", "M", "T", "W", "T", "F", "S"], handler:this.delegateConfig } );
3486
3487 /**
3488 * The short weekday labels for the current locale.
3489 * @config WEEKDAYS_SHORT
3490 * @type String[]
3491 * @default ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"]
3492 */
3493 this.cfg.addProperty("WEEKDAYS_SHORT",{ value:["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"], handler:this.delegateConfig } );
3494
3495 /**
3496 * The medium weekday labels for the current locale.
3497 * @config WEEKDAYS_MEDIUM
3498 * @type String[]
3499 * @default ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"]
3500 */
3501 this.cfg.addProperty("WEEKDAYS_MEDIUM",{ value:["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"], handler:this.delegateConfig } );
3502
3503 /**
3504 * The long weekday labels for the current locale.
3505 * @config WEEKDAYS_LONG
3506 * @type String[]
3507 * @default ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"]
3508 */
3509 this.cfg.addProperty("WEEKDAYS_LONG",{ value:["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"], handler:this.delegateConfig } );
3510
3511 /**
3512 * The setting that determines which length of month labels should be used. Possible values are "short" and "long".
3513 * @config LOCALE_MONTHS
3514 * @type String
3515 * @default "long"
3516 */
3517 this.cfg.addProperty("LOCALE_MONTHS",{ value:"long", handler:this.delegateConfig } );
3518
3519 /**
3520 * The setting that determines which length of weekday labels should be used. Possible values are "1char", "short", "medium", and "long".
3521 * @config LOCALE_WEEKDAYS
3522 * @type String
3523 * @default "short"
3524 */
3525 this.cfg.addProperty("LOCALE_WEEKDAYS",{ value:"short", handler:this.delegateConfig } );
3526
3527 /**
3528 * The value used to delimit individual dates in a date string passed to various Calendar functions.
3529 * @config DATE_DELIMITER
3530 * @type String
3531 * @default ","
3532 */
3533 this.cfg.addProperty("DATE_DELIMITER", { value:",", handler:this.delegateConfig } );
3534
3535 /**
3536 * The value used to delimit date fields in a date string passed to various Calendar functions.
3537 * @config DATE_FIELD_DELIMITER
3538 * @type String
3539 * @default "/"
3540 */
3541 this.cfg.addProperty("DATE_FIELD_DELIMITER",{ value:"/", handler:this.delegateConfig } );
3542
3543 /**
3544 * The value used to delimit date ranges in a date string passed to various Calendar functions.
3545 * @config DATE_RANGE_DELIMITER
3546 * @type String
3547 * @default "-"
3548 */
3549 this.cfg.addProperty("DATE_RANGE_DELIMITER",{ value:"-", handler:this.delegateConfig } );
3550
3551 /**
3552 * The position of the month in a month/year date string
3553 * @config MY_MONTH_POSITION
3554 * @type Number
3555 * @default 1
3556 */
3557 this.cfg.addProperty("MY_MONTH_POSITION",{ value:1, handler:this.delegateConfig, validator:this.cfg.checkNumber } );
3558
3559 /**
3560 * The position of the year in a month/year date string
3561 * @config MY_YEAR_POSITION
3562 * @type Number
3563 * @default 2
3564 */
3565 this.cfg.addProperty("MY_YEAR_POSITION",{ value:2, handler:this.delegateConfig, validator:this.cfg.checkNumber } );
3566
3567 /**
3568 * The position of the month in a month/day date string
3569 * @config MD_MONTH_POSITION
3570 * @type Number
3571 * @default 1
3572 */
3573 this.cfg.addProperty("MD_MONTH_POSITION",{ value:1, handler:this.delegateConfig, validator:this.cfg.checkNumber } );
3574
3575 /**
3576 * The position of the day in a month/year date string
3577 * @config MD_DAY_POSITION
3578 * @type Number
3579 * @default 2
3580 */
3581 this.cfg.addProperty("MD_DAY_POSITION", { value:2, handler:this.delegateConfig, validator:this.cfg.checkNumber } );
3582
3583 /**
3584 * The position of the month in a month/day/year date string
3585 * @config MDY_MONTH_POSITION
3586 * @type Number
3587 * @default 1
3588 */
3589 this.cfg.addProperty("MDY_MONTH_POSITION",{ value:1, handler:this.delegateConfig, validator:this.cfg.checkNumber } );
3590
3591 /**
3592 * The position of the day in a month/day/year date string
3593 * @config MDY_DAY_POSITION
3594 * @type Number
3595 * @default 2
3596 */
3597 this.cfg.addProperty("MDY_DAY_POSITION",{ value:2, handler:this.delegateConfig, validator:this.cfg.checkNumber } );
3598
3599 /**
3600 * The position of the year in a month/day/year date string
3601 * @config MDY_YEAR_POSITION
3602 * @type Number
3603 * @default 3
3604 */
3605 this.cfg.addProperty("MDY_YEAR_POSITION",{ value:3, handler:this.delegateConfig, validator:this.cfg.checkNumber } );
3606
3607};
3608
3609/**
3610* Initializes CalendarGroup's built-in CustomEvents
3611* @method initEvents
3612*/
3613YAHOO.widget.CalendarGroup.prototype.initEvents = function() {
3614 var me = this;
3615
3616 /**
3617 * Proxy subscriber to subscribe to the CalendarGroup's child Calendars' CustomEvents
3618 * @method sub
3619 * @private
3620 * @param {Function} fnThe function to subscribe to this CustomEvent
3621 * @param {Object} objThe CustomEvent's scope object
3622 * @param {Boolean} bOverrideWhether or not to apply scope correction
3623 */
3624 var sub = function(fn, obj, bOverride) {
3625 for (var p=0;p<me.pages.length;++p) {
3626 var cal = me.pages[p];
3627 cal[this.type + "Event"].subscribe(fn, obj, bOverride);
3628 }
3629 };
3630
3631 /**
3632 * Proxy unsubscriber to unsubscribe from the CalendarGroup's child Calendars' CustomEvents
3633 * @method unsub
3634 * @private
3635 * @param {Function} fnThe function to subscribe to this CustomEvent
3636 * @param {Object} objThe CustomEvent's scope object
3637 */
3638 var unsub = function(fn, obj) {
3639 for (var p=0;p<me.pages.length;++p) {
3640 var cal = me.pages[p];
3641 cal[this.type + "Event"].unsubscribe(fn, obj);
3642 }
3643 };
3644
3645 /**
3646 * Fired before a selection is made
3647 * @event beforeSelectEvent
3648 */
3649 this.beforeSelectEvent = new YAHOO.util.CustomEvent("beforeSelect");
3650 this.beforeSelectEvent.subscribe = sub; this.beforeSelectEvent.unsubscribe = unsub;
3651
3652 /**
3653 * Fired when a selection is made
3654 * @event selectEvent
3655 * @param {Array}Array of Date field arrays in the format [YYYY, MM, DD].
3656 */
3657 this.selectEvent = new YAHOO.util.CustomEvent("select");
3658 this.selectEvent.subscribe = sub; this.selectEvent.unsubscribe = unsub;
3659
3660 /**
3661 * Fired before a selection is made
3662 * @event beforeDeselectEvent
3663 */
3664 this.beforeDeselectEvent = new YAHOO.util.CustomEvent("beforeDeselect");
3665 this.beforeDeselectEvent.subscribe = sub; this.beforeDeselectEvent.unsubscribe = unsub;
3666
3667 /**
3668 * Fired when a selection is made
3669 * @event deselectEvent
3670 * @param {Array}Array of Date field arrays in the format [YYYY, MM, DD].
3671 */
3672 this.deselectEvent = new YAHOO.util.CustomEvent("deselect");
3673 this.deselectEvent.subscribe = sub; this.deselectEvent.unsubscribe = unsub;
3674
3675 /**
3676 * Fired when the Calendar page is changed
3677 * @event changePageEvent
3678 */
3679 this.changePageEvent = new YAHOO.util.CustomEvent("changePage");
3680 this.changePageEvent.subscribe = sub; this.changePageEvent.unsubscribe = unsub;
3681
3682 /**
3683 * Fired before the Calendar is rendered
3684 * @event beforeRenderEvent
3685 */
3686 this.beforeRenderEvent = new YAHOO.util.CustomEvent("beforeRender");
3687 this.beforeRenderEvent.subscribe = sub; this.beforeRenderEvent.unsubscribe = unsub;
3688
3689 /**
3690 * Fired when the Calendar is rendered
3691 * @event renderEvent
3692 */
3693 this.renderEvent = new YAHOO.util.CustomEvent("render");
3694 this.renderEvent.subscribe = sub; this.renderEvent.unsubscribe = unsub;
3695
3696 /**
3697 * Fired when the Calendar is reset
3698 * @event resetEvent
3699 */
3700 this.resetEvent = new YAHOO.util.CustomEvent("reset");
3701 this.resetEvent.subscribe = sub; this.resetEvent.unsubscribe = unsub;
3702
3703 /**
3704 * Fired when the Calendar is cleared
3705 * @event clearEvent
3706 */
3707 this.clearEvent = new YAHOO.util.CustomEvent("clear");
3708 this.clearEvent.subscribe = sub; this.clearEvent.unsubscribe = unsub;
3709
3710};
3711
3712/**
3713* The default Config handler for the "pages" property
3714* @method configPages
3715 * @param {String} typeThe CustomEvent type (usually the property name)
3716 * @param {Object[]} argsThe CustomEvent arguments. For configuration handlers, args[0] will equal the newly applied value for the property.
3717 * @param {Object} objThe scope object. For configuration handlers, this will usually equal the owner.
3718*/
3719YAHOO.widget.CalendarGroup.prototype.configPages = function(type, args, obj) {
3720 var pageCount = args[0];
3721
3722 for (var p=0;p<pageCount;++p) {
3723 var calId = this.id + "_" + p;
3724 var calContainerId = this.containerId + "_" + p;
3725
3726 var childConfig = this.cfg.getConfig();
3727 childConfig.close = false;
3728 childConfig.title = false;
3729
3730 var cal = this.constructChild(calId, calContainerId, childConfig);
3731 var caldate = cal.cfg.getProperty("pagedate");
3732 caldate.setMonth(caldate.getMonth()+p);
3733 cal.cfg.setProperty("pagedate", caldate);
3734
3735 YAHOO.util.Dom.removeClass(cal.oDomContainer, this.Style.CSS_SINGLE);
3736 YAHOO.util.Dom.addClass(cal.oDomContainer, "groupcal");
3737
3738 if (p===0) {
3739 YAHOO.util.Dom.addClass(cal.oDomContainer, "first");
3740 }
3741
3742 if (p==(pageCount-1)) {
3743 YAHOO.util.Dom.addClass(cal.oDomContainer, "last");
3744 }
3745
3746 cal.parent = this;
3747 cal.index = p;
3748
3749 this.pages[this.pages.length] = cal;
3750 }
3751};
3752
3753/**
3754* The default Config handler for the "pagedate" property
3755* @method configPageDate
3756 * @param {String} typeThe CustomEvent type (usually the property name)
3757 * @param {Object[]} argsThe CustomEvent arguments. For configuration handlers, args[0] will equal the newly applied value for the property.
3758 * @param {Object} objThe scope object. For configuration handlers, this will usually equal the owner.
3759*/
3760YAHOO.widget.CalendarGroup.prototype.configPageDate = function(type, args, obj) {
3761 var val = args[0];
3762
3763 for (var p=0;p<this.pages.length;++p) {
3764 var cal = this.pages[p];
3765 cal.cfg.setProperty("pagedate", val);
3766 var calDate = cal.cfg.getProperty("pagedate");
3767 calDate.setMonth(calDate.getMonth()+p);
3768 }
3769};
3770
3771/**
3772* Delegates a configuration property to the CustomEvents associated with the CalendarGroup's children
3773* @method delegateConfig
3774 * @param {String} typeThe CustomEvent type (usually the property name)
3775 * @param {Object[]} argsThe CustomEvent arguments. For configuration handlers, args[0] will equal the newly applied value for the property.
3776 * @param {Object} objThe scope object. For configuration handlers, this will usually equal the owner.
3777*/
3778YAHOO.widget.CalendarGroup.prototype.delegateConfig = function(type, args, obj) {
3779 var val = args[0];
3780 var cal;
3781
3782 for (var p=0;p<this.pages.length;p++) {
3783 cal = this.pages[p];
3784 cal.cfg.setProperty(type, val);
3785 }
3786};
3787
3788
3789/**
3790* Adds a function to all child Calendars within this CalendarGroup.
3791* @method setChildFunction
3792 * @param {String} fnName The name of the function
3793 * @param {Function} fn The function to apply to each Calendar page object
3794*/
3795YAHOO.widget.CalendarGroup.prototype.setChildFunction = function(fnName, fn) {
3796 var pageCount = this.cfg.getProperty("pages");
3797
3798 for (var p=0;p<pageCount;++p) {
3799 this.pages[p][fnName] = fn;
3800 }
3801};
3802
3803/**
3804* Calls a function within all child Calendars within this CalendarGroup.
3805* @method callChildFunction
3806 * @param {String} fnName The name of the function
3807 * @param {Array} args The arguments to pass to the function
3808*/
3809YAHOO.widget.CalendarGroup.prototype.callChildFunction = function(fnName, args) {
3810 var pageCount = this.cfg.getProperty("pages");
3811
3812 for (var p=0;p<pageCount;++p) {
3813 var page = this.pages[p];
3814 if (page[fnName]) {
3815 var fn = page[fnName];
3816 fn.call(page, args);
3817 }
3818 }
3819};
3820
3821/**
3822* Constructs a child calendar. This method can be overridden if a subclassed version of the default
3823* calendar is to be used.
3824* @method constructChild
3825 * @param {String} id The id of the table element that will represent the calendar widget
3826 * @param {String} containerIdThe id of the container div element that will wrap the calendar table
3827 * @param {Object} config The configuration object containing the Calendar's arguments
3828 * @return {YAHOO.widget.Calendar}The YAHOO.widget.Calendar instance that is constructed
3829*/
3830YAHOO.widget.CalendarGroup.prototype.constructChild = function(id,containerId,config) {
3831 var container = document.getElementById(containerId);
3832 if (! container) {
3833 container = document.createElement("div");
3834 container.id = containerId;
3835 this.oDomContainer.appendChild(container);
3836 }
3837 return new YAHOO.widget.Calendar(id,containerId,config);
3838};
3839
3840
3841/**
3842* Sets the calendar group's month explicitly. This month will be set into the first
3843* @method setMonth
3844* page of the multi-page calendar, and all other months will be iterated appropriately.
3845 * @param {Number} month The numeric month, from 0 (January) to 11 (December)
3846*/
3847YAHOO.widget.CalendarGroup.prototype.setMonth = function(month) {
3848 for (var p=0;p<this.pages.length;++p) {
3849 var cal = this.pages[p];
3850 cal.setMonth(month+p);
3851 }
3852};
3853
3854/**
3855* Sets the calendar group's year explicitly. This year will be set into the first
3856* @method setYear
3857* page of the multi-page calendar, and all other months will be iterated appropriately.
3858 * @param {Number} year The numeric 4-digit year
3859*/
3860YAHOO.widget.CalendarGroup.prototype.setYear = function(year) {
3861 for (var p=0;p<this.pages.length;++p) {
3862 var cal = this.pages[p];
3863 var pageDate = cal.cfg.getProperty("pageDate");
3864
3865 if ((pageDate.getMonth()+1) == 1 && p>0) {
3866 year+=1;
3867 }
3868 cal.setYear(year);
3869 }
3870};
3871/**
3872* Calls the render function of all child calendars within the group.
3873* @method render
3874*/
3875YAHOO.widget.CalendarGroup.prototype.render = function() {
3876 this.renderHeader();
3877 for (var p=0;p<this.pages.length;++p) {
3878 var cal = this.pages[p];
3879 cal.render();
3880 }
3881 this.renderFooter();
3882};
3883
3884/**
3885* Selects a date or a collection of dates on the current calendar. This method, by default,
3886* does not call the render method explicitly. Once selection has completed, render must be
3887* called for the changes to be reflected visually.
3888* @method select
3889 * @param {String/Date/Date[]} dateThe date string of dates to select in the current calendar. Valid formats are
3890 * individual date(s) (12/24/2005,12/26/2005) or date range(s) (12/24/2005-1/1/2006).
3891 * Multiple comma-delimited dates can also be passed to this method (12/24/2005,12/11/2005-12/13/2005).
3892 * This method can also take a JavaScript Date object or an array of Date objects.
3893 * @return {Date[]} Array of JavaScript Date objects representing all individual dates that are currently selected.
3894*/
3895YAHOO.widget.CalendarGroup.prototype.select = function(date) {
3896 for (var p=0;p<this.pages.length;++p) {
3897 var cal = this.pages[p];
3898 cal.select(date);
3899 }
3900 return this.getSelectedDates();
3901};
3902
3903/**
3904* Selects a date on the current calendar by referencing the index of the cell that should be selected.
3905* This method is used to easily select a single cell (usually with a mouse click) without having to do
3906* a full render. The selected style is applied to the cell directly.
3907* @method selectCell
3908 * @param {Number} cellIndexThe index of the cell to select in the current calendar.
3909 * @return {Date[]}Array of JavaScript Date objects representing all individual dates that are currently selected.
3910*/
3911YAHOO.widget.CalendarGroup.prototype.selectCell = function(cellIndex) {
3912 for (var p=0;p<this.pages.length;++p) {
3913 var cal = this.pages[p];
3914 cal.selectCell(cellIndex);
3915 }
3916 return this.getSelectedDates();
3917};
3918
3919/**
3920* Deselects a date or a collection of dates on the current calendar. This method, by default,
3921* does not call the render method explicitly. Once deselection has completed, render must be
3922* called for the changes to be reflected visually.
3923* @method deselect
3924 * @param {String/Date/Date[]} dateThe date string of dates to deselect in the current calendar. Valid formats are
3925 * individual date(s) (12/24/2005,12/26/2005) or date range(s) (12/24/2005-1/1/2006).
3926 * Multiple comma-delimited dates can also be passed to this method (12/24/2005,12/11/2005-12/13/2005).
3927 * This method can also take a JavaScript Date object or an array of Date objects.
3928 * @return {Date[]} Array of JavaScript Date objects representing all individual dates that are currently selected.
3929*/
3930YAHOO.widget.CalendarGroup.prototype.deselect = function(date) {
3931 for (var p=0;p<this.pages.length;++p) {
3932 var cal = this.pages[p];
3933 cal.deselect(date);
3934 }
3935 return this.getSelectedDates();
3936};
3937
3938/**
3939* Deselects all dates on the current calendar.
3940* @method deselectAll
3941 * @return {Date[]} Array of JavaScript Date objects representing all individual dates that are currently selected.
3942 * Assuming that this function executes properly, the return value should be an empty array.
3943 * However, the empty array is returned for the sake of being able to check the selection status
3944 * of the calendar.
3945*/
3946YAHOO.widget.CalendarGroup.prototype.deselectAll = function() {
3947 for (var p=0;p<this.pages.length;++p) {
3948 var cal = this.pages[p];
3949 cal.deselectAll();
3950 }
3951 return this.getSelectedDates();
3952};
3953
3954/**
3955* Deselects a date on the current calendar by referencing the index of the cell that should be deselected.
3956* This method is used to easily deselect a single cell (usually with a mouse click) without having to do
3957* a full render. The selected style is removed from the cell directly.
3958* @method deselectCell
3959 * @param {Number} cellIndexThe index of the cell to deselect in the current calendar.
3960 * @return {Date[]}Array of JavaScript Date objects representing all individual dates that are currently selected.
3961*/
3962YAHOO.widget.CalendarGroup.prototype.deselectCell = function(cellIndex) {
3963 for (var p=0;p<this.pages.length;++p) {
3964 var cal = this.pages[p];
3965 cal.deselectCell(cellIndex);
3966 }
3967 return this.getSelectedDates();
3968};
3969
3970/**
3971* Resets the calendar widget to the originally selected month and year, and
3972* sets the calendar to the initial selection(s).
3973* @method reset
3974*/
3975YAHOO.widget.CalendarGroup.prototype.reset = function() {
3976 for (var p=0;p<this.pages.length;++p) {
3977 var cal = this.pages[p];
3978 cal.reset();
3979 }
3980};
3981
3982/**
3983* Clears the selected dates in the current calendar widget and sets the calendar
3984* to the current month and year.
3985* @method clear
3986*/
3987YAHOO.widget.CalendarGroup.prototype.clear = function() {
3988 for (var p=0;p<this.pages.length;++p) {
3989 var cal = this.pages[p];
3990 cal.clear();
3991 }
3992};
3993
3994/**
3995* Navigates to the next month page in the calendar widget.
3996* @method nextMonth
3997*/
3998YAHOO.widget.CalendarGroup.prototype.nextMonth = function() {
3999 for (var p=0;p<this.pages.length;++p) {
4000 var cal = this.pages[p];
4001 cal.nextMonth();
4002 }
4003};
4004
4005/**
4006* Navigates to the previous month page in the calendar widget.
4007* @method previousMonth
4008*/
4009YAHOO.widget.CalendarGroup.prototype.previousMonth = function() {
4010 for (var p=this.pages.length-1;p>=0;--p) {
4011 var cal = this.pages[p];
4012 cal.previousMonth();
4013 }
4014};
4015
4016/**
4017* Navigates to the next year in the currently selected month in the calendar widget.
4018* @method nextYear
4019*/
4020YAHOO.widget.CalendarGroup.prototype.nextYear = function() {
4021 for (var p=0;p<this.pages.length;++p) {
4022 var cal = this.pages[p];
4023 cal.nextYear();
4024 }
4025};
4026
4027/**
4028* Navigates to the previous year in the currently selected month in the calendar widget.
4029* @method previousYear
4030*/
4031YAHOO.widget.CalendarGroup.prototype.previousYear = function() {
4032 for (var p=0;p<this.pages.length;++p) {
4033 var cal = this.pages[p];
4034 cal.previousYear();
4035 }
4036};
4037
4038
4039/**
4040* Gets the list of currently selected dates from the calendar.
4041 * @return An array of currently selected JavaScript Date objects.
4042* @type Date[]
4043*/
4044YAHOO.widget.CalendarGroup.prototype.getSelectedDates = function() {
4045 var returnDates = [];
4046 var selected = this.cfg.getProperty("selected");
4047
4048 for (var d=0;d<selected.length;++d) {
4049 var dateArray = selected[d];
4050
4051 var date = new Date(dateArray[0],dateArray[1]-1,dateArray[2]);
4052 returnDates.push(date);
4053 }
4054
4055 returnDates.sort( function(a,b) { return a-b; } );
4056 return returnDates;
4057};
4058
4059/**
4060* Adds a renderer to the render stack. The function reference passed to this method will be executed
4061* when a date cell matches the conditions specified in the date string for this renderer.
4062* @method addRenderer
4063 * @param {String} sDates A date string to associate with the specified renderer. Valid formats
4064 * include date (12/24/2005), month/day (12/24), and range (12/1/2004-1/1/2005)
4065 * @param {Function} fnRenderThe function executed to render cells that match the render rules for this renderer.
4066*/
4067YAHOO.widget.CalendarGroup.prototype.addRenderer = function(sDates, fnRender) {
4068 for (var p=0;p<this.pages.length;++p) {
4069 var cal = this.pages[p];
4070 cal.addRenderer(sDates, fnRender);
4071 }
4072};
4073
4074/**
4075* Adds a month to the render stack. The function reference passed to this method will be executed
4076* when a date cell matches the month passed to this method.
4077* @method addMonthRenderer
4078 * @param {Number} month The month (1-12) to associate with this renderer
4079 * @param {Function} fnRenderThe function executed to render cells that match the render rules for this renderer.
4080*/
4081YAHOO.widget.CalendarGroup.prototype.addMonthRenderer = function(month, fnRender) {
4082 for (var p=0;p<this.pages.length;++p) {
4083 var cal = this.pages[p];
4084 cal.addMonthRenderer(month, fnRender);
4085 }
4086};
4087
4088/**
4089* Adds a weekday to the render stack. The function reference passed to this method will be executed
4090* when a date cell matches the weekday passed to this method.
4091* @method addWeekdayRenderer
4092 * @param {Number} weekday The weekday (0-6) to associate with this renderer
4093 * @param {Function} fnRenderThe function executed to render cells that match the render rules for this renderer.
4094*/
4095YAHOO.widget.CalendarGroup.prototype.addWeekdayRenderer = function(weekday, fnRender) {
4096 for (var p=0;p<this.pages.length;++p) {
4097 var cal = this.pages[p];
4098 cal.addWeekdayRenderer(weekday, fnRender);
4099 }
4100};
4101
4102/**
4103* Renders the header for the CalendarGroup.
4104* @method renderHeader
4105*/
4106YAHOO.widget.CalendarGroup.prototype.renderHeader = function() {};
4107
4108/**
4109* Renders a footer for the 2-up calendar container. By default, this method is
4110* unimplemented.
4111* @method renderFooter
4112*/
4113YAHOO.widget.CalendarGroup.prototype.renderFooter = function() {};
4114
4115/**
4116* Adds the designated number of months to the current calendar month, and sets the current
4117* calendar page date to the new month.
4118* @method addMonths
4119 * @param {Number} countThe number of months to add to the current calendar
4120*/
4121YAHOO.widget.CalendarGroup.prototype.addMonths = function(count) {
4122 this.callChildFunction("addMonths", count);
4123};
4124
4125
4126/**
4127* Subtracts the designated number of months from the current calendar month, and sets the current
4128* calendar page date to the new month.
4129* @method subtractMonths
4130 * @param {Number} countThe number of months to subtract from the current calendar
4131*/
4132YAHOO.widget.CalendarGroup.prototype.subtractMonths = function(count) {
4133 this.callChildFunction("subtractMonths", count);
4134};
4135
4136/**
4137* Adds the designated number of years to the current calendar, and sets the current
4138* calendar page date to the new month.
4139* @method addYears
4140 * @param {Number} countThe number of years to add to the current calendar
4141*/
4142YAHOO.widget.CalendarGroup.prototype.addYears = function(count) {
4143 this.callChildFunction("addYears", count);
4144};
4145
4146/**
4147* Subtcats the designated number of years from the current calendar, and sets the current
4148* calendar page date to the new month.
4149* @method subtractYears
4150 * @param {Number} countThe number of years to subtract from the current calendar
4151*/
4152YAHOO.widget.CalendarGroup.prototype.subtractYears = function(count) {
4153 this.callChildFunction("subtractYears", count);
4154};
4155
4156/**
4157* CSS class representing the container for the calendar
4158* @property YAHOO.widget.CalendarGroup.CSS_CONTAINER
4159* @static
4160* @final
4161* @type String
4162*/
4163YAHOO.widget.CalendarGroup.CSS_CONTAINER = "yui-calcontainer";
4164
4165/**
4166* CSS class representing the container for the calendar
4167* @property YAHOO.widget.CalendarGroup.CSS_MULTI_UP
4168* @static
4169* @final
4170* @type String
4171*/
4172YAHOO.widget.CalendarGroup.CSS_MULTI_UP = "multi";
4173
4174/**
4175* CSS class representing the title for the 2-up calendar
4176* @property YAHOO.widget.CalendarGroup.CSS_2UPTITLE
4177* @static
4178* @final
4179* @type String
4180*/
4181YAHOO.widget.CalendarGroup.CSS_2UPTITLE = "title";
4182
4183/**
4184* CSS class representing the close icon for the 2-up calendar
4185* @property YAHOO.widget.CalendarGroup.CSS_2UPCLOSE
4186* @static
4187* @final
4188* @type String
4189*/
4190YAHOO.widget.CalendarGroup.CSS_2UPCLOSE = "close-icon";
4191
4192YAHOO.augment(YAHOO.widget.CalendarGroup, YAHOO.widget.Calendar, "buildDayLabel",
4193 "buildMonthLabel",
4194 "renderOutOfBoundsDate",
4195 "renderRowHeader",
4196 "renderRowFooter",
4197 "renderCellDefault",
4198 "styleCellDefault",
4199 "renderCellStyleHighlight1",
4200 "renderCellStyleHighlight2",
4201 "renderCellStyleHighlight3",
4202 "renderCellStyleHighlight4",
4203 "renderCellStyleToday",
4204 "renderCellStyleSelected",
4205 "renderCellNotThisMonth",
4206 "renderBodyCellRestricted",
4207 "initStyles",
4208 "configTitle",
4209 "configClose",
4210 "hide",
4211 "show",
4212 "browser");
4213
4214/**
4215* Returns a string representation of the object.
4216* @method toString
4217 * @return {String}A string representation of the CalendarGroup object.
4218*/
4219YAHOO.widget.CalendarGroup.prototype.toString = function() {
4220 return "CalendarGroup " + this.id;
4221};
4222
4223YAHOO.widget.CalGrp = YAHOO.widget.CalendarGroup;
4224
4225/**
4226* @class YAHOO.widget.Calendar2up
4227* @extends YAHOO.widget.CalendarGroup
4228* @deprecated The old Calendar2up class is no longer necessary, since CalendarGroup renders in a 2up view by default.
4229*/
4230YAHOO.widget.Calendar2up = function(id, containerId, config) {
4231 this.init(id, containerId, config);
4232};
4233
4234YAHOO.extend(YAHOO.widget.Calendar2up, YAHOO.widget.CalendarGroup);
4235
4236/**
4237* @deprecated The old Calendar2up class is no longer necessary, since CalendarGroup renders in a 2up view by default.
4238*/
4239YAHOO.widget.Cal2up = YAHOO.widget.Calendar2up; \ No newline at end of file
diff --git a/frontend/beta/js/YUI/connection.js b/frontend/beta/js/YUI/connection.js
new file mode 100644
index 0000000..58f6d0f
--- a/dev/null
+++ b/frontend/beta/js/YUI/connection.js
@@ -0,0 +1,960 @@
1/*
2Copyright (c) 2006, Yahoo! Inc. All rights reserved.
3Code licensed under the BSD License:
4http://developer.yahoo.net/yui/license.txt
5version: 0.12.0
6*/
7
8/**
9 * @description
10 * The Connection Manager provides a simplified interface to the XMLHttpRequest
11 * object. It handles cross-browser instantiantion of XMLHttpRequest, negotiates the
12 * interactive states and server response, returning the results to a pre-defined
13 * callback you create.
14 *
15 * @namespace YAHOO.util
16 * @module Connection
17 * @Class Connect
18 */
19YAHOO.util.Connect =
20{
21 /**
22 * @description Array of MSFT ActiveX ids for XMLHttpRequest.
23 * @property _msxml_progid
24 * @private
25 * @static
26 * @type array
27 */
28 _msxml_progid:[
29 'MSXML2.XMLHTTP.3.0',
30 'MSXML2.XMLHTTP',
31 'Microsoft.XMLHTTP'
32 ],
33
34 /**
35 * @description Object literal of HTTP header(s)
36 * @property _http_header
37 * @private
38 * @static
39 * @type object
40 */
41 _http_header:{},
42
43 /**
44 * @description Determines if HTTP headers are set.
45 * @property _has_http_headers
46 * @private
47 * @static
48 * @type boolean
49 */
50 _has_http_headers:false,
51
52 /**
53 * @description Determines if a default header of
54 * Content-Type of 'application/x-www-form-urlencoded'
55 * will be added to any client HTTP headers sent for POST
56 * transactions.
57 * @property _use_default_post_header
58 * @private
59 * @static
60 * @type boolean
61 */
62 _use_default_post_header:true,
63
64 /**
65 * @description Determines if a default header of
66 * Content-Type of 'application/x-www-form-urlencoded'
67 * will be added to any client HTTP headers sent for POST
68 * transactions.
69 * @property _default_post_header
70 * @private
71 * @static
72 * @type boolean
73 */
74 _default_post_header:'application/x-www-form-urlencoded',
75
76 /**
77 * @description Property modified by setForm() to determine if the data
78 * should be submitted as an HTML form.
79 * @property _isFormSubmit
80 * @private
81 * @static
82 * @type boolean
83 */
84 _isFormSubmit:false,
85
86 /**
87 * @description Property modified by setForm() to determine if a file(s)
88 * upload is expected.
89 * @property _isFileUpload
90 * @private
91 * @static
92 * @type boolean
93 */
94 _isFileUpload:false,
95
96 /**
97 * @description Property modified by setForm() to set a reference to the HTML
98 * form node if the desired action is file upload.
99 * @property _formNode
100 * @private
101 * @static
102 * @type object
103 */
104 _formNode:null,
105
106 /**
107 * @description Property modified by setForm() to set the HTML form data
108 * for each transaction.
109 * @property _sFormData
110 * @private
111 * @static
112 * @type string
113 */
114 _sFormData:null,
115
116 /**
117 * @description Collection of polling references to the polling mechanism in handleReadyState.
118 * @property _poll
119 * @private
120 * @static
121 * @type object
122 */
123 _poll:{},
124
125 /**
126 * @description Queue of timeout values for each transaction callback with a defined timeout value.
127 * @property _timeOut
128 * @private
129 * @static
130 * @type object
131 */
132 _timeOut:{},
133
134 /**
135 * @description The polling frequency, in milliseconds, for HandleReadyState.
136 * when attempting to determine a transaction's XHR readyState.
137 * The default is 50 milliseconds.
138 * @property _polling_interval
139 * @private
140 * @static
141 * @type int
142 */
143 _polling_interval:50,
144
145 /**
146 * @description A transaction counter that increments the transaction id for each transaction.
147 * @property _transaction_id
148 * @private
149 * @static
150 * @type int
151 */
152 _transaction_id:0,
153
154 /**
155 * @description Member to add an ActiveX id to the existing xml_progid array.
156 * In the event(unlikely) a new ActiveX id is introduced, it can be added
157 * without internal code modifications.
158 * @method setProgId
159 * @public
160 * @static
161 * @param {string} id The ActiveX id to be added to initialize the XHR object.
162 * @return void
163 */
164 setProgId:function(id)
165 {
166 this._msxml_progid.unshift(id);
167 },
168
169 /**
170 * @description Member to enable or disable the default POST header.
171 * @method setDefaultPostHeader
172 * @public
173 * @static
174 * @param {boolean} b Set and use default header - true or false .
175 * @return void
176 */
177 setDefaultPostHeader:function(b)
178 {
179 this._use_default_post_header = b;
180 },
181
182 /**
183 * @description Member to modify the default polling interval.
184 * @method setPollingInterval
185 * @public
186 * @static
187 * @param {int} i The polling interval in milliseconds.
188 * @return void
189 */
190 setPollingInterval:function(i)
191 {
192 if(typeof i == 'number' && isFinite(i)){
193 this._polling_interval = i;
194 }
195 },
196
197 /**
198 * @description Instantiates a XMLHttpRequest object and returns an object with two properties:
199 * the XMLHttpRequest instance and the transaction id.
200 * @method createXhrObject
201 * @private
202 * @static
203 * @param {int} transactionId Property containing the transaction id for this transaction.
204 * @return object
205 */
206 createXhrObject:function(transactionId)
207 {
208 var obj,http;
209 try
210 {
211 // Instantiates XMLHttpRequest in non-IE browsers and assigns to http.
212 http = new XMLHttpRequest();
213 // Object literal with http and tId properties
214 obj = { conn:http, tId:transactionId };
215 }
216 catch(e)
217 {
218 for(var i=0; i<this._msxml_progid.length; ++i){
219 try
220 {
221 // Instantiates XMLHttpRequest for IE and assign to http.
222 http = new ActiveXObject(this._msxml_progid[i]);
223 // Object literal with conn and tId properties
224 obj = { conn:http, tId:transactionId };
225 break;
226 }
227 catch(e){}
228 }
229 }
230 finally
231 {
232 return obj;
233 }
234 },
235
236 /**
237 * @description This method is called by asyncRequest to create a
238 * valid connection object for the transaction. It also passes a
239 * transaction id and increments the transaction id counter.
240 * @method getConnectionObject
241 * @private
242 * @static
243 * @return {object}
244 */
245 getConnectionObject:function()
246 {
247 var o;
248 var tId = this._transaction_id;
249
250 try
251 {
252 o = this.createXhrObject(tId);
253 if(o){
254 this._transaction_id++;
255 }
256 }
257 catch(e){}
258 finally
259 {
260 return o;
261 }
262 },
263
264 /**
265 * @description Method for initiating an asynchronous request via the XHR object.
266 * @method asyncRequest
267 * @public
268 * @static
269 * @param {string} method HTTP transaction method
270 * @param {string} uri Fully qualified path of resource
271 * @param {callback} callback User-defined callback function or object
272 * @param {string} postData POST body
273 * @return {object} Returns the connection object
274 */
275 asyncRequest:function(method, uri, callback, postData)
276 {
277 var o = this.getConnectionObject();
278
279 if(!o){
280 return null;
281 }
282 else{
283 if(this._isFormSubmit){
284 if(this._isFileUpload){
285 this.uploadFile(o.tId, callback, uri, postData);
286 this.releaseObject(o);
287
288 return;
289 }
290
291 //If the specified HTTP method is GET, setForm() will return an
292 //encoded string that is concatenated to the uri to
293 //create a querystring.
294 if(method == 'GET'){
295 if(this._sFormData.length != 0){
296 // If the URI already contains a querystring, append an ampersand
297 // and then concatenate _sFormData to the URI.
298 uri += ((uri.indexOf('?') == -1)?'?':'&') + this._sFormData;
299 }
300 else{
301 uri += "?" + this._sFormData;
302 }
303 }
304 else if(method == 'POST'){
305 //If POST data exist in addition to the HTML form data,
306 //it will be concatenated to the form data.
307 postData = postData?this._sFormData + "&" + postData:this._sFormData;
308 }
309 }
310
311 o.conn.open(method, uri, true);
312
313 if(this._isFormSubmit || (postData && this._use_default_post_header)){
314 this.initHeader('Content-Type', this._default_post_header);
315 if(this._isFormSubmit){
316 this.resetFormState();
317 }
318 }
319
320 if(this._has_http_headers){
321 this.setHeader(o);
322 }
323
324 this.handleReadyState(o, callback);
325 o.conn.send(postData || null);
326
327 return o;
328 }
329 },
330
331 /**
332 * @description This method serves as a timer that polls the XHR object's readyState
333 * property during a transaction, instead of binding a callback to the
334 * onreadystatechange event. Upon readyState 4, handleTransactionResponse
335 * will process the response, and the timer will be cleared.
336 * @method handleReadyState
337 * @private
338 * @static
339 * @param {object} o The connection object
340 * @param {callback} callback The user-defined callback object
341 * @return {void}
342 */
343 handleReadyState:function(o, callback)
344 {
345 var oConn = this;
346
347 if(callback && callback.timeout){
348 this._timeOut[o.tId] = window.setTimeout(function(){ oConn.abort(o, callback, true); }, callback.timeout);
349 }
350
351 this._poll[o.tId] = window.setInterval(
352 function(){
353 if(o.conn && o.conn.readyState == 4){
354 window.clearInterval(oConn._poll[o.tId]);
355 delete oConn._poll[o.tId];
356
357 if(callback && callback.timeout){
358 delete oConn._timeOut[o.tId];
359 }
360
361 oConn.handleTransactionResponse(o, callback);
362 }
363 }
364 ,this._polling_interval);
365 },
366
367 /**
368 * @description This method attempts to interpret the server response and
369 * determine whether the transaction was successful, or if an error or
370 * exception was encountered.
371 * @method handleTransactionResponse
372 * @private
373 * @static
374 * @param {object} o The connection object
375 * @param {object} callback The sser-defined callback object
376 * @param {boolean} isAbort Determines if the transaction was aborted.
377 * @return {void}
378 */
379 handleTransactionResponse:function(o, callback, isAbort)
380 {
381 // If no valid callback is provided, then do not process any callback handling.
382 if(!callback){
383 this.releaseObject(o);
384 return;
385 }
386
387 var httpStatus, responseObject;
388
389 try
390 {
391 if(o.conn.status !== undefined && o.conn.status != 0){
392 httpStatus = o.conn.status;
393 }
394 else{
395 httpStatus = 13030;
396 }
397 }
398 catch(e){
399 // 13030 is the custom code to indicate the condition -- in Mozilla/FF --
400 // when the o object's status and statusText properties are
401 // unavailable, and a query attempt throws an exception.
402 httpStatus = 13030;
403 }
404
405 if(httpStatus >= 200 && httpStatus < 300){
406 try
407 {
408 responseObject = this.createResponseObject(o, callback.argument);
409 if(callback.success){
410 if(!callback.scope){
411 callback.success(responseObject);
412 }
413 else{
414 // If a scope property is defined, the callback will be fired from
415 // the context of the object.
416 callback.success.apply(callback.scope, [responseObject]);
417 }
418 }
419 }
420 catch(e){}
421 }
422 else{
423 try
424 {
425 switch(httpStatus){
426 // The following cases are wininet.dll error codes that may be encountered.
427 case 12002: // Server timeout
428 case 12029: // 12029 to 12031 correspond to dropped connections.
429 case 12030:
430 case 12031:
431 case 12152: // Connection closed by server.
432 case 13030: // See above comments for variable status.
433 responseObject = this.createExceptionObject(o.tId, callback.argument, (isAbort?isAbort:false));
434 if(callback.failure){
435 if(!callback.scope){
436 callback.failure(responseObject);
437 }
438 else{
439 callback.failure.apply(callback.scope, [responseObject]);
440 }
441 }
442 break;
443 default:
444 responseObject = this.createResponseObject(o, callback.argument);
445 if(callback.failure){
446 if(!callback.scope){
447 callback.failure(responseObject);
448 }
449 else{
450 callback.failure.apply(callback.scope, [responseObject]);
451 }
452 }
453 }
454 }
455 catch(e){}
456 }
457
458 this.releaseObject(o);
459 responseObject = null;
460 },
461
462 /**
463 * @description This method evaluates the server response, creates and returns the results via
464 * its properties. Success and failure cases will differ in the response
465 * object's property values.
466 * @method createResponseObject
467 * @private
468 * @static
469 * @param {object} o The connection object
470 * @param {callbackArg} callbackArg The user-defined argument or arguments to be passed to the callback
471 * @return {object}
472 */
473 createResponseObject:function(o, callbackArg)
474 {
475 var obj = {};
476 var headerObj = {};
477
478 try
479 {
480 var headerStr = o.conn.getAllResponseHeaders();
481 var header = headerStr.split('\n');
482 for(var i=0; i<header.length; i++){
483 var delimitPos = header[i].indexOf(':');
484 if(delimitPos != -1){
485 headerObj[header[i].substring(0,delimitPos)] = header[i].substring(delimitPos+2);
486 }
487 }
488 }
489 catch(e){}
490
491 obj.tId = o.tId;
492 obj.status = o.conn.status;
493 obj.statusText = o.conn.statusText;
494 obj.getResponseHeader = headerObj;
495 obj.getAllResponseHeaders = headerStr;
496 obj.responseText = o.conn.responseText;
497 obj.responseXML = o.conn.responseXML;
498
499 if(typeof callbackArg !== undefined){
500 obj.argument = callbackArg;
501 }
502
503 return obj;
504 },
505
506 /**
507 * @description If a transaction cannot be completed due to dropped or closed connections,
508 * there may be not be enough information to build a full response object.
509 * The failure callback will be fired and this specific condition can be identified
510 * by a status property value of 0.
511 *
512 * If an abort was successful, the status property will report a value of -1.
513 *
514 * @method createExceptionObject
515 * @private
516 * @static
517 * @param {int} tId The Transaction Id
518 * @param {callbackArg} callbackArg The user-defined argument or arguments to be passed to the callback
519 * @param {boolean} isAbort Determines if the exception case is caused by a transaction abort
520 * @return {object}
521 */
522 createExceptionObject:function(tId, callbackArg, isAbort)
523 {
524 var COMM_CODE = 0;
525 var COMM_ERROR = 'communication failure';
526 var ABORT_CODE = -1;
527 var ABORT_ERROR = 'transaction aborted';
528
529 var obj = {};
530
531 obj.tId = tId;
532 if(isAbort){
533 obj.status = ABORT_CODE;
534 obj.statusText = ABORT_ERROR;
535 }
536 else{
537 obj.status = COMM_CODE;
538 obj.statusText = COMM_ERROR;
539 }
540
541 if(callbackArg){
542 obj.argument = callbackArg;
543 }
544
545 return obj;
546 },
547
548 /**
549 * @description Public method that stores the custom HTTP headers for each transaction.
550 * @method initHeader
551 * @public
552 * @static
553 * @param {string} label The HTTP header label
554 * @param {string} value The HTTP header value
555 * @return {void}
556 */
557 initHeader:function(label,value)
558 {
559 if(this._http_header[label] === undefined){
560 this._http_header[label] = value;
561 }
562 else{
563 // Concatenate multiple values, comma-delimited,
564 // for the same header label,
565 this._http_header[label] = value + "," + this._http_header[label];
566 }
567
568 this._has_http_headers = true;
569 },
570
571 /**
572 * @description Accessor that sets the HTTP headers for each transaction.
573 * @method setHeader
574 * @private
575 * @static
576 * @param {object} o The connection object for the transaction.
577 * @return {void}
578 */
579 setHeader:function(o)
580 {
581 for(var prop in this._http_header){
582 if(this._http_header.hasOwnProperty(prop)){
583 o.conn.setRequestHeader(prop, this._http_header[prop]);
584 }
585 }
586 delete this._http_header;
587
588 this._http_header = {};
589 this._has_http_headers = false;
590 },
591
592 /**
593 * @description This method assembles the form label and value pairs and
594 * constructs an encoded string.
595 * asyncRequest() will automatically initialize the
596 * transaction with a HTTP header Content-Type of
597 * application/x-www-form-urlencoded.
598 * @method setForm
599 * @public
600 * @static
601 * @param {string || object} form id or name attribute, or form object.
602 * @param {string} optional boolean to indicate SSL environment.
603 * @param {string || boolean} optional qualified path of iframe resource for SSL in IE.
604 * @return {string} string of the HTML form field name and value pairs..
605 */
606 setForm:function(formId, isUpload, secureUri)
607 {
608 this.resetFormState();
609 var oForm;
610 if(typeof formId == 'string'){
611 // Determine if the argument is a form id or a form name.
612 // Note form name usage is deprecated by supported
613 // here for legacy reasons.
614 oForm = (document.getElementById(formId) || document.forms[formId]);
615 }
616 else if(typeof formId == 'object'){
617 // Treat argument as an HTML form object.
618 oForm = formId;
619 }
620 else{
621 return;
622 }
623
624 // If the isUpload argument is true, setForm will call createFrame to initialize
625 // an iframe as the form target.
626 //
627 // The argument secureURI is also required by IE in SSL environments
628 // where the secureURI string is a fully qualified HTTP path, used to set the source
629 // of the iframe, to a stub resource in the same domain.
630 if(isUpload){
631
632 // Create iframe in preparation for file upload.
633 this.createFrame(secureUri?secureUri:null);
634
635 // Set form reference and file upload properties to true.
636 this._isFormSubmit = true;
637 this._isFileUpload = true;
638 this._formNode = oForm;
639
640 return;
641 }
642
643 var oElement, oName, oValue, oDisabled;
644 var hasSubmit = false;
645
646 // Iterate over the form elements collection to construct the
647 // label-value pairs.
648 for (var i=0; i<oForm.elements.length; i++){
649 oElement = oForm.elements[i];
650 oDisabled = oForm.elements[i].disabled;
651 oName = oForm.elements[i].name;
652 oValue = oForm.elements[i].value;
653
654 // Do not submit fields that are disabled or
655 // do not have a name attribute value.
656 if(!oDisabled && oName)
657 {
658 switch (oElement.type)
659 {
660 case 'select-one':
661 case 'select-multiple':
662 for(var j=0; j<oElement.options.length; j++){
663 if(oElement.options[j].selected){
664 if(window.ActiveXObject){
665 this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oElement.options[j].attributes['value'].specified?oElement.options[j].value:oElement.options[j].text) + '&';
666 }
667 else{
668 this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oElement.options[j].hasAttribute('value')?oElement.options[j].value:oElement.options[j].text) + '&';
669 }
670
671 }
672 }
673 break;
674 case 'radio':
675 case 'checkbox':
676 if(oElement.checked){
677 this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oValue) + '&';
678 }
679 break;
680 case 'file':
681 // stub case as XMLHttpRequest will only send the file path as a string.
682 case undefined:
683 // stub case for fieldset element which returns undefined.
684 case 'reset':
685 // stub case for input type reset button.
686 case 'button':
687 // stub case for input type button elements.
688 break;
689 case 'submit':
690 if(hasSubmit == false){
691 this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oValue) + '&';
692 hasSubmit = true;
693 }
694 break;
695 default:
696 this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oValue) + '&';
697 break;
698 }
699 }
700 }
701
702 this._isFormSubmit = true;
703 this._sFormData = this._sFormData.substr(0, this._sFormData.length - 1);
704
705 return this._sFormData;
706 },
707
708 /**
709 * @description Resets HTML form properties when an HTML form or HTML form
710 * with file upload transaction is sent.
711 * @method resetFormState
712 * @private
713 * @static
714 * @return {void}
715 */
716 resetFormState:function(){
717 this._isFormSubmit = false;
718 this._isFileUpload = false;
719 this._formNode = null;
720 this._sFormData = "";
721 },
722
723 /**
724 * @description Creates an iframe to be used for form file uploads. It is remove from the
725 * document upon completion of the upload transaction.
726 * @method createFrame
727 * @private
728 * @static
729 * @param {string} secureUri Optional qualified path of iframe resource for SSL in IE.
730 * @return {void}
731 */
732 createFrame:function(secureUri){
733
734 // IE does not allow the setting of id and name attributes as object
735 // properties via createElement(). A different iframe creation
736 // pattern is required for IE.
737 var frameId = 'yuiIO' + this._transaction_id;
738 if(window.ActiveXObject){
739 var io = document.createElement('<iframe id="' + frameId + '" name="' + frameId + '" />');
740
741 // IE will throw a security exception in an SSL environment if the
742 // iframe source is undefined.
743 if(typeof secureUri == 'boolean'){
744 io.src = 'javascript:false';
745 }
746 else if(typeof secureURI == 'string'){
747 // Deprecated
748 io.src = secureUri;
749 }
750 }
751 else{
752 var io = document.createElement('iframe');
753 io.id = frameId;
754 io.name = frameId;
755 }
756
757 io.style.position = 'absolute';
758 io.style.top = '-1000px';
759 io.style.left = '-1000px';
760
761 document.body.appendChild(io);
762 },
763
764 /**
765 * @description Parses the POST data and creates hidden form elements
766 * for each key-value, and appends them to the HTML form object.
767 * @method appendPostData
768 * @private
769 * @static
770 * @param {string} postData The HTTP POST data
771 * @return {array} formElements Collection of hidden fields.
772 */
773 appendPostData:function(postData)
774 {
775 var formElements = new Array();
776 var postMessage = postData.split('&');
777 for(var i=0; i < postMessage.length; i++){
778 var delimitPos = postMessage[i].indexOf('=');
779 if(delimitPos != -1){
780 formElements[i] = document.createElement('input');
781 formElements[i].type = 'hidden';
782 formElements[i].name = postMessage[i].substring(0,delimitPos);
783 formElements[i].value = postMessage[i].substring(delimitPos+1);
784 this._formNode.appendChild(formElements[i]);
785 }
786 }
787
788 return formElements;
789 },
790
791 /**
792 * @description Uploads HTML form, including files/attachments, to the
793 * iframe created in createFrame.
794 * @method uploadFile
795 * @private
796 * @static
797 * @param {int} id The transaction id.
798 * @param {object} callback - User-defined callback object.
799 * @param {string} uri Fully qualified path of resource.
800 * @return {void}
801 */
802 uploadFile:function(id, callback, uri, postData){
803
804 // Each iframe has an id prefix of "yuiIO" followed
805 // by the unique transaction id.
806 var frameId = 'yuiIO' + id;
807 var io = document.getElementById(frameId);
808
809 // Initialize the HTML form properties in case they are
810 // not defined in the HTML form.
811 this._formNode.action = uri;
812 this._formNode.method = 'POST';
813 this._formNode.target = frameId;
814
815 if(this._formNode.encoding){
816 // IE does not respect property enctype for HTML forms.
817 // Instead use property encoding.
818 this._formNode.encoding = 'multipart/form-data';
819 }
820 else{
821 this._formNode.enctype = 'multipart/form-data';
822 }
823
824 if(postData){
825 var oElements = this.appendPostData(postData);
826 }
827
828 this._formNode.submit();
829
830 if(oElements && oElements.length > 0){
831 try
832 {
833 for(var i=0; i < oElements.length; i++){
834 this._formNode.removeChild(oElements[i]);
835 }
836 }
837 catch(e){}
838 }
839
840 // Reset HTML form status properties.
841 this.resetFormState();
842
843 // Create the upload callback handler that fires when the iframe
844 // receives the load event. Subsequently, the event handler is detached
845 // and the iframe removed from the document.
846
847 var uploadCallback = function()
848 {
849 var obj = {};
850 obj.tId = id;
851 obj.argument = callback.argument;
852
853 try
854 {
855 obj.responseText = io.contentWindow.document.body?io.contentWindow.document.body.innerHTML:null;
856 obj.responseXML = io.contentWindow.document.XMLDocument?io.contentWindow.document.XMLDocument:io.contentWindow.document;
857 }
858 catch(e){}
859
860 if(callback.upload){
861 if(!callback.scope){
862 callback.upload(obj);
863 }
864 else{
865 callback.upload.apply(callback.scope, [obj]);
866 }
867 }
868
869 if(YAHOO.util.Event){
870 YAHOO.util.Event.removeListener(io, "load", uploadCallback);
871 }
872 else if(window.detachEvent){
873 io.detachEvent('onload', uploadCallback);
874 }
875 else{
876 io.removeEventListener('load', uploadCallback, false);
877 }
878 setTimeout(function(){ document.body.removeChild(io); }, 100);
879 };
880
881
882 // Bind the onload handler to the iframe to detect the file upload response.
883 if(YAHOO.util.Event){
884 YAHOO.util.Event.addListener(io, "load", uploadCallback);
885 }
886 else if(window.attachEvent){
887 io.attachEvent('onload', uploadCallback);
888 }
889 else{
890 io.addEventListener('load', uploadCallback, false);
891 }
892 },
893
894 /**
895 * @description Method to terminate a transaction, if it has not reached readyState 4.
896 * @method abort
897 * @public
898 * @static
899 * @param {object} o The connection object returned by asyncRequest.
900 * @param {object} callback User-defined callback object.
901 * @param {string} isTimeout boolean to indicate if abort was a timeout.
902 * @return {boolean}
903 */
904 abort:function(o, callback, isTimeout)
905 {
906 if(this.isCallInProgress(o)){
907 o.conn.abort();
908 window.clearInterval(this._poll[o.tId]);
909 delete this._poll[o.tId];
910 if(isTimeout){
911 delete this._timeOut[o.tId];
912 }
913
914 this.handleTransactionResponse(o, callback, true);
915
916 return true;
917 }
918 else{
919 return false;
920 }
921 },
922
923 /**
924 * Public method to check if the transaction is still being processed.
925 *
926 * @method isCallInProgress
927 * @public
928 * @static
929 * @param {object} o The connection object returned by asyncRequest
930 * @return {boolean}
931 */
932 isCallInProgress:function(o)
933 {
934 // if the XHR object assigned to the transaction has not been dereferenced,
935 // then check its readyState status. Otherwise, return false.
936 if(o.conn){
937 return o.conn.readyState != 4 && o.conn.readyState != 0;
938 }
939 else{
940 //The XHR object has been destroyed.
941 return false;
942 }
943 },
944
945 /**
946 * @description Dereference the XHR instance and the connection object after the transaction is completed.
947 * @method releaseObject
948 * @private
949 * @static
950 * @param {object} o The connection object
951 * @return {void}
952 */
953 releaseObject:function(o)
954 {
955 //dereference the XHR instance.
956 o.conn = null;
957 //dereference the connection object.
958 o = null;
959 }
960}; \ No newline at end of file
diff --git a/frontend/beta/js/YUI/container.js b/frontend/beta/js/YUI/container.js
new file mode 100644
index 0000000..ec0f864
--- a/dev/null
+++ b/frontend/beta/js/YUI/container.js
@@ -0,0 +1,4561 @@
1/*
2Copyright (c) 2006, Yahoo! Inc. All rights reserved.
3Code licensed under the BSD License:
4http://developer.yahoo.net/yui/license.txt
5version 0.12.0
6*/
7
8/**
9* Config is a utility used within an Object to allow the implementer to maintain a list of local configuration properties and listen for changes to those properties dynamically using CustomEvent. The initial values are also maintained so that the configuration can be reset at any given point to its initial state.
10* @class YAHOO.util.Config
11* @constructor
12 * @param {Object} ownerThe owner Object to which this Config Object belongs
13*/
14YAHOO.util.Config = function(owner) {
15 if (owner) {
16 this.init(owner);
17 }
18};
19
20YAHOO.util.Config.prototype = {
21
22 /**
23 * Object reference to the owner of this Config Object
24 * @property owner
25 * @type Object
26 */
27 owner : null,
28
29 /**
30 * Boolean flag that specifies whether a queue is currently being executed
31 * @property queueInProgress
32 * @type Boolean
33 */
34 queueInProgress : false,
35
36
37 /**
38 * Validates that the value passed in is a Boolean.
39 * @method checkBoolean
40 * @param {Object} valThe value to validate
41 * @return {Boolean}true, if the value is valid
42 */
43 checkBoolean: function(val) {
44 if (typeof val == 'boolean') {
45 return true;
46 } else {
47 return false;
48 }
49 },
50
51 /**
52 * Validates that the value passed in is a number.
53 * @method checkNumber
54 * @param {Object} valThe value to validate
55 * @return {Boolean}true, if the value is valid
56 */
57 checkNumber: function(val) {
58 if (isNaN(val)) {
59 return false;
60 } else {
61 return true;
62 }
63 }
64};
65
66
67/**
68* Initializes the configuration Object and all of its local members.
69* @method init
70 * @param {Object} ownerThe owner Object to which this Config Object belongs
71*/
72YAHOO.util.Config.prototype.init = function(owner) {
73
74 this.owner = owner;
75
76 /**
77 * Object reference to the owner of this Config Object
78 * @event configChangedEvent
79 */
80 this.configChangedEvent = new YAHOO.util.CustomEvent("configChanged");
81
82 this.queueInProgress = false;
83
84 /* Private Members */
85
86 /**
87 * Maintains the local collection of configuration property objects and their specified values
88 * @property config
89 * @private
90 * @type Object
91 */
92 var config = {};
93
94 /**
95 * Maintains the local collection of configuration property objects as they were initially applied.
96 * This object is used when resetting a property.
97 * @property initialConfig
98 * @private
99 * @type Object
100 */
101 var initialConfig = {};
102
103 /**
104 * Maintains the local, normalized CustomEvent queue
105 * @property eventQueue
106 * @private
107 * @type Object
108 */
109 var eventQueue = [];
110
111 /**
112 * Fires a configuration property event using the specified value.
113 * @method fireEvent
114 * @private
115 * @param {String} key The configuration property's name
116 * @param {value} Object The value of the correct type for the property
117 */
118 var fireEvent = function( key, value ) {
119 key = key.toLowerCase();
120
121 var property = config[key];
122
123 if (typeof property != 'undefined' && property.event) {
124 property.event.fire(value);
125 }
126 };
127 /* End Private Members */
128
129 /**
130 * Adds a property to the Config Object's private config hash.
131 * @method addProperty
132 * @param {String} keyThe configuration property's name
133 * @param {Object} propertyObjectThe Object containing all of this property's arguments
134 */
135 this.addProperty = function( key, propertyObject ) {
136 key = key.toLowerCase();
137
138 config[key] = propertyObject;
139
140 propertyObject.event = new YAHOO.util.CustomEvent(key);
141 propertyObject.key = key;
142
143 if (propertyObject.handler) {
144 propertyObject.event.subscribe(propertyObject.handler, this.owner, true);
145 }
146
147 this.setProperty(key, propertyObject.value, true);
148
149 if (! propertyObject.suppressEvent) {
150 this.queueProperty(key, propertyObject.value);
151 }
152 };
153
154 /**
155 * Returns a key-value configuration map of the values currently set in the Config Object.
156 * @method getConfig
157 * @return {Object} The current config, represented in a key-value map
158 */
159 this.getConfig = function() {
160 var cfg = {};
161
162 for (var prop in config) {
163 var property = config[prop];
164 if (typeof property != 'undefined' && property.event) {
165 cfg[prop] = property.value;
166 }
167 }
168
169 return cfg;
170 };
171
172 /**
173 * Returns the value of specified property.
174 * @method getProperty
175 * @param {String} keyThe name of the property
176 * @return {Object} The value of the specified property
177 */
178 this.getProperty = function(key) {
179 key = key.toLowerCase();
180
181 var property = config[key];
182 if (typeof property != 'undefined' && property.event) {
183 return property.value;
184 } else {
185 return undefined;
186 }
187 };
188
189 /**
190 * Resets the specified property's value to its initial value.
191 * @method resetProperty
192 * @param {String} keyThe name of the property
193 * @return {Boolean} True is the property was reset, false if not
194 */
195 this.resetProperty = function(key) {
196 key = key.toLowerCase();
197
198 var property = config[key];
199 if (typeof property != 'undefined' && property.event) {
200 if (initialConfig[key] && initialConfig[key] != 'undefined'){
201 this.setProperty(key, initialConfig[key]);
202 }
203 return true;
204 } else {
205 return false;
206 }
207 };
208
209 /**
210 * Sets the value of a property. If the silent property is passed as true, the property's event will not be fired.
211 * @method setProperty
212 * @param {String} key The name of the property
213 * @param {String} value The value to set the property to
214 * @param {Boolean} silentWhether the value should be set silently, without firing the property event.
215 * @return {Boolean} True, if the set was successful, false if it failed.
216 */
217 this.setProperty = function(key, value, silent) {
218 key = key.toLowerCase();
219
220 if (this.queueInProgress && ! silent) {
221 this.queueProperty(key,value); // Currently running through a queue...
222 return true;
223 } else {
224 var property = config[key];
225 if (typeof property != 'undefined' && property.event) {
226 if (property.validator && ! property.validator(value)) { // validator
227 return false;
228 } else {
229 property.value = value;
230 if (! silent) {
231 fireEvent(key, value);
232 this.configChangedEvent.fire([key, value]);
233 }
234 return true;
235 }
236 } else {
237 return false;
238 }
239 }
240 };
241
242 /**
243 * Sets the value of a property and queues its event to execute. If the event is already scheduled to execute, it is
244 * moved from its current position to the end of the queue.
245 * @method queueProperty
246 * @param {String} keyThe name of the property
247 * @param {String} valueThe value to set the property to
248 * @return {Boolean} true, if the set was successful, false if it failed.
249 */
250 this.queueProperty = function(key, value) {
251 key = key.toLowerCase();
252
253 var property = config[key];
254
255 if (typeof property != 'undefined' && property.event) {
256 if (typeof value != 'undefined' && property.validator && ! property.validator(value)) { // validator
257 return false;
258 } else {
259
260 if (typeof value != 'undefined') {
261 property.value = value;
262 } else {
263 value = property.value;
264 }
265
266 var foundDuplicate = false;
267
268 for (var i=0;i<eventQueue.length;i++) {
269 var queueItem = eventQueue[i];
270
271 if (queueItem) {
272 var queueItemKey = queueItem[0];
273 var queueItemValue = queueItem[1];
274
275 if (queueItemKey.toLowerCase() == key) {
276 // found a dupe... push to end of queue, null current item, and break
277 eventQueue[i] = null;
278 eventQueue.push([key, (typeof value != 'undefined' ? value : queueItemValue)]);
279 foundDuplicate = true;
280 break;
281 }
282 }
283 }
284
285 if (! foundDuplicate && typeof value != 'undefined') { // this is a refire, or a new property in the queue
286 eventQueue.push([key, value]);
287 }
288 }
289
290 if (property.supercedes) {
291 for (var s=0;s<property.supercedes.length;s++) {
292 var supercedesCheck = property.supercedes[s];
293
294 for (var q=0;q<eventQueue.length;q++) {
295 var queueItemCheck = eventQueue[q];
296
297 if (queueItemCheck) {
298 var queueItemCheckKey = queueItemCheck[0];
299 var queueItemCheckValue = queueItemCheck[1];
300
301 if ( queueItemCheckKey.toLowerCase() == supercedesCheck.toLowerCase() ) {
302 eventQueue.push([queueItemCheckKey, queueItemCheckValue]);
303 eventQueue[q] = null;
304 break;
305 }
306 }
307 }
308 }
309 }
310
311 return true;
312 } else {
313 return false;
314 }
315 };
316
317 /**
318 * Fires the event for a property using the property's current value.
319 * @method refireEvent
320 * @param {String} keyThe name of the property
321 */
322 this.refireEvent = function(key) {
323 key = key.toLowerCase();
324
325 var property = config[key];
326 if (typeof property != 'undefined' && property.event && typeof property.value != 'undefined') {
327 if (this.queueInProgress) {
328 this.queueProperty(key);
329 } else {
330 fireEvent(key, property.value);
331 }
332 }
333 };
334
335 /**
336 * Applies a key-value Object literal to the configuration, replacing any existing values, and queueing the property events.
337 * Although the values will be set, fireQueue() must be called for their associated events to execute.
338 * @method applyConfig
339 * @param {Object} userConfigThe configuration Object literal
340 * @param {Boolean} init When set to true, the initialConfig will be set to the userConfig passed in, so that calling a reset will reset the properties to the passed values.
341 */
342 this.applyConfig = function(userConfig, init) {
343 if (init) {
344 initialConfig = userConfig;
345 }
346 for (var prop in userConfig) {
347 this.queueProperty(prop, userConfig[prop]);
348 }
349 };
350
351 /**
352 * Refires the events for all configuration properties using their current values.
353 * @method refresh
354 */
355 this.refresh = function() {
356 for (var prop in config) {
357 this.refireEvent(prop);
358 }
359 };
360
361 /**
362 * Fires the normalized list of queued property change events
363 * @method fireQueue
364 */
365 this.fireQueue = function() {
366 this.queueInProgress = true;
367 for (var i=0;i<eventQueue.length;i++) {
368 var queueItem = eventQueue[i];
369 if (queueItem) {
370 var key = queueItem[0];
371 var value = queueItem[1];
372
373 var property = config[key];
374 property.value = value;
375
376 fireEvent(key,value);
377 }
378 }
379
380 this.queueInProgress = false;
381 eventQueue = [];
382 };
383
384 /**
385 * Subscribes an external handler to the change event for any given property.
386 * @method subscribeToConfigEvent
387 * @param {String} key The property name
388 * @param {Function} handler The handler function to use subscribe to the property's event
389 * @param {Object} obj The Object to use for scoping the event handler (see CustomEvent documentation)
390 * @param {Boolean} overrideOptional. If true, will override "this" within the handler to map to the scope Object passed into the method.
391 * @return {Boolean} True, if the subscription was successful, otherwise false.
392 */
393 this.subscribeToConfigEvent = function(key, handler, obj, override) {
394 key = key.toLowerCase();
395
396 var property = config[key];
397 if (typeof property != 'undefined' && property.event) {
398 if (! YAHOO.util.Config.alreadySubscribed(property.event, handler, obj)) {
399 property.event.subscribe(handler, obj, override);
400 }
401 return true;
402 } else {
403 return false;
404 }
405 };
406
407 /**
408 * Unsubscribes an external handler from the change event for any given property.
409 * @method unsubscribeFromConfigEvent
410 * @param {String} key The property name
411 * @param {Function} handler The handler function to use subscribe to the property's event
412 * @param {Object} obj The Object to use for scoping the event handler (see CustomEvent documentation)
413 * @return {Boolean} True, if the unsubscription was successful, otherwise false.
414 */
415 this.unsubscribeFromConfigEvent = function(key, handler, obj) {
416 key = key.toLowerCase();
417
418 var property = config[key];
419 if (typeof property != 'undefined' && property.event) {
420 return property.event.unsubscribe(handler, obj);
421 } else {
422 return false;
423 }
424 };
425
426 /**
427 * Returns a string representation of the Config object
428 * @method toString
429 * @return {String}The Config object in string format.
430 */
431 this.toString = function() {
432 var output = "Config";
433 if (this.owner) {
434 output += " [" + this.owner.toString() + "]";
435 }
436 return output;
437 };
438
439 /**
440 * Returns a string representation of the Config object's current CustomEvent queue
441 * @method outputEventQueue
442 * @return {String}The string list of CustomEvents currently queued for execution
443 */
444 this.outputEventQueue = function() {
445 var output = "";
446 for (var q=0;q<eventQueue.length;q++) {
447 var queueItem = eventQueue[q];
448 if (queueItem) {
449 output += queueItem[0] + "=" + queueItem[1] + ", ";
450 }
451 }
452 return output;
453 };
454};
455
456/**
457* Checks to determine if a particular function/Object pair are already subscribed to the specified CustomEvent
458* @method YAHOO.util.Config.alreadySubscribed
459* @static
460 * @param {YAHOO.util.CustomEvent} evtThe CustomEvent for which to check the subscriptions
461 * @param {Function} fnThe function to look for in the subscribers list
462 * @param {Object} objThe execution scope Object for the subscription
463 * @return {Boolean}true, if the function/Object pair is already subscribed to the CustomEvent passed in
464*/
465YAHOO.util.Config.alreadySubscribed = function(evt, fn, obj) {
466 for (var e=0;e<evt.subscribers.length;e++) {
467 var subsc = evt.subscribers[e];
468 if (subsc && subsc.obj == obj && subsc.fn == fn) {
469 return true;
470 }
471 }
472 return false;
473};
474
475/**
476* The Container family of components is designed to enable developers to create different kinds of content-containing modules on the web. Module and Overlay are the most basic containers, and they can be used directly or extended to build custom containers. Also part of the Container family are four UI controls that extend Module and Overlay: Tooltip, Panel, Dialog, and SimpleDialog.
477* @module Container
478* @requires yahoo,dom,event,dragdrop,animation
479*/
480
481/**
482* Module is a JavaScript representation of the Standard Module Format. Standard Module Format is a simple standard for markup containers where child nodes representing the header, body, and footer of the content are denoted using the CSS classes "hd", "bd", and "ft" respectively. Module is the base class for all other classes in the YUI Container package.
483* @class Module
484* @namespace YAHOO.widget
485* @constructor
486 * @param {String} el The element ID representing the Module <em>OR</em>
487 * @param {HTMLElement} el The element representing the Module
488 * @param {Object} userConfigThe configuration Object literal containing the configuration that should be set for this module. See configuration documentation for more details.
489*/
490YAHOO.widget.Module = function(el, userConfig) {
491 if (el) {
492 this.init(el, userConfig);
493 }
494};
495
496/**
497* Constant representing the prefix path to use for non-secure images
498* @property YAHOO.widget.Module.IMG_ROOT
499* @static
500* @final
501* @type String
502*/
503YAHOO.widget.Module.IMG_ROOT = "http://us.i1.yimg.com/us.yimg.com/i/";
504
505/**
506* Constant representing the prefix path to use for securely served images
507* @property YAHOO.widget.Module.IMG_ROOT_SSL
508* @static
509* @final
510* @type String
511*/
512YAHOO.widget.Module.IMG_ROOT_SSL = "https://a248.e.akamai.net/sec.yimg.com/i/";
513
514/**
515* Constant for the default CSS class name that represents a Module
516* @property YAHOO.widget.Module.CSS_MODULE
517* @static
518* @final
519* @type String
520*/
521YAHOO.widget.Module.CSS_MODULE = "module";
522
523/**
524* Constant representing the module header
525* @property YAHOO.widget.Module.CSS_HEADER
526* @static
527* @final
528* @type String
529*/
530YAHOO.widget.Module.CSS_HEADER = "hd";
531
532/**
533* Constant representing the module body
534* @property YAHOO.widget.Module.CSS_BODY
535* @static
536* @final
537* @type String
538*/
539YAHOO.widget.Module.CSS_BODY = "bd";
540
541/**
542* Constant representing the module footer
543* @property YAHOO.widget.Module.CSS_FOOTER
544* @static
545* @final
546* @type String
547*/
548YAHOO.widget.Module.CSS_FOOTER = "ft";
549
550/**
551* Constant representing the url for the "src" attribute of the iframe used to monitor changes to the browser's base font size
552* @property YAHOO.widget.Module.RESIZE_MONITOR_SECURE_URL
553* @static
554* @final
555* @type String
556*/
557YAHOO.widget.Module.RESIZE_MONITOR_SECURE_URL = "javascript:false;";
558
559YAHOO.widget.Module.prototype = {
560 /**
561 * The class's constructor function
562 * @property contructor
563 * @type Function
564 */
565 constructor : YAHOO.widget.Module,
566
567 /**
568 * The main module element that contains the header, body, and footer
569 * @property element
570 * @type HTMLElement
571 */
572 element : null,
573
574 /**
575 * The header element, denoted with CSS class "hd"
576 * @property header
577 * @type HTMLElement
578 */
579 header : null,
580
581 /**
582 * The body element, denoted with CSS class "bd"
583 * @property body
584 * @type HTMLElement
585 */
586 body : null,
587
588 /**
589 * The footer element, denoted with CSS class "ft"
590 * @property footer
591 * @type HTMLElement
592 */
593 footer : null,
594
595 /**
596 * The id of the element
597 * @property id
598 * @type String
599 */
600 id : null,
601
602 /**
603 * The String representing the image root
604 * @property imageRoot
605 * @type String
606 */
607 imageRoot : YAHOO.widget.Module.IMG_ROOT,
608
609 /**
610 * Initializes the custom events for Module which are fired automatically at appropriate times by the Module class.
611 * @method initEvents
612 */
613 initEvents : function() {
614
615 /**
616 * CustomEvent fired prior to class initalization.
617 * @event beforeInitEvent
618 * @param {class} classRefclass reference of the initializing class, such as this.beforeInitEvent.fire(YAHOO.widget.Module)
619 */
620 this.beforeInitEvent = new YAHOO.util.CustomEvent("beforeInit");
621
622 /**
623 * CustomEvent fired after class initalization.
624 * @event initEvent
625 * @param {class} classRefclass reference of the initializing class, such as this.beforeInitEvent.fire(YAHOO.widget.Module)
626 */
627 this.initEvent = new YAHOO.util.CustomEvent("init");
628
629 /**
630 * CustomEvent fired when the Module is appended to the DOM
631 * @event appendEvent
632 */
633 this.appendEvent = new YAHOO.util.CustomEvent("append");
634
635 /**
636 * CustomEvent fired before the Module is rendered
637 * @event beforeRenderEvent
638 */
639 this.beforeRenderEvent = new YAHOO.util.CustomEvent("beforeRender");
640
641 /**
642 * CustomEvent fired after the Module is rendered
643 * @event renderEvent
644 */
645 this.renderEvent = new YAHOO.util.CustomEvent("render");
646
647 /**
648 * CustomEvent fired when the header content of the Module is modified
649 * @event changeHeaderEvent
650 * @param {String/HTMLElement} contentString/element representing the new header content
651 */
652 this.changeHeaderEvent = new YAHOO.util.CustomEvent("changeHeader");
653
654 /**
655 * CustomEvent fired when the body content of the Module is modified
656 * @event changeBodyEvent
657 * @param {String/HTMLElement} contentString/element representing the new body content
658 */
659 this.changeBodyEvent = new YAHOO.util.CustomEvent("changeBody");
660
661 /**
662 * CustomEvent fired when the footer content of the Module is modified
663 * @event changeFooterEvent
664 * @param {String/HTMLElement} contentString/element representing the new footer content
665 */
666 this.changeFooterEvent = new YAHOO.util.CustomEvent("changeFooter");
667
668 /**
669 * CustomEvent fired when the content of the Module is modified
670 * @event changeContentEvent
671 */
672 this.changeContentEvent = new YAHOO.util.CustomEvent("changeContent");
673
674 /**
675 * CustomEvent fired when the Module is destroyed
676 * @event destroyEvent
677 */
678 this.destroyEvent = new YAHOO.util.CustomEvent("destroy");
679
680 /**
681 * CustomEvent fired before the Module is shown
682 * @event beforeShowEvent
683 */
684 this.beforeShowEvent = new YAHOO.util.CustomEvent("beforeShow");
685
686 /**
687 * CustomEvent fired after the Module is shown
688 * @event showEvent
689 */
690 this.showEvent = new YAHOO.util.CustomEvent("show");
691
692 /**
693 * CustomEvent fired before the Module is hidden
694 * @event beforeHideEvent
695 */
696 this.beforeHideEvent = new YAHOO.util.CustomEvent("beforeHide");
697
698 /**
699 * CustomEvent fired after the Module is hidden
700 * @event hideEvent
701 */
702 this.hideEvent = new YAHOO.util.CustomEvent("hide");
703 },
704
705 /**
706 * String representing the current user-agent platform
707 * @property platform
708 * @type String
709 */
710 platform : function() {
711 var ua = navigator.userAgent.toLowerCase();
712 if (ua.indexOf("windows") != -1 || ua.indexOf("win32") != -1) {
713 return "windows";
714 } else if (ua.indexOf("macintosh") != -1) {
715 return "mac";
716 } else {
717 return false;
718 }
719 }(),
720
721 /**
722 * String representing the current user-agent browser
723 * @property browser
724 * @type String
725 */
726 browser : function() {
727 var ua = navigator.userAgent.toLowerCase();
728 if (ua.indexOf('opera')!=-1) { // Opera (check first in case of spoof)
729 return 'opera';
730 } else if (ua.indexOf('msie 7')!=-1) { // IE7
731 return 'ie7';
732 } else if (ua.indexOf('msie') !=-1) { // IE
733 return 'ie';
734 } else if (ua.indexOf('safari')!=-1) { // Safari (check before Gecko because it includes "like Gecko")
735 return 'safari';
736 } else if (ua.indexOf('gecko') != -1) { // Gecko
737 return 'gecko';
738 } else {
739 return false;
740 }
741 }(),
742
743 /**
744 * Boolean representing whether or not the current browsing context is secure (https)
745 * @property isSecure
746 * @type Boolean
747 */
748 isSecure : function() {
749 if (window.location.href.toLowerCase().indexOf("https") === 0) {
750 return true;
751 } else {
752 return false;
753 }
754 }(),
755
756 /**
757 * Initializes the custom events for Module which are fired automatically at appropriate times by the Module class.
758 */
759 initDefaultConfig : function() {
760 // Add properties //
761
762 /**
763 * Specifies whether the Module is visible on the page.
764 * @config visible
765 * @type Boolean
766 * @default true
767 */
768 this.cfg.addProperty("visible", { value:true, handler:this.configVisible, validator:this.cfg.checkBoolean } );
769
770 /**
771 * Object or array of objects representing the ContainerEffect classes that are active for animating the container.
772 * @config effect
773 * @type Object
774 * @default null
775 */
776 this.cfg.addProperty("effect", { suppressEvent:true, supercedes:["visible"] } );
777
778 /**
779 * Specifies whether to create a special proxy iframe to monitor for user font resizing in the document
780 * @config monitorresize
781 * @type Boolean
782 * @default true
783 */
784 this.cfg.addProperty("monitorresize", { value:true, handler:this.configMonitorResize } );
785 },
786
787 /**
788 * The Module class's initialization method, which is executed for Module and all of its subclasses. This method is automatically called by the constructor, and sets up all DOM references for pre-existing markup, and creates required markup if it is not already present.
789 * @method init
790 * @param {String} elThe element ID representing the Module <em>OR</em>
791 * @param {HTMLElement} elThe element representing the Module
792 * @param {Object} userConfigThe configuration Object literal containing the configuration that should be set for this module. See configuration documentation for more details.
793 */
794 init : function(el, userConfig) {
795
796 this.initEvents();
797
798 this.beforeInitEvent.fire(YAHOO.widget.Module);
799
800 /**
801 * The Module's Config object used for monitoring configuration properties.
802 * @property cfg
803 * @type YAHOO.util.Config
804 */
805 this.cfg = new YAHOO.util.Config(this);
806
807 if (this.isSecure) {
808 this.imageRoot = YAHOO.widget.Module.IMG_ROOT_SSL;
809 }
810
811 if (typeof el == "string") {
812 var elId = el;
813
814 el = document.getElementById(el);
815 if (! el) {
816 el = document.createElement("DIV");
817 el.id = elId;
818 }
819 }
820
821 this.element = el;
822
823 if (el.id) {
824 this.id = el.id;
825 }
826
827 var childNodes = this.element.childNodes;
828
829 if (childNodes) {
830 for (var i=0;i<childNodes.length;i++) {
831 var child = childNodes[i];
832 switch (child.className) {
833 case YAHOO.widget.Module.CSS_HEADER:
834 this.header = child;
835 break;
836 case YAHOO.widget.Module.CSS_BODY:
837 this.body = child;
838 break;
839 case YAHOO.widget.Module.CSS_FOOTER:
840 this.footer = child;
841 break;
842 }
843 }
844 }
845
846 this.initDefaultConfig();
847
848 YAHOO.util.Dom.addClass(this.element, YAHOO.widget.Module.CSS_MODULE);
849
850 if (userConfig) {
851 this.cfg.applyConfig(userConfig, true);
852 }
853
854 // Subscribe to the fireQueue() method of Config so that any queued configuration changes are
855 // excecuted upon render of the Module
856 if (! YAHOO.util.Config.alreadySubscribed(this.renderEvent, this.cfg.fireQueue, this.cfg)) {
857 this.renderEvent.subscribe(this.cfg.fireQueue, this.cfg, true);
858 }
859
860 this.initEvent.fire(YAHOO.widget.Module);
861 },
862
863 /**
864 * Initialized an empty IFRAME that is placed out of the visible area that can be used to detect text resize.
865 * @method initResizeMonitor
866 */
867 initResizeMonitor : function() {
868
869 if(this.browser != "opera") {
870
871 var resizeMonitor = document.getElementById("_yuiResizeMonitor");
872
873 if (! resizeMonitor) {
874
875 resizeMonitor = document.createElement("iframe");
876
877 var bIE = (this.browser.indexOf("ie") === 0);
878
879 if(this.isSecure &&
880 YAHOO.widget.Module.RESIZE_MONITOR_SECURE_URL &&
881 bIE) {
882
883 resizeMonitor.src =
884 YAHOO.widget.Module.RESIZE_MONITOR_SECURE_URL;
885
886 }
887
888 resizeMonitor.id = "_yuiResizeMonitor";
889 resizeMonitor.style.visibility = "hidden";
890
891 document.body.appendChild(resizeMonitor);
892
893 resizeMonitor.style.width = "10em";
894 resizeMonitor.style.height = "10em";
895 resizeMonitor.style.position = "absolute";
896
897 var nLeft = -1 * resizeMonitor.offsetWidth,
898 nTop = -1 * resizeMonitor.offsetHeight;
899
900 resizeMonitor.style.top = nTop + "px";
901 resizeMonitor.style.left = nLeft + "px";
902 resizeMonitor.style.borderStyle = "none";
903 resizeMonitor.style.borderWidth = "0";
904 YAHOO.util.Dom.setStyle(resizeMonitor, "opacity", "0");
905
906 resizeMonitor.style.visibility = "visible";
907
908 if(!bIE) {
909
910 var doc = resizeMonitor.contentWindow.document;
911
912 doc.open();
913 doc.close();
914
915 }
916
917 }
918
919 if(resizeMonitor && resizeMonitor.contentWindow) {
920
921 this.resizeMonitor = resizeMonitor;
922
923 YAHOO.util.Event.addListener(this.resizeMonitor.contentWindow, "resize", this.onDomResize, this, true);
924
925 }
926
927 }
928
929 },
930
931 /**
932 * Event handler fired when the resize monitor element is resized.
933 * @method onDomResize
934 * @param {DOMEvent} eThe DOM resize event
935 * @param {Object} objThe scope object passed to the handler
936 */
937 onDomResize : function(e, obj) {
938
939 var nLeft = -1 * this.resizeMonitor.offsetWidth,
940 nTop = -1 * this.resizeMonitor.offsetHeight;
941
942 this.resizeMonitor.style.top = nTop + "px";
943 this.resizeMonitor.style.left = nLeft + "px";
944
945 },
946
947 /**
948 * Sets the Module's header content to the HTML specified, or appends the passed element to the header. If no header is present, one will be automatically created.
949 * @method setHeader
950 * @param {String} headerContentThe HTML used to set the header <em>OR</em>
951 * @param {HTMLElement} headerContentThe HTMLElement to append to the header
952 */
953 setHeader : function(headerContent) {
954 if (! this.header) {
955 this.header = document.createElement("DIV");
956 this.header.className = YAHOO.widget.Module.CSS_HEADER;
957 }
958
959 if (typeof headerContent == "string") {
960 this.header.innerHTML = headerContent;
961 } else {
962 this.header.innerHTML = "";
963 this.header.appendChild(headerContent);
964 }
965
966 this.changeHeaderEvent.fire(headerContent);
967 this.changeContentEvent.fire();
968 },
969
970 /**
971 * Appends the passed element to the header. If no header is present, one will be automatically created.
972 * @method appendToHeader
973 * @param {HTMLElement} elementThe element to append to the header
974 */
975 appendToHeader : function(element) {
976 if (! this.header) {
977 this.header = document.createElement("DIV");
978 this.header.className = YAHOO.widget.Module.CSS_HEADER;
979 }
980
981 this.header.appendChild(element);
982 this.changeHeaderEvent.fire(element);
983 this.changeContentEvent.fire();
984 },
985
986 /**
987 * Sets the Module's body content to the HTML specified, or appends the passed element to the body. If no body is present, one will be automatically created.
988 * @method setBody
989 * @param {String} bodyContentThe HTML used to set the body <em>OR</em>
990 * @param {HTMLElement} bodyContentThe HTMLElement to append to the body
991 */
992 setBody : function(bodyContent) {
993 if (! this.body) {
994 this.body = document.createElement("DIV");
995 this.body.className = YAHOO.widget.Module.CSS_BODY;
996 }
997
998 if (typeof bodyContent == "string")
999 {
1000 this.body.innerHTML = bodyContent;
1001 } else {
1002 this.body.innerHTML = "";
1003 this.body.appendChild(bodyContent);
1004 }
1005
1006 this.changeBodyEvent.fire(bodyContent);
1007 this.changeContentEvent.fire();
1008 },
1009
1010 /**
1011 * Appends the passed element to the body. If no body is present, one will be automatically created.
1012 * @method appendToBody
1013 * @param {HTMLElement} elementThe element to append to the body
1014 */
1015 appendToBody : function(element) {
1016 if (! this.body) {
1017 this.body = document.createElement("DIV");
1018 this.body.className = YAHOO.widget.Module.CSS_BODY;
1019 }
1020
1021 this.body.appendChild(element);
1022 this.changeBodyEvent.fire(element);
1023 this.changeContentEvent.fire();
1024 },
1025
1026 /**
1027 * Sets the Module's footer content to the HTML specified, or appends the passed element to the footer. If no footer is present, one will be automatically created.
1028 * @method setFooter
1029 * @param {String} footerContentThe HTML used to set the footer <em>OR</em>
1030 * @param {HTMLElement} footerContentThe HTMLElement to append to the footer
1031 */
1032 setFooter : function(footerContent) {
1033 if (! this.footer) {
1034 this.footer = document.createElement("DIV");
1035 this.footer.className = YAHOO.widget.Module.CSS_FOOTER;
1036 }
1037
1038 if (typeof footerContent == "string") {
1039 this.footer.innerHTML = footerContent;
1040 } else {
1041 this.footer.innerHTML = "";
1042 this.footer.appendChild(footerContent);
1043 }
1044
1045 this.changeFooterEvent.fire(footerContent);
1046 this.changeContentEvent.fire();
1047 },
1048
1049 /**
1050 * Appends the passed element to the footer. If no footer is present, one will be automatically created.
1051 * @method appendToFooter
1052 * @param {HTMLElement} elementThe element to append to the footer
1053 */
1054 appendToFooter : function(element) {
1055 if (! this.footer) {
1056 this.footer = document.createElement("DIV");
1057 this.footer.className = YAHOO.widget.Module.CSS_FOOTER;
1058 }
1059
1060 this.footer.appendChild(element);
1061 this.changeFooterEvent.fire(element);
1062 this.changeContentEvent.fire();
1063 },
1064
1065 /**
1066 * Renders the Module by inserting the elements that are not already in the main Module into their correct places. Optionally appends the Module to the specified node prior to the render's execution. NOTE: For Modules without existing markup, the appendToNode argument is REQUIRED. If this argument is ommitted and the current element is not present in the document, the function will return false, indicating that the render was a failure.
1067 * @method render
1068 * @param {String} appendToNodeThe element id to which the Module should be appended to prior to rendering <em>OR</em>
1069 * @param {HTMLElement} appendToNodeThe element to which the Module should be appended to prior to rendering
1070 * @param {HTMLElement} moduleElementOPTIONAL. The element that represents the actual Standard Module container.
1071 * @return {Boolean} Success or failure of the render
1072 */
1073 render : function(appendToNode, moduleElement) {
1074 this.beforeRenderEvent.fire();
1075
1076 if (! moduleElement) {
1077 moduleElement = this.element;
1078 }
1079
1080 var me = this;
1081 var appendTo = function(element) {
1082 if (typeof element == "string") {
1083 element = document.getElementById(element);
1084 }
1085
1086 if (element) {
1087 element.appendChild(me.element);
1088 me.appendEvent.fire();
1089 }
1090 };
1091
1092 if (appendToNode) {
1093 appendTo(appendToNode);
1094 } else { // No node was passed in. If the element is not pre-marked up, this fails
1095 if (! YAHOO.util.Dom.inDocument(this.element)) {
1096 return false;
1097 }
1098 }
1099
1100 // Need to get everything into the DOM if it isn't already
1101
1102 if (this.header && ! YAHOO.util.Dom.inDocument(this.header)) {
1103 // There is a header, but it's not in the DOM yet... need to add it
1104 var firstChild = moduleElement.firstChild;
1105 if (firstChild) { // Insert before first child if exists
1106 moduleElement.insertBefore(this.header, firstChild);
1107 } else { // Append to empty body because there are no children
1108 moduleElement.appendChild(this.header);
1109 }
1110 }
1111
1112 if (this.body && ! YAHOO.util.Dom.inDocument(this.body)) {
1113 // There is a body, but it's not in the DOM yet... need to add it
1114 if (this.footer && YAHOO.util.Dom.isAncestor(this.moduleElement, this.footer)) { // Insert before footer if exists in DOM
1115 moduleElement.insertBefore(this.body, this.footer);
1116 } else { // Append to element because there is no footer
1117 moduleElement.appendChild(this.body);
1118 }
1119 }
1120
1121 if (this.footer && ! YAHOO.util.Dom.inDocument(this.footer)) {
1122 // There is a footer, but it's not in the DOM yet... need to add it
1123 moduleElement.appendChild(this.footer);
1124 }
1125
1126 this.renderEvent.fire();
1127 return true;
1128 },
1129
1130 /**
1131 * Removes the Module element from the DOM and sets all child elements to null.
1132 * @method destroy
1133 */
1134 destroy : function() {
1135 if (this.element) {
1136 var parent = this.element.parentNode;
1137 }
1138 if (parent) {
1139 parent.removeChild(this.element);
1140 }
1141
1142 this.element = null;
1143 this.header = null;
1144 this.body = null;
1145 this.footer = null;
1146
1147 this.destroyEvent.fire();
1148 },
1149
1150 /**
1151 * Shows the Module element by setting the visible configuration property to true. Also fires two events: beforeShowEvent prior to the visibility change, and showEvent after.
1152 * @method show
1153 */
1154 show : function() {
1155 this.cfg.setProperty("visible", true);
1156 },
1157
1158 /**
1159 * Hides the Module element by setting the visible configuration property to false. Also fires two events: beforeHideEvent prior to the visibility change, and hideEvent after.
1160 * @method hide
1161 */
1162 hide : function() {
1163 this.cfg.setProperty("visible", false);
1164 },
1165
1166 // BUILT-IN EVENT HANDLERS FOR MODULE //
1167
1168 /**
1169 * Default event handler for changing the visibility property of a Module. By default, this is achieved by switching the "display" style between "block" and "none".
1170 * This method is responsible for firing showEvent and hideEvent.
1171 * @param {String} typeThe CustomEvent type (usually the property name)
1172 * @param {Object[]} argsThe CustomEvent arguments. For configuration handlers, args[0] will equal the newly applied value for the property.
1173 * @param {Object} objThe scope object. For configuration handlers, this will usually equal the owner.
1174 * @method configVisible
1175 */
1176 configVisible : function(type, args, obj) {
1177 var visible = args[0];
1178 if (visible) {
1179 this.beforeShowEvent.fire();
1180 YAHOO.util.Dom.setStyle(this.element, "display", "block");
1181 this.showEvent.fire();
1182 } else {
1183 this.beforeHideEvent.fire();
1184 YAHOO.util.Dom.setStyle(this.element, "display", "none");
1185 this.hideEvent.fire();
1186 }
1187 },
1188
1189 /**
1190 * Default event handler for the "monitorresize" configuration property
1191 * @param {String} typeThe CustomEvent type (usually the property name)
1192 * @param {Object[]} argsThe CustomEvent arguments. For configuration handlers, args[0] will equal the newly applied value for the property.
1193 * @param {Object} objThe scope object. For configuration handlers, this will usually equal the owner.
1194 * @method configMonitorResize
1195 */
1196 configMonitorResize : function(type, args, obj) {
1197 var monitor = args[0];
1198 if (monitor) {
1199 this.initResizeMonitor();
1200 } else {
1201 YAHOO.util.Event.removeListener(this.resizeMonitor, "resize", this.onDomResize);
1202 this.resizeMonitor = null;
1203 }
1204 }
1205};
1206
1207/**
1208* Returns a String representation of the Object.
1209* @method toString
1210 * @return {String}The string representation of the Module
1211*/
1212YAHOO.widget.Module.prototype.toString = function() {
1213 return "Module " + this.id;
1214};
1215
1216/**
1217* Overlay is a Module that is absolutely positioned above the page flow. It has convenience methods for positioning and sizing, as well as options for controlling zIndex and constraining the Overlay's position to the current visible viewport. Overlay also contains a dynamicly generated IFRAME which is placed beneath it for Internet Explorer 6 and 5.x so that it will be properly rendered above SELECT elements.
1218* @class Overlay
1219* @namespace YAHOO.widget
1220* @extends YAHOO.widget.Module
1221 * @param {String} elThe element ID representing the Overlay <em>OR</em>
1222 * @param {HTMLElement} elThe element representing the Overlay
1223 * @param {Object} userConfigThe configuration object literal containing 10/23/2006the configuration that should be set for this Overlay. See configuration documentation for more details.
1224* @constructor
1225*/
1226YAHOO.widget.Overlay = function(el, userConfig) {
1227 YAHOO.widget.Overlay.superclass.constructor.call(this, el, userConfig);
1228};
1229
1230YAHOO.extend(YAHOO.widget.Overlay, YAHOO.widget.Module);
1231
1232/**
1233* The URL that will be placed in the iframe
1234* @property YAHOO.widget.Overlay.IFRAME_SRC
1235* @static
1236* @final
1237* @type String
1238*/
1239YAHOO.widget.Overlay.IFRAME_SRC = "javascript:false;"
1240
1241/**
1242* Constant representing the top left corner of an element, used for configuring the context element alignment
1243* @property YAHOO.widget.Overlay.TOP_LEFT
1244* @static
1245* @final
1246* @type String
1247*/
1248YAHOO.widget.Overlay.TOP_LEFT = "tl";
1249
1250/**
1251* Constant representing the top right corner of an element, used for configuring the context element alignment
1252* @property YAHOO.widget.Overlay.TOP_RIGHT
1253* @static
1254* @final
1255* @type String
1256*/
1257YAHOO.widget.Overlay.TOP_RIGHT = "tr";
1258
1259/**
1260* Constant representing the top bottom left corner of an element, used for configuring the context element alignment
1261* @property YAHOO.widget.Overlay.BOTTOM_LEFT
1262* @static
1263* @final
1264* @type String
1265*/
1266YAHOO.widget.Overlay.BOTTOM_LEFT = "bl";
1267
1268/**
1269* Constant representing the bottom right corner of an element, used for configuring the context element alignment
1270* @property YAHOO.widget.Overlay.BOTTOM_RIGHT
1271* @static
1272* @final
1273* @type String
1274*/
1275YAHOO.widget.Overlay.BOTTOM_RIGHT = "br";
1276
1277/**
1278* Constant representing the default CSS class used for an Overlay
1279* @property YAHOO.widget.Overlay.CSS_OVERLAY
1280* @static
1281* @final
1282* @type String
1283*/
1284YAHOO.widget.Overlay.CSS_OVERLAY = "overlay";
1285
1286/**
1287* The Overlay initialization method, which is executed for Overlay and all of its subclasses. This method is automatically called by the constructor, and sets up all DOM references for pre-existing markup, and creates required markup if it is not already present.
1288* @method init
1289 * @param {String} elThe element ID representing the Overlay <em>OR</em>
1290 * @param {HTMLElement} elThe element representing the Overlay
1291 * @param {Object} userConfigThe configuration object literal containing the configuration that should be set for this Overlay. See configuration documentation for more details.
1292*/
1293YAHOO.widget.Overlay.prototype.init = function(el, userConfig) {
1294 YAHOO.widget.Overlay.superclass.init.call(this, el/*, userConfig*/); // Note that we don't pass the user config in here yet because we only want it executed once, at the lowest subclass level
1295
1296 this.beforeInitEvent.fire(YAHOO.widget.Overlay);
1297
1298 YAHOO.util.Dom.addClass(this.element, YAHOO.widget.Overlay.CSS_OVERLAY);
1299
1300 if (userConfig) {
1301 this.cfg.applyConfig(userConfig, true);
1302 }
1303
1304 if (this.platform == "mac" && this.browser == "gecko") {
1305 if (! YAHOO.util.Config.alreadySubscribed(this.showEvent,this.showMacGeckoScrollbars,this)) {
1306 this.showEvent.subscribe(this.showMacGeckoScrollbars,this,true);
1307 }
1308 if (! YAHOO.util.Config.alreadySubscribed(this.hideEvent,this.hideMacGeckoScrollbars,this)) {
1309 this.hideEvent.subscribe(this.hideMacGeckoScrollbars,this,true);
1310 }
1311 }
1312
1313 this.initEvent.fire(YAHOO.widget.Overlay);
1314};
1315
1316/**
1317* Initializes the custom events for Overlay which are fired automatically at appropriate times by the Overlay class.
1318* @method initEvents
1319*/
1320YAHOO.widget.Overlay.prototype.initEvents = function() {
1321 YAHOO.widget.Overlay.superclass.initEvents.call(this);
1322
1323 /**
1324 * CustomEvent fired before the Overlay is moved.
1325 * @event beforeMoveEvent
1326 * @param {Number} xx coordinate
1327 * @param {Number} yy coordinate
1328 */
1329 this.beforeMoveEvent = new YAHOO.util.CustomEvent("beforeMove", this);
1330
1331 /**
1332 * CustomEvent fired after the Overlay is moved.
1333 * @event moveEvent
1334 * @param {Number} xx coordinate
1335 * @param {Number} yy coordinate
1336 */
1337 this.moveEvent = new YAHOO.util.CustomEvent("move", this);
1338};
1339
1340/**
1341* Initializes the class's configurable properties which can be changed using the Overlay's Config object (cfg).
1342* @method initDefaultConfig
1343*/
1344YAHOO.widget.Overlay.prototype.initDefaultConfig = function() {
1345 YAHOO.widget.Overlay.superclass.initDefaultConfig.call(this);
1346
1347 // Add overlay config properties //
1348
1349 /**
1350 * The absolute x-coordinate position of the Overlay
1351 * @config x
1352 * @type Number
1353 * @default null
1354 */
1355 this.cfg.addProperty("x", { handler:this.configX, validator:this.cfg.checkNumber, suppressEvent:true, supercedes:["iframe"] } );
1356
1357 /**
1358 * The absolute y-coordinate position of the Overlay
1359 * @config y
1360 * @type Number
1361 * @default null
1362 */
1363 this.cfg.addProperty("y", { handler:this.configY, validator:this.cfg.checkNumber, suppressEvent:true, supercedes:["iframe"] } );
1364
1365 /**
1366 * An array with the absolute x and y positions of the Overlay
1367 * @config xy
1368 * @type Number[]
1369 * @default null
1370 */
1371 this.cfg.addProperty("xy",{ handler:this.configXY, suppressEvent:true, supercedes:["iframe"] } );
1372
1373 /**
1374 * The array of context arguments for context-sensitive positioning. The format is: [id or element, element corner, context corner]. For example, setting this property to ["img1", "tl", "bl"] would align the Overlay's top left corner to the context element's bottom left corner.
1375 * @config context
1376 * @type Array
1377 * @default null
1378 */
1379 this.cfg.addProperty("context",{ handler:this.configContext, suppressEvent:true, supercedes:["iframe"] } );
1380
1381 /**
1382 * True if the Overlay should be anchored to the center of the viewport.
1383 * @config fixedcenter
1384 * @type Boolean
1385 * @default false
1386 */
1387 this.cfg.addProperty("fixedcenter", { value:false, handler:this.configFixedCenter, validator:this.cfg.checkBoolean, supercedes:["iframe","visible"] } );
1388
1389 /**
1390 * CSS width of the Overlay.
1391 * @config width
1392 * @type String
1393 * @default null
1394 */
1395 this.cfg.addProperty("width", { handler:this.configWidth, suppressEvent:true, supercedes:["iframe"] } );
1396
1397 /**
1398 * CSS height of the Overlay.
1399 * @config height
1400 * @type String
1401 * @default null
1402 */
1403 this.cfg.addProperty("height", { handler:this.configHeight, suppressEvent:true, supercedes:["iframe"] } );
1404
1405 /**
1406 * CSS z-index of the Overlay.
1407 * @config zIndex
1408 * @type Number
1409 * @default null
1410 */
1411 this.cfg.addProperty("zIndex", { value:null, handler:this.configzIndex } );
1412
1413 /**
1414 * True if the Overlay should be prevented from being positioned out of the viewport.
1415 * @config constraintoviewport
1416 * @type Boolean
1417 * @default false
1418 */
1419 this.cfg.addProperty("constraintoviewport", { value:false, handler:this.configConstrainToViewport, validator:this.cfg.checkBoolean, supercedes:["iframe","x","y","xy"] } );
1420
1421 /**
1422 * True if the Overlay should have an IFRAME shim (for correcting the select z-index bug in IE6 and below).
1423 * @config iframe
1424 * @type Boolean
1425 * @default true for IE6 and below, false for all others
1426 */
1427 this.cfg.addProperty("iframe", { value:(this.browser == "ie" ? true : false), handler:this.configIframe, validator:this.cfg.checkBoolean, supercedes:["zIndex"] } );
1428};
1429
1430/**
1431* Moves the Overlay to the specified position. This function is identical to calling this.cfg.setProperty("xy", [x,y]);
1432* @method moveTo
1433 * @param {Number} xThe Overlay's new x position
1434 * @param {Number} yThe Overlay's new y position
1435*/
1436YAHOO.widget.Overlay.prototype.moveTo = function(x, y) {
1437 this.cfg.setProperty("xy",[x,y]);
1438};
1439
1440/**
1441* Adds a special CSS class to the Overlay when Mac/Gecko is in use, to work around a Gecko bug where
1442* scrollbars cannot be hidden. See https://bugzilla.mozilla.org/show_bug.cgi?id=187435
1443* @method hideMacGeckoScrollbars
1444*/
1445YAHOO.widget.Overlay.prototype.hideMacGeckoScrollbars = function() {
1446 YAHOO.util.Dom.removeClass(this.element, "show-scrollbars");
1447 YAHOO.util.Dom.addClass(this.element, "hide-scrollbars");
1448};
1449
1450/**
1451* Removes a special CSS class from the Overlay when Mac/Gecko is in use, to work around a Gecko bug where
1452* scrollbars cannot be hidden. See https://bugzilla.mozilla.org/show_bug.cgi?id=187435
1453* @method showMacGeckoScrollbars
1454*/
1455YAHOO.widget.Overlay.prototype.showMacGeckoScrollbars = function() {
1456 YAHOO.util.Dom.removeClass(this.element, "hide-scrollbars");
1457 YAHOO.util.Dom.addClass(this.element, "show-scrollbars");
1458};
1459
1460// BEGIN BUILT-IN PROPERTY EVENT HANDLERS //
1461
1462/**
1463* The default event handler fired when the "visible" property is changed. This method is responsible for firing showEvent and hideEvent.
1464* @method configVisible
1465 * @param {String} typeThe CustomEvent type (usually the property name)
1466 * @param {Object[]} argsThe CustomEvent arguments. For configuration handlers, args[0] will equal the newly applied value for the property.
1467 * @param {Object} objThe scope object. For configuration handlers, this will usually equal the owner.
1468*/
1469YAHOO.widget.Overlay.prototype.configVisible = function(type, args, obj) {
1470 var visible = args[0];
1471
1472 var currentVis = YAHOO.util.Dom.getStyle(this.element, "visibility");
1473
1474 if (currentVis == "inherit") {
1475 var e = this.element.parentNode;
1476 while (e.nodeType != 9 && e.nodeType != 11) {
1477 currentVis = YAHOO.util.Dom.getStyle(e, "visibility");
1478 if (currentVis != "inherit") { break; }
1479 e = e.parentNode;
1480 }
1481 if (currentVis == "inherit") {
1482 currentVis = "visible";
1483 }
1484 }
1485
1486 var effect = this.cfg.getProperty("effect");
1487
1488 var effectInstances = [];
1489 if (effect) {
1490 if (effect instanceof Array) {
1491 for (var i=0;i<effect.length;i++) {
1492 var eff = effect[i];
1493 effectInstances[effectInstances.length] = eff.effect(this, eff.duration);
1494 }
1495 } else {
1496 effectInstances[effectInstances.length] = effect.effect(this, effect.duration);
1497 }
1498 }
1499
1500 var isMacGecko = (this.platform == "mac" && this.browser == "gecko");
1501
1502 if (visible) { // Show
1503 if (isMacGecko) {
1504 this.showMacGeckoScrollbars();
1505 }
1506
1507 if (effect) { // Animate in
1508 if (visible) { // Animate in if not showing
1509 if (currentVis != "visible" || currentVis === "") {
1510 this.beforeShowEvent.fire();
1511 for (var j=0;j<effectInstances.length;j++) {
1512 var ei = effectInstances[j];
1513 if (j === 0 && ! YAHOO.util.Config.alreadySubscribed(ei.animateInCompleteEvent,this.showEvent.fire,this.showEvent)) {
1514 ei.animateInCompleteEvent.subscribe(this.showEvent.fire,this.showEvent,true); // Delegate showEvent until end of animateInComplete
1515 }
1516 ei.animateIn();
1517 }
1518 }
1519 }
1520 } else { // Show
1521 if (currentVis != "visible" || currentVis === "") {
1522 this.beforeShowEvent.fire();
1523 YAHOO.util.Dom.setStyle(this.element, "visibility", "visible");
1524 this.cfg.refireEvent("iframe");
1525 this.showEvent.fire();
1526 }
1527 }
1528
1529 } else { // Hide
1530 if (isMacGecko) {
1531 this.hideMacGeckoScrollbars();
1532 }
1533
1534 if (effect) { // Animate out if showing
1535 if (currentVis == "visible") {
1536 this.beforeHideEvent.fire();
1537 for (var k=0;k<effectInstances.length;k++) {
1538 var h = effectInstances[k];
1539 if (k === 0 && ! YAHOO.util.Config.alreadySubscribed(h.animateOutCompleteEvent,this.hideEvent.fire,this.hideEvent)) {
1540 h.animateOutCompleteEvent.subscribe(this.hideEvent.fire,this.hideEvent,true); // Delegate hideEvent until end of animateOutComplete
1541 }
1542 h.animateOut();
1543 }
1544 } else if (currentVis === "") {
1545 YAHOO.util.Dom.setStyle(this.element, "visibility", "hidden");
1546 }
1547 } else { // Simple hide
1548 if (currentVis == "visible" || currentVis === "") {
1549 this.beforeHideEvent.fire();
1550 YAHOO.util.Dom.setStyle(this.element, "visibility", "hidden");
1551 this.cfg.refireEvent("iframe");
1552 this.hideEvent.fire();
1553 }
1554 }
1555 }
1556};
1557
1558/**
1559* Center event handler used for centering on scroll/resize, but only if the Overlay is visible
1560* @method doCenterOnDOMEvent
1561*/
1562YAHOO.widget.Overlay.prototype.doCenterOnDOMEvent = function() {
1563 if (this.cfg.getProperty("visible")) {
1564 this.center();
1565 }
1566};
1567
1568/**
1569* The default event handler fired when the "fixedcenter" property is changed.
1570* @method configFixedCenter
1571 * @param {String} typeThe CustomEvent type (usually the property name)
1572 * @param {Object[]} argsThe CustomEvent arguments. For configuration handlers, args[0] will equal the newly applied value for the property.
1573 * @param {Object} objThe scope object. For configuration handlers, this will usually equal the owner.
1574*/
1575YAHOO.widget.Overlay.prototype.configFixedCenter = function(type, args, obj) {
1576 var val = args[0];
1577
1578 if (val) {
1579 this.center();
1580
1581 if (! YAHOO.util.Config.alreadySubscribed(this.beforeShowEvent, this.center, this)) {
1582 this.beforeShowEvent.subscribe(this.center, this, true);
1583 }
1584
1585 if (! YAHOO.util.Config.alreadySubscribed(YAHOO.widget.Overlay.windowResizeEvent, this.doCenterOnDOMEvent, this)) {
1586 YAHOO.widget.Overlay.windowResizeEvent.subscribe(this.doCenterOnDOMEvent, this, true);
1587 }
1588
1589 if (! YAHOO.util.Config.alreadySubscribed(YAHOO.widget.Overlay.windowScrollEvent, this.doCenterOnDOMEvent, this)) {
1590 YAHOO.widget.Overlay.windowScrollEvent.subscribe( this.doCenterOnDOMEvent, this, true);
1591 }
1592 } else {
1593 YAHOO.widget.Overlay.windowResizeEvent.unsubscribe(this.doCenterOnDOMEvent, this);
1594 YAHOO.widget.Overlay.windowScrollEvent.unsubscribe(this.doCenterOnDOMEvent, this);
1595 }
1596};
1597
1598/**
1599* The default event handler fired when the "height" property is changed.
1600* @method configHeight
1601 * @param {String} typeThe CustomEvent type (usually the property name)
1602 * @param {Object[]} argsThe CustomEvent arguments. For configuration handlers, args[0] will equal the newly applied value for the property.
1603 * @param {Object} objThe scope object. For configuration handlers, this will usually equal the owner.
1604*/
1605YAHOO.widget.Overlay.prototype.configHeight = function(type, args, obj) {
1606 var height = args[0];
1607 var el = this.element;
1608 YAHOO.util.Dom.setStyle(el, "height", height);
1609 this.cfg.refireEvent("iframe");
1610};
1611
1612/**
1613* The default event handler fired when the "width" property is changed.
1614* @method configWidth
1615 * @param {String} typeThe CustomEvent type (usually the property name)
1616 * @param {Object[]} argsThe CustomEvent arguments. For configuration handlers, args[0] will equal the newly applied value for the property.
1617 * @param {Object} objThe scope object. For configuration handlers, this will usually equal the owner.
1618*/
1619YAHOO.widget.Overlay.prototype.configWidth = function(type, args, obj) {
1620 var width = args[0];
1621 var el = this.element;
1622 YAHOO.util.Dom.setStyle(el, "width", width);
1623 this.cfg.refireEvent("iframe");
1624};
1625
1626/**
1627* The default event handler fired when the "zIndex" property is changed.
1628* @method configzIndex
1629 * @param {String} typeThe CustomEvent type (usually the property name)
1630 * @param {Object[]} argsThe CustomEvent arguments. For configuration handlers, args[0] will equal the newly applied value for the property.
1631 * @param {Object} objThe scope object. For configuration handlers, this will usually equal the owner.
1632*/
1633YAHOO.widget.Overlay.prototype.configzIndex = function(type, args, obj) {
1634 var zIndex = args[0];
1635
1636 var el = this.element;
1637
1638 if (! zIndex) {
1639 zIndex = YAHOO.util.Dom.getStyle(el, "zIndex");
1640 if (! zIndex || isNaN(zIndex)) {
1641 zIndex = 0;
1642 }
1643 }
1644
1645 if (this.iframe) {
1646 if (zIndex <= 0) {
1647 zIndex = 1;
1648 }
1649 YAHOO.util.Dom.setStyle(this.iframe, "zIndex", (zIndex-1));
1650 }
1651
1652 YAHOO.util.Dom.setStyle(el, "zIndex", zIndex);
1653 this.cfg.setProperty("zIndex", zIndex, true);
1654};
1655
1656/**
1657* The default event handler fired when the "xy" property is changed.
1658* @method configXY
1659 * @param {String} typeThe CustomEvent type (usually the property name)
1660 * @param {Object[]} argsThe CustomEvent arguments. For configuration handlers, args[0] will equal the newly applied value for the property.
1661 * @param {Object} objThe scope object. For configuration handlers, this will usually equal the owner.
1662*/
1663YAHOO.widget.Overlay.prototype.configXY = function(type, args, obj) {
1664 var pos = args[0];
1665 var x = pos[0];
1666 var y = pos[1];
1667
1668 this.cfg.setProperty("x", x);
1669 this.cfg.setProperty("y", y);
1670
1671 this.beforeMoveEvent.fire([x,y]);
1672
1673 x = this.cfg.getProperty("x");
1674 y = this.cfg.getProperty("y");
1675
1676 this.cfg.refireEvent("iframe");
1677 this.moveEvent.fire([x,y]);
1678};
1679
1680/**
1681* The default event handler fired when the "x" property is changed.
1682* @method configX
1683 * @param {String} typeThe CustomEvent type (usually the property name)
1684 * @param {Object[]} argsThe CustomEvent arguments. For configuration handlers, args[0] will equal the newly applied value for the property.
1685 * @param {Object} objThe scope object. For configuration handlers, this will usually equal the owner.
1686*/
1687YAHOO.widget.Overlay.prototype.configX = function(type, args, obj) {
1688 var x = args[0];
1689 var y = this.cfg.getProperty("y");
1690
1691 this.cfg.setProperty("x", x, true);
1692 this.cfg.setProperty("y", y, true);
1693
1694 this.beforeMoveEvent.fire([x,y]);
1695
1696 x = this.cfg.getProperty("x");
1697 y = this.cfg.getProperty("y");
1698
1699 YAHOO.util.Dom.setX(this.element, x, true);
1700
1701 this.cfg.setProperty("xy", [x, y], true);
1702
1703 this.cfg.refireEvent("iframe");
1704 this.moveEvent.fire([x, y]);
1705};
1706
1707/**
1708* The default event handler fired when the "y" property is changed.
1709* @method configY
1710 * @param {String} typeThe CustomEvent type (usually the property name)
1711 * @param {Object[]} argsThe CustomEvent arguments. For configuration handlers, args[0] will equal the newly applied value for the property.
1712 * @param {Object} objThe scope object. For configuration handlers, this will usually equal the owner.
1713*/
1714YAHOO.widget.Overlay.prototype.configY = function(type, args, obj) {
1715 var x = this.cfg.getProperty("x");
1716 var y = args[0];
1717
1718 this.cfg.setProperty("x", x, true);
1719 this.cfg.setProperty("y", y, true);
1720
1721 this.beforeMoveEvent.fire([x,y]);
1722
1723 x = this.cfg.getProperty("x");
1724 y = this.cfg.getProperty("y");
1725
1726 YAHOO.util.Dom.setY(this.element, y, true);
1727
1728 this.cfg.setProperty("xy", [x, y], true);
1729
1730 this.cfg.refireEvent("iframe");
1731 this.moveEvent.fire([x, y]);
1732};
1733
1734/**
1735* Shows the iframe shim, if it has been enabled
1736* @method showIframe
1737*/
1738YAHOO.widget.Overlay.prototype.showIframe = function() {
1739 if (this.iframe) {
1740 this.iframe.style.display = "block";
1741 }
1742};
1743
1744/**
1745* Hides the iframe shim, if it has been enabled
1746* @method hideIframe
1747*/
1748YAHOO.widget.Overlay.prototype.hideIframe = function() {
1749 if (this.iframe) {
1750 this.iframe.style.display = "none";
1751 }
1752};
1753
1754/**
1755* The default event handler fired when the "iframe" property is changed.
1756* @method configIframe
1757 * @param {String} typeThe CustomEvent type (usually the property name)
1758 * @param {Object[]} argsThe CustomEvent arguments. For configuration handlers, args[0] will equal the newly applied value for the property.
1759 * @param {Object} objThe scope object. For configuration handlers, this will usually equal the owner.
1760*/
1761YAHOO.widget.Overlay.prototype.configIframe = function(type, args, obj) {
1762
1763 var val = args[0];
1764
1765 if (val) { // IFRAME shim is enabled
1766
1767 if (! YAHOO.util.Config.alreadySubscribed(this.showEvent, this.showIframe, this)) {
1768 this.showEvent.subscribe(this.showIframe, this, true);
1769 }
1770 if (! YAHOO.util.Config.alreadySubscribed(this.hideEvent, this.hideIframe, this)) {
1771 this.hideEvent.subscribe(this.hideIframe, this, true);
1772 }
1773
1774 var x = this.cfg.getProperty("x");
1775 var y = this.cfg.getProperty("y");
1776
1777 if (! x || ! y) {
1778 this.syncPosition();
1779 x = this.cfg.getProperty("x");
1780 y = this.cfg.getProperty("y");
1781 }
1782
1783 if (! isNaN(x) && ! isNaN(y)) {
1784 if (! this.iframe) {
1785 this.iframe = document.createElement("iframe");
1786 if (this.isSecure) {
1787 this.iframe.src = this.imageRoot + YAHOO.widget.Overlay.IFRAME_SRC;
1788 }
1789
1790 var parent = this.element.parentNode;
1791 if (parent) {
1792 parent.appendChild(this.iframe);
1793 } else {
1794 document.body.appendChild(this.iframe);
1795 }
1796
1797 YAHOO.util.Dom.setStyle(this.iframe, "position", "absolute");
1798 YAHOO.util.Dom.setStyle(this.iframe, "border", "none");
1799 YAHOO.util.Dom.setStyle(this.iframe, "margin", "0");
1800 YAHOO.util.Dom.setStyle(this.iframe, "padding", "0");
1801 YAHOO.util.Dom.setStyle(this.iframe, "opacity", "0");
1802 if (this.cfg.getProperty("visible")) {
1803 this.showIframe();
1804 } else {
1805 this.hideIframe();
1806 }
1807 }
1808
1809 var iframeDisplay = YAHOO.util.Dom.getStyle(this.iframe, "display");
1810
1811 if (iframeDisplay == "none") {
1812 this.iframe.style.display = "block";
1813 }
1814
1815 YAHOO.util.Dom.setXY(this.iframe, [x,y]);
1816
1817 var width = this.element.clientWidth;
1818 var height = this.element.clientHeight;
1819
1820 YAHOO.util.Dom.setStyle(this.iframe, "width", (width+2) + "px");
1821 YAHOO.util.Dom.setStyle(this.iframe, "height", (height+2) + "px");
1822
1823 if (iframeDisplay == "none") {
1824 this.iframe.style.display = "none";
1825 }
1826 }
1827 } else {
1828 if (this.iframe) {
1829 this.iframe.style.display = "none";
1830 }
1831 this.showEvent.unsubscribe(this.showIframe, this);
1832 this.hideEvent.unsubscribe(this.hideIframe, this);
1833 }
1834};
1835
1836
1837/**
1838* The default event handler fired when the "constraintoviewport" property is changed.
1839* @method configConstrainToViewport
1840 * @param {String} typeThe CustomEvent type (usually the property name)
1841 * @param {Object[]} argsThe CustomEvent arguments. For configuration handlers, args[0] will equal the newly applied value for the property.
1842 * @param {Object} objThe scope object. For configuration handlers, this will usually equal the owner.
1843*/
1844YAHOO.widget.Overlay.prototype.configConstrainToViewport = function(type, args, obj) {
1845 var val = args[0];
1846 if (val) {
1847 if (! YAHOO.util.Config.alreadySubscribed(this.beforeMoveEvent, this.enforceConstraints, this)) {
1848 this.beforeMoveEvent.subscribe(this.enforceConstraints, this, true);
1849 }
1850 } else {
1851 this.beforeMoveEvent.unsubscribe(this.enforceConstraints, this);
1852 }
1853};
1854
1855/**
1856* The default event handler fired when the "context" property is changed.
1857* @method configContext
1858 * @param {String} typeThe CustomEvent type (usually the property name)
1859 * @param {Object[]} argsThe CustomEvent arguments. For configuration handlers, args[0] will equal the newly applied value for the property.
1860 * @param {Object} objThe scope object. For configuration handlers, this will usually equal the owner.
1861*/
1862YAHOO.widget.Overlay.prototype.configContext = function(type, args, obj) {
1863 var contextArgs = args[0];
1864
1865 if (contextArgs) {
1866 var contextEl = contextArgs[0];
1867 var elementMagnetCorner = contextArgs[1];
1868 var contextMagnetCorner = contextArgs[2];
1869
1870 if (contextEl) {
1871 if (typeof contextEl == "string") {
1872 this.cfg.setProperty("context", [document.getElementById(contextEl),elementMagnetCorner,contextMagnetCorner], true);
1873 }
1874
1875 if (elementMagnetCorner && contextMagnetCorner) {
1876 this.align(elementMagnetCorner, contextMagnetCorner);
1877 }
1878 }
1879 }
1880};
1881
1882
1883// END BUILT-IN PROPERTY EVENT HANDLERS //
1884
1885/**
1886* Aligns the Overlay to its context element using the specified corner points (represented by the constants TOP_LEFT, TOP_RIGHT, BOTTOM_LEFT, and BOTTOM_RIGHT.
1887* @method align
1888 * @param {String} elementAlign The String representing the corner of the Overlay that should be aligned to the context element
1889 * @param {String} contextAlign The corner of the context element that the elementAlign corner should stick to.
1890*/
1891YAHOO.widget.Overlay.prototype.align = function(elementAlign, contextAlign) {
1892 var contextArgs = this.cfg.getProperty("context");
1893 if (contextArgs) {
1894 var context = contextArgs[0];
1895
1896 var element = this.element;
1897 var me = this;
1898
1899 if (! elementAlign) {
1900 elementAlign = contextArgs[1];
1901 }
1902
1903 if (! contextAlign) {
1904 contextAlign = contextArgs[2];
1905 }
1906
1907 if (element && context) {
1908 var elementRegion = YAHOO.util.Dom.getRegion(element);
1909 var contextRegion = YAHOO.util.Dom.getRegion(context);
1910
1911 var doAlign = function(v,h) {
1912 switch (elementAlign) {
1913 case YAHOO.widget.Overlay.TOP_LEFT:
1914 me.moveTo(h,v);
1915 break;
1916 case YAHOO.widget.Overlay.TOP_RIGHT:
1917 me.moveTo(h-element.offsetWidth,v);
1918 break;
1919 case YAHOO.widget.Overlay.BOTTOM_LEFT:
1920 me.moveTo(h,v-element.offsetHeight);
1921 break;
1922 case YAHOO.widget.Overlay.BOTTOM_RIGHT:
1923 me.moveTo(h-element.offsetWidth,v-element.offsetHeight);
1924 break;
1925 }
1926 };
1927
1928 switch (contextAlign) {
1929 case YAHOO.widget.Overlay.TOP_LEFT:
1930 doAlign(contextRegion.top, contextRegion.left);
1931 break;
1932 case YAHOO.widget.Overlay.TOP_RIGHT:
1933 doAlign(contextRegion.top, contextRegion.right);
1934 break;
1935 case YAHOO.widget.Overlay.BOTTOM_LEFT:
1936 doAlign(contextRegion.bottom, contextRegion.left);
1937 break;
1938 case YAHOO.widget.Overlay.BOTTOM_RIGHT:
1939 doAlign(contextRegion.bottom, contextRegion.right);
1940 break;
1941 }
1942 }
1943 }
1944};
1945
1946/**
1947* The default event handler executed when the moveEvent is fired, if the "constraintoviewport" is set to true.
1948* @method enforceConstraints
1949 * @param {String} typeThe CustomEvent type (usually the property name)
1950 * @param {Object[]} argsThe CustomEvent arguments. For configuration handlers, args[0] will equal the newly applied value for the property.
1951 * @param {Object} objThe scope object. For configuration handlers, this will usually equal the owner.
1952*/
1953YAHOO.widget.Overlay.prototype.enforceConstraints = function(type, args, obj) {
1954 var pos = args[0];
1955
1956 var x = pos[0];
1957 var y = pos[1];
1958
1959 var offsetHeight = this.element.offsetHeight;
1960 var offsetWidth = this.element.offsetWidth;
1961
1962 var viewPortWidth = YAHOO.util.Dom.getViewportWidth();
1963 var viewPortHeight = YAHOO.util.Dom.getViewportHeight();
1964
1965 var scrollX = document.documentElement.scrollLeft || document.body.scrollLeft;
1966 var scrollY = document.documentElement.scrollTop || document.body.scrollTop;
1967
1968 var topConstraint = scrollY + 10;
1969 var leftConstraint = scrollX + 10;
1970 var bottomConstraint = scrollY + viewPortHeight - offsetHeight - 10;
1971 var rightConstraint = scrollX + viewPortWidth - offsetWidth - 10;
1972
1973 if (x < leftConstraint) {
1974 x = leftConstraint;
1975 } else if (x > rightConstraint) {
1976 x = rightConstraint;
1977 }
1978
1979 if (y < topConstraint) {
1980 y = topConstraint;
1981 } else if (y > bottomConstraint) {
1982 y = bottomConstraint;
1983 }
1984
1985 this.cfg.setProperty("x", x, true);
1986 this.cfg.setProperty("y", y, true);
1987 this.cfg.setProperty("xy", [x,y], true);
1988};
1989
1990/**
1991* Centers the container in the viewport.
1992* @method center
1993*/
1994YAHOO.widget.Overlay.prototype.center = function() {
1995 var scrollX = document.documentElement.scrollLeft || document.body.scrollLeft;
1996 var scrollY = document.documentElement.scrollTop || document.body.scrollTop;
1997
1998 var viewPortWidth = YAHOO.util.Dom.getClientWidth();
1999 var viewPortHeight = YAHOO.util.Dom.getClientHeight();
2000
2001 var elementWidth = this.element.offsetWidth;
2002 var elementHeight = this.element.offsetHeight;
2003
2004 var x = (viewPortWidth / 2) - (elementWidth / 2) + scrollX;
2005 var y = (viewPortHeight / 2) - (elementHeight / 2) + scrollY;
2006
2007 this.cfg.setProperty("xy", [parseInt(x, 10), parseInt(y, 10)]);
2008
2009 this.cfg.refireEvent("iframe");
2010};
2011
2012/**
2013* Synchronizes the Panel's "xy", "x", and "y" properties with the Panel's position in the DOM. This is primarily used to update position information during drag & drop.
2014* @method syncPosition
2015*/
2016YAHOO.widget.Overlay.prototype.syncPosition = function() {
2017 var pos = YAHOO.util.Dom.getXY(this.element);
2018 this.cfg.setProperty("x", pos[0], true);
2019 this.cfg.setProperty("y", pos[1], true);
2020 this.cfg.setProperty("xy", pos, true);
2021};
2022
2023/**
2024* Event handler fired when the resize monitor element is resized.
2025* @method onDomResize
2026 * @param {DOMEvent} eThe resize DOM event
2027 * @param {Object} objThe scope object
2028*/
2029YAHOO.widget.Overlay.prototype.onDomResize = function(e, obj) {
2030 YAHOO.widget.Overlay.superclass.onDomResize.call(this, e, obj);
2031 var me = this;
2032 setTimeout(function() {
2033 me.syncPosition();
2034 me.cfg.refireEvent("iframe");
2035 me.cfg.refireEvent("context");
2036 }, 0);
2037};
2038
2039/**
2040* Removes the Overlay element from the DOM and sets all child elements to null.
2041* @method destroy
2042*/
2043YAHOO.widget.Overlay.prototype.destroy = function() {
2044 if (this.iframe) {
2045 this.iframe.parentNode.removeChild(this.iframe);
2046 }
2047
2048 this.iframe = null;
2049
2050 YAHOO.widget.Overlay.superclass.destroy.call(this);
2051};
2052
2053/**
2054* Returns a String representation of the object.
2055* @method toString
2056* @return {String} The string representation of the Overlay.
2057*/
2058YAHOO.widget.Overlay.prototype.toString = function() {
2059 return "Overlay " + this.id;
2060};
2061
2062/**
2063* A singleton CustomEvent used for reacting to the DOM event for window scroll
2064* @event YAHOO.widget.Overlay.windowScrollEvent
2065*/
2066YAHOO.widget.Overlay.windowScrollEvent = new YAHOO.util.CustomEvent("windowScroll");
2067
2068/**
2069* A singleton CustomEvent used for reacting to the DOM event for window resize
2070* @event YAHOO.widget.Overlay.windowResizeEvent
2071*/
2072YAHOO.widget.Overlay.windowResizeEvent = new YAHOO.util.CustomEvent("windowResize");
2073
2074/**
2075* The DOM event handler used to fire the CustomEvent for window scroll
2076* @method YAHOO.widget.Overlay.windowScrollHandler
2077* @static
2078* @param {DOMEvent} e The DOM scroll event
2079*/
2080YAHOO.widget.Overlay.windowScrollHandler = function(e) {
2081 if (YAHOO.widget.Module.prototype.browser == "ie" || YAHOO.widget.Module.prototype.browser == "ie7") {
2082 if (! window.scrollEnd) {
2083 window.scrollEnd = -1;
2084 }
2085 clearTimeout(window.scrollEnd);
2086 window.scrollEnd = setTimeout(function() { YAHOO.widget.Overlay.windowScrollEvent.fire(); }, 1);
2087 } else {
2088 YAHOO.widget.Overlay.windowScrollEvent.fire();
2089 }
2090};
2091
2092/**
2093* The DOM event handler used to fire the CustomEvent for window resize
2094* @method YAHOO.widget.Overlay.windowResizeHandler
2095* @static
2096* @param {DOMEvent} e The DOM resize event
2097*/
2098YAHOO.widget.Overlay.windowResizeHandler = function(e) {
2099 if (YAHOO.widget.Module.prototype.browser == "ie" || YAHOO.widget.Module.prototype.browser == "ie7") {
2100 if (! window.resizeEnd) {
2101 window.resizeEnd = -1;
2102 }
2103 clearTimeout(window.resizeEnd);
2104 window.resizeEnd = setTimeout(function() { YAHOO.widget.Overlay.windowResizeEvent.fire(); }, 100);
2105 } else {
2106 YAHOO.widget.Overlay.windowResizeEvent.fire();
2107 }
2108};
2109
2110/**
2111* A boolean that indicated whether the window resize and scroll events have already been subscribed to.
2112* @property YAHOO.widget.Overlay._initialized
2113* @private
2114* @type Boolean
2115*/
2116YAHOO.widget.Overlay._initialized = null;
2117
2118if (YAHOO.widget.Overlay._initialized === null) {
2119 YAHOO.util.Event.addListener(window, "scroll", YAHOO.widget.Overlay.windowScrollHandler);
2120 YAHOO.util.Event.addListener(window, "resize", YAHOO.widget.Overlay.windowResizeHandler);
2121
2122 YAHOO.widget.Overlay._initialized = true;
2123}
2124
2125/**
2126* OverlayManager is used for maintaining the focus status of multiple Overlays.* @namespace YAHOO.widget
2127* @namespace YAHOO.widget
2128* @class OverlayManager
2129* @constructor
2130 * @param {Array} overlaysOptional. A collection of Overlays to register with the manager.
2131 * @param {Object} userConfig The object literal representing the user configuration of the OverlayManager
2132*/
2133YAHOO.widget.OverlayManager = function(userConfig) {
2134 this.init(userConfig);
2135};
2136
2137/**
2138* The CSS class representing a focused Overlay
2139* @property YAHOO.widget.OverlayManager.CSS_FOCUSED
2140* @static
2141* @final
2142* @type String
2143*/
2144YAHOO.widget.OverlayManager.CSS_FOCUSED = "focused";
2145
2146YAHOO.widget.OverlayManager.prototype = {
2147 /**
2148 * The class's constructor function
2149 * @property contructor
2150 * @type Function
2151 */
2152 constructor : YAHOO.widget.OverlayManager,
2153
2154 /**
2155 * The array of Overlays that are currently registered
2156 * @property overlays
2157 * @type YAHOO.widget.Overlay[]
2158 */
2159 overlays : null,
2160
2161 /**
2162 * Initializes the default configuration of the OverlayManager
2163 * @method initDefaultConfig
2164 */
2165 initDefaultConfig : function() {
2166 /**
2167 * The collection of registered Overlays in use by the OverlayManager
2168 * @config overlays
2169 * @type YAHOO.widget.Overlay[]
2170 * @default null
2171 */
2172 this.cfg.addProperty("overlays", { suppressEvent:true } );
2173
2174 /**
2175 * The default DOM event that should be used to focus an Overlay
2176 * @config focusevent
2177 * @type String
2178 * @default "mousedown"
2179 */
2180 this.cfg.addProperty("focusevent", { value:"mousedown" } );
2181 },
2182
2183 /**
2184 * Initializes the OverlayManager
2185 * @method init
2186 * @param {YAHOO.widget.Overlay[]} overlaysOptional. A collection of Overlays to register with the manager.
2187 * @param {Object} userConfig The object literal representing the user configuration of the OverlayManager
2188 */
2189 init : function(userConfig) {
2190 /**
2191 * The OverlayManager's Config object used for monitoring configuration properties.
2192 * @property cfg
2193 * @type YAHOO.util.Config
2194 */
2195 this.cfg = new YAHOO.util.Config(this);
2196
2197 this.initDefaultConfig();
2198
2199 if (userConfig) {
2200 this.cfg.applyConfig(userConfig, true);
2201 }
2202 this.cfg.fireQueue();
2203
2204 /**
2205 * The currently activated Overlay
2206 * @property activeOverlay
2207 * @private
2208 * @type YAHOO.widget.Overlay
2209 */
2210 var activeOverlay = null;
2211
2212 /**
2213 * Returns the currently focused Overlay
2214 * @method getActive
2215 * @return {YAHOO.widget.Overlay}The currently focused Overlay
2216 */
2217 this.getActive = function() {
2218 return activeOverlay;
2219 };
2220
2221 /**
2222 * Focuses the specified Overlay
2223 * @method focus
2224 * @param {YAHOO.widget.Overlay} overlayThe Overlay to focus
2225 * @param {String} overlayThe id of the Overlay to focus
2226 */
2227 this.focus = function(overlay) {
2228 var o = this.find(overlay);
2229 if (o) {
2230 this.blurAll();
2231 activeOverlay = o;
2232 YAHOO.util.Dom.addClass(activeOverlay.element, YAHOO.widget.OverlayManager.CSS_FOCUSED);
2233 this.overlays.sort(this.compareZIndexDesc);
2234 var topZIndex = YAHOO.util.Dom.getStyle(this.overlays[0].element, "zIndex");
2235 if (! isNaN(topZIndex) && this.overlays[0] != overlay) {
2236 activeOverlay.cfg.setProperty("zIndex", (parseInt(topZIndex, 10) + 2));
2237 }
2238 this.overlays.sort(this.compareZIndexDesc);
2239 }
2240 };
2241
2242 /**
2243 * Removes the specified Overlay from the manager
2244 * @method remove
2245 * @param {YAHOO.widget.Overlay} overlayThe Overlay to remove
2246 * @param {String} overlayThe id of the Overlay to remove
2247 */
2248 this.remove = function(overlay) {
2249 var o = this.find(overlay);
2250 if (o) {
2251 var originalZ = YAHOO.util.Dom.getStyle(o.element, "zIndex");
2252 o.cfg.setProperty("zIndex", -1000, true);
2253 this.overlays.sort(this.compareZIndexDesc);
2254 this.overlays = this.overlays.slice(0, this.overlays.length-1);
2255 o.cfg.setProperty("zIndex", originalZ, true);
2256
2257 o.cfg.setProperty("manager", null);
2258 o.focusEvent = null;
2259 o.blurEvent = null;
2260 o.focus = null;
2261 o.blur = null;
2262 }
2263 };
2264
2265 /**
2266 * Removes focus from all registered Overlays in the manager
2267 * @method blurAll
2268 */
2269 this.blurAll = function() {
2270 activeOverlay = null;
2271 for (var o=0;o<this.overlays.length;o++) {
2272 YAHOO.util.Dom.removeClass(this.overlays[o].element, YAHOO.widget.OverlayManager.CSS_FOCUSED);
2273 }
2274 };
2275
2276 var overlays = this.cfg.getProperty("overlays");
2277
2278 if (! this.overlays) {
2279 this.overlays = [];
2280 }
2281
2282 if (overlays) {
2283 this.register(overlays);
2284 this.overlays.sort(this.compareZIndexDesc);
2285 }
2286 },
2287
2288 /**
2289 * Registers an Overlay or an array of Overlays with the manager. Upon registration, the Overlay receives functions for focus and blur, along with CustomEvents for each.
2290 * @method register
2291 * @param {YAHOO.widget.Overlay} overlay An Overlay to register with the manager.
2292 * @param {YAHOO.widget.Overlay[]} overlay An array of Overlays to register with the manager.
2293 * @return {Boolean}True if any Overlays are registered.
2294 */
2295 register : function(overlay) {
2296 if (overlay instanceof YAHOO.widget.Overlay) {
2297 overlay.cfg.addProperty("manager", { value:this } );
2298
2299 overlay.focusEvent = new YAHOO.util.CustomEvent("focus");
2300 overlay.blurEvent = new YAHOO.util.CustomEvent("blur");
2301
2302 var mgr=this;
2303
2304 overlay.focus = function() {
2305 mgr.focus(this);
2306 this.focusEvent.fire();
2307 };
2308
2309 overlay.blur = function() {
2310 mgr.blurAll();
2311 this.blurEvent.fire();
2312 };
2313
2314 var focusOnDomEvent = function(e,obj) {
2315 overlay.focus();
2316 };
2317
2318 var focusevent = this.cfg.getProperty("focusevent");
2319 YAHOO.util.Event.addListener(overlay.element,focusevent,focusOnDomEvent,this,true);
2320
2321 var zIndex = YAHOO.util.Dom.getStyle(overlay.element, "zIndex");
2322 if (! isNaN(zIndex)) {
2323 overlay.cfg.setProperty("zIndex", parseInt(zIndex, 10));
2324 } else {
2325 overlay.cfg.setProperty("zIndex", 0);
2326 }
2327
2328 this.overlays.push(overlay);
2329 return true;
2330 } else if (overlay instanceof Array) {
2331 var regcount = 0;
2332 for (var i=0;i<overlay.length;i++) {
2333 if (this.register(overlay[i])) {
2334 regcount++;
2335 }
2336 }
2337 if (regcount > 0) {
2338 return true;
2339 }
2340 } else {
2341 return false;
2342 }
2343 },
2344
2345 /**
2346 * Attempts to locate an Overlay by instance or ID.
2347 * @method find
2348 * @param {YAHOO.widget.Overlay} overlay An Overlay to locate within the manager
2349 * @param {String} overlay An Overlay id to locate within the manager
2350 * @return {YAHOO.widget.Overlay}The requested Overlay, if found, or null if it cannot be located.
2351 */
2352 find : function(overlay) {
2353 if (overlay instanceof YAHOO.widget.Overlay) {
2354 for (var o=0;o<this.overlays.length;o++) {
2355 if (this.overlays[o] == overlay) {
2356 return this.overlays[o];
2357 }
2358 }
2359 } else if (typeof overlay == "string") {
2360 for (var p=0;p<this.overlays.length;p++) {
2361 if (this.overlays[p].id == overlay) {
2362 return this.overlays[p];
2363 }
2364 }
2365 }
2366 return null;
2367 },
2368
2369 /**
2370 * Used for sorting the manager's Overlays by z-index.
2371 * @method compareZIndexDesc
2372 * @private
2373 * @return {Number}0, 1, or -1, depending on where the Overlay should fall in the stacking order.
2374 */
2375 compareZIndexDesc : function(o1, o2) {
2376 var zIndex1 = o1.cfg.getProperty("zIndex");
2377 var zIndex2 = o2.cfg.getProperty("zIndex");
2378
2379 if (zIndex1 > zIndex2) {
2380 return -1;
2381 } else if (zIndex1 < zIndex2) {
2382 return 1;
2383 } else {
2384 return 0;
2385 }
2386 },
2387
2388 /**
2389 * Shows all Overlays in the manager.
2390 * @method showAll
2391 */
2392 showAll : function() {
2393 for (var o=0;o<this.overlays.length;o++) {
2394 this.overlays[o].show();
2395 }
2396 },
2397
2398 /**
2399 * Hides all Overlays in the manager.
2400 * @method hideAll
2401 */
2402 hideAll : function() {
2403 for (var o=0;o<this.overlays.length;o++) {
2404 this.overlays[o].hide();
2405 }
2406 },
2407
2408
2409 /**
2410 * Returns a string representation of the object.
2411 * @method toString
2412 * @return {String}The string representation of the OverlayManager
2413 */
2414 toString : function() {
2415 return "OverlayManager";
2416 }
2417
2418};
2419
2420/**
2421* KeyListener is a utility that provides an easy interface for listening for keydown/keyup events fired against DOM elements.
2422* @namespace YAHOO.util
2423* @class KeyListener
2424* @constructor
2425 * @param {HTMLElement} attachToThe element or element ID to which the key event should be attached
2426 * @param {String} attachToThe element or element ID to which the key event should be attached
2427 * @param {Object} keyData The object literal representing the key(s) to detect. Possible attributes are shift(boolean), alt(boolean), ctrl(boolean) and keys(either an int or an array of ints representing keycodes).
2428 * @param {Function} handler The CustomEvent handler to fire when the key event is detected
2429 * @param {Object} handler An object literal representing the handler.
2430 * @param {String} event Optional. The event (keydown or keyup) to listen for. Defaults automatically to keydown.
2431*/
2432YAHOO.util.KeyListener = function(attachTo, keyData, handler, event) {
2433 if (! event) {
2434 event = YAHOO.util.KeyListener.KEYDOWN;
2435 }
2436
2437 /**
2438 * The CustomEvent fired internally when a key is pressed
2439 * @event keyEvent
2440 * @private
2441 * @param {Object} keyData The object literal representing the key(s) to detect. Possible attributes are shift(boolean), alt(boolean), ctrl(boolean) and keys(either an int or an array of ints representing keycodes).
2442 */
2443 var keyEvent = new YAHOO.util.CustomEvent("keyPressed");
2444
2445 /**
2446 * The CustomEvent fired when the KeyListener is enabled via the enable() function
2447 * @event enabledEvent
2448 * @param {Object} keyData The object literal representing the key(s) to detect. Possible attributes are shift(boolean), alt(boolean), ctrl(boolean) and keys(either an int or an array of ints representing keycodes).
2449 */
2450 this.enabledEvent = new YAHOO.util.CustomEvent("enabled");
2451
2452 /**
2453 * The CustomEvent fired when the KeyListener is disabled via the disable() function
2454 * @event disabledEvent
2455 * @param {Object} keyData The object literal representing the key(s) to detect. Possible attributes are shift(boolean), alt(boolean), ctrl(boolean) and keys(either an int or an array of ints representing keycodes).
2456 */
2457 this.disabledEvent = new YAHOO.util.CustomEvent("disabled");
2458
2459 if (typeof attachTo == 'string') {
2460 attachTo = document.getElementById(attachTo);
2461 }
2462
2463 if (typeof handler == 'function') {
2464 keyEvent.subscribe(handler);
2465 } else {
2466 keyEvent.subscribe(handler.fn, handler.scope, handler.correctScope);
2467 }
2468
2469 /**
2470 * Handles the key event when a key is pressed.
2471 * @method handleKeyPress
2472 * @param {DOMEvent} eThe keypress DOM event
2473 * @param {Object} objThe DOM event scope object
2474 * @private
2475 */
2476 function handleKeyPress(e, obj) {
2477 if (! keyData.shift) {
2478 keyData.shift = false;
2479 }
2480 if (! keyData.alt) {
2481 keyData.alt = false;
2482 }
2483 if (! keyData.ctrl) {
2484 keyData.ctrl = false;
2485 }
2486
2487 // check held down modifying keys first
2488 if (e.shiftKey == keyData.shift &&
2489 e.altKey == keyData.alt &&
2490 e.ctrlKey == keyData.ctrl) { // if we pass this, all modifiers match
2491
2492 var dataItem;
2493 var keyPressed;
2494
2495 if (keyData.keys instanceof Array) {
2496 for (var i=0;i<keyData.keys.length;i++) {
2497 dataItem = keyData.keys[i];
2498
2499 if (dataItem == e.charCode ) {
2500 keyEvent.fire(e.charCode, e);
2501 break;
2502 } else if (dataItem == e.keyCode) {
2503 keyEvent.fire(e.keyCode, e);
2504 break;
2505 }
2506 }
2507 } else {
2508 dataItem = keyData.keys;
2509
2510 if (dataItem == e.charCode ) {
2511 keyEvent.fire(e.charCode, e);
2512 } else if (dataItem == e.keyCode) {
2513 keyEvent.fire(e.keyCode, e);
2514 }
2515 }
2516 }
2517 }
2518
2519 /**
2520 * Enables the KeyListener by attaching the DOM event listeners to the target DOM element
2521 * @method enable
2522 */
2523 this.enable = function() {
2524 if (! this.enabled) {
2525 YAHOO.util.Event.addListener(attachTo, event, handleKeyPress);
2526 this.enabledEvent.fire(keyData);
2527 }
2528 /**
2529 * Boolean indicating the enabled/disabled state of the Tooltip
2530 * @property enabled
2531 * @type Boolean
2532 */
2533 this.enabled = true;
2534 };
2535
2536 /**
2537 * Disables the KeyListener by removing the DOM event listeners from the target DOM element
2538 * @method disable
2539 */
2540 this.disable = function() {
2541 if (this.enabled) {
2542 YAHOO.util.Event.removeListener(attachTo, event, handleKeyPress);
2543 this.disabledEvent.fire(keyData);
2544 }
2545 this.enabled = false;
2546 };
2547
2548 /**
2549 * Returns a String representation of the object.
2550 * @method toString
2551 * @return {String}The string representation of the KeyListener
2552 */
2553 this.toString = function() {
2554 return "KeyListener [" + keyData.keys + "] " + attachTo.tagName + (attachTo.id ? "[" + attachTo.id + "]" : "");
2555 };
2556
2557};
2558
2559/**
2560* Constant representing the DOM "keydown" event.
2561* @property YAHOO.util.KeyListener.KEYDOWN
2562* @static
2563* @final
2564* @type String
2565*/
2566YAHOO.util.KeyListener.KEYDOWN = "keydown";
2567
2568/**
2569* Constant representing the DOM "keyup" event.
2570* @property YAHOO.util.KeyListener.KEYUP
2571* @static
2572* @final
2573* @type String
2574*/
2575YAHOO.util.KeyListener.KEYUP = "keyup";
2576
2577/**
2578* Tooltip is an implementation of Overlay that behaves like an OS tooltip, displaying when the user mouses over a particular element, and disappearing on mouse out.
2579* @namespace YAHOO.widget
2580* @class Tooltip
2581* @extends YAHOO.widget.Overlay
2582* @constructor
2583 * @param {String} elThe element ID representing the Tooltip <em>OR</em>
2584 * @param {HTMLElement} elThe element representing the Tooltip
2585 * @param {Object} userConfigThe configuration object literal containing the configuration that should be set for this Overlay. See configuration documentation for more details.
2586*/
2587YAHOO.widget.Tooltip = function(el, userConfig) {
2588 YAHOO.widget.Tooltip.superclass.constructor.call(this, el, userConfig);
2589};
2590
2591YAHOO.extend(YAHOO.widget.Tooltip, YAHOO.widget.Overlay);
2592
2593/**
2594* Constant representing the Tooltip CSS class
2595* @property YAHOO.widget.Tooltip.CSS_TOOLTIP
2596* @static
2597* @final
2598* @type String
2599*/
2600YAHOO.widget.Tooltip.CSS_TOOLTIP = "tt";
2601
2602/**
2603* The Tooltip initialization method. This method is automatically called by the constructor. A Tooltip is automatically rendered by the init method, and it also is set to be invisible by default, and constrained to viewport by default as well.
2604* @method init
2605 * @param {String} elThe element ID representing the Tooltip <em>OR</em>
2606 * @param {HTMLElement} elThe element representing the Tooltip
2607 * @param {Object} userConfigThe configuration object literal containing the configuration that should be set for this Tooltip. See configuration documentation for more details.
2608*/
2609YAHOO.widget.Tooltip.prototype.init = function(el, userConfig) {
2610 if (document.readyState && document.readyState != "complete") {
2611 var deferredInit = function() {
2612 this.init(el, userConfig);
2613 };
2614 YAHOO.util.Event.addListener(window, "load", deferredInit, this, true);
2615 } else {
2616 YAHOO.widget.Tooltip.superclass.init.call(this, el);
2617
2618 this.beforeInitEvent.fire(YAHOO.widget.Tooltip);
2619
2620 YAHOO.util.Dom.addClass(this.element, YAHOO.widget.Tooltip.CSS_TOOLTIP);
2621
2622 if (userConfig) {
2623 this.cfg.applyConfig(userConfig, true);
2624 }
2625
2626 this.cfg.queueProperty("visible",false);
2627 this.cfg.queueProperty("constraintoviewport",true);
2628
2629 this.setBody("");
2630 this.render(this.cfg.getProperty("container"));
2631
2632 this.initEvent.fire(YAHOO.widget.Tooltip);
2633 }
2634};
2635
2636/**
2637* Initializes the class's configurable properties which can be changed using the Overlay's Config object (cfg).
2638* @method initDefaultConfig
2639*/
2640YAHOO.widget.Tooltip.prototype.initDefaultConfig = function() {
2641 YAHOO.widget.Tooltip.superclass.initDefaultConfig.call(this);
2642
2643 /**
2644 * Specifies whether the Tooltip should be kept from overlapping its context element.
2645 * @config preventoverlap
2646 * @type Boolean
2647 * @default true
2648 */
2649 this.cfg.addProperty("preventoverlap", { value:true, validator:this.cfg.checkBoolean, supercedes:["x","y","xy"] } );
2650
2651 /**
2652 * The number of milliseconds to wait before showing a Tooltip on mouseover.
2653 * @config showdelay
2654 * @type Number
2655 * @default 200
2656 */
2657 this.cfg.addProperty("showdelay", { value:200, handler:this.configShowDelay, validator:this.cfg.checkNumber } );
2658
2659 /**
2660 * The number of milliseconds to wait before automatically dismissing a Tooltip after the mouse has been resting on the context element.
2661 * @config autodismissdelay
2662 * @type Number
2663 * @default 5000
2664 */
2665 this.cfg.addProperty("autodismissdelay",{ value:5000, handler:this.configAutoDismissDelay, validator:this.cfg.checkNumber } );
2666
2667 /**
2668 * The number of milliseconds to wait before hiding a Tooltip on mouseover.
2669 * @config hidedelay
2670 * @type Number
2671 * @default 250
2672 */
2673 this.cfg.addProperty("hidedelay", { value:250, handler:this.configHideDelay, validator:this.cfg.checkNumber } );
2674
2675 /**
2676 * Specifies the Tooltip's text.
2677 * @config text
2678 * @type String
2679 * @default null
2680 */
2681 this.cfg.addProperty("text", { handler:this.configText, suppressEvent:true } );
2682
2683 /**
2684 * Specifies the container element that the Tooltip's markup should be rendered into.
2685 * @config container
2686 * @type HTMLElement/String
2687 * @default document.body
2688 */
2689 this.cfg.addProperty("container", { value:document.body, handler:this.configContainer } );
2690
2691 /**
2692 * Specifies the element or elements that the Tooltip should be anchored to on mouseover.
2693 * @config context
2694 * @type HTMLElement[]/String[]
2695 * @default null
2696 */
2697
2698};
2699
2700// BEGIN BUILT-IN PROPERTY EVENT HANDLERS //
2701
2702/**
2703* The default event handler fired when the "text" property is changed.
2704* @method configText
2705 * @param {String} typeThe CustomEvent type (usually the property name)
2706 * @param {Object[]} argsThe CustomEvent arguments. For configuration handlers, args[0] will equal the newly applied value for the property.
2707 * @param {Object} objThe scope object. For configuration handlers, this will usually equal the owner.
2708*/
2709YAHOO.widget.Tooltip.prototype.configText = function(type, args, obj) {
2710 var text = args[0];
2711 if (text) {
2712 this.setBody(text);
2713 }
2714};
2715
2716/**
2717* The default event handler fired when the "container" property is changed.
2718* @method configContainer
2719 * @param {String} typeThe CustomEvent type (usually the property name)
2720 * @param {Object[]} argsThe CustomEvent arguments. For configuration handlers, args[0] will equal the newly applied value for the property.
2721 * @param {Object} objThe scope object. For configuration handlers, this will usually equal the owner.
2722*/
2723YAHOO.widget.Tooltip.prototype.configContainer = function(type, args, obj) {
2724 var container = args[0];
2725 if (typeof container == 'string') {
2726 this.cfg.setProperty("container", document.getElementById(container), true);
2727 }
2728};
2729
2730/**
2731* The default event handler fired when the "context" property is changed.
2732* @method configContext
2733 * @param {String} typeThe CustomEvent type (usually the property name)
2734 * @param {Object[]} argsThe CustomEvent arguments. For configuration handlers, args[0] will equal the newly applied value for the property.
2735 * @param {Object} objThe scope object. For configuration handlers, this will usually equal the owner.
2736*/
2737YAHOO.widget.Tooltip.prototype.configContext = function(type, args, obj) {
2738 var context = args[0];
2739 if (context) {
2740
2741 // Normalize parameter into an array
2742 if (! (context instanceof Array)) {
2743 if (typeof context == "string") {
2744 this.cfg.setProperty("context", [document.getElementById(context)], true);
2745 } else { // Assuming this is an element
2746 this.cfg.setProperty("context", [context], true);
2747 }
2748 context = this.cfg.getProperty("context");
2749 }
2750
2751
2752 // Remove any existing mouseover/mouseout listeners
2753 if (this._context) {
2754 for (var c=0;c<this._context.length;++c) {
2755 var el = this._context[c];
2756 YAHOO.util.Event.removeListener(el, "mouseover", this.onContextMouseOver);
2757 YAHOO.util.Event.removeListener(el, "mousemove", this.onContextMouseMove);
2758 YAHOO.util.Event.removeListener(el, "mouseout", this.onContextMouseOut);
2759 }
2760 }
2761
2762 // Add mouseover/mouseout listeners to context elements
2763 this._context = context;
2764 for (var d=0;d<this._context.length;++d) {
2765 var el2 = this._context[d];
2766 YAHOO.util.Event.addListener(el2, "mouseover", this.onContextMouseOver, this);
2767 YAHOO.util.Event.addListener(el2, "mousemove", this.onContextMouseMove, this);
2768 YAHOO.util.Event.addListener(el2, "mouseout", this.onContextMouseOut, this);
2769 }
2770 }
2771};
2772
2773// END BUILT-IN PROPERTY EVENT HANDLERS //
2774
2775// BEGIN BUILT-IN DOM EVENT HANDLERS //
2776
2777/**
2778* The default event handler fired when the user moves the mouse while over the context element.
2779* @method onContextMouseMove
2780 * @param {DOMEvent} eThe current DOM event
2781 * @param {Object} objThe object argument
2782*/
2783YAHOO.widget.Tooltip.prototype.onContextMouseMove = function(e, obj) {
2784 obj.pageX = YAHOO.util.Event.getPageX(e);
2785 obj.pageY = YAHOO.util.Event.getPageY(e);
2786
2787};
2788
2789/**
2790* The default event handler fired when the user mouses over the context element.
2791* @method onContextMouseOver
2792 * @param {DOMEvent} eThe current DOM event
2793 * @param {Object} objThe object argument
2794*/
2795YAHOO.widget.Tooltip.prototype.onContextMouseOver = function(e, obj) {
2796
2797 if (obj.hideProcId) {
2798 clearTimeout(obj.hideProcId);
2799 obj.hideProcId = null;
2800 }
2801
2802 var context = this;
2803 YAHOO.util.Event.addListener(context, "mousemove", obj.onContextMouseMove, obj);
2804
2805 if (context.title) {
2806 obj._tempTitle = context.title;
2807 context.title = "";
2808 }
2809
2810 /**
2811 * The unique process ID associated with the thread responsible for showing the Tooltip.
2812 * @type int
2813 */
2814 obj.showProcId = obj.doShow(e, context);
2815};
2816
2817/**
2818* The default event handler fired when the user mouses out of the context element.
2819* @method onContextMouseOut
2820 * @param {DOMEvent} eThe current DOM event
2821 * @param {Object} objThe object argument
2822*/
2823YAHOO.widget.Tooltip.prototype.onContextMouseOut = function(e, obj) {
2824 var el = this;
2825
2826 if (obj._tempTitle) {
2827 el.title = obj._tempTitle;
2828 obj._tempTitle = null;
2829 }
2830
2831 if (obj.showProcId) {
2832 clearTimeout(obj.showProcId);
2833 obj.showProcId = null;
2834 }
2835
2836 if (obj.hideProcId) {
2837 clearTimeout(obj.hideProcId);
2838 obj.hideProcId = null;
2839 }
2840
2841
2842 obj.hideProcId = setTimeout(function() {
2843 obj.hide();
2844 }, obj.cfg.getProperty("hidedelay"));
2845};
2846
2847// END BUILT-IN DOM EVENT HANDLERS //
2848
2849/**
2850* Processes the showing of the Tooltip by setting the timeout delay and offset of the Tooltip.
2851* @method doShow
2852 * @param {DOMEvent} eThe current DOM event
2853 * @return {Number}The process ID of the timeout function associated with doShow
2854*/
2855YAHOO.widget.Tooltip.prototype.doShow = function(e, context) {
2856
2857 var yOffset = 25;
2858 if (this.browser == "opera" && context.tagName == "A") {
2859 yOffset += 12;
2860 }
2861
2862 var me = this;
2863 return setTimeout(
2864 function() {
2865 if (me._tempTitle) {
2866 me.setBody(me._tempTitle);
2867 } else {
2868 me.cfg.refireEvent("text");
2869 }
2870
2871 me.moveTo(me.pageX, me.pageY + yOffset);
2872 if (me.cfg.getProperty("preventoverlap")) {
2873 me.preventOverlap(me.pageX, me.pageY);
2874 }
2875
2876 YAHOO.util.Event.removeListener(context, "mousemove", me.onContextMouseMove);
2877
2878 me.show();
2879 me.hideProcId = me.doHide();
2880 },
2881 this.cfg.getProperty("showdelay"));
2882};
2883
2884/**
2885* Sets the timeout for the auto-dismiss delay, which by default is 5 seconds, meaning that a tooltip will automatically dismiss itself after 5 seconds of being displayed.
2886* @method doHide
2887*/
2888YAHOO.widget.Tooltip.prototype.doHide = function() {
2889 var me = this;
2890 return setTimeout(
2891 function() {
2892 me.hide();
2893 },
2894 this.cfg.getProperty("autodismissdelay"));
2895};
2896
2897/**
2898* Fired when the Tooltip is moved, this event handler is used to prevent the Tooltip from overlapping with its context element.
2899* @method preventOverlay
2900 * @param {Number} pageXThe x coordinate position of the mouse pointer
2901 * @param {Number} pageYThe y coordinate position of the mouse pointer
2902*/
2903YAHOO.widget.Tooltip.prototype.preventOverlap = function(pageX, pageY) {
2904
2905 var height = this.element.offsetHeight;
2906
2907 var elementRegion = YAHOO.util.Dom.getRegion(this.element);
2908
2909 elementRegion.top -= 5;
2910 elementRegion.left -= 5;
2911 elementRegion.right += 5;
2912 elementRegion.bottom += 5;
2913
2914 var mousePoint = new YAHOO.util.Point(pageX, pageY);
2915
2916 if (elementRegion.contains(mousePoint)) {
2917 this.cfg.setProperty("y", (pageY-height-5));
2918 }
2919};
2920
2921/**
2922* Returns a string representation of the object.
2923* @method toString
2924 * @return {String}The string representation of the Tooltip
2925*/
2926YAHOO.widget.Tooltip.prototype.toString = function() {
2927 return "Tooltip " + this.id;
2928};
2929
2930/**
2931* Panel is an implementation of Overlay that behaves like an OS window, with a draggable header and an optional close icon at the top right.
2932* @namespace YAHOO.widget
2933* @class Panel
2934* @extends YAHOO.widget.Overlay
2935* @constructor
2936 * @param {String} elThe element ID representing the Panel <em>OR</em>
2937 * @param {HTMLElement} elThe element representing the Panel
2938 * @param {Object} userConfigThe configuration object literal containing the configuration that should be set for this Panel. See configuration documentation for more details.
2939*/
2940YAHOO.widget.Panel = function(el, userConfig) {
2941 YAHOO.widget.Panel.superclass.constructor.call(this, el, userConfig);
2942};
2943
2944YAHOO.extend(YAHOO.widget.Panel, YAHOO.widget.Overlay);
2945
2946/**
2947* Constant representing the default CSS class used for a Panel
2948* @property YAHOO.widget.Panel.CSS_PANEL
2949* @static
2950* @final
2951* @type String
2952*/
2953YAHOO.widget.Panel.CSS_PANEL = "panel";
2954
2955/**
2956* Constant representing the default CSS class used for a Panel's wrapping container
2957* @property YAHOO.widget.Panel.CSS_PANEL_CONTAINER
2958* @static
2959* @final
2960* @type String
2961*/
2962YAHOO.widget.Panel.CSS_PANEL_CONTAINER = "panel-container";
2963
2964/**
2965* The Overlay initialization method, which is executed for Overlay and all of its subclasses. This method is automatically called by the constructor, and sets up all DOM references for pre-existing markup, and creates required markup if it is not already present.
2966* @method init
2967 * @param {String} elThe element ID representing the Overlay <em>OR</em>
2968 * @param {HTMLElement} elThe element representing the Overlay
2969 * @param {Object} userConfigThe configuration object literal containing the configuration that should be set for this Overlay. See configuration documentation for more details.
2970*/
2971YAHOO.widget.Panel.prototype.init = function(el, userConfig) {
2972 YAHOO.widget.Panel.superclass.init.call(this, el/*, userConfig*/); // Note that we don't pass the user config in here yet because we only want it executed once, at the lowest subclass level
2973
2974 this.beforeInitEvent.fire(YAHOO.widget.Panel);
2975
2976 YAHOO.util.Dom.addClass(this.element, YAHOO.widget.Panel.CSS_PANEL);
2977
2978 this.buildWrapper();
2979
2980 if (userConfig) {
2981 this.cfg.applyConfig(userConfig, true);
2982 }
2983
2984 this.beforeRenderEvent.subscribe(function() {
2985 var draggable = this.cfg.getProperty("draggable");
2986 if (draggable) {
2987 if (! this.header) {
2988 this.setHeader("&nbsp;");
2989 }
2990 }
2991 }, this, true);
2992
2993 var me = this;
2994
2995 this.showMaskEvent.subscribe(function() {
2996 var checkFocusable = function(el) {
2997 if (el.tagName == "A" || el.tagName == "BUTTON" || el.tagName == "SELECT" || el.tagName == "INPUT" || el.tagName == "TEXTAREA" || el.tagName == "FORM") {
2998 if (! YAHOO.util.Dom.isAncestor(me.element, el)) {
2999 YAHOO.util.Event.addListener(el, "focus", el.blur);
3000 return true;
3001 }
3002 } else {
3003 return false;
3004 }
3005 };
3006
3007 this.focusableElements = YAHOO.util.Dom.getElementsBy(checkFocusable);
3008 }, this, true);
3009
3010 this.hideMaskEvent.subscribe(function() {
3011 for (var i=0;i<this.focusableElements.length;i++) {
3012 var el2 = this.focusableElements[i];
3013 YAHOO.util.Event.removeListener(el2, "focus", el2.blur);
3014 }
3015 }, this, true);
3016
3017 this.beforeShowEvent.subscribe(function() {
3018 this.cfg.refireEvent("underlay");
3019 }, this, true);
3020
3021 this.initEvent.fire(YAHOO.widget.Panel);
3022};
3023
3024/**
3025* Initializes the custom events for Module which are fired automatically at appropriate times by the Module class.
3026*/
3027YAHOO.widget.Panel.prototype.initEvents = function() {
3028 YAHOO.widget.Panel.superclass.initEvents.call(this);
3029
3030 /**
3031 * CustomEvent fired after the modality mask is shown
3032 * @event showMaskEvent
3033 */
3034 this.showMaskEvent = new YAHOO.util.CustomEvent("showMask");
3035
3036 /**
3037 * CustomEvent fired after the modality mask is hidden
3038 * @event hideMaskEvent
3039 */
3040 this.hideMaskEvent = new YAHOO.util.CustomEvent("hideMask");
3041
3042 /**
3043 * CustomEvent when the Panel is dragged
3044 * @event dragEvent
3045 */
3046 this.dragEvent = new YAHOO.util.CustomEvent("drag");
3047};
3048
3049/**
3050* Initializes the class's configurable properties which can be changed using the Panel's Config object (cfg).
3051* @method initDefaultConfig
3052*/
3053YAHOO.widget.Panel.prototype.initDefaultConfig = function() {
3054 YAHOO.widget.Panel.superclass.initDefaultConfig.call(this);
3055
3056 // Add panel config properties //
3057
3058 /**
3059 * True if the Panel should display a "close" button
3060 * @config close
3061 * @type Boolean
3062 * @default true
3063 */
3064 this.cfg.addProperty("close", { value:true, handler:this.configClose, validator:this.cfg.checkBoolean, supercedes:["visible"] } );
3065
3066 /**
3067 * True if the Panel should be draggable
3068 * @config draggable
3069 * @type Boolean
3070 * @default true
3071 */
3072 this.cfg.addProperty("draggable", { value:true,handler:this.configDraggable, validator:this.cfg.checkBoolean, supercedes:["visible"] } );
3073
3074 /**
3075 * Sets the type of underlay to display for the Panel. Valid values are "shadow", "matte", and "none".
3076 * @config underlay
3077 * @type String
3078 * @default shadow
3079 */
3080 this.cfg.addProperty("underlay", { value:"shadow", handler:this.configUnderlay, supercedes:["visible"] } );
3081
3082 /**
3083 * True if the Panel should be displayed in a modal fashion, automatically creating a transparent mask over the document that will not be removed until the Panel is dismissed.
3084 * @config modal
3085 * @type Boolean
3086 * @default false
3087 */
3088 this.cfg.addProperty("modal",{ value:false, handler:this.configModal, validator:this.cfg.checkBoolean, supercedes:["visible"] } );
3089
3090 /**
3091 * A KeyListener (or array of KeyListeners) that will be enabled when the Panel is shown, and disabled when the Panel is hidden.
3092 * @config keylisteners
3093 * @type YAHOO.util.KeyListener[]
3094 * @default null
3095 */
3096 this.cfg.addProperty("keylisteners", { handler:this.configKeyListeners, suppressEvent:true, supercedes:["visible"] } );
3097};
3098
3099// BEGIN BUILT-IN PROPERTY EVENT HANDLERS //
3100
3101/**
3102* The default event handler fired when the "close" property is changed. The method controls the appending or hiding of the close icon at the top right of the Panel.
3103* @method configClose
3104 * @param {String} typeThe CustomEvent type (usually the property name)
3105 * @param {Object[]} argsThe CustomEvent arguments. For configuration handlers, args[0] will equal the newly applied value for the property.
3106 * @param {Object} objThe scope object. For configuration handlers, this will usually equal the owner.
3107*/
3108YAHOO.widget.Panel.prototype.configClose = function(type, args, obj) {
3109 var val = args[0];
3110
3111 var doHide = function(e, obj) {
3112 obj.hide();
3113 };
3114
3115 if (val) {
3116 if (! this.close) {
3117 this.close = document.createElement("DIV");
3118 YAHOO.util.Dom.addClass(this.close, "close");
3119
3120 if (this.isSecure) {
3121 YAHOO.util.Dom.addClass(this.close, "secure");
3122 } else {
3123 YAHOO.util.Dom.addClass(this.close, "nonsecure");
3124 }
3125
3126 this.close.innerHTML = "&nbsp;";
3127 this.innerElement.appendChild(this.close);
3128 YAHOO.util.Event.addListener(this.close, "click", doHide, this);
3129 } else {
3130 this.close.style.display = "block";
3131 }
3132 } else {
3133 if (this.close) {
3134 this.close.style.display = "none";
3135 }
3136 }
3137};
3138
3139/**
3140* The default event handler fired when the "draggable" property is changed.
3141* @method configDraggable
3142 * @param {String} typeThe CustomEvent type (usually the property name)
3143 * @param {Object[]} argsThe CustomEvent arguments. For configuration handlers, args[0] will equal the newly applied value for the property.
3144 * @param {Object} objThe scope object. For configuration handlers, this will usually equal the owner.
3145*/
3146YAHOO.widget.Panel.prototype.configDraggable = function(type, args, obj) {
3147 var val = args[0];
3148 if (val) {
3149 if (this.header) {
3150 YAHOO.util.Dom.setStyle(this.header,"cursor","move");
3151 this.registerDragDrop();
3152 }
3153 } else {
3154 if (this.dd) {
3155 this.dd.unreg();
3156 }
3157 if (this.header) {
3158 YAHOO.util.Dom.setStyle(this.header,"cursor","auto");
3159 }
3160 }
3161};
3162
3163/**
3164* The default event handler fired when the "underlay" property is changed.
3165* @method configUnderlay
3166 * @param {String} typeThe CustomEvent type (usually the property name)
3167 * @param {Object[]} argsThe CustomEvent arguments. For configuration handlers, args[0] will equal the newly applied value for the property.
3168 * @param {Object} objThe scope object. For configuration handlers, this will usually equal the owner.
3169*/
3170YAHOO.widget.Panel.prototype.configUnderlay = function(type, args, obj) {
3171 var val = args[0];
3172
3173 switch (val.toLowerCase()) {
3174 case "shadow":
3175 YAHOO.util.Dom.removeClass(this.element, "matte");
3176 YAHOO.util.Dom.addClass(this.element, "shadow");
3177
3178 if (! this.underlay) { // create if not already in DOM
3179 this.underlay = document.createElement("DIV");
3180 this.underlay.className = "underlay";
3181 this.underlay.innerHTML = "&nbsp;";
3182 this.element.appendChild(this.underlay);
3183 }
3184
3185 this.sizeUnderlay();
3186 break;
3187 case "matte":
3188 YAHOO.util.Dom.removeClass(this.element, "shadow");
3189 YAHOO.util.Dom.addClass(this.element, "matte");
3190 break;
3191 default:
3192 YAHOO.util.Dom.removeClass(this.element, "shadow");
3193 YAHOO.util.Dom.removeClass(this.element, "matte");
3194 break;
3195 }
3196};
3197
3198/**
3199* The default event handler fired when the "modal" property is changed. This handler subscribes or unsubscribes to the show and hide events to handle the display or hide of the modality mask.
3200* @method configModal
3201 * @param {String} typeThe CustomEvent type (usually the property name)
3202 * @param {Object[]} argsThe CustomEvent arguments. For configuration handlers, args[0] will equal the newly applied value for the property.
3203 * @param {Object} objThe scope object. For configuration handlers, this will usually equal the owner.
3204*/
3205YAHOO.widget.Panel.prototype.configModal = function(type, args, obj) {
3206 var modal = args[0];
3207
3208 if (modal) {
3209 this.buildMask();
3210
3211 if (! YAHOO.util.Config.alreadySubscribed( this.beforeShowEvent, this.showMask, this ) ) {
3212 this.beforeShowEvent.subscribe(this.showMask, this, true);
3213 }
3214 if (! YAHOO.util.Config.alreadySubscribed( this.hideEvent, this.hideMask, this) ) {
3215 this.hideEvent.subscribe(this.hideMask, this, true);
3216 }
3217 if (! YAHOO.util.Config.alreadySubscribed( YAHOO.widget.Overlay.windowResizeEvent, this.sizeMask, this ) ) {
3218 YAHOO.widget.Overlay.windowResizeEvent.subscribe(this.sizeMask, this, true);
3219 }
3220 if (! YAHOO.util.Config.alreadySubscribed( this.destroyEvent, this.removeMask, this) ) {
3221 this.destroyEvent.subscribe(this.removeMask, this, true);
3222 }
3223
3224 this.cfg.refireEvent("zIndex");
3225 } else {
3226 this.beforeShowEvent.unsubscribe(this.showMask, this);
3227 this.hideEvent.unsubscribe(this.hideMask, this);
3228 YAHOO.widget.Overlay.windowResizeEvent.unsubscribe(this.sizeMask, this);
3229 this.destroyEvent.unsubscribe(this.removeMask, this);
3230 }
3231};
3232
3233/**
3234* Removes the modality mask.
3235* @method removeMask
3236*/
3237YAHOO.widget.Panel.prototype.removeMask = function() {
3238 if (this.mask) {
3239 if (this.mask.parentNode) {
3240 this.mask.parentNode.removeChild(this.mask);
3241 }
3242 this.mask = null;
3243 }
3244};
3245
3246/**
3247* The default event handler fired when the "keylisteners" property is changed.
3248* @method configKeyListeners
3249 * @param {String} typeThe CustomEvent type (usually the property name)
3250 * @param {Object[]} argsThe CustomEvent arguments. For configuration handlers, args[0] will equal the newly applied value for the property.
3251 * @param {Object} objThe scope object. For configuration handlers, this will usually equal the owner.
3252*/
3253YAHOO.widget.Panel.prototype.configKeyListeners = function(type, args, obj) {
3254 var listeners = args[0];
3255
3256 if (listeners) {
3257 if (listeners instanceof Array) {
3258 for (var i=0;i<listeners.length;i++) {
3259 var listener = listeners[i];
3260
3261 if (! YAHOO.util.Config.alreadySubscribed(this.showEvent, listener.enable, listener)) {
3262 this.showEvent.subscribe(listener.enable, listener, true);
3263 }
3264 if (! YAHOO.util.Config.alreadySubscribed(this.hideEvent, listener.disable, listener)) {
3265 this.hideEvent.subscribe(listener.disable, listener, true);
3266 this.destroyEvent.subscribe(listener.disable, listener, true);
3267 }
3268 }
3269 } else {
3270 if (! YAHOO.util.Config.alreadySubscribed(this.showEvent, listeners.enable, listeners)) {
3271 this.showEvent.subscribe(listeners.enable, listeners, true);
3272 }
3273 if (! YAHOO.util.Config.alreadySubscribed(this.hideEvent, listeners.disable, listeners)) {
3274 this.hideEvent.subscribe(listeners.disable, listeners, true);
3275 this.destroyEvent.subscribe(listeners.disable, listeners, true);
3276 }
3277 }
3278 }
3279};
3280
3281/**
3282* The default event handler fired when the "height" property is changed.
3283* @method configHeight
3284 * @param {String} typeThe CustomEvent type (usually the property name)
3285 * @param {Object[]} argsThe CustomEvent arguments. For configuration handlers, args[0] will equal the newly applied value for the property.
3286 * @param {Object} objThe scope object. For configuration handlers, this will usually equal the owner.
3287*/
3288YAHOO.widget.Panel.prototype.configHeight = function(type, args, obj) {
3289 var height = args[0];
3290 var el = this.innerElement;
3291 YAHOO.util.Dom.setStyle(el, "height", height);
3292 this.cfg.refireEvent("underlay");
3293 this.cfg.refireEvent("iframe");
3294};
3295
3296/**
3297* The default event handler fired when the "width" property is changed.
3298* @method configWidth
3299 * @param {String} typeThe CustomEvent type (usually the property name)
3300 * @param {Object[]} argsThe CustomEvent arguments. For configuration handlers, args[0] will equal the newly applied value for the property.
3301 * @param {Object} objThe scope object. For configuration handlers, this will usually equal the owner.
3302*/
3303YAHOO.widget.Panel.prototype.configWidth = function(type, args, obj) {
3304 var width = args[0];
3305 var el = this.innerElement;
3306 YAHOO.util.Dom.setStyle(el, "width", width);
3307 this.cfg.refireEvent("underlay");
3308 this.cfg.refireEvent("iframe");
3309};
3310
3311/**
3312* The default event handler fired when the "zIndex" property is changed.
3313* @method configzIndex
3314 * @param {String} typeThe CustomEvent type (usually the property name)
3315 * @param {Object[]} argsThe CustomEvent arguments. For configuration handlers, args[0] will equal the newly applied value for the property.
3316 * @param {Object} objThe scope object. For configuration handlers, this will usually equal the owner.
3317*/
3318YAHOO.widget.Panel.prototype.configzIndex = function(type, args, obj) {
3319 YAHOO.widget.Panel.superclass.configzIndex.call(this, type, args, obj);
3320
3321 var maskZ = 0;
3322 var currentZ = YAHOO.util.Dom.getStyle(this.element, "zIndex");
3323
3324 if (this.mask) {
3325 if (! currentZ || isNaN(currentZ)) {
3326 currentZ = 0;
3327 }
3328
3329 if (currentZ === 0) {
3330 this.cfg.setProperty("zIndex", 1);
3331 } else {
3332 maskZ = currentZ - 1;
3333 YAHOO.util.Dom.setStyle(this.mask, "zIndex", maskZ);
3334 }
3335
3336 }
3337};
3338
3339// END BUILT-IN PROPERTY EVENT HANDLERS //
3340
3341/**
3342* Builds the wrapping container around the Panel that is used for positioning the shadow and matte underlays. The container element is assigned to a local instance variable called container, and the element is reinserted inside of it.
3343* @method buildWrapper
3344*/
3345YAHOO.widget.Panel.prototype.buildWrapper = function() {
3346 var elementParent = this.element.parentNode;
3347 var originalElement = this.element;
3348
3349 var wrapper = document.createElement("DIV");
3350 wrapper.className = YAHOO.widget.Panel.CSS_PANEL_CONTAINER;
3351 wrapper.id = originalElement.id + "_c";
3352
3353 if (elementParent) {
3354 elementParent.insertBefore(wrapper, originalElement);
3355 }
3356
3357 wrapper.appendChild(originalElement);
3358
3359 this.element = wrapper;
3360 this.innerElement = originalElement;
3361
3362 YAHOO.util.Dom.setStyle(this.innerElement, "visibility", "inherit");
3363};
3364
3365/**
3366* Adjusts the size of the shadow based on the size of the element.
3367* @method sizeUnderlay
3368*/
3369YAHOO.widget.Panel.prototype.sizeUnderlay = function() {
3370 if (this.underlay && this.browser != "gecko" && this.browser != "safari") {
3371 this.underlay.style.width = this.innerElement.offsetWidth + "px";
3372 this.underlay.style.height = this.innerElement.offsetHeight + "px";
3373 }
3374};
3375
3376/**
3377* Event handler fired when the resize monitor element is resized.
3378* @method onDomResize
3379 * @param {DOMEvent} eThe resize DOM event
3380 * @param {Object} objThe scope object
3381*/
3382YAHOO.widget.Panel.prototype.onDomResize = function(e, obj) {
3383 YAHOO.widget.Panel.superclass.onDomResize.call(this, e, obj);
3384 var me = this;
3385 setTimeout(function() {
3386 me.sizeUnderlay();
3387 }, 0);
3388};
3389
3390/**
3391* Registers the Panel's header for drag & drop capability.
3392* @method registerDragDrop
3393*/
3394YAHOO.widget.Panel.prototype.registerDragDrop = function() {
3395 if (this.header) {
3396 this.dd = new YAHOO.util.DD(this.element.id, this.id);
3397
3398 if (! this.header.id) {
3399 this.header.id = this.id + "_h";
3400 }
3401
3402 var me = this;
3403
3404 this.dd.startDrag = function() {
3405
3406 if (me.browser == "ie") {
3407 YAHOO.util.Dom.addClass(me.element,"drag");
3408 }
3409
3410 if (me.cfg.getProperty("constraintoviewport")) {
3411 var offsetHeight = me.element.offsetHeight;
3412 var offsetWidth = me.element.offsetWidth;
3413
3414 var viewPortWidth = YAHOO.util.Dom.getViewportWidth();
3415 var viewPortHeight = YAHOO.util.Dom.getViewportHeight();
3416
3417 var scrollX = window.scrollX || document.documentElement.scrollLeft;
3418 var scrollY = window.scrollY || document.documentElement.scrollTop;
3419
3420 var topConstraint = scrollY + 10;
3421 var leftConstraint = scrollX + 10;
3422 var bottomConstraint = scrollY + viewPortHeight - offsetHeight - 10;
3423 var rightConstraint = scrollX + viewPortWidth - offsetWidth - 10;
3424
3425 this.minX = leftConstraint;
3426 this.maxX = rightConstraint;
3427 this.constrainX = true;
3428
3429 this.minY = topConstraint;
3430 this.maxY = bottomConstraint;
3431 this.constrainY = true;
3432 } else {
3433 this.constrainX = false;
3434 this.constrainY = false;
3435 }
3436
3437 me.dragEvent.fire("startDrag", arguments);
3438 };
3439
3440 this.dd.onDrag = function() {
3441 me.syncPosition();
3442 me.cfg.refireEvent("iframe");
3443 if (this.platform == "mac" && this.browser == "gecko") {
3444 this.showMacGeckoScrollbars();
3445 }
3446
3447 me.dragEvent.fire("onDrag", arguments);
3448 };
3449
3450 this.dd.endDrag = function() {
3451 if (me.browser == "ie") {
3452 YAHOO.util.Dom.removeClass(me.element,"drag");
3453 }
3454
3455 me.dragEvent.fire("endDrag", arguments);
3456 };
3457
3458 this.dd.setHandleElId(this.header.id);
3459 this.dd.addInvalidHandleType("INPUT");
3460 this.dd.addInvalidHandleType("SELECT");
3461 this.dd.addInvalidHandleType("TEXTAREA");
3462 }
3463};
3464
3465/**
3466* Builds the mask that is laid over the document when the Panel is configured to be modal.
3467* @method buildMask
3468*/
3469YAHOO.widget.Panel.prototype.buildMask = function() {
3470 if (! this.mask) {
3471 this.mask = document.createElement("DIV");
3472 this.mask.id = this.id + "_mask";
3473 this.mask.className = "mask";
3474 this.mask.innerHTML = "&nbsp;";
3475
3476 var maskClick = function(e, obj) {
3477 YAHOO.util.Event.stopEvent(e);
3478 };
3479
3480 var firstChild = document.body.firstChild;
3481 if (firstChild){
3482 document.body.insertBefore(this.mask, document.body.firstChild);
3483 } else {
3484 document.body.appendChild(this.mask);
3485 }
3486 }
3487};
3488
3489/**
3490* Hides the modality mask.
3491* @method hideMask
3492*/
3493YAHOO.widget.Panel.prototype.hideMask = function() {
3494 if (this.cfg.getProperty("modal") && this.mask) {
3495 this.mask.style.display = "none";
3496 this.hideMaskEvent.fire();
3497 YAHOO.util.Dom.removeClass(document.body, "masked");
3498 }
3499};
3500
3501/**
3502* Shows the modality mask.
3503* @method showMask
3504*/
3505YAHOO.widget.Panel.prototype.showMask = function() {
3506 if (this.cfg.getProperty("modal") && this.mask) {
3507 YAHOO.util.Dom.addClass(document.body, "masked");
3508 this.sizeMask();
3509 this.mask.style.display = "block";
3510 this.showMaskEvent.fire();
3511 }
3512};
3513
3514/**
3515* Sets the size of the modality mask to cover the entire scrollable area of the document
3516* @method sizeMask
3517*/
3518YAHOO.widget.Panel.prototype.sizeMask = function() {
3519 if (this.mask) {
3520 this.mask.style.height = YAHOO.util.Dom.getDocumentHeight()+"px";
3521 this.mask.style.width = YAHOO.util.Dom.getDocumentWidth()+"px";
3522 }
3523};
3524
3525/**
3526* Renders the Panel by inserting the elements that are not already in the main Panel into their correct places. Optionally appends the Panel to the specified node prior to the render's execution. NOTE: For Panels without existing markup, the appendToNode argument is REQUIRED. If this argument is ommitted and the current element is not present in the document, the function will return false, indicating that the render was a failure.
3527* @method render
3528 * @param {String} appendToNodeThe element id to which the Module should be appended to prior to rendering <em>OR</em>
3529 * @param {HTMLElement} appendToNodeThe element to which the Module should be appended to prior to rendering
3530* @return {boolean} Success or failure of the render
3531*/
3532YAHOO.widget.Panel.prototype.render = function(appendToNode) {
3533 return YAHOO.widget.Panel.superclass.render.call(this, appendToNode, this.innerElement);
3534};
3535
3536/**
3537* Returns a String representation of the object.
3538* @method toString
3539* @return {String} The string representation of the Panel.
3540*/
3541YAHOO.widget.Panel.prototype.toString = function() {
3542 return "Panel " + this.id;
3543};
3544
3545/**
3546* Dialog is an implementation of Panel that can be used to submit form data. Built-in functionality for buttons with event handlers is included, and button sets can be build dynamically, or the preincluded ones for Submit/Cancel and OK/Cancel can be utilized. Forms can be processed in 3 ways -- via an asynchronous Connection utility call, a simple form POST or GET, or manually.
3547* @namespace YAHOO.widget
3548* @class Dialog
3549* @extends YAHOO.widget.Panel
3550* @constructor
3551 * @param {String} elThe element ID representing the Dialog <em>OR</em>
3552 * @param {HTMLElement} elThe element representing the Dialog
3553 * @param {Object} userConfigThe configuration object literal containing the configuration that should be set for this Dialog. See configuration documentation for more details.
3554*/
3555YAHOO.widget.Dialog = function(el, userConfig) {
3556 YAHOO.widget.Dialog.superclass.constructor.call(this, el, userConfig);
3557};
3558
3559YAHOO.extend(YAHOO.widget.Dialog, YAHOO.widget.Panel);
3560
3561/**
3562* Constant representing the default CSS class used for a Dialog
3563* @property YAHOO.widget.Dialog.CSS_DIALOG
3564* @static
3565* @final
3566* @type String
3567*/
3568YAHOO.widget.Dialog.CSS_DIALOG = "dialog";
3569
3570/**
3571* Initializes the class's configurable properties which can be changed using the Dialog's Config object (cfg).
3572* @method initDefaultConfig
3573*/
3574YAHOO.widget.Dialog.prototype.initDefaultConfig = function() {
3575 YAHOO.widget.Dialog.superclass.initDefaultConfig.call(this);
3576
3577 /**
3578 * The internally maintained callback object for use with the Connection utility
3579 * @property callback
3580 * @type Object
3581 */
3582 this.callback = {
3583 /**
3584 * The function to execute upon success of the Connection submission
3585 * @property callback.success
3586 * @type Function
3587 */
3588 success : null,
3589 /**
3590 * The function to execute upon failure of the Connection submission
3591 * @property callback.failure
3592 * @type Function
3593 */
3594 failure : null,
3595 /**
3596 * The arbitraty argument or arguments to pass to the Connection callback functions
3597 * @property callback.argument
3598 * @type Object
3599 */
3600 argument: null
3601 };
3602
3603 // Add form dialog config properties //
3604
3605 /**
3606 * The method to use for posting the Dialog's form. Possible values are "async", "form", and "manual".
3607 * @config postmethod
3608 * @type String
3609 * @default async
3610 */
3611 this.cfg.addProperty("postmethod", { value:"async", validator:function(val) {
3612 if (val != "form" && val != "async" && val != "none" && val != "manual") {
3613 return false;
3614 } else {
3615 return true;
3616 }
3617 } });
3618
3619 /**
3620 * Object literal(s) defining the buttons for the Dialog's footer.
3621 * @config buttons
3622 * @type Object[]
3623 * @default "none"
3624 */
3625 this.cfg.addProperty("buttons", { value:"none",handler:this.configButtons } );
3626};
3627
3628/**
3629* Initializes the custom events for Dialog which are fired automatically at appropriate times by the Dialog class.
3630* @method initEvents
3631*/
3632YAHOO.widget.Dialog.prototype.initEvents = function() {
3633 YAHOO.widget.Dialog.superclass.initEvents.call(this);
3634
3635 /**
3636 * CustomEvent fired prior to submission
3637 * @event beforeSumitEvent
3638 */
3639 this.beforeSubmitEvent= new YAHOO.util.CustomEvent("beforeSubmit");
3640
3641 /**
3642 * CustomEvent fired after submission
3643 * @event submitEvent
3644 */
3645 this.submitEvent = new YAHOO.util.CustomEvent("submit");
3646
3647 /**
3648 * CustomEvent fired prior to manual submission
3649 * @event manualSubmitEvent
3650 */
3651 this.manualSubmitEvent= new YAHOO.util.CustomEvent("manualSubmit");
3652
3653 /**
3654 * CustomEvent fired prior to asynchronous submission
3655 * @event asyncSubmitEvent
3656 */
3657 this.asyncSubmitEvent= new YAHOO.util.CustomEvent("asyncSubmit");
3658
3659 /**
3660 * CustomEvent fired prior to form-based submission
3661 * @event formSubmitEvent
3662 */
3663 this.formSubmitEvent= new YAHOO.util.CustomEvent("formSubmit");
3664
3665 /**
3666 * CustomEvent fired after cancel
3667 * @event cancelEvent
3668 */
3669 this.cancelEvent = new YAHOO.util.CustomEvent("cancel");
3670};
3671
3672/**
3673* The Dialog initialization method, which is executed for Dialog and all of its subclasses. This method is automatically called by the constructor, and sets up all DOM references for pre-existing markup, and creates required markup if it is not already present.
3674* @method init
3675 * @param {String} elThe element ID representing the Dialog <em>OR</em>
3676 * @param {HTMLElement} elThe element representing the Dialog
3677 * @param {Object} userConfigThe configuration object literal containing the configuration that should be set for this Dialog. See configuration documentation for more details.
3678*/
3679YAHOO.widget.Dialog.prototype.init = function(el, userConfig) {
3680 YAHOO.widget.Dialog.superclass.init.call(this, el/*, userConfig*/); // Note that we don't pass the user config in here yet because we only want it executed once, at the lowest subclass level
3681
3682 this.beforeInitEvent.fire(YAHOO.widget.Dialog);
3683
3684 YAHOO.util.Dom.addClass(this.element, YAHOO.widget.Dialog.CSS_DIALOG);
3685
3686 this.cfg.setProperty("visible", false);
3687
3688 if (userConfig) {
3689 this.cfg.applyConfig(userConfig, true);
3690 }
3691
3692 this.renderEvent.subscribe(this.registerForm, this, true);
3693
3694 this.showEvent.subscribe(this.focusFirst, this, true);
3695 this.beforeHideEvent.subscribe(this.blurButtons, this, true);
3696
3697 this.beforeRenderEvent.subscribe(function() {
3698 var buttonCfg = this.cfg.getProperty("buttons");
3699 if (buttonCfg && buttonCfg != "none") {
3700 if (! this.footer) {
3701 this.setFooter("");
3702 }
3703 }
3704 }, this, true);
3705
3706 this.initEvent.fire(YAHOO.widget.Dialog);
3707};
3708
3709/**
3710* Performs the submission of the Dialog form depending on the value of "postmethod" property.
3711* @method doSubmit
3712*/
3713YAHOO.widget.Dialog.prototype.doSubmit = function() {
3714 var pm = this.cfg.getProperty("postmethod");
3715 switch (pm) {
3716 case "async":
3717 var method = this.form.getAttribute("method") || 'POST';
3718 method = method.toUpperCase();
3719 YAHOO.util.Connect.setForm(this.form);
3720 var cObj = YAHOO.util.Connect.asyncRequest(method, this.form.getAttribute("action"), this.callback);
3721 this.asyncSubmitEvent.fire();
3722 break;
3723 case "form":
3724 this.form.submit();
3725 this.formSubmitEvent.fire();
3726 break;
3727 case "none":
3728 case "manual":
3729 this.manualSubmitEvent.fire();
3730 break;
3731 }
3732};
3733
3734/**
3735* Prepares the Dialog's internal FORM object, creating one if one is not currently present.
3736* @method registerForm
3737*/
3738YAHOO.widget.Dialog.prototype.registerForm = function() {
3739 var form = this.element.getElementsByTagName("FORM")[0];
3740
3741 if (! form) {
3742 var formHTML = "<form name=\"frm_" + this.id + "\" action=\"\"></form>";
3743 this.body.innerHTML += formHTML;
3744 form = this.element.getElementsByTagName("FORM")[0];
3745 }
3746
3747 this.firstFormElement = function() {
3748 for (var f=0;f<form.elements.length;f++ ) {
3749 var el = form.elements[f];
3750 if (el.focus) {
3751 if (el.type && el.type != "hidden") {
3752 return el;
3753 }
3754 }
3755 }
3756 return null;
3757 }();
3758
3759 this.lastFormElement = function() {
3760 for (var f=form.elements.length-1;f>=0;f-- ) {
3761 var el = form.elements[f];
3762 if (el.focus) {
3763 if (el.type && el.type != "hidden") {
3764 return el;
3765 }
3766 }
3767 }
3768 return null;
3769 }();
3770
3771 this.form = form;
3772
3773 if (this.cfg.getProperty("modal") && this.form) {
3774
3775 var me = this;
3776
3777 var firstElement = this.firstFormElement || this.firstButton;
3778 if (firstElement) {
3779 this.preventBackTab = new YAHOO.util.KeyListener(firstElement, { shift:true, keys:9 }, {fn:me.focusLast, scope:me, correctScope:true} );
3780 this.showEvent.subscribe(this.preventBackTab.enable, this.preventBackTab, true);
3781 this.hideEvent.subscribe(this.preventBackTab.disable, this.preventBackTab, true);
3782 }
3783
3784 var lastElement = this.lastButton || this.lastFormElement;
3785 if (lastElement) {
3786 this.preventTabOut = new YAHOO.util.KeyListener(lastElement, { shift:false, keys:9 }, {fn:me.focusFirst, scope:me, correctScope:true} );
3787 this.showEvent.subscribe(this.preventTabOut.enable, this.preventTabOut, true);
3788 this.hideEvent.subscribe(this.preventTabOut.disable, this.preventTabOut, true);
3789 }
3790 }
3791};
3792
3793// BEGIN BUILT-IN PROPERTY EVENT HANDLERS //
3794
3795/**
3796* The default event handler for the "buttons" configuration property
3797* @method configButtons
3798 * @param {String} typeThe CustomEvent type (usually the property name)
3799 * @param {Object[]} argsThe CustomEvent arguments. For configuration handlers, args[0] will equal the newly applied value for the property.
3800 * @param {Object} objThe scope object. For configuration handlers, this will usually equal the owner.
3801*/
3802YAHOO.widget.Dialog.prototype.configButtons = function(type, args, obj) {
3803 var buttons = args[0];
3804 if (buttons != "none") {
3805 this.buttonSpan = null;
3806 this.buttonSpan = document.createElement("SPAN");
3807 this.buttonSpan.className = "button-group";
3808
3809 for (var b=0;b<buttons.length;b++) {
3810 var button = buttons[b];
3811
3812 var htmlButton = document.createElement("BUTTON");
3813 htmlButton.setAttribute("type", "button");
3814
3815 if (button.isDefault) {
3816 htmlButton.className = "default";
3817 this.defaultHtmlButton = htmlButton;
3818 }
3819
3820 htmlButton.appendChild(document.createTextNode(button.text));
3821 YAHOO.util.Event.addListener(htmlButton, "click", button.handler, this, true);
3822
3823 this.buttonSpan.appendChild(htmlButton);
3824 button.htmlButton = htmlButton;
3825
3826 if (b === 0) {
3827 this.firstButton = button.htmlButton;
3828 }
3829
3830 if (b == (buttons.length-1)) {
3831 this.lastButton = button.htmlButton;
3832 }
3833
3834 }
3835
3836 this.setFooter(this.buttonSpan);
3837
3838 this.cfg.refireEvent("iframe");
3839 this.cfg.refireEvent("underlay");
3840 } else { // Do cleanup
3841 if (this.buttonSpan) {
3842 if (this.buttonSpan.parentNode) {
3843 this.buttonSpan.parentNode.removeChild(this.buttonSpan);
3844 }
3845
3846 this.buttonSpan = null;
3847 this.firstButton = null;
3848 this.lastButton = null;
3849 this.defaultHtmlButton = null;
3850 }
3851 }
3852};
3853
3854
3855/**
3856* The default event handler used to focus the first field of the form when the Dialog is shown.
3857* @method focusFirst
3858*/
3859YAHOO.widget.Dialog.prototype.focusFirst = function(type,args,obj) {
3860 if (args) {
3861 var e = args[1];
3862 if (e) {
3863 YAHOO.util.Event.stopEvent(e);
3864 }
3865 }
3866
3867 if (this.firstFormElement) {
3868 this.firstFormElement.focus();
3869 } else {
3870 this.focusDefaultButton();
3871 }
3872};
3873
3874/**
3875* Sets the focus to the last button in the button or form element in the Dialog
3876* @method focusLast
3877*/
3878YAHOO.widget.Dialog.prototype.focusLast = function(type,args,obj) {
3879 if (args) {
3880 var e = args[1];
3881 if (e) {
3882 YAHOO.util.Event.stopEvent(e);
3883 }
3884 }
3885
3886 var buttons = this.cfg.getProperty("buttons");
3887 if (buttons && buttons instanceof Array) {
3888 this.focusLastButton();
3889 } else {
3890 if (this.lastFormElement) {
3891 this.lastFormElement.focus();
3892 }
3893 }
3894};
3895
3896/**
3897* Sets the focus to the button that is designated as the default. By default, his handler is executed when the show event is fired.
3898* @method focusDefaultButton
3899*/
3900YAHOO.widget.Dialog.prototype.focusDefaultButton = function() {
3901 if (this.defaultHtmlButton) {
3902 this.defaultHtmlButton.focus();
3903 }
3904};
3905
3906/**
3907* Blurs all the html buttons
3908* @method blurButtons
3909*/
3910YAHOO.widget.Dialog.prototype.blurButtons = function() {
3911 var buttons = this.cfg.getProperty("buttons");
3912 if (buttons && buttons instanceof Array) {
3913 var html = buttons[0].htmlButton;
3914 if (html) {
3915 html.blur();
3916 }
3917 }
3918};
3919
3920/**
3921* Sets the focus to the first button in the button list
3922* @method focusFirstButton
3923*/
3924YAHOO.widget.Dialog.prototype.focusFirstButton = function() {
3925 var buttons = this.cfg.getProperty("buttons");
3926 if (buttons && buttons instanceof Array) {
3927 var html = buttons[0].htmlButton;
3928 if (html) {
3929 html.focus();
3930 }
3931 }
3932};
3933
3934/**
3935* Sets the focus to the first button in the button list
3936* @method focusLastButton
3937*/
3938YAHOO.widget.Dialog.prototype.focusLastButton = function() {
3939 var buttons = this.cfg.getProperty("buttons");
3940 if (buttons && buttons instanceof Array) {
3941 var html = buttons[buttons.length-1].htmlButton;
3942 if (html) {
3943 html.focus();
3944 }
3945 }
3946};
3947
3948// END BUILT-IN PROPERTY EVENT HANDLERS //
3949
3950/**
3951* Built-in function hook for writing a validation function that will be checked for a "true" value prior to a submit. This function, as implemented by default, always returns true, so it should be overridden if validation is necessary.
3952* @method validate
3953*/
3954YAHOO.widget.Dialog.prototype.validate = function() {
3955 return true;
3956};
3957
3958/**
3959* Executes a submit of the Dialog followed by a hide, if validation is successful.
3960* @method submit
3961*/
3962YAHOO.widget.Dialog.prototype.submit = function() {
3963 if (this.validate()) {
3964 this.beforeSubmitEvent.fire();
3965 this.doSubmit();
3966 this.submitEvent.fire();
3967 this.hide();
3968 return true;
3969 } else {
3970 return false;
3971 }
3972};
3973
3974/**
3975* Executes the cancel of the Dialog followed by a hide.
3976* @method cancel
3977*/
3978YAHOO.widget.Dialog.prototype.cancel = function() {
3979 this.cancelEvent.fire();
3980 this.hide();
3981};
3982
3983/**
3984* Returns a JSON-compatible data structure representing the data currently contained in the form.
3985* @method getData
3986* @return {Object} A JSON object reprsenting the data of the current form.
3987*/
3988YAHOO.widget.Dialog.prototype.getData = function() {
3989 var form = this.form;
3990 var data = {};
3991
3992 if (form) {
3993 for (var i in this.form) {
3994 var formItem = form[i];
3995 if (formItem) {
3996 if (formItem.tagName) { // Got a single form item
3997 switch (formItem.tagName) {
3998 case "INPUT":
3999 switch (formItem.type) {
4000 case "checkbox":
4001 data[i] = formItem.checked;
4002 break;
4003 case "textbox":
4004 case "text":
4005 case "hidden":
4006 data[i] = formItem.value;
4007 break;
4008 }
4009 break;
4010 case "TEXTAREA":
4011 data[i] = formItem.value;
4012 break;
4013 case "SELECT":
4014 var val = [];
4015 for (var x=0;x<formItem.options.length;x++){
4016 var option = formItem.options[x];
4017 if (option.selected) {
4018 var selval = option.value;
4019 if (! selval || selval === "") {
4020 selval = option.text;
4021 }
4022 val[val.length] = selval;
4023 }
4024 }
4025 data[i] = val;
4026 break;
4027 }
4028 } else if (formItem[0] && formItem[0].tagName) { // this is an array of form items
4029 if (formItem[0].tagName == "INPUT") {
4030 switch (formItem[0].type) {
4031 case "radio":
4032 for (var r=0; r<formItem.length; r++) {
4033 var radio = formItem[r];
4034 if (radio.checked) {
4035 data[radio.name] = radio.value;
4036 break;
4037 }
4038 }
4039 break;
4040 case "checkbox":
4041 var cbArray = [];
4042 for (var c=0; c<formItem.length; c++) {
4043 var check = formItem[c];
4044 if (check.checked) {
4045 cbArray[cbArray.length] = check.value;
4046 }
4047 }
4048 data[formItem[0].name] = cbArray;
4049 break;
4050 }
4051 }
4052 }
4053 }
4054 }
4055 }
4056 return data;
4057};
4058
4059/**
4060* Returns a string representation of the object.
4061* @method toString
4062 * @return {String}The string representation of the Dialog
4063*/
4064YAHOO.widget.Dialog.prototype.toString = function() {
4065 return "Dialog " + this.id;
4066};
4067
4068/**
4069* SimpleDialog is a simple implementation of Dialog that can be used to submit a single value. Forms can be processed in 3 ways -- via an asynchronous Connection utility call, a simple form POST or GET, or manually.
4070* @namespace YAHOO.widget
4071* @class SimpleDialog
4072* @extends YAHOO.widget.Dialog
4073* @constructor
4074 * @param {String} elThe element ID representing the SimpleDialog <em>OR</em>
4075 * @param {HTMLElement} elThe element representing the SimpleDialog
4076 * @param {Object} userConfigThe configuration object literal containing the configuration that should be set for this SimpleDialog. See configuration documentation for more details.
4077*/
4078YAHOO.widget.SimpleDialog = function(el, userConfig) {
4079 YAHOO.widget.SimpleDialog.superclass.constructor.call(this, el, userConfig);
4080};
4081
4082YAHOO.extend(YAHOO.widget.SimpleDialog, YAHOO.widget.Dialog);
4083
4084/**
4085* Constant for the standard network icon for a blocking action
4086* @property YAHOO.widget.SimpleDialog.ICON_BLOCK
4087* @static
4088* @final
4089* @type String
4090*/
4091YAHOO.widget.SimpleDialog.ICON_BLOCK = "nt/ic/ut/bsc/blck16_1.gif";
4092
4093/**
4094* Constant for the standard network icon for alarm
4095* @property YAHOO.widget.SimpleDialog.ICON_ALARM
4096* @static
4097* @final
4098* @type String
4099*/
4100YAHOO.widget.SimpleDialog.ICON_ALARM = "nt/ic/ut/bsc/alrt16_1.gif";
4101
4102/**
4103* Constant for the standard network icon for help
4104* @property YAHOO.widget.SimpleDialog.ICON_HELP
4105* @static
4106* @final
4107* @type String
4108*/
4109YAHOO.widget.SimpleDialog.ICON_HELP = "nt/ic/ut/bsc/hlp16_1.gif";
4110
4111/**
4112* Constant for the standard network icon for info
4113* @property YAHOO.widget.SimpleDialog.ICON_INFO
4114* @static
4115* @final
4116* @type String
4117*/
4118YAHOO.widget.SimpleDialog.ICON_INFO = "nt/ic/ut/bsc/info16_1.gif";
4119
4120/**
4121* Constant for the standard network icon for warn
4122* @property YAHOO.widget.SimpleDialog.ICON_WARN
4123* @static
4124* @final
4125* @type String
4126*/
4127YAHOO.widget.SimpleDialog.ICON_WARN = "nt/ic/ut/bsc/warn16_1.gif";
4128
4129/**
4130* Constant for the standard network icon for a tip
4131* @property YAHOO.widget.SimpleDialog.ICON_TIP
4132* @static
4133* @final
4134* @type String
4135*/
4136YAHOO.widget.SimpleDialog.ICON_TIP = "nt/ic/ut/bsc/tip16_1.gif";
4137
4138/**
4139* Constant representing the default CSS class used for a SimpleDialog
4140* @property YAHOO.widget.SimpleDialog.CSS_SIMPLEDIALOG
4141* @static
4142* @final
4143* @type String
4144*/
4145YAHOO.widget.SimpleDialog.CSS_SIMPLEDIALOG = "simple-dialog";
4146
4147/**
4148* Initializes the class's configurable properties which can be changed using the SimpleDialog's Config object (cfg).
4149* @method initDefaultConfig
4150*/
4151YAHOO.widget.SimpleDialog.prototype.initDefaultConfig = function() {
4152 YAHOO.widget.SimpleDialog.superclass.initDefaultConfig.call(this);
4153
4154 // Add dialog config properties //
4155
4156 /**
4157 * Sets the informational icon for the SimpleDialog
4158 * @config icon
4159 * @type String
4160 * @default "none"
4161 */
4162 this.cfg.addProperty("icon", { value:"none",handler:this.configIcon, suppressEvent:true } );
4163
4164 /**
4165 * Sets the text for the SimpleDialog
4166 * @config text
4167 * @type String
4168 * @default ""
4169 */
4170 this.cfg.addProperty("text",{ value:"", handler:this.configText, suppressEvent:true, supercedes:["icon"] } );
4171};
4172
4173
4174/**
4175* The SimpleDialog initialization method, which is executed for SimpleDialog and all of its subclasses. This method is automatically called by the constructor, and sets up all DOM references for pre-existing markup, and creates required markup if it is not already present.
4176* @method init
4177 * @param {String} elThe element ID representing the SimpleDialog <em>OR</em>
4178 * @param {HTMLElement} elThe element representing the SimpleDialog
4179 * @param {Object} userConfigThe configuration object literal containing the configuration that should be set for this SimpleDialog. See configuration documentation for more details.
4180*/
4181YAHOO.widget.SimpleDialog.prototype.init = function(el, userConfig) {
4182 YAHOO.widget.SimpleDialog.superclass.init.call(this, el/*, userConfig*/); // Note that we don't pass the user config in here yet because we only want it executed once, at the lowest subclass level
4183
4184 this.beforeInitEvent.fire(YAHOO.widget.SimpleDialog);
4185
4186 YAHOO.util.Dom.addClass(this.element, YAHOO.widget.SimpleDialog.CSS_SIMPLEDIALOG);
4187
4188 this.cfg.queueProperty("postmethod", "manual");
4189
4190 if (userConfig) {
4191 this.cfg.applyConfig(userConfig, true);
4192 }
4193
4194 this.beforeRenderEvent.subscribe(function() {
4195 if (! this.body) {
4196 this.setBody("");
4197 }
4198 }, this, true);
4199
4200 this.initEvent.fire(YAHOO.widget.SimpleDialog);
4201
4202};
4203/**
4204* Prepares the SimpleDialog's internal FORM object, creating one if one is not currently present, and adding the value hidden field.
4205* @method registerForm
4206*/
4207YAHOO.widget.SimpleDialog.prototype.registerForm = function() {
4208 YAHOO.widget.SimpleDialog.superclass.registerForm.call(this);
4209 this.form.innerHTML += "<input type=\"hidden\" name=\"" + this.id + "\" value=\"\"/>";
4210};
4211
4212// BEGIN BUILT-IN PROPERTY EVENT HANDLERS //
4213
4214/**
4215* Fired when the "icon" property is set.
4216* @method configIcon
4217 * @param {String} typeThe CustomEvent type (usually the property name)
4218 * @param {Object[]} argsThe CustomEvent arguments. For configuration handlers, args[0] will equal the newly applied value for the property.
4219 * @param {Object} objThe scope object. For configuration handlers, this will usually equal the owner.
4220*/
4221YAHOO.widget.SimpleDialog.prototype.configIcon = function(type,args,obj) {
4222 var icon = args[0];
4223 if (icon && icon != "none") {
4224 var iconHTML = "<img src=\"" + this.imageRoot + icon + "\" class=\"icon\" />";
4225 this.body.innerHTML = iconHTML + this.body.innerHTML;
4226 }
4227};
4228
4229/**
4230* Fired when the "text" property is set.
4231* @method configText
4232 * @param {String} typeThe CustomEvent type (usually the property name)
4233 * @param {Object[]} argsThe CustomEvent arguments. For configuration handlers, args[0] will equal the newly applied value for the property.
4234 * @param {Object} objThe scope object. For configuration handlers, this will usually equal the owner.
4235*/
4236YAHOO.widget.SimpleDialog.prototype.configText = function(type,args,obj) {
4237 var text = args[0];
4238 if (text) {
4239 this.setBody(text);
4240 this.cfg.refireEvent("icon");
4241 }
4242};
4243// END BUILT-IN PROPERTY EVENT HANDLERS //
4244
4245/**
4246* Returns a string representation of the object.
4247* @method toString
4248 * @return {String}The string representation of the SimpleDialog
4249*/
4250YAHOO.widget.SimpleDialog.prototype.toString = function() {
4251 return "SimpleDialog " + this.id;
4252};
4253
4254/**
4255* ContainerEffect encapsulates animation transitions that are executed when an Overlay is shown or hidden.
4256* @namespace YAHOO.widget
4257* @class ContainerEffect
4258* @constructor
4259 * @param {YAHOO.widget.Overlay} overlay The Overlay that the animation should be associated with
4260 * @param {Object} attrIn The object literal representing the animation arguments to be used for the animate-in transition. The arguments for this literal are: attributes(object, see YAHOO.util.Anim for description), duration(Number), and method(i.e. YAHOO.util.Easing.easeIn).
4261 * @param {Object} attrOut The object literal representing the animation arguments to be used for the animate-out transition. The arguments for this literal are: attributes(object, see YAHOO.util.Anim for description), duration(Number), and method(i.e. YAHOO.util.Easing.easeIn).
4262 * @param {HTMLElement} targetElementOptional. The target element that should be animated during the transition. Defaults to overlay.element.
4263 * @param {class}Optional. The animation class to instantiate. Defaults to YAHOO.util.Anim. Other options include YAHOO.util.Motion.
4264*/
4265YAHOO.widget.ContainerEffect = function(overlay, attrIn, attrOut, targetElement, animClass) {
4266 if (! animClass) {
4267 animClass = YAHOO.util.Anim;
4268 }
4269
4270 /**
4271 * The overlay to animate
4272 * @property overlay
4273 * @type YAHOO.widget.Overlay
4274 */
4275 this.overlay = overlay;
4276 /**
4277 * The animation attributes to use when transitioning into view
4278 * @property attrIn
4279 * @type Object
4280 */
4281 this.attrIn = attrIn;
4282 /**
4283 * The animation attributes to use when transitioning out of view
4284 * @property attrOut
4285 * @type Object
4286 */
4287 this.attrOut = attrOut;
4288 /**
4289 * The target element to be animated
4290 * @property targetElement
4291 * @type HTMLElement
4292 */
4293 this.targetElement = targetElement || overlay.element;
4294 /**
4295 * The animation class to use for animating the overlay
4296 * @property animClass
4297 * @type class
4298 */
4299 this.animClass = animClass;
4300};
4301
4302/**
4303* Initializes the animation classes and events.
4304* @method init
4305*/
4306YAHOO.widget.ContainerEffect.prototype.init = function() {
4307 this.beforeAnimateInEvent = new YAHOO.util.CustomEvent("beforeAnimateIn");
4308 this.beforeAnimateOutEvent = new YAHOO.util.CustomEvent("beforeAnimateOut");
4309
4310 this.animateInCompleteEvent = new YAHOO.util.CustomEvent("animateInComplete");
4311 this.animateOutCompleteEvent = new YAHOO.util.CustomEvent("animateOutComplete");
4312
4313 this.animIn = new this.animClass(this.targetElement, this.attrIn.attributes, this.attrIn.duration, this.attrIn.method);
4314 this.animIn.onStart.subscribe(this.handleStartAnimateIn, this);
4315 this.animIn.onTween.subscribe(this.handleTweenAnimateIn, this);
4316 this.animIn.onComplete.subscribe(this.handleCompleteAnimateIn, this);
4317
4318 this.animOut = new this.animClass(this.targetElement, this.attrOut.attributes, this.attrOut.duration, this.attrOut.method);
4319 this.animOut.onStart.subscribe(this.handleStartAnimateOut, this);
4320 this.animOut.onTween.subscribe(this.handleTweenAnimateOut, this);
4321 this.animOut.onComplete.subscribe(this.handleCompleteAnimateOut, this);
4322};
4323
4324/**
4325* Triggers the in-animation.
4326* @method animateIn
4327*/
4328YAHOO.widget.ContainerEffect.prototype.animateIn = function() {
4329 this.beforeAnimateInEvent.fire();
4330 this.animIn.animate();
4331};
4332
4333/**
4334* Triggers the out-animation.
4335* @method animateOut
4336*/
4337YAHOO.widget.ContainerEffect.prototype.animateOut = function() {
4338 this.beforeAnimateOutEvent.fire();
4339 this.animOut.animate();
4340};
4341
4342/**
4343* The default onStart handler for the in-animation.
4344* @method handleStartAnimateIn
4345 * @param {String} typeThe CustomEvent type
4346 * @param {Object[]} argsThe CustomEvent arguments
4347 * @param {Object} objThe scope object
4348*/
4349YAHOO.widget.ContainerEffect.prototype.handleStartAnimateIn = function(type, args, obj) { };
4350/**
4351* The default onTween handler for the in-animation.
4352* @method handleTweenAnimateIn
4353 * @param {String} typeThe CustomEvent type
4354 * @param {Object[]} argsThe CustomEvent arguments
4355 * @param {Object} objThe scope object
4356*/
4357YAHOO.widget.ContainerEffect.prototype.handleTweenAnimateIn = function(type, args, obj) { };
4358/**
4359* The default onComplete handler for the in-animation.
4360* @method handleCompleteAnimateIn
4361 * @param {String} typeThe CustomEvent type
4362 * @param {Object[]} argsThe CustomEvent arguments
4363 * @param {Object} objThe scope object
4364*/
4365YAHOO.widget.ContainerEffect.prototype.handleCompleteAnimateIn = function(type, args, obj) { };
4366
4367/**
4368* The default onStart handler for the out-animation.
4369* @method handleStartAnimateOut
4370 * @param {String} typeThe CustomEvent type
4371 * @param {Object[]} argsThe CustomEvent arguments
4372 * @param {Object} objThe scope object
4373*/
4374YAHOO.widget.ContainerEffect.prototype.handleStartAnimateOut = function(type, args, obj) { };
4375/**
4376* The default onTween handler for the out-animation.
4377* @method handleTweenAnimateOut
4378 * @param {String} typeThe CustomEvent type
4379 * @param {Object[]} argsThe CustomEvent arguments
4380 * @param {Object} objThe scope object
4381*/
4382YAHOO.widget.ContainerEffect.prototype.handleTweenAnimateOut = function(type, args, obj) { };
4383/**
4384* The default onComplete handler for the out-animation.
4385* @method handleCompleteAnimateOut
4386 * @param {String} typeThe CustomEvent type
4387 * @param {Object[]} argsThe CustomEvent arguments
4388 * @param {Object} objThe scope object
4389*/
4390YAHOO.widget.ContainerEffect.prototype.handleCompleteAnimateOut = function(type, args, obj) { };
4391
4392/**
4393* Returns a string representation of the object.
4394* @method toString
4395 * @return {String}The string representation of the ContainerEffect
4396*/
4397YAHOO.widget.ContainerEffect.prototype.toString = function() {
4398 var output = "ContainerEffect";
4399 if (this.overlay) {
4400 output += " [" + this.overlay.toString() + "]";
4401 }
4402 return output;
4403};
4404
4405/**
4406* A pre-configured ContainerEffect instance that can be used for fading an overlay in and out.
4407* @method FADE
4408* @static
4409 * @param {Overlay}The Overlay object to animate
4410 * @param {Number}The duration of the animation
4411 * @return {ContainerEffect}The configured ContainerEffect object
4412*/
4413YAHOO.widget.ContainerEffect.FADE = function(overlay, dur) {
4414 var fade = new YAHOO.widget.ContainerEffect(overlay, { attributes:{opacity: {from:0, to:1}}, duration:dur, method:YAHOO.util.Easing.easeIn }, { attributes:{opacity: {to:0}}, duration:dur, method:YAHOO.util.Easing.easeOut}, overlay.element );
4415
4416 fade.handleStartAnimateIn = function(type,args,obj) {
4417 YAHOO.util.Dom.addClass(obj.overlay.element, "hide-select");
4418
4419 if (! obj.overlay.underlay) {
4420 obj.overlay.cfg.refireEvent("underlay");
4421 }
4422
4423 if (obj.overlay.underlay) {
4424 obj.initialUnderlayOpacity = YAHOO.util.Dom.getStyle(obj.overlay.underlay, "opacity");
4425 obj.overlay.underlay.style.filter = null;
4426 }
4427
4428 YAHOO.util.Dom.setStyle(obj.overlay.element, "visibility", "visible");
4429 YAHOO.util.Dom.setStyle(obj.overlay.element, "opacity", 0);
4430 };
4431
4432 fade.handleCompleteAnimateIn = function(type,args,obj) {
4433 YAHOO.util.Dom.removeClass(obj.overlay.element, "hide-select");
4434
4435 if (obj.overlay.element.style.filter) {
4436 obj.overlay.element.style.filter = null;
4437 }
4438
4439 if (obj.overlay.underlay) {
4440 YAHOO.util.Dom.setStyle(obj.overlay.underlay, "opacity", obj.initialUnderlayOpacity);
4441 }
4442
4443 obj.overlay.cfg.refireEvent("iframe");
4444 obj.animateInCompleteEvent.fire();
4445 };
4446
4447 fade.handleStartAnimateOut = function(type, args, obj) {
4448 YAHOO.util.Dom.addClass(obj.overlay.element, "hide-select");
4449
4450 if (obj.overlay.underlay) {
4451 obj.overlay.underlay.style.filter = null;
4452 }
4453 };
4454
4455 fade.handleCompleteAnimateOut = function(type, args, obj) {
4456 YAHOO.util.Dom.removeClass(obj.overlay.element, "hide-select");
4457 if (obj.overlay.element.style.filter) {
4458 obj.overlay.element.style.filter = null;
4459 }
4460 YAHOO.util.Dom.setStyle(obj.overlay.element, "visibility", "hidden");
4461 YAHOO.util.Dom.setStyle(obj.overlay.element, "opacity", 1);
4462
4463 obj.overlay.cfg.refireEvent("iframe");
4464
4465 obj.animateOutCompleteEvent.fire();
4466 };
4467
4468 fade.init();
4469 return fade;
4470};
4471
4472
4473/**
4474* A pre-configured ContainerEffect instance that can be used for sliding an overlay in and out.
4475* @method SLIDE
4476* @static
4477 * @param {Overlay}The Overlay object to animate
4478 * @param {Number}The duration of the animation
4479 * @return {ContainerEffect}The configured ContainerEffect object
4480*/
4481YAHOO.widget.ContainerEffect.SLIDE = function(overlay, dur) {
4482 var x = overlay.cfg.getProperty("x") || YAHOO.util.Dom.getX(overlay.element);
4483 var y = overlay.cfg.getProperty("y") || YAHOO.util.Dom.getY(overlay.element);
4484
4485 var clientWidth = YAHOO.util.Dom.getClientWidth();
4486 var offsetWidth = overlay.element.offsetWidth;
4487
4488 var slide = new YAHOO.widget.ContainerEffect(overlay, {
4489 attributes:{ points: { to:[x, y] } },
4490 duration:dur,
4491 method:YAHOO.util.Easing.easeIn
4492 },
4493 {
4494 attributes:{ points: { to:[(clientWidth+25), y] } },
4495 duration:dur,
4496 method:YAHOO.util.Easing.easeOut
4497 },
4498 overlay.element,
4499 YAHOO.util.Motion);
4500
4501
4502 slide.handleStartAnimateIn = function(type,args,obj) {
4503 obj.overlay.element.style.left = (-25-offsetWidth) + "px";
4504 obj.overlay.element.style.top = y + "px";
4505 };
4506
4507 slide.handleTweenAnimateIn = function(type, args, obj) {
4508
4509
4510 var pos = YAHOO.util.Dom.getXY(obj.overlay.element);
4511
4512 var currentX = pos[0];
4513 var currentY = pos[1];
4514
4515 if (YAHOO.util.Dom.getStyle(obj.overlay.element, "visibility") == "hidden" && currentX < x) {
4516 YAHOO.util.Dom.setStyle(obj.overlay.element, "visibility", "visible");
4517 }
4518
4519 obj.overlay.cfg.setProperty("xy", [currentX,currentY], true);
4520 obj.overlay.cfg.refireEvent("iframe");
4521 };
4522
4523 slide.handleCompleteAnimateIn = function(type, args, obj) {
4524 obj.overlay.cfg.setProperty("xy", [x,y], true);
4525 obj.startX = x;
4526 obj.startY = y;
4527 obj.overlay.cfg.refireEvent("iframe");
4528 obj.animateInCompleteEvent.fire();
4529 };
4530
4531 slide.handleStartAnimateOut = function(type, args, obj) {
4532 var vw = YAHOO.util.Dom.getViewportWidth();
4533
4534 var pos = YAHOO.util.Dom.getXY(obj.overlay.element);
4535
4536 var yso = pos[1];
4537
4538 var currentTo = obj.animOut.attributes.points.to;
4539 obj.animOut.attributes.points.to = [(vw+25), yso];
4540 };
4541
4542 slide.handleTweenAnimateOut = function(type, args, obj) {
4543 var pos = YAHOO.util.Dom.getXY(obj.overlay.element);
4544
4545 var xto = pos[0];
4546 var yto = pos[1];
4547
4548 obj.overlay.cfg.setProperty("xy", [xto,yto], true);
4549 obj.overlay.cfg.refireEvent("iframe");
4550 };
4551
4552 slide.handleCompleteAnimateOut = function(type, args, obj) {
4553 YAHOO.util.Dom.setStyle(obj.overlay.element, "visibility", "hidden");
4554
4555 obj.overlay.cfg.setProperty("xy", [x,y]);
4556 obj.animateOutCompleteEvent.fire();
4557 };
4558
4559 slide.init();
4560 return slide;
4561}; \ No newline at end of file
diff --git a/frontend/beta/js/YUI/dom.js b/frontend/beta/js/YUI/dom.js
new file mode 100644
index 0000000..6f04c43
--- a/dev/null
+++ b/frontend/beta/js/YUI/dom.js
@@ -0,0 +1,881 @@
1/*
2Copyright (c) 2006, Yahoo! Inc. All rights reserved.
3Code licensed under the BSD License:
4http://developer.yahoo.net/yui/license.txt
5version: 0.12.0
6*/
7
8/**
9 * The dom module provides helper methods for manipulating Dom elements.
10 * @module dom
11 *
12 */
13
14(function() {
15 var Y = YAHOO.util, // internal shorthand
16 getStyle, // for load time browser branching
17 setStyle, // ditto
18 id_counter = 0, // for use with generateId
19 propertyCache = {}; // for faster hyphen converts
20
21 // brower detection
22 var ua = navigator.userAgent.toLowerCase(),
23 isOpera = (ua.indexOf('opera') > -1),
24 isSafari = (ua.indexOf('safari') > -1),
25 isGecko = (!isOpera && !isSafari && ua.indexOf('gecko') > -1),
26 isIE = (!isOpera && ua.indexOf('msie') > -1);
27
28 // regex cache
29 var patterns = {
30 HYPHEN: /(-[a-z])/i
31 };
32
33
34 var toCamel = function(property) {
35 if ( !patterns.HYPHEN.test(property) ) {
36 return property; // no hyphens
37 }
38
39 if (propertyCache[property]) { // already converted
40 return propertyCache[property];
41 }
42
43 while( patterns.HYPHEN.exec(property) ) {
44 property = property.replace(RegExp.$1,
45 RegExp.$1.substr(1).toUpperCase());
46 }
47
48 propertyCache[property] = property;
49 return property;
50 //return property.replace(/-([a-z])/gi, function(m0, m1) {return m1.toUpperCase()}) // cant use function as 2nd arg yet due to safari bug
51 };
52
53 // branching at load instead of runtime
54 if (document.defaultView && document.defaultView.getComputedStyle) { // W3C DOM method
55 getStyle = function(el, property) {
56 var value = null;
57
58 var computed = document.defaultView.getComputedStyle(el, '');
59 if (computed) { // test computed before touching for safari
60 value = computed[toCamel(property)];
61 }
62
63 return el.style[property] || value;
64 };
65 } else if (document.documentElement.currentStyle && isIE) { // IE method
66 getStyle = function(el, property) {
67 switch( toCamel(property) ) {
68 case 'opacity' :// IE opacity uses filter
69 var val = 100;
70 try { // will error if no DXImageTransform
71 val = el.filters['DXImageTransform.Microsoft.Alpha'].opacity;
72
73 } catch(e) {
74 try { // make sure its in the document
75 val = el.filters('alpha').opacity;
76 } catch(e) {
77 }
78 }
79 return val / 100;
80 break;
81 default:
82 // test currentStyle before touching
83 var value = el.currentStyle ? el.currentStyle[property] : null;
84 return ( el.style[property] || value );
85 }
86 };
87 } else { // default to inline only
88 getStyle = function(el, property) { return el.style[property]; };
89 }
90
91 if (isIE) {
92 setStyle = function(el, property, val) {
93 switch (property) {
94 case 'opacity':
95 if ( typeof el.style.filter == 'string' ) { // in case not appended
96 el.style.filter = 'alpha(opacity=' + val * 100 + ')';
97
98 if (!el.currentStyle || !el.currentStyle.hasLayout) {
99 el.style.zoom = 1; // when no layout or cant tell
100 }
101 }
102 break;
103 default:
104 el.style[property] = val;
105 }
106 };
107 } else {
108 setStyle = function(el, property, val) {
109 el.style[property] = val;
110 };
111 }
112
113 /**
114 * Provides helper methods for DOM elements.
115 * @namespace YAHOO.util
116 * @class Dom
117 */
118 YAHOO.util.Dom = {
119 /**
120 * Returns an HTMLElement reference.
121 * @method get
122 * @param {String | HTMLElement |Array} el Accepts a string to use as an ID for getting a DOM reference, an actual DOM reference, or an Array of IDs and/or HTMLElements.
123 * @return {HTMLElement | Array} A DOM reference to an HTML element or an array of HTMLElements.
124 */
125 get: function(el) {
126 if (!el) { return null; } // nothing to work with
127
128 if (typeof el != 'string' && !(el instanceof Array) ) { // assuming HTMLElement or HTMLCollection, so pass back as is
129 return el;
130 }
131
132 if (typeof el == 'string') { // ID
133 return document.getElementById(el);
134 }
135 else { // array of ID's and/or elements
136 var collection = [];
137 for (var i = 0, len = el.length; i < len; ++i) {
138 collection[collection.length] = Y.Dom.get(el[i]);
139 }
140
141 return collection;
142 }
143
144 return null; // safety, should never happen
145 },
146
147 /**
148 * Normalizes currentStyle and ComputedStyle.
149 * @method getStyle
150 * @param {String | HTMLElement |Array} el Accepts a string to use as an ID, an actual DOM reference, or an Array of IDs and/or HTMLElements.
151 * @param {String} property The style property whose value is returned.
152 * @return {String | Array} The current value of the style property for the element(s).
153 */
154 getStyle: function(el, property) {
155 property = toCamel(property);
156
157 var f = function(element) {
158 return getStyle(element, property);
159 };
160
161 return Y.Dom.batch(el, f, Y.Dom, true);
162 },
163
164 /**
165 * Wrapper for setting style properties of HTMLElements. Normalizes "opacity" across modern browsers.
166 * @method setStyle
167 * @param {String | HTMLElement | Array} el Accepts a string to use as an ID, an actual DOM reference, or an Array of IDs and/or HTMLElements.
168 * @param {String} property The style property to be set.
169 * @param {String} val The value to apply to the given property.
170 */
171 setStyle: function(el, property, val) {
172 property = toCamel(property);
173
174 var f = function(element) {
175 setStyle(element, property, val);
176
177 };
178
179 Y.Dom.batch(el, f, Y.Dom, true);
180 },
181
182 /**
183 * Gets the current position of an element based on page coordinates. Element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
184 * @method getXY
185 * @param {String | HTMLElement | Array} el Accepts a string to use as an ID, an actual DOM reference, or an Array of IDs and/or HTMLElements
186 * @return {Array} The XY position of the element(s)
187 */
188 getXY: function(el) {
189 var f = function(el) {
190
191 // has to be part of document to have pageXY
192 if (el.parentNode === null || el.offsetParent === null ||
193 this.getStyle(el, 'display') == 'none') {
194 return false;
195 }
196
197 var parentNode = null;
198 var pos = [];
199 var box;
200
201 if (el.getBoundingClientRect) { // IE
202 box = el.getBoundingClientRect();
203 var doc = document;
204 if ( !this.inDocument(el) && parent.document != document) {// might be in a frame, need to get its scroll
205 doc = parent.document;
206
207 if ( !this.isAncestor(doc.documentElement, el) ) {
208 return false;
209 }
210
211 }
212
213 var scrollTop = Math.max(doc.documentElement.scrollTop, doc.body.scrollTop);
214 var scrollLeft = Math.max(doc.documentElement.scrollLeft, doc.body.scrollLeft);
215
216 return [box.left + scrollLeft, box.top + scrollTop];
217 }
218 else { // safari, opera, & gecko
219 pos = [el.offsetLeft, el.offsetTop];
220 parentNode = el.offsetParent;
221 if (parentNode != el) {
222 while (parentNode) {
223 pos[0] += parentNode.offsetLeft;
224 pos[1] += parentNode.offsetTop;
225 parentNode = parentNode.offsetParent;
226 }
227 }
228 if (isSafari && this.getStyle(el, 'position') == 'absolute' ) { // safari doubles in some cases
229 pos[0] -= document.body.offsetLeft;
230 pos[1] -= document.body.offsetTop;
231 }
232 }
233
234 if (el.parentNode) { parentNode = el.parentNode; }
235 else { parentNode = null; }
236
237 while (parentNode && parentNode.tagName.toUpperCase() != 'BODY' && parentNode.tagName.toUpperCase() != 'HTML')
238 { // account for any scrolled ancestors
239 if (Y.Dom.getStyle(parentNode, 'display') != 'inline') { // work around opera inline scrollLeft/Top bug
240 pos[0] -= parentNode.scrollLeft;
241 pos[1] -= parentNode.scrollTop;
242 }
243
244 if (parentNode.parentNode) {
245 parentNode = parentNode.parentNode;
246 } else { parentNode = null; }
247 }
248
249
250 return pos;
251 };
252
253 return Y.Dom.batch(el, f, Y.Dom, true);
254 },
255
256 /**
257 * Gets the current X position of an element based on page coordinates. The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
258 * @method getX
259 * @param {String | HTMLElement | Array} el Accepts a string to use as an ID, an actual DOM reference, or an Array of IDs and/or HTMLElements
260 * @return {String | Array} The X position of the element(s)
261 */
262 getX: function(el) {
263 var f = function(el) {
264 return Y.Dom.getXY(el)[0];
265 };
266
267 return Y.Dom.batch(el, f, Y.Dom, true);
268 },
269
270 /**
271 * Gets the current Y position of an element based on page coordinates. Element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
272 * @method getY
273 * @param {String | HTMLElement | Array} el Accepts a string to use as an ID, an actual DOM reference, or an Array of IDs and/or HTMLElements
274 * @return {String | Array} The Y position of the element(s)
275 */
276 getY: function(el) {
277 var f = function(el) {
278 return Y.Dom.getXY(el)[1];
279 };
280
281 return Y.Dom.batch(el, f, Y.Dom, true);
282 },
283
284 /**
285 * Set the position of an html element in page coordinates, regardless of how the element is positioned.
286 * The element(s) must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
287 * @method setXY
288 * @param {String | HTMLElement | Array} el Accepts a string to use as an ID, an actual DOM reference, or an Array of IDs and/or HTMLElements
289 * @param {Array} pos Contains X & Y values for new position (coordinates are page-based)
290 * @param {Boolean} noRetry By default we try and set the position a second time if the first fails
291 */
292 setXY: function(el, pos, noRetry) {
293 var f = function(el) {
294 var style_pos = this.getStyle(el, 'position');
295 if (style_pos == 'static') { // default to relative
296 this.setStyle(el, 'position', 'relative');
297 style_pos = 'relative';
298 }
299
300 var pageXY = this.getXY(el);
301 if (pageXY === false) { // has to be part of doc to have pageXY
302 return false;
303 }
304
305 var delta = [ // assuming pixels; if not we will have to retry
306 parseInt( this.getStyle(el, 'left'), 10 ),
307 parseInt( this.getStyle(el, 'top'), 10 )
308 ];
309
310 if ( isNaN(delta[0]) ) {// in case of 'auto'
311 delta[0] = (style_pos == 'relative') ? 0 : el.offsetLeft;
312 }
313 if ( isNaN(delta[1]) ) { // in case of 'auto'
314 delta[1] = (style_pos == 'relative') ? 0 : el.offsetTop;
315 }
316
317 if (pos[0] !== null) { el.style.left = pos[0] - pageXY[0] + delta[0] + 'px'; }
318 if (pos[1] !== null) { el.style.top = pos[1] - pageXY[1] + delta[1] + 'px'; }
319
320 var newXY = this.getXY(el);
321
322 // if retry is true, try one more time if we miss
323 if (!noRetry && (newXY[0] != pos[0] || newXY[1] != pos[1]) ) {
324 this.setXY(el, pos, true);
325 }
326
327 };
328
329 Y.Dom.batch(el, f, Y.Dom, true);
330 },
331
332 /**
333 * Set the X position of an html element in page coordinates, regardless of how the element is positioned.
334 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
335 * @method setX
336 * @param {String | HTMLElement | Array} el Accepts a string to use as an ID, an actual DOM reference, or an Array of IDs and/or HTMLElements.
337 * @param {Int} x The value to use as the X coordinate for the element(s).
338 */
339 setX: function(el, x) {
340 Y.Dom.setXY(el, [x, null]);
341 },
342
343 /**
344 * Set the Y position of an html element in page coordinates, regardless of how the element is positioned.
345 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
346 * @method setY
347 * @param {String | HTMLElement | Array} el Accepts a string to use as an ID, an actual DOM reference, or an Array of IDs and/or HTMLElements.
348 * @param {Int} x To use as the Y coordinate for the element(s).
349 */
350 setY: function(el, y) {
351 Y.Dom.setXY(el, [null, y]);
352 },
353
354 /**
355 * Returns the region position of the given element.
356 * The element must be part of the DOM tree to have a region (display:none or elements not appended return false).
357 * @method getRegion
358 * @param {String | HTMLElement | Array} el Accepts a string to use as an ID, an actual DOM reference, or an Array of IDs and/or HTMLElements.
359 * @return {Region | Array} A Region or array of Region instances containing "top, left, bottom, right" member data.
360 */
361 getRegion: function(el) {
362 var f = function(el) {
363 var region = new Y.Region.getRegion(el);
364 return region;
365 };
366
367 return Y.Dom.batch(el, f, Y.Dom, true);
368 },
369
370 /**
371 * Returns the width of the client (viewport).
372 * @method getClientWidth
373 * @deprecated Now using getViewportWidth. This interface left intact for back compat.
374 * @return {Int} The width of the viewable area of the page.
375 */
376 getClientWidth: function() {
377 return Y.Dom.getViewportWidth();
378 },
379
380 /**
381 * Returns the height of the client (viewport).
382 * @method getClientHeight
383 * @deprecated Now using getViewportHeight. This interface left intact for back compat.
384 * @return {Int} The height of the viewable area of the page.
385 */
386 getClientHeight: function() {
387 return Y.Dom.getViewportHeight();
388 },
389
390 /**
391 * Returns a array of HTMLElements with the given class.
392 * For optimized performance, include a tag and/or root node when possible.
393 * @method getElementsByClassName
394 * @param {String} className The class name to match against
395 * @param {String} tag (optional) The tag name of the elements being collected
396 * @param {String | HTMLElement} root (optional) The HTMLElement or an ID to use as the starting point
397 * @return {Array} An array of elements that have the given class name
398 */
399 getElementsByClassName: function(className, tag, root) {
400 var method = function(el) { return Y.Dom.hasClass(el, className); };
401 return Y.Dom.getElementsBy(method, tag, root);
402 },
403
404 /**
405 * Determines whether an HTMLElement has the given className.
406 * @method hasClass
407 * @param {String | HTMLElement | Array} el The element or collection to test
408 * @param {String} className the class name to search for
409 * @return {Boolean | Array} A boolean value or array of boolean values
410 */
411 hasClass: function(el, className) {
412 var re = new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)');
413
414 var f = function(el) {
415 return re.test(el['className']);
416 };
417
418 return Y.Dom.batch(el, f, Y.Dom, true);
419 },
420
421 /**
422 * Adds a class name to a given element or collection of elements.
423 * @method addClass
424 * @param {String | HTMLElement | Array} el The element or collection to add the class to
425 * @param {String} className the class name to add to the class attribute
426 */
427 addClass: function(el, className) {
428 var f = function(el) {
429 if (this.hasClass(el, className)) { return; } // already present
430
431
432 el['className'] = [el['className'], className].join(' ');
433 };
434
435 Y.Dom.batch(el, f, Y.Dom, true);
436 },
437
438 /**
439 * Removes a class name from a given element or collection of elements.
440 * @method removeClass
441 * @param {String | HTMLElement | Array} el The element or collection to remove the class from
442 * @param {String} className the class name to remove from the class attribute
443 */
444 removeClass: function(el, className) {
445 var re = new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)', 'g');
446
447 var f = function(el) {
448 if (!this.hasClass(el, className)) { return; } // not present
449
450
451 var c = el['className'];
452 el['className'] = c.replace(re, ' ');
453 if ( this.hasClass(el, className) ) { // in case of multiple adjacent
454 this.removeClass(el, className);
455 }
456
457 };
458
459 Y.Dom.batch(el, f, Y.Dom, true);
460 },
461
462 /**
463 * Replace a class with another class for a given element or collection of elements.
464 * If no oldClassName is present, the newClassName is simply added.
465 * @method replaceClass
466 * @param {String | HTMLElement | Array} el The element or collection to remove the class from
467 * @param {String} oldClassName the class name to be replaced
468 * @param {String} newClassName the class name that will be replacing the old class name
469 */
470 replaceClass: function(el, oldClassName, newClassName) {
471 if (oldClassName === newClassName) { // avoid infinite loop
472 return false;
473 }
474
475 var re = new RegExp('(?:^|\\s+)' + oldClassName + '(?:\\s+|$)', 'g');
476
477 var f = function(el) {
478
479 if ( !this.hasClass(el, oldClassName) ) {
480 this.addClass(el, newClassName); // just add it if nothing to replace
481 return; // note return
482 }
483
484 el['className'] = el['className'].replace(re, ' ' + newClassName + ' ');
485
486 if ( this.hasClass(el, oldClassName) ) { // in case of multiple adjacent
487 this.replaceClass(el, oldClassName, newClassName);
488 }
489 };
490
491 Y.Dom.batch(el, f, Y.Dom, true);
492 },
493
494 /**
495 * Generates a unique ID
496 * @method generateId
497 * @param {String | HTMLElement | Array} el (optional) An optional element array of elements to add an ID to (no ID is added if one is already present).
498 * @param {String} prefix (optional) an optional prefix to use (defaults to "yui-gen").
499 * @return {String | Array} The generated ID, or array of generated IDs (or original ID if already present on an element)
500 */
501 generateId: function(el, prefix) {
502 prefix = prefix || 'yui-gen';
503 el = el || {};
504
505 var f = function(el) {
506 if (el) {
507 el = Y.Dom.get(el);
508 } else {
509 el = {}; // just generating ID in this case
510 }
511
512 if (!el.id) {
513 el.id = prefix + id_counter++;
514 } // dont override existing
515
516
517 return el.id;
518 };
519
520 return Y.Dom.batch(el, f, Y.Dom, true);
521 },
522
523 /**
524 * Determines whether an HTMLElement is an ancestor of another HTML element in the DOM hierarchy.
525 * @method isAncestor
526 * @param {String | HTMLElement} haystack The possible ancestor
527 * @param {String | HTMLElement} needle The possible descendent
528 * @return {Boolean} Whether or not the haystack is an ancestor of needle
529 */
530 isAncestor: function(haystack, needle) {
531 haystack = Y.Dom.get(haystack);
532 if (!haystack || !needle) { return false; }
533
534 var f = function(needle) {
535 if (haystack.contains && !isSafari) { // safari "contains" is broken
536 return haystack.contains(needle);
537 }
538 else if ( haystack.compareDocumentPosition ) {
539 return !!(haystack.compareDocumentPosition(needle) & 16);
540 }
541 else { // loop up and test each parent
542 var parent = needle.parentNode;
543
544 while (parent) {
545 if (parent == haystack) {
546 return true;
547 }
548 else if (!parent.tagName || parent.tagName.toUpperCase() == 'HTML') {
549 return false;
550 }
551
552 parent = parent.parentNode;
553 }
554 return false;
555 }
556 };
557
558 return Y.Dom.batch(needle, f, Y.Dom, true);
559 },
560
561 /**
562 * Determines whether an HTMLElement is present in the current document.
563 * @method inDocument
564 * @param {String | HTMLElement} el The element to search for
565 * @return {Boolean} Whether or not the element is present in the current document
566 */
567 inDocument: function(el) {
568 var f = function(el) {
569 return this.isAncestor(document.documentElement, el);
570 };
571
572 return Y.Dom.batch(el, f, Y.Dom, true);
573 },
574
575 /**
576 * Returns a array of HTMLElements that pass the test applied by supplied boolean method.
577 * For optimized performance, include a tag and/or root node when possible.
578 * @method getElementsBy
579 * @param {Function} method - A boolean method for testing elements which receives the element as its only argument.
580
581 * @param {String} tag (optional) The tag name of the elements being collected
582 * @param {String | HTMLElement} root (optional) The HTMLElement or an ID to use as the starting point
583 */
584 getElementsBy: function(method, tag, root) {
585 tag = tag || '*';
586 root = Y.Dom.get(root) || document;
587
588 var nodes = [];
589 var elements = root.getElementsByTagName(tag);
590
591 if ( !elements.length && (tag == '*' && root.all) ) {
592 elements = root.all; // IE < 6
593 }
594
595 for (var i = 0, len = elements.length; i < len; ++i) {
596 if ( method(elements[i]) ) { nodes[nodes.length] = elements[i]; }
597 }
598
599
600 return nodes;
601 },
602
603 /**
604 * Returns an array of elements that have had the supplied method applied.
605 * The method is called with the element(s) as the first arg, and the optional param as the second ( method(el, o) ).
606 * @method batch
607 * @param {String | HTMLElement | Array} el (optional) An element or array of elements to apply the method to
608 * @param {Function} method The method to apply to the element(s)
609 * @param {Any} o (optional) An optional arg that is passed to the supplied method
610 * @param {Boolean} override (optional) Whether or not to override the scope of "method" with "o"
611 * @return {HTMLElement | Array} The element(s) with the method applied
612 */
613 batch: function(el, method, o, override) {
614 var id = el;
615 el = Y.Dom.get(el);
616
617 var scope = (override) ? o : window;
618
619 if (!el || el.tagName || !el.length) { // is null or not a collection (tagName for SELECT and others that can be both an element and a collection)
620 if (!el) {
621 return false;
622 }
623 return method.call(scope, el, o);
624 }
625
626 var collection = [];
627
628 for (var i = 0, len = el.length; i < len; ++i) {
629 if (!el[i]) {
630 id = el[i];
631 }
632 collection[collection.length] = method.call(scope, el[i], o);
633 }
634
635 return collection;
636 },
637
638 /**
639 * Returns the height of the document.
640 * @method getDocumentHeight
641 * @return {Int} The height of the actual document (which includes the body and its margin).
642 */
643 getDocumentHeight: function() {
644 var scrollHeight = (document.compatMode != 'CSS1Compat') ? document.body.scrollHeight : document.documentElement.scrollHeight;
645
646 var h = Math.max(scrollHeight, Y.Dom.getViewportHeight());
647 return h;
648 },
649
650 /**
651 * Returns the width of the document.
652 * @method getDocumentWidth
653 * @return {Int} The width of the actual document (which includes the body and its margin).
654 */
655 getDocumentWidth: function() {
656 var scrollWidth = (document.compatMode != 'CSS1Compat') ? document.body.scrollWidth : document.documentElement.scrollWidth;
657 var w = Math.max(scrollWidth, Y.Dom.getViewportWidth());
658 return w;
659 },
660
661 /**
662 * Returns the current height of the viewport.
663 * @method getViewportHeight
664 * @return {Int} The height of the viewable area of the page (excludes scrollbars).
665 */
666 getViewportHeight: function() {
667 var height = self.innerHeight; // Safari, Opera
668 var mode = document.compatMode;
669
670 if ( (mode || isIE) && !isOpera ) { // IE, Gecko
671 height = (mode == 'CSS1Compat') ?
672 document.documentElement.clientHeight : // Standards
673 document.body.clientHeight; // Quirks
674 }
675
676 return height;
677 },
678
679 /**
680 * Returns the current width of the viewport.
681 * @method getViewportWidth
682 * @return {Int} The width of the viewable area of the page (excludes scrollbars).
683 */
684
685 getViewportWidth: function() {
686 var width = self.innerWidth; // Safari
687 var mode = document.compatMode;
688
689 if (mode || isIE) { // IE, Gecko, Opera
690 width = (mode == 'CSS1Compat') ?
691 document.documentElement.clientWidth : // Standards
692 document.body.clientWidth; // Quirks
693 }
694 return width;
695 }
696 };
697})();
698/**
699 * A region is a representation of an object on a grid. It is defined
700 * by the top, right, bottom, left extents, so is rectangular by default. If
701 * other shapes are required, this class could be extended to support it.
702 * @namespace YAHOO.util
703 * @class Region
704 * @param {Int} t the top extent
705 * @param {Int} r the right extent
706 * @param {Int} b the bottom extent
707 * @param {Int} l the left extent
708 * @constructor
709 */
710YAHOO.util.Region = function(t, r, b, l) {
711
712 /**
713 * The region's top extent
714 * @property top
715 * @type Int
716 */
717 this.top = t;
718
719 /**
720 * The region's top extent as index, for symmetry with set/getXY
721 * @property 1
722 * @type Int
723 */
724 this[1] = t;
725
726 /**
727 * The region's right extent
728 * @property right
729 * @type int
730 */
731 this.right = r;
732
733 /**
734 * The region's bottom extent
735 * @property bottom
736 * @type Int
737 */
738 this.bottom = b;
739
740 /**
741 * The region's left extent
742 * @property left
743 * @type Int
744 */
745 this.left = l;
746
747 /**
748 * The region's left extent as index, for symmetry with set/getXY
749 * @property 0
750 * @type Int
751 */
752 this[0] = l;
753};
754
755/**
756 * Returns true if this region contains the region passed in
757 * @method contains
758 * @param {Region} region The region to evaluate
759 * @return {Boolean} True if the region is contained with this region,
760 * else false
761 */
762YAHOO.util.Region.prototype.contains = function(region) {
763 return ( region.left >= this.left &&
764 region.right <= this.right &&
765 region.top >= this.top &&
766 region.bottom <= this.bottom );
767
768};
769
770/**
771 * Returns the area of the region
772 * @method getArea
773 * @return {Int} the region's area
774 */
775YAHOO.util.Region.prototype.getArea = function() {
776 return ( (this.bottom - this.top) * (this.right - this.left) );
777};
778
779/**
780 * Returns the region where the passed in region overlaps with this one
781 * @method intersect
782 * @param {Region} region The region that intersects
783 * @return {Region} The overlap region, or null if there is no overlap
784 */
785YAHOO.util.Region.prototype.intersect = function(region) {
786 var t = Math.max( this.top, region.top );
787 var r = Math.min( this.right, region.right );
788 var b = Math.min( this.bottom, region.bottom );
789 var l = Math.max( this.left, region.left );
790
791 if (b >= t && r >= l) {
792 return new YAHOO.util.Region(t, r, b, l);
793 } else {
794 return null;
795 }
796};
797
798/**
799 * Returns the region representing the smallest region that can contain both
800 * the passed in region and this region.
801 * @method union
802 * @param {Region} region The region that to create the union with
803 * @return {Region} The union region
804 */
805YAHOO.util.Region.prototype.union = function(region) {
806 var t = Math.min( this.top, region.top );
807 var r = Math.max( this.right, region.right );
808 var b = Math.max( this.bottom, region.bottom );
809 var l = Math.min( this.left, region.left );
810
811 return new YAHOO.util.Region(t, r, b, l);
812};
813
814/**
815 * toString
816 * @method toString
817 * @return string the region properties
818 */
819YAHOO.util.Region.prototype.toString = function() {
820 return ( "Region {" +
821 "top: " + this.top +
822 ", right: " + this.right +
823 ", bottom: " + this.bottom +
824 ", left: " + this.left +
825 "}" );
826};
827
828/**
829 * Returns a region that is occupied by the DOM element
830 * @method getRegion
831 * @param {HTMLElement} el The element
832 * @return {Region} The region that the element occupies
833 * @static
834 */
835YAHOO.util.Region.getRegion = function(el) {
836 var p = YAHOO.util.Dom.getXY(el);
837
838 var t = p[1];
839 var r = p[0] + el.offsetWidth;
840 var b = p[1] + el.offsetHeight;
841 var l = p[0];
842
843 return new YAHOO.util.Region(t, r, b, l);
844};
845
846/////////////////////////////////////////////////////////////////////////////
847
848/**
849 * A point is a region that is special in that it represents a single point on
850 * the grid.
851 * @namespace YAHOO.util
852 * @class Point
853 * @param {Int} x The X position of the point
854 * @param {Int} y The Y position of the point
855 * @constructor
856 * @extends YAHOO.util.Region
857 */
858YAHOO.util.Point = function(x, y) {
859 if (x instanceof Array) { // accept output from Dom.getXY
860 y = x[1];
861 x = x[0];
862 }
863
864 /**
865 * The X position of the point, which is also the right, left and index zero (for Dom.getXY symmetry)
866 * @property x
867 * @type Int
868 */
869
870 this.x = this.right = this.left = this[0] = x;
871
872 /**
873 * The Y position of the point, which is also the top, bottom and index one (for Dom.getXY symmetry)
874 * @property y
875 * @type Int
876 */
877 this.y = this.top = this.bottom = this[1] = y;
878};
879
880YAHOO.util.Point.prototype = new YAHOO.util.Region();
881
diff --git a/frontend/beta/js/YUI/dragdrop.js b/frontend/beta/js/YUI/dragdrop.js
new file mode 100644
index 0000000..43a0f61
--- a/dev/null
+++ b/frontend/beta/js/YUI/dragdrop.js
@@ -0,0 +1,2940 @@
1/*
2Copyright (c) 2006, Yahoo! Inc. All rights reserved.
3Code licensed under the BSD License:
4http://developer.yahoo.net/yui/license.txt
5version: 0.12.0
6*/
7
8(function() {
9
10var Event=YAHOO.util.Event;
11var Dom=YAHOO.util.Dom;
12
13/**
14 * Defines the interface and base operation of items that that can be
15 * dragged or can be drop targets. It was designed to be extended, overriding
16 * the event handlers for startDrag, onDrag, onDragOver, onDragOut.
17 * Up to three html elements can be associated with a DragDrop instance:
18 * <ul>
19 * <li>linked element: the element that is passed into the constructor.
20 * This is the element which defines the boundaries for interaction with
21 * other DragDrop objects.</li>
22 * <li>handle element(s): The drag operation only occurs if the element that
23 * was clicked matches a handle element. By default this is the linked
24 * element, but there are times that you will want only a portion of the
25 * linked element to initiate the drag operation, and the setHandleElId()
26 * method provides a way to define this.</li>
27 * <li>drag element: this represents an the element that would be moved along
28 * with the cursor during a drag operation. By default, this is the linked
29 * element itself as in {@link YAHOO.util.DD}. setDragElId() lets you define
30 * a separate element that would be moved, as in {@link YAHOO.util.DDProxy}
31 * </li>
32 * </ul>
33 * This class should not be instantiated until the onload event to ensure that
34 * the associated elements are available.
35 * The following would define a DragDrop obj that would interact with any
36 * other DragDrop obj in the "group1" group:
37 * <pre>
38 * dd = new YAHOO.util.DragDrop("div1", "group1");
39 * </pre>
40 * Since none of the event handlers have been implemented, nothing would
41 * actually happen if you were to run the code above. Normally you would
42 * override this class or one of the default implementations, but you can
43 * also override the methods you want on an instance of the class...
44 * <pre>
45 * dd.onDragDrop = function(e, id) {
46 * &nbsp;&nbsp;alert("dd was dropped on " + id);
47 * }
48 * </pre>
49 * @namespace YAHOO.util
50 * @class DragDrop
51 * @constructor
52 * @param {String} id of the element that is linked to this instance
53 * @param {String} sGroup the group of related DragDrop objects
54 * @param {object} config an object containing configurable attributes
55 * Valid properties for DragDrop:
56 * padding, isTarget, maintainOffset, primaryButtonOnly
57 */
58YAHOO.util.DragDrop = function(id, sGroup, config) {
59 if (id) {
60 this.init(id, sGroup, config);
61 }
62};
63
64YAHOO.util.DragDrop.prototype = {
65
66 /**
67 * The id of the element associated with this object. This is what we
68 * refer to as the "linked element" because the size and position of
69 * this element is used to determine when the drag and drop objects have
70 * interacted.
71 * @property id
72 * @type String
73 */
74 id: null,
75
76 /**
77 * Configuration attributes passed into the constructor
78 * @property config
79 * @type object
80 */
81 config: null,
82
83 /**
84 * The id of the element that will be dragged. By default this is same
85 * as the linked element , but could be changed to another element. Ex:
86 * YAHOO.util.DDProxy
87 * @property dragElId
88 * @type String
89 * @private
90 */
91 dragElId: null,
92
93 /**
94 * the id of the element that initiates the drag operation. By default
95 * this is the linked element, but could be changed to be a child of this
96 * element. This lets us do things like only starting the drag when the
97 * header element within the linked html element is clicked.
98 * @property handleElId
99 * @type String
100 * @private
101 */
102 handleElId: null,
103
104 /**
105 * An associative array of HTML tags that will be ignored if clicked.
106 * @property invalidHandleTypes
107 * @type {string: string}
108 */
109 invalidHandleTypes: null,
110
111 /**
112 * An associative array of ids for elements that will be ignored if clicked
113 * @property invalidHandleIds
114 * @type {string: string}
115 */
116 invalidHandleIds: null,
117
118 /**
119 * An indexted array of css class names for elements that will be ignored
120 * if clicked.
121 * @property invalidHandleClasses
122 * @type string[]
123 */
124 invalidHandleClasses: null,
125
126 /**
127 * The linked element's absolute X position at the time the drag was
128 * started
129 * @property startPageX
130 * @type int
131 * @private
132 */
133 startPageX: 0,
134
135 /**
136 * The linked element's absolute X position at the time the drag was
137 * started
138 * @property startPageY
139 * @type int
140 * @private
141 */
142 startPageY: 0,
143
144 /**
145 * The group defines a logical collection of DragDrop objects that are
146 * related. Instances only get events when interacting with other
147 * DragDrop object in the same group. This lets us define multiple
148 * groups using a single DragDrop subclass if we want.
149 * @property groups
150 * @type {string: string}
151 */
152 groups: null,
153
154 /**
155 * Individual drag/drop instances can be locked. This will prevent
156 * onmousedown start drag.
157 * @property locked
158 * @type boolean
159 * @private
160 */
161 locked: false,
162
163 /**
164 * Lock this instance
165 * @method lock
166 */
167 lock: function() { this.locked = true; },
168
169 /**
170 * Unlock this instace
171 * @method unlock
172 */
173 unlock: function() { this.locked = false; },
174
175 /**
176 * By default, all insances can be a drop target. This can be disabled by
177 * setting isTarget to false.
178 * @method isTarget
179 * @type boolean
180 */
181 isTarget: true,
182
183 /**
184 * The padding configured for this drag and drop object for calculating
185 * the drop zone intersection with this object.
186 * @method padding
187 * @type int[]
188 */
189 padding: null,
190
191 /**
192 * Cached reference to the linked element
193 * @property _domRef
194 * @private
195 */
196 _domRef: null,
197
198 /**
199 * Internal typeof flag
200 * @property __ygDragDrop
201 * @private
202 */
203 __ygDragDrop: true,
204
205 /**
206 * Set to true when horizontal contraints are applied
207 * @property constrainX
208 * @type boolean
209 * @private
210 */
211 constrainX: false,
212
213 /**
214 * Set to true when vertical contraints are applied
215 * @property constrainY
216 * @type boolean
217 * @private
218 */
219 constrainY: false,
220
221 /**
222 * The left constraint
223 * @property minX
224 * @type int
225 * @private
226 */
227 minX: 0,
228
229 /**
230 * The right constraint
231 * @property maxX
232 * @type int
233 * @private
234 */
235 maxX: 0,
236
237 /**
238 * The up constraint
239 * @property minY
240 * @type int
241 * @type int
242 * @private
243 */
244 minY: 0,
245
246 /**
247 * The down constraint
248 * @property maxY
249 * @type int
250 * @private
251 */
252 maxY: 0,
253
254 /**
255 * Maintain offsets when we resetconstraints. Set to true when you want
256 * the position of the element relative to its parent to stay the same
257 * when the page changes
258 *
259 * @property maintainOffset
260 * @type boolean
261 */
262 maintainOffset: false,
263
264 /**
265 * Array of pixel locations the element will snap to if we specified a
266 * horizontal graduation/interval. This array is generated automatically
267 * when you define a tick interval.
268 * @property xTicks
269 * @type int[]
270 */
271 xTicks: null,
272
273 /**
274 * Array of pixel locations the element will snap to if we specified a
275 * vertical graduation/interval. This array is generated automatically
276 * when you define a tick interval.
277 * @property yTicks
278 * @type int[]
279 */
280 yTicks: null,
281
282 /**
283 * By default the drag and drop instance will only respond to the primary
284 * button click (left button for a right-handed mouse). Set to true to
285 * allow drag and drop to start with any mouse click that is propogated
286 * by the browser
287 * @property primaryButtonOnly
288 * @type boolean
289 */
290 primaryButtonOnly: true,
291
292 /**
293 * The availabe property is false until the linked dom element is accessible.
294 * @property available
295 * @type boolean
296 */
297 available: false,
298
299 /**
300 * By default, drags can only be initiated if the mousedown occurs in the
301 * region the linked element is. This is done in part to work around a
302 * bug in some browsers that mis-report the mousedown if the previous
303 * mouseup happened outside of the window. This property is set to true
304 * if outer handles are defined.
305 *
306 * @property hasOuterHandles
307 * @type boolean
308 * @default false
309 */
310 hasOuterHandles: false,
311
312 /**
313 * Code that executes immediately before the startDrag event
314 * @method b4StartDrag
315 * @private
316 */
317 b4StartDrag: function(x, y) { },
318
319 /**
320 * Abstract method called after a drag/drop object is clicked
321 * and the drag or mousedown time thresholds have beeen met.
322 * @method startDrag
323 * @param {int} X click location
324 * @param {int} Y click location
325 */
326 startDrag: function(x, y) { /* override this */ },
327
328 /**
329 * Code that executes immediately before the onDrag event
330 * @method b4Drag
331 * @private
332 */
333 b4Drag: function(e) { },
334
335 /**
336 * Abstract method called during the onMouseMove event while dragging an
337 * object.
338 * @method onDrag
339 * @param {Event} e the mousemove event
340 */
341 onDrag: function(e) { /* override this */ },
342
343 /**
344 * Abstract method called when this element fist begins hovering over
345 * another DragDrop obj
346 * @method onDragEnter
347 * @param {Event} e the mousemove event
348 * @param {String|DragDrop[]} id In POINT mode, the element
349 * id this is hovering over. In INTERSECT mode, an array of one or more
350 * dragdrop items being hovered over.
351 */
352 onDragEnter: function(e, id) { /* override this */ },
353
354 /**
355 * Code that executes immediately before the onDragOver event
356 * @method b4DragOver
357 * @private
358 */
359 b4DragOver: function(e) { },
360
361 /**
362 * Abstract method called when this element is hovering over another
363 * DragDrop obj
364 * @method onDragOver
365 * @param {Event} e the mousemove event
366 * @param {String|DragDrop[]} id In POINT mode, the element
367 * id this is hovering over. In INTERSECT mode, an array of dd items
368 * being hovered over.
369 */
370 onDragOver: function(e, id) { /* override this */ },
371
372 /**
373 * Code that executes immediately before the onDragOut event
374 * @method b4DragOut
375 * @private
376 */
377 b4DragOut: function(e) { },
378
379 /**
380 * Abstract method called when we are no longer hovering over an element
381 * @method onDragOut
382 * @param {Event} e the mousemove event
383 * @param {String|DragDrop[]} id In POINT mode, the element
384 * id this was hovering over. In INTERSECT mode, an array of dd items
385 * that the mouse is no longer over.
386 */
387 onDragOut: function(e, id) { /* override this */ },
388
389 /**
390 * Code that executes immediately before the onDragDrop event
391 * @method b4DragDrop
392 * @private
393 */
394 b4DragDrop: function(e) { },
395
396 /**
397 * Abstract method called when this item is dropped on another DragDrop
398 * obj
399 * @method onDragDrop
400 * @param {Event} e the mouseup event
401 * @param {String|DragDrop[]} id In POINT mode, the element
402 * id this was dropped on. In INTERSECT mode, an array of dd items this
403 * was dropped on.
404 */
405 onDragDrop: function(e, id) { /* override this */ },
406
407 /**
408 * Abstract method called when this item is dropped on an area with no
409 * drop target
410 * @method onInvalidDrop
411 * @param {Event} e the mouseup event
412 */
413 onInvalidDrop: function(e) { /* override this */ },
414
415 /**
416 * Code that executes immediately before the endDrag event
417 * @method b4EndDrag
418 * @private
419 */
420 b4EndDrag: function(e) { },
421
422 /**
423 * Fired when we are done dragging the object
424 * @method endDrag
425 * @param {Event} e the mouseup event
426 */
427 endDrag: function(e) { /* override this */ },
428
429 /**
430 * Code executed immediately before the onMouseDown event
431 * @method b4MouseDown
432 * @param {Event} e the mousedown event
433 * @private
434 */
435 b4MouseDown: function(e) { },
436
437 /**
438 * Event handler that fires when a drag/drop obj gets a mousedown
439 * @method onMouseDown
440 * @param {Event} e the mousedown event
441 */
442 onMouseDown: function(e) { /* override this */ },
443
444 /**
445 * Event handler that fires when a drag/drop obj gets a mouseup
446 * @method onMouseUp
447 * @param {Event} e the mouseup event
448 */
449 onMouseUp: function(e) { /* override this */ },
450
451 /**
452 * Override the onAvailable method to do what is needed after the initial
453 * position was determined.
454 * @method onAvailable
455 */
456 onAvailable: function () {
457 },
458
459 /**
460 * Returns a reference to the linked element
461 * @method getEl
462 * @return {HTMLElement} the html element
463 */
464 getEl: function() {
465 if (!this._domRef) {
466 this._domRef = Dom.get(this.id);
467 }
468
469 return this._domRef;
470 },
471
472 /**
473 * Returns a reference to the actual element to drag. By default this is
474 * the same as the html element, but it can be assigned to another
475 * element. An example of this can be found in YAHOO.util.DDProxy
476 * @method getDragEl
477 * @return {HTMLElement} the html element
478 */
479 getDragEl: function() {
480 return Dom.get(this.dragElId);
481 },
482
483 /**
484 * Sets up the DragDrop object. Must be called in the constructor of any
485 * YAHOO.util.DragDrop subclass
486 * @method init
487 * @param id the id of the linked element
488 * @param {String} sGroup the group of related items
489 * @param {object} config configuration attributes
490 */
491 init: function(id, sGroup, config) {
492 this.initTarget(id, sGroup, config);
493 Event.on(this.id, "mousedown", this.handleMouseDown, this, true);
494 // Event.on(this.id, "selectstart", Event.preventDefault);
495 },
496
497 /**
498 * Initializes Targeting functionality only... the object does not
499 * get a mousedown handler.
500 * @method initTarget
501 * @param id the id of the linked element
502 * @param {String} sGroup the group of related items
503 * @param {object} config configuration attributes
504 */
505 initTarget: function(id, sGroup, config) {
506
507 // configuration attributes
508 this.config = config || {};
509
510 // create a local reference to the drag and drop manager
511 this.DDM = YAHOO.util.DDM;
512 // initialize the groups array
513 this.groups = {};
514
515 // assume that we have an element reference instead of an id if the
516 // parameter is not a string
517 if (typeof id !== "string") {
518 YAHOO.log("id is not a string, assuming it is an HTMLElement");
519 id = Dom.generateId(id);
520 }
521
522 // set the id
523 this.id = id;
524
525 // add to an interaction group
526 this.addToGroup((sGroup) ? sGroup : "default");
527
528 // We don't want to register this as the handle with the manager
529 // so we just set the id rather than calling the setter.
530 this.handleElId = id;
531
532 Event.onAvailable(id, this.handleOnAvailable, this, true);
533
534
535 // the linked element is the element that gets dragged by default
536 this.setDragElId(id);
537
538 // by default, clicked anchors will not start drag operations.
539 // @TODO what else should be here? Probably form fields.
540 this.invalidHandleTypes = { A: "A" };
541 this.invalidHandleIds = {};
542 this.invalidHandleClasses = [];
543
544 this.applyConfig();
545 },
546
547 /**
548 * Applies the configuration parameters that were passed into the constructor.
549 * This is supposed to happen at each level through the inheritance chain. So
550 * a DDProxy implentation will execute apply config on DDProxy, DD, and
551 * DragDrop in order to get all of the parameters that are available in
552 * each object.
553 * @method applyConfig
554 */
555 applyConfig: function() {
556
557 // configurable properties:
558 // padding, isTarget, maintainOffset, primaryButtonOnly
559 this.padding = this.config.padding || [0, 0, 0, 0];
560 this.isTarget = (this.config.isTarget !== false);
561 this.maintainOffset = (this.config.maintainOffset);
562 this.primaryButtonOnly = (this.config.primaryButtonOnly !== false);
563
564 },
565
566 /**
567 * Executed when the linked element is available
568 * @method handleOnAvailable
569 * @private
570 */
571 handleOnAvailable: function() {
572 this.available = true;
573 this.resetConstraints();
574 this.onAvailable();
575 },
576
577 /**
578 * Configures the padding for the target zone in px. Effectively expands
579 * (or reduces) the virtual object size for targeting calculations.
580 * Supports css-style shorthand; if only one parameter is passed, all sides
581 * will have that padding, and if only two are passed, the top and bottom
582 * will have the first param, the left and right the second.
583 * @method setPadding
584 * @param {int} iTop Top pad
585 * @param {int} iRight Right pad
586 * @param {int} iBot Bot pad
587 * @param {int} iLeft Left pad
588 */
589 setPadding: function(iTop, iRight, iBot, iLeft) {
590 // this.padding = [iLeft, iRight, iTop, iBot];
591 if (!iRight && 0 !== iRight) {
592 this.padding = [iTop, iTop, iTop, iTop];
593 } else if (!iBot && 0 !== iBot) {
594 this.padding = [iTop, iRight, iTop, iRight];
595 } else {
596 this.padding = [iTop, iRight, iBot, iLeft];
597 }
598 },
599
600 /**
601 * Stores the initial placement of the linked element.
602 * @method setInitialPosition
603 * @param {int} diffX the X offset, default 0
604 * @param {int} diffY the Y offset, default 0
605 */
606 setInitPosition: function(diffX, diffY) {
607 var el = this.getEl();
608
609 if (!this.DDM.verifyEl(el)) {
610 return;
611 }
612
613 var dx = diffX || 0;
614 var dy = diffY || 0;
615
616 var p = Dom.getXY( el );
617
618 this.initPageX = p[0] - dx;
619 this.initPageY = p[1] - dy;
620
621 this.lastPageX = p[0];
622 this.lastPageY = p[1];
623
624
625 this.setStartPosition(p);
626 },
627
628 /**
629 * Sets the start position of the element. This is set when the obj
630 * is initialized, the reset when a drag is started.
631 * @method setStartPosition
632 * @param pos current position (from previous lookup)
633 * @private
634 */
635 setStartPosition: function(pos) {
636 var p = pos || Dom.getXY( this.getEl() );
637 this.deltaSetXY = null;
638
639 this.startPageX = p[0];
640 this.startPageY = p[1];
641 },
642
643 /**
644 * Add this instance to a group of related drag/drop objects. All
645 * instances belong to at least one group, and can belong to as many
646 * groups as needed.
647 * @method addToGroup
648 * @param sGroup {string} the name of the group
649 */
650 addToGroup: function(sGroup) {
651 this.groups[sGroup] = true;
652 this.DDM.regDragDrop(this, sGroup);
653 },
654
655 /**
656 * Remove's this instance from the supplied interaction group
657 * @method removeFromGroup
658 * @param {string} sGroup The group to drop
659 */
660 removeFromGroup: function(sGroup) {
661 if (this.groups[sGroup]) {
662 delete this.groups[sGroup];
663 }
664
665 this.DDM.removeDDFromGroup(this, sGroup);
666 },
667
668 /**
669 * Allows you to specify that an element other than the linked element
670 * will be moved with the cursor during a drag
671 * @method setDragElId
672 * @param id {string} the id of the element that will be used to initiate the drag
673 */
674 setDragElId: function(id) {
675 this.dragElId = id;
676 },
677
678 /**
679 * Allows you to specify a child of the linked element that should be
680 * used to initiate the drag operation. An example of this would be if
681 * you have a content div with text and links. Clicking anywhere in the
682 * content area would normally start the drag operation. Use this method
683 * to specify that an element inside of the content div is the element
684 * that starts the drag operation.
685 * @method setHandleElId
686 * @param id {string} the id of the element that will be used to
687 * initiate the drag.
688 */
689 setHandleElId: function(id) {
690 if (typeof id !== "string") {
691 YAHOO.log("id is not a string, assuming it is an HTMLElement");
692 id = Dom.generateId(id);
693 }
694 this.handleElId = id;
695 this.DDM.regHandle(this.id, id);
696 },
697
698 /**
699 * Allows you to set an element outside of the linked element as a drag
700 * handle
701 * @method setOuterHandleElId
702 * @param id the id of the element that will be used to initiate the drag
703 */
704 setOuterHandleElId: function(id) {
705 if (typeof id !== "string") {
706 YAHOO.log("id is not a string, assuming it is an HTMLElement");
707 id = Dom.generateId(id);
708 }
709 Event.on(id, "mousedown",
710 this.handleMouseDown, this, true);
711 this.setHandleElId(id);
712
713 this.hasOuterHandles = true;
714 },
715
716 /**
717 * Remove all drag and drop hooks for this element
718 * @method unreg
719 */
720 unreg: function() {
721 Event.removeListener(this.id, "mousedown",
722 this.handleMouseDown);
723 this._domRef = null;
724 this.DDM._remove(this);
725 },
726
727 /**
728 * Returns true if this instance is locked, or the drag drop mgr is locked
729 * (meaning that all drag/drop is disabled on the page.)
730 * @method isLocked
731 * @return {boolean} true if this obj or all drag/drop is locked, else
732 * false
733 */
734 isLocked: function() {
735 return (this.DDM.isLocked() || this.locked);
736 },
737
738 /**
739 * Fired when this object is clicked
740 * @method handleMouseDown
741 * @param {Event} e
742 * @param {YAHOO.util.DragDrop} oDD the clicked dd object (this dd obj)
743 * @private
744 */
745 handleMouseDown: function(e, oDD) {
746
747 var button = e.which || e.button;
748
749 if (this.primaryButtonOnly && button > 1) {
750 return;
751 }
752
753 if (this.isLocked()) {
754 return;
755 }
756
757 this.DDM.refreshCache(this.groups);
758 // var self = this;
759 // setTimeout( function() { self.DDM.refreshCache(self.groups); }, 0);
760
761 // Only process the event if we really clicked within the linked
762 // element. The reason we make this check is that in the case that
763 // another element was moved between the clicked element and the
764 // cursor in the time between the mousedown and mouseup events. When
765 // this happens, the element gets the next mousedown event
766 // regardless of where on the screen it happened.
767 var pt = new YAHOO.util.Point(Event.getPageX(e), Event.getPageY(e));
768 if (!this.hasOuterHandles && !this.DDM.isOverTarget(pt, this) ) {
769 } else {
770 if (this.clickValidator(e)) {
771
772
773 // set the initial element position
774 this.setStartPosition();
775
776
777 this.b4MouseDown(e);
778 this.onMouseDown(e);
779 this.DDM.handleMouseDown(e, this);
780
781 this.DDM.stopEvent(e);
782 } else {
783
784
785 }
786 }
787 },
788
789 clickValidator: function(e) {
790 var target = Event.getTarget(e);
791 return ( this.isValidHandleChild(target) &&
792 (this.id == this.handleElId ||
793 this.DDM.handleWasClicked(target, this.id)) );
794 },
795
796 /**
797 * Allows you to specify a tag name that should not start a drag operation
798 * when clicked. This is designed to facilitate embedding links within a
799 * drag handle that do something other than start the drag.
800 * @method addInvalidHandleType
801 * @param {string} tagName the type of element to exclude
802 */
803 addInvalidHandleType: function(tagName) {
804 var type = tagName.toUpperCase();
805 this.invalidHandleTypes[type] = type;
806 },
807
808 /**
809 * Lets you to specify an element id for a child of a drag handle
810 * that should not initiate a drag
811 * @method addInvalidHandleId
812 * @param {string} id the element id of the element you wish to ignore
813 */
814 addInvalidHandleId: function(id) {
815 if (typeof id !== "string") {
816 YAHOO.log("id is not a string, assuming it is an HTMLElement");
817 id = Dom.generateId(id);
818 }
819 this.invalidHandleIds[id] = id;
820 },
821
822 /**
823 * Lets you specify a css class of elements that will not initiate a drag
824 * @method addInvalidHandleClass
825 * @param {string} cssClass the class of the elements you wish to ignore
826 */
827 addInvalidHandleClass: function(cssClass) {
828 this.invalidHandleClasses.push(cssClass);
829 },
830
831 /**
832 * Unsets an excluded tag name set by addInvalidHandleType
833 * @method removeInvalidHandleType
834 * @param {string} tagName the type of element to unexclude
835 */
836 removeInvalidHandleType: function(tagName) {
837 var type = tagName.toUpperCase();
838 // this.invalidHandleTypes[type] = null;
839 delete this.invalidHandleTypes[type];
840 },
841
842 /**
843 * Unsets an invalid handle id
844 * @method removeInvalidHandleId
845 * @param {string} id the id of the element to re-enable
846 */
847 removeInvalidHandleId: function(id) {
848 if (typeof id !== "string") {
849 YAHOO.log("id is not a string, assuming it is an HTMLElement");
850 id = Dom.generateId(id);
851 }
852 delete this.invalidHandleIds[id];
853 },
854
855 /**
856 * Unsets an invalid css class
857 * @method removeInvalidHandleClass
858 * @param {string} cssClass the class of the element(s) you wish to
859 * re-enable
860 */
861 removeInvalidHandleClass: function(cssClass) {
862 for (var i=0, len=this.invalidHandleClasses.length; i<len; ++i) {
863 if (this.invalidHandleClasses[i] == cssClass) {
864 delete this.invalidHandleClasses[i];
865 }
866 }
867 },
868
869 /**
870 * Checks the tag exclusion list to see if this click should be ignored
871 * @method isValidHandleChild
872 * @param {HTMLElement} node the HTMLElement to evaluate
873 * @return {boolean} true if this is a valid tag type, false if not
874 */
875 isValidHandleChild: function(node) {
876
877 var valid = true;
878 // var n = (node.nodeName == "#text") ? node.parentNode : node;
879 var nodeName;
880 try {
881 nodeName = node.nodeName.toUpperCase();
882 } catch(e) {
883 nodeName = node.nodeName;
884 }
885 valid = valid && !this.invalidHandleTypes[nodeName];
886 valid = valid && !this.invalidHandleIds[node.id];
887
888 for (var i=0, len=this.invalidHandleClasses.length; valid && i<len; ++i) {
889 valid = !Dom.hasClass(node, this.invalidHandleClasses[i]);
890 }
891
892
893 return valid;
894
895 },
896
897 /**
898 * Create the array of horizontal tick marks if an interval was specified
899 * in setXConstraint().
900 * @method setXTicks
901 * @private
902 */
903 setXTicks: function(iStartX, iTickSize) {
904 this.xTicks = [];
905 this.xTickSize = iTickSize;
906
907 var tickMap = {};
908
909 for (var i = this.initPageX; i >= this.minX; i = i - iTickSize) {
910 if (!tickMap[i]) {
911 this.xTicks[this.xTicks.length] = i;
912 tickMap[i] = true;
913 }
914 }
915
916 for (i = this.initPageX; i <= this.maxX; i = i + iTickSize) {
917 if (!tickMap[i]) {
918 this.xTicks[this.xTicks.length] = i;
919 tickMap[i] = true;
920 }
921 }
922
923 this.xTicks.sort(this.DDM.numericSort) ;
924 },
925
926 /**
927 * Create the array of vertical tick marks if an interval was specified in
928 * setYConstraint().
929 * @method setYTicks
930 * @private
931 */
932 setYTicks: function(iStartY, iTickSize) {
933 this.yTicks = [];
934 this.yTickSize = iTickSize;
935
936 var tickMap = {};
937
938 for (var i = this.initPageY; i >= this.minY; i = i - iTickSize) {
939 if (!tickMap[i]) {
940 this.yTicks[this.yTicks.length] = i;
941 tickMap[i] = true;
942 }
943 }
944
945 for (i = this.initPageY; i <= this.maxY; i = i + iTickSize) {
946 if (!tickMap[i]) {
947 this.yTicks[this.yTicks.length] = i;
948 tickMap[i] = true;
949 }
950 }
951
952 this.yTicks.sort(this.DDM.numericSort) ;
953 },
954
955 /**
956 * By default, the element can be dragged any place on the screen. Use
957 * this method to limit the horizontal travel of the element. Pass in
958 * 0,0 for the parameters if you want to lock the drag to the y axis.
959 * @method setXConstraint
960 * @param {int} iLeft the number of pixels the element can move to the left
961 * @param {int} iRight the number of pixels the element can move to the
962 * right
963 * @param {int} iTickSize optional parameter for specifying that the
964 * element
965 * should move iTickSize pixels at a time.
966 */
967 setXConstraint: function(iLeft, iRight, iTickSize) {
968 this.leftConstraint = iLeft;
969 this.rightConstraint = iRight;
970
971 this.minX = this.initPageX - iLeft;
972 this.maxX = this.initPageX + iRight;
973 if (iTickSize) { this.setXTicks(this.initPageX, iTickSize); }
974
975 this.constrainX = true;
976 },
977
978 /**
979 * Clears any constraints applied to this instance. Also clears ticks
980 * since they can't exist independent of a constraint at this time.
981 * @method clearConstraints
982 */
983 clearConstraints: function() {
984 this.constrainX = false;
985 this.constrainY = false;
986 this.clearTicks();
987 },
988
989 /**
990 * Clears any tick interval defined for this instance
991 * @method clearTicks
992 */
993 clearTicks: function() {
994 this.xTicks = null;
995 this.yTicks = null;
996 this.xTickSize = 0;
997 this.yTickSize = 0;
998 },
999
1000 /**
1001 * By default, the element can be dragged any place on the screen. Set
1002 * this to limit the vertical travel of the element. Pass in 0,0 for the
1003 * parameters if you want to lock the drag to the x axis.
1004 * @method setYConstraint
1005 * @param {int} iUp the number of pixels the element can move up
1006 * @param {int} iDown the number of pixels the element can move down
1007 * @param {int} iTickSize optional parameter for specifying that the
1008 * element should move iTickSize pixels at a time.
1009 */
1010 setYConstraint: function(iUp, iDown, iTickSize) {
1011 this.topConstraint = iUp;
1012 this.bottomConstraint = iDown;
1013
1014 this.minY = this.initPageY - iUp;
1015 this.maxY = this.initPageY + iDown;
1016 if (iTickSize) { this.setYTicks(this.initPageY, iTickSize); }
1017
1018 this.constrainY = true;
1019
1020 },
1021
1022 /**
1023 * resetConstraints must be called if you manually reposition a dd element.
1024 * @method resetConstraints
1025 * @param {boolean} maintainOffset
1026 */
1027 resetConstraints: function() {
1028
1029
1030 // Maintain offsets if necessary
1031 if (this.initPageX || this.initPageX === 0) {
1032 // figure out how much this thing has moved
1033 var dx = (this.maintainOffset) ? this.lastPageX - this.initPageX : 0;
1034 var dy = (this.maintainOffset) ? this.lastPageY - this.initPageY : 0;
1035
1036 this.setInitPosition(dx, dy);
1037
1038 // This is the first time we have detected the element's position
1039 } else {
1040 this.setInitPosition();
1041 }
1042
1043 if (this.constrainX) {
1044 this.setXConstraint( this.leftConstraint,
1045 this.rightConstraint,
1046 this.xTickSize );
1047 }
1048
1049 if (this.constrainY) {
1050 this.setYConstraint( this.topConstraint,
1051 this.bottomConstraint,
1052 this.yTickSize );
1053 }
1054 },
1055
1056 /**
1057 * Normally the drag element is moved pixel by pixel, but we can specify
1058 * that it move a number of pixels at a time. This method resolves the
1059 * location when we have it set up like this.
1060 * @method getTick
1061 * @param {int} val where we want to place the object
1062 * @param {int[]} tickArray sorted array of valid points
1063 * @return {int} the closest tick
1064 * @private
1065 */
1066 getTick: function(val, tickArray) {
1067
1068 if (!tickArray) {
1069 // If tick interval is not defined, it is effectively 1 pixel,
1070 // so we return the value passed to us.
1071 return val;
1072 } else if (tickArray[0] >= val) {
1073 // The value is lower than the first tick, so we return the first
1074 // tick.
1075 return tickArray[0];
1076 } else {
1077 for (var i=0, len=tickArray.length; i<len; ++i) {
1078 var next = i + 1;
1079 if (tickArray[next] && tickArray[next] >= val) {
1080 var diff1 = val - tickArray[i];
1081 var diff2 = tickArray[next] - val;
1082 return (diff2 > diff1) ? tickArray[i] : tickArray[next];
1083 }
1084 }
1085
1086 // The value is larger than the last tick, so we return the last
1087 // tick.
1088 return tickArray[tickArray.length - 1];
1089 }
1090 },
1091
1092 /**
1093 * toString method
1094 * @method toString
1095 * @return {string} string representation of the dd obj
1096 */
1097 toString: function() {
1098 return ("DragDrop " + this.id);
1099 }
1100
1101};
1102
1103})();
1104/**
1105 * The drag and drop utility provides a framework for building drag and drop
1106 * applications. In addition to enabling drag and drop for specific elements,
1107 * the drag and drop elements are tracked by the manager class, and the
1108 * interactions between the various elements are tracked during the drag and
1109 * the implementing code is notified about these important moments.
1110 * @module dragdrop
1111 * @title Drag and Drop
1112 * @requires yahoo,dom,event
1113 * @namespace YAHOO.util
1114 */
1115
1116// Only load the library once. Rewriting the manager class would orphan
1117// existing drag and drop instances.
1118if (!YAHOO.util.DragDropMgr) {
1119
1120/**
1121 * DragDropMgr is a singleton that tracks the element interaction for
1122 * all DragDrop items in the window. Generally, you will not call
1123 * this class directly, but it does have helper methods that could
1124 * be useful in your DragDrop implementations.
1125 * @class DragDropMgr
1126 * @static
1127 */
1128YAHOO.util.DragDropMgr = function() {
1129
1130 var Event = YAHOO.util.Event;
1131
1132 return {
1133
1134 /**
1135 * Two dimensional Array of registered DragDrop objects. The first
1136 * dimension is the DragDrop item group, the second the DragDrop
1137 * object.
1138 * @property ids
1139 * @type {string: string}
1140 * @private
1141 * @static
1142 */
1143 ids: {},
1144
1145 /**
1146 * Array of element ids defined as drag handles. Used to determine
1147 * if the element that generated the mousedown event is actually the
1148 * handle and not the html element itself.
1149 * @property handleIds
1150 * @type {string: string}
1151 * @private
1152 * @static
1153 */
1154 handleIds: {},
1155
1156 /**
1157 * the DragDrop object that is currently being dragged
1158 * @property dragCurrent
1159 * @type DragDrop
1160 * @private
1161 * @static
1162 **/
1163 dragCurrent: null,
1164
1165 /**
1166 * the DragDrop object(s) that are being hovered over
1167 * @property dragOvers
1168 * @type Array
1169 * @private
1170 * @static
1171 */
1172 dragOvers: {},
1173
1174 /**
1175 * the X distance between the cursor and the object being dragged
1176 * @property deltaX
1177 * @type int
1178 * @private
1179 * @static
1180 */
1181 deltaX: 0,
1182
1183 /**
1184 * the Y distance between the cursor and the object being dragged
1185 * @property deltaY
1186 * @type int
1187 * @private
1188 * @static
1189 */
1190 deltaY: 0,
1191
1192 /**
1193 * Flag to determine if we should prevent the default behavior of the
1194 * events we define. By default this is true, but this can be set to
1195 * false if you need the default behavior (not recommended)
1196 * @property preventDefault
1197 * @type boolean
1198 * @static
1199 */
1200 preventDefault: true,
1201
1202 /**
1203 * Flag to determine if we should stop the propagation of the events
1204 * we generate. This is true by default but you may want to set it to
1205 * false if the html element contains other features that require the
1206 * mouse click.
1207 * @property stopPropagation
1208 * @type boolean
1209 * @static
1210 */
1211 stopPropagation: true,
1212
1213 /**
1214 * Internal flag that is set to true when drag and drop has been
1215 * intialized
1216 * @property initialized
1217 * @private
1218 * @static
1219 */
1220 initalized: false,
1221
1222 /**
1223 * All drag and drop can be disabled.
1224 * @property locked
1225 * @private
1226 * @static
1227 */
1228 locked: false,
1229
1230 /**
1231 * Called the first time an element is registered.
1232 * @method init
1233 * @private
1234 * @static
1235 */
1236 init: function() {
1237 this.initialized = true;
1238 },
1239
1240 /**
1241 * In point mode, drag and drop interaction is defined by the
1242 * location of the cursor during the drag/drop
1243 * @property POINT
1244 * @type int
1245 * @static
1246 */
1247 POINT: 0,
1248
1249 /**
1250 * In intersect mode, drag and drop interactio nis defined by the
1251 * overlap of two or more drag and drop objects.
1252 * @property INTERSECT
1253 * @type int
1254 * @static
1255 */
1256 INTERSECT: 1,
1257
1258 /**
1259 * The current drag and drop mode. Default: POINT
1260 * @property mode
1261 * @type int
1262 * @static
1263 */
1264 mode: 0,
1265
1266 /**
1267 * Runs method on all drag and drop objects
1268 * @method _execOnAll
1269 * @private
1270 * @static
1271 */
1272 _execOnAll: function(sMethod, args) {
1273 for (var i in this.ids) {
1274 for (var j in this.ids[i]) {
1275 var oDD = this.ids[i][j];
1276 if (! this.isTypeOfDD(oDD)) {
1277 continue;
1278 }
1279 oDD[sMethod].apply(oDD, args);
1280 }
1281 }
1282 },
1283
1284 /**
1285 * Drag and drop initialization. Sets up the global event handlers
1286 * @method _onLoad
1287 * @private
1288 * @static
1289 */
1290 _onLoad: function() {
1291
1292 this.init();
1293
1294
1295 Event.on(document, "mouseup", this.handleMouseUp, this, true);
1296 Event.on(document, "mousemove", this.handleMouseMove, this, true);
1297 Event.on(window, "unload", this._onUnload, this, true);
1298 Event.on(window, "resize", this._onResize, this, true);
1299 // Event.on(window, "mouseout", this._test);
1300
1301 },
1302
1303 /**
1304 * Reset constraints on all drag and drop objs
1305 * @method _onResize
1306 * @private
1307 * @static
1308 */
1309 _onResize: function(e) {
1310 this._execOnAll("resetConstraints", []);
1311 },
1312
1313 /**
1314 * Lock all drag and drop functionality
1315 * @method lock
1316 * @static
1317 */
1318 lock: function() { this.locked = true; },
1319
1320 /**
1321 * Unlock all drag and drop functionality
1322 * @method unlock
1323 * @static
1324 */
1325 unlock: function() { this.locked = false; },
1326
1327 /**
1328 * Is drag and drop locked?
1329 * @method isLocked
1330 * @return {boolean} True if drag and drop is locked, false otherwise.
1331 * @static
1332 */
1333 isLocked: function() { return this.locked; },
1334
1335 /**
1336 * Location cache that is set for all drag drop objects when a drag is
1337 * initiated, cleared when the drag is finished.
1338 * @property locationCache
1339 * @private
1340 * @static
1341 */
1342 locationCache: {},
1343
1344 /**
1345 * Set useCache to false if you want to force object the lookup of each
1346 * drag and drop linked element constantly during a drag.
1347 * @property useCache
1348 * @type boolean
1349 * @static
1350 */
1351 useCache: true,
1352
1353 /**
1354 * The number of pixels that the mouse needs to move after the
1355 * mousedown before the drag is initiated. Default=3;
1356 * @property clickPixelThresh
1357 * @type int
1358 * @static
1359 */
1360 clickPixelThresh: 3,
1361
1362 /**
1363 * The number of milliseconds after the mousedown event to initiate the
1364 * drag if we don't get a mouseup event. Default=1000
1365 * @property clickTimeThresh
1366 * @type int
1367 * @static
1368 */
1369 clickTimeThresh: 1000,
1370
1371 /**
1372 * Flag that indicates that either the drag pixel threshold or the
1373 * mousdown time threshold has been met
1374 * @property dragThreshMet
1375 * @type boolean
1376 * @private
1377 * @static
1378 */
1379 dragThreshMet: false,
1380
1381 /**
1382 * Timeout used for the click time threshold
1383 * @property clickTimeout
1384 * @type Object
1385 * @private
1386 * @static
1387 */
1388 clickTimeout: null,
1389
1390 /**
1391 * The X position of the mousedown event stored for later use when a
1392 * drag threshold is met.
1393 * @property startX
1394 * @type int
1395 * @private
1396 * @static
1397 */
1398 startX: 0,
1399
1400 /**
1401 * The Y position of the mousedown event stored for later use when a
1402 * drag threshold is met.
1403 * @property startY
1404 * @type int
1405 * @private
1406 * @static
1407 */
1408 startY: 0,
1409
1410 /**
1411 * Each DragDrop instance must be registered with the DragDropMgr.
1412 * This is executed in DragDrop.init()
1413 * @method regDragDrop
1414 * @param {DragDrop} oDD the DragDrop object to register
1415 * @param {String} sGroup the name of the group this element belongs to
1416 * @static
1417 */
1418 regDragDrop: function(oDD, sGroup) {
1419 if (!this.initialized) { this.init(); }
1420
1421 if (!this.ids[sGroup]) {
1422 this.ids[sGroup] = {};
1423 }
1424 this.ids[sGroup][oDD.id] = oDD;
1425 },
1426
1427 /**
1428 * Removes the supplied dd instance from the supplied group. Executed
1429 * by DragDrop.removeFromGroup, so don't call this function directly.
1430 * @method removeDDFromGroup
1431 * @private
1432 * @static
1433 */
1434 removeDDFromGroup: function(oDD, sGroup) {
1435 if (!this.ids[sGroup]) {
1436 this.ids[sGroup] = {};
1437 }
1438
1439 var obj = this.ids[sGroup];
1440 if (obj && obj[oDD.id]) {
1441 delete obj[oDD.id];
1442 }
1443 },
1444
1445 /**
1446 * Unregisters a drag and drop item. This is executed in
1447 * DragDrop.unreg, use that method instead of calling this directly.
1448 * @method _remove
1449 * @private
1450 * @static
1451 */
1452 _remove: function(oDD) {
1453 for (var g in oDD.groups) {
1454 if (g && this.ids[g][oDD.id]) {
1455 delete this.ids[g][oDD.id];
1456 }
1457 }
1458 delete this.handleIds[oDD.id];
1459 },
1460
1461 /**
1462 * Each DragDrop handle element must be registered. This is done
1463 * automatically when executing DragDrop.setHandleElId()
1464 * @method regHandle
1465 * @param {String} sDDId the DragDrop id this element is a handle for
1466 * @param {String} sHandleId the id of the element that is the drag
1467 * handle
1468 * @static
1469 */
1470 regHandle: function(sDDId, sHandleId) {
1471 if (!this.handleIds[sDDId]) {
1472 this.handleIds[sDDId] = {};
1473 }
1474 this.handleIds[sDDId][sHandleId] = sHandleId;
1475 },
1476
1477 /**
1478 * Utility function to determine if a given element has been
1479 * registered as a drag drop item.
1480 * @method isDragDrop
1481 * @param {String} id the element id to check
1482 * @return {boolean} true if this element is a DragDrop item,
1483 * false otherwise
1484 * @static
1485 */
1486 isDragDrop: function(id) {
1487 return ( this.getDDById(id) ) ? true : false;
1488 },
1489
1490 /**
1491 * Returns the drag and drop instances that are in all groups the
1492 * passed in instance belongs to.
1493 * @method getRelated
1494 * @param {DragDrop} p_oDD the obj to get related data for
1495 * @param {boolean} bTargetsOnly if true, only return targetable objs
1496 * @return {DragDrop[]} the related instances
1497 * @static
1498 */
1499 getRelated: function(p_oDD, bTargetsOnly) {
1500 var oDDs = [];
1501 for (var i in p_oDD.groups) {
1502 for (j in this.ids[i]) {
1503 var dd = this.ids[i][j];
1504 if (! this.isTypeOfDD(dd)) {
1505 continue;
1506 }
1507 if (!bTargetsOnly || dd.isTarget) {
1508 oDDs[oDDs.length] = dd;
1509 }
1510 }
1511 }
1512
1513 return oDDs;
1514 },
1515
1516 /**
1517 * Returns true if the specified dd target is a legal target for
1518 * the specifice drag obj
1519 * @method isLegalTarget
1520 * @param {DragDrop} the drag obj
1521 * @param {DragDrop} the target
1522 * @return {boolean} true if the target is a legal target for the
1523 * dd obj
1524 * @static
1525 */
1526 isLegalTarget: function (oDD, oTargetDD) {
1527 var targets = this.getRelated(oDD, true);
1528 for (var i=0, len=targets.length;i<len;++i) {
1529 if (targets[i].id == oTargetDD.id) {
1530 return true;
1531 }
1532 }
1533
1534 return false;
1535 },
1536
1537 /**
1538 * My goal is to be able to transparently determine if an object is
1539 * typeof DragDrop, and the exact subclass of DragDrop. typeof
1540 * returns "object", oDD.constructor.toString() always returns
1541 * "DragDrop" and not the name of the subclass. So for now it just
1542 * evaluates a well-known variable in DragDrop.
1543 * @method isTypeOfDD
1544 * @param {Object} the object to evaluate
1545 * @return {boolean} true if typeof oDD = DragDrop
1546 * @static
1547 */
1548 isTypeOfDD: function (oDD) {
1549 return (oDD && oDD.__ygDragDrop);
1550 },
1551
1552 /**
1553 * Utility function to determine if a given element has been
1554 * registered as a drag drop handle for the given Drag Drop object.
1555 * @method isHandle
1556 * @param {String} id the element id to check
1557 * @return {boolean} true if this element is a DragDrop handle, false
1558 * otherwise
1559 * @static
1560 */
1561 isHandle: function(sDDId, sHandleId) {
1562 return ( this.handleIds[sDDId] &&
1563 this.handleIds[sDDId][sHandleId] );
1564 },
1565
1566 /**
1567 * Returns the DragDrop instance for a given id
1568 * @method getDDById
1569 * @param {String} id the id of the DragDrop object
1570 * @return {DragDrop} the drag drop object, null if it is not found
1571 * @static
1572 */
1573 getDDById: function(id) {
1574 for (var i in this.ids) {
1575 if (this.ids[i][id]) {
1576 return this.ids[i][id];
1577 }
1578 }
1579 return null;
1580 },
1581
1582 /**
1583 * Fired after a registered DragDrop object gets the mousedown event.
1584 * Sets up the events required to track the object being dragged
1585 * @method handleMouseDown
1586 * @param {Event} e the event
1587 * @param oDD the DragDrop object being dragged
1588 * @private
1589 * @static
1590 */
1591 handleMouseDown: function(e, oDD) {
1592
1593 this.currentTarget = YAHOO.util.Event.getTarget(e);
1594
1595 this.dragCurrent = oDD;
1596
1597 var el = oDD.getEl();
1598
1599 // track start position
1600 this.startX = YAHOO.util.Event.getPageX(e);
1601 this.startY = YAHOO.util.Event.getPageY(e);
1602
1603 this.deltaX = this.startX - el.offsetLeft;
1604 this.deltaY = this.startY - el.offsetTop;
1605
1606 this.dragThreshMet = false;
1607
1608 this.clickTimeout = setTimeout(
1609 function() {
1610 var DDM = YAHOO.util.DDM;
1611 DDM.startDrag(DDM.startX, DDM.startY);
1612 },
1613 this.clickTimeThresh );
1614 },
1615
1616 /**
1617 * Fired when either the drag pixel threshol or the mousedown hold
1618 * time threshold has been met.
1619 * @method startDrag
1620 * @param x {int} the X position of the original mousedown
1621 * @param y {int} the Y position of the original mousedown
1622 * @static
1623 */
1624 startDrag: function(x, y) {
1625 clearTimeout(this.clickTimeout);
1626 if (this.dragCurrent) {
1627 this.dragCurrent.b4StartDrag(x, y);
1628 this.dragCurrent.startDrag(x, y);
1629 }
1630 this.dragThreshMet = true;
1631 },
1632
1633 /**
1634 * Internal function to handle the mouseup event. Will be invoked
1635 * from the context of the document.
1636 * @method handleMouseUp
1637 * @param {Event} e the event
1638 * @private
1639 * @static
1640 */
1641 handleMouseUp: function(e) {
1642
1643 if (! this.dragCurrent) {
1644 return;
1645 }
1646
1647 clearTimeout(this.clickTimeout);
1648
1649 if (this.dragThreshMet) {
1650 this.fireEvents(e, true);
1651 } else {
1652 }
1653
1654 this.stopDrag(e);
1655
1656 this.stopEvent(e);
1657 },
1658
1659 /**
1660 * Utility to stop event propagation and event default, if these
1661 * features are turned on.
1662 * @method stopEvent
1663 * @param {Event} e the event as returned by this.getEvent()
1664 * @static
1665 */
1666 stopEvent: function(e) {
1667 if (this.stopPropagation) {
1668 YAHOO.util.Event.stopPropagation(e);
1669 }
1670
1671 if (this.preventDefault) {
1672 YAHOO.util.Event.preventDefault(e);
1673 }
1674 },
1675
1676 /**
1677 * Internal function to clean up event handlers after the drag
1678 * operation is complete
1679 * @method stopDrag
1680 * @param {Event} e the event
1681 * @private
1682 * @static
1683 */
1684 stopDrag: function(e) {
1685
1686 // Fire the drag end event for the item that was dragged
1687 if (this.dragCurrent) {
1688 if (this.dragThreshMet) {
1689 this.dragCurrent.b4EndDrag(e);
1690 this.dragCurrent.endDrag(e);
1691 }
1692
1693 this.dragCurrent.onMouseUp(e);
1694 }
1695
1696 this.dragCurrent = null;
1697 this.dragOvers = {};
1698 },
1699
1700 /**
1701 * Internal function to handle the mousemove event. Will be invoked
1702 * from the context of the html element.
1703 *
1704 * @TODO figure out what we can do about mouse events lost when the
1705 * user drags objects beyond the window boundary. Currently we can
1706 * detect this in internet explorer by verifying that the mouse is
1707 * down during the mousemove event. Firefox doesn't give us the
1708 * button state on the mousemove event.
1709 * @method handleMouseMove
1710 * @param {Event} e the event
1711 * @private
1712 * @static
1713 */
1714 handleMouseMove: function(e) {
1715 if (! this.dragCurrent) {
1716 return true;
1717 }
1718
1719 // var button = e.which || e.button;
1720
1721 // check for IE mouseup outside of page boundary
1722 if (YAHOO.util.Event.isIE && !e.button) {
1723 this.stopEvent(e);
1724 return this.handleMouseUp(e);
1725 }
1726
1727 if (!this.dragThreshMet) {
1728 var diffX = Math.abs(this.startX - YAHOO.util.Event.getPageX(e));
1729 var diffY = Math.abs(this.startY - YAHOO.util.Event.getPageY(e));
1730 if (diffX > this.clickPixelThresh ||
1731 diffY > this.clickPixelThresh) {
1732 this.startDrag(this.startX, this.startY);
1733 }
1734 }
1735
1736 if (this.dragThreshMet) {
1737 this.dragCurrent.b4Drag(e);
1738 this.dragCurrent.onDrag(e);
1739 this.fireEvents(e, false);
1740 }
1741
1742 this.stopEvent(e);
1743
1744 return true;
1745 },
1746
1747 /**
1748 * Iterates over all of the DragDrop elements to find ones we are
1749 * hovering over or dropping on
1750 * @method fireEvents
1751 * @param {Event} e the event
1752 * @param {boolean} isDrop is this a drop op or a mouseover op?
1753 * @private
1754 * @static
1755 */
1756 fireEvents: function(e, isDrop) {
1757 var dc = this.dragCurrent;
1758
1759 // If the user did the mouse up outside of the window, we could
1760 // get here even though we have ended the drag.
1761 if (!dc || dc.isLocked()) {
1762 return;
1763 }
1764
1765 var x = YAHOO.util.Event.getPageX(e);
1766 var y = YAHOO.util.Event.getPageY(e);
1767 var pt = new YAHOO.util.Point(x,y);
1768
1769 // cache the previous dragOver array
1770 var oldOvers = [];
1771
1772 var outEvts = [];
1773 var overEvts = [];
1774 var dropEvts = [];
1775 var enterEvts = [];
1776
1777 // Check to see if the object(s) we were hovering over is no longer
1778 // being hovered over so we can fire the onDragOut event
1779 for (var i in this.dragOvers) {
1780
1781 var ddo = this.dragOvers[i];
1782
1783 if (! this.isTypeOfDD(ddo)) {
1784 continue;
1785 }
1786
1787 if (! this.isOverTarget(pt, ddo, this.mode)) {
1788 outEvts.push( ddo );
1789 }
1790
1791 oldOvers[i] = true;
1792 delete this.dragOvers[i];
1793 }
1794
1795 for (var sGroup in dc.groups) {
1796
1797 if ("string" != typeof sGroup) {
1798 continue;
1799 }
1800
1801 for (i in this.ids[sGroup]) {
1802 var oDD = this.ids[sGroup][i];
1803 if (! this.isTypeOfDD(oDD)) {
1804 continue;
1805 }
1806
1807 if (oDD.isTarget && !oDD.isLocked() && oDD != dc) {
1808 if (this.isOverTarget(pt, oDD, this.mode)) {
1809 // look for drop interactions
1810 if (isDrop) {
1811 dropEvts.push( oDD );
1812 // look for drag enter and drag over interactions
1813 } else {
1814
1815 // initial drag over: dragEnter fires
1816 if (!oldOvers[oDD.id]) {
1817 enterEvts.push( oDD );
1818 // subsequent drag overs: dragOver fires
1819 } else {
1820 overEvts.push( oDD );
1821 }
1822
1823 this.dragOvers[oDD.id] = oDD;
1824 }
1825 }
1826 }
1827 }
1828 }
1829
1830 if (this.mode) {
1831 if (outEvts.length) {
1832 dc.b4DragOut(e, outEvts);
1833 dc.onDragOut(e, outEvts);
1834 }
1835
1836 if (enterEvts.length) {
1837 dc.onDragEnter(e, enterEvts);
1838 }
1839
1840 if (overEvts.length) {
1841 dc.b4DragOver(e, overEvts);
1842 dc.onDragOver(e, overEvts);
1843 }
1844
1845 if (dropEvts.length) {
1846 dc.b4DragDrop(e, dropEvts);
1847 dc.onDragDrop(e, dropEvts);
1848 }
1849
1850 } else {
1851 // fire dragout events
1852 var len = 0;
1853 for (i=0, len=outEvts.length; i<len; ++i) {
1854 dc.b4DragOut(e, outEvts[i].id);
1855 dc.onDragOut(e, outEvts[i].id);
1856 }
1857
1858 // fire enter events
1859 for (i=0,len=enterEvts.length; i<len; ++i) {
1860 // dc.b4DragEnter(e, oDD.id);
1861 dc.onDragEnter(e, enterEvts[i].id);
1862 }
1863
1864 // fire over events
1865 for (i=0,len=overEvts.length; i<len; ++i) {
1866 dc.b4DragOver(e, overEvts[i].id);
1867 dc.onDragOver(e, overEvts[i].id);
1868 }
1869
1870 // fire drop events
1871 for (i=0, len=dropEvts.length; i<len; ++i) {
1872 dc.b4DragDrop(e, dropEvts[i].id);
1873 dc.onDragDrop(e, dropEvts[i].id);
1874 }
1875
1876 }
1877
1878 // notify about a drop that did not find a target
1879 if (isDrop && !dropEvts.length) {
1880 dc.onInvalidDrop(e);
1881 }
1882
1883 },
1884
1885 /**
1886 * Helper function for getting the best match from the list of drag
1887 * and drop objects returned by the drag and drop events when we are
1888 * in INTERSECT mode. It returns either the first object that the
1889 * cursor is over, or the object that has the greatest overlap with
1890 * the dragged element.
1891 * @method getBestMatch
1892 * @param {DragDrop[]} dds The array of drag and drop objects
1893 * targeted
1894 * @return {DragDrop} The best single match
1895 * @static
1896 */
1897 getBestMatch: function(dds) {
1898 var winner = null;
1899 // Return null if the input is not what we expect
1900 //if (!dds || !dds.length || dds.length == 0) {
1901 // winner = null;
1902 // If there is only one item, it wins
1903 //} else if (dds.length == 1) {
1904
1905 var len = dds.length;
1906
1907 if (len == 1) {
1908 winner = dds[0];
1909 } else {
1910 // Loop through the targeted items
1911 for (var i=0; i<len; ++i) {
1912 var dd = dds[i];
1913 // If the cursor is over the object, it wins. If the
1914 // cursor is over multiple matches, the first one we come
1915 // to wins.
1916 if (dd.cursorIsOver) {
1917 winner = dd;
1918 break;
1919 // Otherwise the object with the most overlap wins
1920 } else {
1921 if (!winner ||
1922 winner.overlap.getArea() < dd.overlap.getArea()) {
1923 winner = dd;
1924 }
1925 }
1926 }
1927 }
1928
1929 return winner;
1930 },
1931
1932 /**
1933 * Refreshes the cache of the top-left and bottom-right points of the
1934 * drag and drop objects in the specified group(s). This is in the
1935 * format that is stored in the drag and drop instance, so typical
1936 * usage is:
1937 * <code>
1938 * YAHOO.util.DragDropMgr.refreshCache(ddinstance.groups);
1939 * </code>
1940 * Alternatively:
1941 * <code>
1942 * YAHOO.util.DragDropMgr.refreshCache({group1:true, group2:true});
1943 * </code>
1944 * @TODO this really should be an indexed array. Alternatively this
1945 * method could accept both.
1946 * @method refreshCache
1947 * @param {Object} groups an associative array of groups to refresh
1948 * @static
1949 */
1950 refreshCache: function(groups) {
1951 for (var sGroup in groups) {
1952 if ("string" != typeof sGroup) {
1953 continue;
1954 }
1955 for (var i in this.ids[sGroup]) {
1956 var oDD = this.ids[sGroup][i];
1957
1958 if (this.isTypeOfDD(oDD)) {
1959 // if (this.isTypeOfDD(oDD) && oDD.isTarget) {
1960 var loc = this.getLocation(oDD);
1961 if (loc) {
1962 this.locationCache[oDD.id] = loc;
1963 } else {
1964 delete this.locationCache[oDD.id];
1965 // this will unregister the drag and drop object if
1966 // the element is not in a usable state
1967 // oDD.unreg();
1968 }
1969 }
1970 }
1971 }
1972 },
1973
1974 /**
1975 * This checks to make sure an element exists and is in the DOM. The
1976 * main purpose is to handle cases where innerHTML is used to remove
1977 * drag and drop objects from the DOM. IE provides an 'unspecified
1978 * error' when trying to access the offsetParent of such an element
1979 * @method verifyEl
1980 * @param {HTMLElement} el the element to check
1981 * @return {boolean} true if the element looks usable
1982 * @static
1983 */
1984 verifyEl: function(el) {
1985 try {
1986 if (el) {
1987 var parent = el.offsetParent;
1988 if (parent) {
1989 return true;
1990 }
1991 }
1992 } catch(e) {
1993 }
1994
1995 return false;
1996 },
1997
1998 /**
1999 * Returns a Region object containing the drag and drop element's position
2000 * and size, including the padding configured for it
2001 * @method getLocation
2002 * @param {DragDrop} oDD the drag and drop object to get the
2003 * location for
2004 * @return {YAHOO.util.Region} a Region object representing the total area
2005 * the element occupies, including any padding
2006 * the instance is configured for.
2007 * @static
2008 */
2009 getLocation: function(oDD) {
2010 if (! this.isTypeOfDD(oDD)) {
2011 return null;
2012 }
2013
2014 var el = oDD.getEl(), pos, x1, x2, y1, y2, t, r, b, l;
2015
2016 try {
2017 pos= YAHOO.util.Dom.getXY(el);
2018 } catch (e) { }
2019
2020 if (!pos) {
2021 return null;
2022 }
2023
2024 x1 = pos[0];
2025 x2 = x1 + el.offsetWidth;
2026 y1 = pos[1];
2027 y2 = y1 + el.offsetHeight;
2028
2029 t = y1 - oDD.padding[0];
2030 r = x2 + oDD.padding[1];
2031 b = y2 + oDD.padding[2];
2032 l = x1 - oDD.padding[3];
2033
2034 return new YAHOO.util.Region( t, r, b, l );
2035 },
2036
2037 /**
2038 * Checks the cursor location to see if it over the target
2039 * @method isOverTarget
2040 * @param {YAHOO.util.Point} pt The point to evaluate
2041 * @param {DragDrop} oTarget the DragDrop object we are inspecting
2042 * @return {boolean} true if the mouse is over the target
2043 * @private
2044 * @static
2045 */
2046 isOverTarget: function(pt, oTarget, intersect) {
2047 // use cache if available
2048 var loc = this.locationCache[oTarget.id];
2049 if (!loc || !this.useCache) {
2050 loc = this.getLocation(oTarget);
2051 this.locationCache[oTarget.id] = loc;
2052
2053 }
2054
2055 if (!loc) {
2056 return false;
2057 }
2058
2059 oTarget.cursorIsOver = loc.contains( pt );
2060
2061 // DragDrop is using this as a sanity check for the initial mousedown
2062 // in this case we are done. In POINT mode, if the drag obj has no
2063 // contraints, we are also done. Otherwise we need to evaluate the
2064 // location of the target as related to the actual location of the
2065 // dragged element.
2066 var dc = this.dragCurrent;
2067 if (!dc || !dc.getTargetCoord ||
2068 (!intersect && !dc.constrainX && !dc.constrainY)) {
2069 return oTarget.cursorIsOver;
2070 }
2071
2072 oTarget.overlap = null;
2073
2074 // Get the current location of the drag element, this is the
2075 // location of the mouse event less the delta that represents
2076 // where the original mousedown happened on the element. We
2077 // need to consider constraints and ticks as well.
2078 var pos = dc.getTargetCoord(pt.x, pt.y);
2079
2080 var el = dc.getDragEl();
2081 var curRegion = new YAHOO.util.Region( pos.y,
2082 pos.x + el.offsetWidth,
2083 pos.y + el.offsetHeight,
2084 pos.x );
2085
2086 var overlap = curRegion.intersect(loc);
2087
2088 if (overlap) {
2089 oTarget.overlap = overlap;
2090 return (intersect) ? true : oTarget.cursorIsOver;
2091 } else {
2092 return false;
2093 }
2094 },
2095
2096 /**
2097 * unload event handler
2098 * @method _onUnload
2099 * @private
2100 * @static
2101 */
2102 _onUnload: function(e, me) {
2103 this.unregAll();
2104 },
2105
2106 /**
2107 * Cleans up the drag and drop events and objects.
2108 * @method unregAll
2109 * @private
2110 * @static
2111 */
2112 unregAll: function() {
2113
2114 if (this.dragCurrent) {
2115 this.stopDrag();
2116 this.dragCurrent = null;
2117 }
2118
2119 this._execOnAll("unreg", []);
2120
2121 for (i in this.elementCache) {
2122 delete this.elementCache[i];
2123 }
2124
2125 this.elementCache = {};
2126 this.ids = {};
2127 },
2128
2129 /**
2130 * A cache of DOM elements
2131 * @property elementCache
2132 * @private
2133 * @static
2134 */
2135 elementCache: {},
2136
2137 /**
2138 * Get the wrapper for the DOM element specified
2139 * @method getElWrapper
2140 * @param {String} id the id of the element to get
2141 * @return {YAHOO.util.DDM.ElementWrapper} the wrapped element
2142 * @private
2143 * @deprecated This wrapper isn't that useful
2144 * @static
2145 */
2146 getElWrapper: function(id) {
2147 var oWrapper = this.elementCache[id];
2148 if (!oWrapper || !oWrapper.el) {
2149 oWrapper = this.elementCache[id] =
2150 new this.ElementWrapper(YAHOO.util.Dom.get(id));
2151 }
2152 return oWrapper;
2153 },
2154
2155 /**
2156 * Returns the actual DOM element
2157 * @method getElement
2158 * @param {String} id the id of the elment to get
2159 * @return {Object} The element
2160 * @deprecated use YAHOO.util.Dom.get instead
2161 * @static
2162 */
2163 getElement: function(id) {
2164 return YAHOO.util.Dom.get(id);
2165 },
2166
2167 /**
2168 * Returns the style property for the DOM element (i.e.,
2169 * document.getElById(id).style)
2170 * @method getCss
2171 * @param {String} id the id of the elment to get
2172 * @return {Object} The style property of the element
2173 * @deprecated use YAHOO.util.Dom instead
2174 * @static
2175 */
2176 getCss: function(id) {
2177 var el = YAHOO.util.Dom.get(id);
2178 return (el) ? el.style : null;
2179 },
2180
2181 /**
2182 * Inner class for cached elements
2183 * @class DragDropMgr.ElementWrapper
2184 * @for DragDropMgr
2185 * @private
2186 * @deprecated
2187 */
2188 ElementWrapper: function(el) {
2189 /**
2190 * The element
2191 * @property el
2192 */
2193 this.el = el || null;
2194 /**
2195 * The element id
2196 * @property id
2197 */
2198 this.id = this.el && el.id;
2199 /**
2200 * A reference to the style property
2201 * @property css
2202 */
2203 this.css = this.el && el.style;
2204 },
2205
2206 /**
2207 * Returns the X position of an html element
2208 * @method getPosX
2209 * @param el the element for which to get the position
2210 * @return {int} the X coordinate
2211 * @for DragDropMgr
2212 * @deprecated use YAHOO.util.Dom.getX instead
2213 * @static
2214 */
2215 getPosX: function(el) {
2216 return YAHOO.util.Dom.getX(el);
2217 },
2218
2219 /**
2220 * Returns the Y position of an html element
2221 * @method getPosY
2222 * @param el the element for which to get the position
2223 * @return {int} the Y coordinate
2224 * @deprecated use YAHOO.util.Dom.getY instead
2225 * @static
2226 */
2227 getPosY: function(el) {
2228 return YAHOO.util.Dom.getY(el);
2229 },
2230
2231 /**
2232 * Swap two nodes. In IE, we use the native method, for others we
2233 * emulate the IE behavior
2234 * @method swapNode
2235 * @param n1 the first node to swap
2236 * @param n2 the other node to swap
2237 * @static
2238 */
2239 swapNode: function(n1, n2) {
2240 if (n1.swapNode) {
2241 n1.swapNode(n2);
2242 } else {
2243 var p = n2.parentNode;
2244 var s = n2.nextSibling;
2245
2246 if (s == n1) {
2247 p.insertBefore(n1, n2);
2248 } else if (n2 == n1.nextSibling) {
2249 p.insertBefore(n2, n1);
2250 } else {
2251 n1.parentNode.replaceChild(n2, n1);
2252 p.insertBefore(n1, s);
2253 }
2254 }
2255 },
2256
2257 /**
2258 * Returns the current scroll position
2259 * @method getScroll
2260 * @private
2261 * @static
2262 */
2263 getScroll: function () {
2264 var t, l, dde=document.documentElement, db=document.body;
2265 if (dde && (dde.scrollTop || dde.scrollLeft)) {
2266 t = dde.scrollTop;
2267 l = dde.scrollLeft;
2268 } else if (db) {
2269 t = db.scrollTop;
2270 l = db.scrollLeft;
2271 } else {
2272 YAHOO.log("could not get scroll property");
2273 }
2274 return { top: t, left: l };
2275 },
2276
2277 /**
2278 * Returns the specified element style property
2279 * @method getStyle
2280 * @param {HTMLElement} el the element
2281 * @param {string} styleProp the style property
2282 * @return {string} The value of the style property
2283 * @deprecated use YAHOO.util.Dom.getStyle
2284 * @static
2285 */
2286 getStyle: function(el, styleProp) {
2287 return YAHOO.util.Dom.getStyle(el, styleProp);
2288 },
2289
2290 /**
2291 * Gets the scrollTop
2292 * @method getScrollTop
2293 * @return {int} the document's scrollTop
2294 * @static
2295 */
2296 getScrollTop: function () { return this.getScroll().top; },
2297
2298 /**
2299 * Gets the scrollLeft
2300 * @method getScrollLeft
2301 * @return {int} the document's scrollTop
2302 * @static
2303 */
2304 getScrollLeft: function () { return this.getScroll().left; },
2305
2306 /**
2307 * Sets the x/y position of an element to the location of the
2308 * target element.
2309 * @method moveToEl
2310 * @param {HTMLElement} moveEl The element to move
2311 * @param {HTMLElement} targetEl The position reference element
2312 * @static
2313 */
2314 moveToEl: function (moveEl, targetEl) {
2315 var aCoord = YAHOO.util.Dom.getXY(targetEl);
2316 YAHOO.util.Dom.setXY(moveEl, aCoord);
2317 },
2318
2319 /**
2320 * Gets the client height
2321 * @method getClientHeight
2322 * @return {int} client height in px
2323 * @deprecated use YAHOO.util.Dom.getViewportHeight instead
2324 * @static
2325 */
2326 getClientHeight: function() {
2327 return YAHOO.util.Dom.getViewportHeight();
2328 },
2329
2330 /**
2331 * Gets the client width
2332 * @method getClientWidth
2333 * @return {int} client width in px
2334 * @deprecated use YAHOO.util.Dom.getViewportWidth instead
2335 * @static
2336 */
2337 getClientWidth: function() {
2338 return YAHOO.util.Dom.getViewportWidth();
2339 },
2340
2341 /**
2342 * Numeric array sort function
2343 * @method numericSort
2344 * @static
2345 */
2346 numericSort: function(a, b) { return (a - b); },
2347
2348 /**
2349 * Internal counter
2350 * @property _timeoutCount
2351 * @private
2352 * @static
2353 */
2354 _timeoutCount: 0,
2355
2356 /**
2357 * Trying to make the load order less important. Without this we get
2358 * an error if this file is loaded before the Event Utility.
2359 * @method _addListeners
2360 * @private
2361 * @static
2362 */
2363 _addListeners: function() {
2364 var DDM = YAHOO.util.DDM;
2365 if ( YAHOO.util.Event && document ) {
2366 DDM._onLoad();
2367 } else {
2368 if (DDM._timeoutCount > 2000) {
2369 } else {
2370 setTimeout(DDM._addListeners, 10);
2371 if (document && document.body) {
2372 DDM._timeoutCount += 1;
2373 }
2374 }
2375 }
2376 },
2377
2378 /**
2379 * Recursively searches the immediate parent and all child nodes for
2380 * the handle element in order to determine wheter or not it was
2381 * clicked.
2382 * @method handleWasClicked
2383 * @param node the html element to inspect
2384 * @static
2385 */
2386 handleWasClicked: function(node, id) {
2387 if (this.isHandle(id, node.id)) {
2388 return true;
2389 } else {
2390 // check to see if this is a text node child of the one we want
2391 var p = node.parentNode;
2392
2393 while (p) {
2394 if (this.isHandle(id, p.id)) {
2395 return true;
2396 } else {
2397 p = p.parentNode;
2398 }
2399 }
2400 }
2401
2402 return false;
2403 }
2404
2405 };
2406
2407}();
2408
2409// shorter alias, save a few bytes
2410YAHOO.util.DDM = YAHOO.util.DragDropMgr;
2411YAHOO.util.DDM._addListeners();
2412
2413}
2414
2415/**
2416 * A DragDrop implementation where the linked element follows the
2417 * mouse cursor during a drag.
2418 * @class DD
2419 * @extends YAHOO.util.DragDrop
2420 * @constructor
2421 * @param {String} id the id of the linked element
2422 * @param {String} sGroup the group of related DragDrop items
2423 * @param {object} config an object containing configurable attributes
2424 * Valid properties for DD:
2425 * scroll
2426 */
2427YAHOO.util.DD = function(id, sGroup, config) {
2428 if (id) {
2429 this.init(id, sGroup, config);
2430 }
2431};
2432
2433YAHOO.extend(YAHOO.util.DD, YAHOO.util.DragDrop, {
2434
2435 /**
2436 * When set to true, the utility automatically tries to scroll the browser
2437 * window wehn a drag and drop element is dragged near the viewport boundary.
2438 * Defaults to true.
2439 * @property scroll
2440 * @type boolean
2441 */
2442 scroll: true,
2443
2444 /**
2445 * Sets the pointer offset to the distance between the linked element's top
2446 * left corner and the location the element was clicked
2447 * @method autoOffset
2448 * @param {int} iPageX the X coordinate of the click
2449 * @param {int} iPageY the Y coordinate of the click
2450 */
2451 autoOffset: function(iPageX, iPageY) {
2452 var x = iPageX - this.startPageX;
2453 var y = iPageY - this.startPageY;
2454 this.setDelta(x, y);
2455 },
2456
2457 /**
2458 * Sets the pointer offset. You can call this directly to force the
2459 * offset to be in a particular location (e.g., pass in 0,0 to set it
2460 * to the center of the object, as done in YAHOO.widget.Slider)
2461 * @method setDelta
2462 * @param {int} iDeltaX the distance from the left
2463 * @param {int} iDeltaY the distance from the top
2464 */
2465 setDelta: function(iDeltaX, iDeltaY) {
2466 this.deltaX = iDeltaX;
2467 this.deltaY = iDeltaY;
2468 },
2469
2470 /**
2471 * Sets the drag element to the location of the mousedown or click event,
2472 * maintaining the cursor location relative to the location on the element
2473 * that was clicked. Override this if you want to place the element in a
2474 * location other than where the cursor is.
2475 * @method setDragElPos
2476 * @param {int} iPageX the X coordinate of the mousedown or drag event
2477 * @param {int} iPageY the Y coordinate of the mousedown or drag event
2478 */
2479 setDragElPos: function(iPageX, iPageY) {
2480 // the first time we do this, we are going to check to make sure
2481 // the element has css positioning
2482
2483 var el = this.getDragEl();
2484 this.alignElWithMouse(el, iPageX, iPageY);
2485 },
2486
2487 /**
2488 * Sets the element to the location of the mousedown or click event,
2489 * maintaining the cursor location relative to the location on the element
2490 * that was clicked. Override this if you want to place the element in a
2491 * location other than where the cursor is.
2492 * @method alignElWithMouse
2493 * @param {HTMLElement} el the element to move
2494 * @param {int} iPageX the X coordinate of the mousedown or drag event
2495 * @param {int} iPageY the Y coordinate of the mousedown or drag event
2496 */
2497 alignElWithMouse: function(el, iPageX, iPageY) {
2498 var oCoord = this.getTargetCoord(iPageX, iPageY);
2499
2500 if (!this.deltaSetXY) {
2501 var aCoord = [oCoord.x, oCoord.y];
2502 YAHOO.util.Dom.setXY(el, aCoord);
2503 var newLeft = parseInt( YAHOO.util.Dom.getStyle(el, "left"), 10 );
2504 var newTop = parseInt( YAHOO.util.Dom.getStyle(el, "top" ), 10 );
2505
2506 this.deltaSetXY = [ newLeft - oCoord.x, newTop - oCoord.y ];
2507 } else {
2508 YAHOO.util.Dom.setStyle(el, "left", (oCoord.x + this.deltaSetXY[0]) + "px");
2509 YAHOO.util.Dom.setStyle(el, "top", (oCoord.y + this.deltaSetXY[1]) + "px");
2510 }
2511
2512 this.cachePosition(oCoord.x, oCoord.y);
2513 this.autoScroll(oCoord.x, oCoord.y, el.offsetHeight, el.offsetWidth);
2514 },
2515
2516 /**
2517 * Saves the most recent position so that we can reset the constraints and
2518 * tick marks on-demand. We need to know this so that we can calculate the
2519 * number of pixels the element is offset from its original position.
2520 * @method cachePosition
2521 * @param iPageX the current x position (optional, this just makes it so we
2522 * don't have to look it up again)
2523 * @param iPageY the current y position (optional, this just makes it so we
2524 * don't have to look it up again)
2525 */
2526 cachePosition: function(iPageX, iPageY) {
2527 if (iPageX) {
2528 this.lastPageX = iPageX;
2529 this.lastPageY = iPageY;
2530 } else {
2531 var aCoord = YAHOO.util.Dom.getXY(this.getEl());
2532 this.lastPageX = aCoord[0];
2533 this.lastPageY = aCoord[1];
2534 }
2535 },
2536
2537 /**
2538 * Auto-scroll the window if the dragged object has been moved beyond the
2539 * visible window boundary.
2540 * @method autoScroll
2541 * @param {int} x the drag element's x position
2542 * @param {int} y the drag element's y position
2543 * @param {int} h the height of the drag element
2544 * @param {int} w the width of the drag element
2545 * @private
2546 */
2547 autoScroll: function(x, y, h, w) {
2548
2549 if (this.scroll) {
2550 // The client height
2551 var clientH = this.DDM.getClientHeight();
2552
2553 // The client width
2554 var clientW = this.DDM.getClientWidth();
2555
2556 // The amt scrolled down
2557 var st = this.DDM.getScrollTop();
2558
2559 // The amt scrolled right
2560 var sl = this.DDM.getScrollLeft();
2561
2562 // Location of the bottom of the element
2563 var bot = h + y;
2564
2565 // Location of the right of the element
2566 var right = w + x;
2567
2568 // The distance from the cursor to the bottom of the visible area,
2569 // adjusted so that we don't scroll if the cursor is beyond the
2570 // element drag constraints
2571 var toBot = (clientH + st - y - this.deltaY);
2572
2573 // The distance from the cursor to the right of the visible area
2574 var toRight = (clientW + sl - x - this.deltaX);
2575
2576
2577 // How close to the edge the cursor must be before we scroll
2578 // var thresh = (document.all) ? 100 : 40;
2579 var thresh = 40;
2580
2581 // How many pixels to scroll per autoscroll op. This helps to reduce
2582 // clunky scrolling. IE is more sensitive about this ... it needs this
2583 // value to be higher.
2584 var scrAmt = (document.all) ? 80 : 30;
2585
2586 // Scroll down if we are near the bottom of the visible page and the
2587 // obj extends below the crease
2588 if ( bot > clientH && toBot < thresh ) {
2589 window.scrollTo(sl, st + scrAmt);
2590 }
2591
2592 // Scroll up if the window is scrolled down and the top of the object
2593 // goes above the top border
2594 if ( y < st && st > 0 && y - st < thresh ) {
2595 window.scrollTo(sl, st - scrAmt);
2596 }
2597
2598 // Scroll right if the obj is beyond the right border and the cursor is
2599 // near the border.
2600 if ( right > clientW && toRight < thresh ) {
2601 window.scrollTo(sl + scrAmt, st);
2602 }
2603
2604 // Scroll left if the window has been scrolled to the right and the obj
2605 // extends past the left border
2606 if ( x < sl && sl > 0 && x - sl < thresh ) {
2607 window.scrollTo(sl - scrAmt, st);
2608 }
2609 }
2610 },
2611
2612 /**
2613 * Finds the location the element should be placed if we want to move
2614 * it to where the mouse location less the click offset would place us.
2615 * @method getTargetCoord
2616 * @param {int} iPageX the X coordinate of the click
2617 * @param {int} iPageY the Y coordinate of the click
2618 * @return an object that contains the coordinates (Object.x and Object.y)
2619 * @private
2620 */
2621 getTargetCoord: function(iPageX, iPageY) {
2622
2623
2624 var x = iPageX - this.deltaX;
2625 var y = iPageY - this.deltaY;
2626
2627 if (this.constrainX) {
2628 if (x < this.minX) { x = this.minX; }
2629 if (x > this.maxX) { x = this.maxX; }
2630 }
2631
2632 if (this.constrainY) {
2633 if (y < this.minY) { y = this.minY; }
2634 if (y > this.maxY) { y = this.maxY; }
2635 }
2636
2637 x = this.getTick(x, this.xTicks);
2638 y = this.getTick(y, this.yTicks);
2639
2640
2641 return {x:x, y:y};
2642 },
2643
2644 /*
2645 * Sets up config options specific to this class. Overrides
2646 * YAHOO.util.DragDrop, but all versions of this method through the
2647 * inheritance chain are called
2648 */
2649 applyConfig: function() {
2650 YAHOO.util.DD.superclass.applyConfig.call(this);
2651 this.scroll = (this.config.scroll !== false);
2652 },
2653
2654 /*
2655 * Event that fires prior to the onMouseDown event. Overrides
2656 * YAHOO.util.DragDrop.
2657 */
2658 b4MouseDown: function(e) {
2659 // this.resetConstraints();
2660 this.autoOffset(YAHOO.util.Event.getPageX(e),
2661 YAHOO.util.Event.getPageY(e));
2662 },
2663
2664 /*
2665 * Event that fires prior to the onDrag event. Overrides
2666 * YAHOO.util.DragDrop.
2667 */
2668 b4Drag: function(e) {
2669 this.setDragElPos(YAHOO.util.Event.getPageX(e),
2670 YAHOO.util.Event.getPageY(e));
2671 },
2672
2673 toString: function() {
2674 return ("DD " + this.id);
2675 }
2676
2677 //////////////////////////////////////////////////////////////////////////
2678 // Debugging ygDragDrop events that can be overridden
2679 //////////////////////////////////////////////////////////////////////////
2680 /*
2681 startDrag: function(x, y) {
2682 },
2683
2684 onDrag: function(e) {
2685 },
2686
2687 onDragEnter: function(e, id) {
2688 },
2689
2690 onDragOver: function(e, id) {
2691 },
2692
2693 onDragOut: function(e, id) {
2694 },
2695
2696 onDragDrop: function(e, id) {
2697 },
2698
2699 endDrag: function(e) {
2700 }
2701
2702 */
2703
2704});
2705/**
2706 * A DragDrop implementation that inserts an empty, bordered div into
2707 * the document that follows the cursor during drag operations. At the time of
2708 * the click, the frame div is resized to the dimensions of the linked html
2709 * element, and moved to the exact location of the linked element.
2710 *
2711 * References to the "frame" element refer to the single proxy element that
2712 * was created to be dragged in place of all DDProxy elements on the
2713 * page.
2714 *
2715 * @class DDProxy
2716 * @extends YAHOO.util.DD
2717 * @constructor
2718 * @param {String} id the id of the linked html element
2719 * @param {String} sGroup the group of related DragDrop objects
2720 * @param {object} config an object containing configurable attributes
2721 * Valid properties for DDProxy in addition to those in DragDrop:
2722 * resizeFrame, centerFrame, dragElId
2723 */
2724YAHOO.util.DDProxy = function(id, sGroup, config) {
2725 if (id) {
2726 this.init(id, sGroup, config);
2727 this.initFrame();
2728 }
2729};
2730
2731/**
2732 * The default drag frame div id
2733 * @property YAHOO.util.DDProxy.dragElId
2734 * @type String
2735 * @static
2736 */
2737YAHOO.util.DDProxy.dragElId = "ygddfdiv";
2738
2739YAHOO.extend(YAHOO.util.DDProxy, YAHOO.util.DD, {
2740
2741 /**
2742 * By default we resize the drag frame to be the same size as the element
2743 * we want to drag (this is to get the frame effect). We can turn it off
2744 * if we want a different behavior.
2745 * @property resizeFrame
2746 * @type boolean
2747 */
2748 resizeFrame: true,
2749
2750 /**
2751 * By default the frame is positioned exactly where the drag element is, so
2752 * we use the cursor offset provided by YAHOO.util.DD. Another option that works only if
2753 * you do not have constraints on the obj is to have the drag frame centered
2754 * around the cursor. Set centerFrame to true for this effect.
2755 * @property centerFrame
2756 * @type boolean
2757 */
2758 centerFrame: false,
2759
2760 /**
2761 * Creates the proxy element if it does not yet exist
2762 * @method createFrame
2763 */
2764 createFrame: function() {
2765 var self = this;
2766 var body = document.body;
2767
2768 if (!body || !body.firstChild) {
2769 setTimeout( function() { self.createFrame(); }, 50 );
2770 return;
2771 }
2772
2773 var div = this.getDragEl();
2774
2775 if (!div) {
2776 div = document.createElement("div");
2777 div.id = this.dragElId;
2778 var s = div.style;
2779
2780 s.position = "absolute";
2781 s.visibility = "hidden";
2782 s.cursor = "move";
2783 s.border = "2px solid #aaa";
2784 s.zIndex = 999;
2785
2786 // appendChild can blow up IE if invoked prior to the window load event
2787 // while rendering a table. It is possible there are other scenarios
2788 // that would cause this to happen as well.
2789 body.insertBefore(div, body.firstChild);
2790 }
2791 },
2792
2793 /**
2794 * Initialization for the drag frame element. Must be called in the
2795 * constructor of all subclasses
2796 * @method initFrame
2797 */
2798 initFrame: function() {
2799 this.createFrame();
2800 },
2801
2802 applyConfig: function() {
2803 YAHOO.util.DDProxy.superclass.applyConfig.call(this);
2804
2805 this.resizeFrame = (this.config.resizeFrame !== false);
2806 this.centerFrame = (this.config.centerFrame);
2807 this.setDragElId(this.config.dragElId || YAHOO.util.DDProxy.dragElId);
2808 },
2809
2810 /**
2811 * Resizes the drag frame to the dimensions of the clicked object, positions
2812 * it over the object, and finally displays it
2813 * @method showFrame
2814 * @param {int} iPageX X click position
2815 * @param {int} iPageY Y click position
2816 * @private
2817 */
2818 showFrame: function(iPageX, iPageY) {
2819 var el = this.getEl();
2820 var dragEl = this.getDragEl();
2821 var s = dragEl.style;
2822
2823 this._resizeProxy();
2824
2825 if (this.centerFrame) {
2826 this.setDelta( Math.round(parseInt(s.width, 10)/2),
2827 Math.round(parseInt(s.height, 10)/2) );
2828 }
2829
2830 this.setDragElPos(iPageX, iPageY);
2831
2832 YAHOO.util.Dom.setStyle(dragEl, "visibility", "visible");
2833 },
2834
2835 /**
2836 * The proxy is automatically resized to the dimensions of the linked
2837 * element when a drag is initiated, unless resizeFrame is set to false
2838 * @method _resizeProxy
2839 * @private
2840 */
2841 _resizeProxy: function() {
2842 if (this.resizeFrame) {
2843 var DOM = YAHOO.util.Dom;
2844 var el = this.getEl();
2845 var dragEl = this.getDragEl();
2846
2847 var bt = parseInt( DOM.getStyle(dragEl, "borderTopWidth" ), 10);
2848 var br = parseInt( DOM.getStyle(dragEl, "borderRightWidth" ), 10);
2849 var bb = parseInt( DOM.getStyle(dragEl, "borderBottomWidth" ), 10);
2850 var bl = parseInt( DOM.getStyle(dragEl, "borderLeftWidth" ), 10);
2851
2852 if (isNaN(bt)) { bt = 0; }
2853 if (isNaN(br)) { br = 0; }
2854 if (isNaN(bb)) { bb = 0; }
2855 if (isNaN(bl)) { bl = 0; }
2856
2857
2858 var newWidth = Math.max(0, el.offsetWidth - br - bl);
2859 var newHeight = Math.max(0, el.offsetHeight - bt - bb);
2860
2861
2862 DOM.setStyle( dragEl, "width", newWidth + "px" );
2863 DOM.setStyle( dragEl, "height", newHeight + "px" );
2864 }
2865 },
2866
2867 // overrides YAHOO.util.DragDrop
2868 b4MouseDown: function(e) {
2869 var x = YAHOO.util.Event.getPageX(e);
2870 var y = YAHOO.util.Event.getPageY(e);
2871 this.autoOffset(x, y);
2872 this.setDragElPos(x, y);
2873 },
2874
2875 // overrides YAHOO.util.DragDrop
2876 b4StartDrag: function(x, y) {
2877 // show the drag frame
2878 this.showFrame(x, y);
2879 },
2880
2881 // overrides YAHOO.util.DragDrop
2882 b4EndDrag: function(e) {
2883 YAHOO.util.Dom.setStyle(this.getDragEl(), "visibility", "hidden");
2884 },
2885
2886 // overrides YAHOO.util.DragDrop
2887 // By default we try to move the element to the last location of the frame.
2888 // This is so that the default behavior mirrors that of YAHOO.util.DD.
2889 endDrag: function(e) {
2890 var DOM = YAHOO.util.Dom;
2891 var lel = this.getEl();
2892 var del = this.getDragEl();
2893
2894 // Show the drag frame briefly so we can get its position
2895 // del.style.visibility = "";
2896 DOM.setStyle(del, "visibility", "");
2897
2898 // Hide the linked element before the move to get around a Safari
2899 // rendering bug.
2900 //lel.style.visibility = "hidden";
2901 DOM.setStyle(lel, "visibility", "hidden");
2902 YAHOO.util.DDM.moveToEl(lel, del);
2903 //del.style.visibility = "hidden";
2904 DOM.setStyle(del, "visibility", "hidden");
2905 //lel.style.visibility = "";
2906 DOM.setStyle(lel, "visibility", "");
2907 },
2908
2909 toString: function() {
2910 return ("DDProxy " + this.id);
2911 }
2912
2913});
2914/**
2915 * A DragDrop implementation that does not move, but can be a drop
2916 * target. You would get the same result by simply omitting implementation
2917 * for the event callbacks, but this way we reduce the processing cost of the
2918 * event listener and the callbacks.
2919 * @class DDTarget
2920 * @extends YAHOO.util.DragDrop
2921 * @constructor
2922 * @param {String} id the id of the element that is a drop target
2923 * @param {String} sGroup the group of related DragDrop objects
2924 * @param {object} config an object containing configurable attributes
2925 * Valid properties for DDTarget in addition to those in
2926 * DragDrop:
2927 * none
2928 */
2929YAHOO.util.DDTarget = function(id, sGroup, config) {
2930 if (id) {
2931 this.initTarget(id, sGroup, config);
2932 }
2933};
2934
2935// YAHOO.util.DDTarget.prototype = new YAHOO.util.DragDrop();
2936YAHOO.extend(YAHOO.util.DDTarget, YAHOO.util.DragDrop, {
2937 toString: function() {
2938 return ("DDTarget " + this.id);
2939 }
2940});
diff --git a/frontend/beta/js/YUI/event.js b/frontend/beta/js/YUI/event.js
new file mode 100644
index 0000000..7bfac3b
--- a/dev/null
+++ b/frontend/beta/js/YUI/event.js
@@ -0,0 +1,1738 @@
1/*
2Copyright (c) 2006, Yahoo! Inc. All rights reserved.
3Code licensed under the BSD License:
4http://developer.yahoo.net/yui/license.txt
5version: 0.12.0
6*/
7
8/**
9 * The CustomEvent class lets you define events for your application
10 * that can be subscribed to by one or more independent component.
11 *
12 * @param {String} type The type of event, which is passed to the callback
13 * when the event fires
14 * @param {Object} oScope The context the event will fire from. "this" will
15 * refer to this object in the callback. Default value:
16 * the window object. The listener can override this.
17 * @param {boolean} silent pass true to prevent the event from writing to
18 * the log system
19 * @namespace YAHOO.util
20 * @class CustomEvent
21 * @constructor
22 */
23YAHOO.util.CustomEvent = function(type, oScope, silent, signature) {
24
25 /**
26 * The type of event, returned to subscribers when the event fires
27 * @property type
28 * @type string
29 */
30 this.type = type;
31
32 /**
33 * The scope the the event will fire from by default. Defaults to the window
34 * obj
35 * @property scope
36 * @type object
37 */
38 this.scope = oScope || window;
39
40 /**
41 * By default all custom events are logged in the debug build, set silent
42 * to true to disable logging for this event.
43 * @property silent
44 * @type boolean
45 */
46 this.silent = silent;
47
48 /**
49 * Custom events support two styles of arguments provided to the event
50 * subscribers.
51 * <ul>
52 * <li>YAHOO.util.CustomEvent.LIST:
53 * <ul>
54 * <li>param1: event name</li>
55 * <li>param2: array of arguments sent to fire</li>
56 * <li>param3: <optional> a custom object supplied by the subscriber</li>
57 * </ul>
58 * </li>
59 * <li>YAHOO.util.CustomEvent.FLAT
60 * <ul>
61 * <li>param1: the first argument passed to fire. If you need to
62 * pass multiple parameters, use and array or object literal</li>
63 * <li>param2: <optional> a custom object supplied by the subscriber</li>
64 * </ul>
65 * </li>
66 * </ul>
67 * @property signature
68 * @type int
69 */
70 this.signature = signature || YAHOO.util.CustomEvent.LIST;
71
72 /**
73 * The subscribers to this event
74 * @property subscribers
75 * @type Subscriber[]
76 */
77 this.subscribers = [];
78
79 if (!this.silent) {
80 }
81
82 var onsubscribeType = "_YUICEOnSubscribe";
83
84 // Only add subscribe events for events that are not generated by
85 // CustomEvent
86 if (type !== onsubscribeType) {
87
88 /**
89 * Custom events provide a custom event that fires whenever there is
90 * a new subscriber to the event. This provides an opportunity to
91 * handle the case where there is a non-repeating event that has
92 * already fired has a new subscriber.
93 *
94 * @event subscribeEvent
95 * @type YAHOO.util.CustomEvent
96 * @param {Function} fn The function to execute
97 * @param {Object} obj An object to be passed along when the event
98 * fires
99 * @param {boolean|Object} override If true, the obj passed in becomes
100 * the execution scope of the listener.
101 * if an object, that object becomes the
102 * the execution scope.
103 */
104 this.subscribeEvent =
105 new YAHOO.util.CustomEvent(onsubscribeType, this, true);
106
107 }
108};
109
110/**
111 * Subscriber listener sigature constant. The LIST type returns three
112 * parameters: the event type, the array of args passed to fire, and
113 * the optional custom object
114 * @property YAHOO.util.CustomEvent.LIST
115 * @static
116 * @type int
117 */
118YAHOO.util.CustomEvent.LIST = 0;
119
120/**
121 * Subscriber listener sigature constant. The FLAT type returns two
122 * parameters: the first argument passed to fire and the optional
123 * custom object
124 * @property YAHOO.util.CustomEvent.FLAT
125 * @static
126 * @type int
127 */
128YAHOO.util.CustomEvent.FLAT = 1;
129
130YAHOO.util.CustomEvent.prototype = {
131
132 /**
133 * Subscribes the caller to this event
134 * @method subscribe
135 * @param {Function} fn The function to execute
136 * @param {Object} obj An object to be passed along when the event
137 * fires
138 * @param {boolean|Object} override If true, the obj passed in becomes
139 * the execution scope of the listener.
140 * if an object, that object becomes the
141 * the execution scope.
142 */
143 subscribe: function(fn, obj, override) {
144 if (this.subscribeEvent) {
145 this.subscribeEvent.fire(fn, obj, override);
146 }
147
148 this.subscribers.push( new YAHOO.util.Subscriber(fn, obj, override) );
149 },
150
151 /**
152 * Unsubscribes the caller from this event
153 * @method unsubscribe
154 * @param {Function} fn The function to execute
155 * @param {Object} obj The custom object passed to subscribe (optional)
156 * @return {boolean} True if the subscriber was found and detached.
157 */
158 unsubscribe: function(fn, obj) {
159 var found = false;
160 for (var i=0, len=this.subscribers.length; i<len; ++i) {
161 var s = this.subscribers[i];
162 if (s && s.contains(fn, obj)) {
163 this._delete(i);
164 found = true;
165 }
166 }
167
168 return found;
169 },
170
171 /**
172 * Notifies the subscribers. The callback functions will be executed
173 * from the scope specified when the event was created, and with the
174 * following parameters:
175 * <ul>
176 * <li>The type of event</li>
177 * <li>All of the arguments fire() was executed with as an array</li>
178 * <li>The custom object (if any) that was passed into the subscribe()
179 * method</li>
180 * </ul>
181 * @method fire
182 * @param {Object*} arguments an arbitrary set of parameters to pass to
183 * the handler.
184 */
185 fire: function() {
186 var len=this.subscribers.length;
187 if (!len && this.silent) {
188 return true;
189 }
190
191 var args=[], ret=true, i;
192
193 for (i=0; i<arguments.length; ++i) {
194 args.push(arguments[i]);
195 }
196
197 var argslength = args.length;
198
199 if (!this.silent) {
200 }
201
202 for (i=0; i<len; ++i) {
203 var s = this.subscribers[i];
204 if (s) {
205 if (!this.silent) {
206 }
207
208 var scope = s.getScope(this.scope);
209
210 if (this.signature == YAHOO.util.CustomEvent.FLAT) {
211 var param = null;
212 if (args.length > 0) {
213 param = args[0];
214 }
215 ret = s.fn.call(scope, param, s.obj);
216 } else {
217 ret = s.fn.call(scope, this.type, args, s.obj);
218 }
219 if (false === ret) {
220 if (!this.silent) {
221 }
222
223 //break;
224 return false;
225 }
226 }
227 }
228
229 return true;
230 },
231
232 /**
233 * Removes all listeners
234 * @method unsubscribeAll
235 */
236 unsubscribeAll: function() {
237 for (var i=0, len=this.subscribers.length; i<len; ++i) {
238 this._delete(len - 1 - i);
239 }
240 },
241
242 /**
243 * @method _delete
244 * @private
245 */
246 _delete: function(index) {
247 var s = this.subscribers[index];
248 if (s) {
249 delete s.fn;
250 delete s.obj;
251 }
252
253 // delete this.subscribers[index];
254 this.subscribers.splice(index, 1);
255 },
256
257 /**
258 * @method toString
259 */
260 toString: function() {
261 return "CustomEvent: " + "'" + this.type + "', " +
262 "scope: " + this.scope;
263
264 }
265};
266
267/////////////////////////////////////////////////////////////////////
268
269/**
270 * Stores the subscriber information to be used when the event fires.
271 * @param {Function} fn The function to execute
272 * @param {Object} obj An object to be passed along when the event fires
273 * @param {boolean} override If true, the obj passed in becomes the execution
274 * scope of the listener
275 * @class Subscriber
276 * @constructor
277 */
278YAHOO.util.Subscriber = function(fn, obj, override) {
279
280 /**
281 * The callback that will be execute when the event fires
282 * @property fn
283 * @type function
284 */
285 this.fn = fn;
286
287 /**
288 * An optional custom object that will passed to the callback when
289 * the event fires
290 * @property obj
291 * @type object
292 */
293 this.obj = obj || null;
294
295 /**
296 * The default execution scope for the event listener is defined when the
297 * event is created (usually the object which contains the event).
298 * By setting override to true, the execution scope becomes the custom
299 * object passed in by the subscriber. If override is an object, that
300 * object becomes the scope.
301 * @property override
302 * @type boolean|object
303 */
304 this.override = override;
305
306};
307
308/**
309 * Returns the execution scope for this listener. If override was set to true
310 * the custom obj will be the scope. If override is an object, that is the
311 * scope, otherwise the default scope will be used.
312 * @method getScope
313 * @param {Object} defaultScope the scope to use if this listener does not
314 * override it.
315 */
316YAHOO.util.Subscriber.prototype.getScope = function(defaultScope) {
317 if (this.override) {
318 if (this.override === true) {
319 return this.obj;
320 } else {
321 return this.override;
322 }
323 }
324 return defaultScope;
325};
326
327/**
328 * Returns true if the fn and obj match this objects properties.
329 * Used by the unsubscribe method to match the right subscriber.
330 *
331 * @method contains
332 * @param {Function} fn the function to execute
333 * @param {Object} obj an object to be passed along when the event fires
334 * @return {boolean} true if the supplied arguments match this
335 * subscriber's signature.
336 */
337YAHOO.util.Subscriber.prototype.contains = function(fn, obj) {
338 if (obj) {
339 return (this.fn == fn && this.obj == obj);
340 } else {
341 return (this.fn == fn);
342 }
343};
344
345/**
346 * @method toString
347 */
348YAHOO.util.Subscriber.prototype.toString = function() {
349 return "Subscriber { obj: " + (this.obj || "") +
350 ", override: " + (this.override || "no") + " }";
351};
352
353/**
354 * The Event Utility provides utilities for managing DOM Events and tools
355 * for building event systems
356 *
357 * @module event
358 * @title Event Utility
359 * @namespace YAHOO.util
360 * @requires yahoo
361 */
362
363// The first instance of Event will win if it is loaded more than once.
364if (!YAHOO.util.Event) {
365
366/**
367 * The event utility provides functions to add and remove event listeners,
368 * event cleansing. It also tries to automatically remove listeners it
369 * registers during the unload event.
370 *
371 * @class Event
372 * @static
373 */
374 YAHOO.util.Event = function() {
375
376 /**
377 * True after the onload event has fired
378 * @property loadComplete
379 * @type boolean
380 * @static
381 * @private
382 */
383 var loadComplete = false;
384
385 /**
386 * Cache of wrapped listeners
387 * @property listeners
388 * @type array
389 * @static
390 * @private
391 */
392 var listeners = [];
393
394 /**
395 * User-defined unload function that will be fired before all events
396 * are detached
397 * @property unloadListeners
398 * @type array
399 * @static
400 * @private
401 */
402 var unloadListeners = [];
403
404 /**
405 * Cache of DOM0 event handlers to work around issues with DOM2 events
406 * in Safari
407 * @property legacyEvents
408 * @static
409 * @private
410 */
411 var legacyEvents = [];
412
413 /**
414 * Listener stack for DOM0 events
415 * @property legacyHandlers
416 * @static
417 * @private
418 */
419 var legacyHandlers = [];
420
421 /**
422 * The number of times to poll after window.onload. This number is
423 * increased if additional late-bound handlers are requested after
424 * the page load.
425 * @property retryCount
426 * @static
427 * @private
428 */
429 var retryCount = 0;
430
431 /**
432 * onAvailable listeners
433 * @property onAvailStack
434 * @static
435 * @private
436 */
437 var onAvailStack = [];
438
439 /**
440 * Lookup table for legacy events
441 * @property legacyMap
442 * @static
443 * @private
444 */
445 var legacyMap = [];
446
447 /**
448 * Counter for auto id generation
449 * @property counter
450 * @static
451 * @private
452 */
453 var counter = 0;
454
455 return { // PREPROCESS
456
457 /**
458 * The number of times we should look for elements that are not
459 * in the DOM at the time the event is requested after the document
460 * has been loaded. The default is 200@amp;50 ms, so it will poll
461 * for 10 seconds or until all outstanding handlers are bound
462 * (whichever comes first).
463 * @property POLL_RETRYS
464 * @type int
465 * @static
466 * @final
467 */
468 POLL_RETRYS: 200,
469
470 /**
471 * The poll interval in milliseconds
472 * @property POLL_INTERVAL
473 * @type int
474 * @static
475 * @final
476 */
477 POLL_INTERVAL: 20,
478
479 /**
480 * Element to bind, int constant
481 * @property EL
482 * @type int
483 * @static
484 * @final
485 */
486 EL: 0,
487
488 /**
489 * Type of event, int constant
490 * @property TYPE
491 * @type int
492 * @static
493 * @final
494 */
495 TYPE: 1,
496
497 /**
498 * Function to execute, int constant
499 * @property FN
500 * @type int
501 * @static
502 * @final
503 */
504 FN: 2,
505
506 /**
507 * Function wrapped for scope correction and cleanup, int constant
508 * @property WFN
509 * @type int
510 * @static
511 * @final
512 */
513 WFN: 3,
514
515 /**
516 * Object passed in by the user that will be returned as a
517 * parameter to the callback, int constant
518 * @property OBJ
519 * @type int
520 * @static
521 * @final
522 */
523 OBJ: 3,
524
525 /**
526 * Adjusted scope, either the element we are registering the event
527 * on or the custom object passed in by the listener, int constant
528 * @property ADJ_SCOPE
529 * @type int
530 * @static
531 * @final
532 */
533 ADJ_SCOPE: 4,
534
535 /**
536 * Safari detection is necessary to work around the preventDefault
537 * bug that makes it so you can't cancel a href click from the
538 * handler. There is not a capabilities check we can use here.
539 * @property isSafari
540 * @private
541 * @static
542 */
543 isSafari: (/Safari|Konqueror|KHTML/gi).test(navigator.userAgent),
544
545 /**
546 * IE detection needed to properly calculate pageX and pageY.
547 * capabilities checking didn't seem to work because another
548 * browser that does not provide the properties have the values
549 * calculated in a different manner than IE.
550 * @property isIE
551 * @private
552 * @static
553 */
554 isIE: (!this.isSafari && !navigator.userAgent.match(/opera/gi) &&
555 navigator.userAgent.match(/msie/gi)),
556
557 /**
558 * poll handle
559 * @property _interval
560 * @private
561 */
562 _interval: null,
563
564 /**
565 * @method startInterval
566 * @static
567 * @private
568 */
569 startInterval: function() {
570 if (!this._interval) {
571 var self = this;
572 var callback = function() { self._tryPreloadAttach(); };
573 this._interval = setInterval(callback, this.POLL_INTERVAL);
574 // this.timeout = setTimeout(callback, i);
575 }
576 },
577
578 /**
579 * Executes the supplied callback when the item with the supplied
580 * id is found. This is meant to be used to execute behavior as
581 * soon as possible as the page loads. If you use this after the
582 * initial page load it will poll for a fixed time for the element.
583 * The number of times it will poll and the frequency are
584 * configurable. By default it will poll for 10 seconds.
585 *
586 * @method onAvailable
587 *
588 * @param {string} p_id the id of the element to look for.
589 * @param {function} p_fn what to execute when the element is found.
590 * @param {object} p_obj an optional object to be passed back as
591 * a parameter to p_fn.
592 * @param {boolean} p_override If set to true, p_fn will execute
593 * in the scope of p_obj
594 *
595 * @static
596 */
597 onAvailable: function(p_id, p_fn, p_obj, p_override) {
598 onAvailStack.push( { id: p_id,
599 fn: p_fn,
600 obj: p_obj,
601 override: p_override,
602 checkReady: false } );
603
604 retryCount = this.POLL_RETRYS;
605 this.startInterval();
606 },
607
608 /**
609 * Works the same way as onAvailable, but additionally checks the
610 * state of sibling elements to determine if the content of the
611 * available element is safe to modify.
612 *
613 * @method onContentReady
614 *
615 * @param {string} p_id the id of the element to look for.
616 * @param {function} p_fn what to execute when the element is ready.
617 * @param {object} p_obj an optional object to be passed back as
618 * a parameter to p_fn.
619 * @param {boolean} p_override If set to true, p_fn will execute
620 * in the scope of p_obj
621 *
622 * @static
623 */
624 onContentReady: function(p_id, p_fn, p_obj, p_override) {
625 onAvailStack.push( { id: p_id,
626 fn: p_fn,
627 obj: p_obj,
628 override: p_override,
629 checkReady: true } );
630
631 retryCount = this.POLL_RETRYS;
632 this.startInterval();
633 },
634
635 /**
636 * Appends an event handler
637 *
638 * @method addListener
639 *
640 * @param {Object} el The html element to assign the
641 * event to
642 * @param {String} sType The type of event to append
643 * @param {Function} fn The method the event invokes
644 * @param {Object} obj An arbitrary object that will be
645 * passed as a parameter to the handler
646 * @param {boolean} override If true, the obj passed in becomes
647 * the execution scope of the listener
648 * @return {boolean} True if the action was successful or defered,
649 * false if one or more of the elements
650 * could not have the event bound to it.
651 * @static
652 */
653 addListener: function(el, sType, fn, obj, override) {
654
655 if (!fn || !fn.call) {
656 return false;
657 }
658
659 // The el argument can be an array of elements or element ids.
660 if ( this._isValidCollection(el)) {
661 var ok = true;
662 for (var i=0,len=el.length; i<len; ++i) {
663 ok = this.on(el[i],
664 sType,
665 fn,
666 obj,
667 override) && ok;
668 }
669 return ok;
670
671 } else if (typeof el == "string") {
672 var oEl = this.getEl(el);
673 // If the el argument is a string, we assume it is
674 // actually the id of the element. If the page is loaded
675 // we convert el to the actual element, otherwise we
676 // defer attaching the event until onload event fires
677
678 // check to see if we need to delay hooking up the event
679 // until after the page loads.
680 if (oEl) {
681 el = oEl;
682 } else {
683 // defer adding the event until the element is available
684 this.onAvailable(el, function() {
685 YAHOO.util.Event.on(el, sType, fn, obj, override);
686 });
687
688 return true;
689 }
690 }
691
692 // Element should be an html element or an array if we get
693 // here.
694 if (!el) {
695 return false;
696 }
697
698 // we need to make sure we fire registered unload events
699 // prior to automatically unhooking them. So we hang on to
700 // these instead of attaching them to the window and fire the
701 // handles explicitly during our one unload event.
702 if ("unload" == sType && obj !== this) {
703 unloadListeners[unloadListeners.length] =
704 [el, sType, fn, obj, override];
705 return true;
706 }
707
708 // if the user chooses to override the scope, we use the custom
709 // object passed in, otherwise the executing scope will be the
710 // HTML element that the event is registered on
711 var scope = el;
712 if (override) {
713 if (override === true) {
714 scope = obj;
715 } else {
716 scope = override;
717 }
718 }
719
720 // wrap the function so we can return the obj object when
721 // the event fires;
722 var wrappedFn = function(e) {
723 return fn.call(scope, YAHOO.util.Event.getEvent(e),
724 obj);
725 };
726
727 var li = [el, sType, fn, wrappedFn, scope];
728 var index = listeners.length;
729 // cache the listener so we can try to automatically unload
730 listeners[index] = li;
731
732 if (this.useLegacyEvent(el, sType)) {
733 var legacyIndex = this.getLegacyIndex(el, sType);
734
735 // Add a new dom0 wrapper if one is not detected for this
736 // element
737 if ( legacyIndex == -1 ||
738 el != legacyEvents[legacyIndex][0] ) {
739
740 legacyIndex = legacyEvents.length;
741 legacyMap[el.id + sType] = legacyIndex;
742
743 // cache the signature for the DOM0 event, and
744 // include the existing handler for the event, if any
745 legacyEvents[legacyIndex] =
746 [el, sType, el["on" + sType]];
747 legacyHandlers[legacyIndex] = [];
748
749 el["on" + sType] =
750 function(e) {
751 YAHOO.util.Event.fireLegacyEvent(
752 YAHOO.util.Event.getEvent(e), legacyIndex);
753 };
754 }
755
756 // add a reference to the wrapped listener to our custom
757 // stack of events
758 //legacyHandlers[legacyIndex].push(index);
759 legacyHandlers[legacyIndex].push(li);
760
761 } else {
762 this._simpleAdd(el, sType, wrappedFn, false);
763 }
764
765 return true;
766
767 },
768
769 /**
770 * When using legacy events, the handler is routed to this object
771 * so we can fire our custom listener stack.
772 * @method fireLegacyEvent
773 * @static
774 * @private
775 */
776 fireLegacyEvent: function(e, legacyIndex) {
777 var ok = true;
778
779 var le = legacyHandlers[legacyIndex];
780 for (var i=0,len=le.length; i<len; ++i) {
781 var li = le[i];
782 if ( li && li[this.WFN] ) {
783 var scope = li[this.ADJ_SCOPE];
784 var ret = li[this.WFN].call(scope, e);
785 ok = (ok && ret);
786 }
787 }
788
789 return ok;
790 },
791
792 /**
793 * Returns the legacy event index that matches the supplied
794 * signature
795 * @method getLegacyIndex
796 * @static
797 * @private
798 */
799 getLegacyIndex: function(el, sType) {
800 var key = this.generateId(el) + sType;
801 if (typeof legacyMap[key] == "undefined") {
802 return -1;
803 } else {
804 return legacyMap[key];
805 }
806 },
807
808 /**
809 * Logic that determines when we should automatically use legacy
810 * events instead of DOM2 events.
811 * @method useLegacyEvent
812 * @static
813 * @private
814 */
815 useLegacyEvent: function(el, sType) {
816 if (!el.addEventListener && !el.attachEvent) {
817 return true;
818 } else if (this.isSafari) {
819 if ("click" == sType || "dblclick" == sType) {
820 return true;
821 }
822 }
823 return false;
824 },
825
826 /**
827 * Removes an event handler
828 *
829 * @method removeListener
830 *
831 * @param {Object} el the html element or the id of the element to
832 * assign the event to.
833 * @param {String} sType the type of event to remove.
834 * @param {Function} fn the method the event invokes. If fn is
835 * undefined, then all event handlers for the type of event are
836 * removed.
837 * @return {boolean} true if the unbind was successful, false
838 * otherwise.
839 * @static
840 */
841 removeListener: function(el, sType, fn) {
842 var i, len;
843
844 // The el argument can be a string
845 if (typeof el == "string") {
846 el = this.getEl(el);
847 // The el argument can be an array of elements or element ids.
848 } else if ( this._isValidCollection(el)) {
849 var ok = true;
850 for (i=0,len=el.length; i<len; ++i) {
851 ok = ( this.removeListener(el[i], sType, fn) && ok );
852 }
853 return ok;
854 }
855
856 if (!fn || !fn.call) {
857 //return false;
858 return this.purgeElement(el, false, sType);
859 }
860
861 if ("unload" == sType) {
862
863 for (i=0, len=unloadListeners.length; i<len; i++) {
864 var li = unloadListeners[i];
865 if (li &&
866 li[0] == el &&
867 li[1] == sType &&
868 li[2] == fn) {
869 unloadListeners.splice(i, 1);
870 return true;
871 }
872 }
873
874 return false;
875 }
876
877 var cacheItem = null;
878
879 // The index is a hidden parameter; needed to remove it from
880 // the method signature because it was tempting users to
881 // try and take advantage of it, which is not possible.
882 var index = arguments[3];
883
884 if ("undefined" == typeof index) {
885 index = this._getCacheIndex(el, sType, fn);
886 }
887
888 if (index >= 0) {
889 cacheItem = listeners[index];
890 }
891
892 if (!el || !cacheItem) {
893 return false;
894 }
895
896 if (this.useLegacyEvent(el, sType)) {
897 var legacyIndex = this.getLegacyIndex(el, sType);
898 var llist = legacyHandlers[legacyIndex];
899 if (llist) {
900 for (i=0, len=llist.length; i<len; ++i) {
901 li = llist[i];
902 if (li &&
903 li[this.EL] == el &&
904 li[this.TYPE] == sType &&
905 li[this.FN] == fn) {
906 llist.splice(i, 1);
907 break;
908 }
909 }
910 }
911
912 } else {
913 this._simpleRemove(el, sType, cacheItem[this.WFN], false);
914 }
915
916 // removed the wrapped handler
917 delete listeners[index][this.WFN];
918 delete listeners[index][this.FN];
919 listeners.splice(index, 1);
920
921 return true;
922
923 },
924
925 /**
926 * Returns the event's target element
927 * @method getTarget
928 * @param {Event} ev the event
929 * @param {boolean} resolveTextNode when set to true the target's
930 * parent will be returned if the target is a
931 * text node. @deprecated, the text node is
932 * now resolved automatically
933 * @return {HTMLElement} the event's target
934 * @static
935 */
936 getTarget: function(ev, resolveTextNode) {
937 var t = ev.target || ev.srcElement;
938 return this.resolveTextNode(t);
939 },
940
941 /**
942 * In some cases, some browsers will return a text node inside
943 * the actual element that was targeted. This normalizes the
944 * return value for getTarget and getRelatedTarget.
945 * @method resolveTextNode
946 * @param {HTMLElement} node node to resolve
947 * @return {HTMLElement} the normized node
948 * @static
949 */
950 resolveTextNode: function(node) {
951 // if (node && node.nodeName &&
952 // "#TEXT" == node.nodeName.toUpperCase()) {
953 if (node && 3 == node.nodeType) {
954 return node.parentNode;
955 } else {
956 return node;
957 }
958 },
959
960 /**
961 * Returns the event's pageX
962 * @method getPageX
963 * @param {Event} ev the event
964 * @return {int} the event's pageX
965 * @static
966 */
967 getPageX: function(ev) {
968 var x = ev.pageX;
969 if (!x && 0 !== x) {
970 x = ev.clientX || 0;
971
972 if ( this.isIE ) {
973 x += this._getScrollLeft();
974 }
975 }
976
977 return x;
978 },
979
980 /**
981 * Returns the event's pageY
982 * @method getPageY
983 * @param {Event} ev the event
984 * @return {int} the event's pageY
985 * @static
986 */
987 getPageY: function(ev) {
988 var y = ev.pageY;
989 if (!y && 0 !== y) {
990 y = ev.clientY || 0;
991
992 if ( this.isIE ) {
993 y += this._getScrollTop();
994 }
995 }
996
997 return y;
998 },
999
1000 /**
1001 * Returns the pageX and pageY properties as an indexed array.
1002 * @method getXY
1003 * @type int[]
1004 * @static
1005 */
1006 getXY: function(ev) {
1007 return [this.getPageX(ev), this.getPageY(ev)];
1008 },
1009
1010 /**
1011 * Returns the event's related target
1012 * @method getRelatedTarget
1013 * @param {Event} ev the event
1014 * @return {HTMLElement} the event's relatedTarget
1015 * @static
1016 */
1017 getRelatedTarget: function(ev) {
1018 var t = ev.relatedTarget;
1019 if (!t) {
1020 if (ev.type == "mouseout") {
1021 t = ev.toElement;
1022 } else if (ev.type == "mouseover") {
1023 t = ev.fromElement;
1024 }
1025 }
1026
1027 return this.resolveTextNode(t);
1028 },
1029
1030 /**
1031 * Returns the time of the event. If the time is not included, the
1032 * event is modified using the current time.
1033 * @method getTime
1034 * @param {Event} ev the event
1035 * @return {Date} the time of the event
1036 * @static
1037 */
1038 getTime: function(ev) {
1039 if (!ev.time) {
1040 var t = new Date().getTime();
1041 try {
1042 ev.time = t;
1043 } catch(e) {
1044 return t;
1045 }
1046 }
1047
1048 return ev.time;
1049 },
1050
1051 /**
1052 * Convenience method for stopPropagation + preventDefault
1053 * @method stopEvent
1054 * @param {Event} ev the event
1055 * @static
1056 */
1057 stopEvent: function(ev) {
1058 this.stopPropagation(ev);
1059 this.preventDefault(ev);
1060 },
1061
1062 /**
1063 * Stops event propagation
1064 * @method stopPropagation
1065 * @param {Event} ev the event
1066 * @static
1067 */
1068 stopPropagation: function(ev) {
1069 if (ev.stopPropagation) {
1070 ev.stopPropagation();
1071 } else {
1072 ev.cancelBubble = true;
1073 }
1074 },
1075
1076 /**
1077 * Prevents the default behavior of the event
1078 * @method preventDefault
1079 * @param {Event} ev the event
1080 * @static
1081 */
1082 preventDefault: function(ev) {
1083 if (ev.preventDefault) {
1084 ev.preventDefault();
1085 } else {
1086 ev.returnValue = false;
1087 }
1088 },
1089
1090 /**
1091 * Finds the event in the window object, the caller's arguments, or
1092 * in the arguments of another method in the callstack. This is
1093 * executed automatically for events registered through the event
1094 * manager, so the implementer should not normally need to execute
1095 * this function at all.
1096 * @method getEvent
1097 * @param {Event} e the event parameter from the handler
1098 * @return {Event} the event
1099 * @static
1100 */
1101 getEvent: function(e) {
1102 var ev = e || window.event;
1103
1104 if (!ev) {
1105 var c = this.getEvent.caller;
1106 while (c) {
1107 ev = c.arguments[0];
1108 if (ev && Event == ev.constructor) {
1109 break;
1110 }
1111 c = c.caller;
1112 }
1113 }
1114
1115 return ev;
1116 },
1117
1118 /**
1119 * Returns the charcode for an event
1120 * @method getCharCode
1121 * @param {Event} ev the event
1122 * @return {int} the event's charCode
1123 * @static
1124 */
1125 getCharCode: function(ev) {
1126 return ev.charCode || ev.keyCode || 0;
1127 },
1128
1129 /**
1130 * Locating the saved event handler data by function ref
1131 *
1132 * @method _getCacheIndex
1133 * @static
1134 * @private
1135 */
1136 _getCacheIndex: function(el, sType, fn) {
1137 for (var i=0,len=listeners.length; i<len; ++i) {
1138 var li = listeners[i];
1139 if ( li &&
1140 li[this.FN] == fn &&
1141 li[this.EL] == el &&
1142 li[this.TYPE] == sType ) {
1143 return i;
1144 }
1145 }
1146
1147 return -1;
1148 },
1149
1150 /**
1151 * Generates an unique ID for the element if it does not already
1152 * have one.
1153 * @method generateId
1154 * @param el the element to create the id for
1155 * @return {string} the resulting id of the element
1156 * @static
1157 */
1158 generateId: function(el) {
1159 var id = el.id;
1160
1161 if (!id) {
1162 id = "yuievtautoid-" + counter;
1163 ++counter;
1164 el.id = id;
1165 }
1166
1167 return id;
1168 },
1169
1170 /**
1171 * We want to be able to use getElementsByTagName as a collection
1172 * to attach a group of events to. Unfortunately, different
1173 * browsers return different types of collections. This function
1174 * tests to determine if the object is array-like. It will also
1175 * fail if the object is an array, but is empty.
1176 * @method _isValidCollection
1177 * @param o the object to test
1178 * @return {boolean} true if the object is array-like and populated
1179 * @static
1180 * @private
1181 */
1182 _isValidCollection: function(o) {
1183 // this.logger.debug(o.constructor.toString())
1184 // this.logger.debug(typeof o)
1185
1186 return ( o && // o is something
1187 o.length && // o is indexed
1188 typeof o != "string" && // o is not a string
1189 !o.tagName && // o is not an HTML element
1190 !o.alert && // o is not a window
1191 typeof o[0] != "undefined" );
1192
1193 },
1194
1195 /**
1196 * @private
1197 * @property elCache
1198 * DOM element cache
1199 * @static
1200 */
1201 elCache: {},
1202
1203 /**
1204 * We cache elements bound by id because when the unload event
1205 * fires, we can no longer use document.getElementById
1206 * @method getEl
1207 * @static
1208 * @private
1209 */
1210 getEl: function(id) {
1211 return document.getElementById(id);
1212 },
1213
1214 /**
1215 * Clears the element cache
1216 * @deprecated Elements are not cached any longer
1217 * @method clearCache
1218 * @static
1219 * @private
1220 */
1221 clearCache: function() { },
1222
1223 /**
1224 * hook up any deferred listeners
1225 * @method _load
1226 * @static
1227 * @private
1228 */
1229 _load: function(e) {
1230 loadComplete = true;
1231 var EU = YAHOO.util.Event;
1232 // Remove the listener to assist with the IE memory issue, but not
1233 // for other browsers because FF 1.0x does not like it.
1234 if (this.isIE) {
1235 EU._simpleRemove(window, "load", EU._load);
1236 }
1237 },
1238
1239 /**
1240 * Polling function that runs before the onload event fires,
1241 * attempting to attach to DOM Nodes as soon as they are
1242 * available
1243 * @method _tryPreloadAttach
1244 * @static
1245 * @private
1246 */
1247 _tryPreloadAttach: function() {
1248
1249 if (this.locked) {
1250 return false;
1251 }
1252
1253 this.locked = true;
1254
1255 // keep trying until after the page is loaded. We need to
1256 // check the page load state prior to trying to bind the
1257 // elements so that we can be certain all elements have been
1258 // tested appropriately
1259 var tryAgain = !loadComplete;
1260 if (!tryAgain) {
1261 tryAgain = (retryCount > 0);
1262 }
1263
1264 // onAvailable
1265 var notAvail = [];
1266 for (var i=0,len=onAvailStack.length; i<len ; ++i) {
1267 var item = onAvailStack[i];
1268 if (item) {
1269 var el = this.getEl(item.id);
1270
1271 if (el) {
1272 // The element is available, but not necessarily ready
1273
1274 if ( !item.checkReady ||
1275 loadComplete ||
1276 el.nextSibling ||
1277 (document && document.body) ) {
1278
1279 var scope = el;
1280 if (item.override) {
1281 if (item.override === true) {
1282 scope = item.obj;
1283 } else {
1284 scope = item.override;
1285 }
1286 }
1287 item.fn.call(scope, item.obj);
1288 delete onAvailStack[i];
1289 }
1290 } else {
1291 notAvail.push(item);
1292 }
1293 }
1294 }
1295
1296 retryCount = (notAvail.length === 0) ? 0 : retryCount - 1;
1297
1298 if (tryAgain) {
1299 this.startInterval();
1300 } else {
1301 clearInterval(this._interval);
1302 this._interval = null;
1303 }
1304
1305 this.locked = false;
1306
1307 return true;
1308
1309 },
1310
1311 /**
1312 * Removes all listeners attached to the given element via addListener.
1313 * Optionally, the node's children can also be purged.
1314 * Optionally, you can specify a specific type of event to remove.
1315 * @method purgeElement
1316 * @param {HTMLElement} el the element to purge
1317 * @param {boolean} recurse recursively purge this element's children
1318 * as well. Use with caution.
1319 * @param {string} sType optional type of listener to purge. If
1320 * left out, all listeners will be removed
1321 * @static
1322 */
1323 purgeElement: function(el, recurse, sType) {
1324 var elListeners = this.getListeners(el, sType);
1325 if (elListeners) {
1326 for (var i=0,len=elListeners.length; i<len ; ++i) {
1327 var l = elListeners[i];
1328 // can't use the index on the changing collection
1329 //this.removeListener(el, l.type, l.fn, l.index);
1330 this.removeListener(el, l.type, l.fn);
1331 }
1332 }
1333
1334 if (recurse && el && el.childNodes) {
1335 for (i=0,len=el.childNodes.length; i<len ; ++i) {
1336 this.purgeElement(el.childNodes[i], recurse, sType);
1337 }
1338 }
1339 },
1340
1341 /**
1342 * Returns all listeners attached to the given element via addListener.
1343 * Optionally, you can specify a specific type of event to return.
1344 * @method getListeners
1345 * @param el {HTMLElement} the element to inspect
1346 * @param sType {string} optional type of listener to return. If
1347 * left out, all listeners will be returned
1348 * @return {Object} the listener. Contains the following fields:
1349 * &nbsp;&nbsp;type: (string) the type of event
1350 * &nbsp;&nbsp;fn: (function) the callback supplied to addListener
1351 * &nbsp;&nbsp;obj: (object) the custom object supplied to addListener
1352 * &nbsp;&nbsp;adjust: (boolean) whether or not to adjust the default scope
1353 * &nbsp;&nbsp;index: (int) its position in the Event util listener cache
1354 * @static
1355 */
1356 getListeners: function(el, sType) {
1357 var elListeners = [];
1358 if (listeners && listeners.length > 0) {
1359 for (var i=0,len=listeners.length; i<len ; ++i) {
1360 var l = listeners[i];
1361 if ( l && l[this.EL] === el &&
1362 (!sType || sType === l[this.TYPE]) ) {
1363 elListeners.push({
1364 type: l[this.TYPE],
1365 fn: l[this.FN],
1366 obj: l[this.OBJ],
1367 adjust: l[this.ADJ_SCOPE],
1368 index: i
1369 });
1370 }
1371 }
1372 }
1373
1374 return (elListeners.length) ? elListeners : null;
1375 },
1376
1377 /**
1378 * Removes all listeners registered by pe.event. Called
1379 * automatically during the unload event.
1380 * @method _unload
1381 * @static
1382 * @private
1383 */
1384 _unload: function(e) {
1385
1386 var EU = YAHOO.util.Event, i, j, l, len, index;
1387
1388 for (i=0,len=unloadListeners.length; i<len; ++i) {
1389 l = unloadListeners[i];
1390 if (l) {
1391 var scope = window;
1392 if (l[EU.ADJ_SCOPE]) {
1393 if (l[EU.ADJ_SCOPE] === true) {
1394 scope = l[EU.OBJ];
1395 } else {
1396 scope = l[EU.ADJ_SCOPE];
1397 }
1398 }
1399 l[EU.FN].call(scope, EU.getEvent(e), l[EU.OBJ] );
1400 delete unloadListeners[i];
1401 l=null;
1402 scope=null;
1403 }
1404 }
1405
1406 if (listeners && listeners.length > 0) {
1407 j = listeners.length;
1408 while (j) {
1409 index = j-1;
1410 l = listeners[index];
1411 if (l) {
1412 EU.removeListener(l[EU.EL], l[EU.TYPE],
1413 l[EU.FN], index);
1414 }
1415 j = j - 1;
1416 }
1417 l=null;
1418
1419 EU.clearCache();
1420 }
1421
1422 for (i=0,len=legacyEvents.length; i<len; ++i) {
1423 // dereference the element
1424 delete legacyEvents[i][0];
1425 // delete the array item
1426 delete legacyEvents[i];
1427 }
1428
1429 EU._simpleRemove(window, "unload", EU._unload);
1430
1431 },
1432
1433 /**
1434 * Returns scrollLeft
1435 * @method _getScrollLeft
1436 * @static
1437 * @private
1438 */
1439 _getScrollLeft: function() {
1440 return this._getScroll()[1];
1441 },
1442
1443 /**
1444 * Returns scrollTop
1445 * @method _getScrollTop
1446 * @static
1447 * @private
1448 */
1449 _getScrollTop: function() {
1450 return this._getScroll()[0];
1451 },
1452
1453 /**
1454 * Returns the scrollTop and scrollLeft. Used to calculate the
1455 * pageX and pageY in Internet Explorer
1456 * @method _getScroll
1457 * @static
1458 * @private
1459 */
1460 _getScroll: function() {
1461 var dd = document.documentElement, db = document.body;
1462 if (dd && (dd.scrollTop || dd.scrollLeft)) {
1463 return [dd.scrollTop, dd.scrollLeft];
1464 } else if (db) {
1465 return [db.scrollTop, db.scrollLeft];
1466 } else {
1467 return [0, 0];
1468 }
1469 },
1470
1471 /**
1472 * Adds a DOM event directly without the caching, cleanup, scope adj, etc
1473 *
1474 * @method _simpleAdd
1475 * @param {HTMLElement} el the element to bind the handler to
1476 * @param {string} sType the type of event handler
1477 * @param {function} fn the callback to invoke
1478 * @param {boolen} capture capture or bubble phase
1479 * @static
1480 * @private
1481 */
1482 _simpleAdd: function () {
1483 if (window.addEventListener) {
1484 return function(el, sType, fn, capture) {
1485 el.addEventListener(sType, fn, (capture));
1486 };
1487 } else if (window.attachEvent) {
1488 return function(el, sType, fn, capture) {
1489 el.attachEvent("on" + sType, fn);
1490 };
1491 } else {
1492 return function(){};
1493 }
1494 }(),
1495
1496 /**
1497 * Basic remove listener
1498 *
1499 * @method _simpleRemove
1500 * @param {HTMLElement} el the element to bind the handler to
1501 * @param {string} sType the type of event handler
1502 * @param {function} fn the callback to invoke
1503 * @param {boolen} capture capture or bubble phase
1504 * @static
1505 * @private
1506 */
1507 _simpleRemove: function() {
1508 if (window.removeEventListener) {
1509 return function (el, sType, fn, capture) {
1510 el.removeEventListener(sType, fn, (capture));
1511 };
1512 } else if (window.detachEvent) {
1513 return function (el, sType, fn) {
1514 el.detachEvent("on" + sType, fn);
1515 };
1516 } else {
1517 return function(){};
1518 }
1519 }()
1520 };
1521
1522 }();
1523
1524 (function() {
1525 var EU = YAHOO.util.Event;
1526
1527 /**
1528 * YAHOO.util.Event.on is an alias for addListener
1529 * @method on
1530 * @see addListener
1531 * @static
1532 */
1533 EU.on = EU.addListener;
1534
1535 // YAHOO.mix(EU, YAHOO.util.EventProvider.prototype);
1536 // EU.createEvent("DOMContentReady");
1537 // EU.subscribe("DOMContentReady", EU._load);
1538
1539 if (document && document.body) {
1540 EU._load();
1541 } else {
1542 // EU._simpleAdd(document, "DOMContentLoaded", EU._load);
1543 EU._simpleAdd(window, "load", EU._load);
1544 }
1545 EU._simpleAdd(window, "unload", EU._unload);
1546 EU._tryPreloadAttach();
1547 })();
1548}
1549
1550/**
1551 * EventProvider is designed to be used with YAHOO.augment to wrap
1552 * CustomEvents in an interface that allows events to be subscribed to
1553 * and fired by name. This makes it possible for implementing code to
1554 * subscribe to an event that either has not been created yet, or will
1555 * not be created at all.
1556 *
1557 * @Class EventProvider
1558 */
1559YAHOO.util.EventProvider = function() { };
1560
1561YAHOO.util.EventProvider.prototype = {
1562
1563 /**
1564 * Private storage of custom events
1565 * @property __yui_events
1566 * @type Object[]
1567 * @private
1568 */
1569 __yui_events: null,
1570
1571 /**
1572 * Private storage of custom event subscribers
1573 * @property __yui_subscribers
1574 * @type Object[]
1575 * @private
1576 */
1577 __yui_subscribers: null,
1578
1579 /**
1580 * Subscribe to a CustomEvent by event type
1581 *
1582 * @method subscribe
1583 * @param p_type {string} the type, or name of the event
1584 * @param p_fn {function} the function to exectute when the event fires
1585 * @param p_obj
1586 * @param p_obj {Object} An object to be passed along when the event
1587 * fires
1588 * @param p_override {boolean} If true, the obj passed in becomes the
1589 * execution scope of the listener
1590 */
1591 subscribe: function(p_type, p_fn, p_obj, p_override) {
1592
1593 this.__yui_events = this.__yui_events || {};
1594 var ce = this.__yui_events[p_type];
1595
1596 if (ce) {
1597 ce.subscribe(p_fn, p_obj, p_override);
1598 } else {
1599 this.__yui_subscribers = this.__yui_subscribers || {};
1600 var subs = this.__yui_subscribers;
1601 if (!subs[p_type]) {
1602 subs[p_type] = [];
1603 }
1604 subs[p_type].push(
1605 { fn: p_fn, obj: p_obj, override: p_override } );
1606 }
1607 },
1608
1609 /**
1610 * Unsubscribes the from the specified event
1611 * @method unsubscribe
1612 * @param p_type {string} The type, or name of the event
1613 * @param p_fn {Function} The function to execute
1614 * @param p_obj {Object} The custom object passed to subscribe (optional)
1615 * @return {boolean} true if the subscriber was found and detached.
1616 */
1617 unsubscribe: function(p_type, p_fn, p_obj) {
1618 this.__yui_events = this.__yui_events || {};
1619 var ce = this.__yui_events[p_type];
1620 if (ce) {
1621 return ce.unsubscribe(p_fn, p_obj);
1622 } else {
1623 return false;
1624 }
1625 },
1626
1627 /**
1628 * Creates a new custom event of the specified type. If a custom event
1629 * by that name already exists, it will not be re-created. In either
1630 * case the custom event is returned.
1631 *
1632 * @method createEvent
1633 *
1634 * @param p_type {string} the type, or name of the event
1635 * @param p_config {object} optional config params. Valid properties are:
1636 *
1637 * <ul>
1638 * <li>
1639 * scope: defines the default execution scope. If not defined
1640 * the default scope will be this instance.
1641 * </li>
1642 * <li>
1643 * silent: if true, the custom event will not generate log messages.
1644 * This is false by default.
1645 * </li>
1646 * <li>
1647 * onSubscribeCallback: specifies a callback to execute when the
1648 * event has a new subscriber. This will fire immediately for
1649 * each queued subscriber if any exist prior to the creation of
1650 * the event.
1651 * </li>
1652 * </ul>
1653 *
1654 * @return {CustomEvent} the custom event
1655 *
1656 */
1657 createEvent: function(p_type, p_config) {
1658
1659 this.__yui_events = this.__yui_events || {};
1660 var opts = p_config || {};
1661 var events = this.__yui_events;
1662
1663 if (events[p_type]) {
1664 } else {
1665
1666 var scope = opts.scope || this;
1667 var silent = opts.silent || null;
1668
1669 var ce = new YAHOO.util.CustomEvent(p_type, scope, silent,
1670 YAHOO.util.CustomEvent.FLAT);
1671 events[p_type] = ce;
1672
1673 if (opts.onSubscribeCallback) {
1674 ce.subscribeEvent.subscribe(opts.onSubscribeCallback);
1675 }
1676
1677 this.__yui_subscribers = this.__yui_subscribers || {};
1678 var qs = this.__yui_subscribers[p_type];
1679
1680 if (qs) {
1681 for (var i=0; i<qs.length; ++i) {
1682 ce.subscribe(qs[i].fn, qs[i].obj, qs[i].override);
1683 }
1684 }
1685 }
1686
1687 return events[p_type];
1688 },
1689
1690 /**
1691 * Fire a custom event by name. The callback functions will be executed
1692 * from the scope specified when the event was created, and with the
1693 * following parameters:
1694 * <ul>
1695 * <li>The first argument fire() was executed with</li>
1696 * <li>The custom object (if any) that was passed into the subscribe()
1697 * method</li>
1698 * </ul>
1699 * @method fireEvent
1700 * @param p_type {string} the type, or name of the event
1701 * @param arguments {Object*} an arbitrary set of parameters to pass to
1702 * the handler.
1703 * @return {boolean} the return value from CustomEvent.fire, or null if
1704 * the custom event does not exist.
1705 */
1706 fireEvent: function(p_type, arg1, arg2, etc) {
1707
1708 this.__yui_events = this.__yui_events || {};
1709 var ce = this.__yui_events[p_type];
1710
1711 if (ce) {
1712 var args = [];
1713 for (var i=1; i<arguments.length; ++i) {
1714 args.push(arguments[i]);
1715 }
1716 return ce.fire.apply(ce, args);
1717 } else {
1718 return null;
1719 }
1720 },
1721
1722 /**
1723 * Returns true if the custom event of the provided type has been created
1724 * with createEvent.
1725 * @method hasEvent
1726 * @param type {string} the type, or name of the event
1727 */
1728 hasEvent: function(type) {
1729 if (this.__yui_events) {
1730 if (this.__yui_events[type]) {
1731 return true;
1732 }
1733 }
1734 return false;
1735 }
1736
1737};
1738
diff --git a/frontend/beta/js/YUI/logger.js b/frontend/beta/js/YUI/logger.js
new file mode 100644
index 0000000..a2b40b2
--- a/dev/null
+++ b/frontend/beta/js/YUI/logger.js
@@ -0,0 +1,1559 @@
1/*
2Copyright (c) 2006, Yahoo! Inc. All rights reserved.
3Code licensed under the BSD License:
4http://developer.yahoo.com/yui/license.txt
5version: 0.12.0
6*/
7
8/****************************************************************************/
9/****************************************************************************/
10/****************************************************************************/
11
12/**
13 * The LogMsg class defines a single log message.
14 *
15 * @class LogMsg
16 * @constructor
17 * @param oConfigs {Object} Object literal of configuration params.
18 */
19 YAHOO.widget.LogMsg = function(oConfigs) {
20 // Parse configs
21 if (typeof oConfigs == "object") {
22 for(var param in oConfigs) {
23 this[param] = oConfigs[param];
24 }
25 }
26 };
27
28/////////////////////////////////////////////////////////////////////////////
29//
30// Public member variables
31//
32/////////////////////////////////////////////////////////////////////////////
33
34/**
35 * Log message.
36 *
37 * @property msg
38 * @type String
39 */
40YAHOO.widget.LogMsg.prototype.msg = null;
41
42/**
43 * Log timestamp.
44 *
45 * @property time
46 * @type Date
47 */
48YAHOO.widget.LogMsg.prototype.time = null;
49
50/**
51 * Log category.
52 *
53 * @property category
54 * @type String
55 */
56YAHOO.widget.LogMsg.prototype.category = null;
57
58/**
59 * Log source. The first word passed in as the source argument.
60 *
61 * @property source
62 * @type String
63 */
64YAHOO.widget.LogMsg.prototype.source = null;
65
66/**
67 * Log source detail. The remainder of the string passed in as the source argument, not
68 * including the first word (if any).
69 *
70 * @property sourceDetail
71 * @type String
72 */
73YAHOO.widget.LogMsg.prototype.sourceDetail = null;
74
75/****************************************************************************/
76/****************************************************************************/
77/****************************************************************************/
78
79/**
80 * The LogWriter class provides a mechanism to log messages through
81 * YAHOO.widget.Logger from a named source.
82 *
83 * @class LogWriter
84 * @constructor
85 * @param sSource {String} Source of LogWriter instance.
86 */
87YAHOO.widget.LogWriter = function(sSource) {
88 if(!sSource) {
89 YAHOO.log("Could not instantiate LogWriter due to invalid source.",
90 "error", "LogWriter");
91 return;
92 }
93 this._source = sSource;
94 };
95
96/////////////////////////////////////////////////////////////////////////////
97//
98// Public methods
99//
100/////////////////////////////////////////////////////////////////////////////
101
102 /**
103 * Public accessor to the unique name of the LogWriter instance.
104 *
105 * @method toString
106 * @return {String} Unique name of the LogWriter instance.
107 */
108YAHOO.widget.LogWriter.prototype.toString = function() {
109 return "LogWriter " + this._sSource;
110};
111
112/**
113 * Logs a message attached to the source of the LogWriter.
114 *
115 * @method log
116 * @param sMsg {String} The log message.
117 * @param sCategory {String} Category name.
118 */
119YAHOO.widget.LogWriter.prototype.log = function(sMsg, sCategory) {
120 YAHOO.widget.Logger.log(sMsg, sCategory, this._source);
121};
122
123/**
124 * Public accessor to get the source name.
125 *
126 * @method getSource
127 * @return {String} The LogWriter source.
128 */
129YAHOO.widget.LogWriter.prototype.getSource = function() {
130 return this._sSource;
131};
132
133/**
134 * Public accessor to set the source name.
135 *
136 * @method setSource
137 * @param sSource {String} Source of LogWriter instance.
138 */
139YAHOO.widget.LogWriter.prototype.setSource = function(sSource) {
140 if(!sSource) {
141 YAHOO.log("Could not set source due to invalid source.", "error", this.toString());
142 return;
143 }
144 else {
145 this._sSource = sSource;
146 }
147};
148
149/////////////////////////////////////////////////////////////////////////////
150//
151// Private member variables
152//
153/////////////////////////////////////////////////////////////////////////////
154
155/**
156 * Source of the LogWriter instance.
157 *
158 * @property _source
159 * @type String
160 * @private
161 */
162YAHOO.widget.LogWriter.prototype._source = null;
163
164
165
166/****************************************************************************/
167/****************************************************************************/
168/****************************************************************************/
169
170/**
171 * The LogReader class provides UI to read messages logged to YAHOO.widget.Logger.
172 *
173 * @class LogReader
174 * @constructor
175 * @param elContainer {HTMLElement} (optional) DOM element reference of an existing DIV.
176 * @param elContainer {String} (optional) String ID of an existing DIV.
177 * @param oConfigs {Object} (optional) Object literal of configuration params.
178 */
179YAHOO.widget.LogReader = function(elContainer, oConfigs) {
180 var oSelf = this;
181 this._sName = YAHOO.widget.LogReader._index;
182 YAHOO.widget.LogReader._index++;
183
184 // Parse config vars here
185 if (typeof oConfigs == "object") {
186 for(var param in oConfigs) {
187 this[param] = oConfigs[param];
188 }
189 }
190
191 // Attach container...
192 if(elContainer) {
193 if(typeof elContainer == "string") {
194 this._elContainer = document.getElementById(elContainer);
195 }
196 else if(elContainer.tagName) {
197 this._elContainer = elContainer;
198 }
199 this._elContainer.className = "yui-log";
200 }
201 // ...or create container from scratch
202 if(!this._elContainer) {
203 if(YAHOO.widget.LogReader._elDefaultContainer) {
204 this._elContainer = YAHOO.widget.LogReader._elDefaultContainer;
205 }
206 else {
207 this._elContainer = document.body.appendChild(document.createElement("div"));
208 this._elContainer.id = "yui-log";
209 this._elContainer.className = "yui-log";
210
211 YAHOO.widget.LogReader._elDefaultContainer = this._elContainer;
212 }
213
214 // If implementer has provided container values, trust and set those
215 var containerStyle = this._elContainer.style;
216 if(this.width) {
217 containerStyle.width = this.width;
218 }
219 if(this.left) {
220 containerStyle.left = this.left;
221 }
222 if(this.right) {
223 containerStyle.right = this.right;
224 }
225 if(this.bottom) {
226 containerStyle.bottom = this.bottom;
227 }
228 if(this.top) {
229 containerStyle.top = this.top;
230 }
231 if(this.fontSize) {
232 containerStyle.fontSize = this.fontSize;
233 }
234 }
235
236 if(this._elContainer) {
237 // Create header
238 if(!this._elHd) {
239 this._elHd = this._elContainer.appendChild(document.createElement("div"));
240 this._elHd.id = "yui-log-hd" + this._sName;
241 this._elHd.className = "yui-log-hd";
242
243 this._elCollapse = this._elHd.appendChild(document.createElement("div"));
244 this._elCollapse.className = "yui-log-btns";
245
246 this._btnCollapse = document.createElement("input");
247 this._btnCollapse.type = "button";
248 this._btnCollapse.style.fontSize =
249 YAHOO.util.Dom.getStyle(this._elContainer,"fontSize");
250 this._btnCollapse.className = "yui-log-button";
251 this._btnCollapse.value = "Collapse";
252 this._btnCollapse = this._elCollapse.appendChild(this._btnCollapse);
253 YAHOO.util.Event.addListener(
254 oSelf._btnCollapse,'click',oSelf._onClickCollapseBtn,oSelf);
255
256 this._title = this._elHd.appendChild(document.createElement("h4"));
257 this._title.innerHTML = "Logger Console";
258
259 // If Drag and Drop utility is available...
260 // ...and this container was created from scratch...
261 // ...then make the header draggable
262 if(YAHOO.util.DD &&
263 (YAHOO.widget.LogReader._elDefaultContainer == this._elContainer)) {
264 var ylog_dd = new YAHOO.util.DD(this._elContainer.id);
265 ylog_dd.setHandleElId(this._elHd.id);
266 this._elHd.style.cursor = "move";
267 }
268 }
269 // Ceate console
270 if(!this._elConsole) {
271 this._elConsole =
272 this._elContainer.appendChild(document.createElement("div"));
273 this._elConsole.className = "yui-log-bd";
274
275 // If implementer has provided console, trust and set those
276 if(this.height) {
277 this._elConsole.style.height = this.height;
278 }
279 }
280 // Don't create footer if disabled
281 if(!this._elFt && this.footerEnabled) {
282 this._elFt = this._elContainer.appendChild(document.createElement("div"));
283 this._elFt.className = "yui-log-ft";
284
285 this._elBtns = this._elFt.appendChild(document.createElement("div"));
286 this._elBtns.className = "yui-log-btns";
287
288 this._btnPause = document.createElement("input");
289 this._btnPause.type = "button";
290 this._btnPause.style.fontSize =
291 YAHOO.util.Dom.getStyle(this._elContainer,"fontSize");
292 this._btnPause.className = "yui-log-button";
293 this._btnPause.value = "Pause";
294 this._btnPause = this._elBtns.appendChild(this._btnPause);
295 YAHOO.util.Event.addListener(
296 oSelf._btnPause,'click',oSelf._onClickPauseBtn,oSelf);
297
298 this._btnClear = document.createElement("input");
299 this._btnClear.type = "button";
300 this._btnClear.style.fontSize =
301 YAHOO.util.Dom.getStyle(this._elContainer,"fontSize");
302 this._btnClear.className = "yui-log-button";
303 this._btnClear.value = "Clear";
304 this._btnClear = this._elBtns.appendChild(this._btnClear);
305 YAHOO.util.Event.addListener(
306 oSelf._btnClear,'click',oSelf._onClickClearBtn,oSelf);
307
308 this._elCategoryFilters = this._elFt.appendChild(document.createElement("div"));
309 this._elCategoryFilters.className = "yui-log-categoryfilters";
310 this._elSourceFilters = this._elFt.appendChild(document.createElement("div"));
311 this._elSourceFilters.className = "yui-log-sourcefilters";
312 }
313 }
314
315 // Initialize internal vars
316 if(!this._buffer) {
317 this._buffer = []; // output buffer
318 }
319 // Timestamp of last log message to console
320 this._lastTime = YAHOO.widget.Logger.getStartTime();
321
322 // Subscribe to Logger custom events
323 YAHOO.widget.Logger.newLogEvent.subscribe(this._onNewLog, this);
324 YAHOO.widget.Logger.logResetEvent.subscribe(this._onReset, this);
325
326 // Initialize category filters
327 this._categoryFilters = [];
328 var catsLen = YAHOO.widget.Logger.categories.length;
329 if(this._elCategoryFilters) {
330 for(var i=0; i < catsLen; i++) {
331 this._createCategoryCheckbox(YAHOO.widget.Logger.categories[i]);
332 }
333 }
334 // Initialize source filters
335 this._sourceFilters = [];
336 var sourcesLen = YAHOO.widget.Logger.sources.length;
337 if(this._elSourceFilters) {
338 for(var j=0; j < sourcesLen; j++) {
339 this._createSourceCheckbox(YAHOO.widget.Logger.sources[j]);
340 }
341 }
342 YAHOO.widget.Logger.categoryCreateEvent.subscribe(this._onCategoryCreate, this);
343 YAHOO.widget.Logger.sourceCreateEvent.subscribe(this._onSourceCreate, this);
344
345 this._filterLogs();
346 YAHOO.log("LogReader initialized", null, this.toString());
347};
348
349/////////////////////////////////////////////////////////////////////////////
350//
351// Public member variables
352//
353/////////////////////////////////////////////////////////////////////////////
354
355/**
356 * Whether or not the log reader is enabled to output log messages.
357 *
358 * @property logReaderEnabled
359 * @type Boolean
360 * @default true
361 */
362YAHOO.widget.LogReader.prototype.logReaderEnabled = true;
363
364/**
365 * Public member to access CSS width of the log reader container.
366 *
367 * @property width
368 * @type String
369 */
370YAHOO.widget.LogReader.prototype.width = null;
371
372/**
373 * Public member to access CSS height of the log reader container.
374 *
375 * @property height
376 * @type String
377 */
378YAHOO.widget.LogReader.prototype.height = null;
379
380/**
381 * Public member to access CSS top position of the log reader container.
382 *
383 * @property top
384 * @type String
385 */
386YAHOO.widget.LogReader.prototype.top = null;
387
388/**
389 * Public member to access CSS left position of the log reader container.
390 *
391 * @property left
392 * @type String
393 */
394YAHOO.widget.LogReader.prototype.left = null;
395
396/**
397 * Public member to access CSS right position of the log reader container.
398 *
399 * @property right
400 * @type String
401 */
402YAHOO.widget.LogReader.prototype.right = null;
403
404/**
405 * Public member to access CSS bottom position of the log reader container.
406 *
407 * @property bottom
408 * @type String
409 */
410YAHOO.widget.LogReader.prototype.bottom = null;
411
412/**
413 * Public member to access CSS font size of the log reader container.
414 *
415 * @property fontSize
416 * @type String
417 */
418YAHOO.widget.LogReader.prototype.fontSize = null;
419
420/**
421 * Whether or not the footer UI is enabled for the log reader.
422 *
423 * @property footerEnabled
424 * @type Boolean
425 * @default true
426 */
427YAHOO.widget.LogReader.prototype.footerEnabled = true;
428
429/**
430 * Whether or not output is verbose (more readable). Setting to true will make
431 * output more compact (less readable).
432 *
433 * @property verboseOutput
434 * @type Boolean
435 * @default true
436 */
437YAHOO.widget.LogReader.prototype.verboseOutput = true;
438
439/**
440 * Whether or not newest message is printed on top.
441 *
442 * @property newestOnTop
443 * @type Boolean
444 */
445YAHOO.widget.LogReader.prototype.newestOnTop = true;
446
447/**
448 * Maximum number of messages a LogReader console will display.
449 *
450 * @property thresholdMax
451 * @type Number
452 * @default 500
453 */
454YAHOO.widget.LogReader.prototype.thresholdMax = 500;
455
456/**
457 * When a LogReader console reaches its thresholdMax, it will clear out messages
458 * and print out the latest thresholdMin number of messages.
459 *
460 * @property thresholdMin
461 * @type Number
462 * @default 100
463 */
464YAHOO.widget.LogReader.prototype.thresholdMin = 100;
465
466/////////////////////////////////////////////////////////////////////////////
467//
468// Public methods
469//
470/////////////////////////////////////////////////////////////////////////////
471
472 /**
473 * Public accessor to the unique name of the LogReader instance.
474 *
475 * @method toString
476 * @return {String} Unique name of the LogReader instance.
477 */
478YAHOO.widget.LogReader.prototype.toString = function() {
479 return "LogReader instance" + this._sName;
480};
481/**
482 * Pauses output of log messages. While paused, log messages are not lost, but
483 * get saved to a buffer and then output upon resume of log reader.
484 *
485 * @method pause
486 */
487YAHOO.widget.LogReader.prototype.pause = function() {
488 this._timeout = null;
489 this.logReaderEnabled = false;
490};
491
492/**
493 * Resumes output of log messages, including outputting any log messages that
494 * have been saved to buffer while paused.
495 *
496 * @method resume
497 */
498YAHOO.widget.LogReader.prototype.resume = function() {
499 this.logReaderEnabled = true;
500 this._printBuffer();
501};
502
503/**
504 * Hides UI of log reader. Logging functionality is not disrupted.
505 *
506 * @method hide
507 */
508YAHOO.widget.LogReader.prototype.hide = function() {
509 this._elContainer.style.display = "none";
510};
511
512/**
513 * Shows UI of log reader. Logging functionality is not disrupted.
514 *
515 * @method show
516 */
517YAHOO.widget.LogReader.prototype.show = function() {
518 this._elContainer.style.display = "block";
519};
520
521/**
522 * Updates title to given string.
523 *
524 * @method setTitle
525 * @param sTitle {String} New title.
526 */
527YAHOO.widget.LogReader.prototype.setTitle = function(sTitle) {
528 this._title.innerHTML = this.html2Text(sTitle);
529};
530
531/**
532 * Gets timestamp of the last log.
533 *
534 * @method getLastTime
535 * @return {Date} Timestamp of the last log.
536 */
537YAHOO.widget.LogReader.prototype.getLastTime = function() {
538 return this._lastTime;
539};
540
541/**
542 * Formats message string to HTML for output to console.
543 *
544 * @method formatMsg
545 * @param oLogMsg {Object} Log message object.
546 * @return {String} HTML-formatted message for output to console.
547 */
548YAHOO.widget.LogReader.prototype.formatMsg = function(oLogMsg) {
549 var category = oLogMsg.category;
550
551 // Label for color-coded display
552 var label = category.substring(0,4).toUpperCase();
553
554 // Calculate the elapsed time to be from the last item that passed through the filter,
555 // not the absolute previous item in the stack
556
557 var time = oLogMsg.time;
558 if (time.toLocaleTimeString) {
559 var localTime = time.toLocaleTimeString();
560 }
561 else {
562 localTime = time.toString();
563 }
564
565 var msecs = time.getTime();
566 var startTime = YAHOO.widget.Logger.getStartTime();
567 var totalTime = msecs - startTime;
568 var elapsedTime = msecs - this.getLastTime();
569
570 var source = oLogMsg.source;
571 var sourceDetail = oLogMsg.sourceDetail;
572 var sourceAndDetail = (sourceDetail) ?
573 source + " " + sourceDetail : source;
574
575 // Escape HTML entities in the log message itself for output to console
576 var msg = this.html2Text(oLogMsg.msg);
577
578 // Verbose output includes extra line breaks
579 var output = (this.verboseOutput) ?
580 ["<p><span class='", category, "'>", label, "</span> ",
581 totalTime, "ms (+", elapsedTime, ") ",
582 localTime, ": ",
583 "</p><p>",
584 sourceAndDetail,
585 ": </p><p>",
586 msg,
587 "</p>"] :
588
589 ["<p><span class='", category, "'>", label, "</span> ",
590 totalTime, "ms (+", elapsedTime, ") ",
591 localTime, ": ",
592 sourceAndDetail, ": ",
593 msg,"</p>"];
594
595 return output.join("");
596};
597
598/**
599 * Converts input chars "<", ">", and "&" to HTML entities.
600 *
601 * @method html2Text
602 * @param sHtml {String} String to convert.
603 * @private
604 */
605YAHOO.widget.LogReader.prototype.html2Text = function(sHtml) {
606 if(sHtml) {
607 sHtml += "";
608 return sHtml.replace(/&/g, "&#38;").replace(/</g, "&#60;").replace(/>/g, "&#62;");
609 }
610 return "";
611};
612
613/////////////////////////////////////////////////////////////////////////////
614//
615// Private member variables
616//
617/////////////////////////////////////////////////////////////////////////////
618
619/**
620 * Internal class member to index multiple log reader instances.
621 *
622 * @property _memberName
623 * @static
624 * @type Number
625 * @default 0
626 * @private
627 */
628YAHOO.widget.LogReader._index = 0;
629
630/**
631 * Name of LogReader instance.
632 *
633 * @property _sName
634 * @type String
635 * @private
636 */
637YAHOO.widget.LogReader.prototype._sName = null;
638
639/**
640 * A class member shared by all log readers if a container needs to be
641 * created during instantiation. Will be null if a container element never needs to
642 * be created on the fly, such as when the implementer passes in their own element.
643 *
644 * @property _elDefaultContainer
645 * @type HTMLElement
646 * @private
647 */
648YAHOO.widget.LogReader._elDefaultContainer = null;
649
650/**
651 * Buffer of log message objects for batch output.
652 *
653 * @property _buffer
654 * @type Object[]
655 * @private
656 */
657YAHOO.widget.LogReader.prototype._buffer = null;
658
659/**
660 * Number of log messages output to console.
661 *
662 * @property _consoleMsgCount
663 * @type Number
664 * @default 0
665 * @private
666 */
667YAHOO.widget.LogReader.prototype._consoleMsgCount = 0;
668
669/**
670 * Date of last output log message.
671 *
672 * @property _lastTime
673 * @type Date
674 * @private
675 */
676YAHOO.widget.LogReader.prototype._lastTime = null;
677
678/**
679 * Batched output timeout ID.
680 *
681 * @property _timeout
682 * @type Number
683 * @private
684 */
685YAHOO.widget.LogReader.prototype._timeout = null;
686
687/**
688 * Array of filters for log message categories.
689 *
690 * @property _categoryFilters
691 * @type String[]
692 * @private
693 */
694YAHOO.widget.LogReader.prototype._categoryFilters = null;
695
696/**
697 * Array of filters for log message sources.
698 *
699 * @property _sourceFilters
700 * @type String[]
701 * @private
702 */
703YAHOO.widget.LogReader.prototype._sourceFilters = null;
704
705/**
706 * Log reader container element.
707 *
708 * @property _elContainer
709 * @type HTMLElement
710 * @private
711 */
712YAHOO.widget.LogReader.prototype._elContainer = null;
713
714/**
715 * Log reader header element.
716 *
717 * @property _elHd
718 * @type HTMLElement
719 * @private
720 */
721YAHOO.widget.LogReader.prototype._elHd = null;
722
723/**
724 * Log reader collapse element.
725 *
726 * @property _elCollapse
727 * @type HTMLElement
728 * @private
729 */
730YAHOO.widget.LogReader.prototype._elCollapse = null;
731
732/**
733 * Log reader collapse button element.
734 *
735 * @property _btnCollapse
736 * @type HTMLElement
737 * @private
738 */
739YAHOO.widget.LogReader.prototype._btnCollapse = null;
740
741/**
742 * Log reader title header element.
743 *
744 * @property _title
745 * @type HTMLElement
746 * @private
747 */
748YAHOO.widget.LogReader.prototype._title = null;
749
750/**
751 * Log reader console element.
752 *
753 * @property _elConsole
754 * @type HTMLElement
755 * @private
756 */
757YAHOO.widget.LogReader.prototype._elConsole = null;
758
759/**
760 * Log reader footer element.
761 *
762 * @property _elFt
763 * @type HTMLElement
764 * @private
765 */
766YAHOO.widget.LogReader.prototype._elFt = null;
767
768/**
769 * Log reader buttons container element.
770 *
771 * @property _elBtns
772 * @type HTMLElement
773 * @private
774 */
775YAHOO.widget.LogReader.prototype._elBtns = null;
776
777/**
778 * Container element for log reader category filter checkboxes.
779 *
780 * @property _elCategoryFilters
781 * @type HTMLElement
782 * @private
783 */
784YAHOO.widget.LogReader.prototype._elCategoryFilters = null;
785
786/**
787 * Container element for log reader source filter checkboxes.
788 *
789 * @property _elSourceFilters
790 * @type HTMLElement
791 * @private
792 */
793YAHOO.widget.LogReader.prototype._elSourceFilters = null;
794
795/**
796 * Log reader pause button element.
797 *
798 * @property _btnPause
799 * @type HTMLElement
800 * @private
801 */
802YAHOO.widget.LogReader.prototype._btnPause = null;
803
804/**
805 * Clear button element.
806 *
807 * @property _btnClear
808 * @type HTMLElement
809 * @private
810 */
811YAHOO.widget.LogReader.prototype._btnClear = null;
812
813/////////////////////////////////////////////////////////////////////////////
814//
815// Private methods
816//
817/////////////////////////////////////////////////////////////////////////////
818
819/**
820 * Creates the UI for a category filter in the log reader footer element.
821 *
822 * @method _createCategoryCheckbox
823 * @param sCategory {String} Category name.
824 * @private
825 */
826YAHOO.widget.LogReader.prototype._createCategoryCheckbox = function(sCategory) {
827 var oSelf = this;
828
829 if(this._elFt) {
830 var elParent = this._elCategoryFilters;
831 var filters = this._categoryFilters;
832
833 var elFilter = elParent.appendChild(document.createElement("span"));
834 elFilter.className = "yui-log-filtergrp";
835 // Append el at the end so IE 5.5 can set "type" attribute
836 // and THEN set checked property
837 var chkCategory = document.createElement("input");
838 chkCategory.id = "yui-log-filter-" + sCategory + this._sName;
839 chkCategory.className = "yui-log-filter-" + sCategory;
840 chkCategory.type = "checkbox";
841 chkCategory.category = sCategory;
842 chkCategory = elFilter.appendChild(chkCategory);
843 chkCategory.checked = true;
844
845 // Add this checked filter to the internal array of filters
846 filters.push(sCategory);
847 // Subscribe to the click event
848 YAHOO.util.Event.addListener(chkCategory,'click',oSelf._onCheckCategory,oSelf);
849
850 // Create and class the text label
851 var lblCategory = elFilter.appendChild(document.createElement("label"));
852 lblCategory.htmlFor = chkCategory.id;
853 lblCategory.className = sCategory;
854 lblCategory.innerHTML = sCategory;
855 }
856};
857
858/**
859 * Creates a checkbox in the log reader footer element to filter by source.
860 *
861 * @method _createSourceCheckbox
862 * @param sSource {String} Source name.
863 * @private
864 */
865YAHOO.widget.LogReader.prototype._createSourceCheckbox = function(sSource) {
866 var oSelf = this;
867
868 if(this._elFt) {
869 var elParent = this._elSourceFilters;
870 var filters = this._sourceFilters;
871
872 var elFilter = elParent.appendChild(document.createElement("span"));
873 elFilter.className = "yui-log-filtergrp";
874
875 // Append el at the end so IE 5.5 can set "type" attribute
876 // and THEN set checked property
877 var chkSource = document.createElement("input");
878 chkSource.id = "yui-log-filter" + sSource + this._sName;
879 chkSource.className = "yui-log-filter" + sSource;
880 chkSource.type = "checkbox";
881 chkSource.source = sSource;
882 chkSource = elFilter.appendChild(chkSource);
883 chkSource.checked = true;
884
885 // Add this checked filter to the internal array of filters
886 filters.push(sSource);
887 // Subscribe to the click event
888 YAHOO.util.Event.addListener(chkSource,'click',oSelf._onCheckSource,oSelf);
889
890 // Create and class the text label
891 var lblSource = elFilter.appendChild(document.createElement("label"));
892 lblSource.htmlFor = chkSource.id;
893 lblSource.className = sSource;
894 lblSource.innerHTML = sSource;
895 }
896};
897
898/**
899 * Reprints all log messages in the stack through filters.
900 *
901 * @method _filterLogs
902 * @private
903 */
904YAHOO.widget.LogReader.prototype._filterLogs = function() {
905 // Reprint stack with new filters
906 if (this._elConsole !== null) {
907 this._clearConsole();
908 this._printToConsole(YAHOO.widget.Logger.getStack());
909 }
910};
911
912/**
913 * Clears all outputted log messages from the console and resets the time of the
914 * last output log message.
915 *
916 * @method _clearConsole
917 * @private
918 */
919YAHOO.widget.LogReader.prototype._clearConsole = function() {
920 // Clear the buffer of any pending messages
921 this._timeout = null;
922 this._buffer = [];
923 this._consoleMsgCount = 0;
924
925 // Reset the rolling timer
926 this._lastTime = YAHOO.widget.Logger.getStartTime();
927
928 var elConsole = this._elConsole;
929 while(elConsole.hasChildNodes()) {
930 elConsole.removeChild(elConsole.firstChild);
931 }
932};
933
934/**
935 * Sends buffer of log messages to output and clears buffer.
936 *
937 * @method _printBuffer
938 * @private
939 */
940YAHOO.widget.LogReader.prototype._printBuffer = function() {
941 this._timeout = null;
942
943 if(this._elConsole !== null) {
944 var thresholdMax = this.thresholdMax;
945 thresholdMax = (thresholdMax && !isNaN(thresholdMax)) ? thresholdMax : 500;
946 if(this._consoleMsgCount < thresholdMax) {
947 var entries = [];
948 for (var i=0; i<this._buffer.length; i++) {
949 entries[i] = this._buffer[i];
950 }
951 this._buffer = [];
952 this._printToConsole(entries);
953 }
954 else {
955 this._filterLogs();
956 }
957
958 if(!this.newestOnTop) {
959 this._elConsole.scrollTop = this._elConsole.scrollHeight;
960 }
961 }
962};
963
964/**
965 * Cycles through an array of log messages, and outputs each one to the console
966 * if its category has not been filtered out.
967 *
968 * @method _printToConsole
969 * @param aEntries {Object[]} Array of LogMsg objects to output to console.
970 * @private
971 */
972YAHOO.widget.LogReader.prototype._printToConsole = function(aEntries) {
973 // Manage the number of messages displayed in the console
974 var entriesLen = aEntries.length;
975 var thresholdMin = this.thresholdMin;
976 if(isNaN(thresholdMin) || (thresholdMin > this.thresholdMax)) {
977 thresholdMin = 0;
978 }
979 var entriesStartIndex = (entriesLen > thresholdMin) ? (entriesLen - thresholdMin) : 0;
980
981 // Iterate through all log entries
982 var sourceFiltersLen = this._sourceFilters.length;
983 var categoryFiltersLen = this._categoryFilters.length;
984 for(var i=entriesStartIndex; i<entriesLen; i++) {
985 // Print only the ones that filter through
986 var okToPrint = false;
987 var okToFilterCats = false;
988
989 // Get log message details
990 var entry = aEntries[i];
991 var source = entry.source;
992 var category = entry.category;
993
994 for(var j=0; j<sourceFiltersLen; j++) {
995 if(source == this._sourceFilters[j]) {
996 okToFilterCats = true;
997 break;
998 }
999 }
1000 if(okToFilterCats) {
1001 for(var k=0; k<categoryFiltersLen; k++) {
1002 if(category == this._categoryFilters[k]) {
1003 okToPrint = true;
1004 break;
1005 }
1006 }
1007 }
1008 if(okToPrint) {
1009 var output = this.formatMsg(entry);
1010
1011 // Verbose output uses <code> tag instead of <pre> tag (for wrapping)
1012 var container = (this.verboseOutput) ? "CODE" : "PRE";
1013 var oNewElement = (this.newestOnTop) ?
1014 this._elConsole.insertBefore(
1015 document.createElement(container),this._elConsole.firstChild):
1016 this._elConsole.appendChild(document.createElement(container));
1017
1018 oNewElement.innerHTML = output;
1019 this._consoleMsgCount++;
1020 this._lastTime = entry.time.getTime();
1021 }
1022 }
1023};
1024
1025/////////////////////////////////////////////////////////////////////////////
1026//
1027// Private event handlers
1028//
1029/////////////////////////////////////////////////////////////////////////////
1030
1031/**
1032 * Handles Logger's categoryCreateEvent.
1033 *
1034 * @method _onCategoryCreate
1035 * @param sType {String} The event.
1036 * @param aArgs {Object[]} Data passed from event firer.
1037 * @param oSelf {Object} The LogReader instance.
1038 * @private
1039 */
1040YAHOO.widget.LogReader.prototype._onCategoryCreate = function(sType, aArgs, oSelf) {
1041 var category = aArgs[0];
1042 if(oSelf._elFt) {
1043 oSelf._createCategoryCheckbox(category);
1044 }
1045};
1046
1047/**
1048 * Handles Logger's sourceCreateEvent.
1049 *
1050 * @method _onSourceCreate
1051 * @param sType {String} The event.
1052 * @param aArgs {Object[]} Data passed from event firer.
1053 * @param oSelf {Object} The LogReader instance.
1054 * @private
1055 */
1056YAHOO.widget.LogReader.prototype._onSourceCreate = function(sType, aArgs, oSelf) {
1057 var source = aArgs[0];
1058 if(oSelf._elFt) {
1059 oSelf._createSourceCheckbox(source);
1060 }
1061};
1062
1063/**
1064 * Handles check events on the category filter checkboxes.
1065 *
1066 * @method _onCheckCategory
1067 * @param v {HTMLEvent} The click event.
1068 * @param oSelf {Object} The LogReader instance.
1069 * @private
1070 */
1071YAHOO.widget.LogReader.prototype._onCheckCategory = function(v, oSelf) {
1072 var newFilter = this.category;
1073 var filtersArray = oSelf._categoryFilters;
1074
1075 if(!this.checked) { // Remove category from filters
1076 for(var i=0; i<filtersArray.length; i++) {
1077 if(newFilter == filtersArray[i]) {
1078 filtersArray.splice(i, 1);
1079 break;
1080 }
1081 }
1082 }
1083 else { // Add category to filters
1084 filtersArray.push(newFilter);
1085 }
1086 oSelf._filterLogs();
1087};
1088
1089/**
1090 * Handles check events on the category filter checkboxes.
1091 *
1092 * @method _onCheckSource
1093 * @param v {HTMLEvent} The click event.
1094 * @param oSelf {Object} The log reader instance.
1095 * @private
1096 */
1097YAHOO.widget.LogReader.prototype._onCheckSource = function(v, oSelf) {
1098 var newFilter = this.source;
1099 var filtersArray = oSelf._sourceFilters;
1100
1101 if(!this.checked) { // Remove category from filters
1102 for(var i=0; i<filtersArray.length; i++) {
1103 if(newFilter == filtersArray[i]) {
1104 filtersArray.splice(i, 1);
1105 break;
1106 }
1107 }
1108 }
1109 else { // Add category to filters
1110 filtersArray.push(newFilter);
1111 }
1112 oSelf._filterLogs();
1113};
1114
1115/**
1116 * Handles click events on the collapse button.
1117 *
1118 * @method _onClickCollapseBtn
1119 * @param v {HTMLEvent} The click event.
1120 * @param oSelf {Object} The LogReader instance
1121 * @private
1122 */
1123YAHOO.widget.LogReader.prototype._onClickCollapseBtn = function(v, oSelf) {
1124 var btn = oSelf._btnCollapse;
1125 if(btn.value == "Expand") {
1126 oSelf._elConsole.style.display = "block";
1127 if(oSelf._elFt) {
1128 oSelf._elFt.style.display = "block";
1129 }
1130 btn.value = "Collapse";
1131 }
1132 else {
1133 oSelf._elConsole.style.display = "none";
1134 if(oSelf._elFt) {
1135 oSelf._elFt.style.display = "none";
1136 }
1137 btn.value = "Expand";
1138 }
1139};
1140
1141/**
1142 * Handles click events on the pause button.
1143 *
1144 * @method _onClickPauseBtn
1145 * @param v {HTMLEvent} The click event.
1146 * @param oSelf {Object} The LogReader instance.
1147 * @private
1148 */
1149YAHOO.widget.LogReader.prototype._onClickPauseBtn = function(v, oSelf) {
1150 var btn = oSelf._btnPause;
1151 if(btn.value == "Resume") {
1152 oSelf.resume();
1153 btn.value = "Pause";
1154 }
1155 else {
1156 oSelf.pause();
1157 btn.value = "Resume";
1158 }
1159};
1160
1161/**
1162 * Handles click events on the clear button.
1163 *
1164 * @method _onClickClearBtn
1165 * @param v {HTMLEvent} The click event.
1166 * @param oSelf {Object} The LogReader instance.
1167 * @private
1168 */
1169YAHOO.widget.LogReader.prototype._onClickClearBtn = function(v, oSelf) {
1170 oSelf._clearConsole();
1171};
1172
1173/**
1174 * Handles Logger's newLogEvent.
1175 *
1176 * @method _onNewLog
1177 * @param sType {String} The event.
1178 * @param aArgs {Object[]} Data passed from event firer.
1179 * @param oSelf {Object} The LogReader instance.
1180 * @private
1181 */
1182YAHOO.widget.LogReader.prototype._onNewLog = function(sType, aArgs, oSelf) {
1183 var logEntry = aArgs[0];
1184 oSelf._buffer.push(logEntry);
1185
1186 if (oSelf.logReaderEnabled === true && oSelf._timeout === null) {
1187 oSelf._timeout = setTimeout(function(){oSelf._printBuffer();}, 100);
1188 }
1189};
1190
1191/**
1192 * Handles Logger's resetEvent.
1193 *
1194 * @method _onReset
1195 * @param sType {String} The event.
1196 * @param aArgs {Object[]} Data passed from event firer.
1197 * @param oSelf {Object} The LogReader instance.
1198 * @private
1199 */
1200YAHOO.widget.LogReader.prototype._onReset = function(sType, aArgs, oSelf) {
1201 oSelf._filterLogs();
1202};
1203 /**
1204 * The Logger widget provides a simple way to read or write log messages in
1205 * JavaScript code. Integration with the YUI Library's debug builds allow
1206 * implementers to access under-the-hood events, errors, and debugging messages.
1207 * Output may be read through a LogReader console and/or output to a browser
1208 * console.
1209 *
1210 * @module logger
1211 * @requires yahoo, event, dom
1212 * @optional dragdrop
1213 * @namespace YAHOO.widget
1214 * @title Logger Widget
1215 */
1216
1217/****************************************************************************/
1218/****************************************************************************/
1219/****************************************************************************/
1220
1221/**
1222 * The singleton Logger class provides core log management functionality. Saves
1223 * logs written through the global YAHOO.log function or written by a LogWriter
1224 * instance. Provides access to logs for reading by a LogReader instance or
1225 * native browser console such as the Firebug extension to Firefox or Safari's
1226 * JavaScript console through integration with the console.log() method.
1227 *
1228 * @class Logger
1229 * @static
1230 */
1231YAHOO.widget.Logger = {
1232 // Initialize members
1233 loggerEnabled: true,
1234 _browserConsoleEnabled: false,
1235 categories: ["info","warn","error","time","window"],
1236 sources: ["global"],
1237 _stack: [], // holds all log msgs
1238 maxStackEntries: 2500,
1239 _startTime: new Date().getTime(), // static start timestamp
1240 _lastTime: null // timestamp of last logged message
1241};
1242
1243/////////////////////////////////////////////////////////////////////////////
1244//
1245// Public methods
1246//
1247/////////////////////////////////////////////////////////////////////////////
1248/**
1249 * Saves a log message to the stack and fires newLogEvent. If the log message is
1250 * assigned to an unknown category, creates a new category. If the log message is
1251 * from an unknown source, creates a new source. If browser console is enabled,
1252 * outputs the log message to browser console.
1253 *
1254 * @method log
1255 * @param sMsg {String} The log message.
1256 * @param sCategory {String} Category of log message, or null.
1257 * @param sSource {String} Source of LogWriter, or null if global.
1258 */
1259YAHOO.widget.Logger.log = function(sMsg, sCategory, sSource) {
1260 if(this.loggerEnabled) {
1261 if(!sCategory) {
1262 sCategory = "info"; // default category
1263 }
1264 else {
1265 sCategory = sCategory.toLocaleLowerCase();
1266 if(this._isNewCategory(sCategory)) {
1267 this._createNewCategory(sCategory);
1268 }
1269 }
1270 var sClass = "global"; // default source
1271 var sDetail = null;
1272 if(sSource) {
1273 var spaceIndex = sSource.indexOf(" ");
1274 if(spaceIndex > 0) {
1275 // Substring until first space
1276 sClass = sSource.substring(0,spaceIndex);
1277 // The rest of the source
1278 sDetail = sSource.substring(spaceIndex,sSource.length);
1279 }
1280 else {
1281 sClass = sSource;
1282 }
1283 if(this._isNewSource(sClass)) {
1284 this._createNewSource(sClass);
1285 }
1286 }
1287
1288 var timestamp = new Date();
1289 var logEntry = new YAHOO.widget.LogMsg({
1290 msg: sMsg,
1291 time: timestamp,
1292 category: sCategory,
1293 source: sClass,
1294 sourceDetail: sDetail
1295 });
1296
1297 var stack = this._stack;
1298 var maxStackEntries = this.maxStackEntries;
1299 if(maxStackEntries && !isNaN(maxStackEntries) &&
1300 (stack.length >= maxStackEntries)) {
1301 stack.shift();
1302 }
1303 stack.push(logEntry);
1304 this.newLogEvent.fire(logEntry);
1305
1306 if(this._browserConsoleEnabled) {
1307 this._printToBrowserConsole(logEntry);
1308 }
1309 return true;
1310 }
1311 else {
1312 return false;
1313 }
1314};
1315
1316/**
1317 * Resets internal stack and startTime, enables Logger, and fires logResetEvent.
1318 *
1319 * @method reset
1320 */
1321YAHOO.widget.Logger.reset = function() {
1322 this._stack = [];
1323 this._startTime = new Date().getTime();
1324 this.loggerEnabled = true;
1325 this.log("Logger reset");
1326 this.logResetEvent.fire();
1327};
1328
1329/**
1330 * Public accessor to internal stack of log message objects.
1331 *
1332 * @method getStack
1333 * @return {Object[]} Array of log message objects.
1334 */
1335YAHOO.widget.Logger.getStack = function() {
1336 return this._stack;
1337};
1338
1339/**
1340 * Public accessor to internal start time.
1341 *
1342 * @method getStartTime
1343 * @return {Date} Internal date of when Logger singleton was initialized.
1344 */
1345YAHOO.widget.Logger.getStartTime = function() {
1346 return this._startTime;
1347};
1348
1349/**
1350 * Disables output to the browser's global console.log() function, which is used
1351 * by the Firebug extension to Firefox as well as Safari.
1352 *
1353 * @method disableBrowserConsole
1354 */
1355YAHOO.widget.Logger.disableBrowserConsole = function() {
1356 YAHOO.log("Logger output to the function console.log() has been disabled.");
1357 this._browserConsoleEnabled = false;
1358};
1359
1360/**
1361 * Enables output to the browser's global console.log() function, which is used
1362 * by the Firebug extension to Firefox as well as Safari.
1363 *
1364 * @method enableBrowserConsole
1365 */
1366YAHOO.widget.Logger.enableBrowserConsole = function() {
1367 this._browserConsoleEnabled = true;
1368 YAHOO.log("Logger output to the function console.log() has been enabled.");
1369};
1370
1371/////////////////////////////////////////////////////////////////////////////
1372//
1373// Public events
1374//
1375/////////////////////////////////////////////////////////////////////////////
1376
1377 /**
1378 * Fired when a new category has been created.
1379 *
1380 * @event categoryCreateEvent
1381 * @param sCategory {String} Category name.
1382 */
1383YAHOO.widget.Logger.categoryCreateEvent =
1384 new YAHOO.util.CustomEvent("categoryCreate", this, true);
1385
1386 /**
1387 * Fired when a new source has been named.
1388 *
1389 * @event sourceCreateEvent
1390 * @param sSource {String} Source name.
1391 */
1392YAHOO.widget.Logger.sourceCreateEvent =
1393 new YAHOO.util.CustomEvent("sourceCreate", this, true);
1394
1395 /**
1396 * Fired when a new log message has been created.
1397 *
1398 * @event newLogEvent
1399 * @param sMsg {String} Log message.
1400 */
1401YAHOO.widget.Logger.newLogEvent = new YAHOO.util.CustomEvent("newLog", this, true);
1402
1403/**
1404 * Fired when the Logger has been reset has been created.
1405 *
1406 * @event logResetEvent
1407 */
1408YAHOO.widget.Logger.logResetEvent = new YAHOO.util.CustomEvent("logReset", this, true);
1409
1410/////////////////////////////////////////////////////////////////////////////
1411//
1412// Private methods
1413//
1414/////////////////////////////////////////////////////////////////////////////
1415
1416/**
1417 * Creates a new category of log messages and fires categoryCreateEvent.
1418 *
1419 * @method _createNewCategory
1420 * @param sCategory {String} Category name.
1421 * @private
1422 */
1423YAHOO.widget.Logger._createNewCategory = function(sCategory) {
1424 this.categories.push(sCategory);
1425 this.categoryCreateEvent.fire(sCategory);
1426};
1427
1428/**
1429 * Checks to see if a category has already been created.
1430 *
1431 * @method _isNewCategory
1432 * @param sCategory {String} Category name.
1433 * @return {Boolean} Returns true if category is unknown, else returns false.
1434 * @private
1435 */
1436YAHOO.widget.Logger._isNewCategory = function(sCategory) {
1437 for(var i=0; i < this.categories.length; i++) {
1438 if(sCategory == this.categories[i]) {
1439 return false;
1440 }
1441 }
1442 return true;
1443};
1444
1445/**
1446 * Creates a new source of log messages and fires sourceCreateEvent.
1447 *
1448 * @method _createNewSource
1449 * @param sSource {String} Source name.
1450 * @private
1451 */
1452YAHOO.widget.Logger._createNewSource = function(sSource) {
1453 this.sources.push(sSource);
1454 this.sourceCreateEvent.fire(sSource);
1455};
1456
1457/**
1458 * Checks to see if a source already exists.
1459 *
1460 * @method _isNewSource
1461 * @param sSource {String} Source name.
1462 * @return {Boolean} Returns true if source is unknown, else returns false.
1463 * @private
1464 */
1465YAHOO.widget.Logger._isNewSource = function(sSource) {
1466 if(sSource) {
1467 for(var i=0; i < this.sources.length; i++) {
1468 if(sSource == this.sources[i]) {
1469 return false;
1470 }
1471 }
1472 return true;
1473 }
1474};
1475
1476/**
1477 * Outputs a log message to global console.log() function.
1478 *
1479 * @method _printToBrowserConsole
1480 * @param oEntry {Object} Log entry object.
1481 * @private
1482 */
1483YAHOO.widget.Logger._printToBrowserConsole = function(oEntry) {
1484 if(window.console && console.log) {
1485 var category = oEntry.category;
1486 var label = oEntry.category.substring(0,4).toUpperCase();
1487
1488 var time = oEntry.time;
1489 if (time.toLocaleTimeString) {
1490 var localTime = time.toLocaleTimeString();
1491 }
1492 else {
1493 localTime = time.toString();
1494 }
1495
1496 var msecs = time.getTime();
1497 var elapsedTime = (YAHOO.widget.Logger._lastTime) ?
1498 (msecs - YAHOO.widget.Logger._lastTime) : 0;
1499 YAHOO.widget.Logger._lastTime = msecs;
1500
1501 var output =
1502 localTime + " (" +
1503 elapsedTime + "ms): " +
1504 oEntry.source + ": " +
1505 oEntry.msg;
1506
1507 console.log(output);
1508 }
1509};
1510
1511/////////////////////////////////////////////////////////////////////////////
1512//
1513// Private event handlers
1514//
1515/////////////////////////////////////////////////////////////////////////////
1516
1517/**
1518 * Handles logging of messages due to window error events.
1519 *
1520 * @method _onWindowError
1521 * @param sMsg {String} The error message.
1522 * @param sUrl {String} URL of the error.
1523 * @param sLine {String} Line number of the error.
1524 * @private
1525 */
1526YAHOO.widget.Logger._onWindowError = function(sMsg,sUrl,sLine) {
1527 // Logger is not in scope of this event handler
1528 try {
1529 YAHOO.widget.Logger.log(sMsg+' ('+sUrl+', line '+sLine+')', "window");
1530 if(YAHOO.widget.Logger._origOnWindowError) {
1531 YAHOO.widget.Logger._origOnWindowError();
1532 }
1533 }
1534 catch(e) {
1535 return false;
1536 }
1537};
1538
1539/////////////////////////////////////////////////////////////////////////////
1540//
1541// Enable handling of native JavaScript errors
1542// NB: Not all browsers support the window.onerror event
1543//
1544/////////////////////////////////////////////////////////////////////////////
1545
1546if(window.onerror) {
1547 // Save any previously defined handler to call
1548 YAHOO.widget.Logger._origOnWindowError = window.onerror;
1549}
1550window.onerror = YAHOO.widget.Logger._onWindowError;
1551
1552/////////////////////////////////////////////////////////////////////////////
1553//
1554// First log
1555//
1556/////////////////////////////////////////////////////////////////////////////
1557
1558YAHOO.widget.Logger.log("Logger initialized");
1559
diff --git a/frontend/beta/js/YUI/menu.js b/frontend/beta/js/YUI/menu.js
new file mode 100644
index 0000000..50eb0cf
--- a/dev/null
+++ b/frontend/beta/js/YUI/menu.js
@@ -0,0 +1,6780 @@
1/*
2Copyright (c) 2006, Yahoo! Inc. All rights reserved.
3Code licensed under the BSD License:
4http://developer.yahoo.com/yui/license.txt
5version: 0.12.0
6*/
7
8/**
9* @module menu
10* @description <p>The Menu Library features a collection of widgets that make
11* it easy to add menus to your website or web application. With the Menu
12* Library you can create website fly-out menus, customized context menus, or
13* application-style menu bars with just a small amount of scripting.</p>
14* <ul>
15* <li>Screen-reader accessibility.</li>
16* <li>Keyboard and mouse navigation.</li>
17* <li>A rich event model that provides access to all of a menu's
18* interesting moments.</li>
19* <li>Support for
20* <a href="http://en.wikipedia.org/wiki/Progressive_Enhancement">Progressive
21* Enhancement</a>; Menus can be created from simple,
22* semantic markup on the page or purely through JavaScript.</li>
23* </ul>
24* @title Menu Library
25* @namespace YAHOO.widget
26* @requires Event, Dom, Container
27*/
28(function() {
29
30var Dom = YAHOO.util.Dom;
31var Event = YAHOO.util.Event;
32
33/**
34* Singleton that manages a collection of all menus and menu items. Listens for
35* DOM events at the document level and dispatches the events to the
36* corresponding menu or menu item.
37*
38* @namespace YAHOO.widget
39* @class MenuManager
40* @static
41*/
42YAHOO.widget.MenuManager = new function() {
43
44 // Private member variables
45
46 // Flag indicating if the DOM event handlers have been attached
47
48 var m_bInitializedEventHandlers = false;
49
50 // Collection of menus
51
52 var m_oMenus = {};
53
54
55 // Collection of menu items
56
57 var m_oItems = {};
58
59 // Collection of visible menus
60
61 var m_oVisibleMenus = {};
62
63 // Logger
64
65
66 // Private methods
67
68 /**
69 * Adds an item to the collection of known menu items.
70 * @private
71 * @param {YAHOO.widget.MenuItem} p_oItem Object specifying the MenuItem
72 * instance to be added.
73 */
74 var addItem = function(p_oItem) {
75
76 var sYUIId = Dom.generateId();
77
78 if(p_oItem && m_oItems[sYUIId] != p_oItem) {
79
80 p_oItem.element.setAttribute("yuiid", sYUIId);
81
82 m_oItems[sYUIId] = p_oItem;
83
84 p_oItem.destroyEvent.subscribe(onItemDestroy, p_oItem);
85
86
87 }
88
89 };
90
91 /**
92 * Removes an item from the collection of known menu items.
93 * @private
94 * @param {YAHOO.widget.MenuItem} p_oItem Object specifying the MenuItem
95 * instance to be removed.
96 */
97 var removeItem = function(p_oItem) {
98
99 var sYUIId = p_oItem.element.getAttribute("yuiid");
100
101 if(sYUIId && m_oItems[sYUIId]) {
102
103 delete m_oItems[sYUIId];
104
105
106 }
107
108 };
109
110 /**
111 * Finds the root DIV node of a menu or the root LI node of a menu item.
112 * @private
113 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
114 * one-html.html#ID-58190037">HTMLElement</a>} p_oElement Object specifying
115 * an HTML element.
116 */
117 var getMenuRootElement = function(p_oElement) {
118
119 var oParentNode;
120
121 if(p_oElement && p_oElement.tagName) {
122
123 switch(p_oElement.tagName.toUpperCase()) {
124
125 case "DIV":
126
127 oParentNode = p_oElement.parentNode;
128
129 // Check if the DIV is the inner "body" node of a menu
130
131 if(
132 Dom.hasClass(p_oElement, "bd") &&
133 oParentNode &&
134 oParentNode.tagName &&
135 oParentNode.tagName.toUpperCase() == "DIV"
136 ) {
137
138 return oParentNode;
139
140 }
141 else {
142
143 return p_oElement;
144
145 }
146
147 break;
148
149 case "LI":
150
151 return p_oElement;
152
153 default:
154
155 oParentNode = p_oElement.parentNode;
156
157 if(oParentNode) {
158
159 return getMenuRootElement(oParentNode);
160
161 }
162
163 break;
164
165 }
166
167 }
168
169 };
170
171 // Private event handlers
172
173 /**
174 * Generic, global event handler for all of a menu's DOM-based
175 * events. This listens for events against the document object. If the
176 * target of a given event is a member of a menu or menu item's DOM, the
177 * instance's corresponding Custom Event is fired.
178 * @private
179 * @param {Event} p_oEvent Object representing the DOM event object passed
180 * back by the event utility (YAHOO.util.Event).
181 */
182 var onDOMEvent = function(p_oEvent) {
183
184 // Get the target node of the DOM event
185
186 var oTarget = Event.getTarget(p_oEvent);
187
188 // See if the target of the event was a menu, or a menu item
189
190 var oElement = getMenuRootElement(oTarget);
191
192 var oMenuItem;
193 var oMenu;
194
195 if(oElement) {
196
197 var sTagName = oElement.tagName.toUpperCase();
198
199 if(sTagName == "LI") {
200
201 var sYUIId = oElement.getAttribute("yuiid");
202
203 if(sYUIId) {
204
205 oMenuItem = m_oItems[sYUIId];
206 oMenu = oMenuItem.parent;
207
208 }
209
210 }
211 else if(sTagName == "DIV") {
212
213 if(oElement.id) {
214
215 oMenu = m_oMenus[oElement.id];
216
217 }
218
219 }
220
221 }
222
223 if(oMenu) {
224
225 // Map of DOM event names to CustomEvent names
226
227 var oEventTypes = {
228 "click": "clickEvent",
229 "mousedown": "mouseDownEvent",
230 "mouseup": "mouseUpEvent",
231 "mouseover": "mouseOverEvent",
232 "mouseout": "mouseOutEvent",
233 "keydown": "keyDownEvent",
234 "keyup": "keyUpEvent",
235 "keypress": "keyPressEvent"
236 };
237
238 var sCustomEventType = oEventTypes[p_oEvent.type];
239
240 // Fire the Custom Even that corresponds the current DOM event
241
242 if(oMenuItem && !oMenuItem.cfg.getProperty("disabled")) {
243
244 oMenuItem[sCustomEventType].fire(p_oEvent);
245
246 }
247
248 oMenu[sCustomEventType].fire(p_oEvent, oMenuItem);
249
250 }
251 else if(p_oEvent.type == "mousedown") {
252
253 /*
254 If the target of the event wasn't a menu, hide all
255 dynamically positioned menus
256 */
257
258 var oActiveItem;
259
260 for(var i in m_oMenus) {
261
262 if(m_oMenus.hasOwnProperty(i)) {
263
264 oMenu = m_oMenus[i];
265
266 if(
267 oMenu.cfg.getProperty("clicktohide") &&
268 oMenu.cfg.getProperty("position") == "dynamic"
269 ) {
270
271 oMenu.hide();
272
273 }
274 else {
275
276 oMenu.clearActiveItem(true);
277
278 }
279
280 }
281
282 }
283
284 }
285
286 };
287
288 /**
289 * "destroy" event handler for a menu.
290 * @private
291 * @param {String} p_sType String representing the name of the event that
292 * was fired.
293 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
294 * @param {YAHOO.widget.Menu} p_oMenu Object representing the menu that
295 * fired the event.
296 */
297 var onMenuDestroy = function(p_sType, p_aArgs, p_oMenu) {
298
299 this.removeMenu(p_oMenu);
300
301 };
302
303 /**
304 * "destroy" event handler for a MenuItem instance.
305 * @private
306 * @param {String} p_sType String representing the name of the event that
307 * was fired.
308 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
309 * @param {YAHOO.widget.MenuItem} p_oItem Object representing the menu item
310 * that fired the event.
311 */
312 var onItemDestroy = function(p_sType, p_aArgs, p_oItem) {
313
314 var sYUIId = p_oItem.element.getAttribute("yuiid");
315
316 if(sYUIId) {
317
318 delete m_oItems[sYUIId];
319
320 }
321
322 };
323
324 /**
325 * Event handler for when the "visible" configuration property
326 * of a Menu instance changes.
327 * @private
328 * @param {String} p_sType String representing the name of the event that
329 * was fired.
330 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
331 * @param {YAHOO.widget.Menu} p_oMenu Object representing the menu that
332 * fired the event.
333 */
334 var onMenuVisibleConfigChange = function(p_sType, p_aArgs, p_oMenu) {
335
336 var bVisible = p_aArgs[0];
337
338 if(bVisible) {
339
340 m_oVisibleMenus[p_oMenu.id] = p_oMenu;
341
342
343 }
344 else if(m_oVisibleMenus[p_oMenu.id]) {
345
346 delete m_oVisibleMenus[p_oMenu.id];
347
348
349 }
350
351 };
352
353 /**
354 * "itemadded" event handler for a Menu instance.
355 * @private
356 * @param {String} p_sType String representing the name of the event that
357 * was fired.
358 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
359 */
360 var onItemAdded = function(p_sType, p_aArgs) {
361
362 addItem(p_aArgs[0]);
363
364 };
365
366
367 /**
368 * "itemremoved" event handler for a Menu instance.
369 * @private
370 * @param {String} p_sType String representing the name of the event that
371 * was fired.
372 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
373 */
374 var onItemRemoved = function(p_sType, p_aArgs) {
375
376 removeItem(p_aArgs[0]);
377
378 };
379
380 // Privileged methods
381
382 /**
383 * @method addMenu
384 * @description Adds a menu to the collection of known menus.
385 * @param {YAHOO.widget.Menu} p_oMenu Object specifying the Menu instance
386 * to be added.
387 */
388 this.addMenu = function(p_oMenu) {
389
390 if(p_oMenu && p_oMenu.id && !m_oMenus[p_oMenu.id]) {
391
392 m_oMenus[p_oMenu.id] = p_oMenu;
393
394
395 if(!m_bInitializedEventHandlers) {
396
397 var oDoc = document;
398
399 Event.addListener(oDoc, "mouseover", onDOMEvent, this, true);
400 Event.addListener(oDoc, "mouseout", onDOMEvent, this, true);
401 Event.addListener(oDoc, "mousedown", onDOMEvent, this, true);
402 Event.addListener(oDoc, "mouseup", onDOMEvent, this, true);
403 Event.addListener(oDoc, "click", onDOMEvent, this, true);
404 Event.addListener(oDoc, "keydown", onDOMEvent, this, true);
405 Event.addListener(oDoc, "keyup", onDOMEvent, this, true);
406 Event.addListener(oDoc, "keypress", onDOMEvent, this, true);
407
408 m_bInitializedEventHandlers = true;
409
410
411 }
412
413 p_oMenu.destroyEvent.subscribe(onMenuDestroy, p_oMenu, this);
414
415 p_oMenu.cfg.subscribeToConfigEvent(
416 "visible",
417 onMenuVisibleConfigChange,
418 p_oMenu
419 );
420
421 p_oMenu.itemAddedEvent.subscribe(onItemAdded);
422 p_oMenu.itemRemovedEvent.subscribe(onItemRemoved);
423
424
425 }
426
427 };
428
429 /**
430 * @method removeMenu
431 * @description Removes a menu from the collection of known menus.
432 * @param {YAHOO.widget.Menu} p_oMenu Object specifying the Menu instance
433 * to be removed.
434 */
435 this.removeMenu = function(p_oMenu) {
436
437 if(p_oMenu && m_oMenus[p_oMenu.id]) {
438
439 delete m_oMenus[p_oMenu.id];
440
441
442 }
443
444 };
445
446 /**
447 * @method hideVisible
448 * @description Hides all visible, dynamically positioned menus.
449 */
450 this.hideVisible = function() {
451
452 var oMenu;
453
454 for(var i in m_oVisibleMenus) {
455
456 if(m_oVisibleMenus.hasOwnProperty(i)) {
457
458 oMenu = m_oVisibleMenus[i];
459
460 if(oMenu.cfg.getProperty("position") == "dynamic") {
461
462 oMenu.hide();
463
464 }
465
466 }
467
468 }
469
470 };
471
472 /**
473 * @method getMenus
474 * @description Returns an array of all menus registered with the
475 * menu manger.
476 * @return {Array}
477 */
478 this.getMenus = function() {
479
480 return m_oMenus;
481
482 };
483
484 /**
485 * @method getMenu
486 * @description Returns a menu with the specified id.
487 * @param {String} p_sId String specifying the id of the menu to
488 * be retrieved.
489 * @return {YAHOO.widget.Menu}
490 */
491 this.getMenu = function(p_sId) {
492
493 if(m_oMenus[p_sId]) {
494
495 return m_oMenus[p_sId];
496
497 }
498
499 };
500
501
502 /**
503 * @method toString
504 * @description Returns a string representing the menu manager.
505 * @return {String}
506 */
507 this.toString = function() {
508
509 return ("MenuManager");
510
511 };
512
513};
514
515})();
516
517(function() {
518
519var Dom = YAHOO.util.Dom;
520var Event = YAHOO.util.Event;
521
522/**
523* The Menu class creates a container that holds a vertical list representing
524* a set of options or commands. Menu is the base class for all
525* menu containers.
526* @param {String} p_oElement String specifying the id attribute of the
527* <code>&#60;div&#62;</code> element of the menu.
528* @param {String} p_oElement String specifying the id attribute of the
529* <code>&#60;select&#62;</code> element to be used as the data source
530* for the menu.
531* @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
532* level-one-html.html#ID-22445964">HTMLDivElement</a>} p_oElement Object
533* specifying the <code>&#60;div&#62;</code> element of the menu.
534* @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
535* level-one-html.html#ID-94282980">HTMLSelectElement</a>} p_oElement
536* Object specifying the <code>&#60;select&#62;</code> element to be used as
537* the data source for the menu.
538* @param {Object} p_oConfig Optional. Object literal specifying the
539* configuration for the menu. See configuration class documentation for
540* more details.
541* @namespace YAHOO.widget
542* @class Menu
543* @constructor
544* @extends YAHOO.widget.Overlay
545*/
546YAHOO.widget.Menu = function(p_oElement, p_oConfig) {
547
548 if(p_oConfig) {
549
550 this.parent = p_oConfig.parent;
551
552 this.lazyLoad = p_oConfig.lazyLoad || p_oConfig.lazyload;
553
554 this.itemData = p_oConfig.itemData || p_oConfig.itemdata;
555
556 }
557
558 YAHOO.widget.Menu.superclass.constructor.call(
559 this,
560 p_oElement,
561 p_oConfig
562 );
563
564};
565
566YAHOO.extend(YAHOO.widget.Menu, YAHOO.widget.Overlay, {
567
568// Constants
569
570/**
571* @property CSS_CLASS_NAME
572* @description String representing the CSS class(es) to be applied to the
573* menu's <code>&#60;div&#62;</code> element.
574* @default "yuimenu"
575* @final
576* @type String
577*/
578CSS_CLASS_NAME: "yuimenu",
579
580/**
581* @property ITEM_TYPE
582* @description Object representing the type of menu item to instantiate and
583* add when parsing the child nodes (either <code>&#60;li&#62;</code> element,
584* <code>&#60;optgroup&#62;</code> element or <code>&#60;option&#62;</code>)
585* of the menu's source HTML element.
586* @default YAHOO.widget.MenuItem
587* @final
588* @type YAHOO.widget.MenuItem
589*/
590ITEM_TYPE: null,
591
592/**
593* @property GROUP_TITLE_TAG_NAME
594* @description String representing the tagname of the HTML element used to
595* title the menu's item groups.
596* @default H6
597* @final
598* @type String
599*/
600GROUP_TITLE_TAG_NAME: "h6",
601
602// Private properties
603
604/**
605* @property _nHideDelayId
606* @description Number representing the time-out setting used to cancel the
607* hiding of a menu.
608* @default null
609* @private
610* @type Number
611*/
612_nHideDelayId: null,
613
614/**
615* @property _nShowDelayId
616* @description Number representing the time-out setting used to cancel the
617* showing of a menu.
618* @default null
619* @private
620* @type Number
621*/
622_nShowDelayId: null,
623
624/**
625* @property _hideDelayEventHandlersAssigned
626* @description Boolean indicating if the "mouseover" and "mouseout" event
627* handlers used for hiding the menu via a call to "window.setTimeout" have
628* already been assigned.
629* @default false
630* @private
631* @type Boolean
632*/
633_hideDelayEventHandlersAssigned: false,
634
635/**
636* @property _bHandledMouseOverEvent
637* @description Boolean indicating the current state of the menu's
638* "mouseover" event.
639* @default false
640* @private
641* @type Boolean
642*/
643_bHandledMouseOverEvent: false,
644
645/**
646* @property _bHandledMouseOutEvent
647* @description Boolean indicating the current state of the menu's
648* "mouseout" event.
649* @default false
650* @private
651* @type Boolean
652*/
653_bHandledMouseOutEvent: false,
654
655/**
656* @property _aGroupTitleElements
657* @description Array of HTML element used to title groups of menu items.
658* @default []
659* @private
660* @type Array
661*/
662_aGroupTitleElements: null,
663
664/**
665* @property _aItemGroups
666* @description Array of menu items.
667* @default []
668* @private
669* @type Array
670*/
671_aItemGroups: null,
672
673/**
674* @property _aListElements
675* @description Array of <code>&#60;ul&#62;</code> elements, each of which is
676* the parent node for each item's <code>&#60;li&#62;</code> element.
677* @default []
678* @private
679* @type Array
680*/
681_aListElements: null,
682
683// Public properties
684
685/**
686* @property lazyLoad
687* @description Boolean indicating if the menu's "lazy load" feature is
688* enabled. If set to "true," initialization and rendering of the menu's
689* items will be deferred until the first time it is made visible. This
690* property should be set via the constructor using the configuration
691* object literal.
692* @default false
693* @type Boolean
694*/
695lazyLoad: false,
696
697/**
698* @property itemData
699* @description Array of items to be added to the menu. The array can contain
700* strings representing the text for each item to be created, object literals
701* representing the menu item configuration properties, or MenuItem instances.
702* This property should be set via the constructor using the configuration
703* object literal.
704* @default null
705* @type Array
706*/
707itemData: null,
708
709/**
710* @property activeItem
711* @description Object reference to the item in the menu that has focus.
712* @default null
713* @type YAHOO.widget.MenuItem
714*/
715activeItem: null,
716
717/**
718* @property parent
719* @description Object reference to the menu's parent menu or menu item.
720* This property can be set via the constructor using the configuration
721* object literal.
722* @default null
723* @type YAHOO.widget.MenuItem
724*/
725parent: null,
726
727/**
728* @property srcElement
729* @description Object reference to the HTML element (either
730* <code>&#60;select&#62;</code> or <code>&#60;div&#62;</code>) used to
731* create the menu.
732* @default null
733* @type <a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
734* level-one-html.html#ID-94282980">HTMLSelectElement</a>|<a
735* href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-one-html.
736* html#ID-22445964">HTMLDivElement</a>
737*/
738srcElement: null,
739
740// Events
741
742/**
743* @event mouseOverEvent
744* @description Fires when the mouse has entered the menu. Passes back
745* the DOM Event object as an argument.
746*/
747mouseOverEvent: null,
748
749/**
750* @event mouseOutEvent
751* @description Fires when the mouse has left the menu. Passes back the DOM
752* Event object as an argument.
753* @type YAHOO.util.CustomEvent
754*/
755mouseOutEvent: null,
756
757/**
758* @event mouseDownEvent
759* @description Fires when the user mouses down on the menu. Passes back the
760* DOM Event object as an argument.
761* @type YAHOO.util.CustomEvent
762*/
763mouseDownEvent: null,
764
765/**
766* @event mouseUpEvent
767* @description Fires when the user releases a mouse button while the mouse is
768* over the menu. Passes back the DOM Event object as an argument.
769* @type YAHOO.util.CustomEvent
770*/
771mouseUpEvent: null,
772
773/**
774* @event clickEvent
775* @description Fires when the user clicks the on the menu. Passes back the
776* DOM Event object as an argument.
777* @type YAHOO.util.CustomEvent
778*/
779clickEvent: null,
780
781/**
782* @event keyPressEvent
783* @description Fires when the user presses an alphanumeric key when one of the
784* menu's items has focus. Passes back the DOM Event object as an argument.
785* @type YAHOO.util.CustomEvent
786*/
787keyPressEvent: null,
788
789/**
790* @event keyDownEvent
791* @description Fires when the user presses a key when one of the menu's items
792* has focus. Passes back the DOM Event object as an argument.
793* @type YAHOO.util.CustomEvent
794*/
795keyDownEvent: null,
796
797/**
798* @event keyUpEvent
799* @description Fires when the user releases a key when one of the menu's items
800* has focus. Passes back the DOM Event object as an argument.
801* @type YAHOO.util.CustomEvent
802*/
803keyUpEvent: null,
804
805/**
806* @event itemAddedEvent
807* @description Fires when an item is added to the menu.
808* @type YAHOO.util.CustomEvent
809*/
810itemAddedEvent: null,
811
812/**
813* @event itemRemovedEvent
814* @description Fires when an item is removed to the menu.
815* @type YAHOO.util.CustomEvent
816*/
817itemRemovedEvent: null,
818
819/**
820* @method init
821* @description The Menu class's initialization method. This method is
822* automatically called by the constructor, and sets up all DOM references
823* for pre-existing markup, and creates required markup if it is not
824* already present.
825* @param {String} p_oElement String specifying the id attribute of the
826* <code>&#60;div&#62;</code> element of the menu.
827* @param {String} p_oElement String specifying the id attribute of the
828* <code>&#60;select&#62;</code> element to be used as the data source
829* for the menu.
830* @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
831* level-one-html.html#ID-22445964">HTMLDivElement</a>} p_oElement Object
832* specifying the <code>&#60;div&#62;</code> element of the menu.
833* @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
834* level-one-html.html#ID-94282980">HTMLSelectElement</a>} p_oElement
835* Object specifying the <code>&#60;select&#62;</code> element to be used as
836* the data source for the menu.
837* @param {Object} p_oConfig Optional. Object literal specifying the
838* configuration for the menu. See configuration class documentation for
839* more details.
840*/
841init: function(p_oElement, p_oConfig) {
842
843 this._aItemGroups = [];
844 this._aListElements = [];
845 this._aGroupTitleElements = [];
846
847 if(!this.ITEM_TYPE) {
848
849 this.ITEM_TYPE = YAHOO.widget.MenuItem;
850
851 }
852
853 var oElement;
854
855 if(typeof p_oElement == "string") {
856
857 oElement = document.getElementById(p_oElement);
858
859 }
860 else if(p_oElement.tagName) {
861
862 oElement = p_oElement;
863
864 }
865
866 if(oElement && oElement.tagName) {
867
868 switch(oElement.tagName.toUpperCase()) {
869
870 case "DIV":
871
872 this.srcElement = oElement;
873
874 if(!oElement.id) {
875
876 oElement.setAttribute("id", Dom.generateId());
877
878 }
879
880 /*
881 Note: we don't pass the user config in here yet
882 because we only want it executed once, at the lowest
883 subclass level.
884 */
885
886 YAHOO.widget.Menu.superclass.init.call(this, oElement);
887
888 this.beforeInitEvent.fire(YAHOO.widget.Menu);
889
890
891 break;
892
893 case "SELECT":
894
895 this.srcElement = oElement;
896
897
898 /*
899 The source element is not something that we can use
900 outright, so we need to create a new Overlay
901
902 Note: we don't pass the user config in here yet
903 because we only want it executed once, at the lowest
904 subclass level.
905 */
906
907 YAHOO.widget.Menu.superclass.init.call(this, Dom.generateId());
908
909 this.beforeInitEvent.fire(YAHOO.widget.Menu);
910
911 break;
912
913 }
914
915 }
916 else {
917
918 /*
919 Note: we don't pass the user config in here yet
920 because we only want it executed once, at the lowest
921 subclass level.
922 */
923
924 YAHOO.widget.Menu.superclass.init.call(this, p_oElement);
925
926 this.beforeInitEvent.fire(YAHOO.widget.Menu);
927
928 }
929
930 if(this.element) {
931
932 var oEl = this.element;
933
934 Dom.addClass(oEl, this.CSS_CLASS_NAME);
935
936 // Subscribe to Custom Events
937
938 this.initEvent.subscribe(this._onInit, this, true);
939 this.beforeRenderEvent.subscribe(this._onBeforeRender, this, true);
940 this.renderEvent.subscribe(this._onRender, this, true);
941 this.beforeShowEvent.subscribe(this._onBeforeShow, this, true);
942 this.showEvent.subscribe(this._onShow, this, true);
943 this.beforeHideEvent.subscribe(this._onBeforeHide, this, true);
944 this.mouseOverEvent.subscribe(this._onMouseOver, this, true);
945 this.mouseOutEvent.subscribe(this._onMouseOut, this, true);
946 this.clickEvent.subscribe(this._onClick, this, true);
947 this.keyDownEvent.subscribe(this._onKeyDown, this, true);
948
949 if(p_oConfig) {
950
951 this.cfg.applyConfig(p_oConfig, true);
952
953 }
954
955 // Register the Menu instance with the MenuManager
956
957 YAHOO.widget.MenuManager.addMenu(this);
958
959
960 this.initEvent.fire(YAHOO.widget.Menu);
961
962 }
963
964},
965
966// Private methods
967
968/**
969* @method _initSubTree
970* @description Iterates the childNodes of the source element to find nodes
971* used to instantiate menu and menu items.
972* @private
973*/
974_initSubTree: function() {
975
976 var oNode;
977
978 if(this.srcElement.tagName == "DIV") {
979
980 /*
981 Populate the collection of item groups and item
982 group titles
983 */
984
985 oNode = this.body.firstChild;
986
987 var nGroup = 0;
988 var sGroupTitleTagName = this.GROUP_TITLE_TAG_NAME.toUpperCase();
989
990 do {
991
992 if(oNode && oNode.tagName) {
993
994 switch(oNode.tagName.toUpperCase()) {
995
996 case sGroupTitleTagName:
997
998 this._aGroupTitleElements[nGroup] = oNode;
999
1000 break;
1001
1002 case "UL":
1003
1004 this._aListElements[nGroup] = oNode;
1005 this._aItemGroups[nGroup] = [];
1006 nGroup++;
1007
1008 break;
1009
1010 }
1011
1012 }
1013
1014 }
1015 while((oNode = oNode.nextSibling));
1016
1017 /*
1018 Apply the "first-of-type" class to the first UL to mimic
1019 the "first-of-type" CSS3 psuedo class.
1020 */
1021
1022 if(this._aListElements[0]) {
1023
1024 Dom.addClass(this._aListElements[0], "first-of-type");
1025
1026 }
1027
1028 }
1029
1030 oNode = null;
1031
1032 if(this.srcElement.tagName) {
1033
1034 switch(this.srcElement.tagName.toUpperCase()) {
1035
1036 case "DIV":
1037
1038 if(this._aListElements.length > 0) {
1039
1040
1041 var i = this._aListElements.length - 1;
1042
1043 do {
1044
1045 oNode = this._aListElements[i].firstChild;
1046
1047
1048 do {
1049
1050 if(oNode && oNode.tagName) {
1051
1052 switch(oNode.tagName.toUpperCase()) {
1053
1054 case "LI":
1055
1056
1057 this.addItem(
1058 new this.ITEM_TYPE(
1059 oNode,
1060 { parent: this }
1061 ),
1062 i
1063 );
1064
1065 break;
1066
1067 }
1068
1069 }
1070
1071 }
1072 while((oNode = oNode.nextSibling));
1073
1074 }
1075 while(i--);
1076
1077 }
1078
1079 break;
1080
1081 case "SELECT":
1082
1083
1084 oNode = this.srcElement.firstChild;
1085
1086 do {
1087
1088 if(oNode && oNode.tagName) {
1089
1090 switch(oNode.tagName.toUpperCase()) {
1091
1092 case "OPTGROUP":
1093 case "OPTION":
1094
1095
1096 this.addItem(
1097 new this.ITEM_TYPE(
1098 oNode,
1099 { parent: this }
1100 )
1101 );
1102
1103 break;
1104
1105 }
1106
1107 }
1108
1109 }
1110 while((oNode = oNode.nextSibling));
1111
1112 break;
1113
1114 }
1115
1116 }
1117
1118},
1119
1120/**
1121* @method _getFirstEnabledItem
1122* @description Returns the first enabled item in the menu.
1123* @return {YAHOO.widget.MenuItem}
1124* @private
1125*/
1126_getFirstEnabledItem: function() {
1127
1128 var nGroups = this._aItemGroups.length;
1129 var oItem;
1130 var aItemGroup;
1131
1132 for(var i=0; i<nGroups; i++) {
1133
1134 aItemGroup = this._aItemGroups[i];
1135
1136 if(aItemGroup) {
1137
1138 var nItems = aItemGroup.length;
1139
1140 for(var n=0; n<nItems; n++) {
1141
1142 oItem = aItemGroup[n];
1143
1144 if(
1145 !oItem.cfg.getProperty("disabled") &&
1146 oItem.element.style.display != "none"
1147 ) {
1148
1149 return oItem;
1150
1151 }
1152
1153 oItem = null;
1154
1155 }
1156
1157 }
1158
1159 }
1160
1161},
1162
1163/**
1164* @method _checkPosition
1165* @description Checks to make sure that the value of the "position" property
1166* is one of the supported strings. Returns true if the position is supported.
1167* @private
1168* @param {Object} p_sPosition String specifying the position of the menu.
1169* @return {Boolean}
1170*/
1171_checkPosition: function(p_sPosition) {
1172
1173 if(typeof p_sPosition == "string") {
1174
1175 var sPosition = p_sPosition.toLowerCase();
1176
1177 return ("dynamic,static".indexOf(sPosition) != -1);
1178
1179 }
1180
1181},
1182
1183/**
1184* @method _addItemToGroup
1185* @description Adds a menu item to a group.
1186* @private
1187* @param {Number} p_nGroupIndex Number indicating the group to which the
1188* item belongs.
1189* @param {YAHOO.widget.MenuItem} p_oItem Object reference for the MenuItem
1190* instance to be added to the menu.
1191* @param {String} p_oItem String specifying the text of the item to be added
1192* to the menu.
1193* @param {Object} p_oItem Object literal containing a set of menu item
1194* configuration properties.
1195* @param {Number} p_nItemIndex Optional. Number indicating the index at
1196* which the menu item should be added.
1197* @return {YAHOO.widget.MenuItem}
1198*/
1199_addItemToGroup: function(p_nGroupIndex, p_oItem, p_nItemIndex) {
1200
1201 var oItem;
1202
1203 if(p_oItem instanceof this.ITEM_TYPE) {
1204
1205 oItem = p_oItem;
1206 oItem.parent = this;
1207
1208 }
1209 else if(typeof p_oItem == "string") {
1210
1211 oItem = new this.ITEM_TYPE(p_oItem, { parent: this });
1212
1213 }
1214 else if(typeof p_oItem == "object" && p_oItem.text) {
1215
1216 var sText = p_oItem.text;
1217
1218 delete p_oItem["text"];
1219
1220 p_oItem.parent = this;
1221
1222 oItem = new this.ITEM_TYPE(sText, p_oItem);
1223
1224 }
1225
1226 if(oItem) {
1227
1228 var nGroupIndex = typeof p_nGroupIndex == "number" ? p_nGroupIndex : 0;
1229
1230 var aGroup = this._getItemGroup(nGroupIndex);
1231
1232 var oGroupItem;
1233
1234 if(!aGroup) {
1235
1236 aGroup = this._createItemGroup(nGroupIndex);
1237
1238 }
1239
1240 if(typeof p_nItemIndex == "number") {
1241
1242 var bAppend = (p_nItemIndex >= aGroup.length);
1243
1244 if(aGroup[p_nItemIndex]) {
1245
1246 aGroup.splice(p_nItemIndex, 0, oItem);
1247
1248 }
1249 else {
1250
1251 aGroup[p_nItemIndex] = oItem;
1252
1253 }
1254
1255 oGroupItem = aGroup[p_nItemIndex];
1256
1257 if(oGroupItem) {
1258
1259 if(
1260 bAppend &&
1261 (
1262 !oGroupItem.element.parentNode ||
1263 oGroupItem.element.parentNode.nodeType == 11
1264 )
1265 ) {
1266
1267 this._aListElements[nGroupIndex].appendChild(
1268 oGroupItem.element
1269 );
1270
1271 }
1272 else {
1273
1274
1275 /**
1276 * Returns the next sibling of an item in an array.
1277 * @private
1278 * @param {p_aArray} Array to search.
1279 * @param {p_nStartIndex} Number indicating the index to
1280 * start searching the array.
1281 * @return {Object}
1282 */
1283 var getNextItemSibling =
1284
1285 function(p_aArray, p_nStartIndex) {
1286
1287 return (
1288 p_aArray[p_nStartIndex] ||
1289 getNextItemSibling(
1290 p_aArray,
1291 (p_nStartIndex+1)
1292 )
1293 );
1294
1295 };
1296
1297
1298 var oNextItemSibling =
1299 getNextItemSibling(aGroup, (p_nItemIndex+1));
1300
1301 if(
1302 oNextItemSibling &&
1303 (
1304 !oGroupItem.element.parentNode ||
1305 oGroupItem.element.parentNode.nodeType == 11
1306 )
1307 ) {
1308
1309 this._aListElements[nGroupIndex].insertBefore(
1310 oGroupItem.element,
1311 oNextItemSibling.element
1312 );
1313
1314 }
1315
1316 }
1317
1318
1319 oGroupItem.parent = this;
1320
1321 this._subscribeToItemEvents(oGroupItem);
1322
1323 this._configureSubmenu(oGroupItem);
1324
1325 this._updateItemProperties(nGroupIndex);
1326
1327
1328 this.itemAddedEvent.fire(oGroupItem);
1329
1330 return oGroupItem;
1331
1332 }
1333
1334 }
1335 else {
1336
1337 var nItemIndex = aGroup.length;
1338
1339 aGroup[nItemIndex] = oItem;
1340
1341 oGroupItem = aGroup[nItemIndex];
1342
1343
1344 if(oGroupItem) {
1345
1346 if(
1347 !Dom.isAncestor(
1348 this._aListElements[nGroupIndex],
1349 oGroupItem.element
1350 )
1351 ) {
1352
1353 this._aListElements[nGroupIndex].appendChild(
1354 oGroupItem.element
1355 );
1356
1357 }
1358
1359 oGroupItem.element.setAttribute("groupindex", nGroupIndex);
1360 oGroupItem.element.setAttribute("index", nItemIndex);
1361
1362 oGroupItem.parent = this;
1363
1364 oGroupItem.index = nItemIndex;
1365 oGroupItem.groupIndex = nGroupIndex;
1366
1367 this._subscribeToItemEvents(oGroupItem);
1368
1369 this._configureSubmenu(oGroupItem);
1370
1371 if(nItemIndex === 0) {
1372
1373 Dom.addClass(oGroupItem.element, "first-of-type");
1374
1375 }
1376
1377
1378
1379 this.itemAddedEvent.fire(oGroupItem);
1380
1381 return oGroupItem;
1382
1383 }
1384
1385 }
1386
1387 }
1388
1389},
1390
1391/**
1392* @method _removeItemFromGroupByIndex
1393* @description Removes a menu item from a group by index. Returns the menu
1394* item that was removed.
1395* @private
1396* @param {Number} p_nGroupIndex Number indicating the group to which the menu
1397* item belongs.
1398* @param {Number} p_nItemIndex Number indicating the index of the menu item
1399* to be removed.
1400* @return {YAHOO.widget.MenuItem}
1401*/
1402_removeItemFromGroupByIndex: function(p_nGroupIndex, p_nItemIndex) {
1403
1404 var nGroupIndex = typeof p_nGroupIndex == "number" ? p_nGroupIndex : 0;
1405 var aGroup = this._getItemGroup(nGroupIndex);
1406
1407 if(aGroup) {
1408
1409 var aArray = aGroup.splice(p_nItemIndex, 1);
1410 var oItem = aArray[0];
1411
1412 if(oItem) {
1413
1414 // Update the index and className properties of each member
1415
1416 this._updateItemProperties(nGroupIndex);
1417
1418 if(aGroup.length === 0) {
1419
1420 // Remove the UL
1421
1422 var oUL = this._aListElements[nGroupIndex];
1423
1424 if(this.body && oUL) {
1425
1426 this.body.removeChild(oUL);
1427
1428 }
1429
1430 // Remove the group from the array of items
1431
1432 this._aItemGroups.splice(nGroupIndex, 1);
1433
1434
1435 // Remove the UL from the array of ULs
1436
1437 this._aListElements.splice(nGroupIndex, 1);
1438
1439
1440 /*
1441 Assign the "first-of-type" class to the new first UL
1442 in the collection
1443 */
1444
1445 oUL = this._aListElements[0];
1446
1447 if(oUL) {
1448
1449 Dom.addClass(oUL, "first-of-type");
1450
1451 }
1452
1453 }
1454
1455
1456 this.itemRemovedEvent.fire(oItem);
1457
1458 // Return a reference to the item that was removed
1459
1460 return oItem;
1461
1462 }
1463
1464 }
1465
1466},
1467
1468/**
1469* @method _removeItemFromGroupByValue
1470* @description Removes a menu item from a group by reference. Returns the
1471* menu item that was removed.
1472* @private
1473* @param {Number} p_nGroupIndex Number indicating the group to which the
1474* menu item belongs.
1475* @param {YAHOO.widget.MenuItem} p_oItem Object reference for the MenuItem
1476* instance to be removed.
1477* @return {YAHOO.widget.MenuItem}
1478*/
1479_removeItemFromGroupByValue: function(p_nGroupIndex, p_oItem) {
1480
1481 var aGroup = this._getItemGroup(p_nGroupIndex);
1482
1483 if(aGroup) {
1484
1485 var nItems = aGroup.length;
1486 var nItemIndex = -1;
1487
1488 if(nItems > 0) {
1489
1490 var i = nItems-1;
1491
1492 do {
1493
1494 if(aGroup[i] == p_oItem) {
1495
1496 nItemIndex = i;
1497 break;
1498
1499 }
1500
1501 }
1502 while(i--);
1503
1504 if(nItemIndex > -1) {
1505
1506 return this._removeItemFromGroupByIndex(
1507 p_nGroupIndex,
1508 nItemIndex
1509 );
1510
1511 }
1512
1513 }
1514
1515 }
1516
1517},
1518
1519/**
1520* @method _updateItemProperties
1521* @description Updates the "index," "groupindex," and "className" properties
1522* of the menu items in the specified group.
1523* @private
1524* @param {Number} p_nGroupIndex Number indicating the group of items to update.
1525*/
1526_updateItemProperties: function(p_nGroupIndex) {
1527
1528 var aGroup = this._getItemGroup(p_nGroupIndex);
1529 var nItems = aGroup.length;
1530
1531 if(nItems > 0) {
1532
1533 var i = nItems - 1;
1534 var oItem;
1535 var oLI;
1536
1537 // Update the index and className properties of each member
1538
1539 do {
1540
1541 oItem = aGroup[i];
1542
1543 if(oItem) {
1544
1545 oLI = oItem.element;
1546
1547 oItem.index = i;
1548 oItem.groupIndex = p_nGroupIndex;
1549
1550 oLI.setAttribute("groupindex", p_nGroupIndex);
1551 oLI.setAttribute("index", i);
1552
1553 Dom.removeClass(oLI, "first-of-type");
1554
1555 }
1556
1557 }
1558 while(i--);
1559
1560 if(oLI) {
1561
1562 Dom.addClass(oLI, "first-of-type");
1563
1564 }
1565
1566 }
1567
1568},
1569
1570/**
1571* @method _createItemGroup
1572* @description Creates a new menu item group (array) and its associated
1573* <code>&#60;ul&#62;</code> element. Returns an aray of menu item groups.
1574* @private
1575* @param {Number} p_nIndex Number indicating the group to create.
1576* @return {Array}
1577*/
1578_createItemGroup: function(p_nIndex) {
1579
1580 if(!this._aItemGroups[p_nIndex]) {
1581
1582 this._aItemGroups[p_nIndex] = [];
1583
1584 var oUL = document.createElement("ul");
1585
1586 this._aListElements[p_nIndex] = oUL;
1587
1588 return this._aItemGroups[p_nIndex];
1589
1590 }
1591
1592},
1593
1594/**
1595* @method _getItemGroup
1596* @description Returns the menu item group at the specified index.
1597* @private
1598* @param {Number} p_nIndex Number indicating the index of the menu item group
1599* to be retrieved.
1600* @return {Array}
1601*/
1602_getItemGroup: function(p_nIndex) {
1603
1604 var nIndex = ((typeof p_nIndex == "number") ? p_nIndex : 0);
1605
1606 return this._aItemGroups[nIndex];
1607
1608},
1609
1610/**
1611* @method _configureSubmenu
1612* @description Subscribes the menu item's submenu to its parent menu's events.
1613* @private
1614* @param {YAHOO.widget.MenuItem} p_oItem Object reference for the MenuItem
1615* instance with the submenu to be configured.
1616*/
1617_configureSubmenu: function(p_oItem) {
1618
1619 var oSubmenu = p_oItem.cfg.getProperty("submenu");
1620
1621 if(oSubmenu) {
1622
1623 /*
1624 Listen for configuration changes to the parent menu
1625 so they they can be applied to the submenu.
1626 */
1627
1628 this.cfg.configChangedEvent.subscribe(
1629 this._onParentMenuConfigChange,
1630 oSubmenu,
1631 true
1632 );
1633
1634 this.renderEvent.subscribe(
1635 this._onParentMenuRender,
1636 oSubmenu,
1637 true
1638 );
1639
1640 oSubmenu.beforeShowEvent.subscribe(
1641 this._onSubmenuBeforeShow,
1642 oSubmenu,
1643 true
1644 );
1645
1646 oSubmenu.showEvent.subscribe(
1647 this._onSubmenuShow,
1648 oSubmenu,
1649 true
1650 );
1651
1652 oSubmenu.hideEvent.subscribe(
1653 this._onSubmenuHide,
1654 oSubmenu,
1655 true
1656 );
1657
1658 }
1659
1660},
1661
1662/**
1663* @method _subscribeToItemEvents
1664* @description Subscribes a menu to a menu item's event.
1665* @private
1666* @param {YAHOO.widget.MenuItem} p_oItem Object reference for the MenuItem
1667* instance whose events should be subscribed to.
1668*/
1669_subscribeToItemEvents: function(p_oItem) {
1670
1671 p_oItem.focusEvent.subscribe(this._onMenuItemFocus, p_oItem, this);
1672
1673 p_oItem.blurEvent.subscribe(this._onMenuItemBlur, this, true);
1674
1675 p_oItem.cfg.configChangedEvent.subscribe(
1676 this._onMenuItemConfigChange,
1677 p_oItem,
1678 this
1679 );
1680
1681},
1682
1683/**
1684* @method _getOffsetWidth
1685* @description Returns the offset width of the menu's
1686* <code>&#60;div&#62;</code> element.
1687* @private
1688*/
1689_getOffsetWidth: function() {
1690
1691 var oClone = this.element.cloneNode(true);
1692
1693 Dom.setStyle(oClone, "width", "");
1694
1695 document.body.appendChild(oClone);
1696
1697 var sWidth = oClone.offsetWidth;
1698
1699 document.body.removeChild(oClone);
1700
1701 return sWidth;
1702
1703},
1704
1705/**
1706* @method _cancelHideDelay
1707* @description Cancels the call to "hideMenu."
1708* @private
1709*/
1710_cancelHideDelay: function() {
1711
1712 var oRoot = this.getRoot();
1713
1714 if(oRoot._nHideDelayId) {
1715
1716 window.clearTimeout(oRoot._nHideDelayId);
1717
1718 }
1719
1720},
1721
1722/**
1723* @method _execHideDelay
1724* @description Hides the menu after the number of milliseconds specified by
1725* the "hidedelay" configuration property.
1726* @private
1727*/
1728_execHideDelay: function() {
1729
1730 this._cancelHideDelay();
1731
1732 var oRoot = this.getRoot();
1733 var me = this;
1734
1735 var hideMenu = function() {
1736
1737 if(oRoot.activeItem) {
1738
1739 oRoot.clearActiveItem();
1740
1741 }
1742
1743 if(oRoot == me && me.cfg.getProperty("position") == "dynamic") {
1744
1745 me.hide();
1746
1747 }
1748
1749 };
1750
1751 oRoot._nHideDelayId =
1752 window.setTimeout(hideMenu, oRoot.cfg.getProperty("hidedelay"));
1753
1754},
1755
1756/**
1757* @method _cancelShowDelay
1758* @description Cancels the call to the "showMenu."
1759* @private
1760*/
1761_cancelShowDelay: function() {
1762
1763 var oRoot = this.getRoot();
1764
1765 if(oRoot._nShowDelayId) {
1766
1767 window.clearTimeout(oRoot._nShowDelayId);
1768
1769 }
1770
1771},
1772
1773/**
1774* @method _execShowDelay
1775* @description Shows the menu after the number of milliseconds specified by
1776* the "showdelay" configuration property have ellapsed.
1777* @private
1778* @param {YAHOO.widget.Menu} p_oMenu Object specifying the menu that should
1779* be made visible.
1780*/
1781_execShowDelay: function(p_oMenu) {
1782
1783 this._cancelShowDelay();
1784
1785 var oRoot = this.getRoot();
1786
1787 var showMenu = function() {
1788
1789 p_oMenu.show();
1790
1791 };
1792
1793 oRoot._nShowDelayId =
1794 window.setTimeout(showMenu, oRoot.cfg.getProperty("showdelay"));
1795
1796},
1797
1798// Protected methods
1799
1800/**
1801* @method _onMouseOver
1802* @description "mouseover" event handler for the menu.
1803* @protected
1804* @param {String} p_sType String representing the name of the event that
1805* was fired.
1806* @param {Array} p_aArgs Array of arguments sent when the event was fired.
1807* @param {YAHOO.widget.Menu} p_oMenu Object representing the menu that
1808* fired the event.
1809*/
1810_onMouseOver: function(p_sType, p_aArgs, p_oMenu) {
1811
1812 var oEvent = p_aArgs[0];
1813 var oItem = p_aArgs[1];
1814 var oTarget = Event.getTarget(oEvent);
1815
1816 if(
1817 !this._bHandledMouseOverEvent &&
1818 (oTarget == this.element || Dom.isAncestor(this.element, oTarget))
1819 ) {
1820
1821 // MENU MOUSEOVER LOGIC HERE
1822
1823 this.clearActiveItem();
1824
1825 this._bHandledMouseOverEvent = true;
1826 this._bHandledMouseOutEvent = false;
1827
1828 }
1829
1830 if(
1831 oItem && !oItem.handledMouseOverEvent &&
1832 (oTarget == oItem.element || Dom.isAncestor(oItem.element, oTarget))
1833 ) {
1834
1835 var oItemCfg = oItem.cfg;
1836
1837 // Select and focus the current menu item
1838
1839 oItemCfg.setProperty("selected", true);
1840 oItem.focus();
1841
1842 if(this.cfg.getProperty("autosubmenudisplay")) {
1843
1844 // Show the submenu this menu item
1845
1846 var oSubmenu = oItemCfg.getProperty("submenu");
1847
1848 if(oSubmenu) {
1849
1850 if(this.cfg.getProperty("showdelay") > 0) {
1851
1852 this._execShowDelay(oSubmenu);
1853
1854 }
1855 else {
1856
1857 oSubmenu.show();
1858
1859 }
1860
1861 }
1862
1863 }
1864
1865 oItem.handledMouseOverEvent = true;
1866 oItem.handledMouseOutEvent = false;
1867
1868 }
1869
1870},
1871
1872/**
1873* @method _onMouseOut
1874* @description "mouseout" event handler for the menu.
1875* @protected
1876* @param {String} p_sType String representing the name of the event that
1877* was fired.
1878* @param {Array} p_aArgs Array of arguments sent when the event was fired.
1879* @param {YAHOO.widget.Menu} p_oMenu Object representing the menu that
1880* fired the event.
1881*/
1882_onMouseOut: function(p_sType, p_aArgs, p_oMenu) {
1883
1884 var oEvent = p_aArgs[0];
1885 var oItem = p_aArgs[1];
1886 var oRelatedTarget = Event.getRelatedTarget(oEvent);
1887 var bMovingToSubmenu = false;
1888
1889 if(oItem) {
1890
1891 var oItemCfg = oItem.cfg;
1892 var oSubmenu = oItemCfg.getProperty("submenu");
1893
1894 if(
1895 oSubmenu &&
1896 (
1897 oRelatedTarget == oSubmenu.element ||
1898 Dom.isAncestor(oSubmenu.element, oRelatedTarget)
1899 )
1900 ) {
1901
1902 bMovingToSubmenu = true;
1903
1904 }
1905
1906 if(
1907 !oItem.handledMouseOutEvent &&
1908 (
1909 (
1910 oRelatedTarget != oItem.element &&
1911 !Dom.isAncestor(oItem.element, oRelatedTarget)
1912 ) || bMovingToSubmenu
1913 )
1914 ) {
1915
1916 if(this.cfg.getProperty("showdelay") > 0) {
1917
1918 this._cancelShowDelay();
1919
1920 }
1921
1922 if(!bMovingToSubmenu) {
1923
1924 oItemCfg.setProperty("selected", false);
1925
1926 }
1927
1928 if(this.cfg.getProperty("autosubmenudisplay")) {
1929
1930 if(oSubmenu) {
1931
1932 if(
1933 !(
1934 oRelatedTarget == oSubmenu.element ||
1935 YAHOO.util.Dom.isAncestor(
1936 oSubmenu.element,
1937 oRelatedTarget
1938 )
1939 )
1940 ) {
1941
1942 oSubmenu.hide();
1943
1944 }
1945
1946 }
1947
1948 }
1949
1950 oItem.handledMouseOutEvent = true;
1951 oItem.handledMouseOverEvent = false;
1952
1953 }
1954
1955 }
1956
1957 if(
1958 !this._bHandledMouseOutEvent &&
1959 (
1960 (
1961 oRelatedTarget != this.element &&
1962 !Dom.isAncestor(this.element, oRelatedTarget)
1963 )
1964 || bMovingToSubmenu
1965 )
1966 ) {
1967
1968 this._bHandledMouseOutEvent = true;
1969 this._bHandledMouseOverEvent = false;
1970
1971 }
1972
1973},
1974
1975/**
1976* @method _onClick
1977* @description "click" event handler for the menu.
1978* @protected
1979* @param {String} p_sType String representing the name of the event that
1980* was fired.
1981* @param {Array} p_aArgs Array of arguments sent when the event was fired.
1982* @param {YAHOO.widget.Menu} p_oMenu Object representing the menu that
1983* fired the event.
1984*/
1985_onClick: function(p_sType, p_aArgs, p_oMenu) {
1986
1987 var oEvent = p_aArgs[0];
1988 var oItem = p_aArgs[1];
1989 var oTarget = Event.getTarget(oEvent);
1990
1991 if(oItem) {
1992
1993 var oItemCfg = oItem.cfg;
1994 var oSubmenu = oItemCfg.getProperty("submenu");
1995
1996 /*
1997 ACCESSIBILITY FEATURE FOR SCREEN READERS:
1998 Expand/collapse the submenu when the user clicks
1999 on the submenu indicator image.
2000 */
2001
2002 if(oTarget == oItem.submenuIndicator && oSubmenu) {
2003
2004 if(oSubmenu.cfg.getProperty("visible")) {
2005
2006 oSubmenu.hide();
2007
2008 }
2009 else {
2010
2011 this.clearActiveItem();
2012
2013 this.activeItem = oItem;
2014
2015 oItem.cfg.setProperty("selected", true);
2016
2017 oSubmenu.show();
2018
2019 }
2020
2021 }
2022 else {
2023
2024 var sURL = oItemCfg.getProperty("url");
2025 var bCurrentPageURL = (sURL.substr((sURL.length-1),1) == "#");
2026 var sTarget = oItemCfg.getProperty("target");
2027 var bHasTarget = (sTarget && sTarget.length > 0);
2028
2029 /*
2030 Prevent the browser from following links
2031 equal to "#"
2032 */
2033
2034 if(
2035 oTarget.tagName.toUpperCase() == "A" &&
2036 bCurrentPageURL && !bHasTarget
2037 ) {
2038
2039 Event.preventDefault(oEvent);
2040
2041 }
2042
2043 if(
2044 oTarget.tagName.toUpperCase() != "A" &&
2045 !bCurrentPageURL && !bHasTarget
2046 ) {
2047
2048 /*
2049 Follow the URL of the item regardless of
2050 whether or not the user clicked specifically
2051 on the anchor element.
2052 */
2053
2054 document.location = sURL;
2055
2056 }
2057
2058 /*
2059 If the item doesn't navigate to a URL and it doesn't have
2060 a submenu, then collapse the menu tree.
2061 */
2062
2063 if(bCurrentPageURL && !oSubmenu) {
2064
2065 var oRoot = this.getRoot();
2066
2067 if(oRoot.cfg.getProperty("position") == "static") {
2068
2069 oRoot.clearActiveItem();
2070
2071 }
2072 else {
2073
2074 oRoot.hide();
2075
2076 }
2077
2078 }
2079
2080 }
2081
2082 }
2083
2084},
2085
2086/**
2087* @method _onKeyDown
2088* @description "keydown" event handler for the menu.
2089* @protected
2090* @param {String} p_sType String representing the name of the event that
2091* was fired.
2092* @param {Array} p_aArgs Array of arguments sent when the event was fired.
2093* @param {YAHOO.widget.Menu} p_oMenu Object representing the menu that
2094* fired the event.
2095*/
2096_onKeyDown: function(p_sType, p_aArgs, p_oMenu) {
2097
2098 var oEvent = p_aArgs[0];
2099 var oItem = p_aArgs[1];
2100 var oSubmenu;
2101
2102 if(oItem) {
2103
2104 var oItemCfg = oItem.cfg;
2105 var oParentItem = this.parent;
2106 var oRoot;
2107 var oNextItem;
2108
2109 switch(oEvent.keyCode) {
2110
2111 case 38: // Up arrow
2112 case 40: // Down arrow
2113
2114 if(
2115 oItem == this.activeItem &&
2116 !oItemCfg.getProperty("selected")
2117 ) {
2118
2119 oItemCfg.setProperty("selected", true);
2120
2121 }
2122 else {
2123
2124 oNextItem = (oEvent.keyCode == 38) ?
2125 oItem.getPreviousEnabledSibling() :
2126 oItem.getNextEnabledSibling();
2127
2128 if(oNextItem) {
2129
2130 this.clearActiveItem();
2131
2132 oNextItem.cfg.setProperty("selected", true);
2133 oNextItem.focus();
2134
2135 }
2136
2137 }
2138
2139 Event.preventDefault(oEvent);
2140
2141 break;
2142
2143
2144 case 39: // Right arrow
2145
2146 oSubmenu = oItemCfg.getProperty("submenu");
2147
2148 if(oSubmenu) {
2149
2150 if(!oItemCfg.getProperty("selected")) {
2151
2152 oItemCfg.setProperty("selected", true);
2153
2154 }
2155
2156 oSubmenu.show();
2157
2158 oSubmenu.setInitialSelection();
2159
2160 }
2161 else {
2162
2163 oRoot = this.getRoot();
2164
2165 if(oRoot instanceof YAHOO.widget.MenuBar) {
2166
2167 oNextItem = oRoot.activeItem.getNextEnabledSibling();
2168
2169 if(oNextItem) {
2170
2171 oRoot.clearActiveItem();
2172
2173 oNextItem.cfg.setProperty("selected", true);
2174
2175 oSubmenu = oNextItem.cfg.getProperty("submenu");
2176
2177 if(oSubmenu) {
2178
2179 oSubmenu.show();
2180
2181 }
2182
2183 oNextItem.focus();
2184
2185 }
2186
2187 }
2188
2189 }
2190
2191
2192 Event.preventDefault(oEvent);
2193
2194 break;
2195
2196
2197 case 37: // Left arrow
2198
2199 if(oParentItem) {
2200
2201 var oParentMenu = oParentItem.parent;
2202
2203 if(oParentMenu instanceof YAHOO.widget.MenuBar) {
2204
2205 oNextItem =
2206 oParentMenu.activeItem.getPreviousEnabledSibling();
2207
2208 if(oNextItem) {
2209
2210 oParentMenu.clearActiveItem();
2211
2212 oNextItem.cfg.setProperty("selected", true);
2213
2214 oSubmenu = oNextItem.cfg.getProperty("submenu");
2215
2216 if(oSubmenu) {
2217
2218 oSubmenu.show();
2219
2220 }
2221
2222 oNextItem.focus();
2223
2224 }
2225
2226 }
2227 else {
2228
2229 this.hide();
2230
2231 oParentItem.focus();
2232
2233 }
2234
2235 }
2236
2237 Event.preventDefault(oEvent);
2238
2239 break;
2240
2241 }
2242
2243 }
2244
2245 if(oEvent.keyCode == 27) { // Esc key
2246
2247 if(this.cfg.getProperty("position") == "dynamic") {
2248
2249 this.hide();
2250
2251 if(this.parent) {
2252
2253 this.parent.focus();
2254
2255 }
2256
2257 }
2258 else if(this.activeItem) {
2259
2260 oSubmenu = this.activeItem.cfg.getProperty("submenu");
2261
2262 if(oSubmenu && oSubmenu.cfg.getProperty("visible")) {
2263
2264 oSubmenu.hide();
2265 this.activeItem.focus();
2266
2267 }
2268 else {
2269
2270 this.activeItem.cfg.setProperty("selected", false);
2271 this.activeItem.blur();
2272
2273 }
2274
2275 }
2276
2277 Event.preventDefault(oEvent);
2278
2279 }
2280
2281},
2282
2283// Private methods
2284
2285/**
2286* @method _onInit
2287* @description "init" event handler for the menu.
2288* @private
2289* @param {String} p_sType String representing the name of the event that
2290* was fired.
2291* @param {Array} p_aArgs Array of arguments sent when the event was fired.
2292* @param {YAHOO.widget.Menu} p_oMenu Object representing the menu that
2293* fired the event.
2294*/
2295_onInit: function(p_sType, p_aArgs, p_oMenu) {
2296
2297 if(
2298 (
2299 (this.parent && !this.lazyLoad) ||
2300 (!this.parent && this.cfg.getProperty("position") == "static") ||
2301 (
2302 !this.parent &&
2303 !this.lazyLoad &&
2304 this.cfg.getProperty("position") == "dynamic"
2305 )
2306 ) &&
2307 this.getItemGroups().length === 0
2308 ) {
2309
2310 if(this.srcElement) {
2311
2312 this._initSubTree();
2313
2314 }
2315
2316 if(this.itemData) {
2317
2318 this.addItems(this.itemData);
2319
2320 }
2321
2322 }
2323 else if(this.lazyLoad) {
2324
2325 this.cfg.fireQueue();
2326
2327 }
2328
2329},
2330
2331/**
2332* @method _onBeforeRender
2333* @description "beforerender" event handler for the menu. Appends all of the
2334* <code>&#60;ul&#62;</code>, <code>&#60;li&#62;</code> and their accompanying
2335* title elements to the body element of the menu.
2336* @private
2337* @param {String} p_sType String representing the name of the event that
2338* was fired.
2339* @param {Array} p_aArgs Array of arguments sent when the event was fired.
2340* @param {YAHOO.widget.Menu} p_oMenu Object representing the menu that
2341* fired the event.
2342*/
2343_onBeforeRender: function(p_sType, p_aArgs, p_oMenu) {
2344
2345 var oConfig = this.cfg;
2346 var oEl = this.element;
2347 var nListElements = this._aListElements.length;
2348
2349 if(nListElements > 0) {
2350
2351 var i = 0;
2352 var bFirstList = true;
2353 var oUL;
2354 var oGroupTitle;
2355
2356 do {
2357
2358 oUL = this._aListElements[i];
2359
2360 if(oUL) {
2361
2362 if(bFirstList) {
2363
2364 Dom.addClass(oUL, "first-of-type");
2365 bFirstList = false;
2366
2367 }
2368
2369 if(!Dom.isAncestor(oEl, oUL)) {
2370
2371 this.appendToBody(oUL);
2372
2373 }
2374
2375 oGroupTitle = this._aGroupTitleElements[i];
2376
2377 if(oGroupTitle) {
2378
2379 if(!Dom.isAncestor(oEl, oGroupTitle)) {
2380
2381 oUL.parentNode.insertBefore(oGroupTitle, oUL);
2382
2383 }
2384
2385 Dom.addClass(oUL, "hastitle");
2386
2387 }
2388
2389 }
2390
2391 i++;
2392
2393 }
2394 while(i < nListElements);
2395
2396 }
2397
2398},
2399
2400/**
2401* @method _onRender
2402* @description "render" event handler for the menu.
2403* @private
2404* @param {String} p_sType String representing the name of the event that
2405* was fired.
2406* @param {Array} p_aArgs Array of arguments sent when the event was fired.
2407* @param {YAHOO.widget.Menu} p_oMenu Object representing the menu that
2408* fired the event.
2409*/
2410_onRender: function(p_sType, p_aArgs, p_oMenu) {
2411
2412 if(this.cfg.getProperty("position") == "dynamic") {
2413
2414 var sWidth =
2415 this.element.parentNode.tagName.toUpperCase() == "BODY" ?
2416 this.element.offsetWidth : this._getOffsetWidth();
2417
2418 this.cfg.setProperty("width", (sWidth + "px"));
2419
2420 }
2421
2422},
2423
2424/**
2425* @method _onBeforeShow
2426* @description "beforeshow" event handler for the menu.
2427* @private
2428* @param {String} p_sType String representing the name of the event that
2429* was fired.
2430* @param {Array} p_aArgs Array of arguments sent when the event was fired.
2431* @param {YAHOO.widget.Menu} p_oMenu Object representing the menu that
2432* fired the event.
2433*/
2434_onBeforeShow: function(p_sType, p_aArgs, p_oMenu) {
2435
2436 if(this.lazyLoad && this.getItemGroups().length === 0) {
2437
2438 if(this.srcElement) {
2439
2440 this._initSubTree();
2441
2442 }
2443
2444 if(this.itemData) {
2445
2446 if(
2447 this.parent && this.parent.parent &&
2448 this.parent.parent.srcElement &&
2449 this.parent.parent.srcElement.tagName.toUpperCase() == "SELECT"
2450 ) {
2451
2452 var nOptions = this.itemData.length;
2453
2454 for(var n=0; n<nOptions; n++) {
2455
2456 if(this.itemData[n].tagName) {
2457
2458 this.addItem((new this.ITEM_TYPE(this.itemData[n])));
2459
2460 }
2461
2462 }
2463
2464 }
2465 else {
2466
2467 this.addItems(this.itemData);
2468
2469 }
2470
2471 }
2472
2473 if(this.srcElement) {
2474
2475 this.render();
2476
2477 }
2478 else {
2479
2480 if(this.parent) {
2481
2482 this.render(this.parent.element);
2483
2484 }
2485 else {
2486
2487 this.render(this.cfg.getProperty("container"));
2488
2489 }
2490
2491 }
2492
2493 }
2494
2495},
2496
2497/**
2498* @method _onShow
2499* @description "show" event handler for the menu.
2500* @private
2501* @param {String} p_sType String representing the name of the event that
2502* was fired.
2503* @param {Array} p_aArgs Array of arguments sent when the event was fired.
2504* @param {YAHOO.widget.Menu} p_oMenu Object representing the menu that fired
2505* the event.
2506*/
2507_onShow: function(p_sType, p_aArgs, p_oMenu) {
2508
2509 this.setInitialFocus();
2510
2511 var oParent = this.parent;
2512
2513 if(oParent) {
2514
2515 var oParentMenu = oParent.parent;
2516
2517 var aParentAlignment = oParentMenu.cfg.getProperty("submenualignment");
2518 var aAlignment = this.cfg.getProperty("submenualignment");
2519
2520 if(
2521 (aParentAlignment[0] != aAlignment[0]) &&
2522 (aParentAlignment[1] != aAlignment[1])
2523 ) {
2524
2525 this.cfg.setProperty(
2526 "submenualignment",
2527 [ aParentAlignment[0], aParentAlignment[1] ]
2528 );
2529
2530 }
2531
2532 if(
2533 !oParentMenu.cfg.getProperty("autosubmenudisplay") &&
2534 oParentMenu.cfg.getProperty("position") == "static"
2535 ) {
2536
2537 oParentMenu.cfg.setProperty("autosubmenudisplay", true);
2538
2539 /**
2540 * "click" event handler for the document
2541 * @private
2542 * @param {Event} p_oEvent Object reference for the DOM event object
2543 * passed back by the event utility (YAHOO.util.Event).
2544 */
2545 var disableAutoSubmenuDisplay = function(p_oEvent) {
2546
2547 if(
2548 p_oEvent.type == "mousedown" ||
2549 (p_oEvent.type == "keydown" && p_oEvent.keyCode == 27)
2550 ) {
2551
2552 /*
2553 Set the "autosubmenudisplay" to "false" if the user
2554 clicks outside the menu bar.
2555 */
2556
2557 var oTarget = Event.getTarget(p_oEvent);
2558
2559 if(
2560 oTarget != oParentMenu.element ||
2561 !YAHOO.util.Dom.isAncestor(oParentMenu.element, oTarget)
2562 ) {
2563
2564 oParentMenu.cfg.setProperty(
2565 "autosubmenudisplay",
2566 false
2567 );
2568
2569 Event.removeListener(
2570 document,
2571 "mousedown",
2572 disableAutoSubmenuDisplay
2573 );
2574
2575 Event.removeListener(
2576 document,
2577 "keydown",
2578 disableAutoSubmenuDisplay
2579 );
2580
2581 }
2582
2583 }
2584
2585 };
2586
2587 Event.addListener(document, "mousedown", disableAutoSubmenuDisplay);
2588 Event.addListener(document, "keydown", disableAutoSubmenuDisplay);
2589
2590 }
2591
2592 }
2593
2594},
2595
2596/**
2597* @method _onBeforeHide
2598* @description "beforehide" event handler for the menu.
2599* @private
2600* @param {String} p_sType String representing the name of the event that
2601* was fired.
2602* @param {Array} p_aArgs Array of arguments sent when the event was fired.
2603* @param {YAHOO.widget.Menu} p_oMenu Object representing the menu that fired
2604* the event.
2605*/
2606_onBeforeHide: function(p_sType, p_aArgs, p_oMenu) {
2607
2608 this.clearActiveItem(true);
2609
2610},
2611
2612/**
2613* @method _onParentMenuConfigChange
2614* @description "configchange" event handler for a submenu.
2615* @private
2616* @param {String} p_sType String representing the name of the event that
2617* was fired.
2618* @param {Array} p_aArgs Array of arguments sent when the event was fired.
2619* @param {YAHOO.widget.Menu} p_oSubmenu Object representing the submenu that
2620* subscribed to the event.
2621*/
2622_onParentMenuConfigChange: function(p_sType, p_aArgs, p_oSubmenu) {
2623
2624 var sPropertyName = p_aArgs[0][0];
2625 var oPropertyValue = p_aArgs[0][1];
2626
2627 switch(sPropertyName) {
2628
2629 case "iframe":
2630 case "constraintoviewport":
2631 case "hidedelay":
2632 case "showdelay":
2633 case "clicktohide":
2634 case "effect":
2635
2636 p_oSubmenu.cfg.setProperty(sPropertyName, oPropertyValue);
2637
2638 break;
2639
2640 }
2641
2642},
2643
2644/**
2645* @method _onParentMenuRender
2646* @description "render" event handler for a submenu. Renders a
2647* submenu in response to the firing of its parent's "render" event.
2648* @private
2649* @param {String} p_sType String representing the name of the event that
2650* was fired.
2651* @param {Array} p_aArgs Array of arguments sent when the event was fired.
2652* @param {YAHOO.widget.Menu} p_oSubmenu Object representing the submenu that
2653* subscribed to the event.
2654*/
2655_onParentMenuRender: function(p_sType, p_aArgs, p_oSubmenu) {
2656
2657 /*
2658 Set the "constraintoviewport" configuration
2659 property to match the parent Menu
2660 */
2661
2662 var oParentMenu = p_oSubmenu.parent.parent;
2663
2664 var oConfig = {
2665
2666 constraintoviewport:
2667 oParentMenu.cfg.getProperty("constraintoviewport"),
2668
2669 xy: [0,0],
2670
2671 clicktohide:
2672 oParentMenu.cfg.getProperty("clicktohide"),
2673
2674 effect:
2675 oParentMenu.cfg.getProperty("effect")
2676
2677 };
2678
2679 var nShowDelay = oParentMenu.cfg.getProperty("showdelay");
2680
2681 if(nShowDelay > 0) {
2682
2683 oConfig.showdelay = nShowDelay;
2684
2685 }
2686
2687 var nHideDelay = oParentMenu.cfg.getProperty("hidedelay");
2688
2689 if(nHideDelay > 0) {
2690
2691 oConfig.hidedelay = nHideDelay;
2692
2693 }
2694
2695 /*
2696 Only sync the "iframe" configuration property if the parent
2697 menu's "position" configuration is the same.
2698 */
2699
2700 if(
2701 this.cfg.getProperty("position") ==
2702 oParentMenu.cfg.getProperty("position")
2703 ) {
2704
2705 oConfig.iframe = oParentMenu.cfg.getProperty("iframe");
2706
2707 }
2708
2709
2710 p_oSubmenu.cfg.applyConfig(oConfig);
2711
2712 if(!this.lazyLoad) {
2713
2714 if(Dom.inDocument(this.element)) {
2715
2716 this.render();
2717
2718 }
2719 else {
2720
2721 this.render(this.parent.element);
2722
2723 }
2724
2725 }
2726
2727},
2728
2729/**
2730* @method _onSubmenuBeforeShow
2731* @description "beforeshow" event handler for a submenu.
2732* @private
2733* @param {String} p_sType String representing the name of the event that
2734* was fired.
2735* @param {Array} p_aArgs Array of arguments sent when the event was fired.
2736* @param {YAHOO.widget.Menu} p_oSubmenu Object representing the submenu that
2737* subscribed to the event.
2738*/
2739_onSubmenuBeforeShow: function(p_sType, p_aArgs, p_oSubmenu) {
2740
2741 var oParent = this.parent;
2742 var aAlignment = oParent.parent.cfg.getProperty("submenualignment");
2743
2744 this.cfg.setProperty(
2745 "context",
2746 [oParent.element, aAlignment[0], aAlignment[1]]
2747 );
2748
2749 oParent.submenuIndicator.alt = oParent.EXPANDED_SUBMENU_INDICATOR_ALT_TEXT;
2750
2751},
2752
2753/**
2754* @method _onSubmenuShow
2755* @description "show" event handler for a submenu.
2756* @private
2757* @param {String} p_sType String representing the name of the event that
2758* was fired.
2759* @param {Array} p_aArgs Array of arguments sent when the event was fired.
2760* @param {YAHOO.widget.Menu} p_oSubmenu Object representing the submenu that
2761* subscribed to the event.
2762*/
2763_onSubmenuShow: function(p_sType, p_aArgs, p_oSubmenu) {
2764
2765 var oParent = this.parent;
2766
2767 oParent.submenuIndicator.alt = oParent.EXPANDED_SUBMENU_INDICATOR_ALT_TEXT;
2768
2769},
2770
2771/**
2772* @method _onSubmenuHide
2773* @description "hide" Custom Event handler for a submenu.
2774* @private
2775* @param {String} p_sType String representing the name of the event that
2776* was fired.
2777* @param {Array} p_aArgs Array of arguments sent when the event was fired.
2778* @param {YAHOO.widget.Menu} p_oSubmenu Object representing the submenu that
2779* subscribed to the event.
2780*/
2781_onSubmenuHide: function(p_sType, p_aArgs, p_oSubmenu) {
2782
2783 var oParent = this.parent;
2784
2785 oParent.submenuIndicator.alt = oParent.COLLAPSED_SUBMENU_INDICATOR_ALT_TEXT;
2786
2787},
2788
2789/**
2790* @method _onMenuItemFocus
2791* @description "focus" event handler for the menu's items.
2792* @private
2793* @param {String} p_sType String representing the name of the event that
2794* was fired.
2795* @param {Array} p_aArgs Array of arguments sent when the event was fired.
2796* @param {YAHOO.widget.MenuItem} p_oItem Object representing the menu item
2797* that fired the event.
2798*/
2799_onMenuItemFocus: function(p_sType, p_aArgs, p_oItem) {
2800
2801 this.activeItem = p_oItem;
2802
2803},
2804
2805/**
2806* @method _onMenuItemBlur
2807* @description "blur" event handler for the menu's items.
2808* @private
2809* @param {String} p_sType String representing the name of the event
2810* that was fired.
2811* @param {Array} p_aArgs Array of arguments sent when the event was fired.
2812*/
2813_onMenuItemBlur: function(p_sType, p_aArgs) {
2814
2815 this.activeItem = null;
2816
2817},
2818
2819/**
2820* @method _onMenuItemConfigChange
2821* @description "configchange" event handler for the menu's items.
2822* @private
2823* @param {String} p_sType String representing the name of the event that
2824* was fired.
2825* @param {Array} p_aArgs Array of arguments sent when the event was fired.
2826* @param {YAHOO.widget.MenuItem} p_oItem Object representing the menu item
2827* that fired the event.
2828*/
2829_onMenuItemConfigChange: function(p_sType, p_aArgs, p_oItem) {
2830
2831 var sProperty = p_aArgs[0][0];
2832
2833 switch(sProperty) {
2834
2835 case "submenu":
2836
2837 var oSubmenu = p_aArgs[0][1];
2838
2839 if(oSubmenu) {
2840
2841 this._configureSubmenu(p_oItem);
2842
2843 }
2844
2845 break;
2846
2847 case "text":
2848 case "helptext":
2849
2850 /*
2851 A change to an item's "text" or "helptext"
2852 configuration properties requires the width of the parent
2853 menu to be recalculated.
2854 */
2855
2856 if(this.element.style.width) {
2857
2858 var sWidth = this._getOffsetWidth() + "px";
2859
2860 Dom.setStyle(this.element, "width", sWidth);
2861
2862 }
2863
2864 break;
2865
2866 }
2867
2868},
2869
2870// Public event handlers for configuration properties
2871
2872/**
2873* @method enforceConstraints
2874* @description The default event handler executed when the moveEvent is fired,
2875* if the "constraintoviewport" configuration property is set to true.
2876* @param {String} type The name of the event that was fired.
2877* @param {Array} args Collection of arguments sent when the
2878* event was fired.
2879* @param {Array} obj Array containing the current Menu instance
2880* and the item that fired the event.
2881*/
2882enforceConstraints: function(type, args, obj) {
2883
2884 var oConfig = this.cfg;
2885
2886 var pos = args[0];
2887
2888 var x = pos[0];
2889 var y = pos[1];
2890
2891 var bod = document.getElementsByTagName('body')[0];
2892 var htm = document.getElementsByTagName('html')[0];
2893
2894 var bodyOverflow = Dom.getStyle(bod, "overflow");
2895 var htmOverflow = Dom.getStyle(htm, "overflow");
2896
2897 var offsetHeight = this.element.offsetHeight;
2898 var offsetWidth = this.element.offsetWidth;
2899
2900 var viewPortWidth = Dom.getClientWidth();
2901 var viewPortHeight = Dom.getClientHeight();
2902
2903 var scrollX = window.scrollX || document.body.scrollLeft;
2904 var scrollY = window.scrollY || document.body.scrollTop;
2905
2906 var topConstraint = scrollY + 10;
2907 var leftConstraint = scrollX + 10;
2908 var bottomConstraint = scrollY + viewPortHeight - offsetHeight - 10;
2909 var rightConstraint = scrollX + viewPortWidth - offsetWidth - 10;
2910
2911 var aContext = oConfig.getProperty("context");
2912 var oContextElement = aContext ? aContext[0] : null;
2913
2914
2915 if (x < 10) {
2916
2917 x = leftConstraint;
2918
2919 } else if ((x + offsetWidth) > viewPortWidth) {
2920
2921 if(
2922 oContextElement &&
2923 ((x - oContextElement.offsetWidth) > offsetWidth)
2924 ) {
2925
2926 x = (x - (oContextElement.offsetWidth + offsetWidth));
2927
2928 }
2929 else {
2930
2931 x = rightConstraint;
2932
2933 }
2934
2935 }
2936
2937 if (y < 10) {
2938
2939 y = topConstraint;
2940
2941 } else if (y > bottomConstraint) {
2942
2943 if(oContextElement && (y > offsetHeight)) {
2944
2945 y = ((y + oContextElement.offsetHeight) - offsetHeight);
2946
2947 }
2948 else {
2949
2950 y = bottomConstraint;
2951
2952 }
2953
2954 }
2955
2956 oConfig.setProperty("x", x, true);
2957 oConfig.setProperty("y", y, true);
2958
2959},
2960
2961/**
2962* @method configVisible
2963* @description Event handler for when the "visible" configuration property
2964* the menu changes.
2965* @param {String} p_sType String representing the name of the event that
2966* was fired.
2967* @param {Array} p_aArgs Array of arguments sent when the event was fired.
2968* @param {YAHOO.widget.Menu} p_oMenu Object representing the menu that
2969* fired the event.
2970*/
2971configVisible: function(p_sType, p_aArgs, p_oMenu) {
2972
2973 if(this.cfg.getProperty("position") == "dynamic") {
2974
2975 YAHOO.widget.Menu.superclass.configVisible.call(
2976 this,
2977 p_sType,
2978 p_aArgs,
2979 p_oMenu
2980 );
2981
2982 }
2983 else {
2984
2985 var bVisible = p_aArgs[0];
2986 var sDisplay = Dom.getStyle(this.element, "display");
2987
2988 if(bVisible) {
2989
2990 if(sDisplay != "block") {
2991 this.beforeShowEvent.fire();
2992 Dom.setStyle(this.element, "display", "block");
2993 this.showEvent.fire();
2994 }
2995
2996 }
2997 else {
2998
2999 if(sDisplay == "block") {
3000 this.beforeHideEvent.fire();
3001 Dom.setStyle(this.element, "display", "none");
3002 this.hideEvent.fire();
3003 }
3004
3005 }
3006
3007 }
3008
3009},
3010
3011/**
3012* @method configPosition
3013* @description Event handler for when the "position" configuration property
3014* of the menu changes.
3015* @param {String} p_sType String representing the name of the event that
3016* was fired.
3017* @param {Array} p_aArgs Array of arguments sent when the event was fired.
3018* @param {YAHOO.widget.Menu} p_oMenu Object representing the menu that
3019* fired the event.
3020*/
3021configPosition: function(p_sType, p_aArgs, p_oMenu) {
3022
3023 var sCSSPosition = p_aArgs[0] == "static" ? "static" : "absolute";
3024 var oCfg = this.cfg;
3025
3026 Dom.setStyle(this.element, "position", sCSSPosition);
3027
3028 if(sCSSPosition == "static") {
3029
3030 /*
3031 Remove the iframe for statically positioned menus since it will
3032 intercept mouse events.
3033 */
3034
3035 oCfg.setProperty("iframe", false);
3036
3037 // Statically positioned menus are visible by default
3038
3039 Dom.setStyle(this.element, "display", "block");
3040
3041 oCfg.setProperty("visible", true);
3042
3043 }
3044 else {
3045
3046 /*
3047 Even though the "visible" property is queued to
3048 "false" by default, we need to set the "visibility" property to
3049 "hidden" since Overlay's "configVisible" implementation checks the
3050 element's "visibility" style property before deciding whether
3051 or not to show an Overlay instance.
3052 */
3053
3054 Dom.setStyle(this.element, "visibility", "hidden");
3055
3056 }
3057
3058 if(sCSSPosition == "absolute") {
3059
3060 var nZIndex = oCfg.getProperty("zindex");
3061
3062 if(!nZIndex || nZIndex === 0) {
3063
3064 nZIndex = this.parent ?
3065 (this.parent.parent.cfg.getProperty("zindex") + 1) : 1;
3066
3067 oCfg.setProperty("zindex", nZIndex);
3068
3069 }
3070
3071 }
3072
3073},
3074
3075/**
3076* @method configIframe
3077* @description Event handler for when the "iframe" configuration property of
3078* the menu changes.
3079* @param {String} p_sType String representing the name of the event that
3080* was fired.
3081* @param {Array} p_aArgs Array of arguments sent when the event was fired.
3082* @param {YAHOO.widget.Menu} p_oMenu Object representing the menu that
3083* fired the event.
3084*/
3085configIframe: function(p_sType, p_aArgs, p_oMenu) {
3086
3087 if(this.cfg.getProperty("position") == "dynamic") {
3088
3089 YAHOO.widget.Menu.superclass.configIframe.call(
3090 this,
3091 p_sType,
3092 p_aArgs,
3093 p_oMenu
3094 );
3095
3096 }
3097
3098},
3099
3100/**
3101* @method configHideDelay
3102* @description Event handler for when the "hidedelay" configuration property
3103* of the menu changes.
3104* @param {String} p_sType String representing the name of the event that
3105* was fired.
3106* @param {Array} p_aArgs Array of arguments sent when the event was fired.
3107* @param {YAHOO.widget.Menu} p_oMenu Object representing the menu that
3108* fired the event.
3109*/
3110configHideDelay: function(p_sType, p_aArgs, p_oMenu) {
3111
3112 var nHideDelay = p_aArgs[0];
3113 var oMouseOutEvent = this.mouseOutEvent;
3114 var oMouseOverEvent = this.mouseOverEvent;
3115 var oKeyDownEvent = this.keyDownEvent;
3116
3117 if(nHideDelay > 0) {
3118
3119 /*
3120 Only assign event handlers once. This way the user change
3121 the value for the hidedelay as many times as they want.
3122 */
3123
3124 if(!this._hideDelayEventHandlersAssigned) {
3125
3126 oMouseOutEvent.subscribe(this._execHideDelay, true);
3127 oMouseOverEvent.subscribe(this._cancelHideDelay, this, true);
3128 oKeyDownEvent.subscribe(this._cancelHideDelay, this, true);
3129
3130 this._hideDelayEventHandlersAssigned = true;
3131
3132 }
3133
3134 }
3135 else {
3136
3137 oMouseOutEvent.unsubscribe(this._execHideDelay, this);
3138 oMouseOverEvent.unsubscribe(this._cancelHideDelay, this);
3139 oKeyDownEvent.unsubscribe(this._cancelHideDelay, this);
3140
3141 this._hideDelayEventHandlersAssigned = false;
3142
3143 }
3144
3145},
3146
3147/**
3148* @method configContainer
3149* @description Event handler for when the "container" configuration property
3150of the menu changes.
3151* @param {String} p_sType String representing the name of the event that
3152* was fired.
3153* @param {Array} p_aArgs Array of arguments sent when the event was fired.
3154* @param {YAHOO.widget.Menu} p_oMenu Object representing the menu that
3155* fired the event.
3156*/
3157configContainer: function(p_sType, p_aArgs, p_oMenu) {
3158
3159 var oElement = p_aArgs[0];
3160
3161 if(typeof oElement == 'string') {
3162
3163 this.cfg.setProperty(
3164 "container",
3165 document.getElementById(oElement),
3166 true
3167 );
3168
3169 }
3170
3171},
3172
3173// Public methods
3174
3175/**
3176* Event handler called when the resize monitor element's "resize" evet is fired.
3177*/
3178onDomResize: function(e, obj) {
3179
3180 if(!this._handleResize) {
3181
3182 this._handleResize = true;
3183 return;
3184
3185 }
3186
3187 var oConfig = this.cfg;
3188
3189 if(oConfig.getProperty("position") == "dynamic") {
3190
3191 oConfig.setProperty("width", (this._getOffsetWidth() + "px"));
3192
3193 }
3194
3195 YAHOO.widget.Menu.superclass.onDomResize.call(this, e, obj);
3196
3197},
3198
3199/**
3200* @method initEvents
3201* @description Initializes the custom events for the menu.
3202*/
3203initEvents: function() {
3204
3205 YAHOO.widget.Menu.superclass.initEvents.call(this);
3206
3207 // Create custom events
3208
3209 var CustomEvent = YAHOO.util.CustomEvent;
3210
3211 this.mouseOverEvent = new CustomEvent("mouseOverEvent", this);
3212 this.mouseOutEvent = new CustomEvent("mouseOutEvent", this);
3213 this.mouseDownEvent = new CustomEvent("mouseDownEvent", this);
3214 this.mouseUpEvent = new CustomEvent("mouseUpEvent", this);
3215 this.clickEvent = new CustomEvent("clickEvent", this);
3216 this.keyPressEvent = new CustomEvent("keyPressEvent", this);
3217 this.keyDownEvent = new CustomEvent("keyDownEvent", this);
3218 this.keyUpEvent = new CustomEvent("keyUpEvent", this);
3219 this.itemAddedEvent = new CustomEvent("itemAddedEvent", this);
3220 this.itemRemovedEvent = new CustomEvent("itemRemovedEvent", this);
3221
3222},
3223
3224/**
3225* @method getRoot
3226* @description Finds the menu's root menu.
3227*/
3228getRoot: function() {
3229
3230 var oItem = this.parent;
3231
3232 if(oItem) {
3233
3234 var oParentMenu = oItem.parent;
3235
3236 return oParentMenu ? oParentMenu.getRoot() : this;
3237
3238 }
3239 else {
3240
3241 return this;
3242
3243 }
3244
3245},
3246
3247/**
3248* @method toString
3249* @description Returns a string representing the menu.
3250* @return {String}
3251*/
3252toString: function() {
3253
3254 return ("Menu " + this.id);
3255
3256},
3257
3258/**
3259* @method setItemGroupTitle
3260* @description Sets the title of a group of menu items.
3261* @param {String} p_sGroupTitle String specifying the title of the group.
3262* @param {Number} p_nGroupIndex Optional. Number specifying the group to which
3263* the title belongs.
3264*/
3265setItemGroupTitle: function(p_sGroupTitle, p_nGroupIndex) {
3266
3267 if(typeof p_sGroupTitle == "string" && p_sGroupTitle.length > 0) {
3268
3269 var nGroupIndex = typeof p_nGroupIndex == "number" ? p_nGroupIndex : 0;
3270 var oTitle = this._aGroupTitleElements[nGroupIndex];
3271
3272 if(oTitle) {
3273
3274 oTitle.innerHTML = p_sGroupTitle;
3275
3276 }
3277 else {
3278
3279 oTitle = document.createElement(this.GROUP_TITLE_TAG_NAME);
3280
3281 oTitle.innerHTML = p_sGroupTitle;
3282
3283 this._aGroupTitleElements[nGroupIndex] = oTitle;
3284
3285 }
3286
3287 var i = this._aGroupTitleElements.length - 1;
3288 var nFirstIndex;
3289
3290 do {
3291
3292 if(this._aGroupTitleElements[i]) {
3293
3294 Dom.removeClass(this._aGroupTitleElements[i], "first-of-type");
3295
3296 nFirstIndex = i;
3297
3298 }
3299
3300 }
3301 while(i--);
3302
3303 if(nFirstIndex !== null) {
3304
3305 Dom.addClass(
3306 this._aGroupTitleElements[nFirstIndex],
3307 "first-of-type"
3308 );
3309
3310 }
3311
3312 }
3313
3314},
3315
3316/**
3317* @method addItem
3318* @description Appends an item to the menu.
3319* @param {YAHOO.widget.MenuItem} p_oItem Object reference for the MenuItem
3320* instance to be added to the menu.
3321* @param {String} p_oItem String specifying the text of the item to be added
3322* to the menu.
3323* @param {Object} p_oItem Object literal containing a set of menu item
3324* configuration properties.
3325* @param {Number} p_nGroupIndex Optional. Number indicating the group to
3326* which the item belongs.
3327* @return {YAHOO.widget.MenuItem}
3328*/
3329addItem: function(p_oItem, p_nGroupIndex) {
3330
3331 if(p_oItem) {
3332
3333 return this._addItemToGroup(p_nGroupIndex, p_oItem);
3334
3335 }
3336
3337},
3338
3339/**
3340* @method addItems
3341* @description Adds an array of items to the menu.
3342* @param {Array} p_aItems Array of items to be added to the menu. The array
3343* can contain strings specifying the text for each item to be created, object
3344* literals specifying each of the menu item configuration properties,
3345* or MenuItem instances.
3346* @param {Number} p_nGroupIndex Optional. Number specifying the group to
3347* which the items belongs.
3348* @return {Array}
3349*/
3350addItems: function(p_aItems, p_nGroupIndex) {
3351
3352 function isArray(p_oValue) {
3353
3354 return (typeof p_oValue == "object" && p_oValue.constructor == Array);
3355
3356 }
3357
3358 if(isArray(p_aItems)) {
3359
3360 var nItems = p_aItems.length;
3361 var aItems = [];
3362 var oItem;
3363
3364 for(var i=0; i<nItems; i++) {
3365
3366 oItem = p_aItems[i];
3367
3368 if(isArray(oItem)) {
3369
3370 aItems[aItems.length] = this.addItems(oItem, i);
3371
3372 }
3373 else {
3374
3375 aItems[aItems.length] =
3376 this._addItemToGroup(p_nGroupIndex, oItem);
3377
3378 }
3379
3380 }
3381
3382 if(aItems.length) {
3383
3384 return aItems;
3385
3386 }
3387
3388 }
3389
3390},
3391
3392/**
3393* @method insertItem
3394* @description Inserts an item into the menu at the specified index.
3395* @param {YAHOO.widget.MenuItem} p_oItem Object reference for the MenuItem
3396* instance to be added to the menu.
3397* @param {String} p_oItem String specifying the text of the item to be added
3398* to the menu.
3399* @param {Object} p_oItem Object literal containing a set of menu item
3400* configuration properties.
3401* @param {Number} p_nItemIndex Number indicating the ordinal position at which
3402* the item should be added.
3403* @param {Number} p_nGroupIndex Optional. Number indicating the group to which
3404* the item belongs.
3405* @return {YAHOO.widget.MenuItem}
3406*/
3407insertItem: function(p_oItem, p_nItemIndex, p_nGroupIndex) {
3408
3409 if(p_oItem) {
3410
3411 return this._addItemToGroup(p_nGroupIndex, p_oItem, p_nItemIndex);
3412
3413 }
3414
3415},
3416
3417/**
3418* @method removeItem
3419* @description Removes the specified item from the menu.
3420* @param {YAHOO.widget.MenuItem} p_oObject Object reference for the MenuItem
3421* instance to be removed from the menu.
3422* @param {Number} p_oObject Number specifying the index of the item
3423* to be removed.
3424* @param {Number} p_nGroupIndex Optional. Number specifying the group to
3425* which the item belongs.
3426* @return {YAHOO.widget.MenuItem}
3427*/
3428removeItem: function(p_oObject, p_nGroupIndex) {
3429
3430 if(typeof p_oObject != "undefined") {
3431
3432 var oItem;
3433
3434 if(p_oObject instanceof YAHOO.widget.MenuItem) {
3435
3436 oItem = this._removeItemFromGroupByValue(p_nGroupIndex, p_oObject);
3437
3438 }
3439 else if(typeof p_oObject == "number") {
3440
3441 oItem = this._removeItemFromGroupByIndex(p_nGroupIndex, p_oObject);
3442
3443 }
3444
3445 if(oItem) {
3446
3447 oItem.destroy();
3448
3449 return oItem;
3450
3451 }
3452
3453 }
3454
3455},
3456
3457/**
3458* @method getItemGroups
3459* @description Returns a multi-dimensional array of all of the items in the menu.
3460* @return {Array}
3461*/
3462getItemGroups: function() {
3463
3464 return this._aItemGroups;
3465
3466},
3467
3468/**
3469* @method getItem
3470* @description Returns the item at the specified index.
3471* @param {Number} p_nItemIndex Number indicating the ordinal position of the
3472* item to be retrieved.
3473* @param {Number} p_nGroupIndex Optional. Number indicating the group to which
3474* the item belongs.
3475* @return {YAHOO.widget.MenuItem}
3476*/
3477getItem: function(p_nItemIndex, p_nGroupIndex) {
3478
3479 if(typeof p_nItemIndex == "number") {
3480
3481 var aGroup = this._getItemGroup(p_nGroupIndex);
3482
3483 if(aGroup) {
3484
3485 return aGroup[p_nItemIndex];
3486
3487 }
3488
3489 }
3490
3491},
3492
3493/**
3494* @method destroy
3495* @description Removes the menu's <code>&#60;div&#62;</code> element
3496* (and accompanying child nodes) from the document.
3497*/
3498destroy: function() {
3499
3500 // Remove Custom Event listeners
3501
3502 this.mouseOverEvent.unsubscribeAll();
3503 this.mouseOutEvent.unsubscribeAll();
3504 this.mouseDownEvent.unsubscribeAll();
3505 this.mouseUpEvent.unsubscribeAll();
3506 this.clickEvent.unsubscribeAll();
3507 this.keyPressEvent.unsubscribeAll();
3508 this.keyDownEvent.unsubscribeAll();
3509 this.keyUpEvent.unsubscribeAll();
3510
3511 var nItemGroups = this._aItemGroups.length;
3512 var nItems;
3513 var oItemGroup;
3514 var oItem;
3515 var i;
3516 var n;
3517
3518 // Remove all items
3519
3520 if(nItemGroups > 0) {
3521
3522 i = nItemGroups - 1;
3523
3524 do {
3525
3526 oItemGroup = this._aItemGroups[i];
3527
3528 if(oItemGroup) {
3529
3530 nItems = oItemGroup.length;
3531
3532 if(nItems > 0) {
3533
3534 n = nItems - 1;
3535
3536 do {
3537
3538 oItem = this._aItemGroups[i][n];
3539
3540 if(oItem) {
3541
3542 oItem.destroy();
3543 }
3544
3545 }
3546 while(n--);
3547
3548 }
3549
3550 }
3551
3552 }
3553 while(i--);
3554
3555 }
3556
3557 // Continue with the superclass implementation of this method
3558
3559 YAHOO.widget.Menu.superclass.destroy.call(this);
3560
3561
3562},
3563
3564/**
3565* @method setInitialFocus
3566* @description Sets focus to the menu's first enabled item.
3567*/
3568setInitialFocus: function() {
3569
3570 var oItem = this._getFirstEnabledItem();
3571
3572 if(oItem) {
3573
3574 oItem.focus();
3575 }
3576
3577},
3578
3579/**
3580* @method setInitialSelection
3581* @description Sets the "selected" configuration property of the menu's first
3582* enabled item to "true."
3583*/
3584setInitialSelection: function() {
3585
3586 var oItem = this._getFirstEnabledItem();
3587
3588 if(oItem) {
3589
3590 oItem.cfg.setProperty("selected", true);
3591 }
3592
3593},
3594
3595/**
3596* @method clearActiveItem
3597* @description Sets the "selected" configuration property of the menu's active
3598* item to "false" and hides the item's submenu.
3599* @param {Boolean} p_bBlur Boolean indicating if the menu's active item
3600* should be blurred.
3601*/
3602clearActiveItem: function(p_bBlur) {
3603
3604 if(this.cfg.getProperty("showdelay") > 0) {
3605
3606 this._cancelShowDelay();
3607
3608 }
3609
3610 var oActiveItem = this.activeItem;
3611
3612 if(oActiveItem) {
3613
3614 var oConfig = oActiveItem.cfg;
3615
3616 oConfig.setProperty("selected", false);
3617
3618 var oSubmenu = oConfig.getProperty("submenu");
3619
3620 if(oSubmenu) {
3621
3622 oSubmenu.hide();
3623
3624 }
3625
3626 if(p_bBlur) {
3627
3628 oActiveItem.blur();
3629
3630 }
3631
3632 }
3633
3634},
3635
3636/**
3637* @description Initializes the class's configurable properties which can be
3638* changed using the menu's Config object ("cfg").
3639* @method initDefaultConfig
3640*/
3641initDefaultConfig: function() {
3642
3643 YAHOO.widget.Menu.superclass.initDefaultConfig.call(this);
3644
3645 var oConfig = this.cfg;
3646
3647 // Add configuration properties
3648
3649 /*
3650 Change the default value for the "visible" configuration
3651 property to "false" by re-adding the property.
3652 */
3653
3654 /**
3655 * @config visible
3656 * @description Boolean indicating whether or not the menu is visible. If
3657 * the menu's "position" configuration property is set to "dynamic" (the
3658 * default), this property toggles the menu's <code>&#60;div&#62;</code>
3659 * element's "visibility" style property between "visible" (true) or
3660 * "hidden" (false). If the menu's "position" configuration property is
3661 * set to "static" this property toggles the menu's
3662 * <code>&#60;div&#62;</code> element's "display" style property
3663 * between "block" (true) or "none" (false).
3664 * @default false
3665 * @type Boolean
3666 */
3667 oConfig.addProperty(
3668 "visible",
3669 {
3670 value:false,
3671 handler:this.configVisible,
3672 validator:this.cfg.checkBoolean
3673 }
3674 );
3675
3676 /*
3677 Change the default value for the "constraintoviewport" configuration
3678 property to "true" by re-adding the property.
3679 */
3680
3681 /**
3682 * @config constraintoviewport
3683 * @description Boolean indicating if the menu will try to remain inside
3684 * the boundaries of the size of viewport.
3685 * @default true
3686 * @type Boolean
3687 */
3688 oConfig.addProperty(
3689 "constraintoviewport",
3690 {
3691 value:true,
3692 handler:this.configConstrainToViewport,
3693 validator:this.cfg.checkBoolean,
3694 supercedes:["iframe","x","y","xy"]
3695 }
3696 );
3697
3698 /**
3699 * @config position
3700 * @description String indicating how a menu should be positioned on the
3701 * screen. Possible values are "static" and "dynamic." Static menus are
3702 * visible by default and reside in the normal flow of the document
3703 * (CSS position: static). Dynamic menus are hidden by default, reside
3704 * out of the normal flow of the document (CSS position: absolute), and
3705 * can overlay other elements on the screen.
3706 * @default dynamic
3707 * @type String
3708 */
3709 oConfig.addProperty(
3710 "position",
3711 {
3712 value: "dynamic",
3713 handler: this.configPosition,
3714 validator: this._checkPosition,
3715 supercedes: ["visible"]
3716 }
3717 );
3718
3719 /**
3720 * @config submenualignment
3721 * @description Array defining how submenus should be aligned to their
3722 * parent menu item. The format is: [itemCorner, submenuCorner]. By default
3723 * a submenu's top left corner is aligned to its parent menu item's top
3724 * right corner.
3725 * @default ["tl","tr"]
3726 * @type Array
3727 */
3728 oConfig.addProperty("submenualignment", { value: ["tl","tr"] } );
3729
3730 /**
3731 * @config autosubmenudisplay
3732 * @description Boolean indicating if submenus are automatically made
3733 * visible when the user mouses over the menu's items.
3734 * @default true
3735 * @type Boolean
3736 */
3737 oConfig.addProperty(
3738 "autosubmenudisplay",
3739 {
3740 value: true,
3741 validator: oConfig.checkBoolean
3742 }
3743 );
3744
3745 /**
3746 * @config showdelay
3747 * @description Number indicating the time (in milliseconds) that should
3748 * expire before a submenu is made visible when the user mouses over
3749 * the menu's items.
3750 * @default 0
3751 * @type Number
3752 */
3753 oConfig.addProperty(
3754 "showdelay",
3755 {
3756 value: 0,
3757 validator: oConfig.checkNumber
3758 }
3759 );
3760
3761 /**
3762 * @config hidedelay
3763 * @description Number indicating the time (in milliseconds) that should
3764 * expire before the menu is hidden.
3765 * @default 0
3766 * @type Number
3767 */
3768 oConfig.addProperty(
3769 "hidedelay",
3770 {
3771 value: 0,
3772 validator: oConfig.checkNumber,
3773 handler: this.configHideDelay,
3774 suppressEvent: true
3775 }
3776 );
3777
3778 /**
3779 * @config clicktohide
3780 * @description Boolean indicating if the menu will automatically be
3781 * hidden if the user clicks outside of it.
3782 * @default true
3783 * @type Boolean
3784 */
3785 oConfig.addProperty(
3786 "clicktohide",
3787 {
3788 value: true,
3789 validator: oConfig.checkBoolean
3790 }
3791 );
3792
3793 /**
3794 * @config container
3795 * @description HTML element reference or string specifying the id
3796 * attribute of the HTML element that the menu's markup should be rendered into.
3797 * @type <a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
3798 * level-one-html.html#ID-58190037">HTMLElement</a>|String
3799 * @default document.body
3800 */
3801 this.cfg.addProperty(
3802 "container",
3803 { value:document.body, handler:this.configContainer }
3804 );
3805
3806}
3807
3808}); // END YAHOO.extend
3809
3810})();
3811
3812/**
3813* The base class for all menuing containers.
3814*
3815* @param {String} p_oElement String specifying the id attribute of the
3816* <code>&#60;div&#62;</code> element of the menu module.
3817* @param {String} p_oElement String specifying the id attribute of the
3818* <code>&#60;select&#62;</code> element to be used as the data source for the
3819* menu module.
3820* @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929
3821* /level-one-html.html#ID-22445964">HTMLDivElement</a>} p_oElement Object
3822* specifying the <code>&#60;div&#62;</code> element of the menu module.
3823* @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
3824* one-html.html#ID-94282980">HTMLSelectElement</a>} p_oElement Object
3825* specifying the <code>&#60;select&#62;</code> element to be used as the data
3826* source for the menu module.
3827* @param {Object} p_oConfig Optional. Object literal specifying the
3828* configuration for the menu module. See configuration class documentation for
3829* more details.
3830* @class MenuModule
3831* @constructor
3832* @extends YAHOO.widget.Overlay
3833* @deprecated As of version 0.12, all MenuModule functionality has been
3834* implemented directly in YAHOO.widget.Menu, making YAHOO.widget.Menu the base
3835* class for all menuing containers.
3836*/
3837YAHOO.widget.MenuModule = YAHOO.widget.Menu;
3838
3839(function() {
3840
3841var Dom = YAHOO.util.Dom;
3842var Module = YAHOO.widget.Module;
3843var Menu = YAHOO.widget.Menu;
3844
3845/**
3846* Creates an item for a menu.
3847*
3848* @param {String} p_oObject String specifying the text of the menu item.
3849* @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
3850* one-html.html#ID-74680021">HTMLLIElement</a>} p_oObject Object specifying
3851* the <code>&#60;li&#62;</code> element of the menu item.
3852* @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
3853* one-html.html#ID-38450247">HTMLOptGroupElement</a>} p_oObject Object
3854* specifying the <code>&#60;optgroup&#62;</code> element of the menu item.
3855* @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
3856* one-html.html#ID-70901257">HTMLOptionElement</a>} p_oObject Object
3857* specifying the <code>&#60;option&#62;</code> element of the menu item.
3858* @param {Object} p_oConfig Optional. Object literal specifying the
3859* configuration for the menu item. See configuration class documentation
3860* for more details.
3861* @class MenuItem
3862* @constructor
3863*/
3864YAHOO.widget.MenuItem = function(p_oObject, p_oConfig) {
3865
3866 if(p_oObject) {
3867
3868 if(p_oConfig) {
3869
3870 this.parent = p_oConfig.parent;
3871 this.value = p_oConfig.value;
3872
3873 }
3874
3875 this.init(p_oObject, p_oConfig);
3876
3877 }
3878
3879};
3880
3881YAHOO.widget.MenuItem.prototype = {
3882
3883 // Constants
3884
3885 /**
3886 * @property SUBMENU_INDICATOR_IMAGE_PATH
3887 * @description String representing the path to the image to be used for the
3888 * menu item's submenu arrow indicator.
3889 * @default "nt/ic/ut/alt1/menuarorght8_nrm_1.gif"
3890 * @final
3891 * @type String
3892 */
3893 SUBMENU_INDICATOR_IMAGE_PATH: "nt/ic/ut/alt1/menuarorght8_nrm_1.gif",
3894
3895 /**
3896 * @property SELECTED_SUBMENU_INDICATOR_IMAGE_PATH
3897 * @description String representing the path to the image to be used for the
3898 * submenu arrow indicator when the menu item is selected.
3899 * @default "nt/ic/ut/alt1/menuarorght8_hov_1.gif"
3900 * @final
3901 * @type String
3902 */
3903 SELECTED_SUBMENU_INDICATOR_IMAGE_PATH:
3904 "nt/ic/ut/alt1/menuarorght8_hov_1.gif",
3905
3906 /**
3907 * @property DISABLED_SUBMENU_INDICATOR_IMAGE_PATH
3908 * @description String representing the path to the image to be used for the
3909 * submenu arrow indicator when the menu item is disabled.
3910 * @default "nt/ic/ut/alt1/menuarorght8_dim_1.gif"
3911 * @final
3912 * @type String
3913 */
3914 DISABLED_SUBMENU_INDICATOR_IMAGE_PATH:
3915 "nt/ic/ut/alt1/menuarorght8_dim_1.gif",
3916
3917 /**
3918 * @property COLLAPSED_SUBMENU_INDICATOR_ALT_TEXT
3919 * @description String representing the alt text for the image to be used
3920 * for the submenu arrow indicator.
3921 * @default "Collapsed. Click to expand."
3922 * @final
3923 * @type String
3924 */
3925 COLLAPSED_SUBMENU_INDICATOR_ALT_TEXT: "Collapsed. Click to expand.",
3926
3927 /**
3928 * @property EXPANDED_SUBMENU_INDICATOR_ALT_TEXT
3929 * @description String representing the alt text for the image to be used
3930 * for the submenu arrow indicator when the submenu is visible.
3931 * @default "Expanded. Click to collapse."
3932 * @final
3933 * @type String
3934 */
3935 EXPANDED_SUBMENU_INDICATOR_ALT_TEXT: "Expanded. Click to collapse.",
3936
3937 /**
3938 * @property DISABLED_SUBMENU_INDICATOR_ALT_TEXT
3939 * @description String representing the alt text for the image to be used
3940 * for the submenu arrow indicator when the menu item is disabled.
3941 * @default "Disabled."
3942 * @final
3943 * @type String
3944 */
3945 DISABLED_SUBMENU_INDICATOR_ALT_TEXT: "Disabled.",
3946
3947 /**
3948 * @property CHECKED_IMAGE_PATH
3949 * @description String representing the path to the image to be used for
3950 * the checked state.
3951 * @default "nt/ic/ut/bsc/menuchk8_nrm_1.gif"
3952 * @final
3953 * @type String
3954 */
3955 CHECKED_IMAGE_PATH: "nt/ic/ut/bsc/menuchk8_nrm_1.gif",
3956
3957
3958 /**
3959 * @property SELECTED_CHECKED_IMAGE_PATH
3960 * @description String representing the path to the image to be used for
3961 * the selected checked state.
3962 * @default "nt/ic/ut/bsc/menuchk8_hov_1.gif"
3963 * @final
3964 * @type String
3965 */
3966 SELECTED_CHECKED_IMAGE_PATH: "nt/ic/ut/bsc/menuchk8_hov_1.gif",
3967
3968
3969 /**
3970 * @property DISABLED_CHECKED_IMAGE_PATH
3971 * @description String representing the path to the image to be used for
3972 * the disabled checked state.
3973 * @default "nt/ic/ut/bsc/menuchk8_dim_1.gif"
3974 * @final
3975 * @type String
3976 */
3977 DISABLED_CHECKED_IMAGE_PATH: "nt/ic/ut/bsc/menuchk8_dim_1.gif",
3978
3979
3980 /**
3981 * @property CHECKED_IMAGE_ALT_TEXT
3982 * @description String representing the alt text for the image to be used
3983 * for the checked image.
3984 * @default "Checked."
3985 * @final
3986 * @type String
3987 */
3988 CHECKED_IMAGE_ALT_TEXT: "Checked.",
3989
3990
3991 /**
3992 * @property DISABLED_CHECKED_IMAGE_ALT_TEXT
3993 * @description String representing the alt text for the image to be used
3994 * for the checked image when the item is disabled.
3995 * @default "Checked. (Item disabled.)"
3996 * @final
3997 * @type String
3998 */
3999 DISABLED_CHECKED_IMAGE_ALT_TEXT: "Checked. (Item disabled.)",
4000
4001 /**
4002 * @property CSS_CLASS_NAME
4003 * @description String representing the CSS class(es) to be applied to the
4004 * <code>&#60;li&#62;</code> element of the menu item.
4005 * @default "yuimenuitem"
4006 * @final
4007 * @type String
4008 */
4009 CSS_CLASS_NAME: "yuimenuitem",
4010
4011 /**
4012 * @property SUBMENU_TYPE
4013 * @description Object representing the type of menu to instantiate and
4014 * add when parsing the child nodes of the menu item's source HTML element.
4015 * @final
4016 * @type YAHOO.widget.Menu
4017 */
4018 SUBMENU_TYPE: null,
4019
4020 /**
4021 * @property IMG_ROOT
4022 * @description String representing the prefix path to use for
4023 * non-secure images.
4024 * @default "http://us.i1.yimg.com/us.yimg.com/i/"
4025 * @type String
4026 */
4027 IMG_ROOT: "http://us.i1.yimg.com/us.yimg.com/i/",
4028
4029
4030 /**
4031 * @property IMG_ROOT_SSL
4032 * @description String representing the prefix path to use for securely
4033 * served images.
4034 * @default "https://a248.e.akamai.net/sec.yimg.com/i/"
4035 * @type String
4036 */
4037 IMG_ROOT_SSL: "https://a248.e.akamai.net/sec.yimg.com/i/",
4038
4039 // Private member variables
4040
4041 /**
4042 * @property _oAnchor
4043 * @description Object reference to the menu item's
4044 * <code>&#60;a&#62;</code> element.
4045 * @default null
4046 * @private
4047 * @type <a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
4048 * one-html.html#ID-48250443">HTMLAnchorElement</a>
4049 */
4050 _oAnchor: null,
4051
4052
4053 /**
4054 * @property _oText
4055 * @description Object reference to the menu item's text node.
4056 * @default null
4057 * @private
4058 * @type TextNode
4059 */
4060 _oText: null,
4061
4062
4063 /**
4064 * @property _oHelpTextEM
4065 * @description Object reference to the menu item's help text
4066 * <code>&#60;em&#62;</code> element.
4067 * @default null
4068 * @private
4069 * @type <a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
4070 * one-html.html#ID-58190037">HTMLElement</a>
4071 */
4072 _oHelpTextEM: null,
4073
4074
4075 /**
4076 * @property _oSubmenu
4077 * @description Object reference to the menu item's submenu.
4078 * @default null
4079 * @private
4080 * @type YAHOO.widget.Menu
4081 */
4082 _oSubmenu: null,
4083
4084 /**
4085 * @property _checkImage
4086 * @description Object reference to the menu item's checkmark image.
4087 * @default null
4088 * @private
4089 * @type <a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
4090 * one-html.html#ID-17701901">HTMLImageElement</a>
4091 */
4092 _checkImage: null,
4093
4094 // Public properties
4095
4096 /**
4097 * @property constructor
4098 * @description Object reference to the menu item's constructor function.
4099 * @default YAHOO.widget.MenuItem
4100 * @type YAHOO.widget.MenuItem
4101 */
4102 constructor: YAHOO.widget.MenuItem,
4103
4104 /**
4105 * @property imageRoot
4106 * @description String representing the root path for all of the menu
4107 * item's images.
4108 * @type String
4109 */
4110 imageRoot: null,
4111
4112 /**
4113 * @property isSecure
4114 * @description Boolean representing whether or not the current browsing
4115 * context is secure (HTTPS).
4116 * @type Boolean
4117 */
4118 isSecure: Module.prototype.isSecure,
4119
4120 /**
4121 * @property index
4122 * @description Number indicating the ordinal position of the menu item in
4123 * its group.
4124 * @default null
4125 * @type Number
4126 */
4127 index: null,
4128
4129 /**
4130 * @property groupIndex
4131 * @description Number indicating the index of the group to which the menu
4132 * item belongs.
4133 * @default null
4134 * @type Number
4135 */
4136 groupIndex: null,
4137
4138 /**
4139 * @property parent
4140 * @description Object reference to the menu item's parent menu.
4141 * @default null
4142 * @type YAHOO.widget.Menu
4143 */
4144 parent: null,
4145
4146 /**
4147 * @property element
4148 * @description Object reference to the menu item's
4149 * <code>&#60;li&#62;</code> element.
4150 * @default <a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level
4151 * -one-html.html#ID-74680021">HTMLLIElement</a>
4152 * @type <a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
4153 * one-html.html#ID-74680021">HTMLLIElement</a>
4154 */
4155 element: null,
4156
4157 /**
4158 * @property srcElement
4159 * @description Object reference to the HTML element (either
4160 * <code>&#60;li&#62;</code>, <code>&#60;optgroup&#62;</code> or
4161 * <code>&#60;option&#62;</code>) used create the menu item.
4162 * @default <a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
4163 * level-one-html.html#ID-74680021">HTMLLIElement</a>|<a href="http://www.
4164 * w3.org/TR/2000/WD-DOM-Level-1-20000929/level-one-html.html#ID-38450247"
4165 * >HTMLOptGroupElement</a>|<a href="http://www.w3.org/TR/2000/WD-DOM-
4166 * Level-1-20000929/level-one-html.html#ID-70901257">HTMLOptionElement</a>
4167 * @type <a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
4168 * one-html.html#ID-74680021">HTMLLIElement</a>|<a href="http://www.w3.
4169 * org/TR/2000/WD-DOM-Level-1-20000929/level-one-html.html#ID-38450247">
4170 * HTMLOptGroupElement</a>|<a href="http://www.w3.org/TR/2000/WD-DOM-
4171 * Level-1-20000929/level-one-html.html#ID-70901257">HTMLOptionElement</a>
4172 */
4173 srcElement: null,
4174
4175 /**
4176 * @property value
4177 * @description Object reference to the menu item's value.
4178 * @default null
4179 * @type Object
4180 */
4181 value: null,
4182
4183 /**
4184 * @property submenuIndicator
4185 * @description Object reference to the <code>&#60;img&#62;</code> element
4186 * used to create the submenu indicator for the menu item.
4187 * @default <a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
4188 * level-one-html.html#ID-17701901">HTMLImageElement</a>
4189 * @type <a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
4190 * level-one-html.html#ID-17701901">HTMLImageElement</a>
4191 */
4192 submenuIndicator: null,
4193
4194 /**
4195 * @property browser
4196 * @description String representing the browser.
4197 * @type String
4198 */
4199 browser: Module.prototype.browser,
4200
4201 // Events
4202
4203 /**
4204 * @event destroyEvent
4205 * @description Fires when the menu item's <code>&#60;li&#62;</code>
4206 * element is removed from its parent <code>&#60;ul&#62;</code> element.
4207 * @type YAHOO.util.CustomEvent
4208 */
4209 destroyEvent: null,
4210
4211 /**
4212 * @event mouseOverEvent
4213 * @description Fires when the mouse has entered the menu item. Passes
4214 * back the DOM Event object as an argument.
4215 * @type YAHOO.util.CustomEvent
4216 */
4217 mouseOverEvent: null,
4218
4219 /**
4220 * @event mouseOutEvent
4221 * @description Fires when the mouse has left the menu item. Passes back
4222 * the DOM Event object as an argument.
4223 * @type YAHOO.util.CustomEvent
4224 */
4225 mouseOutEvent: null,
4226
4227 /**
4228 * @event mouseDownEvent
4229 * @description Fires when the user mouses down on the menu item. Passes
4230 * back the DOM Event object as an argument.
4231 * @type YAHOO.util.CustomEvent
4232 */
4233 mouseDownEvent: null,
4234
4235 /**
4236 * @event mouseUpEvent
4237 * @description Fires when the user releases a mouse button while the mouse
4238 * is over the menu item. Passes back the DOM Event object as an argument.
4239 * @type YAHOO.util.CustomEvent
4240 */
4241 mouseUpEvent: null,
4242
4243 /**
4244 * @event clickEvent
4245 * @description Fires when the user clicks the on the menu item. Passes
4246 * back the DOM Event object as an argument.
4247 * @type YAHOO.util.CustomEvent
4248 */
4249 clickEvent: null,
4250
4251 /**
4252 * @event keyPressEvent
4253 * @description Fires when the user presses an alphanumeric key when the
4254 * menu item has focus. Passes back the DOM Event object as an argument.
4255 * @type YAHOO.util.CustomEvent
4256 */
4257 keyPressEvent: null,
4258
4259 /**
4260 * @event keyDownEvent
4261 * @description Fires when the user presses a key when the menu item has
4262 * focus. Passes back the DOM Event object as an argument.
4263 * @type YAHOO.util.CustomEvent
4264 */
4265 keyDownEvent: null,
4266
4267 /**
4268 * @event keyUpEvent
4269 * @description Fires when the user releases a key when the menu item has
4270 * focus. Passes back the DOM Event object as an argument.
4271 * @type YAHOO.util.CustomEvent
4272 */
4273 keyUpEvent: null,
4274
4275 /**
4276 * @event focusEvent
4277 * @description Fires when the menu item receives focus.
4278 * @type YAHOO.util.CustomEvent
4279 */
4280 focusEvent: null,
4281
4282 /**
4283 * @event blurEvent
4284 * @description Fires when the menu item loses the input focus.
4285 * @type YAHOO.util.CustomEvent
4286 */
4287 blurEvent: null,
4288
4289 /**
4290 * @method init
4291 * @description The MenuItem class's initialization method. This method is
4292 * automatically called by the constructor, and sets up all DOM references
4293 * for pre-existing markup, and creates required markup if it is not
4294 * already present.
4295 * @param {String} p_oObject String specifying the text of the menu item.
4296 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
4297 * one-html.html#ID-74680021">HTMLLIElement</a>} p_oObject Object specifying
4298 * the <code>&#60;li&#62;</code> element of the menu item.
4299 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
4300 * one-html.html#ID-38450247">HTMLOptGroupElement</a>} p_oObject Object
4301 * specifying the <code>&#60;optgroup&#62;</code> element of the menu item.
4302 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
4303 * one-html.html#ID-70901257">HTMLOptionElement</a>} p_oObject Object
4304 * specifying the <code>&#60;option&#62;</code> element of the menu item.
4305 * @param {Object} p_oConfig Optional. Object literal specifying the
4306 * configuration for the menu item. See configuration class documentation
4307 * for more details.
4308 */
4309 init: function(p_oObject, p_oConfig) {
4310
4311 this.imageRoot = (this.isSecure) ? this.IMG_ROOT_SSL : this.IMG_ROOT;
4312
4313 if(!this.SUBMENU_TYPE) {
4314
4315 this.SUBMENU_TYPE = Menu;
4316
4317 }
4318
4319 // Create the config object
4320
4321 this.cfg = new YAHOO.util.Config(this);
4322
4323 this.initDefaultConfig();
4324
4325 var oConfig = this.cfg;
4326
4327 if(this._checkString(p_oObject)) {
4328
4329 this._createRootNodeStructure();
4330
4331 oConfig.setProperty("text", p_oObject);
4332
4333 }
4334 else if(this._checkDOMNode(p_oObject)) {
4335
4336 switch(p_oObject.tagName.toUpperCase()) {
4337
4338 case "OPTION":
4339
4340 this._createRootNodeStructure();
4341
4342 oConfig.setProperty("text", p_oObject.text);
4343
4344 this.srcElement = p_oObject;
4345
4346 break;
4347
4348 case "OPTGROUP":
4349
4350 this._createRootNodeStructure();
4351
4352 oConfig.setProperty("text", p_oObject.label);
4353
4354 this.srcElement = p_oObject;
4355
4356 this._initSubTree();
4357
4358 break;
4359
4360 case "LI":
4361
4362 // Get the anchor node (if it exists)
4363
4364 var oAnchor = this._getFirstElement(p_oObject, "A");
4365 var sURL = "#";
4366 var sTarget = null;
4367 var sText = null;
4368
4369 // Capture the "text" and/or the "URL"
4370
4371 if(oAnchor) {
4372
4373 sURL = oAnchor.getAttribute("href");
4374 sTarget = oAnchor.getAttribute("target");
4375
4376 if(oAnchor.innerText) {
4377
4378 sText = oAnchor.innerText;
4379
4380 }
4381 else {
4382
4383 var oRange = oAnchor.ownerDocument.createRange();
4384
4385 oRange.selectNodeContents(oAnchor);
4386
4387 sText = oRange.toString();
4388
4389 }
4390
4391 }
4392 else {
4393
4394 var oText = p_oObject.firstChild;
4395
4396 sText = oText.nodeValue;
4397
4398 oAnchor = document.createElement("a");
4399
4400 oAnchor.setAttribute("href", sURL);
4401
4402 p_oObject.replaceChild(oAnchor, oText);
4403
4404 oAnchor.appendChild(oText);
4405
4406 }
4407
4408 this.srcElement = p_oObject;
4409 this.element = p_oObject;
4410 this._oAnchor = oAnchor;
4411
4412
4413 // Check if emphasis has been applied to the MenuItem
4414
4415 var oEmphasisNode = this._getFirstElement(oAnchor);
4416 var bEmphasis = false;
4417 var bStrongEmphasis = false;
4418
4419 if(oEmphasisNode) {
4420
4421 // Set a reference to the text node
4422
4423 this._oText = oEmphasisNode.firstChild;
4424
4425 switch(oEmphasisNode.tagName.toUpperCase()) {
4426
4427 case "EM":
4428
4429 bEmphasis = true;
4430
4431 break;
4432
4433 case "STRONG":
4434
4435 bStrongEmphasis = true;
4436
4437 break;
4438
4439 }
4440
4441 }
4442 else {
4443
4444 // Set a reference to the text node
4445
4446 this._oText = oAnchor.firstChild;
4447
4448 }
4449
4450 /*
4451 Set these properties silently to sync up the
4452 configuration object without making changes to the
4453 element's DOM
4454 */
4455
4456 oConfig.setProperty("text", sText, true);
4457 oConfig.setProperty("url", sURL, true);
4458 oConfig.setProperty("target", sTarget, true);
4459 oConfig.setProperty("emphasis", bEmphasis, true);
4460 oConfig.setProperty(
4461 "strongemphasis",
4462 bStrongEmphasis,
4463 true
4464 );
4465
4466 this._initSubTree();
4467
4468 break;
4469
4470 }
4471
4472 }
4473
4474 if(this.element) {
4475
4476 Dom.addClass(this.element, this.CSS_CLASS_NAME);
4477
4478 // Create custom events
4479
4480 var CustomEvent = YAHOO.util.CustomEvent;
4481
4482 this.destroyEvent = new CustomEvent("destroyEvent", this);
4483 this.mouseOverEvent = new CustomEvent("mouseOverEvent", this);
4484 this.mouseOutEvent = new CustomEvent("mouseOutEvent", this);
4485 this.mouseDownEvent = new CustomEvent("mouseDownEvent", this);
4486 this.mouseUpEvent = new CustomEvent("mouseUpEvent", this);
4487 this.clickEvent = new CustomEvent("clickEvent", this);
4488 this.keyPressEvent = new CustomEvent("keyPressEvent", this);
4489 this.keyDownEvent = new CustomEvent("keyDownEvent", this);
4490 this.keyUpEvent = new CustomEvent("keyUpEvent", this);
4491 this.focusEvent = new CustomEvent("focusEvent", this);
4492 this.blurEvent = new CustomEvent("blurEvent", this);
4493
4494 if(p_oConfig) {
4495
4496 oConfig.applyConfig(p_oConfig);
4497
4498 }
4499
4500 oConfig.fireQueue();
4501
4502 }
4503
4504 },
4505
4506 // Private methods
4507
4508 /**
4509 * @method _getFirstElement
4510 * @description Returns an HTML element's first HTML element node.
4511 * @private
4512 * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
4513 * level-one-html.html#ID-58190037">HTMLElement</a>} p_oElement Object
4514 * reference specifying the element to be evaluated.
4515 * @param {String} p_sTagName Optional. String specifying the tagname of
4516 * the element to be retrieved.
4517 * @return {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
4518 * level-one-html.html#ID-58190037">HTMLElement</a>}
4519 */
4520 _getFirstElement: function(p_oElement, p_sTagName) {
4521
4522 var oElement;
4523
4524 if(p_oElement.firstChild && p_oElement.firstChild.nodeType == 1) {
4525
4526 oElement = p_oElement.firstChild;
4527
4528 }
4529 else if(
4530 p_oElement.firstChild &&
4531 p_oElement.firstChild.nextSibling &&
4532 p_oElement.firstChild.nextSibling.nodeType == 1
4533 ) {
4534
4535 oElement = p_oElement.firstChild.nextSibling;
4536
4537 }
4538
4539 if(p_sTagName) {
4540
4541 return (oElement && oElement.tagName.toUpperCase() == p_sTagName) ?
4542 oElement : false;
4543
4544 }
4545
4546 return oElement;
4547
4548 },
4549
4550 /**
4551 * @method _checkString
4552 * @description Determines if an object is a string.
4553 * @private
4554 * @param {Object} p_oObject Object to be evaluated.
4555 * @return {Boolean}
4556 */
4557 _checkString: function(p_oObject) {
4558
4559 return (typeof p_oObject == "string");
4560
4561 },
4562
4563 /**
4564 * @method _checkDOMNode
4565 * @description Determines if an object is an HTML element.
4566 * @private
4567 * @param {Object} p_oObject Object to be evaluated.
4568 * @return {Boolean}
4569 */
4570 _checkDOMNode: function(p_oObject) {
4571
4572 return (p_oObject && p_oObject.tagName);
4573
4574 },
4575
4576 /**
4577 * @method _createRootNodeStructure
4578 * @description Creates the core DOM structure for the menu item.
4579 * @private
4580 */
4581 _createRootNodeStructure: function () {
4582
4583 this.element = document.createElement("li");
4584
4585 this._oText = document.createTextNode("");
4586
4587 this._oAnchor = document.createElement("a");
4588 this._oAnchor.appendChild(this._oText);
4589
4590 this.cfg.refireEvent("url");
4591
4592 this.element.appendChild(this._oAnchor);
4593
4594 },
4595
4596 /**
4597 * @method _initSubTree
4598 * @description Iterates the source element's childNodes collection and uses
4599 * the child nodes to instantiate other menus.
4600 * @private
4601 */
4602 _initSubTree: function() {
4603
4604 var oSrcEl = this.srcElement;
4605 var oConfig = this.cfg;
4606
4607 if(oSrcEl.childNodes.length > 0) {
4608
4609 if(
4610 this.parent.lazyLoad &&
4611 this.parent.srcElement &&
4612 this.parent.srcElement.tagName.toUpperCase() == "SELECT"
4613 ) {
4614
4615 oConfig.setProperty(
4616 "submenu",
4617 { id: Dom.generateId(), itemdata: oSrcEl.childNodes }
4618 );
4619
4620 }
4621 else {
4622
4623 var oNode = oSrcEl.firstChild;
4624 var aOptions = [];
4625
4626 do {
4627
4628 if(oNode && oNode.tagName) {
4629
4630 switch(oNode.tagName.toUpperCase()) {
4631
4632 case "DIV":
4633
4634 oConfig.setProperty("submenu", oNode);
4635
4636 break;
4637
4638 case "OPTION":
4639
4640 aOptions[aOptions.length] = oNode;
4641
4642 break;
4643
4644 }
4645
4646 }
4647
4648 }
4649 while((oNode = oNode.nextSibling));
4650
4651
4652 var nOptions = aOptions.length;
4653
4654 if(nOptions > 0) {
4655
4656 var oMenu = new this.SUBMENU_TYPE(Dom.generateId());
4657
4658 oConfig.setProperty("submenu", oMenu);
4659
4660 for(var n=0; n<nOptions; n++) {
4661
4662 oMenu.addItem((new oMenu.ITEM_TYPE(aOptions[n])));
4663
4664 }
4665
4666 }
4667
4668 }
4669
4670 }
4671
4672 },
4673
4674 /**
4675 * @method _preloadImage
4676 * @description Preloads an image by creating an image element from the
4677 * specified path and appending the image to the body of the document.
4678 * @private
4679 * @param {String} p_sPath String specifying the path to the image.
4680 */
4681 _preloadImage: function(p_sPath) {
4682
4683 var sPath = this.imageRoot + p_sPath;
4684
4685 if(!document.images[sPath]) {
4686
4687 var oImage = document.createElement("img");
4688 oImage.src = sPath;
4689 oImage.name = sPath;
4690 oImage.id = sPath;
4691 oImage.style.display = "none";
4692
4693 document.body.appendChild(oImage);
4694
4695 }
4696
4697 },
4698
4699 // Event handlers for configuration properties
4700
4701 /**
4702 * @method configText
4703 * @description Event handler for when the "text" configuration property of
4704 * the menu item changes.
4705 * @param {String} p_sType String representing the name of the event that
4706 * was fired.
4707 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
4708 * @param {YAHOO.widget.MenuItem} p_oItem Object representing the menu item
4709 * that fired the event.
4710 */
4711 configText: function(p_sType, p_aArgs, p_oItem) {
4712
4713 var sText = p_aArgs[0];
4714
4715 if(this._oText) {
4716
4717 this._oText.nodeValue = sText;
4718
4719 }
4720
4721 },
4722
4723 /**
4724 * @method configHelpText
4725 * @description Event handler for when the "helptext" configuration property
4726 * of the menu item changes.
4727 * @param {String} p_sType String representing the name of the event that
4728 * was fired.
4729 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
4730 * @param {YAHOO.widget.MenuItem} p_oItem Object representing the menu item
4731 * that fired the event.
4732 */
4733 configHelpText: function(p_sType, p_aArgs, p_oItem) {
4734
4735 var me = this;
4736 var oHelpText = p_aArgs[0];
4737 var oEl = this.element;
4738 var oConfig = this.cfg;
4739 var aNodes = [oEl, this._oAnchor];
4740 var oImg = this.submenuIndicator;
4741
4742 /**
4743 * Adds the "hashelptext" class to the necessary nodes and refires the
4744 * "selected" and "disabled" configuration events.
4745 * @private
4746 */
4747 var initHelpText = function() {
4748
4749 Dom.addClass(aNodes, "hashelptext");
4750
4751 if(oConfig.getProperty("disabled")) {
4752
4753 oConfig.refireEvent("disabled");
4754
4755 }
4756
4757 if(oConfig.getProperty("selected")) {
4758
4759 oConfig.refireEvent("selected");
4760
4761 }
4762
4763 };
4764
4765 /**
4766 * Removes the "hashelptext" class and corresponding DOM element (EM).
4767 * @private
4768 */
4769 var removeHelpText = function() {
4770
4771 Dom.removeClass(aNodes, "hashelptext");
4772
4773 oEl.removeChild(me._oHelpTextEM);
4774 me._oHelpTextEM = null;
4775
4776 };
4777
4778 if(this._checkDOMNode(oHelpText)) {
4779
4780 if(this._oHelpTextEM) {
4781
4782 this._oHelpTextEM.parentNode.replaceChild(
4783 oHelpText,
4784 this._oHelpTextEM
4785 );
4786
4787 }
4788 else {
4789
4790 this._oHelpTextEM = oHelpText;
4791
4792 oEl.insertBefore(this._oHelpTextEM, oImg);
4793
4794 }
4795
4796 initHelpText();
4797
4798 }
4799 else if(this._checkString(oHelpText)) {
4800
4801 if(oHelpText.length === 0) {
4802
4803 removeHelpText();
4804
4805 }
4806 else {
4807
4808 if(!this._oHelpTextEM) {
4809
4810 this._oHelpTextEM = document.createElement("em");
4811
4812 oEl.insertBefore(this._oHelpTextEM, oImg);
4813
4814 }
4815
4816 this._oHelpTextEM.innerHTML = oHelpText;
4817
4818 initHelpText();
4819
4820 }
4821
4822 }
4823 else if(!oHelpText && this._oHelpTextEM) {
4824
4825 removeHelpText();
4826
4827 }
4828
4829 },
4830
4831 /**
4832 * @method configURL
4833 * @description Event handler for when the "url" configuration property of
4834 * the menu item changes.
4835 * @param {String} p_sType String representing the name of the event that
4836 * was fired.
4837 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
4838 * @param {YAHOO.widget.MenuItem} p_oItem Object representing the menu item
4839 * that fired the event.
4840 */
4841 configURL: function(p_sType, p_aArgs, p_oItem) {
4842
4843 var sURL = p_aArgs[0];
4844
4845 if(!sURL) {
4846
4847 sURL = "#";
4848
4849 }
4850
4851 this._oAnchor.setAttribute("href", sURL);
4852
4853 },
4854
4855 /**
4856 * @method configTarget
4857 * @description Event handler for when the "target" configuration property
4858 * of the menu item changes.
4859 * @param {String} p_sType String representing the name of the event that
4860 * was fired.
4861 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
4862 * @param {YAHOO.widget.MenuItem} p_oItem Object representing the menu item
4863 * that fired the event.
4864 */
4865 configTarget: function(p_sType, p_aArgs, p_oItem) {
4866
4867 var sTarget = p_aArgs[0];
4868 var oAnchor = this._oAnchor;
4869
4870 if(sTarget && sTarget.length > 0) {
4871
4872 oAnchor.setAttribute("target", sTarget);
4873
4874 }
4875 else {
4876
4877 oAnchor.removeAttribute("target");
4878
4879 }
4880
4881 },
4882
4883 /**
4884 * @method configEmphasis
4885 * @description Event handler for when the "emphasis" configuration property
4886 * of the menu item changes.
4887 * @param {String} p_sType String representing the name of the event that
4888 * was fired.
4889 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
4890 * @param {YAHOO.widget.MenuItem} p_oItem Object representing the menu item
4891 * that fired the event.
4892 */
4893 configEmphasis: function(p_sType, p_aArgs, p_oItem) {
4894
4895 var bEmphasis = p_aArgs[0];
4896 var oAnchor = this._oAnchor;
4897 var oText = this._oText;
4898 var oConfig = this.cfg;
4899 var oEM;
4900
4901 if(bEmphasis && oConfig.getProperty("strongemphasis")) {
4902
4903 oConfig.setProperty("strongemphasis", false);
4904
4905 }
4906
4907 if(oAnchor) {
4908
4909 if(bEmphasis) {
4910
4911 oEM = document.createElement("em");
4912 oEM.appendChild(oText);
4913
4914 oAnchor.appendChild(oEM);
4915
4916 }
4917 else {
4918
4919 oEM = this._getFirstElement(oAnchor, "EM");
4920
4921 oAnchor.removeChild(oEM);
4922 oAnchor.appendChild(oText);
4923
4924 }
4925
4926 }
4927
4928 },
4929
4930 /**
4931 * @method configStrongEmphasis
4932 * @description Event handler for when the "strongemphasis" configuration
4933 * property of the menu item changes.
4934 * @param {String} p_sType String representing the name of the event that
4935 * was fired.
4936 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
4937 * @param {YAHOO.widget.MenuItem} p_oItem Object representing the menu item
4938 * that fired the event.
4939 */
4940 configStrongEmphasis: function(p_sType, p_aArgs, p_oItem) {
4941
4942 var bStrongEmphasis = p_aArgs[0];
4943 var oAnchor = this._oAnchor;
4944 var oText = this._oText;
4945 var oConfig = this.cfg;
4946 var oStrong;
4947
4948 if(bStrongEmphasis && oConfig.getProperty("emphasis")) {
4949
4950 oConfig.setProperty("emphasis", false);
4951
4952 }
4953
4954 if(oAnchor) {
4955
4956 if(bStrongEmphasis) {
4957
4958 oStrong = document.createElement("strong");
4959 oStrong.appendChild(oText);
4960
4961 oAnchor.appendChild(oStrong);
4962
4963 }
4964 else {
4965
4966 oStrong = this._getFirstElement(oAnchor, "STRONG");
4967
4968 oAnchor.removeChild(oStrong);
4969 oAnchor.appendChild(oText);
4970
4971 }
4972
4973 }
4974
4975 },
4976
4977 /**
4978 * @method configChecked
4979 * @description Event handler for when the "checked" configuration property
4980 * of the menu item changes.
4981 * @param {String} p_sType String representing the name of the event that
4982 * was fired.
4983 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
4984 * @param {YAHOO.widget.MenuItem} p_oItem Object representing the menu item
4985 * that fired the event.
4986 */
4987 configChecked: function(p_sType, p_aArgs, p_oItem) {
4988
4989 var bChecked = p_aArgs[0];
4990 var oEl = this.element;
4991 var oConfig = this.cfg;
4992 var oImg;
4993
4994
4995 if(bChecked) {
4996
4997 this._preloadImage(this.CHECKED_IMAGE_PATH);
4998 this._preloadImage(this.SELECTED_CHECKED_IMAGE_PATH);
4999 this._preloadImage(this.DISABLED_CHECKED_IMAGE_PATH);
5000
5001 oImg = document.createElement("img");
5002 oImg.src = (this.imageRoot + this.CHECKED_IMAGE_PATH);
5003 oImg.alt = this.CHECKED_IMAGE_ALT_TEXT;
5004
5005 var oSubmenu = this.cfg.getProperty("submenu");
5006
5007 if(oSubmenu) {
5008
5009 oEl.insertBefore(oImg, oSubmenu.element);
5010
5011 }
5012 else {
5013
5014 oEl.appendChild(oImg);
5015
5016 }
5017
5018 Dom.addClass([oEl, oImg], "checked");
5019
5020 this._checkImage = oImg;
5021
5022 if(oConfig.getProperty("disabled")) {
5023
5024 oConfig.refireEvent("disabled");
5025
5026 }
5027
5028 if(oConfig.getProperty("selected")) {
5029
5030 oConfig.refireEvent("selected");
5031
5032 }
5033
5034 }
5035 else {
5036
5037 oImg = this._checkImage;
5038
5039 Dom.removeClass([oEl, oImg], "checked");
5040
5041 if(oImg) {
5042
5043 oEl.removeChild(oImg);
5044
5045 }
5046
5047 this._checkImage = null;
5048
5049 }
5050
5051 },
5052
5053 /**
5054 * @method configDisabled
5055 * @description Event handler for when the "disabled" configuration property
5056 * of the menu item changes.
5057 * @param {String} p_sType String representing the name of the event that
5058 * was fired.
5059 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
5060 * @param {YAHOO.widget.MenuItem} p_oItem Object representing the menu item
5061 * that fired the event.
5062 */
5063 configDisabled: function(p_sType, p_aArgs, p_oItem) {
5064
5065 var bDisabled = p_aArgs[0];
5066 var oAnchor = this._oAnchor;
5067 var aNodes = [this.element, oAnchor];
5068 var oEM = this._oHelpTextEM;
5069 var oConfig = this.cfg;
5070 var oImg;
5071 var sImgSrc;
5072 var sImgAlt;
5073
5074 if(oEM) {
5075
5076 aNodes[2] = oEM;
5077
5078 }
5079
5080 if(this.cfg.getProperty("checked")) {
5081
5082 sImgAlt = this.CHECKED_IMAGE_ALT_TEXT;
5083 sImgSrc = this.CHECKED_IMAGE_PATH;
5084 oImg = this._checkImage;
5085
5086 if(bDisabled) {
5087
5088 sImgAlt = this.DISABLED_CHECKED_IMAGE_ALT_TEXT;
5089 sImgSrc = this.DISABLED_CHECKED_IMAGE_PATH;
5090
5091 }
5092
5093 oImg.src = document.images[(this.imageRoot + sImgSrc)].src;
5094 oImg.alt = sImgAlt;
5095
5096 }
5097
5098 oImg = this.submenuIndicator;
5099
5100 if(bDisabled) {
5101
5102 if(oConfig.getProperty("selected")) {
5103
5104 oConfig.setProperty("selected", false);
5105
5106 }
5107
5108 oAnchor.removeAttribute("href");
5109
5110 Dom.addClass(aNodes, "disabled");
5111
5112 sImgSrc = this.DISABLED_SUBMENU_INDICATOR_IMAGE_PATH;
5113 sImgAlt = this.DISABLED_SUBMENU_INDICATOR_ALT_TEXT;
5114
5115 }
5116 else {
5117
5118 oAnchor.setAttribute("href", oConfig.getProperty("url"));
5119
5120 Dom.removeClass(aNodes, "disabled");
5121
5122 sImgSrc = this.SUBMENU_INDICATOR_IMAGE_PATH;
5123 sImgAlt = this.COLLAPSED_SUBMENU_INDICATOR_ALT_TEXT;
5124
5125 }
5126
5127 if(oImg) {
5128
5129 oImg.src = this.imageRoot + sImgSrc;
5130 oImg.alt = sImgAlt;
5131
5132 }
5133
5134 },
5135
5136 /**
5137 * @method configSelected
5138 * @description Event handler for when the "selected" configuration property
5139 * of the menu item changes.
5140 * @param {String} p_sType String representing the name of the event that
5141 * was fired.
5142 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
5143 * @param {YAHOO.widget.MenuItem} p_oItem Object representing the menu item
5144 * that fired the event.
5145 */
5146 configSelected: function(p_sType, p_aArgs, p_oItem) {
5147
5148 if(!this.cfg.getProperty("disabled")) {
5149
5150 var bSelected = p_aArgs[0];
5151 var oEM = this._oHelpTextEM;
5152 var aNodes = [this.element, this._oAnchor];
5153 var oImg = this.submenuIndicator;
5154 var sImgSrc;
5155
5156 if(oEM) {
5157
5158 aNodes[aNodes.length] = oEM;
5159
5160 }
5161
5162 if(oImg) {
5163
5164 aNodes[aNodes.length] = oImg;
5165
5166 }
5167
5168
5169 if(this.cfg.getProperty("checked")) {
5170
5171 sImgSrc = this.imageRoot + (bSelected ?
5172 this.SELECTED_CHECKED_IMAGE_PATH : this.CHECKED_IMAGE_PATH);
5173
5174 this._checkImage.src = document.images[sImgSrc].src;
5175
5176 }
5177
5178 if(bSelected) {
5179
5180 Dom.addClass(aNodes, "selected");
5181 sImgSrc = this.SELECTED_SUBMENU_INDICATOR_IMAGE_PATH;
5182
5183 }
5184 else {
5185
5186 Dom.removeClass(aNodes, "selected");
5187 sImgSrc = this.SUBMENU_INDICATOR_IMAGE_PATH;
5188
5189 }
5190
5191 if(oImg) {
5192
5193 oImg.src = document.images[(this.imageRoot + sImgSrc)].src;
5194
5195 }
5196
5197 }
5198
5199 },
5200
5201 /**
5202 * @method configSubmenu
5203 * @description Event handler for when the "submenu" configuration property
5204 * of the menu item changes.
5205 * @param {String} p_sType String representing the name of the event that
5206 * was fired.
5207 * @param {Array} p_aArgs Array of arguments sent when the event was fired.
5208 * @param {YAHOO.widget.MenuItem} p_oItem Object representing the menu item
5209 * that fired the event.
5210 */
5211 configSubmenu: function(p_sType, p_aArgs, p_oItem) {
5212
5213 var oEl = this.element;
5214 var oSubmenu = p_aArgs[0];
5215 var oImg = this.submenuIndicator;
5216 var oConfig = this.cfg;
5217 var aNodes = [this.element, this._oAnchor];
5218 var oMenu;
5219 var bLazyLoad = this.parent && this.parent.lazyLoad;
5220
5221 if(oSubmenu) {
5222
5223 if(oSubmenu instanceof Menu) {
5224
5225 oMenu = oSubmenu;
5226 oMenu.parent = this;
5227 oMenu.lazyLoad = bLazyLoad;
5228
5229 }
5230 else if(
5231 typeof oSubmenu == "object" &&
5232 oSubmenu.id &&
5233 !oSubmenu.nodeType
5234 ) {
5235
5236 var sSubmenuId = oSubmenu.id;
5237 var oSubmenuConfig = oSubmenu;
5238
5239 delete oSubmenu["id"];
5240
5241 oSubmenuConfig.lazyload = bLazyLoad;
5242 oSubmenuConfig.parent = this;
5243
5244 oMenu = new this.SUBMENU_TYPE(sSubmenuId, oSubmenuConfig);
5245
5246 // Set the value of the property to the Menu instance
5247
5248 this.cfg.setProperty("submenu", oMenu, true);
5249
5250 }
5251 else {
5252
5253 oMenu = new this.SUBMENU_TYPE(
5254 oSubmenu,
5255 { lazyload: bLazyLoad, parent: this }
5256 );
5257
5258 // Set the value of the property to the Menu instance
5259
5260 this.cfg.setProperty("submenu", oMenu, true);
5261
5262 }
5263
5264 if(oMenu) {
5265
5266 this._oSubmenu = oMenu;
5267
5268 if(!oImg) {
5269
5270 this._preloadImage(this.SUBMENU_INDICATOR_IMAGE_PATH);
5271 this._preloadImage(
5272 this.SELECTED_SUBMENU_INDICATOR_IMAGE_PATH
5273 );
5274
5275 this._preloadImage(
5276 this.DISABLED_SUBMENU_INDICATOR_IMAGE_PATH
5277 );
5278
5279 oImg = document.createElement("img");
5280
5281 oImg.src =
5282 (this.imageRoot + this.SUBMENU_INDICATOR_IMAGE_PATH);
5283
5284 oImg.alt = this.COLLAPSED_SUBMENU_INDICATOR_ALT_TEXT;
5285
5286 oEl.appendChild(oImg);
5287
5288 this.submenuIndicator = oImg;
5289
5290 Dom.addClass(aNodes, "hassubmenu");
5291
5292 if(oConfig.getProperty("disabled")) {
5293
5294 oConfig.refireEvent("disabled");
5295
5296 }
5297
5298 if(oConfig.getProperty("selected")) {
5299
5300 oConfig.refireEvent("selected");
5301
5302 }
5303
5304 }
5305
5306 }
5307
5308 }
5309 else {
5310
5311 Dom.removeClass(aNodes, "hassubmenu");
5312
5313 if(oImg) {
5314
5315 oEl.removeChild(oImg);
5316
5317 }
5318
5319 if(this._oSubmenu) {
5320
5321 this._oSubmenu.destroy();
5322
5323 }
5324
5325 }
5326
5327 },
5328
5329 // Public methods
5330
5331 /**
5332 * @method initDefaultConfig
5333 * @description Initializes an item's configurable properties.
5334 */
5335 initDefaultConfig : function() {
5336
5337 var oConfig = this.cfg;
5338 var CheckBoolean = oConfig.checkBoolean;
5339
5340 // Define the config properties
5341
5342 /**
5343 * @config text
5344 * @description String specifying the text label for the menu item.
5345 * When building a menu from existing HTML the value of this property
5346 * will be interpreted from the menu's markup.
5347 * @default ""
5348 * @type String
5349 */
5350 oConfig.addProperty(
5351 "text",
5352 {
5353 value: "",
5354 handler: this.configText,
5355 validator: this._checkString,
5356 suppressEvent: true
5357 }
5358 );
5359
5360
5361 /**
5362 * @config helptext
5363 * @description String specifying additional instructional text to
5364 * accompany the text for the nenu item.
5365 * @default null
5366 * @type String|<a href="http://www.w3.org/TR/
5367 * 2000/WD-DOM-Level-1-20000929/level-one-html.html#ID-58190037">
5368 * HTMLElement</a>
5369 */
5370 oConfig.addProperty("helptext", { handler: this.configHelpText });
5371
5372 /**
5373 * @config url
5374 * @description String specifying the URL for the menu item's anchor's
5375 * "href" attribute. When building a menu from existing HTML the value
5376 * of this property will be interpreted from the menu's markup.
5377 * @default "#"
5378 * @type String
5379 */
5380 oConfig.addProperty(
5381 "url",
5382 { value: "#", handler: this.configURL, suppressEvent: true }
5383 );
5384
5385 /**
5386 * @config target
5387 * @description String specifying the value for the "target" attribute
5388 * of the menu item's anchor element. <strong>Specifying a target will
5389 * require the user to click directly on the menu item's anchor node in
5390 * order to cause the browser to navigate to the specified URL.</strong>
5391 * When building a menu from existing HTML the value of this property
5392 * will be interpreted from the menu's markup.
5393 * @default null
5394 * @type String
5395 */
5396 oConfig.addProperty(
5397 "target",
5398 { handler: this.configTarget, suppressEvent: true }
5399 );
5400
5401 /**
5402 * @config emphasis
5403 * @description Boolean indicating if the text of the menu item will be
5404 * rendered with emphasis. When building a menu from existing HTML the
5405 * value of this property will be interpreted from the menu's markup.
5406 * @default false
5407 * @type Boolean
5408 */
5409 oConfig.addProperty(
5410 "emphasis",
5411 {
5412 value: false,
5413 handler: this.configEmphasis,
5414 validator: CheckBoolean,
5415 suppressEvent: true
5416 }
5417 );
5418
5419 /**
5420 * @config strongemphasis
5421 * @description Boolean indicating if the text of the menu item will be
5422 * rendered with strong emphasis. When building a menu from existing
5423 * HTML the value of this property will be interpreted from the
5424 * menu's markup.
5425 * @default false
5426 * @type Boolean
5427 */
5428 oConfig.addProperty(
5429 "strongemphasis",
5430 {
5431 value: false,
5432 handler: this.configStrongEmphasis,
5433 validator: CheckBoolean,
5434 suppressEvent: true
5435 }
5436 );
5437
5438 /**
5439 * @config checked
5440 * @description Boolean indicating if the menu item should be rendered
5441 * with a checkmark.
5442 * @default false
5443 * @type Boolean
5444 */
5445 oConfig.addProperty(
5446 "checked",
5447 {
5448 value: false,
5449 handler: this.configChecked,
5450 validator: this.cfg.checkBoolean,
5451 suppressEvent: true,
5452 supercedes:["disabled"]
5453 }
5454 );
5455
5456 /**
5457 * @config disabled
5458 * @description Boolean indicating if the menu item should be disabled.
5459 * (Disabled menu items are dimmed and will not respond to user input
5460 * or fire events.)
5461 * @default false
5462 * @type Boolean
5463 */
5464 oConfig.addProperty(
5465 "disabled",
5466 {
5467 value: false,
5468 handler: this.configDisabled,
5469 validator: CheckBoolean,
5470 suppressEvent: true
5471 }
5472 );
5473
5474 /**
5475 * @config selected
5476 * @description Boolean indicating if the menu item should
5477 * be highlighted.
5478 * @default false
5479 * @type Boolean
5480 */
5481 oConfig.addProperty(
5482 "selected",
5483 {
5484 value: false,
5485 handler: this.configSelected,
5486 validator: CheckBoolean,
5487 suppressEvent: true
5488 }
5489 );
5490
5491 /**
5492 * @config submenu
5493 * @description Object specifying the submenu to be appended to the
5494 * menu item. The value can be one of the following: <ul><li>Object
5495 * specifying a Menu instance.</li><li>Object literal specifying the
5496 * menu to be created. Format: <code>{ id: [menu id], itemdata:
5497 * [<a href="YAHOO.widget.Menu.html#itemData">array of values for
5498 * items</a>] }</code>.</li><li>String specifying the id attribute
5499 * of the <code>&#60;div&#62;</code> element of the menu.</li><li>
5500 * Object specifying the <code>&#60;div&#62;</code> element of the
5501 * menu.</li></ul>
5502 * @default null
5503 * @type Menu|String|Object|<a href="http://www.w3.org/TR/2000/
5504 * WD-DOM-Level-1-20000929/level-one-html.html#ID-58190037">
5505 * HTMLElement</a>
5506 */
5507 oConfig.addProperty("submenu", { handler: this.configSubmenu });
5508
5509 },
5510
5511 /**
5512 * @method getNextEnabledSibling
5513 * @description Finds the menu item's next enabled sibling.
5514 * @return YAHOO.widget.MenuItem
5515 */
5516 getNextEnabledSibling: function() {
5517
5518 if(this.parent instanceof Menu) {
5519
5520 var nGroupIndex = this.groupIndex;
5521
5522 /**
5523 * Finds the next item in an array.
5524 * @private
5525 * @param {p_aArray} Array to search.
5526 * @param {p_nStartIndex} Number indicating the index to
5527 * start searching the array.
5528 * @return {Object}
5529 */
5530 var getNextArrayItem = function(p_aArray, p_nStartIndex) {
5531
5532 return p_aArray[p_nStartIndex] ||
5533 getNextArrayItem(p_aArray, (p_nStartIndex+1));
5534
5535 };
5536
5537
5538 var aItemGroups = this.parent.getItemGroups();
5539 var oNextItem;
5540
5541
5542 if(this.index < (aItemGroups[nGroupIndex].length - 1)) {
5543
5544 oNextItem = getNextArrayItem(
5545 aItemGroups[nGroupIndex],
5546 (this.index+1)
5547 );
5548
5549 }
5550 else {
5551
5552 var nNextGroupIndex;
5553
5554 if(nGroupIndex < (aItemGroups.length - 1)) {
5555
5556 nNextGroupIndex = nGroupIndex + 1;
5557
5558 }
5559 else {
5560
5561 nNextGroupIndex = 0;
5562
5563 }
5564
5565 var aNextGroup = getNextArrayItem(aItemGroups, nNextGroupIndex);
5566
5567 // Retrieve the first menu item in the next group
5568
5569 oNextItem = getNextArrayItem(aNextGroup, 0);
5570
5571 }
5572
5573 return (
5574 oNextItem.cfg.getProperty("disabled") ||
5575 oNextItem.element.style.display == "none"
5576 ) ?
5577 oNextItem.getNextEnabledSibling() : oNextItem;
5578
5579 }
5580
5581 },
5582
5583 /**
5584 * @method getPreviousEnabledSibling
5585 * @description Finds the menu item's previous enabled sibling.
5586 * @return {YAHOO.widget.MenuItem}
5587 */
5588 getPreviousEnabledSibling: function() {
5589
5590 if(this.parent instanceof Menu) {
5591
5592 var nGroupIndex = this.groupIndex;
5593
5594 /**
5595 * Returns the previous item in an array
5596 * @private
5597 * @param {p_aArray} Array to search.
5598 * @param {p_nStartIndex} Number indicating the index to
5599 * start searching the array.
5600 * @return {Object}
5601 */
5602 var getPreviousArrayItem = function(p_aArray, p_nStartIndex) {
5603
5604 return p_aArray[p_nStartIndex] ||
5605 getPreviousArrayItem(p_aArray, (p_nStartIndex-1));
5606
5607 };
5608
5609 /**
5610 * Get the index of the first item in an array
5611 * @private
5612 * @param {p_aArray} Array to search.
5613 * @param {p_nStartIndex} Number indicating the index to
5614 * start searching the array.
5615 * @return {Object}
5616 */
5617 var getFirstItemIndex = function(p_aArray, p_nStartIndex) {
5618
5619 return p_aArray[p_nStartIndex] ?
5620 p_nStartIndex :
5621 getFirstItemIndex(p_aArray, (p_nStartIndex+1));
5622
5623 };
5624
5625 var aItemGroups = this.parent.getItemGroups();
5626 var oPreviousItem;
5627
5628 if(
5629 this.index > getFirstItemIndex(aItemGroups[nGroupIndex], 0)
5630 ) {
5631
5632 oPreviousItem =
5633 getPreviousArrayItem(
5634 aItemGroups[nGroupIndex],
5635 (this.index-1)
5636 );
5637
5638 }
5639 else {
5640
5641 var nPreviousGroupIndex;
5642
5643 if(nGroupIndex > getFirstItemIndex(aItemGroups, 0)) {
5644
5645 nPreviousGroupIndex = nGroupIndex - 1;
5646
5647 }
5648 else {
5649
5650 nPreviousGroupIndex = aItemGroups.length - 1;
5651
5652 }
5653
5654 var aPreviousGroup =
5655 getPreviousArrayItem(aItemGroups, nPreviousGroupIndex);
5656
5657 oPreviousItem =
5658 getPreviousArrayItem(
5659 aPreviousGroup,
5660 (aPreviousGroup.length - 1)
5661 );
5662
5663 }
5664
5665 return (
5666 oPreviousItem.cfg.getProperty("disabled") ||
5667 oPreviousItem.element.style.display == "none"
5668 ) ?
5669 oPreviousItem.getPreviousEnabledSibling() : oPreviousItem;
5670
5671 }
5672
5673 },
5674
5675 /**
5676 * @method focus
5677 * @description Causes the menu item to receive the focus and fires the
5678 * focus event.
5679 */
5680 focus: function() {
5681
5682 var oParent = this.parent;
5683 var oAnchor = this._oAnchor;
5684 var oActiveItem = oParent.activeItem;
5685
5686 if(
5687 !this.cfg.getProperty("disabled") &&
5688 oParent &&
5689 oParent.cfg.getProperty("visible") &&
5690 this.element.style.display != "none"
5691 ) {
5692
5693 if(oActiveItem) {
5694
5695 oActiveItem.blur();
5696
5697 }
5698
5699 try {
5700
5701 oAnchor.focus();
5702
5703 }
5704 catch(e) {
5705
5706 }
5707
5708 this.focusEvent.fire();
5709
5710 }
5711
5712 },
5713
5714 /**
5715 * @method blur
5716 * @description Causes the menu item to lose focus and fires the
5717 * onblur event.
5718 */
5719 blur: function() {
5720
5721 var oParent = this.parent;
5722
5723 if(
5724 !this.cfg.getProperty("disabled") &&
5725 oParent &&
5726 Dom.getStyle(oParent.element, "visibility") == "visible"
5727 ) {
5728
5729 this._oAnchor.blur();
5730
5731 this.blurEvent.fire();
5732
5733 }
5734
5735 },
5736
5737 /**
5738 * @method destroy
5739 * @description Removes the menu item's <code>&#60;li&#62;</code> element
5740 * from its parent <code>&#60;ul&#62;</code> element.
5741 */
5742 destroy: function() {
5743
5744 var oEl = this.element;
5745
5746 if(oEl) {
5747
5748 // Remove CustomEvent listeners
5749
5750 this.mouseOverEvent.unsubscribeAll();
5751 this.mouseOutEvent.unsubscribeAll();
5752 this.mouseDownEvent.unsubscribeAll();
5753 this.mouseUpEvent.unsubscribeAll();
5754 this.clickEvent.unsubscribeAll();
5755 this.keyPressEvent.unsubscribeAll();
5756 this.keyDownEvent.unsubscribeAll();
5757 this.keyUpEvent.unsubscribeAll();
5758 this.focusEvent.unsubscribeAll();
5759 this.blurEvent.unsubscribeAll();
5760 this.cfg.configChangedEvent.unsubscribeAll();
5761
5762 // Remove the element from the parent node
5763
5764 var oParentNode = oEl.parentNode;
5765
5766 if(oParentNode) {
5767
5768 oParentNode.removeChild(oEl);
5769
5770 this.destroyEvent.fire();
5771
5772 }
5773
5774 this.destroyEvent.unsubscribeAll();
5775
5776 }
5777
5778 },
5779
5780 /**
5781 * @method toString
5782 * @description Returns a string representing the menu item.
5783 * @return {String}
5784 */
5785 toString: function() {
5786
5787 return ("MenuItem: " + this.cfg.getProperty("text"));
5788
5789 }
5790
5791};
5792
5793})();
5794
5795/**
5796* Creates an item for a menu module.
5797*
5798* @param {String} p_oObject String specifying the text of the menu module item.
5799* @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-one-
5800* html.html#ID-74680021">HTMLLIElement</a>} p_oObject Object specifying the
5801* <code>&#60;li&#62;</code> element of the menu module item.
5802* @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-one-
5803* html.html#ID-38450247">HTMLOptGroupElement</a>} p_oObject Object specifying
5804* the <code>&#60;optgroup&#62;</code> element of the menu module item.
5805* @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-one-
5806* html.html#ID-70901257">HTMLOptionElement</a>} p_oObject Object specifying the
5807* <code>&#60;option&#62;</code> element of the menu module item.
5808* @param {Object} p_oConfig Optional. Object literal specifying the
5809* configuration for the menu module item. See configuration class documentation
5810* for more details.
5811* @class MenuModuleItem
5812* @constructor
5813* @deprecated As of version 0.12, all MenuModuleItem functionality has been
5814* implemented directly in YAHOO.widget.MenuItem, making YAHOO.widget.MenuItem
5815* the base class for all menu items.
5816*/
5817YAHOO.widget.MenuModuleItem = YAHOO.widget.MenuItem;
5818
5819/**
5820* Creates a list of options or commands which are made visible in response to
5821* an HTML element's "contextmenu" event ("mousedown" for Opera).
5822*
5823* @param {String} p_oElement String specifying the id attribute of the
5824* <code>&#60;div&#62;</code> element of the context menu.
5825* @param {String} p_oElement String specifying the id attribute of the
5826* <code>&#60;select&#62;</code> element to be used as the data source for the
5827* context menu.
5828* @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-one-
5829* html.html#ID-22445964">HTMLDivElement</a>} p_oElement Object specifying the
5830* <code>&#60;div&#62;</code> element of the context menu.
5831* @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-one-
5832* html.html#ID-94282980">HTMLSelectElement</a>} p_oElement Object specifying
5833* the <code>&#60;select&#62;</code> element to be used as the data source for
5834* the context menu.
5835* @param {Object} p_oConfig Optional. Object literal specifying the
5836* configuration for the context menu. See configuration class documentation
5837* for more details.
5838* @class ContextMenu
5839* @constructor
5840* @extends YAHOO.widget.Menu
5841* @namespace YAHOO.widget
5842*/
5843YAHOO.widget.ContextMenu = function(p_oElement, p_oConfig) {
5844
5845 YAHOO.widget.ContextMenu.superclass.constructor.call(
5846 this,
5847 p_oElement,
5848 p_oConfig
5849 );
5850
5851};
5852
5853YAHOO.extend(YAHOO.widget.ContextMenu, YAHOO.widget.Menu, {
5854
5855// Private properties
5856
5857/**
5858* @property _oTrigger
5859* @description Object reference to the current value of the "trigger"
5860* configuration property.
5861* @default null
5862* @private
5863* @type String|<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/leve
5864* l-one-html.html#ID-58190037">HTMLElement</a>|Array
5865*/
5866_oTrigger: null,
5867
5868// Public properties
5869
5870/**
5871* @property contextEventTarget
5872* @description Object reference for the HTML element that was the target of the
5873* "contextmenu" DOM event ("mousedown" for Opera) that triggered the display of
5874* the context menu.
5875* @default null
5876* @type <a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-one-
5877* html.html#ID-58190037">HTMLElement</a>
5878*/
5879contextEventTarget: null,
5880
5881/**
5882* @method init
5883* @description The ContextMenu class's initialization method. This method is
5884* automatically called by the constructor, and sets up all DOM references for
5885* pre-existing markup, and creates required markup if it is not already present.
5886* @param {String} p_oElement String specifying the id attribute of the
5887* <code>&#60;div&#62;</code> element of the context menu.
5888* @param {String} p_oElement String specifying the id attribute of the
5889* <code>&#60;select&#62;</code> element to be used as the data source for
5890* the context menu.
5891* @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-one-
5892* html.html#ID-22445964">HTMLDivElement</a>} p_oElement Object specifying the
5893* <code>&#60;div&#62;</code> element of the context menu.
5894* @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-one-
5895* html.html#ID-94282980">HTMLSelectElement</a>} p_oElement Object specifying
5896* the <code>&#60;select&#62;</code> element to be used as the data source for
5897* the context menu.
5898* @param {Object} p_oConfig Optional. Object literal specifying the
5899* configuration for the context menu. See configuration class documentation
5900* for more details.
5901*/
5902init: function(p_oElement, p_oConfig) {
5903
5904 if(!this.ITEM_TYPE) {
5905
5906 this.ITEM_TYPE = YAHOO.widget.ContextMenuItem;
5907
5908 }
5909
5910 // Call the init of the superclass (YAHOO.widget.Menu)
5911
5912 YAHOO.widget.ContextMenu.superclass.init.call(this, p_oElement);
5913
5914 this.beforeInitEvent.fire(YAHOO.widget.ContextMenu);
5915
5916 if(p_oConfig) {
5917
5918 this.cfg.applyConfig(p_oConfig, true);
5919
5920 }
5921
5922
5923 this.initEvent.fire(YAHOO.widget.ContextMenu);
5924
5925},
5926
5927// Private methods
5928
5929/**
5930* @method _removeEventHandlers
5931* @description Removes all of the DOM event handlers from the HTML element(s)
5932* whose "context menu" event ("click" for Opera) trigger the display of
5933* the context menu.
5934* @private
5935*/
5936_removeEventHandlers: function() {
5937
5938 var Event = YAHOO.util.Event;
5939 var oTrigger = this._oTrigger;
5940 var bOpera = (this.browser == "opera");
5941
5942 // Remove the event handlers from the trigger(s)
5943
5944 Event.removeListener(
5945 oTrigger,
5946 (bOpera ? "mousedown" : "contextmenu"),
5947 this._onTriggerContextMenu
5948 );
5949
5950 if(bOpera) {
5951
5952 Event.removeListener(oTrigger, "click", this._onTriggerClick);
5953
5954 }
5955
5956},
5957
5958// Private event handlers
5959
5960/**
5961* @method _onTriggerClick
5962* @description "click" event handler for the HTML element(s) identified as the
5963* "trigger" for the context menu. Used to cancel default behaviors in Opera.
5964* @private
5965* @param {Event} p_oEvent Object representing the DOM event object passed back
5966* by the event utility (YAHOO.util.Event).
5967* @param {YAHOO.widget.ContextMenu} p_oMenu Object representing the context
5968* menu that is handling the event.
5969*/
5970_onTriggerClick: function(p_oEvent, p_oMenu) {
5971
5972 if(p_oEvent.ctrlKey) {
5973
5974 YAHOO.util.Event.stopEvent(p_oEvent);
5975
5976 }
5977
5978},
5979
5980/**
5981* @method _onTriggerContextMenu
5982* @description "contextmenu" event handler ("mousedown" for Opera) for the HTML
5983* element(s) that trigger the display of the context menu.
5984* @private
5985* @param {Event} p_oEvent Object representing the DOM event object passed back
5986* by the event utility (YAHOO.util.Event).
5987* @param {YAHOO.widget.ContextMenu} p_oMenu Object representing the context
5988* menu that is handling the event.
5989*/
5990_onTriggerContextMenu: function(p_oEvent, p_oMenu) {
5991
5992 // Hide any other ContextMenu instances that might be visible
5993
5994 YAHOO.widget.MenuManager.hideVisible();
5995
5996 var Event = YAHOO.util.Event;
5997 var oConfig = this.cfg;
5998
5999 if(p_oEvent.type == "mousedown" && !p_oEvent.ctrlKey) {
6000
6001 return;
6002
6003 }
6004
6005 this.contextEventTarget = Event.getTarget(p_oEvent);
6006
6007 // Position and display the context menu
6008
6009 var nX = Event.getPageX(p_oEvent);
6010 var nY = Event.getPageY(p_oEvent);
6011
6012 oConfig.applyConfig( { xy:[nX, nY], visible:true } );
6013 oConfig.fireQueue();
6014
6015 /*
6016 Prevent the browser's default context menu from appearing and
6017 stop the propagation of the "contextmenu" event so that
6018 other ContextMenu instances are not displayed.
6019 */
6020
6021 Event.stopEvent(p_oEvent);
6022
6023},
6024
6025// Public methods
6026
6027/**
6028* @method toString
6029* @description Returns a string representing the context menu.
6030* @return {String}
6031*/
6032toString: function() {
6033
6034 return ("ContextMenu " + this.id);
6035
6036},
6037
6038/**
6039* @method initDefaultConfig
6040* @description Initializes the class's configurable properties which can be
6041* changed using the context menu's Config object ("cfg").
6042*/
6043initDefaultConfig: function() {
6044
6045 YAHOO.widget.ContextMenu.superclass.initDefaultConfig.call(this);
6046
6047 /**
6048 * @config trigger
6049 * @description The HTML element(s) whose "contextmenu" event ("mousedown"
6050 * for Opera) trigger the display of the context menu. Can be a string
6051 * representing the id attribute of the HTML element, an object reference
6052 * for the HTML element, or an array of strings or HTML element references.
6053 * @default null
6054 * @type String|<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
6055 * level-one-html.html#ID-58190037">HTMLElement</a>|Array
6056 */
6057 this.cfg.addProperty("trigger", { handler: this.configTrigger });
6058
6059},
6060
6061/**
6062* @method destroy
6063* @description Removes the context menu's <code>&#60;div&#62;</code> element
6064* (and accompanying child nodes) from the document.
6065*/
6066destroy: function() {
6067
6068 // Remove the DOM event handlers from the current trigger(s)
6069
6070 this._removeEventHandlers();
6071
6072
6073 // Continue with the superclass implementation of this method
6074
6075 YAHOO.widget.ContextMenu.superclass.destroy.call(this);
6076
6077},
6078
6079// Public event handlers for configuration properties
6080
6081/**
6082* @method configTrigger
6083* @description Event handler for when the value of the "trigger" configuration
6084* property changes.
6085* @param {String} p_sType String representing the name of the event that
6086* was fired.
6087* @param {Array} p_aArgs Array of arguments sent when the event was fired.
6088* @param {YAHOO.widget.ContextMenu} p_oMenu Object representing the context
6089* menu that fired the event.
6090*/
6091configTrigger: function(p_sType, p_aArgs, p_oMenu) {
6092
6093 var Event = YAHOO.util.Event;
6094 var oTrigger = p_aArgs[0];
6095
6096 if(oTrigger) {
6097
6098 /*
6099 If there is a current "trigger" - remove the event handlers
6100 from that element(s) before assigning new ones
6101 */
6102
6103 if(this._oTrigger) {
6104
6105 this._removeEventHandlers();
6106
6107 }
6108
6109 this._oTrigger = oTrigger;
6110
6111 /*
6112 Listen for the "mousedown" event in Opera b/c it does not
6113 support the "contextmenu" event
6114 */
6115
6116 var bOpera = (this.browser == "opera");
6117
6118 Event.addListener(
6119 oTrigger,
6120 (bOpera ? "mousedown" : "contextmenu"),
6121 this._onTriggerContextMenu,
6122 this,
6123 true
6124 );
6125
6126 /*
6127 Assign a "click" event handler to the trigger element(s) for
6128 Opera to prevent default browser behaviors.
6129 */
6130
6131 if(bOpera) {
6132
6133 Event.addListener(
6134 oTrigger,
6135 "click",
6136 this._onTriggerClick,
6137 this,
6138 true
6139 );
6140
6141 }
6142
6143 }
6144 else {
6145
6146 this._removeEventHandlers();
6147
6148 }
6149
6150}
6151
6152}); // END YAHOO.extend
6153
6154/**
6155* Creates an item for a context menu.
6156*
6157* @param {String} p_oObject String specifying the text of the context menu item.
6158* @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
6159* one-html.html#ID-74680021">HTMLLIElement</a>} p_oObject Object specifying the
6160* <code>&#60;li&#62;</code> element of the context menu item.
6161* @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
6162* one-html.html#ID-38450247">HTMLOptGroupElement</a>} p_oObject Object
6163* specifying the <code>&#60;optgroup&#62;</code> element of the context
6164* menu item.
6165* @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
6166* one-html.html#ID-70901257">HTMLOptionElement</a>} p_oObject Object specifying
6167* the <code>&#60;option&#62;</code> element of the context menu item.
6168* @param {Object} p_oConfig Optional. Object literal specifying the
6169* configuration for the context menu item. See configuration class
6170* documentation for more details.
6171* @class ContextMenuItem
6172* @constructor
6173* @extends YAHOO.widget.MenuItem
6174*/
6175YAHOO.widget.ContextMenuItem = function(p_oObject, p_oConfig) {
6176
6177 YAHOO.widget.ContextMenuItem.superclass.constructor.call(
6178 this,
6179 p_oObject,
6180 p_oConfig
6181 );
6182
6183};
6184
6185YAHOO.extend(YAHOO.widget.ContextMenuItem, YAHOO.widget.MenuItem, {
6186
6187/**
6188* @method init
6189* @description The ContextMenuItem class's initialization method. This method
6190* is automatically called by the constructor, and sets up all DOM references
6191* for pre-existing markup, and creates required markup if it is not
6192* already present.
6193* @param {String} p_oObject String specifying the text of the context menu item.
6194* @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
6195* one-html.html#ID-74680021">HTMLLIElement</a>} p_oObject Object specifying the
6196* <code>&#60;li&#62;</code> element of the context menu item.
6197* @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
6198* one-html.html#ID-38450247">HTMLOptGroupElement</a>} p_oObject Object
6199* specifying the <code>&#60;optgroup&#62;</code> element of the context
6200* menu item.
6201* @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
6202* one-html.html#ID-70901257">HTMLOptionElement</a>} p_oObject Object specifying
6203* the <code>&#60;option&#62;</code> element of the context menu item.
6204* @param {Object} p_oConfig Optional. Object literal specifying the
6205* configuration for the context menu item. See configuration class
6206* documentation for more details.
6207*/
6208init: function(p_oObject, p_oConfig) {
6209
6210 if(!this.SUBMENU_TYPE) {
6211
6212 this.SUBMENU_TYPE = YAHOO.widget.ContextMenu;
6213
6214 }
6215
6216 /*
6217 Call the init of the superclass (YAHOO.widget.MenuItem)
6218 Note: We don't pass the user config in here yet
6219 because we only want it executed once, at the lowest
6220 subclass level.
6221 */
6222
6223 YAHOO.widget.ContextMenuItem.superclass.init.call(this, p_oObject);
6224
6225 var oConfig = this.cfg;
6226
6227 if(p_oConfig) {
6228
6229 oConfig.applyConfig(p_oConfig, true);
6230
6231 }
6232
6233 oConfig.fireQueue();
6234
6235},
6236
6237// Public methods
6238
6239/**
6240* @method toString
6241* @description Returns a string representing the context menu item.
6242* @return {String}
6243*/
6244toString: function() {
6245
6246 return ("MenuBarItem: " + this.cfg.getProperty("text"));
6247
6248}
6249
6250}); // END YAHOO.extend
6251
6252/**
6253* Horizontal collection of items, each of which can contain a submenu.
6254*
6255* @param {String} p_oElement String specifying the id attribute of the
6256* <code>&#60;div&#62;</code> element of the menu bar.
6257* @param {String} p_oElement String specifying the id attribute of the
6258* <code>&#60;select&#62;</code> element to be used as the data source for the
6259* menu bar.
6260* @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
6261* one-html.html#ID-22445964">HTMLDivElement</a>} p_oElement Object specifying
6262* the <code>&#60;div&#62;</code> element of the menu bar.
6263* @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
6264* one-html.html#ID-94282980">HTMLSelectElement</a>} p_oElement Object
6265* specifying the <code>&#60;select&#62;</code> element to be used as the data
6266* source for the menu bar.
6267* @param {Object} p_oConfig Optional. Object literal specifying the
6268* configuration for the menu bar. See configuration class documentation for
6269* more details.
6270* @class Menubar
6271* @constructor
6272* @extends YAHOO.widget.Menu
6273* @namespace YAHOO.widget
6274*/
6275YAHOO.widget.MenuBar = function(p_oElement, p_oConfig) {
6276
6277 YAHOO.widget.MenuBar.superclass.constructor.call(
6278 this,
6279 p_oElement,
6280 p_oConfig
6281 );
6282
6283};
6284
6285YAHOO.extend(YAHOO.widget.MenuBar, YAHOO.widget.Menu, {
6286
6287/**
6288* @method init
6289* @description The MenuBar class's initialization method. This method is
6290* automatically called by the constructor, and sets up all DOM references for
6291* pre-existing markup, and creates required markup if it is not already present.
6292* @param {String} p_oElement String specifying the id attribute of the
6293* <code>&#60;div&#62;</code> element of the menu bar.
6294* @param {String} p_oElement String specifying the id attribute of the
6295* <code>&#60;select&#62;</code> element to be used as the data source for the
6296* menu bar.
6297* @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
6298* one-html.html#ID-22445964">HTMLDivElement</a>} p_oElement Object specifying
6299* the <code>&#60;div&#62;</code> element of the menu bar.
6300* @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
6301* one-html.html#ID-94282980">HTMLSelectElement</a>} p_oElement Object
6302* specifying the <code>&#60;select&#62;</code> element to be used as the data
6303* source for the menu bar.
6304* @param {Object} p_oConfig Optional. Object literal specifying the
6305* configuration for the menu bar. See configuration class documentation for
6306* more details.
6307*/
6308init: function(p_oElement, p_oConfig) {
6309
6310 if(!this.ITEM_TYPE) {
6311
6312 this.ITEM_TYPE = YAHOO.widget.MenuBarItem;
6313
6314 }
6315
6316 // Call the init of the superclass (YAHOO.widget.Menu)
6317
6318 YAHOO.widget.MenuBar.superclass.init.call(this, p_oElement);
6319
6320 this.beforeInitEvent.fire(YAHOO.widget.MenuBar);
6321
6322 if(p_oConfig) {
6323
6324 this.cfg.applyConfig(p_oConfig, true);
6325
6326 }
6327
6328 this.initEvent.fire(YAHOO.widget.MenuBar);
6329
6330},
6331
6332// Constants
6333
6334/**
6335* @property CSS_CLASS_NAME
6336* @description String representing the CSS class(es) to be applied to the menu
6337* bar's <code>&#60;div&#62;</code> element.
6338* @default "yuimenubar"
6339* @final
6340* @type String
6341*/
6342CSS_CLASS_NAME: "yuimenubar",
6343
6344// Protected event handlers
6345
6346/**
6347* @method _onKeyDown
6348* @description "keydown" Custom Event handler for the menu bar.
6349* @private
6350* @param {String} p_sType String representing the name of the event that
6351* was fired.
6352* @param {Array} p_aArgs Array of arguments sent when the event was fired.
6353* @param {YAHOO.widget.MenuBar} p_oMenuBar Object representing the menu bar
6354* that fired the event.
6355*/
6356_onKeyDown: function(p_sType, p_aArgs, p_oMenuBar) {
6357
6358 var Event = YAHOO.util.Event;
6359 var oEvent = p_aArgs[0];
6360 var oItem = p_aArgs[1];
6361 var oItemCfg = oItem.cfg;
6362 var oSubmenu;
6363
6364 switch(oEvent.keyCode) {
6365
6366 case 27: // Esc key
6367
6368 if(this.cfg.getProperty("position") == "dynamic") {
6369
6370 this.hide();
6371
6372 if(this.parent) {
6373
6374 this.parent.focus();
6375
6376 }
6377
6378 }
6379 else if(this.activeItem) {
6380
6381 oSubmenu = this.activeItem.cfg.getProperty("submenu");
6382
6383 if(oSubmenu && oSubmenu.cfg.getProperty("visible")) {
6384
6385 oSubmenu.hide();
6386 this.activeItem.focus();
6387
6388 }
6389 else {
6390
6391 this.activeItem.cfg.setProperty("selected", false);
6392 this.activeItem.blur();
6393
6394 }
6395
6396 }
6397
6398
6399 Event.preventDefault(oEvent);
6400
6401 break;
6402
6403 case 37: // Left arrow
6404 case 39: // Right arrow
6405
6406 if(
6407 oItem == this.activeItem &&
6408 !oItemCfg.getProperty("selected")
6409 ) {
6410
6411 oItemCfg.setProperty("selected", true);
6412
6413 }
6414 else {
6415
6416 var oNextItem = (oEvent.keyCode == 37) ?
6417 oItem.getPreviousEnabledSibling() :
6418 oItem.getNextEnabledSibling();
6419
6420 if(oNextItem) {
6421
6422 this.clearActiveItem();
6423
6424 oNextItem.cfg.setProperty("selected", true);
6425
6426 if(this.cfg.getProperty("autosubmenudisplay")) {
6427
6428 oSubmenu = oNextItem.cfg.getProperty("submenu");
6429
6430 if(oSubmenu) {
6431
6432 oSubmenu.show();
6433 oSubmenu.activeItem.blur();
6434 oSubmenu.activeItem = null;
6435
6436 }
6437
6438 }
6439
6440 oNextItem.focus();
6441
6442 }
6443
6444 }
6445
6446 Event.preventDefault(oEvent);
6447
6448 break;
6449
6450 case 40: // Down arrow
6451
6452 if(this.activeItem != oItem) {
6453
6454 this.clearActiveItem();
6455
6456 oItemCfg.setProperty("selected", true);
6457 oItem.focus();
6458
6459 }
6460
6461 oSubmenu = oItemCfg.getProperty("submenu");
6462
6463 if(oSubmenu) {
6464
6465 if(oSubmenu.cfg.getProperty("visible")) {
6466
6467 oSubmenu.setInitialSelection();
6468 oSubmenu.setInitialFocus();
6469
6470 }
6471 else {
6472
6473 oSubmenu.show();
6474
6475 }
6476
6477 }
6478
6479 Event.preventDefault(oEvent);
6480
6481 break;
6482
6483 }
6484
6485},
6486
6487/**
6488* @method _onClick
6489* @description "click" event handler for the menu bar.
6490* @protected
6491* @param {String} p_sType String representing the name of the event that
6492* was fired.
6493* @param {Array} p_aArgs Array of arguments sent when the event was fired.
6494* @param {YAHOO.widget.MenuBar} p_oMenuBar Object representing the menu bar
6495* that fired the event.
6496*/
6497_onClick: function(p_sType, p_aArgs, p_oMenuBar) {
6498
6499 YAHOO.widget.MenuBar.superclass._onClick.call(
6500 this,
6501 p_sType,
6502 p_aArgs,
6503 p_oMenuBar
6504 );
6505
6506 var oItem = p_aArgs[1];
6507
6508 if(oItem) {
6509
6510 var Event = YAHOO.util.Event;
6511 var Dom = YAHOO.util.Dom;
6512
6513 var oEvent = p_aArgs[0];
6514 var oTarget = Event.getTarget(oEvent);
6515
6516 var oActiveItem = this.activeItem;
6517 var oConfig = this.cfg;
6518
6519 // Hide any other submenus that might be visible
6520
6521 if(oActiveItem && oActiveItem != oItem) {
6522
6523 this.clearActiveItem();
6524
6525 }
6526
6527
6528 // Select and focus the current item
6529
6530 oItem.cfg.setProperty("selected", true);
6531 oItem.focus();
6532
6533
6534 // Show the submenu for the item
6535
6536 var oSubmenu = oItem.cfg.getProperty("submenu");
6537
6538 if(oSubmenu && oTarget != oItem.submenuIndicator) {
6539
6540 if(oSubmenu.cfg.getProperty("visible")) {
6541
6542 oSubmenu.hide();
6543
6544 }
6545 else {
6546
6547 oSubmenu.show();
6548
6549 }
6550
6551 }
6552
6553 }
6554
6555},
6556
6557// Public methods
6558
6559/**
6560* @method toString
6561* @description Returns a string representing the menu bar.
6562* @return {String}
6563*/
6564toString: function() {
6565
6566 return ("MenuBar " + this.id);
6567
6568},
6569
6570/**
6571* @description Initializes the class's configurable properties which can be
6572* changed using the menu bar's Config object ("cfg").
6573* @method initDefaultConfig
6574*/
6575initDefaultConfig: function() {
6576
6577 YAHOO.widget.MenuBar.superclass.initDefaultConfig.call(this);
6578
6579 var oConfig = this.cfg;
6580
6581 // Add configuration properties
6582
6583 /*
6584 Set the default value for the "position" configuration property
6585 to "static" by re-adding the property.
6586 */
6587
6588 /**
6589 * @config position
6590 * @description String indicating how a menu bar should be positioned on the
6591 * screen. Possible values are "static" and "dynamic." Static menu bars
6592 * are visible by default and reside in the normal flow of the document
6593 * (CSS position: static). Dynamic menu bars are hidden by default, reside
6594 * out of the normal flow of the document (CSS position: absolute), and can
6595 * overlay other elements on the screen.
6596 * @default static
6597 * @type String
6598 */
6599 oConfig.addProperty(
6600 "position",
6601 {
6602 value: "static",
6603 handler: this.configPosition,
6604 validator: this._checkPosition,
6605 supercedes: ["visible"]
6606 }
6607 );
6608
6609 /*
6610 Set the default value for the "submenualignment" configuration property
6611 to ["tl","bl"] by re-adding the property.
6612 */
6613
6614 /**
6615 * @config submenualignment
6616 * @description Array defining how submenus should be aligned to their
6617 * parent menu bar item. The format is: [itemCorner, submenuCorner].
6618 * @default ["tl","bl"]
6619 * @type Array
6620 */
6621 oConfig.addProperty("submenualignment", { value: ["tl","bl"] } );
6622
6623 /*
6624 Change the default value for the "autosubmenudisplay" configuration
6625 property to "false" by re-adding the property.
6626 */
6627
6628 /**
6629 * @config autosubmenudisplay
6630 * @description Boolean indicating if submenus are automatically made
6631 * visible when the user mouses over the menu bar's items.
6632 * @default false
6633 * @type Boolean
6634 */
6635 oConfig.addProperty(
6636 "autosubmenudisplay",
6637 { value: false, validator: oConfig.checkBoolean }
6638 );
6639
6640}
6641
6642}); // END YAHOO.extend
6643
6644/**
6645* Creates an item for a menu bar.
6646*
6647* @param {String} p_oObject String specifying the text of the menu bar item.
6648* @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
6649* one-html.html#ID-74680021">HTMLLIElement</a>} p_oObject Object specifying the
6650* <code>&#60;li&#62;</code> element of the menu bar item.
6651* @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
6652* one-html.html#ID-38450247">HTMLOptGroupElement</a>} p_oObject Object
6653* specifying the <code>&#60;optgroup&#62;</code> element of the menu bar item.
6654* @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
6655* one-html.html#ID-70901257">HTMLOptionElement</a>} p_oObject Object specifying
6656* the <code>&#60;option&#62;</code> element of the menu bar item.
6657* @param {Object} p_oConfig Optional. Object literal specifying the
6658* configuration for the menu bar item. See configuration class documentation
6659* for more details.
6660* @class MenuBarItem
6661* @constructor
6662* @extends YAHOO.widget.MenuItem
6663*/
6664YAHOO.widget.MenuBarItem = function(p_oObject, p_oConfig) {
6665
6666 YAHOO.widget.MenuBarItem.superclass.constructor.call(
6667 this,
6668 p_oObject,
6669 p_oConfig
6670 );
6671
6672};
6673
6674YAHOO.extend(YAHOO.widget.MenuBarItem, YAHOO.widget.MenuItem, {
6675
6676/**
6677* @method init
6678* @description The MenuBarItem class's initialization method. This method is
6679* automatically called by the constructor, and sets up all DOM references for
6680* pre-existing markup, and creates required markup if it is not already present.
6681* @param {String} p_oObject String specifying the text of the menu bar item.
6682* @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
6683* one-html.html#ID-74680021">HTMLLIElement</a>} p_oObject Object specifying the
6684* <code>&#60;li&#62;</code> element of the menu bar item.
6685* @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
6686* one-html.html#ID-38450247">HTMLOptGroupElement</a>} p_oObject Object
6687* specifying the <code>&#60;optgroup&#62;</code> element of the menu bar item.
6688* @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
6689* one-html.html#ID-70901257">HTMLOptionElement</a>} p_oObject Object specifying
6690* the <code>&#60;option&#62;</code> element of the menu bar item.
6691* @param {Object} p_oConfig Optional. Object literal specifying the
6692* configuration for the menu bar item. See configuration class documentation
6693* for more details.
6694*/
6695init: function(p_oObject, p_oConfig) {
6696
6697 if(!this.SUBMENU_TYPE) {
6698
6699 this.SUBMENU_TYPE = YAHOO.widget.Menu;
6700
6701 }
6702
6703 /*
6704 Call the init of the superclass (YAHOO.widget.MenuItem)
6705 Note: We don't pass the user config in here yet
6706 because we only want it executed once, at the lowest
6707 subclass level.
6708 */
6709
6710 YAHOO.widget.MenuBarItem.superclass.init.call(this, p_oObject);
6711
6712 var oConfig = this.cfg;
6713
6714 if(p_oConfig) {
6715
6716 oConfig.applyConfig(p_oConfig, true);
6717
6718 }
6719
6720 oConfig.fireQueue();
6721
6722},
6723
6724// Constants
6725
6726/**
6727* @property CSS_CLASS_NAME
6728* @description String representing the CSS class(es) to be applied to the
6729* <code>&#60;li&#62;</code> element of the menu bar item.
6730* @default "yuimenubaritem"
6731* @final
6732* @type String
6733*/
6734CSS_CLASS_NAME: "yuimenubaritem",
6735
6736/**
6737* @property SUBMENU_INDICATOR_IMAGE_PATH
6738* @description String representing the path to the image to be used for the
6739* menu bar item's submenu arrow indicator.
6740* @default "nt/ic/ut/alt1/menuarodwn8_nrm_1.gif"
6741* @final
6742* @type String
6743*/
6744SUBMENU_INDICATOR_IMAGE_PATH: "nt/ic/ut/alt1/menuarodwn8_nrm_1.gif",
6745
6746/**
6747* @property SELECTED_SUBMENU_INDICATOR_IMAGE_PATH
6748* @description String representing the path to the image to be used for the
6749* submenu arrow indicator when the menu bar item is selected.
6750* @default "nt/ic/ut/alt1/menuarodwn8_hov_1.gif"
6751* @final
6752* @type String
6753*/
6754SELECTED_SUBMENU_INDICATOR_IMAGE_PATH: "nt/ic/ut/alt1/menuarodwn8_hov_1.gif",
6755
6756/**
6757* @property DISABLED_SUBMENU_INDICATOR_IMAGE_PATH
6758* @description String representing the path to the image to be used for the
6759* submenu arrow indicator when the menu bar item is disabled.
6760* @default "nt/ic/ut/alt1/menuarodwn8_dim_1.gif"
6761* @final
6762* @type String
6763*/
6764DISABLED_SUBMENU_INDICATOR_IMAGE_PATH: "nt/ic/ut/alt1/menuarodwn8_dim_1.gif",
6765
6766// Public methods
6767
6768/**
6769* @method toString
6770* @description Returns a string representing the menu bar item.
6771* @return {String}
6772*/
6773toString: function() {
6774
6775 return ("MenuBarItem: " + this.cfg.getProperty("text"));
6776
6777}
6778
6779}); // END YAHOO.extend
6780
diff --git a/frontend/beta/js/YUI/slider.js b/frontend/beta/js/YUI/slider.js
new file mode 100644
index 0000000..8d3cd62
--- a/dev/null
+++ b/frontend/beta/js/YUI/slider.js
@@ -0,0 +1,1113 @@
1/*
2Copyright (c) 2006, Yahoo! Inc. All rights reserved.
3Code licensed under the BSD License:
4http://developer.yahoo.net/yui/license.txt
5version: 0.12.0
6*/
7
8/**
9 * The Slider component is a UI control that enables the user to adjust
10 * values in a finite range along one or two axes. Typically, the Slider
11 * control is used in a web application as a rich, visual replacement
12 * for an input box that takes a number as input. The Slider control can
13 * also easily accommodate a second dimension, providing x,y output for
14 * a selection point chosen from a rectangular region.
15 *
16 * @module slider
17 * @title Slider Widget
18 * @namespace YAHOO.widget
19 * @requires yahoo,dom,dragdrop,event
20 * @optional animation
21 */
22
23/**
24 * A DragDrop implementation that can be used as a background for a
25 * slider. It takes a reference to the thumb instance
26 * so it can delegate some of the events to it. The goal is to make the
27 * thumb jump to the location on the background when the background is
28 * clicked.
29 *
30 * @class Slider
31 * @extends YAHOO.util.DragDrop
32 * @constructor
33 * @param {String} id The id of the element linked to this instance
34 * @param {String} sGroup The group of related DragDrop items
35 * @param {String} sType The type of slider (horiz, vert, region)
36 */
37YAHOO.widget.Slider = function(sElementId, sGroup, oThumb, sType) {
38 if (sElementId) {
39
40 /**
41 * The type of the slider (horiz, vert, region)
42 * @property type
43 * @type string
44 */
45 this.type = sType;
46
47 this.init(sElementId, sGroup, true);
48
49 //this.removeInvalidHandleType("A");
50
51
52 var self = this;
53
54 /**
55 * Event the fires when the value of the control changes. If
56 * the control is animated the event will fire every point
57 * along the way.
58 * @event change
59 * @param {int} new
60 * @param {int} firstOffset the number of pixels the thumb has moved
61 * from its start position. Normal horizontal and vertical sliders will only
62 * have the firstOffset. Regions will have both, the first is the horizontal
63 * offset, the second the vertical.
64 * @param {int} secondOffset the y offset for region sliders
65 */
66 this.createEvent("change", this);
67
68 /**
69 * Event that fires at the end of a slider thumb move.
70 * @event slideStart
71 */
72 this.createEvent("slideStart", this);
73
74 /**
75 * Event that fires at the end of a slider thumb move
76 * @event slideEnd
77 */
78 this.createEvent("slideEnd", this);
79
80 /**
81 * A YAHOO.widget.SliderThumb instance that we will use to
82 * reposition the thumb when the background is clicked
83 * @property thumb
84 * @type YAHOO.widget.SliderThumb
85 */
86 this.thumb = oThumb;
87
88 // add handler for the handle onchange event
89 oThumb.onChange = function() {
90 self.handleThumbChange();
91 };
92
93 /**
94 * Overrides the isTarget property in YAHOO.util.DragDrop
95 * @property isTarget
96 * @private
97 */
98 this.isTarget = false;
99
100 /**
101 * Flag that determines if the thumb will animate when moved
102 * @property animate
103 * @type boolean
104 */
105 this.animate = YAHOO.widget.Slider.ANIM_AVAIL;
106
107 /**
108 * Set to false to disable a background click thumb move
109 * @property backgroundEnabled
110 * @type boolean
111 */
112 this.backgroundEnabled = true;
113
114 /**
115 * Adjustment factor for tick animation, the more ticks, the
116 * faster the animation (by default)
117 * @property tickPause
118 * @type int
119 */
120 this.tickPause = 40;
121
122 /**
123 * Enables the arrow, home and end keys, defaults to true.
124 * @property enableKeys
125 * @type boolean
126 */
127 this.enableKeys = true;
128
129 /**
130 * Specifies the number of pixels the arrow keys will move the slider.
131 * Default is 25.
132 * @property keyIncrement
133 * @type int
134 */
135 this.keyIncrement = 20;
136
137 /**
138 * moveComplete is set to true when the slider has moved to its final
139 * destination. For animated slider, this value can be checked in
140 * the onChange handler to make it possible to execute logic only
141 * when the move is complete rather than at all points along the way.
142 *
143 * @property moveComplete
144 * @type Boolean
145 */
146 this.moveComplete = true;
147
148 /**
149 * If animation is configured, specifies the length of the animation
150 * in seconds.
151 * @property animationDuration
152 * @type int
153 * @default 0.2
154 */
155 this.animationDuration = 0.2;
156
157 if (oThumb._isHoriz && oThumb.xTicks && oThumb.xTicks.length) {
158 this.tickPause = Math.round(360 / oThumb.xTicks.length);
159 } else if (oThumb.yTicks && oThumb.yTicks.length) {
160 this.tickPause = Math.round(360 / oThumb.yTicks.length);
161 }
162
163
164 // delegate thumb methods
165 oThumb.onMouseDown = function () { return self.focus(); };
166 //oThumb.b4MouseDown = function () { return self.b4MouseDown(); };
167 // oThumb.lock = function() { self.lock(); };
168 // oThumb.unlock = function() { self.unlock(); };
169 oThumb.onMouseUp = function() { self.thumbMouseUp(); };
170 oThumb.onDrag = function() { self.fireEvents(); };
171 oThumb.onAvailable = function() { return self.setStartSliderState(); };
172 }
173};
174
175/**
176 * Factory method for creating a horizontal slider
177 * @method YAHOO.widget.Slider.getHorizSlider
178 * @static
179 * @param {String} sBGElId the id of the slider's background element
180 * @param {String} sHandleElId the id of the thumb element
181 * @param {int} iLeft the number of pixels the element can move left
182 * @param {int} iRight the number of pixels the element can move right
183 * @param {int} iTickSize optional parameter for specifying that the element
184 * should move a certain number pixels at a time.
185 * @return {Slider} a horizontal slider control
186 */
187YAHOO.widget.Slider.getHorizSlider =
188 function (sBGElId, sHandleElId, iLeft, iRight, iTickSize) {
189 return new YAHOO.widget.Slider(sBGElId, sBGElId,
190 new YAHOO.widget.SliderThumb(sHandleElId, sBGElId,
191 iLeft, iRight, 0, 0, iTickSize), "horiz");
192};
193
194/**
195 * Factory method for creating a vertical slider
196 * @method YAHOO.widget.Slider.getVertSlider
197 * @static
198 * @param {String} sBGElId the id of the slider's background element
199 * @param {String} sHandleElId the id of the thumb element
200 * @param {int} iUp the number of pixels the element can move up
201 * @param {int} iDown the number of pixels the element can move down
202 * @param {int} iTickSize optional parameter for specifying that the element
203 * should move a certain number pixels at a time.
204 * @return {Slider} a vertical slider control
205 */
206YAHOO.widget.Slider.getVertSlider =
207 function (sBGElId, sHandleElId, iUp, iDown, iTickSize) {
208 return new YAHOO.widget.Slider(sBGElId, sBGElId,
209 new YAHOO.widget.SliderThumb(sHandleElId, sBGElId, 0, 0,
210 iUp, iDown, iTickSize), "vert");
211};
212
213/**
214 * Factory method for creating a slider region like the one in the color
215 * picker example
216 * @method YAHOO.widget.Slider.getSliderRegion
217 * @static
218 * @param {String} sBGElId the id of the slider's background element
219 * @param {String} sHandleElId the id of the thumb element
220 * @param {int} iLeft the number of pixels the element can move left
221 * @param {int} iRight the number of pixels the element can move right
222 * @param {int} iUp the number of pixels the element can move up
223 * @param {int} iDown the number of pixels the element can move down
224 * @param {int} iTickSize optional parameter for specifying that the element
225 * should move a certain number pixels at a time.
226 * @return {Slider} a slider region control
227 */
228YAHOO.widget.Slider.getSliderRegion =
229 function (sBGElId, sHandleElId, iLeft, iRight, iUp, iDown, iTickSize) {
230 return new YAHOO.widget.Slider(sBGElId, sBGElId,
231 new YAHOO.widget.SliderThumb(sHandleElId, sBGElId, iLeft, iRight,
232 iUp, iDown, iTickSize), "region");
233};
234
235/**
236 * By default, animation is available if the animation library is detected.
237 * @property YAHOO.widget.Slider.ANIM_AVAIL
238 * @static
239 * @type boolean
240 */
241YAHOO.widget.Slider.ANIM_AVAIL = true;
242
243YAHOO.extend(YAHOO.widget.Slider, YAHOO.util.DragDrop, {
244
245 onAvailable: function() {
246 var Event = YAHOO.util.Event;
247 Event.on(this.id, "keydown", this.handleKeyDown, this, true);
248 Event.on(this.id, "keypress", this.handleKeyPress, this, true);
249 },
250
251 handleKeyPress: function(e) {
252 if (this.enableKeys) {
253 var Event = YAHOO.util.Event;
254 var kc = Event.getCharCode(e);
255 switch (kc) {
256 case 0x25: // left
257 case 0x26: // up
258 case 0x27: // right
259 case 0x28: // down
260 case 0x24: // home
261 case 0x23: // end
262 Event.preventDefault(e);
263 break;
264 default:
265 }
266 }
267 },
268
269 handleKeyDown: function(e) {
270 if (this.enableKeys) {
271 var Event = YAHOO.util.Event;
272
273 var kc = Event.getCharCode(e), t=this.thumb;
274 var h=this.getXValue(),v=this.getYValue();
275
276 var horiz = false;
277 var changeValue = true;
278 switch (kc) {
279
280 // left
281 case 0x25: h -= this.keyIncrement; break;
282
283 // up
284 case 0x26: v -= this.keyIncrement; break;
285
286 // right
287 case 0x27: h += this.keyIncrement; break;
288
289 // down
290 case 0x28: v += this.keyIncrement; break;
291
292 // home
293 case 0x24: h = t.leftConstraint;
294 v = t.topConstraint;
295 break;
296
297 // end
298 case 0x23: h = t.rightConstraint;
299 v = t.bottomConstraint;
300 break;
301
302 default: changeValue = false;
303 }
304
305 if (changeValue) {
306 if (t._isRegion) {
307 this.setRegionValue(h, v, true);
308 } else {
309 var newVal = (t._isHoriz) ? h : v;
310 this.setValue(newVal, true);
311 }
312 Event.stopEvent(e);
313 }
314
315 }
316 },
317
318 /**
319 * Initialization that sets up the value offsets once the elements are ready
320 * @method setSliderStartState
321 */
322 setStartSliderState: function() {
323
324
325 this.setThumbCenterPoint();
326
327 /**
328 * The basline position of the background element, used
329 * to determine if the background has moved since the last
330 * operation.
331 * @property baselinePos
332 * @type [int, int]
333 */
334 this.baselinePos = YAHOO.util.Dom.getXY(this.getEl());
335
336 this.thumb.startOffset = this.thumb.getOffsetFromParent(this.baselinePos);
337
338 if (this.thumb._isRegion) {
339 if (this.deferredSetRegionValue) {
340 this.setRegionValue.apply(this, this.deferredSetRegionValue, true);
341 this.deferredSetRegionValue = null;
342 } else {
343 this.setRegionValue(0, 0, true);
344 }
345 } else {
346 if (this.deferredSetValue) {
347 this.setValue.apply(this, this.deferredSetValue, true);
348 this.deferredSetValue = null;
349 } else {
350 this.setValue(0, true, true);
351 }
352 }
353 },
354
355 /**
356 * When the thumb is available, we cache the centerpoint of the element so
357 * we can position the element correctly when the background is clicked
358 * @method setThumbCenterPoint
359 */
360 setThumbCenterPoint: function() {
361
362 var el = this.thumb.getEl();
363
364 if (el) {
365 /**
366 * The center of the slider element is stored so we can position
367 * place it in the correct position when the background is clicked
368 * @property thumbCenterPoint
369 * @type {"x": int, "y": int}
370 */
371 this.thumbCenterPoint = {
372 x: parseInt(el.offsetWidth/2, 10),
373 y: parseInt(el.offsetHeight/2, 10)
374 };
375 }
376
377 },
378
379 /**
380 * Locks the slider, overrides YAHOO.util.DragDrop
381 * @method lock
382 */
383 lock: function() {
384 this.thumb.lock();
385 this.locked = true;
386 },
387
388 /**
389 * Unlocks the slider, overrides YAHOO.util.DragDrop
390 * @method unlock
391 */
392 unlock: function() {
393 this.thumb.unlock();
394 this.locked = false;
395 },
396
397 /**
398 * Handles mouseup event on the slider background
399 * @method thumbMouseUp
400 * @private
401 */
402 thumbMouseUp: function() {
403 if (!this.isLocked() && !this.moveComplete) {
404 this.endMove();
405 }
406
407 },
408
409 /**
410 * Returns a reference to this slider's thumb
411 * @method getThumb
412 * @return {SliderThumb} this slider's thumb
413 */
414 getThumb: function() {
415 return this.thumb;
416 },
417
418 /**
419 * Try to focus the element when clicked so we can add
420 * accessibility features
421 * @method focus
422 * @private
423 */
424 focus: function() {
425
426 // Focus the background element if possible
427 var el = this.getEl();
428
429 if (el.focus) {
430 try {
431 el.focus();
432 } catch(e) {
433 // Prevent permission denied unhandled exception in FF that can
434 // happen when setting focus while another element is handling
435 // the blur. @TODO this is still writing to the error log
436 // (unhandled error) in FF1.5 with strict error checking on.
437 }
438 }
439
440 this.verifyOffset();
441
442 if (this.isLocked()) {
443 return false;
444 } else {
445 this.onSlideStart();
446 return true;
447 }
448 },
449
450 /**
451 * Event that fires when the value of the slider has changed
452 * @method onChange
453 * @param {int} firstOffset the number of pixels the thumb has moved
454 * from its start position. Normal horizontal and vertical sliders will only
455 * have the firstOffset. Regions will have both, the first is the horizontal
456 * offset, the second the vertical.
457 * @param {int} secondOffset the y offset for region sliders
458 * @deprecated use instance.subscribe("change") instead
459 */
460 onChange: function (firstOffset, secondOffset) {
461 /* override me */
462 },
463
464 /**
465 * Event that fires when the at the beginning of the slider thumb move
466 * @method onSlideStart
467 * @deprecated use instance.subscribe("slideStart") instead
468 */
469 onSlideStart: function () {
470 /* override me */
471 },
472
473 /**
474 * Event that fires at the end of a slider thumb move
475 * @method onSliderEnd
476 * @deprecated use instance.subscribe("slideEnd") instead
477 */
478 onSlideEnd: function () {
479 /* override me */
480 },
481
482 /**
483 * Returns the slider's thumb offset from the start position
484 * @method getValue
485 * @return {int} the current value
486 */
487 getValue: function () {
488 return this.thumb.getValue();
489 },
490
491 /**
492 * Returns the slider's thumb X offset from the start position
493 * @method getXValue
494 * @return {int} the current horizontal offset
495 */
496 getXValue: function () {
497 return this.thumb.getXValue();
498 },
499
500 /**
501 * Returns the slider's thumb Y offset from the start position
502 * @method getYValue
503 * @return {int} the current vertical offset
504 */
505 getYValue: function () {
506 return this.thumb.getYValue();
507 },
508
509 /**
510 * Internal handler for the slider thumb's onChange event
511 * @method handleThumbChange
512 * @private
513 */
514 handleThumbChange: function () {
515 var t = this.thumb;
516 if (t._isRegion) {
517 t.onChange(t.getXValue(), t.getYValue());
518 this.fireEvent("change", { x: t.getXValue(), y: t.getYValue() } );
519 } else {
520 t.onChange(t.getValue());
521 this.fireEvent("change", t.getValue());
522 }
523
524 },
525
526 /**
527 * Provides a way to set the value of the slider in code.
528 * @method setValue
529 * @param {int} newOffset the number of pixels the thumb should be
530 * positioned away from the initial start point
531 * @param {boolean} skipAnim set to true to disable the animation
532 * for this move action (but not others).
533 * @param {boolean} force ignore the locked setting and set value anyway
534 * @return {boolean} true if the move was performed, false if it failed
535 */
536 setValue: function(newOffset, skipAnim, force) {
537
538 if (!this.thumb.available) {
539 this.deferredSetValue = arguments;
540 return false;
541 }
542
543 if (this.isLocked() && !force) {
544 return false;
545 }
546
547 if ( isNaN(newOffset) ) {
548 return false;
549 }
550
551 var t = this.thumb;
552 var newX, newY;
553 this.verifyOffset();
554 if (t._isRegion) {
555 return false;
556 } else if (t._isHoriz) {
557 this.onSlideStart();
558 // this.fireEvent("slideStart");
559 newX = t.initPageX + newOffset + this.thumbCenterPoint.x;
560 this.moveThumb(newX, t.initPageY, skipAnim);
561 } else {
562 this.onSlideStart();
563 // this.fireEvent("slideStart");
564 newY = t.initPageY + newOffset + this.thumbCenterPoint.y;
565 this.moveThumb(t.initPageX, newY, skipAnim);
566 }
567
568 return true;
569 },
570
571 /**
572 * Provides a way to set the value of the region slider in code.
573 * @method setRegionValue
574 * @param {int} newOffset the number of pixels the thumb should be
575 * positioned away from the initial start point (x axis for region)
576 * @param {int} newOffset2 the number of pixels the thumb should be
577 * positioned away from the initial start point (y axis for region)
578 * @param {boolean} skipAnim set to true to disable the animation
579 * for this move action (but not others).
580 * @param {boolean} force ignore the locked setting and set value anyway
581 * @return {boolean} true if the move was performed, false if it failed
582 */
583 setRegionValue: function(newOffset, newOffset2, skipAnim) {
584
585 if (!this.thumb.available) {
586 this.deferredSetRegionValue = arguments;
587 return false;
588 }
589
590 if (this.isLocked() && !force) {
591 return false;
592 }
593
594 if ( isNaN(newOffset) ) {
595 return false;
596 }
597
598 var t = this.thumb;
599 if (t._isRegion) {
600 this.onSlideStart();
601 var newX = t.initPageX + newOffset + this.thumbCenterPoint.x;
602 var newY = t.initPageY + newOffset2 + this.thumbCenterPoint.y;
603 this.moveThumb(newX, newY, skipAnim);
604 return true;
605 }
606
607 return false;
608
609 },
610
611 /**
612 * Checks the background position element position. If it has moved from the
613 * baseline position, the constraints for the thumb are reset
614 * @method verifyOffset
615 * @return {boolean} True if the offset is the same as the baseline.
616 */
617 verifyOffset: function() {
618
619 var newPos = YAHOO.util.Dom.getXY(this.getEl());
620
621 if (newPos[0] != this.baselinePos[0] || newPos[1] != this.baselinePos[1]) {
622 this.thumb.resetConstraints();
623 this.baselinePos = newPos;
624 return false;
625 }
626
627 return true;
628 },
629
630 /**
631 * Move the associated slider moved to a timeout to try to get around the
632 * mousedown stealing moz does when I move the slider element between the
633 * cursor and the background during the mouseup event
634 * @method moveThumb
635 * @param {int} x the X coordinate of the click
636 * @param {int} y the Y coordinate of the click
637 * @param {boolean} skipAnim don't animate if the move happend onDrag
638 * @private
639 */
640 moveThumb: function(x, y, skipAnim) {
641
642
643 var t = this.thumb;
644 var self = this;
645
646 if (!t.available) {
647 return;
648 }
649
650
651 // this.verifyOffset();
652
653 t.setDelta(this.thumbCenterPoint.x, this.thumbCenterPoint.y);
654
655 var _p = t.getTargetCoord(x, y);
656 var p = [_p.x, _p.y];
657
658 this.fireEvent("slideStart");
659
660 if (this.animate && YAHOO.widget.Slider.ANIM_AVAIL && t._graduated && !skipAnim) {
661 // this.thumb._animating = true;
662 this.lock();
663
664 setTimeout( function() { self.moveOneTick(p); }, this.tickPause );
665
666 } else if (this.animate && YAHOO.widget.Slider.ANIM_AVAIL && !skipAnim) {
667
668 // this.thumb._animating = true;
669 this.lock();
670
671 var oAnim = new YAHOO.util.Motion(
672 t.id, { points: { to: p } },
673 this.animationDuration,
674 YAHOO.util.Easing.easeOut );
675
676 oAnim.onComplete.subscribe( function() { self.endMove(); } );
677 oAnim.animate();
678 } else {
679 t.setDragElPos(x, y);
680 // this.fireEvents();
681 this.endMove();
682 }
683 },
684
685 /**
686 * Move the slider one tick mark towards its final coordinate. Used
687 * for the animation when tick marks are defined
688 * @method moveOneTick
689 * @param {int[]} the destination coordinate
690 * @private
691 */
692 moveOneTick: function(finalCoord) {
693
694 var t = this.thumb;
695 var curCoord = YAHOO.util.Dom.getXY(t.getEl());
696 var tmp;
697
698 // var thresh = Math.min(t.tickSize + (Math.floor(t.tickSize/2)), 10);
699 // var thresh = 10;
700 // var thresh = t.tickSize + (Math.floor(t.tickSize/2));
701
702 var nextCoord = null;
703
704 if (t._isRegion) {
705 nextCoord = this._getNextX(curCoord, finalCoord);
706 var tmpX = (nextCoord) ? nextCoord[0] : curCoord[0];
707 nextCoord = this._getNextY([tmpX, curCoord[1]], finalCoord);
708
709 } else if (t._isHoriz) {
710 nextCoord = this._getNextX(curCoord, finalCoord);
711 } else {
712 nextCoord = this._getNextY(curCoord, finalCoord);
713 }
714
715
716 if (nextCoord) {
717
718 // move to the next coord
719 // YAHOO.util.Dom.setXY(t.getEl(), nextCoord);
720
721 // var el = t.getEl();
722 // YAHOO.util.Dom.setStyle(el, "left", (nextCoord[0] + this.thumb.deltaSetXY[0]) + "px");
723 // YAHOO.util.Dom.setStyle(el, "top", (nextCoord[1] + this.thumb.deltaSetXY[1]) + "px");
724
725 this.thumb.alignElWithMouse(t.getEl(), nextCoord[0], nextCoord[1]);
726
727 // check if we are in the final position, if not make a recursive call
728 if (!(nextCoord[0] == finalCoord[0] && nextCoord[1] == finalCoord[1])) {
729 var self = this;
730 setTimeout(function() { self.moveOneTick(finalCoord); },
731 this.tickPause);
732 } else {
733 this.endMove();
734 }
735 } else {
736 this.endMove();
737 }
738
739 //this.tickPause = Math.round(this.tickPause/2);
740 },
741
742 /**
743 * Returns the next X tick value based on the current coord and the target coord.
744 * @method _getNextX
745 * @private
746 */
747 _getNextX: function(curCoord, finalCoord) {
748 var t = this.thumb;
749 var thresh;
750 var tmp = [];
751 var nextCoord = null;
752 if (curCoord[0] > finalCoord[0]) {
753 thresh = t.tickSize - this.thumbCenterPoint.x;
754 tmp = t.getTargetCoord( curCoord[0] - thresh, curCoord[1] );
755 nextCoord = [tmp.x, tmp.y];
756 } else if (curCoord[0] < finalCoord[0]) {
757 thresh = t.tickSize + this.thumbCenterPoint.x;
758 tmp = t.getTargetCoord( curCoord[0] + thresh, curCoord[1] );
759 nextCoord = [tmp.x, tmp.y];
760 } else {
761 // equal, do nothing
762 }
763
764 return nextCoord;
765 },
766
767 /**
768 * Returns the next Y tick value based on the current coord and the target coord.
769 * @method _getNextY
770 * @private
771 */
772 _getNextY: function(curCoord, finalCoord) {
773 var t = this.thumb;
774 var thresh;
775 var tmp = [];
776 var nextCoord = null;
777
778 if (curCoord[1] > finalCoord[1]) {
779 thresh = t.tickSize - this.thumbCenterPoint.y;
780 tmp = t.getTargetCoord( curCoord[0], curCoord[1] - thresh );
781 nextCoord = [tmp.x, tmp.y];
782 } else if (curCoord[1] < finalCoord[1]) {
783 thresh = t.tickSize + this.thumbCenterPoint.y;
784 tmp = t.getTargetCoord( curCoord[0], curCoord[1] + thresh );
785 nextCoord = [tmp.x, tmp.y];
786 } else {
787 // equal, do nothing
788 }
789
790 return nextCoord;
791 },
792
793 /**
794 * Resets the constraints before moving the thumb.
795 * @method b4MouseDown
796 * @private
797 */
798 b4MouseDown: function(e) {
799 this.thumb.autoOffset();
800 this.thumb.resetConstraints();
801 },
802
803 /**
804 * Handles the mousedown event for the slider background
805 * @method onMouseDown
806 * @private
807 */
808 onMouseDown: function(e) {
809 // this.resetConstraints(true);
810 // this.thumb.resetConstraints(true);
811
812 if (! this.isLocked() && this.backgroundEnabled) {
813 var x = YAHOO.util.Event.getPageX(e);
814 var y = YAHOO.util.Event.getPageY(e);
815
816 this.focus();
817 this.moveThumb(x, y);
818 }
819
820 },
821
822 /**
823 * Handles the onDrag event for the slider background
824 * @method onDrag
825 * @private
826 */
827 onDrag: function(e) {
828 if (! this.isLocked()) {
829 var x = YAHOO.util.Event.getPageX(e);
830 var y = YAHOO.util.Event.getPageY(e);
831 this.moveThumb(x, y, true);
832 }
833 },
834
835 /**
836 * Fired when the slider movement ends
837 * @method endMove
838 * @private
839 */
840 endMove: function () {
841 // this._animating = false;
842 this.unlock();
843 this.moveComplete = true;
844 this.fireEvents();
845 },
846
847 /**
848 * Fires the change event if the value has been changed. Ignored if we are in
849 * the middle of an animation as the event will fire when the animation is
850 * complete
851 * @method fireEvents
852 * @private
853 */
854 fireEvents: function () {
855
856 var t = this.thumb;
857
858 t.cachePosition();
859
860 if (! this.isLocked()) {
861 if (t._isRegion) {
862 var newX = t.getXValue();
863 var newY = t.getYValue();
864
865 if (newX != this.previousX || newY != this.previousY) {
866 this.onChange(newX, newY);
867 this.fireEvent("change", { x: newX, y: newY });
868 }
869
870 this.previousX = newX;
871 this.previousY = newY;
872
873 } else {
874 var newVal = t.getValue();
875 if (newVal != this.previousVal) {
876 this.onChange( newVal );
877 this.fireEvent("change", newVal);
878 }
879 this.previousVal = newVal;
880 }
881
882 if (this.moveComplete) {
883 this.onSlideEnd();
884 this.fireEvent("slideEnd");
885 this.moveComplete = false;
886 }
887
888 }
889 },
890
891 /**
892 * Slider toString
893 * @method toString
894 * @return {string} string representation of the instance
895 */
896 toString: function () {
897 return ("Slider (" + this.type +") " + this.id);
898 }
899
900});
901
902YAHOO.augment(YAHOO.widget.Slider, YAHOO.util.EventProvider);
903
904/**
905 * A drag and drop implementation to be used as the thumb of a slider.
906 * @class SliderThumb
907 * @extends YAHOO.util.DD
908 * @constructor
909 * @param {String} id the id of the slider html element
910 * @param {String} sGroup the group of related DragDrop items
911 * @param {int} iLeft the number of pixels the element can move left
912 * @param {int} iRight the number of pixels the element can move right
913 * @param {int} iUp the number of pixels the element can move up
914 * @param {int} iDown the number of pixels the element can move down
915 * @param {int} iTickSize optional parameter for specifying that the element
916 * should move a certain number pixels at a time.
917 */
918YAHOO.widget.SliderThumb = function(id, sGroup, iLeft, iRight, iUp, iDown, iTickSize) {
919
920 if (id) {
921 this.init(id, sGroup);
922
923 /**
924 * The id of the thumbs parent HTML element (the slider background
925 * element).
926 * @property parentElId
927 * @type string
928 */
929 this.parentElId = sGroup;
930 }
931
932 //this.removeInvalidHandleType("A");
933
934
935 /**
936 * Overrides the isTarget property in YAHOO.util.DragDrop
937 * @property isTarget
938 * @private
939 */
940 this.isTarget = false;
941
942 /**
943 * The tick size for this slider
944 * @property tickSize
945 * @type int
946 * @private
947 */
948 this.tickSize = iTickSize;
949
950 /**
951 * Informs the drag and drop util that the offsets should remain when
952 * resetting the constraints. This preserves the slider value when
953 * the constraints are reset
954 * @property maintainOffset
955 * @type boolean
956 * @private
957 */
958 this.maintainOffset = true;
959
960 this.initSlider(iLeft, iRight, iUp, iDown, iTickSize);
961
962 /**
963 * Turns off the autoscroll feature in drag and drop
964 * @property scroll
965 * @private
966 */
967 this.scroll = false;
968
969};
970
971YAHOO.extend(YAHOO.widget.SliderThumb, YAHOO.util.DD, {
972
973 /**
974 * The (X and Y) difference between the thumb location and its parent
975 * (the slider background) when the control is instantiated.
976 * @property startOffset
977 * @type [int, int]
978 */
979 startOffset: null,
980
981 /**
982 * Flag used to figure out if this is a horizontal or vertical slider
983 * @property _isHoriz
984 * @type boolean
985 * @private
986 */
987 _isHoriz: false,
988
989 /**
990 * Cache the last value so we can check for change
991 * @property _prevVal
992 * @type int
993 * @private
994 */
995 _prevVal: 0,
996
997 /**
998 * The slider is _graduated if there is a tick interval defined
999 * @property _graduated
1000 * @type boolean
1001 * @private
1002 */
1003 _graduated: false,
1004
1005 /**
1006 * Returns the difference between the location of the thumb and its parent.
1007 * @method getOffsetFromParent
1008 * @param {[int, int]} parentPos Optionally accepts the position of the parent
1009 * @type [int, int]
1010 */
1011 getOffsetFromParent: function(parentPos) {
1012 var myPos = YAHOO.util.Dom.getXY(this.getEl());
1013 var ppos = parentPos || YAHOO.util.Dom.getXY(this.parentElId);
1014
1015 return [ (myPos[0] - ppos[0]), (myPos[1] - ppos[1]) ];
1016 },
1017
1018 /**
1019 * Set up the slider, must be called in the constructor of all subclasses
1020 * @method initSlider
1021 * @param {int} iLeft the number of pixels the element can move left
1022 * @param {int} iRight the number of pixels the element can move right
1023 * @param {int} iUp the number of pixels the element can move up
1024 * @param {int} iDown the number of pixels the element can move down
1025 * @param {int} iTickSize the width of the tick interval.
1026 */
1027 initSlider: function (iLeft, iRight, iUp, iDown, iTickSize) {
1028
1029 this.setXConstraint(iLeft, iRight, iTickSize);
1030 this.setYConstraint(iUp, iDown, iTickSize);
1031
1032 if (iTickSize && iTickSize > 1) {
1033 this._graduated = true;
1034 }
1035
1036 this._isHoriz = (iLeft || iRight);
1037 this._isVert = (iUp || iDown);
1038 this._isRegion = (this._isHoriz && this._isVert);
1039
1040 },
1041
1042 /**
1043 * Clear's the slider's ticks
1044 * @method clearTicks
1045 */
1046 clearTicks: function () {
1047 YAHOO.widget.SliderThumb.superclass.clearTicks.call(this);
1048 this._graduated = false;
1049 },
1050
1051 /**
1052 * Gets the current offset from the element's start position in
1053 * pixels.
1054 * @method getValue
1055 * @return {int} the number of pixels (positive or negative) the
1056 * slider has moved from the start position.
1057 */
1058 getValue: function () {
1059 if (!this.available) { return 0; }
1060 var val = (this._isHoriz) ? this.getXValue() : this.getYValue();
1061 return val;
1062 },
1063
1064 /**
1065 * Gets the current X offset from the element's start position in
1066 * pixels.
1067 * @method getXValue
1068 * @return {int} the number of pixels (positive or negative) the
1069 * slider has moved horizontally from the start position.
1070 */
1071 getXValue: function () {
1072 if (!this.available) { return 0; }
1073 var newOffset = this.getOffsetFromParent();
1074 return (newOffset[0] - this.startOffset[0]);
1075 },
1076
1077 /**
1078 * Gets the current Y offset from the element's start position in
1079 * pixels.
1080 * @method getYValue
1081 * @return {int} the number of pixels (positive or negative) the
1082 * slider has moved vertically from the start position.
1083 */
1084 getYValue: function () {
1085 if (!this.available) { return 0; }
1086 var newOffset = this.getOffsetFromParent();
1087 return (newOffset[1] - this.startOffset[1]);
1088 },
1089
1090 /**
1091 * Thumb toString
1092 * @method toString
1093 * @return {string} string representation of the instance
1094 */
1095 toString: function () {
1096 return "SliderThumb " + this.id;
1097 },
1098
1099 /**
1100 * The onchange event for the handle/thumb is delegated to the YAHOO.widget.Slider
1101 * instance it belongs to.
1102 * @method onChange
1103 * @private
1104 */
1105 onChange: function (x, y) {
1106 }
1107
1108});
1109
1110if ("undefined" == typeof YAHOO.util.Anim) {
1111 YAHOO.widget.Slider.ANIM_AVAIL = false;
1112}
1113
diff --git a/frontend/beta/js/YUI/tabview.js b/frontend/beta/js/YUI/tabview.js
new file mode 100644
index 0000000..34a09bb
--- a/dev/null
+++ b/frontend/beta/js/YUI/tabview.js
@@ -0,0 +1,1950 @@
1/*
2Copyright (c) 2006, Yahoo! Inc. All rights reserved.
3Code licensed under the BSD License:
4http://developer.yahoo.net/yui/license.txt
5version: 0.12.0
6*/
7(function() {
8
9 YAHOO.util.Lang = {
10 isArray: function(val) { // frames lose type, so test constructor string
11 if (val.constructor && val.constructor.toString().indexOf('Array') > -1) {
12 return true;
13 } else {
14 return YAHOO.util.Lang.isObject(val) && val.constructor == Array;
15 }
16 },
17
18 isBoolean: function(val) {
19 return typeof val == 'boolean';
20 },
21
22 isFunction: function(val) {
23 return typeof val == 'function';
24 },
25
26 isNull: function(val) {
27 return val === null;
28 },
29
30 isNumber: function(val) {
31 return !isNaN(val);
32 },
33
34 isObject: function(val) {
35 return typeof val == 'object' || YAHOO.util.Lang.isFunction(val);
36 },
37
38 isString: function(val) {
39 return typeof val == 'string';
40 },
41
42 isUndefined: function(val) {
43 return typeof val == 'undefined';
44 }
45 };
46})();/**
47 * Provides Attribute configurations.
48 * @namespace YAHOO.util
49 * @class Attribute
50 * @constructor
51 * @param hash {Object} The intial Attribute.
52 * @param {YAHOO.util.AttributeProvider} The owner of the Attribute instance.
53 */
54
55YAHOO.util.Attribute = function(hash, owner) {
56 if (owner) {
57 this.owner = owner;
58 this.configure(hash, true);
59 }
60};
61
62YAHOO.util.Attribute.prototype = {
63 /**
64 * The name of the attribute.
65 * @property name
66 * @type String
67 */
68 name: undefined,
69
70 /**
71 * The value of the attribute.
72 * @property value
73 * @type String
74 */
75 value: null,
76
77 /**
78 * The owner of the attribute.
79 * @property owner
80 * @type YAHOO.util.AttributeProvider
81 */
82 owner: null,
83
84 /**
85 * Whether or not the attribute is read only.
86 * @property readOnly
87 * @type Boolean
88 */
89 readOnly: false,
90
91 /**
92 * Whether or not the attribute can only be written once.
93 * @property writeOnce
94 * @type Boolean
95 */
96 writeOnce: false,
97
98 /**
99 * The attribute's initial configuration.
100 * @private
101 * @property _initialConfig
102 * @type Object
103 */
104 _initialConfig: null,
105
106 /**
107 * Whether or not the attribute's value has been set.
108 * @private
109 * @property _written
110 * @type Boolean
111 */
112 _written: false,
113
114 /**
115 * The method to use when setting the attribute's value.
116 * The method recieves the new value as the only argument.
117 * @property method
118 * @type Function
119 */
120 method: null,
121
122 /**
123 * The validator to use when setting the attribute's value.
124 * @property validator
125 * @type Function
126 * @return Boolean
127 */
128 validator: null,
129
130 /**
131 * Retrieves the current value of the attribute.
132 * @method getValue
133 * @return {any} The current value of the attribute.
134 */
135 getValue: function() {
136 return this.value;
137 },
138
139 /**
140 * Sets the value of the attribute and fires beforeChange and change events.
141 * @method setValue
142 * @param {Any} value The value to apply to the attribute.
143 * @param {Boolean} silent If true the change events will not be fired.
144 * @return {Boolean} Whether or not the value was set.
145 */
146 setValue: function(value, silent) {
147 var beforeRetVal;
148 var owner = this.owner;
149 var name = this.name;
150
151 var event = {
152 type: name,
153 prevValue: this.getValue(),
154 newValue: value
155 };
156
157 if (this.readOnly || ( this.writeOnce && this._written) ) {
158 return false; // write not allowed
159 }
160
161 if (this.validator && !this.validator.call(owner, value) ) {
162 return false; // invalid value
163 }
164
165 if (!silent) {
166 beforeRetVal = owner.fireBeforeChangeEvent(event);
167 if (beforeRetVal === false) {
168 YAHOO.log('setValue ' + name +
169 'cancelled by beforeChange event', 'info', 'Attribute');
170 return false;
171 }
172 }
173
174 if (this.method) {
175 this.method.call(owner, value);
176 }
177
178 this.value = value;
179 this._written = true;
180
181 event.type = name;
182
183 if (!silent) {
184 this.owner.fireChangeEvent(event);
185 }
186
187 return true;
188 },
189
190 /**
191 * Allows for configuring the Attribute's properties.
192 * @method configure
193 * @param {Object} map A key-value map of Attribute properties.
194 * @param {Boolean} init Whether or not this should become the initial config.
195 */
196 configure: function(map, init) {
197 map = map || {};
198 this._written = false; // reset writeOnce
199 this._initialConfig = this._initialConfig || {};
200
201 for (var key in map) {
202 if ( key && map.hasOwnProperty(key) ) {
203 this[key] = map[key];
204 if (init) {
205 this._initialConfig[key] = map[key];
206 }
207 }
208 }
209 },
210
211 /**
212 * Resets the value to the initial config value.
213 * @method resetValue
214 * @return {Boolean} Whether or not the value was set.
215 */
216 resetValue: function() {
217 return this.setValue(this._initialConfig.value);
218 },
219
220 /**
221 * Resets the attribute config to the initial config state.
222 * @method resetConfig
223 */
224 resetConfig: function() {
225 this.configure(this._initialConfig);
226 },
227
228 /**
229 * Resets the value to the current value.
230 * Useful when values may have gotten out of sync with actual properties.
231 * @method refresh
232 * @return {Boolean} Whether or not the value was set.
233 */
234 refresh: function(silent) {
235 this.setValue(this.value, silent);
236 }
237};(function() {
238 var Lang = YAHOO.util.Lang;
239
240 /*
241 Copyright (c) 2006, Yahoo! Inc. All rights reserved.
242 Code licensed under the BSD License:
243 http://developer.yahoo.net/yui/license.txt
244 */
245
246 /**
247 * Provides and manages YAHOO.util.Attribute instances
248 * @namespace YAHOO.util
249 * @class AttributeProvider
250 * @uses YAHOO.util.EventProvider
251 */
252 YAHOO.util.AttributeProvider = function() {};
253
254 YAHOO.util.AttributeProvider.prototype = {
255
256 /**
257 * A key-value map of Attribute configurations
258 * @property _configs
259 * @protected (may be used by subclasses and augmentors)
260 * @private
261 * @type {Object}
262 */
263 _configs: null,
264 /**
265 * Returns the current value of the attribute.
266 * @method get
267 * @param {String} key The attribute whose value will be returned.
268 */
269 get: function(key){
270 var configs = this._configs || {};
271 var config = configs[key];
272
273 if (!config) {
274 YAHOO.log(key + ' not found', 'error', 'AttributeProvider');
275 return undefined;
276 }
277
278 return config.value;
279 },
280
281 /**
282 * Sets the value of a config.
283 * @method set
284 * @param {String} key The name of the attribute
285 * @param {Any} value The value to apply to the attribute
286 * @param {Boolean} silent Whether or not to suppress change events
287 * @return {Boolean} Whether or not the value was set.
288 */
289 set: function(key, value, silent){
290 var configs = this._configs || {};
291 var config = configs[key];
292
293 if (!config) {
294 YAHOO.log('set failed: ' + key + ' not found',
295 'error', 'AttributeProvider');
296 return false;
297 }
298
299 return config.setValue(value, silent);
300 },
301
302 /**
303 * Returns an array of attribute names.
304 * @method getAttributeKeys
305 * @return {Array} An array of attribute names.
306 */
307 getAttributeKeys: function(){
308 var configs = this._configs;
309 var keys = [];
310 var config;
311 for (var key in configs) {
312 config = configs[key];
313 if ( configs.hasOwnProperty(key) &&
314 !Lang.isUndefined(config) ) {
315 keys[keys.length] = key;
316 }
317 }
318
319 return keys;
320 },
321
322 /**
323 * Sets multiple attribute values.
324 * @method setAttributes
325 * @param {Object} map A key-value map of attributes
326 * @param {Boolean} silent Whether or not to suppress change events
327 */
328 setAttributes: function(map, silent){
329 for (var key in map) {
330 if ( map.hasOwnProperty(key) ) {
331 this.set(key, map[key], silent);
332 }
333 }
334 },
335
336 /**
337 * Resets the specified attribute's value to its initial value.
338 * @method resetValue
339 * @param {String} key The name of the attribute
340 * @param {Boolean} silent Whether or not to suppress change events
341 * @return {Boolean} Whether or not the value was set
342 */
343 resetValue: function(key, silent){
344 var configs = this._configs || {};
345 if (configs[key]) {
346 this.set(key, configs[key]._initialConfig.value, silent);
347 return true;
348 }
349 return false;
350 },
351
352 /**
353 * Sets the attribute's value to its current value.
354 * @method refresh
355 * @param {String | Array} key The attribute(s) to refresh
356 * @param {Boolean} silent Whether or not to suppress change events
357 */
358 refresh: function(key, silent){
359 var configs = this._configs;
360
361 key = ( ( Lang.isString(key) ) ? [key] : key ) ||
362 this.getAttributeKeys();
363
364 for (var i = 0, len = key.length; i < len; ++i) {
365 if ( // only set if there is a value and not null
366 configs[key[i]] &&
367 ! Lang.isUndefined(configs[key[i]].value) &&
368 ! Lang.isNull(configs[key[i]].value) ) {
369 configs[key[i]].refresh(silent);
370 }
371 }
372 },
373
374 /**
375 * Adds an Attribute to the AttributeProvider instance.
376 * @method register
377 * @param {String} key The attribute's name
378 * @param {Object} map A key-value map containing the
379 * attribute's properties.
380 */
381 register: function(key, map) {
382 this._configs = this._configs || {};
383
384 if (this._configs[key]) { // dont override
385 return false;
386 }
387
388 map.name = key;
389 this._configs[key] = new YAHOO.util.Attribute(map, this);
390 return true;
391 },
392
393 /**
394 * Returns the attribute's properties.
395 * @method getAttributeConfig
396 * @param {String} key The attribute's name
397 * @private
398 * @return {object} A key-value map containing all of the
399 * attribute's properties.
400 */
401 getAttributeConfig: function(key) {
402 var configs = this._configs || {};
403 var config = configs[key] || {};
404 var map = {}; // returning a copy to prevent overrides
405
406 for (key in config) {
407 if ( config.hasOwnProperty(key) ) {
408 map[key] = config[key];
409 }
410 }
411
412 return map;
413 },
414
415 /**
416 * Sets or updates an Attribute instance's properties.
417 * @method configureAttribute
418 * @param {String} key The attribute's name.
419 * @param {Object} map A key-value map of attribute properties
420 * @param {Boolean} init Whether or not this should become the intial config.
421 */
422 configureAttribute: function(key, map, init) {
423 var configs = this._configs || {};
424
425 if (!configs[key]) {
426 YAHOO.log('unable to configure, ' + key + ' not found',
427 'error', 'AttributeProvider');
428 return false;
429 }
430
431 configs[key].configure(map, init);
432 },
433
434 /**
435 * Resets an attribute to its intial configuration.
436 * @method resetAttributeConfig
437 * @param {String} key The attribute's name.
438 * @private
439 */
440 resetAttributeConfig: function(key){
441 var configs = this._configs || {};
442 configs[key].resetConfig();
443 },
444
445 /**
446 * Fires the attribute's beforeChange event.
447 * @method fireBeforeChangeEvent
448 * @param {String} key The attribute's name.
449 * @param {Obj} e The event object to pass to handlers.
450 */
451 fireBeforeChangeEvent: function(e) {
452 var type = 'before';
453 type += e.type.charAt(0).toUpperCase() + e.type.substr(1) + 'Change';
454 e.type = type;
455 return this.fireEvent(e.type, e);
456 },
457
458 /**
459 * Fires the attribute's change event.
460 * @method fireChangeEvent
461 * @param {String} key The attribute's name.
462 * @param {Obj} e The event object to pass to the handlers.
463 */
464 fireChangeEvent: function(e) {
465 e.type += 'Change';
466 return this.fireEvent(e.type, e);
467 }
468 };
469
470 YAHOO.augment(YAHOO.util.AttributeProvider, YAHOO.util.EventProvider);
471})();(function() {
472// internal shorthand
473var Dom = YAHOO.util.Dom,
474 Lang = YAHOO.util.Lang,
475 EventPublisher = YAHOO.util.EventPublisher,
476 AttributeProvider = YAHOO.util.AttributeProvider;
477
478/**
479 * Element provides an interface to an HTMLElement's attributes and common
480 * methods. Other commonly used attributes are added as well.
481 * @namespace YAHOO.util
482 * @class Element
483 * @uses YAHOO.util.AttributeProvider
484 * @constructor
485 * @param el {HTMLElement | String} The html element that
486 * represents the Element.
487 * @param {Object} map A key-value map of initial config names and values
488 */
489YAHOO.util.Element = function(el, map) {
490 if (arguments.length) {
491 this.init(el, map);
492 }
493};
494
495YAHOO.util.Element.prototype = {
496 /**
497 * Dom events supported by the Element instance.
498 * @property DOM_EVENTS
499 * @type Object
500 */
501 DOM_EVENTS: null,
502
503 /**
504 * Wrapper for HTMLElement method.
505 * @method appendChild
506 * @param {Boolean} deep Whether or not to do a deep clone
507 */
508 appendChild: function(child) {
509 child = child.get ? child.get('element') : child;
510 this.get('element').appendChild(child);
511 },
512
513 /**
514 * Wrapper for HTMLElement method.
515 * @method getElementsByTagName
516 * @param {String} tag The tagName to collect
517 */
518 getElementsByTagName: function(tag) {
519 return this.get('element').getElementsByTagName(tag);
520 },
521
522 /**
523 * Wrapper for HTMLElement method.
524 * @method hasChildNodes
525 * @return {Boolean} Whether or not the element has childNodes
526 */
527 hasChildNodes: function() {
528 return this.get('element').hasChildNodes();
529 },
530
531 /**
532 * Wrapper for HTMLElement method.
533 * @method insertBefore
534 * @param {HTMLElement} element The HTMLElement to insert
535 * @param {HTMLElement} before The HTMLElement to insert
536 * the element before.
537 */
538 insertBefore: function(element, before) {
539 element = element.get ? element.get('element') : element;
540 before = (before && before.get) ? before.get('element') : before;
541
542 this.get('element').insertBefore(element, before);
543 },
544
545 /**
546 * Wrapper for HTMLElement method.
547 * @method removeChild
548 * @param {HTMLElement} child The HTMLElement to remove
549 */
550 removeChild: function(child) {
551 child = child.get ? child.get('element') : child;
552 this.get('element').removeChild(child);
553 return true;
554 },
555
556 /**
557 * Wrapper for HTMLElement method.
558 * @method replaceChild
559 * @param {HTMLElement} newNode The HTMLElement to insert
560 * @param {HTMLElement} oldNode The HTMLElement to replace
561 */
562 replaceChild: function(newNode, oldNode) {
563 newNode = newNode.get ? newNode.get('element') : newNode;
564 oldNode = oldNode.get ? oldNode.get('element') : oldNode;
565 return this.get('element').replaceChild(newNode, oldNode);
566 },
567
568
569 /**
570 * Registers Element specific attributes.
571 * @method initAttributes
572 * @param {Object} map A key-value map of initial attribute configs
573 */
574 initAttributes: function(map) {
575 map = map || {};
576 var element = Dom.get(map.element) || null;
577
578 /**
579 * The HTMLElement the Element instance refers to.
580 * @config element
581 * @type HTMLElement
582 */
583 this.register('element', {
584 value: element,
585 readOnly: true
586 });
587 },
588
589 /**
590 * Adds a listener for the given event. These may be DOM or
591 * customEvent listeners. Any event that is fired via fireEvent
592 * can be listened for. All handlers receive an event object.
593 * @method addListener
594 * @param {String} type The name of the event to listen for
595 * @param {Function} fn The handler to call when the event fires
596 * @param {Any} obj A variable to pass to the handler
597 * @param {Object} scope The object to use for the scope of the handler
598 */
599 addListener: function(type, fn, obj, scope) {
600 var el = this.get('element');
601 var scope = scope || this;
602
603 el = this.get('id') || el;
604
605 if (!this._events[type]) { // create on the fly
606 if ( this.DOM_EVENTS[type] ) {
607 YAHOO.util.Event.addListener(el, type, function(e) {
608 if (e.srcElement && !e.target) { // supplement IE with target
609 e.target = e.srcElement;
610 }
611 this.fireEvent(type, e);
612 }, obj, scope);
613 }
614
615 this.createEvent(type, this);
616 this._events[type] = true;
617 }
618
619 this.subscribe.apply(this, arguments); // notify via customEvent
620 },
621
622
623 /**
624 * Alias for addListener
625 * @method on
626 * @param {String} type The name of the event to listen for
627 * @param {Function} fn The function call when the event fires
628 * @param {Any} obj A variable to pass to the handler
629 * @param {Object} scope The object to use for the scope of the handler
630 */
631 on: function() { this.addListener.apply(this, arguments); },
632
633
634 /**
635 * Remove an event listener
636 * @method removeListener
637 * @param {String} type The name of the event to listen for
638 * @param {Function} fn The function call when the event fires
639 */
640 removeListener: function(type, fn) {
641 this.unsubscribe.apply(this, arguments);
642 },
643
644 /**
645 * Wrapper for Dom method.
646 * @method addClass
647 * @param {String} className The className to add
648 */
649 addClass: function(className) {
650 Dom.addClass(this.get('element'), className);
651 },
652
653 /**
654 * Wrapper for Dom method.
655 * @method getElementsByClassName
656 * @param {String} className The className to collect
657 * @param {String} tag (optional) The tag to use in
658 * conjunction with class name
659 * @return {Array} Array of HTMLElements
660 */
661 getElementsByClassName: function(className, tag) {
662 return Dom.getElementsByClassName(className, tag,
663 this.get('element') );
664 },
665
666 /**
667 * Wrapper for Dom method.
668 * @method hasClass
669 * @param {String} className The className to add
670 * @return {Boolean} Whether or not the element has the class name
671 */
672 hasClass: function(className) {
673 return Dom.hasClass(this.get('element'), className);
674 },
675
676 /**
677 * Wrapper for Dom method.
678 * @method removeClass
679 * @param {String} className The className to remove
680 */
681 removeClass: function(className) {
682 return Dom.removeClass(this.get('element'), className);
683 },
684
685 /**
686 * Wrapper for Dom method.
687 * @method replaceClass
688 * @param {String} oldClassName The className to replace
689 * @param {String} newClassName The className to add
690 */
691 replaceClass: function(oldClassName, newClassName) {
692 return Dom.replaceClass(this.get('element'),
693 oldClassName, newClassName);
694 },
695
696 /**
697 * Wrapper for Dom method.
698 * @method setStyle
699 * @param {String} property The style property to set
700 * @param {String} value The value to apply to the style property
701 */
702 setStyle: function(property, value) {
703 return Dom.setStyle(this.get('element'), property, value);
704 },
705
706 /**
707 * Wrapper for Dom method.
708 * @method getStyle
709 * @param {String} property The style property to retrieve
710 * @return {String} The current value of the property
711 */
712 getStyle: function(property) {
713 return Dom.getStyle(this.get('element'), property);
714 },
715
716 /**
717 * Apply any queued set calls.
718 * @method fireQueue
719 */
720 fireQueue: function() {
721 var queue = this._queue;
722 for (var i = 0, len = queue.length; i < len; ++i) {
723 this[queue[i][0]].apply(this, queue[i][1]);
724 }
725 },
726
727 /**
728 * Appends the HTMLElement into either the supplied parentNode.
729 * @method appendTo
730 * @param {HTMLElement | Element} parentNode The node to append to
731 * @param {HTMLElement | Element} before An optional node to insert before
732 */
733 appendTo: function(parent, before) {
734 parent = (parent.get) ? parent.get('element') : Dom.get(parent);
735
736 before = (before && before.get) ?
737 before.get('element') : Dom.get(before);
738 var element = this.get('element');
739
740 var newAddition = !Dom.inDocument(element);
741
742 if (!element) {
743 YAHOO.log('appendTo failed: element not available',
744 'error', 'Element');
745 return false;
746 }
747
748 if (!parent) {
749 YAHOO.log('appendTo failed: parent not available',
750 'error', 'Element');
751 return false;
752 }
753
754 if (element.parent != parent) {
755 if (before) {
756 parent.insertBefore(element, before);
757 } else {
758 parent.appendChild(element);
759 }
760 }
761
762 YAHOO.log(element + 'appended to ' + parent);
763
764 if (!newAddition) {
765 return false; // note return; no refresh if in document
766 }
767
768 // if a new addition, refresh HTMLElement any applied attributes
769 var keys = this.getAttributeKeys();
770
771 for (var key in keys) { // only refresh HTMLElement attributes
772 if ( !Lang.isUndefined(element[key]) ) {
773 this.refresh(key);
774 }
775 }
776 },
777
778 get: function(key) {
779 var configs = this._configs || {};
780 var el = configs.element; // avoid loop due to 'element'
781 if (el && !configs[key] && !Lang.isUndefined(el.value[key]) ) {
782 return el.value[key];
783 }
784
785 return AttributeProvider.prototype.get.call(this, key);
786 },
787
788 set: function(key, value, silent) {
789 var el = this.get('element');
790 if (!el) {
791 this._queue[key] = ['set', arguments];
792 return false;
793 }
794
795 // set it on the element if not a property
796 if ( !this._configs[key] && !Lang.isUndefined(el[key]) ) {
797 _registerHTMLAttr(this, key);
798 }
799
800 return AttributeProvider.prototype.set.apply(this, arguments);
801 },
802
803 register: function(key) { // protect html attributes
804 var configs = this._configs || {};
805 var element = this.get('element') || null;
806
807 if ( element && !Lang.isUndefined(element[key]) ) {
808 YAHOO.log(key + ' is reserved for ' + element,
809 'error', 'Element');
810 return false;
811 }
812
813 return AttributeProvider.prototype.register.apply(this, arguments);
814 },
815
816 configureAttribute: function(property, map, init) { // protect html attributes
817 if (!this._configs[property] && this._configs.element &&
818 !Lang.isUndefined(this._configs.element[property]) ) {
819 _registerHTMLAttr(this, property, map);
820 return false;
821 }
822
823 return AttributeProvider.prototype.configure.apply(this, arguments);
824 },
825
826 getAttributeKeys: function() {
827 var el = this.get('element');
828 var keys = AttributeProvider.prototype.getAttributeKeys.call(this);
829
830 //add any unconfigured element keys
831 for (var key in el) {
832 if (!this._configs[key]) {
833 keys[key] = keys[key] || el[key];
834 }
835 }
836
837 return keys;
838 },
839
840 init: function(el, attr) {
841 this._queue = this._queue || [];
842 this._events = this._events || {};
843 this._configs = this._configs || {};
844 attr = attr || {};
845 attr.element = attr.element || el || null;
846
847 this.DOM_EVENTS = {
848 'click': true,
849 'keydown': true,
850 'keypress': true,
851 'keyup': true,
852 'mousedown': true,
853 'mousemove': true,
854 'mouseout': true,
855 'mouseover': true,
856 'mouseup': true
857 };
858
859 var readyHandler = function() {
860 this.initAttributes(attr);
861
862 this.setAttributes(attr, true);
863 this.fireQueue();
864 this.fireEvent('contentReady', {
865 type: 'contentReady',
866 target: attr.element
867 });
868 };
869
870 if ( Lang.isString(el) ) {
871 _registerHTMLAttr(this, 'id', { value: el });
872 YAHOO.util.Event.onAvailable(el, function() {
873 attr.element = Dom.get(el);
874 this.fireEvent('available', {
875 type: 'available',
876 target: attr.element
877 });
878 }, this, true);
879
880 YAHOO.util.Event.onContentReady(el, function() {
881 readyHandler.call(this);
882 }, this, true);
883 } else {
884 readyHandler.call(this);
885 }
886 }
887};
888
889/**
890 * Sets the value of the property and fires beforeChange and change events.
891 * @private
892 * @method _registerHTMLAttr
893 * @param {YAHOO.util.Element} element The Element instance to
894 * register the config to.
895 * @param {String} key The name of the config to register
896 * @param {Object} map A key-value map of the config's params
897 */
898var _registerHTMLAttr = function(self, key, map) {
899 var el = self.get('element');
900 map = map || {};
901 map.name = key;
902 map.method = map.method || function(value) {
903 el[key] = value;
904 };
905 map.value = map.value || el[key];
906 self._configs[key] = new YAHOO.util.Attribute(map, self);
907};
908
909/**
910 * Fires when the Element's HTMLElement can be retrieved by Id.
911 * <p>See: <a href="#addListener">Element.addListener</a></p>
912 * <p><strong>Event fields:</strong><br>
913 * <code>&lt;String&gt; type</code> available<br>
914 * <code>&lt;HTMLElement&gt;
915 * target</code> the HTMLElement bound to this Element instance<br>
916 * <p><strong>Usage:</strong><br>
917 * <code>var handler = function(e) {var target = e.target};<br>
918 * myTabs.addListener('available', handler);</code></p>
919 * @event available
920 */
921
922/**
923 * Fires when the Element's HTMLElement subtree is rendered.
924 * <p>See: <a href="#addListener">Element.addListener</a></p>
925 * <p><strong>Event fields:</strong><br>
926 * <code>&lt;String&gt; type</code> contentReady<br>
927 * <code>&lt;HTMLElement&gt;
928 * target</code> the HTMLElement bound to this Element instance<br>
929 * <p><strong>Usage:</strong><br>
930 * <code>var handler = function(e) {var target = e.target};<br>
931 * myTabs.addListener('contentReady', handler);</code></p>
932 * @event contentReady
933 */
934
935YAHOO.augment(YAHOO.util.Element, AttributeProvider);
936})();(function() {
937 var Dom = YAHOO.util.Dom,
938 Event = YAHOO.util.Event,
939 Lang = YAHOO.util.Lang;
940
941 /**
942 * A representation of a Tab's label and content.
943 * @namespace YAHOO.widget
944 * @class Tab
945 * @extends YAHOO.util.Element
946 * @constructor
947 * @param element {HTMLElement | String} (optional) The html element that
948 * represents the TabView. An element will be created if none provided.
949 * @param {Object} properties A key map of initial properties
950 */
951 Tab = function(el, attr) {
952 attr = attr || {};
953 if (arguments.length == 1 && !Lang.isString(el) && !el.nodeName) {
954 attr = el;
955 el = attr.element;
956 }
957
958 if (!el && !attr.element) {
959 el = _createTabElement.call(this, attr);
960 }
961
962 this.loadHandler = {
963 success: function(o) {
964 this.set('content', o.responseText);
965 },
966 failure: function(o) {
967 YAHOO.log('loading failed: ' + o.statusText,
968 'error', 'Tab');
969 }
970 };
971
972 Tab.superclass.constructor.call(this, el, attr);
973
974 this.DOM_EVENTS = {}; // delegating to tabView
975 };
976
977 YAHOO.extend(Tab, YAHOO.util.Element);
978 var proto = Tab.prototype;
979
980 /**
981 * The default tag name for a Tab's inner element.
982 * @property LABEL_INNER_TAGNAME
983 * @type String
984 * @default "em"
985 */
986 proto.LABEL_TAGNAME = 'em';
987
988 /**
989 * The class name applied to active tabs.
990 * @property ACTIVE_CLASSNAME
991 * @type String
992 * @default "on"
993 */
994 proto.ACTIVE_CLASSNAME = 'selected';
995
996 /**
997 * The class name applied to disabled tabs.
998 * @property DISABLED_CLASSNAME
999 * @type String
1000 * @default "disabled"
1001 */
1002 proto.DISABLED_CLASSNAME = 'disabled';
1003
1004 /**
1005 * The class name applied to dynamic tabs while loading.
1006 * @property LOADING_CLASSNAME
1007 * @type String
1008 * @default "disabled"
1009 */
1010 proto.LOADING_CLASSNAME = 'loading';
1011
1012 /**
1013 * Provides a reference to the connection request object when data is
1014 * loaded dynamically.
1015 * @property dataConnection
1016 * @type Object
1017 */
1018 proto.dataConnection = null;
1019
1020 /**
1021 * Object containing success and failure callbacks for loading data.
1022 * @property loadHandler
1023 * @type object
1024 */
1025 proto.loadHandler = null;
1026
1027 /**
1028 * Provides a readable name for the tab.
1029 * @method toString
1030 * @return String
1031 */
1032 proto.toString = function() {
1033 var el = this.get('element');
1034 var id = el.id || el.tagName;
1035 return "Tab " + id;
1036 };
1037
1038 /**
1039 * Registers TabView specific properties.
1040 * @method initAttributes
1041 * @param {Object} attr Hash of initial attributes
1042 */
1043 proto.initAttributes = function(attr) {
1044 attr = attr || {};
1045 Tab.superclass.initAttributes.call(this, attr);
1046
1047 var el = this.get('element');
1048
1049 /**
1050 * The event that triggers the tab's activation.
1051 * @config activationEvent
1052 * @type String
1053 */
1054 this.register('activationEvent', {
1055 value: attr.activationEvent || 'click'
1056 });
1057
1058 /**
1059 * The element that contains the tab's label.
1060 * @config labelEl
1061 * @type HTMLElement
1062 */
1063 this.register('labelEl', {
1064 value: attr.labelEl || _getlabelEl.call(this),
1065 method: function(value) {
1066 var current = this.get('labelEl');
1067
1068 if (current) {
1069 if (current == value) {
1070 return false; // already set
1071 }
1072
1073 this.replaceChild(value, current);
1074 } else if (el.firstChild) { // ensure label is firstChild by default
1075 this.insertBefore(value, el.firstChild);
1076 } else {
1077 this.appendChild(value);
1078 }
1079 }
1080 });
1081
1082 /**
1083 * The tab's label text (or innerHTML).
1084 * @config label
1085 * @type String
1086 */
1087 this.register('label', {
1088 value: attr.label || _getLabel.call(this),
1089 method: function(value) {
1090 var labelEl = this.get('labelEl');
1091 if (!labelEl) { // create if needed
1092 this.set('labelEl', _createlabelEl.call(this));
1093 }
1094
1095 _setLabel.call(this, value);
1096 }
1097 });
1098
1099 /**
1100 * The HTMLElement that contains the tab's content.
1101 * @config contentEl
1102 * @type HTMLElement
1103 */
1104 this.register('contentEl', { // TODO: apply className?
1105 value: attr.contentEl || document.createElement('div'),
1106 method: function(value) {
1107 var current = this.get('contentEl');
1108
1109 if (current) {
1110 if (current == value) {
1111 return false; // already set
1112 }
1113 this.replaceChild(value, current);
1114 }
1115 }
1116 });
1117
1118 /**
1119 * The tab's content.
1120 * @config content
1121 * @type String
1122 */
1123 this.register('content', {
1124 value: attr.content, // TODO: what about existing?
1125 method: function(value) {
1126 this.get('contentEl').innerHTML = value;
1127 }
1128 });
1129
1130 var _dataLoaded = false;
1131
1132 /**
1133 * The tab's data source, used for loading content dynamically.
1134 * @config dataSrc
1135 * @type String
1136 */
1137 this.register('dataSrc', {
1138 value: attr.dataSrc
1139 });
1140
1141 /**
1142 * Whether or not content should be reloaded for every view.
1143 * @config cacheData
1144 * @type Boolean
1145 * @default false
1146 */
1147 this.register('cacheData', {
1148 value: attr.cacheData || false,
1149 validator: Lang.isBoolean
1150 });
1151
1152 /**
1153 * The method to use for the data request.
1154 * @config loadMethod
1155 * @type String
1156 * @default "GET"
1157 */
1158 this.register('loadMethod', {
1159 value: attr.loadMethod || 'GET',
1160 validator: Lang.isString
1161 });
1162
1163 /**
1164 * Whether or not any data has been loaded from the server.
1165 * @config dataLoaded
1166 * @type Boolean
1167 */
1168 this.register('dataLoaded', {
1169 value: false,
1170 validator: Lang.isBoolean,
1171 writeOnce: true
1172 });
1173
1174 /**
1175 * Number if milliseconds before aborting and calling failure handler.
1176 * @config dataTimeout
1177 * @type Number
1178 * @default null
1179 */
1180 this.register('dataTimeout', {
1181 value: attr.dataTimeout || null,
1182 validator: Lang.isNumber
1183 });
1184
1185 /**
1186 * Whether or not the tab is currently active.
1187 * If a dataSrc is set for the tab, the content will be loaded from
1188 * the given source.
1189 * @config active
1190 * @type Boolean
1191 */
1192 this.register('active', {
1193 value: attr.active || this.hasClass(this.ACTIVE_CLASSNAME),
1194 method: function(value) {
1195 if (value === true) {
1196 this.addClass(this.ACTIVE_CLASSNAME);
1197 this.set('title', 'active');
1198 } else {
1199 this.removeClass(this.ACTIVE_CLASSNAME);
1200 this.set('title', '');
1201 }
1202 },
1203 validator: function(value) {
1204 return Lang.isBoolean(value) && !this.get('disabled') ;
1205 }
1206 });
1207
1208 /**
1209 * Whether or not the tab is disabled.
1210 * @config disabled
1211 * @type Boolean
1212 */
1213 this.register('disabled', {
1214 value: attr.disabled || this.hasClass(this.DISABLED_CLASSNAME),
1215 method: function(value) {
1216 if (value === true) {
1217 Dom.addClass(this.get('element'), this.DISABLED_CLASSNAME);
1218 } else {
1219 Dom.removeClass(this.get('element'), this.DISABLED_CLASSNAME);
1220 }
1221 },
1222 validator: Lang.isBoolean
1223 });
1224
1225 /**
1226 * The href of the tab's anchor element.
1227 * @config href
1228 * @type String
1229 * @default '#'
1230 */
1231 this.register('href', {
1232 value: attr.href || '#',
1233 method: function(value) {
1234 this.getElementsByTagName('a')[0].href = value;
1235 },
1236 validator: Lang.isString
1237 });
1238
1239 /**
1240 * The Whether or not the tab's content is visible.
1241 * @config contentVisible
1242 * @type Boolean
1243 * @default false
1244 */
1245 this.register('contentVisible', {
1246 value: attr.contentVisible,
1247 method: function(value) {
1248 if (value == true) {
1249 this.get('contentEl').style.display = 'block';
1250
1251 if ( this.get('dataSrc') ) {
1252 // load dynamic content unless already loaded and caching
1253 if ( !this.get('dataLoaded') || !this.get('cacheData') ) {
1254 _dataConnect.call(this);
1255 }
1256 }
1257 } else {
1258 this.get('contentEl').style.display = 'none';
1259 }
1260 },
1261 validator: Lang.isBoolean
1262 });
1263 };
1264
1265 var _createTabElement = function(attr) {
1266 var el = document.createElement('li');
1267 var a = document.createElement('a');
1268
1269 a.href = attr.href || '#';
1270
1271 el.appendChild(a);
1272
1273 var label = attr.label || null;
1274 var labelEl = attr.labelEl || null;
1275
1276 if (labelEl) { // user supplied labelEl
1277 if (!label) { // user supplied label
1278 label = _getLabel.call(this, labelEl);
1279 }
1280 } else {
1281 labelEl = _createlabelEl.call(this);
1282 }
1283
1284 a.appendChild(labelEl);
1285
1286 return el;
1287 };
1288
1289 var _getlabelEl = function() {
1290 return this.getElementsByTagName(this.LABEL_TAGNAME)[0];
1291 };
1292
1293 var _createlabelEl = function() {
1294 var el = document.createElement(this.LABEL_TAGNAME);
1295 return el;
1296 };
1297
1298 var _setLabel = function(label) {
1299 var el = this.get('labelEl');
1300 el.innerHTML = label;
1301 };
1302
1303 var _getLabel = function() {
1304 var label,
1305 el = this.get('labelEl');
1306
1307 if (!el) {
1308 return undefined;
1309 }
1310
1311 return el.innerHTML;
1312 };
1313
1314 var _dataConnect = function() {
1315 if (!YAHOO.util.Connect) {
1316 YAHOO.log('YAHOO.util.Connect dependency not met',
1317 'error', 'Tab');
1318 return false;
1319 }
1320
1321 Dom.addClass(this.get('contentEl').parentNode, this.LOADING_CLASSNAME);
1322
1323 this.dataConnection = YAHOO.util.Connect.asyncRequest(
1324 this.get('loadMethod'),
1325 this.get('dataSrc'),
1326 {
1327 success: function(o) {
1328 this.loadHandler.success.call(this, o);
1329 this.set('dataLoaded', true);
1330 this.dataConnection = null;
1331 Dom.removeClass(this.get('contentEl').parentNode,
1332 this.LOADING_CLASSNAME);
1333 },
1334 failure: function(o) {
1335 this.loadHandler.failure.call(this, o);
1336 this.dataConnection = null;
1337 Dom.removeClass(this.get('contentEl').parentNode,
1338 this.LOADING_CLASSNAME);
1339 },
1340 scope: this,
1341 timeout: this.get('dataTimeout')
1342 }
1343 );
1344 };
1345
1346 YAHOO.widget.Tab = Tab;
1347
1348 /**
1349 * Fires before the active state is changed.
1350 * <p>See: <a href="YAHOO.util.Element.html#addListener">Element.addListener</a></p>
1351 * <p>If handler returns false, the change will be cancelled, and the value will not
1352 * be set.</p>
1353 * <p><strong>Event fields:</strong><br>
1354 * <code>&lt;String&gt; type</code> beforeActiveChange<br>
1355 * <code>&lt;Boolean&gt;
1356 * prevValue</code> the current value<br>
1357 * <code>&lt;Boolean&gt;
1358 * newValue</code> the new value</p>
1359 * <p><strong>Usage:</strong><br>
1360 * <code>var handler = function(e) {var previous = e.prevValue};<br>
1361 * myTabs.addListener('beforeActiveChange', handler);</code></p>
1362 * @event beforeActiveChange
1363 */
1364
1365 /**
1366 * Fires after the active state is changed.
1367 * <p>See: <a href="YAHOO.util.Element.html#addListener">Element.addListener</a></p>
1368 * <p><strong>Event fields:</strong><br>
1369 * <code>&lt;String&gt; type</code> activeChange<br>
1370 * <code>&lt;Boolean&gt;
1371 * prevValue</code> the previous value<br>
1372 * <code>&lt;Boolean&gt;
1373 * newValue</code> the updated value</p>
1374 * <p><strong>Usage:</strong><br>
1375 * <code>var handler = function(e) {var previous = e.prevValue};<br>
1376 * myTabs.addListener('activeChange', handler);</code></p>
1377 * @event activeChange
1378 */
1379
1380 /**
1381 * Fires before the tab label is changed.
1382 * <p>See: <a href="YAHOO.util.Element.html#addListener">Element.addListener</a></p>
1383 * <p>If handler returns false, the change will be cancelled, and the value will not
1384 * be set.</p>
1385 * <p><strong>Event fields:</strong><br>
1386 * <code>&lt;String&gt; type</code> beforeLabelChange<br>
1387 * <code>&lt;String&gt;
1388 * prevValue</code> the current value<br>
1389 * <code>&lt;String&gt;
1390 * newValue</code> the new value</p>
1391 * <p><strong>Usage:</strong><br>
1392 * <code>var handler = function(e) {var previous = e.prevValue};<br>
1393 * myTabs.addListener('beforeLabelChange', handler);</code></p>
1394 * @event beforeLabelChange
1395 */
1396
1397 /**
1398 * Fires after the tab label is changed.
1399 * <p>See: <a href="YAHOO.util.Element.html#addListener">Element.addListener</a></p>
1400 * <p><strong>Event fields:</strong><br>
1401 * <code>&lt;String&gt; type</code> labelChange<br>
1402 * <code>&lt;String&gt;
1403 * prevValue</code> the previous value<br>
1404 * <code>&lt;String&gt;
1405 * newValue</code> the updated value</p>
1406 * <p><strong>Usage:</strong><br>
1407 * <code>var handler = function(e) {var previous = e.prevValue};<br>
1408 * myTabs.addListener('labelChange', handler);</code></p>
1409 * @event labelChange
1410 */
1411
1412 /**
1413 * Fires before the tab content is changed.
1414 * <p>See: <a href="YAHOO.util.Element.html#addListener">Element.addListener</a></p>
1415 * <p>If handler returns false, the change will be cancelled, and the value will not
1416 * be set.</p>
1417 * <p><strong>Event fields:</strong><br>
1418 * <code>&lt;String&gt; type</code> beforeContentChange<br>
1419 * <code>&lt;String&gt;
1420 * prevValue</code> the current value<br>
1421 * <code>&lt;String&gt;
1422 * newValue</code> the new value</p>
1423 * <p><strong>Usage:</strong><br>
1424 * <code>var handler = function(e) {var previous = e.prevValue};<br>
1425 * myTabs.addListener('beforeContentChange', handler);</code></p>
1426 * @event beforeContentChange
1427 */
1428
1429 /**
1430 * Fires after the tab content is changed.
1431 * <p>See: <a href="YAHOO.util.Element.html#addListener">Element.addListener</a></p>
1432 * <p><strong>Event fields:</strong><br>
1433 * <code>&lt;String&gt; type</code> contentChange<br>
1434 * <code>&lt;String&gt;
1435 * prevValue</code> the previous value<br>
1436 * <code>&lt;Boolean&gt;
1437 * newValue</code> the updated value</p>
1438 * <p><strong>Usage:</strong><br>
1439 * <code>var handler = function(e) {var previous = e.prevValue};<br>
1440 * myTabs.addListener('contentChange', handler);</code></p>
1441 * @event contentChange
1442 */
1443})();(function() {
1444
1445 /**
1446 * The tabview module provides a widget for managing content bound to tabs.
1447 * @module tabview
1448 *
1449 */
1450 /**
1451 * A widget to control tabbed views.
1452 * @namespace YAHOO.widget
1453 * @class TabView
1454 * @extends YAHOO.util.Element
1455 * @constructor
1456 * @param {HTMLElement | String | Object} el(optional) The html
1457 * element that represents the TabView, or the attribute object to use.
1458 * An element will be created if none provided.
1459 * @param {Object} attr (optional) A key map of the tabView's
1460 * initial attributes. Ignored if first arg is attributes object.
1461 */
1462 YAHOO.widget.TabView = function(el, attr) {
1463 attr = attr || {};
1464 if (arguments.length == 1 && !Lang.isString(el) && !el.nodeName) {
1465 attr = el; // treat first arg as attr object
1466 el = attr.element || null;
1467 }
1468
1469 if (!el && !attr.element) { // create if we dont have one
1470 el = _createTabViewElement.call(this, attr);
1471 }
1472 YAHOO.widget.TabView.superclass.constructor.call(this, el, attr);
1473 };
1474
1475 YAHOO.extend(YAHOO.widget.TabView, YAHOO.util.Element);
1476
1477 var proto = YAHOO.widget.TabView.prototype;
1478 var Dom = YAHOO.util.Dom;
1479 var Lang = YAHOO.util.Lang;
1480 var Event = YAHOO.util.Event;
1481 var Tab = YAHOO.widget.Tab;
1482
1483
1484 /**
1485 * The className to add when building from scratch.
1486 * @property CLASSNAME
1487 * @default "navset"
1488 */
1489 proto.CLASSNAME = 'yui-navset';
1490
1491 /**
1492 * The className of the HTMLElement containing the TabView's tab elements
1493 * to look for when building from existing markup, or to add when building
1494 * from scratch.
1495 * All childNodes of the tab container are treated as Tabs when building
1496 * from existing markup.
1497 * @property TAB_PARENT_CLASSNAME
1498 * @default "nav"
1499 */
1500 proto.TAB_PARENT_CLASSNAME = 'yui-nav';
1501
1502 /**
1503 * The className of the HTMLElement containing the TabView's label elements
1504 * to look for when building from existing markup, or to add when building
1505 * from scratch.
1506 * All childNodes of the content container are treated as content elements when
1507 * building from existing markup.
1508 * @property CONTENT_PARENT_CLASSNAME
1509 * @default "nav-content"
1510 */
1511 proto.CONTENT_PARENT_CLASSNAME = 'yui-content';
1512
1513 proto._tabParent = null;
1514 proto._contentParent = null;
1515
1516 /**
1517 * Adds a Tab to the TabView instance.
1518 * If no index is specified, the tab is added to the end of the tab list.
1519 * @method addTab
1520 * @param {YAHOO.widget.Tab} tab A Tab instance to add.
1521 * @param {Integer} index The position to add the tab.
1522 * @return void
1523 */
1524 proto.addTab = function(tab, index) {
1525 var tabs = this.get('tabs');
1526 if (!tabs) { // not ready yet
1527 this._queue[this._queue.length] = ['addTab', arguments];
1528 return false;
1529 }
1530
1531 index = (index === undefined) ? tabs.length : index;
1532
1533 var before = this.getTab(index);
1534
1535 var self = this;
1536 var el = this.get('element');
1537 var tabParent = this._tabParent;
1538 var contentParent = this._contentParent;
1539
1540 var tabElement = tab.get('element');
1541 var contentEl = tab.get('contentEl');
1542
1543 if ( before ) {
1544 tabParent.insertBefore(tabElement, before.get('element'));
1545 } else {
1546 tabParent.appendChild(tabElement);
1547 }
1548
1549 if ( contentEl && !Dom.isAncestor(contentParent, contentEl) ) {
1550 contentParent.appendChild(contentEl);
1551 }
1552
1553 if ( !tab.get('active') ) {
1554 tab.set('contentVisible', false, true); /* hide if not active */
1555 } else {
1556 this.set('activeTab', tab, true);
1557
1558 }
1559
1560 var activate = function(e) {
1561 YAHOO.util.Event.preventDefault(e);
1562 self.set('activeTab', this);
1563 };
1564
1565 tab.addListener( tab.get('activationEvent'), activate);
1566
1567 tab.addListener('activationEventChange', function(e) {
1568 if (e.prevValue != e.newValue) {
1569 tab.removeListener(e.prevValue, activate);
1570 tab.addListener(e.newValue, activate);
1571 }
1572 });
1573
1574 tabs.splice(index, 0, tab);
1575 };
1576
1577 /**
1578 * Routes childNode events.
1579 * @method DOMEventHandler
1580 * @param {event} e The Dom event that is being handled.
1581 * @return void
1582 */
1583 proto.DOMEventHandler = function(e) {
1584 var el = this.get('element');
1585 var target = YAHOO.util.Event.getTarget(e);
1586 var tabParent = this._tabParent;
1587
1588 if (Dom.isAncestor(tabParent, target) ) {
1589 var tabEl;
1590 var tab = null;
1591 var contentEl;
1592 var tabs = this.get('tabs');
1593
1594 for (var i = 0, len = tabs.length; i < len; i++) {
1595 tabEl = tabs[i].get('element');
1596 contentEl = tabs[i].get('contentEl');
1597
1598 if ( target == tabEl || Dom.isAncestor(tabEl, target) ) {
1599 tab = tabs[i];
1600 break; // note break
1601 }
1602 }
1603
1604 if (tab) {
1605 tab.fireEvent(e.type, e);
1606 }
1607 }
1608 };
1609
1610 /**
1611 * Returns the Tab instance at the specified index.
1612 * @method getTab
1613 * @param {Integer} index The position of the Tab.
1614 * @return YAHOO.widget.Tab
1615 */
1616 proto.getTab = function(index) {
1617 return this.get('tabs')[index];
1618 };
1619
1620 /**
1621 * Returns the index of given tab.
1622 * @method getTabIndex
1623 * @param {YAHOO.widget.Tab} tab The tab whose index will be returned.
1624 * @return int
1625 */
1626 proto.getTabIndex = function(tab) {
1627 var index = null;
1628 var tabs = this.get('tabs');
1629 for (var i = 0, len = tabs.length; i < len; ++i) {
1630 if (tab == tabs[i]) {
1631 index = i;
1632 break;
1633 }
1634 }
1635
1636 return index;
1637 };
1638
1639 /**
1640 * Removes the specified Tab from the TabView.
1641 * @method removeTab
1642 * @param {YAHOO.widget.Tab} item The Tab instance to be removed.
1643 * @return void
1644 */
1645 proto.removeTab = function(tab) {
1646 var tabCount = this.get('tabs').length;
1647
1648 var index = this.getTabIndex(tab);
1649 var nextIndex = index + 1;
1650 if ( tab == this.get('activeTab') ) { // select next tab
1651 if (tabCount > 1) {
1652 if (index + 1 == tabCount) {
1653 this.set('activeIndex', index - 1);
1654 } else {
1655 this.set('activeIndex', index + 1);
1656 }
1657 }
1658 }
1659
1660 this._tabParent.removeChild( tab.get('element') );
1661 this._contentParent.removeChild( tab.get('contentEl') );
1662 this._configs.tabs.value.splice(index, 1);
1663
1664 };
1665
1666 /**
1667 * Provides a readable name for the TabView instance.
1668 * @method toString
1669 * @return String
1670 */
1671 proto.toString = function() {
1672 var name = this.get('id') || this.get('tagName');
1673 return "TabView " + name;
1674 };
1675
1676 /**
1677 * The transiton to use when switching between tabs.
1678 * @method contentTransition
1679 */
1680 proto.contentTransition = function(newTab, oldTab) {
1681 newTab.set('contentVisible', true);
1682 oldTab.set('contentVisible', false);
1683 };
1684
1685 /**
1686 * Registers TabView specific properties.
1687 * @method initAttributes
1688 * @param {Object} attr Hash of initial attributes
1689 */
1690 proto.initAttributes = function(attr) {
1691 YAHOO.widget.TabView.superclass.initAttributes.call(this, attr);
1692
1693 if (!attr.orientation) {
1694 attr.orientation = 'top';
1695 }
1696
1697 var el = this.get('element');
1698
1699 /**
1700 * The Tabs belonging to the TabView instance.
1701 * @config tabs
1702 * @type Array
1703 */
1704 this.register('tabs', {
1705 value: [],
1706 readOnly: true
1707 });
1708
1709 /**
1710 * The container of the tabView's label elements.
1711 * @property _tabParent
1712 * @private
1713 * @type HTMLElement
1714 */
1715 this._tabParent =
1716 this.getElementsByClassName(this.TAB_PARENT_CLASSNAME,
1717 'ul' )[0] || _createTabParent.call(this);
1718
1719 /**
1720 * The container of the tabView's content elements.
1721 * @property _contentParent
1722 * @type HTMLElement
1723 * @private
1724 */
1725 this._contentParent =
1726 this.getElementsByClassName(this.CONTENT_PARENT_CLASSNAME,
1727 'div')[0] || _createContentParent.call(this);
1728
1729 /**
1730 * How the Tabs should be oriented relative to the TabView.
1731 * @config orientation
1732 * @type String
1733 * @default "top"
1734 */
1735 this.register('orientation', {
1736 value: attr.orientation,
1737 method: function(value) {
1738 var current = this.get('orientation');
1739 this.addClass('yui-navset-' + value);
1740
1741 if (current != value) {
1742 this.removeClass('yui-navset-' + current);
1743 }
1744
1745 switch(value) {
1746 case 'bottom':
1747 this.appendChild(this._tabParent);
1748 break;
1749 }
1750 }
1751 });
1752
1753 /**
1754 * The index of the tab currently active.
1755 * @config activeIndex
1756 * @type Int
1757 */
1758 this.register('activeIndex', {
1759 value: attr.activeIndex,
1760 method: function(value) {
1761 this.set('activeTab', this.getTab(value));
1762 },
1763 validator: function(value) {
1764 return !this.getTab(value).get('disabled'); // cannot activate if disabled
1765 }
1766 });
1767
1768 /**
1769 * The tab currently active.
1770 * @config activeTab
1771 * @type YAHOO.widget.Tab
1772 */
1773 this.register('activeTab', {
1774 value: attr.activeTab,
1775 method: function(tab) {
1776 var activeTab = this.get('activeTab');
1777
1778 if (tab) {
1779 tab.set('active', true);
1780 }
1781
1782 if (activeTab && activeTab != tab) {
1783 activeTab.set('active', false);
1784 }
1785
1786 if (activeTab && tab != activeTab) { // no transition if only 1
1787 this.contentTransition(tab, activeTab);
1788 } else if (tab) {
1789 tab.set('contentVisible', true);
1790 }
1791 },
1792 validator: function(value) {
1793 return !value.get('disabled'); // cannot activate if disabled
1794 }
1795 });
1796
1797 if ( this._tabParent ) {
1798 _initTabs.call(this);
1799 }
1800
1801 for (var type in this.DOM_EVENTS) {
1802 if ( this.DOM_EVENTS.hasOwnProperty(type) ) {
1803 this.addListener.call(this, type, this.DOMEventHandler);
1804 }
1805 }
1806 };
1807
1808 /**
1809 * Creates Tab instances from a collection of HTMLElements.
1810 * @method createTabs
1811 * @private
1812 * @param {Array|HTMLCollection} elements The elements to use for Tabs.
1813 * @return void
1814 */
1815 var _initTabs = function() {
1816 var tab,
1817 attr,
1818 contentEl;
1819
1820 var el = this.get('element');
1821 var tabs = _getChildNodes(this._tabParent);
1822 var contentElements = _getChildNodes(this._contentParent);
1823
1824 for (var i = 0, len = tabs.length; i < len; ++i) {
1825 attr = {};
1826
1827 if (contentElements[i]) {
1828 attr.contentEl = contentElements[i];
1829 }
1830
1831 tab = new YAHOO.widget.Tab(tabs[i], attr);
1832 this.addTab(tab);
1833
1834 if (tab.hasClass(tab.ACTIVE_CLASSNAME) ) {
1835 this._configs.activeTab.value = tab; // dont invoke method
1836 }
1837 }
1838 };
1839
1840 var _createTabViewElement = function(attr) {
1841 var el = document.createElement('div');
1842
1843 if ( this.CLASSNAME ) {
1844 el.className = this.CLASSNAME;
1845 }
1846
1847 return el;
1848 };
1849
1850 var _createTabParent = function(attr) {
1851 var el = document.createElement('ul');
1852
1853 if ( this.TAB_PARENT_CLASSNAME ) {
1854 el.className = this.TAB_PARENT_CLASSNAME;
1855 }
1856
1857 this.get('element').appendChild(el);
1858
1859 return el;
1860 };
1861
1862 var _createContentParent = function(attr) {
1863 var el = document.createElement('div');
1864
1865 if ( this.CONTENT_PARENT_CLASSNAME ) {
1866 el.className = this.CONTENT_PARENT_CLASSNAME;
1867 }
1868
1869 this.get('element').appendChild(el);
1870
1871 return el;
1872 };
1873
1874 var _getChildNodes = function(el) {
1875 var nodes = [];
1876 var childNodes = el.childNodes;
1877
1878 for (var i = 0, len = childNodes.length; i < len; ++i) {
1879 if (childNodes[i].nodeType == 1) {
1880 nodes[nodes.length] = childNodes[i];
1881 }
1882 }
1883
1884 return nodes;
1885 };
1886
1887/**
1888 * Fires before the activeTab is changed.
1889 * <p>See: <a href="YAHOO.util.Element.html#addListener">Element.addListener</a></p>
1890 * <p>If handler returns false, the change will be cancelled, and the value will not
1891 * be set.</p>
1892 * <p><strong>Event fields:</strong><br>
1893 * <code>&lt;String&gt; type</code> beforeActiveTabChange<br>
1894 * <code>&lt;<a href="YAHOO.widget.Tab.html">YAHOO.widget.Tab</a>&gt;
1895 * prevValue</code> the currently active tab<br>
1896 * <code>&lt;<a href="YAHOO.widget.Tab.html">YAHOO.widget.Tab</a>&gt;
1897 * newValue</code> the tab to be made active</p>
1898 * <p><strong>Usage:</strong><br>
1899 * <code>var handler = function(e) {var previous = e.prevValue};<br>
1900 * myTabs.addListener('beforeActiveTabChange', handler);</code></p>
1901 * @event beforeActiveTabChange
1902 */
1903
1904/**
1905 * Fires after the activeTab is changed.
1906 * <p>See: <a href="YAHOO.util.Element.html#addListener">Element.addListener</a></p>
1907 * <p><strong>Event fields:</strong><br>
1908 * <code>&lt;String&gt; type</code> activeTabChange<br>
1909 * <code>&lt;<a href="YAHOO.widget.Tab.html">YAHOO.widget.Tab</a>&gt;
1910 * prevValue</code> the formerly active tab<br>
1911 * <code>&lt;<a href="YAHOO.widget.Tab.html">YAHOO.widget.Tab</a>&gt;
1912 * newValue</code> the new active tab</p>
1913 * <p><strong>Usage:</strong><br>
1914 * <code>var handler = function(e) {var previous = e.prevValue};<br>
1915 * myTabs.addListener('activeTabChange', handler);</code></p>
1916 * @event activeTabChange
1917 */
1918
1919/**
1920 * Fires before the orientation is changed.
1921 * <p>See: <a href="YAHOO.util.Element.html#addListener">Element.addListener</a></p>
1922 * <p>If handler returns false, the change will be cancelled, and the value will not
1923 * be set.</p>
1924 * <p><strong>Event fields:</strong><br>
1925 * <code>&lt;String&gt; type</code> beforeOrientationChange<br>
1926 * <code>&lt;String&gt;
1927 * prevValue</code> the current orientation<br>
1928 * <code>&lt;String&gt;
1929 * newValue</code> the new orientation to be applied</p>
1930 * <p><strong>Usage:</strong><br>
1931 * <code>var handler = function(e) {var previous = e.prevValue};<br>
1932 * myTabs.addListener('beforeOrientationChange', handler);</code></p>
1933 * @event beforeOrientationChange
1934 */
1935
1936/**
1937 * Fires after the orientation is changed.
1938 * <p>See: <a href="YAHOO.util.Element.html#addListener">Element.addListener</a></p>
1939 * <p><strong>Event fields:</strong><br>
1940 * <code>&lt;String&gt; type</code> orientationChange<br>
1941 * <code>&lt;String&gt;
1942 * prevValue</code> the former orientation<br>
1943 * <code>&lt;String&gt;
1944 * newValue</code> the new orientation</p>
1945 * <p><strong>Usage:</strong><br>
1946 * <code>var handler = function(e) {var previous = e.prevValue};<br>
1947 * myTabs.addListener('orientationChange', handler);</code></p>
1948 * @event orientationChange
1949 */
1950})(); \ No newline at end of file
diff --git a/frontend/beta/js/YUI/treeview.js b/frontend/beta/js/YUI/treeview.js
new file mode 100644
index 0000000..ea6b6ef
--- a/dev/null
+++ b/frontend/beta/js/YUI/treeview.js
@@ -0,0 +1,2182 @@
1/*
2Copyright (c) 2006, Yahoo! Inc. All rights reserved.
3Code licensed under the BSD License:
4http://developer.yahoo.net/yui/license.txt
5version: 0.12.0
6*/
7
8/**
9 * The treeview widget is a generic tree building tool.
10 * @module treeview
11 * @title TreeView Widget
12 * @requires yahoo
13 * @optional animation
14 * @namespace YAHOO.widget
15 */
16
17/**
18 * Contains the tree view state data and the root node.
19 *
20 * @class TreeView
21 * @constructor
22 * @param {string|HTMLElement} id The id of the element, or the element
23 * itself that the tree will be inserted into.
24 */
25YAHOO.widget.TreeView = function(id) {
26 if (id) { this.init(id); }
27};
28
29YAHOO.widget.TreeView.prototype = {
30
31 /**
32 * The id of tree container element
33 * @property id
34 * @type String
35 */
36 id: null,
37
38 /**
39 * The host element for this tree
40 * @property _el
41 * @private
42 */
43 _el: null,
44
45 /**
46 * Flat collection of all nodes in this tree
47 * @property _nodes
48 * @type Node[]
49 * @private
50 */
51 _nodes: null,
52
53 /**
54 * We lock the tree control while waiting for the dynamic loader to return
55 * @property locked
56 * @type boolean
57 */
58 locked: false,
59
60 /**
61 * The animation to use for expanding children, if any
62 * @property _expandAnim
63 * @type string
64 * @private
65 */
66 _expandAnim: null,
67
68 /**
69 * The animation to use for collapsing children, if any
70 * @property _collapseAnim
71 * @type string
72 * @private
73 */
74 _collapseAnim: null,
75
76 /**
77 * The current number of animations that are executing
78 * @property _animCount
79 * @type int
80 * @private
81 */
82 _animCount: 0,
83
84 /**
85 * The maximum number of animations to run at one time.
86 * @property maxAnim
87 * @type int
88 */
89 maxAnim: 2,
90
91 /**
92 * Sets up the animation for expanding children
93 * @method setExpandAnim
94 * @param {string} type the type of animation (acceptable values defined
95 * in YAHOO.widget.TVAnim)
96 */
97 setExpandAnim: function(type) {
98 if (YAHOO.widget.TVAnim.isValid(type)) {
99 this._expandAnim = type;
100 }
101 },
102
103 /**
104 * Sets up the animation for collapsing children
105 * @method setCollapseAnim
106 * @param {string} the type of animation (acceptable values defined in
107 * YAHOO.widget.TVAnim)
108 */
109 setCollapseAnim: function(type) {
110 if (YAHOO.widget.TVAnim.isValid(type)) {
111 this._collapseAnim = type;
112 }
113 },
114
115 /**
116 * Perform the expand animation if configured, or just show the
117 * element if not configured or too many animations are in progress
118 * @method animateExpand
119 * @param el {HTMLElement} the element to animate
120 * @param node {YAHOO.util.Node} the node that was expanded
121 * @return {boolean} true if animation could be invoked, false otherwise
122 */
123 animateExpand: function(el, node) {
124
125 if (this._expandAnim && this._animCount < this.maxAnim) {
126 // this.locked = true;
127 var tree = this;
128 var a = YAHOO.widget.TVAnim.getAnim(this._expandAnim, el,
129 function() { tree.expandComplete(node); });
130 if (a) {
131 ++this._animCount;
132 this.fireEvent("animStart", {
133 "node": node,
134 "type": "expand"
135 });
136 a.animate();
137 }
138
139 return true;
140 }
141
142 return false;
143 },
144
145 /**
146 * Perform the collapse animation if configured, or just show the
147 * element if not configured or too many animations are in progress
148 * @method animateCollapse
149 * @param el {HTMLElement} the element to animate
150 * @param node {YAHOO.util.Node} the node that was expanded
151 * @return {boolean} true if animation could be invoked, false otherwise
152 */
153 animateCollapse: function(el, node) {
154
155 if (this._collapseAnim && this._animCount < this.maxAnim) {
156 // this.locked = true;
157 var tree = this;
158 var a = YAHOO.widget.TVAnim.getAnim(this._collapseAnim, el,
159 function() { tree.collapseComplete(node); });
160 if (a) {
161 ++this._animCount;
162 this.fireEvent("animStart", {
163 "node": node,
164 "type": "collapse"
165 });
166 a.animate();
167 }
168
169 return true;
170 }
171
172 return false;
173 },
174
175 /**
176 * Function executed when the expand animation completes
177 * @method expandComplete
178 */
179 expandComplete: function(node) {
180 --this._animCount;
181 this.fireEvent("animComplete", {
182 "node": node,
183 "type": "expand"
184 });
185 // this.locked = false;
186 },
187
188 /**
189 * Function executed when the collapse animation completes
190 * @method collapseComplete
191 */
192 collapseComplete: function(node) {
193 --this._animCount;
194 this.fireEvent("animComplete", {
195 "node": node,
196 "type": "collapse"
197 });
198 // this.locked = false;
199 },
200
201 /**
202 * Initializes the tree
203 * @method init
204 * @parm {string|HTMLElement} id the id of the element that will hold the tree
205 * @private
206 */
207 init: function(id) {
208
209 this.id = id;
210
211 if ("string" !== typeof id) {
212 this._el = id;
213 this.id = this.generateId(id);
214 }
215
216 /**
217 * When animation is enabled, this event fires when the animation
218 * starts
219 * @event animStart
220 * @type CustomEvent
221 * @param {YAHOO.widget.Node} node the node that is expanding/collapsing
222 * @parm {String} type the type of animation ("expand" or "collapse")
223 */
224 this.createEvent("animStart", this);
225
226 /**
227 * When animation is enabled, this event fires when the animation
228 * completes
229 * @event animComplete
230 * @type CustomEvent
231 * @param {YAHOO.widget.Node} node the node that is expanding/collapsing
232 * @parm {String} type the type of animation ("expand" or "collapse")
233 */
234 this.createEvent("animComplete", this);
235
236 /**
237 * Fires when a node is going to be expanded. Return false to stop
238 * the expand.
239 * @event collapse
240 * @type CustomEvent
241 * @param {YAHOO.widget.Node} node the node that is expanding/collapsing
242 */
243 this.createEvent("collapse", this);
244
245 /**
246 * Fires when a node is going to be collapsed. Return false to stop
247 * the collapse.
248 * @event expand
249 * @type CustomEvent
250 * @param {YAHOO.widget.Node} node the node that is expanding/collapsing
251 */
252 this.createEvent("expand", this);
253
254 this._nodes = [];
255
256 // store a global reference
257 YAHOO.widget.TreeView.trees[this.id] = this;
258
259 // Set up the root node
260 this.root = new YAHOO.widget.RootNode(this);
261
262
263 },
264
265 /**
266 * Renders the tree boilerplate and visible nodes
267 * @method draw
268 */
269 draw: function() {
270 var html = this.root.getHtml();
271 this.getEl().innerHTML = html;
272 this.firstDraw = false;
273 },
274
275 /**
276 * Returns the tree's host element
277 * @method getEl
278 * @return {HTMLElement} the host element
279 */
280 getEl: function() {
281 if (! this._el) {
282 this._el = document.getElementById(this.id);
283 }
284 return this._el;
285 },
286
287 /**
288 * Nodes register themselves with the tree instance when they are created.
289 * @method regNode
290 * @param node {Node} the node to register
291 * @private
292 */
293 regNode: function(node) {
294 this._nodes[node.index] = node;
295 },
296
297 /**
298 * Returns the root node of this tree
299 * @method getRoot
300 * @return {Node} the root node
301 */
302 getRoot: function() {
303 return this.root;
304 },
305
306 /**
307 * Configures this tree to dynamically load all child data
308 * @method setDynamicLoad
309 * @param {function} fnDataLoader the function that will be called to get the data
310 * @param iconMode {int} configures the icon that is displayed when a dynamic
311 * load node is expanded the first time without children. By default, the
312 * "collapse" icon will be used. If set to 1, the leaf node icon will be
313 * displayed.
314 */
315 setDynamicLoad: function(fnDataLoader, iconMode) {
316 this.root.setDynamicLoad(fnDataLoader, iconMode);
317 },
318
319 /**
320 * Expands all child nodes. Note: this conflicts with the "multiExpand"
321 * node property. If expand all is called in a tree with nodes that
322 * do not allow multiple siblings to be displayed, only the last sibling
323 * will be expanded.
324 * @method expandAll
325 */
326 expandAll: function() {
327 if (!this.locked) {
328 this.root.expandAll();
329 }
330 },
331
332 /**
333 * Collapses all expanded child nodes in the entire tree.
334 * @method collapseAll
335 */
336 collapseAll: function() {
337 if (!this.locked) {
338 this.root.collapseAll();
339 }
340 },
341
342 /**
343 * Returns a node in the tree that has the specified index (this index
344 * is created internally, so this function probably will only be used
345 * in html generated for a given node.)
346 * @method getNodeByIndex
347 * @param {int} nodeIndex the index of the node wanted
348 * @return {Node} the node with index=nodeIndex, null if no match
349 */
350 getNodeByIndex: function(nodeIndex) {
351 var n = this._nodes[nodeIndex];
352 return (n) ? n : null;
353 },
354
355 /**
356 * Returns a node that has a matching property and value in the data
357 * object that was passed into its constructor.
358 * @method getNodeByProperty
359 * @param {object} property the property to search (usually a string)
360 * @param {object} value the value we want to find (usuall an int or string)
361 * @return {Node} the matching node, null if no match
362 */
363 getNodeByProperty: function(property, value) {
364 for (var i in this._nodes) {
365 var n = this._nodes[i];
366 if (n.data && value == n.data[property]) {
367 return n;
368 }
369 }
370
371 return null;
372 },
373
374 /**
375 * Returns a collection of nodes that have a matching property
376 * and value in the data object that was passed into its constructor.
377 * @method getNodesByProperty
378 * @param {object} property the property to search (usually a string)
379 * @param {object} value the value we want to find (usuall an int or string)
380 * @return {Array} the matching collection of nodes, null if no match
381 */
382 getNodesByProperty: function(property, value) {
383 var values = [];
384 for (var i in this._nodes) {
385 var n = this._nodes[i];
386 if (n.data && value == n.data[property]) {
387 values.push(n);
388 }
389 }
390
391 return (values.length) ? values : null;
392 },
393
394 /**
395 * Removes the node and its children, and optionally refreshes the
396 * branch of the tree that was affected.
397 * @method removeNode
398 * @param {Node} The node to remove
399 * @param {boolean} autoRefresh automatically refreshes branch if true
400 * @return {boolean} False is there was a problem, true otherwise.
401 */
402 removeNode: function(node, autoRefresh) {
403
404 // Don't delete the root node
405 if (node.isRoot()) {
406 return false;
407 }
408
409 // Get the branch that we may need to refresh
410 var p = node.parent;
411 if (p.parent) {
412 p = p.parent;
413 }
414
415 // Delete the node and its children
416 this._deleteNode(node);
417
418 // Refresh the parent of the parent
419 if (autoRefresh && p && p.childrenRendered) {
420 p.refresh();
421 }
422
423 return true;
424 },
425
426 /**
427 * Deletes this nodes child collection, recursively. Also collapses
428 * the node, and resets the dynamic load flag. The primary use for
429 * this method is to purge a node and allow it to fetch its data
430 * dynamically again.
431 * @method removeChildren
432 * @param {Node} node the node to purge
433 */
434 removeChildren: function(node) {
435 while (node.children.length) {
436 this._deleteNode(node.children[0]);
437 }
438
439 node.childrenRendered = false;
440 node.dynamicLoadComplete = false;
441 if (node.expanded) {
442 node.collapse();
443 } else {
444 node.updateIcon();
445 }
446 },
447
448 /**
449 * Deletes the node and recurses children
450 * @method _deleteNode
451 * @private
452 */
453 _deleteNode: function(node) {
454 // Remove all the child nodes first
455 this.removeChildren(node);
456
457 // Remove the node from the tree
458 this.popNode(node);
459 },
460
461 /**
462 * Removes the node from the tree, preserving the child collection
463 * to make it possible to insert the branch into another part of the
464 * tree, or another tree.
465 * @method popNode
466 * @param {Node} the node to remove
467 */
468 popNode: function(node) {
469 var p = node.parent;
470
471 // Update the parent's collection of children
472 var a = [];
473
474 for (var i=0, len=p.children.length;i<len;++i) {
475 if (p.children[i] != node) {
476 a[a.length] = p.children[i];
477 }
478 }
479
480 p.children = a;
481
482 // reset the childrenRendered flag for the parent
483 p.childrenRendered = false;
484
485 // Update the sibling relationship
486 if (node.previousSibling) {
487 node.previousSibling.nextSibling = node.nextSibling;
488 }
489
490 if (node.nextSibling) {
491 node.nextSibling.previousSibling = node.previousSibling;
492 }
493
494 node.parent = null;
495 node.previousSibling = null;
496 node.nextSibling = null;
497 node.tree = null;
498
499 // Update the tree's node collection
500 delete this._nodes[node.index];
501 },
502
503 /**
504 * TreeView instance toString
505 * @method toString
506 * @return {string} string representation of the tree
507 */
508 toString: function() {
509 return "TreeView " + this.id;
510 },
511
512 /**
513 * Generates an unique id for an element if it doesn't yet have one
514 * @method generateId
515 * @private
516 */
517 generateId: function(el) {
518 var id = el.id;
519
520 if (!id) {
521 id = "yui-tv-auto-id-" + YAHOO.widget.TreeView.counter;
522 ++YAHOO.widget.TreeView.counter;
523 }
524
525 return id;
526 },
527
528 /**
529 * Abstract method that is executed when a node is expanded
530 * @method onExpand
531 * @param node {Node} the node that was expanded
532 * @deprecated use treeobj.subscribe("expand") instead
533 */
534 onExpand: function(node) { },
535
536 /**
537 * Abstract method that is executed when a node is collapsed.
538 * @method onCollapse
539 * @param node {Node} the node that was collapsed.
540 * @deprecated use treeobj.subscribe("collapse") instead
541 */
542 onCollapse: function(node) { }
543
544};
545
546YAHOO.augment(YAHOO.widget.TreeView, YAHOO.util.EventProvider);
547
548/**
549 * Count of all nodes in all trees
550 * @property YAHOO.widget.TreeView.nodeCount
551 * @type int
552 * @static
553 */
554YAHOO.widget.TreeView.nodeCount = 0;
555
556/**
557 * Global cache of tree instances
558 * @property YAHOO.widget.TreeView.trees
559 * @type Array
560 * @static
561 * @private
562 */
563YAHOO.widget.TreeView.trees = [];
564
565/**
566 * Counter for generating a new unique element id
567 * @property YAHOO.widget.TreeView.counter
568 * @static
569 * @private
570 */
571YAHOO.widget.TreeView.counter = 0;
572
573/**
574 * Global method for getting a tree by its id. Used in the generated
575 * tree html.
576 * @method YAHOO.widget.TreeView.getTree
577 * @param treeId {String} the id of the tree instance
578 * @return {TreeView} the tree instance requested, null if not found.
579 * @static
580 */
581YAHOO.widget.TreeView.getTree = function(treeId) {
582 var t = YAHOO.widget.TreeView.trees[treeId];
583 return (t) ? t : null;
584};
585
586/**
587 * Global method for getting a node by its id. Used in the generated
588 * tree html.
589 * @method YAHOO.widget.TreeView.getNode
590 * @param treeId {String} the id of the tree instance
591 * @param nodeIndex {String} the index of the node to return
592 * @return {Node} the node instance requested, null if not found
593 * @static
594 */
595YAHOO.widget.TreeView.getNode = function(treeId, nodeIndex) {
596 var t = YAHOO.widget.TreeView.getTree(treeId);
597 return (t) ? t.getNodeByIndex(nodeIndex) : null;
598};
599
600/**
601 * Add a DOM event
602 * @method YAHOO.widget.TreeView.addHandler
603 * @param el the elment to bind the handler to
604 * @param {string} sType the type of event handler
605 * @param {function} fn the callback to invoke
606 * @static
607 */
608YAHOO.widget.TreeView.addHandler = function (el, sType, fn) {
609 if (el.addEventListener) {
610 el.addEventListener(sType, fn, false);
611 } else if (el.attachEvent) {
612 el.attachEvent("on" + sType, fn);
613 }
614};
615
616/**
617 * Remove a DOM event
618 * @method YAHOO.widget.TreeView.removeHandler
619 * @param el the elment to bind the handler to
620 * @param {string} sType the type of event handler
621 * @param {function} fn the callback to invoke
622 * @static
623 */
624
625YAHOO.widget.TreeView.removeHandler = function (el, sType, fn) {
626 if (el.removeEventListener) {
627 el.removeEventListener(sType, fn, false);
628 } else if (el.detachEvent) {
629 el.detachEvent("on" + sType, fn);
630 }
631};
632
633/**
634 * Attempts to preload the images defined in the styles used to draw the tree by
635 * rendering off-screen elements that use the styles.
636 * @method YAHOO.widget.TreeView.preload
637 * @param {string} prefix the prefix to use to generate the names of the
638 * images to preload, default is ygtv
639 * @static
640 */
641YAHOO.widget.TreeView.preload = function(prefix) {
642 prefix = prefix || "ygtv";
643 var styles = ["tn","tm","tmh","tp","tph","ln","lm","lmh","lp","lph","loading"];
644
645 var sb = [];
646
647 for (var i = 0; i < styles.length; ++i) {
648 sb[sb.length] = '<span class="' + prefix + styles[i] + '">&#160;</span>';
649 }
650
651 var f = document.createElement("div");
652 var s = f.style;
653 s.position = "absolute";
654 s.top = "-1000px";
655 s.left = "-1000px";
656 f.innerHTML = sb.join("");
657
658 document.body.appendChild(f);
659
660 YAHOO.widget.TreeView.removeHandler(window,
661 "load", YAHOO.widget.TreeView.preload);
662
663};
664
665YAHOO.widget.TreeView.addHandler(window,
666 "load", YAHOO.widget.TreeView.preload);
667
668/**
669 * The base class for all tree nodes. The node's presentation and behavior in
670 * response to mouse events is handled in Node subclasses.
671 * @namespace YAHOO.widget
672 * @class Node
673 * @param oData {object} a string or object containing the data that will
674 * be used to render this node
675 * @param oParent {Node} this node's parent node
676 * @param expanded {boolean} the initial expanded/collapsed state
677 * @constructor
678 */
679YAHOO.widget.Node = function(oData, oParent, expanded) {
680 if (oData) { this.init(oData, oParent, expanded); }
681};
682
683YAHOO.widget.Node.prototype = {
684
685 /**
686 * The index for this instance obtained from global counter in YAHOO.widget.TreeView.
687 * @property index
688 * @type int
689 */
690 index: 0,
691
692 /**
693 * This node's child node collection.
694 * @property children
695 * @type Node[]
696 */
697 children: null,
698
699 /**
700 * Tree instance this node is part of
701 * @property tree
702 * @type TreeView
703 */
704 tree: null,
705
706 /**
707 * The data linked to this node. This can be any object or primitive
708 * value, and the data can be used in getNodeHtml().
709 * @property data
710 * @type object
711 */
712 data: null,
713
714 /**
715 * Parent node
716 * @property parent
717 * @type Node
718 */
719 parent: null,
720
721 /**
722 * The depth of this node. We start at -1 for the root node.
723 * @property depth
724 * @type int
725 */
726 depth: -1,
727
728 /**
729 * The href for the node's label. If one is not specified, the href will
730 * be set so that it toggles the node.
731 * @property href
732 * @type string
733 */
734 href: null,
735
736 /**
737 * The label href target, defaults to current window
738 * @property target
739 * @type string
740 */
741 target: "_self",
742
743 /**
744 * The node's expanded/collapsed state
745 * @property expanded
746 * @type boolean
747 */
748 expanded: false,
749
750 /**
751 * Can multiple children be expanded at once?
752 * @property multiExpand
753 * @type boolean
754 */
755 multiExpand: true,
756
757 /**
758 * Should we render children for a collapsed node? It is possible that the
759 * implementer will want to render the hidden data... @todo verify that we
760 * need this, and implement it if we do.
761 * @property renderHidden
762 * @type boolean
763 */
764 renderHidden: false,
765
766 /**
767 * This flag is set to true when the html is generated for this node's
768 * children, and set to false when new children are added.
769 * @property childrenRendered
770 * @type boolean
771 */
772 childrenRendered: false,
773
774 /**
775 * Dynamically loaded nodes only fetch the data the first time they are
776 * expanded. This flag is set to true once the data has been fetched.
777 * @property dynamicLoadComplete
778 * @type boolean
779 */
780 dynamicLoadComplete: false,
781
782 /**
783 * This node's previous sibling
784 * @property previousSibling
785 * @type Node
786 */
787 previousSibling: null,
788
789 /**
790 * This node's next sibling
791 * @property nextSibling
792 * @type Node
793 */
794 nextSibling: null,
795
796 /**
797 * We can set the node up to call an external method to get the child
798 * data dynamically.
799 * @property _dynLoad
800 * @type boolean
801 * @private
802 */
803 _dynLoad: false,
804
805 /**
806 * Function to execute when we need to get this node's child data.
807 * @property dataLoader
808 * @type function
809 */
810 dataLoader: null,
811
812 /**
813 * This is true for dynamically loading nodes while waiting for the
814 * callback to return.
815 * @property isLoading
816 * @type boolean
817 */
818 isLoading: false,
819
820 /**
821 * The toggle/branch icon will not show if this is set to false. This
822 * could be useful if the implementer wants to have the child contain
823 * extra info about the parent, rather than an actual node.
824 * @property hasIcon
825 * @type boolean
826 */
827 hasIcon: true,
828
829 /**
830 * Used to configure what happens when a dynamic load node is expanded
831 * and we discover that it does not have children. By default, it is
832 * treated as if it still could have children (plus/minus icon). Set
833 * iconMode to have it display like a leaf node instead.
834 * @property iconMode
835 * @type int
836 */
837 iconMode: 0,
838
839 /**
840 * The node type
841 * @property _type
842 * @private
843 */
844 _type: "Node",
845
846 /*
847 spacerPath: "http://us.i1.yimg.com/us.yimg.com/i/space.gif",
848 expandedText: "Expanded",
849 collapsedText: "Collapsed",
850 loadingText: "Loading",
851 */
852
853 /**
854 * Initializes this node, gets some of the properties from the parent
855 * @method init
856 * @param oData {object} a string or object containing the data that will
857 * be used to render this node
858 * @param oParent {Node} this node's parent node
859 * @param expanded {boolean} the initial expanded/collapsed state
860 */
861 init: function(oData, oParent, expanded) {
862
863 this.data = oData;
864 this.children = [];
865 this.index = YAHOO.widget.TreeView.nodeCount;
866 ++YAHOO.widget.TreeView.nodeCount;
867 this.expanded = expanded;
868
869 /**
870 * The parentChange event is fired when a parent element is applied
871 * to the node. This is useful if you need to apply tree-level
872 * properties to a tree that need to happen if a node is moved from
873 * one tre to another.
874 *
875 * @event parentChange
876 * @type CustomEvent
877 */
878 this.createEvent("parentChange", this);
879
880 // oParent should never be null except when we create the root node.
881 if (oParent) {
882 oParent.appendChild(this);
883 }
884 },
885
886 /**
887 * Certain properties for the node cannot be set until the parent
888 * is known. This is called after the node is inserted into a tree.
889 * the parent is also applied to this node's children in order to
890 * make it possible to move a branch from one tree to another.
891 * @method applyParent
892 * @param {Node} parentNode this node's parent node
893 * @return {boolean} true if the application was successful
894 */
895 applyParent: function(parentNode) {
896 if (!parentNode) {
897 return false;
898 }
899
900 this.tree = parentNode.tree;
901 this.parent = parentNode;
902 this.depth = parentNode.depth + 1;
903
904 if (!this.href) {
905 this.href = "javascript:" + this.getToggleLink();
906 }
907
908 if (! this.multiExpand) {
909 this.multiExpand = parentNode.multiExpand;
910 }
911
912 this.tree.regNode(this);
913 parentNode.childrenRendered = false;
914
915 // cascade update existing children
916 for (var i=0, len=this.children.length;i<len;++i) {
917 this.children[i].applyParent(this);
918 }
919
920 this.fireEvent("parentChange");
921
922 return true;
923 },
924
925 /**
926 * Appends a node to the child collection.
927 * @method appendChild
928 * @param childNode {Node} the new node
929 * @return {Node} the child node
930 * @private
931 */
932 appendChild: function(childNode) {
933 if (this.hasChildren()) {
934 var sib = this.children[this.children.length - 1];
935 sib.nextSibling = childNode;
936 childNode.previousSibling = sib;
937 }
938 this.children[this.children.length] = childNode;
939 childNode.applyParent(this);
940
941 return childNode;
942 },
943
944 /**
945 * Appends this node to the supplied node's child collection
946 * @method appendTo
947 * @param parentNode {Node} the node to append to.
948 * @return {Node} The appended node
949 */
950 appendTo: function(parentNode) {
951 return parentNode.appendChild(this);
952 },
953
954 /**
955 * Inserts this node before this supplied node
956 * @method insertBefore
957 * @param node {Node} the node to insert this node before
958 * @return {Node} the inserted node
959 */
960 insertBefore: function(node) {
961 var p = node.parent;
962 if (p) {
963
964 if (this.tree) {
965 this.tree.popNode(this);
966 }
967
968 var refIndex = node.isChildOf(p);
969 p.children.splice(refIndex, 0, this);
970 if (node.previousSibling) {
971 node.previousSibling.nextSibling = this;
972 }
973 this.previousSibling = node.previousSibling;
974 this.nextSibling = node;
975 node.previousSibling = this;
976
977 this.applyParent(p);
978 }
979
980 return this;
981 },
982
983 /**
984 * Inserts this node after the supplied node
985 * @method insertAfter
986 * @param node {Node} the node to insert after
987 * @return {Node} the inserted node
988 */
989 insertAfter: function(node) {
990 var p = node.parent;
991 if (p) {
992
993 if (this.tree) {
994 this.tree.popNode(this);
995 }
996
997 var refIndex = node.isChildOf(p);
998
999 if (!node.nextSibling) {
1000 return this.appendTo(p);
1001 }
1002
1003 p.children.splice(refIndex + 1, 0, this);
1004
1005 node.nextSibling.previousSibling = this;
1006 this.previousSibling = node;
1007 this.nextSibling = node.nextSibling;
1008 node.nextSibling = this;
1009
1010 this.applyParent(p);
1011 }
1012
1013 return this;
1014 },
1015
1016 /**
1017 * Returns true if the Node is a child of supplied Node
1018 * @method isChildOf
1019 * @param parentNode {Node} the Node to check
1020 * @return {boolean} The node index if this Node is a child of
1021 * supplied Node, else -1.
1022 * @private
1023 */
1024 isChildOf: function(parentNode) {
1025 if (parentNode && parentNode.children) {
1026 for (var i=0, len=parentNode.children.length; i<len ; ++i) {
1027 if (parentNode.children[i] === this) {
1028 return i;
1029 }
1030 }
1031 }
1032
1033 return -1;
1034 },
1035
1036 /**
1037 * Returns a node array of this node's siblings, null if none.
1038 * @method getSiblings
1039 * @return Node[]
1040 */
1041 getSiblings: function() {
1042 return this.parent.children;
1043 },
1044
1045 /**
1046 * Shows this node's children
1047 * @method showChildren
1048 */
1049 showChildren: function() {
1050 if (!this.tree.animateExpand(this.getChildrenEl(), this)) {
1051 if (this.hasChildren()) {
1052 this.getChildrenEl().style.display = "";
1053 }
1054 }
1055 },
1056
1057 /**
1058 * Hides this node's children
1059 * @method hideChildren
1060 */
1061 hideChildren: function() {
1062
1063 if (!this.tree.animateCollapse(this.getChildrenEl(), this)) {
1064 this.getChildrenEl().style.display = "none";
1065 }
1066 },
1067
1068 /**
1069 * Returns the id for this node's container div
1070 * @method getElId
1071 * @return {string} the element id
1072 */
1073 getElId: function() {
1074 return "ygtv" + this.index;
1075 },
1076
1077 /**
1078 * Returns the id for this node's children div
1079 * @method getChildrenElId
1080 * @return {string} the element id for this node's children div
1081 */
1082 getChildrenElId: function() {
1083 return "ygtvc" + this.index;
1084 },
1085
1086 /**
1087 * Returns the id for this node's toggle element
1088 * @method getToggleElId
1089 * @return {string} the toggel element id
1090 */
1091 getToggleElId: function() {
1092 return "ygtvt" + this.index;
1093 },
1094
1095 /*
1096 * Returns the id for this node's spacer image. The spacer is positioned
1097 * over the toggle and provides feedback for screen readers.
1098 * @method getSpacerId
1099 * @return {string} the id for the spacer image
1100 */
1101 /*
1102 getSpacerId: function() {
1103 return "ygtvspacer" + this.index;
1104 },
1105 */
1106
1107 /**
1108 * Returns this node's container html element
1109 * @method getEl
1110 * @return {HTMLElement} the container html element
1111 */
1112 getEl: function() {
1113 return document.getElementById(this.getElId());
1114 },
1115
1116 /**
1117 * Returns the div that was generated for this node's children
1118 * @method getChildrenEl
1119 * @return {HTMLElement} this node's children div
1120 */
1121 getChildrenEl: function() {
1122 return document.getElementById(this.getChildrenElId());
1123 },
1124
1125 /**
1126 * Returns the element that is being used for this node's toggle.
1127 * @method getToggleEl
1128 * @return {HTMLElement} this node's toggle html element
1129 */
1130 getToggleEl: function() {
1131 return document.getElementById(this.getToggleElId());
1132 },
1133
1134 /*
1135 * Returns the element that is being used for this node's spacer.
1136 * @method getSpacer
1137 * @return {HTMLElement} this node's spacer html element
1138 */
1139 /*
1140 getSpacer: function() {
1141 return document.getElementById( this.getSpacerId() ) || {};
1142 },
1143 */
1144
1145 /*
1146 getStateText: function() {
1147 if (this.isLoading) {
1148 return this.loadingText;
1149 } else if (this.hasChildren(true)) {
1150 if (this.expanded) {
1151 return this.expandedText;
1152 } else {
1153 return this.collapsedText;
1154 }
1155 } else {
1156 return "";
1157 }
1158 },
1159 */
1160
1161 /**
1162 * Generates the link that will invoke this node's toggle method
1163 * @method getToggleLink
1164 * @return {string} the javascript url for toggling this node
1165 */
1166 getToggleLink: function() {
1167 return "YAHOO.widget.TreeView.getNode(\'" + this.tree.id + "\'," +
1168 this.index + ").toggle()";
1169 },
1170
1171 /**
1172 * Hides this nodes children (creating them if necessary), changes the
1173 * @method collapse
1174 * toggle style.
1175 */
1176 collapse: function() {
1177 // Only collapse if currently expanded
1178 if (!this.expanded) { return; }
1179
1180 // fire the collapse event handler
1181 var ret = this.tree.onCollapse(this);
1182
1183 if (false === ret) {
1184 return;
1185 }
1186
1187 ret = this.tree.fireEvent("collapse", this);
1188
1189 if (false === ret) {
1190 return;
1191 }
1192
1193 if (!this.getEl()) {
1194 this.expanded = false;
1195 return;
1196 }
1197
1198 // hide the child div
1199 this.hideChildren();
1200 this.expanded = false;
1201
1202 this.updateIcon();
1203
1204 // this.getSpacer().title = this.getStateText();
1205
1206 },
1207
1208 /**
1209 * Shows this nodes children (creating them if necessary), changes the
1210 * toggle style, and collapses its siblings if multiExpand is not set.
1211 * @method expand
1212 */
1213 expand: function() {
1214 // Only expand if currently collapsed.
1215 if (this.expanded) { return; }
1216
1217 // fire the expand event handler
1218 var ret = this.tree.onExpand(this);
1219
1220 if (false === ret) {
1221 return;
1222 }
1223
1224 ret = this.tree.fireEvent("expand", this);
1225
1226 if (false === ret) {
1227 return;
1228 }
1229
1230 if (!this.getEl()) {
1231 this.expanded = true;
1232 return;
1233 }
1234
1235 if (! this.childrenRendered) {
1236 this.getChildrenEl().innerHTML = this.renderChildren();
1237 } else {
1238 }
1239
1240 this.expanded = true;
1241
1242 this.updateIcon();
1243
1244 // this.getSpacer().title = this.getStateText();
1245
1246 // We do an extra check for children here because the lazy
1247 // load feature can expose nodes that have no children.
1248
1249 // if (!this.hasChildren()) {
1250 if (this.isLoading) {
1251 this.expanded = false;
1252 return;
1253 }
1254
1255 if (! this.multiExpand) {
1256 var sibs = this.getSiblings();
1257 for (var i=0; i<sibs.length; ++i) {
1258 if (sibs[i] != this && sibs[i].expanded) {
1259 sibs[i].collapse();
1260 }
1261 }
1262 }
1263
1264 this.showChildren();
1265 },
1266
1267 updateIcon: function() {
1268 if (this.hasIcon) {
1269 var el = this.getToggleEl();
1270 if (el) {
1271 el.className = this.getStyle();
1272 }
1273 }
1274 },
1275
1276 /**
1277 * Returns the css style name for the toggle
1278 * @method getStyle
1279 * @return {string} the css class for this node's toggle
1280 */
1281 getStyle: function() {
1282 if (this.isLoading) {
1283 return "ygtvloading";
1284 } else {
1285 // location top or bottom, middle nodes also get the top style
1286 var loc = (this.nextSibling) ? "t" : "l";
1287
1288 // type p=plus(expand), m=minus(collapase), n=none(no children)
1289 var type = "n";
1290 if (this.hasChildren(true) || (this.isDynamic() && !this.getIconMode())) {
1291 // if (this.hasChildren(true)) {
1292 type = (this.expanded) ? "m" : "p";
1293 }
1294
1295 return "ygtv" + loc + type;
1296 }
1297 },
1298
1299 /**
1300 * Returns the hover style for the icon
1301 * @return {string} the css class hover state
1302 * @method getHoverStyle
1303 */
1304 getHoverStyle: function() {
1305 var s = this.getStyle();
1306 if (this.hasChildren(true) && !this.isLoading) {
1307 s += "h";
1308 }
1309 return s;
1310 },
1311
1312 /**
1313 * Recursively expands all of this node's children.
1314 * @method expandAll
1315 */
1316 expandAll: function() {
1317 for (var i=0;i<this.children.length;++i) {
1318 var c = this.children[i];
1319 if (c.isDynamic()) {
1320 alert("Not supported (lazy load + expand all)");
1321 break;
1322 } else if (! c.multiExpand) {
1323 alert("Not supported (no multi-expand + expand all)");
1324 break;
1325 } else {
1326 c.expand();
1327 c.expandAll();
1328 }
1329 }
1330 },
1331
1332 /**
1333 * Recursively collapses all of this node's children.
1334 * @method collapseAll
1335 */
1336 collapseAll: function() {
1337 for (var i=0;i<this.children.length;++i) {
1338 this.children[i].collapse();
1339 this.children[i].collapseAll();
1340 }
1341 },
1342
1343 /**
1344 * Configures this node for dynamically obtaining the child data
1345 * when the node is first expanded. Calling it without the callback
1346 * will turn off dynamic load for the node.
1347 * @method setDynamicLoad
1348 * @param fmDataLoader {function} the function that will be used to get the data.
1349 * @param iconMode {int} configures the icon that is displayed when a dynamic
1350 * load node is expanded the first time without children. By default, the
1351 * "collapse" icon will be used. If set to 1, the leaf node icon will be
1352 * displayed.
1353 */
1354 setDynamicLoad: function(fnDataLoader, iconMode) {
1355 if (fnDataLoader) {
1356 this.dataLoader = fnDataLoader;
1357 this._dynLoad = true;
1358 } else {
1359 this.dataLoader = null;
1360 this._dynLoad = false;
1361 }
1362
1363 if (iconMode) {
1364 this.iconMode = iconMode;
1365 }
1366 },
1367
1368 /**
1369 * Evaluates if this node is the root node of the tree
1370 * @method isRoot
1371 * @return {boolean} true if this is the root node
1372 */
1373 isRoot: function() {
1374 return (this == this.tree.root);
1375 },
1376
1377 /**
1378 * Evaluates if this node's children should be loaded dynamically. Looks for
1379 * the property both in this instance and the root node. If the tree is
1380 * defined to load all children dynamically, the data callback function is
1381 * defined in the root node
1382 * @method isDynamic
1383 * @return {boolean} true if this node's children are to be loaded dynamically
1384 */
1385 isDynamic: function() {
1386 var lazy = (!this.isRoot() && (this._dynLoad || this.tree.root._dynLoad));
1387 return lazy;
1388 },
1389
1390 /**
1391 * Returns the current icon mode. This refers to the way childless dynamic
1392 * load nodes appear.
1393 * @method getIconMode
1394 * @return {int} 0 for collapse style, 1 for leaf node style
1395 */
1396 getIconMode: function() {
1397 return (this.iconMode || this.tree.root.iconMode);
1398 },
1399
1400 /**
1401 * Checks if this node has children. If this node is lazy-loading and the
1402 * children have not been rendered, we do not know whether or not there
1403 * are actual children. In most cases, we need to assume that there are
1404 * children (for instance, the toggle needs to show the expandable
1405 * presentation state). In other times we want to know if there are rendered
1406 * children. For the latter, "checkForLazyLoad" should be false.
1407 * @method hasChildren
1408 * @param checkForLazyLoad {boolean} should we check for unloaded children?
1409 * @return {boolean} true if this has children or if it might and we are
1410 * checking for this condition.
1411 */
1412 hasChildren: function(checkForLazyLoad) {
1413 return ( this.children.length > 0 ||
1414 (checkForLazyLoad && this.isDynamic() && !this.dynamicLoadComplete) );
1415 },
1416
1417 /**
1418 * Expands if node is collapsed, collapses otherwise.
1419 * @method toggle
1420 */
1421 toggle: function() {
1422 if (!this.tree.locked && ( this.hasChildren(true) || this.isDynamic()) ) {
1423 if (this.expanded) { this.collapse(); } else { this.expand(); }
1424 }
1425 },
1426
1427 /**
1428 * Returns the markup for this node and its children.
1429 * @method getHtml
1430 * @return {string} the markup for this node and its expanded children.
1431 */
1432 getHtml: function() {
1433
1434 this.childrenRendered = false;
1435
1436 var sb = [];
1437 sb[sb.length] = '<div class="ygtvitem" id="' + this.getElId() + '">';
1438 sb[sb.length] = this.getNodeHtml();
1439 sb[sb.length] = this.getChildrenHtml();
1440 sb[sb.length] = '</div>';
1441 return sb.join("");
1442 },
1443
1444 /**
1445 * Called when first rendering the tree. We always build the div that will
1446 * contain this nodes children, but we don't render the children themselves
1447 * unless this node is expanded.
1448 * @method getChildrenHtml
1449 * @return {string} the children container div html and any expanded children
1450 * @private
1451 */
1452 getChildrenHtml: function() {
1453
1454 var sb = [];
1455 sb[sb.length] = '<div class="ygtvchildren"';
1456 sb[sb.length] = ' id="' + this.getChildrenElId() + '"';
1457 if (!this.expanded) {
1458 sb[sb.length] = ' style="display:none;"';
1459 }
1460 sb[sb.length] = '>';
1461
1462 // Don't render the actual child node HTML unless this node is expanded.
1463 if ( (this.hasChildren(true) && this.expanded) ||
1464 (this.renderHidden && !this.isDynamic()) ) {
1465 sb[sb.length] = this.renderChildren();
1466 }
1467
1468 sb[sb.length] = '</div>';
1469
1470 return sb.join("");
1471 },
1472
1473 /**
1474 * Generates the markup for the child nodes. This is not done until the node
1475 * is expanded.
1476 * @method renderChildren
1477 * @return {string} the html for this node's children
1478 * @private
1479 */
1480 renderChildren: function() {
1481
1482
1483 var node = this;
1484
1485 if (this.isDynamic() && !this.dynamicLoadComplete) {
1486 this.isLoading = true;
1487 this.tree.locked = true;
1488
1489 if (this.dataLoader) {
1490
1491 setTimeout(
1492 function() {
1493 node.dataLoader(node,
1494 function() {
1495 node.loadComplete();
1496 });
1497 }, 10);
1498
1499 } else if (this.tree.root.dataLoader) {
1500
1501 setTimeout(
1502 function() {
1503 node.tree.root.dataLoader(node,
1504 function() {
1505 node.loadComplete();
1506 });
1507 }, 10);
1508
1509 } else {
1510 return "Error: data loader not found or not specified.";
1511 }
1512
1513 return "";
1514
1515 } else {
1516 return this.completeRender();
1517 }
1518 },
1519
1520 /**
1521 * Called when we know we have all the child data.
1522 * @method completeRender
1523 * @return {string} children html
1524 */
1525 completeRender: function() {
1526 var sb = [];
1527
1528 for (var i=0; i < this.children.length; ++i) {
1529 // this.children[i].childrenRendered = false;
1530 sb[sb.length] = this.children[i].getHtml();
1531 }
1532
1533 this.childrenRendered = true;
1534
1535 return sb.join("");
1536 },
1537
1538 /**
1539 * Load complete is the callback function we pass to the data provider
1540 * in dynamic load situations.
1541 * @method loadComplete
1542 */
1543 loadComplete: function() {
1544 this.getChildrenEl().innerHTML = this.completeRender();
1545 this.dynamicLoadComplete = true;
1546 this.isLoading = false;
1547 this.expand();
1548 this.tree.locked = false;
1549 },
1550
1551 /**
1552 * Returns this node's ancestor at the specified depth.
1553 * @method getAncestor
1554 * @param {int} depth the depth of the ancestor.
1555 * @return {Node} the ancestor
1556 */
1557 getAncestor: function(depth) {
1558 if (depth >= this.depth || depth < 0) {
1559 return null;
1560 }
1561
1562 var p = this.parent;
1563
1564 while (p.depth > depth) {
1565 p = p.parent;
1566 }
1567
1568 return p;
1569 },
1570
1571 /**
1572 * Returns the css class for the spacer at the specified depth for
1573 * this node. If this node's ancestor at the specified depth
1574 * has a next sibling the presentation is different than if it
1575 * does not have a next sibling
1576 * @method getDepthStyle
1577 * @param {int} depth the depth of the ancestor.
1578 * @return {string} the css class for the spacer
1579 */
1580 getDepthStyle: function(depth) {
1581 return (this.getAncestor(depth).nextSibling) ?
1582 "ygtvdepthcell" : "ygtvblankdepthcell";
1583 },
1584
1585 /**
1586 * Get the markup for the node. This is designed to be overrided so that we can
1587 * support different types of nodes.
1588 * @method getNodeHtml
1589 * @return {string} The HTML that will render this node.
1590 */
1591 getNodeHtml: function() {
1592 return "";
1593 },
1594
1595 /**
1596 * Regenerates the html for this node and its children. To be used when the
1597 * node is expanded and new children have been added.
1598 * @method refresh
1599 */
1600 refresh: function() {
1601 // this.loadComplete();
1602 this.getChildrenEl().innerHTML = this.completeRender();
1603
1604 if (this.hasIcon) {
1605 var el = this.getToggleEl();
1606 if (el) {
1607 el.className = this.getStyle();
1608 }
1609 }
1610 },
1611
1612 /**
1613 * Node toString
1614 * @method toString
1615 * @return {string} string representation of the node
1616 */
1617 toString: function() {
1618 return "Node (" + this.index + ")";
1619 }
1620
1621};
1622
1623YAHOO.augment(YAHOO.widget.Node, YAHOO.util.EventProvider);
1624
1625/**
1626 * A custom YAHOO.widget.Node that handles the unique nature of
1627 * the virtual, presentationless root node.
1628 * @namespace YAHOO.widget
1629 * @class RootNode
1630 * @extends YAHOO.widget.Node
1631 * @param oTree {YAHOO.widget.TreeView} The tree instance this node belongs to
1632 * @constructor
1633 */
1634YAHOO.widget.RootNode = function(oTree) {
1635 // Initialize the node with null params. The root node is a
1636 // special case where the node has no presentation. So we have
1637 // to alter the standard properties a bit.
1638 this.init(null, null, true);
1639
1640 /*
1641 * For the root node, we get the tree reference from as a param
1642 * to the constructor instead of from the parent element.
1643 */
1644 this.tree = oTree;
1645};
1646
1647YAHOO.extend(YAHOO.widget.RootNode, YAHOO.widget.Node, {
1648
1649 // overrides YAHOO.widget.Node
1650 getNodeHtml: function() {
1651 return "";
1652 },
1653
1654 toString: function() {
1655 return "RootNode";
1656 },
1657
1658 loadComplete: function() {
1659 this.tree.draw();
1660 }
1661
1662});
1663/**
1664 * The default node presentation. The first parameter should be
1665 * either a string that will be used as the node's label, or an object
1666 * that has a string propery called label. By default, the clicking the
1667 * label will toggle the expanded/collapsed state of the node. By
1668 * changing the href property of the instance, this behavior can be
1669 * changed so that the label will go to the specified href.
1670 * @namespace YAHOO.widget
1671 * @class TextNode
1672 * @extends YAHOO.widget.Node
1673 * @constructor
1674 * @param oData {object} a string or object containing the data that will
1675 * be used to render this node
1676 * @param oParent {YAHOO.widget.Node} this node's parent node
1677 * @param expanded {boolean} the initial expanded/collapsed state
1678 */
1679YAHOO.widget.TextNode = function(oData, oParent, expanded) {
1680
1681 if (oData) {
1682 this.init(oData, oParent, expanded);
1683 this.setUpLabel(oData);
1684 }
1685
1686};
1687
1688YAHOO.extend(YAHOO.widget.TextNode, YAHOO.widget.Node, {
1689
1690 /**
1691 * The CSS class for the label href. Defaults to ygtvlabel, but can be
1692 * overridden to provide a custom presentation for a specific node.
1693 * @property labelStyle
1694 * @type string
1695 */
1696 labelStyle: "ygtvlabel",
1697
1698 /**
1699 * The derived element id of the label for this node
1700 * @property labelElId
1701 * @type string
1702 */
1703 labelElId: null,
1704
1705 /**
1706 * The text for the label. It is assumed that the oData parameter will
1707 * either be a string that will be used as the label, or an object that
1708 * has a property called "label" that we will use.
1709 * @property label
1710 * @type string
1711 */
1712 label: null,
1713
1714 textNodeParentChange: function() {
1715
1716 /**
1717 * Custom event that is fired when the text node label is clicked. The
1718 * custom event is defined on the tree instance, so there is a single
1719 * event that handles all nodes in the tree. The node clicked is
1720 * provided as an argument
1721 *
1722 * @event labelClick
1723 * @for YAHOO.widget.TreeView
1724 * @param {YAHOO.widget.Node} node the node clicked
1725 */
1726 if (this.tree && !this.tree.hasEvent("labelClick")) {
1727 this.tree.createEvent("labelClick", this.tree);
1728 }
1729
1730 },
1731
1732 /**
1733 * Sets up the node label
1734 * @method setUpLabel
1735 * @param oData string containing the label, or an object with a label property
1736 */
1737 setUpLabel: function(oData) {
1738
1739 // set up the custom event on the tree
1740 this.textNodeParentChange();
1741 this.subscribe("parentChange", this.textNodeParentChange);
1742
1743 if (typeof oData == "string") {
1744 oData = { label: oData };
1745 }
1746 this.label = oData.label;
1747
1748 // update the link
1749 if (oData.href) {
1750 this.href = oData.href;
1751 }
1752
1753 // set the target
1754 if (oData.target) {
1755 this.target = oData.target;
1756 }
1757
1758 if (oData.style) {
1759 this.labelStyle = oData.style;
1760 }
1761
1762 this.labelElId = "ygtvlabelel" + this.index;
1763 },
1764
1765 /**
1766 * Returns the label element
1767 * @for YAHOO.widget.TextNode
1768 * @method getLabelEl
1769 * @return {object} the element
1770 */
1771 getLabelEl: function() {
1772 return document.getElementById(this.labelElId);
1773 },
1774
1775 // overrides YAHOO.widget.Node
1776 getNodeHtml: function() {
1777 var sb = [];
1778
1779 sb[sb.length] = '<table border="0" cellpadding="0" cellspacing="0">';
1780 sb[sb.length] = '<tr>';
1781
1782 for (var i=0;i<this.depth;++i) {
1783 // sb[sb.length] = '<td class="ygtvdepthcell">&#160;</td>';
1784 sb[sb.length] = '<td class="' + this.getDepthStyle(i) + '">&#160;</td>';
1785 }
1786
1787 var getNode = 'YAHOO.widget.TreeView.getNode(\'' +
1788 this.tree.id + '\',' + this.index + ')';
1789
1790 sb[sb.length] = '<td';
1791 // sb[sb.length] = ' onselectstart="return false"';
1792 sb[sb.length] = ' id="' + this.getToggleElId() + '"';
1793 sb[sb.length] = ' class="' + this.getStyle() + '"';
1794 if (this.hasChildren(true)) {
1795 sb[sb.length] = ' onmouseover="this.className=';
1796 sb[sb.length] = getNode + '.getHoverStyle()"';
1797 sb[sb.length] = ' onmouseout="this.className=';
1798 sb[sb.length] = getNode + '.getStyle()"';
1799 }
1800 sb[sb.length] = ' onclick="javascript:' + this.getToggleLink() + '">';
1801
1802 /*
1803 sb[sb.length] = '<img id="' + this.getSpacerId() + '"';
1804 sb[sb.length] = ' alt=""';
1805 sb[sb.length] = ' tabindex=0';
1806 sb[sb.length] = ' src="' + this.spacerPath + '"';
1807 sb[sb.length] = ' title="' + this.getStateText() + '"';
1808 sb[sb.length] = ' class="ygtvspacer"';
1809 // sb[sb.length] = ' onkeypress="return ' + getNode + '".onKeyPress()"';
1810 sb[sb.length] = ' />';
1811 */
1812
1813 sb[sb.length] = '&#160;';
1814
1815 sb[sb.length] = '</td>';
1816 sb[sb.length] = '<td>';
1817 sb[sb.length] = '<a';
1818 sb[sb.length] = ' id="' + this.labelElId + '"';
1819 sb[sb.length] = ' class="' + this.labelStyle + '"';
1820 sb[sb.length] = ' href="' + this.href + '"';
1821 sb[sb.length] = ' target="' + this.target + '"';
1822 sb[sb.length] = ' onclick="return ' + getNode + '.onLabelClick(' + getNode +')"';
1823 if (this.hasChildren(true)) {
1824 sb[sb.length] = ' onmouseover="document.getElementById(\'';
1825 sb[sb.length] = this.getToggleElId() + '\').className=';
1826 sb[sb.length] = getNode + '.getHoverStyle()"';
1827 sb[sb.length] = ' onmouseout="document.getElementById(\'';
1828 sb[sb.length] = this.getToggleElId() + '\').className=';
1829 sb[sb.length] = getNode + '.getStyle()"';
1830 }
1831 sb[sb.length] = ' >';
1832 sb[sb.length] = this.label;
1833 sb[sb.length] = '</a>';
1834 sb[sb.length] = '</td>';
1835 sb[sb.length] = '</tr>';
1836 sb[sb.length] = '</table>';
1837
1838 return sb.join("");
1839 },
1840
1841 /**
1842 * Executed when the label is clicked. Fires the labelClick custom event.
1843 * @method onLabelClick
1844 * @param me {Node} this node
1845 * @scope the anchor tag clicked
1846 * @return false to cancel the anchor click
1847 */
1848 onLabelClick: function(me) {
1849 return me.tree.fireEvent("labelClick", me);
1850 //return true;
1851 },
1852
1853 toString: function() {
1854 return "TextNode (" + this.index + ") " + this.label;
1855 }
1856
1857});
1858/**
1859 * A menu-specific implementation that differs from TextNode in that only
1860 * one sibling can be expanded at a time.
1861 * @namespace YAHOO.widget
1862 * @class MenuNode
1863 * @extends YAHOO.widget.TextNode
1864 * @param oData {object} a string or object containing the data that will
1865 * be used to render this node
1866 * @param oParent {YAHOO.widget.Node} this node's parent node
1867 * @param expanded {boolean} the initial expanded/collapsed state
1868 * @constructor
1869 */
1870YAHOO.widget.MenuNode = function(oData, oParent, expanded) {
1871 if (oData) {
1872 this.init(oData, oParent, expanded);
1873 this.setUpLabel(oData);
1874 }
1875
1876 /*
1877 * Menus usually allow only one branch to be open at a time.
1878 */
1879 this.multiExpand = false;
1880
1881
1882};
1883
1884YAHOO.extend(YAHOO.widget.MenuNode, YAHOO.widget.TextNode, {
1885
1886 toString: function() {
1887 return "MenuNode (" + this.index + ") " + this.label;
1888 }
1889
1890});
1891/**
1892 * This implementation takes either a string or object for the
1893 * oData argument. If is it a string, we will use it for the display
1894 * of this node (and it can contain any html code). If the parameter
1895 * is an object, we look for a parameter called "html" that will be
1896 * used for this node's display.
1897 * @namespace YAHOO.widget
1898 * @class HTMLNode
1899 * @extends YAHOO.widget.Node
1900 * @constructor
1901 * @param oData {object} a string or object containing the data that will
1902 * be used to render this node
1903 * @param oParent {YAHOO.widget.Node} this node's parent node
1904 * @param expanded {boolean} the initial expanded/collapsed state
1905 * @param hasIcon {boolean} specifies whether or not leaf nodes should
1906 * have an icon
1907 */
1908YAHOO.widget.HTMLNode = function(oData, oParent, expanded, hasIcon) {
1909 if (oData) {
1910 this.init(oData, oParent, expanded);
1911 this.initContent(oData, hasIcon);
1912 }
1913};
1914
1915YAHOO.extend(YAHOO.widget.HTMLNode, YAHOO.widget.Node, {
1916
1917 /**
1918 * The CSS class for the html content container. Defaults to ygtvhtml, but
1919 * can be overridden to provide a custom presentation for a specific node.
1920 * @property contentStyle
1921 * @type string
1922 */
1923 contentStyle: "ygtvhtml",
1924
1925 /**
1926 * The generated id that will contain the data passed in by the implementer.
1927 * @property contentElId
1928 * @type string
1929 */
1930 contentElId: null,
1931
1932 /**
1933 * The HTML content to use for this node's display
1934 * @property content
1935 * @type string
1936 */
1937 content: null,
1938
1939 /**
1940 * Sets up the node label
1941 * @property initContent
1942 * @param {object} An html string or object containing an html property
1943 * @param {boolean} hasIcon determines if the node will be rendered with an
1944 * icon or not
1945 */
1946 initContent: function(oData, hasIcon) {
1947 if (typeof oData == "string") {
1948 oData = { html: oData };
1949 }
1950
1951 this.html = oData.html;
1952 this.contentElId = "ygtvcontentel" + this.index;
1953 this.hasIcon = hasIcon;
1954
1955 },
1956
1957 /**
1958 * Returns the outer html element for this node's content
1959 * @method getContentEl
1960 * @return {HTMLElement} the element
1961 */
1962 getContentEl: function() {
1963 return document.getElementById(this.contentElId);
1964 },
1965
1966 // overrides YAHOO.widget.Node
1967 getNodeHtml: function() {
1968 var sb = [];
1969
1970 sb[sb.length] = '<table border="0" cellpadding="0" cellspacing="0">';
1971 sb[sb.length] = '<tr>';
1972
1973 for (var i=0;i<this.depth;++i) {
1974 sb[sb.length] = '<td class="' + this.getDepthStyle(i) + '">&#160;</td>';
1975 }
1976
1977 if (this.hasIcon) {
1978 sb[sb.length] = '<td';
1979 sb[sb.length] = ' id="' + this.getToggleElId() + '"';
1980 sb[sb.length] = ' class="' + this.getStyle() + '"';
1981 sb[sb.length] = ' onclick="javascript:' + this.getToggleLink() + '"';
1982 if (this.hasChildren(true)) {
1983 sb[sb.length] = ' onmouseover="this.className=';
1984 sb[sb.length] = 'YAHOO.widget.TreeView.getNode(\'';
1985 sb[sb.length] = this.tree.id + '\',' + this.index + ').getHoverStyle()"';
1986 sb[sb.length] = ' onmouseout="this.className=';
1987 sb[sb.length] = 'YAHOO.widget.TreeView.getNode(\'';
1988 sb[sb.length] = this.tree.id + '\',' + this.index + ').getStyle()"';
1989 }
1990 sb[sb.length] = '>&#160;</td>';
1991 }
1992
1993 sb[sb.length] = '<td';
1994 sb[sb.length] = ' id="' + this.contentElId + '"';
1995 sb[sb.length] = ' class="' + this.contentStyle + '"';
1996 sb[sb.length] = ' >';
1997 sb[sb.length] = this.html;
1998 sb[sb.length] = '</td>';
1999 sb[sb.length] = '</tr>';
2000 sb[sb.length] = '</table>';
2001
2002 return sb.join("");
2003 },
2004
2005 toString: function() {
2006 return "HTMLNode (" + this.index + ")";
2007 }
2008
2009});
2010/**
2011 * A static factory class for tree view expand/collapse animations
2012 * @class TVAnim
2013 * @static
2014 */
2015YAHOO.widget.TVAnim = function() {
2016 return {
2017 /**
2018 * Constant for the fade in animation
2019 * @property FADE_IN
2020 * @type string
2021 * @static
2022 */
2023 FADE_IN: "TVFadeIn",
2024
2025 /**
2026 * Constant for the fade out animation
2027 * @property FADE_OUT
2028 * @type string
2029 * @static
2030 */
2031 FADE_OUT: "TVFadeOut",
2032
2033 /**
2034 * Returns a ygAnim instance of the given type
2035 * @method getAnim
2036 * @param type {string} the type of animation
2037 * @param el {HTMLElement} the element to element (probably the children div)
2038 * @param callback {function} function to invoke when the animation is done.
2039 * @return {YAHOO.util.Animation} the animation instance
2040 * @static
2041 */
2042 getAnim: function(type, el, callback) {
2043 if (YAHOO.widget[type]) {
2044 return new YAHOO.widget[type](el, callback);
2045 } else {
2046 return null;
2047 }
2048 },
2049
2050 /**
2051 * Returns true if the specified animation class is available
2052 * @method isValid
2053 * @param type {string} the type of animation
2054 * @return {boolean} true if valid, false if not
2055 * @static
2056 */
2057 isValid: function(type) {
2058 return (YAHOO.widget[type]);
2059 }
2060 };
2061} ();
2062
2063/**
2064 * A 1/2 second fade-in animation.
2065 * @class TVFadeIn
2066 * @constructor
2067 * @param el {HTMLElement} the element to animate
2068 * @param callback {function} function to invoke when the animation is finished
2069 */
2070YAHOO.widget.TVFadeIn = function(el, callback) {
2071 /**
2072 * The element to animate
2073 * @property el
2074 * @type HTMLElement
2075 */
2076 this.el = el;
2077
2078 /**
2079 * the callback to invoke when the animation is complete
2080 * @property callback
2081 * @type function
2082 */
2083 this.callback = callback;
2084
2085};
2086
2087YAHOO.widget.TVFadeIn.prototype = {
2088 /**
2089 * Performs the animation
2090 * @method animate
2091 */
2092 animate: function() {
2093 var tvanim = this;
2094
2095 var s = this.el.style;
2096 s.opacity = 0.1;
2097 s.filter = "alpha(opacity=10)";
2098 s.display = "";
2099
2100 var dur = 0.4;
2101 var a = new YAHOO.util.Anim(this.el, {opacity: {from: 0.1, to: 1, unit:""}}, dur);
2102 a.onComplete.subscribe( function() { tvanim.onComplete(); } );
2103 a.animate();
2104 },
2105
2106 /**
2107 * Clean up and invoke callback
2108 * @method onComplete
2109 */
2110 onComplete: function() {
2111 this.callback();
2112 },
2113
2114 /**
2115 * toString
2116 * @method toString
2117 * @return {string} the string representation of the instance
2118 */
2119 toString: function() {
2120 return "TVFadeIn";
2121 }
2122};
2123
2124/**
2125 * A 1/2 second fade out animation.
2126 * @class TVFadeOut
2127 * @constructor
2128 * @param el {HTMLElement} the element to animate
2129 * @param callback {Function} function to invoke when the animation is finished
2130 */
2131YAHOO.widget.TVFadeOut = function(el, callback) {
2132 /**
2133 * The element to animate
2134 * @property el
2135 * @type HTMLElement
2136 */
2137 this.el = el;
2138
2139 /**
2140 * the callback to invoke when the animation is complete
2141 * @property callback
2142 * @type function
2143 */
2144 this.callback = callback;
2145
2146};
2147
2148YAHOO.widget.TVFadeOut.prototype = {
2149 /**
2150 * Performs the animation
2151 * @method animate
2152 */
2153 animate: function() {
2154 var tvanim = this;
2155 var dur = 0.4;
2156 var a = new YAHOO.util.Anim(this.el, {opacity: {from: 1, to: 0.1, unit:""}}, dur);
2157 a.onComplete.subscribe( function() { tvanim.onComplete(); } );
2158 a.animate();
2159 },
2160
2161 /**
2162 * Clean up and invoke callback
2163 * @method onComplete
2164 */
2165 onComplete: function() {
2166 var s = this.el.style;
2167 s.display = "none";
2168 // s.opacity = 1;
2169 s.filter = "alpha(opacity=100)";
2170 this.callback();
2171 },
2172
2173 /**
2174 * toString
2175 * @method toString
2176 * @return {string} the string representation of the instance
2177 */
2178 toString: function() {
2179 return "TVFadeOut";
2180 }
2181};
2182
diff --git a/frontend/beta/js/YUI/yahoo.js b/frontend/beta/js/YUI/yahoo.js
new file mode 100644
index 0000000..8a44a91
--- a/dev/null
+++ b/frontend/beta/js/YUI/yahoo.js
@@ -0,0 +1,145 @@
1/*
2Copyright (c) 2006, Yahoo! Inc. All rights reserved.
3Code licensed under the BSD License:
4http://developer.yahoo.net/yui/license.txt
5version: 0.12.0
6*/
7
8/**
9 * The YAHOO object is the single global object used by YUI Library. It
10 * contains utility function for setting up namespaces, inheritance, and
11 * logging. YAHOO.util, YAHOO.widget, and YAHOO.example are namespaces
12 * created automatically for and used by the library.
13 * @module yahoo
14 * @title YAHOO Global
15 */
16
17/**
18 * The YAHOO global namespace object
19 * @class YAHOO
20 * @static
21 */
22if (typeof YAHOO == "undefined") {
23 var YAHOO = {};
24}
25
26/**
27 * Returns the namespace specified and creates it if it doesn't exist
28 * <pre>
29 * YAHOO.namespace("property.package");
30 * YAHOO.namespace("YAHOO.property.package");
31 * </pre>
32 * Either of the above would create YAHOO.property, then
33 * YAHOO.property.package
34 *
35 * Be careful when naming packages. Reserved words may work in some browsers
36 * and not others. For instance, the following will fail in Safari:
37 * <pre>
38 * YAHOO.namespace("really.long.nested.namespace");
39 * </pre>
40 * This fails because "long" is a future reserved word in ECMAScript
41 *
42 * @method namespace
43 * @static
44 * @param {String*} arguments 1-n namespaces to create
45 * @return {Object} A reference to the last namespace object created
46 */
47YAHOO.namespace = function() {
48 var a=arguments, o=null, i, j, d;
49 for (i=0; i<a.length; ++i) {
50 d=a[i].split(".");
51 o=YAHOO;
52
53 // YAHOO is implied, so it is ignored if it is included
54 for (j=(d[0] == "YAHOO") ? 1 : 0; j<d.length; ++j) {
55 o[d[j]]=o[d[j]] || {};
56 o=o[d[j]];
57 }
58 }
59
60 return o;
61};
62
63/**
64 * Uses YAHOO.widget.Logger to output a log message, if the widget is available.
65 *
66 * @method log
67 * @static
68 * @param {String} msg The message to log.
69 * @param {String} cat The log category for the message. Default
70 * categories are "info", "warn", "error", time".
71 * Custom categories can be used as well. (opt)
72 * @param {String} src The source of the the message (opt)
73 * @return {Boolean} True if the log operation was successful.
74 */
75YAHOO.log = function(msg, cat, src) {
76 var l=YAHOO.widget.Logger;
77 if(l && l.log) {
78 return l.log(msg, cat, src);
79 } else {
80 return false;
81 }
82};
83
84/**
85 * Utility to set up the prototype, constructor and superclass properties to
86 * support an inheritance strategy that can chain constructors and methods.
87 *
88 * @method extend
89 * @static
90 * @param {Function} subc the object to modify
91 * @param {Function} superc the object to inherit
92 * @param {String[]} overrides additional properties/methods to add to the
93 * subclass prototype. These will override the
94 * matching items obtained from the superclass
95 * if present.
96 */
97YAHOO.extend = function(subc, superc, overrides) {
98 var F = function() {};
99 F.prototype=superc.prototype;
100 subc.prototype=new F();
101 subc.prototype.constructor=subc;
102 subc.superclass=superc.prototype;
103 if (superc.prototype.constructor == Object.prototype.constructor) {
104 superc.prototype.constructor=superc;
105 }
106
107 if (overrides) {
108 for (var i in overrides) {
109 subc.prototype[i]=overrides[i];
110 }
111 }
112};
113
114/**
115 * Applies all prototype properties in the supplier to the receiver if the
116 * receiver does not have these properties yet. Optionally, one or more
117 * methods/properties can be specified (as additional parameters). This
118 * option will overwrite the property if receiver has it already.
119 *
120 * @method augment
121 * @static
122 * @param {Function} r the object to receive the augmentation
123 * @param {Function} s the object that supplies the properties to augment
124 * @param {String*} arguments zero or more properties methods to augment the
125 * receiver with. If none specified, everything
126 * in the supplier will be used unless it would
127 * overwrite an existing property in the receiver
128 */
129YAHOO.augment = function(r, s) {
130 var rp=r.prototype, sp=s.prototype, a=arguments, i, p;
131 if (a[2]) {
132 for (i=2; i<a.length; ++i) {
133 rp[a[i]] = sp[a[i]];
134 }
135 } else {
136 for (p in sp) {
137 if (!rp[p]) {
138 rp[p] = sp[p];
139 }
140 }
141 }
142};
143
144YAHOO.namespace("util", "widget", "example");
145
diff --git a/frontend/beta/properties/beta.properties.json b/frontend/beta/properties/beta.properties.json
new file mode 100644
index 0000000..156f03a
--- a/dev/null
+++ b/frontend/beta/properties/beta.properties.json
@@ -0,0 +1,183 @@
1{
2 "copyright.values": {
3 "mochikit.repository": "http://svn.mochikit.com/mochikit/trunk/",
4 "mochikit.version": "1249"
5 },
6 "js": [
7 "MochiKit/Base.js",
8 "MochiKit/Iter.js",
9 "MochiKit/DOM.js",
10 "MochiKit/Style.js",
11 "MochiKit/Signal.js",
12 "MochiKit/Format.js",
13 "MochiKit/Async.js",
14 "MochiKit/Selector.js",
15 "MochiKit/Logging.js",
16 "MochiKit/LoggingPane.js",
17
18 "YUI/yahoo.js",
19 "YUI/animation.js",
20 "YUI/event.js",
21 "YUI/dom.js",
22 "YUI/dragdrop.js",
23 "YUI/logger.js",
24
25 "YUI-extensions/yutil.js",
26 "YUI-extensions/Bench.js",
27 "YUI-extensions/Date.js",
28 "YUI-extensions/DomHelper.js",
29 "YUI-extensions/Element.js",
30 "YUI-extensions/CompositeElement.js",
31 "YUI-extensions/State.js",
32 "YUI-extensions/EventManager.js",
33 "YUI-extensions/KeyMap.js",
34 "YUI-extensions/Layer.js",
35 "YUI-extensions/MixedCollection.js",
36 "YUI-extensions/State.js",
37 "YUI-extensions/UpdateManager.js",
38 "YUI-extensions/anim/Actor.js",
39 "YUI-extensions/anim/Animator.js",
40 "YUI-extensions/dd/Registry.js",
41 "YUI-extensions/dd/ScrollManager.js",
42 "YUI-extensions/dd/StatusProxy.js",
43 "YUI-extensions/layout/ContentPanels.js",
44 "YUI-extensions/layout/LayoutManager.js",
45 "YUI-extensions/layout/BorderLayout.js",
46 "YUI-extensions/layout/BasicLayoutRegion.js",
47 "YUI-extensions/layout/LayoutRegion.js",
48 "YUI-extensions/layout/LayoutStateManager.js",
49 "YUI-extensions/layout/SplitLayoutRegion.js",
50 "YUI-extensions/layout/BorderLayoutRegions.js",
51 "YUI-extensions/widgets/BasicDialog.js",
52 "YUI-extensions/widgets/Button.js",
53 "YUI-extensions/widgets/MessageBox.js",
54 "YUI-extensions/widgets/Resizable.js",
55 "YUI-extensions/widgets/SplitBar.js",
56 "YUI-extensions/widgets/TabPanel.js",
57 "YUI-extensions/widgets/TemplateView.js",
58 "YUI-extensions/widgets/Toolbar.js",
59 "YUI-extensions/widgets/InlineEditor.js",
60 "YUI-extensions/widgets/QuickTips.js",
61 "YUI-extensions/CSS.js",
62
63 "JSON/json2.js",
64
65 "Clipperz/ByteArray.js",
66 "Clipperz/Base.js",
67 "Clipperz/CSVProcessor.js",
68 "Clipperz/KeePassExportProcessor.js",
69 "Clipperz/Date.js",
70 "Clipperz/DOM.js",
71 "Clipperz/Signal.js",
72 "Clipperz/Style.js",
73 "Clipperz/Set.js",
74 "Clipperz/NotificationCenter.js",
75 "Clipperz/Crypto/SHA.js",
76 "Clipperz/Crypto/AES.js",
77 "Clipperz/Crypto/PRNG.js",
78 "Clipperz/Crypto/BigInt.js",
79 "Clipperz/Crypto/Base.js",
80 "Clipperz/Crypto/SRP.js",
81 "Clipperz/Crypto/RSA.js",
82 "Clipperz/PM/Strings/Strings_en-US.js",
83 "Clipperz/PM/Strings/Strings_it-IT.js",
84 "Clipperz/PM/Strings/Strings_pt-BR.js",
85 "Clipperz/PM/Strings/Strings_ja-JP.js",
86 "Clipperz/PM/Strings/Strings_zh-CN.js",
87 "Clipperz/PM/Strings/Strings_es-ES.js",
88 "Clipperz/PM/Strings/Strings_fr-FR.js",
89 "Clipperz/PM/Strings.js",
90 "Clipperz/PM/Strings/MessagePanelConfigurations.js",
91 "Clipperz/PM/Date.js",
92 "Clipperz/PM/Components/BaseComponent.js",
93 "Clipperz/PM/Components/MessageBox.js",
94 "Clipperz/PM/Components/TextFormField.js",
95 "Clipperz/PM/Components/PasswordEntropyDisplay.js",
96 "Clipperz/PM/Components/PasswordGenerator.js",
97 "Clipperz/PM/Components/Panels/BasePanel.js",
98 "Clipperz/PM/Components/Panels/LoginPanel.js",
99 "Clipperz/PM/Components/Panels/MainPanel.js",
100 "Clipperz/PM/Components/Panels/AccountPanel.js",
101 "Clipperz/PM/Components/Panels/DataPanel.js",
102 "Clipperz/PM/Components/Panels/ContactsPanel.js",
103 "Clipperz/PM/Components/Panels/ToolsPanel.js",
104 "Clipperz/PM/Components/Panels/LogoutPanel.js",
105 "Clipperz/PM/Components/RecordDetail/MainComponent.js",
106 "Clipperz/PM/Components/RecordDetail/AbstractComponent.js",
107 "Clipperz/PM/Components/RecordDetail/HeaderComponent.js",
108 "Clipperz/PM/Components/RecordDetail/TitleComponent.js",
109 "Clipperz/PM/Components/RecordDetail/NotesComponent.js",
110 "Clipperz/PM/Components/RecordDetail/FieldComponent.js",
111 "Clipperz/PM/Components/RecordDetail/AbstractFieldSubComponent.js",
112 "Clipperz/PM/Components/RecordDetail/FieldButtonComponent.js",
113 "Clipperz/PM/Components/RecordDetail/FieldLabelComponent.js",
114 "Clipperz/PM/Components/RecordDetail/FieldDragHandler.js",
115 "Clipperz/PM/Components/RecordDetail/FieldValueComponent.js",
116 "Clipperz/PM/Components/RecordDetail/FieldTypeComponent.js",
117 "Clipperz/PM/Components/RecordDetail/DirectLoginsComponent.js",
118 "Clipperz/PM/Components/RecordDetail/DirectLoginComponent.js",
119 "Clipperz/PM/Components/RecordDetail/DirectLoginBindingComponent.js",
120 "Clipperz/PM/Components/RecordDetail/DirectLoginValueComponent.js",
121 "Clipperz/PM/Components/RecordDetail/CreationWizard.js",
122 "Clipperz/PM/Components/TabPanel/TabPanelController.js",
123 "Clipperz/PM/Components/Import/MainComponent.js",
124 "Clipperz/PM/Components/Import/GenericImportComponent.js",
125 "Clipperz/PM/Components/Import/CSVImportComponent.js",
126 "Clipperz/PM/Components/Import/CSVImport/CSVImportColumns.js",
127 "Clipperz/PM/Components/Import/CSVImport/CSVImportHeader.js",
128 "Clipperz/PM/Components/Import/CSVImport/CSVImportTitle.js",
129 "Clipperz/PM/Components/Import/CSVImport/CSVImportNotes.js",
130 "Clipperz/PM/Components/Import/CSVImport/CSVImportFields.js",
131 "Clipperz/PM/Components/Import/ExcelImportComponent.js",
132 "Clipperz/PM/Components/Import/PasswordPlusImportComponent.js",
133 "Clipperz/PM/Components/Import/ClipperzImportComponent.js",
134 "Clipperz/PM/Components/Import/RoboFormImportComponent.js",
135 "Clipperz/PM/Components/Import/KeePassImportComponent.js",
136 "Clipperz/PM/Components/Printing/Header.js",
137 "Clipperz/PM/Components/Printing/Record.js",
138 "Clipperz/PM/Components/Printing/Footer.js",
139 "Clipperz/PM/Components/OTP/MainComponent.js",
140 "Clipperz/PM/Components/Compact/CompactHeader.js",
141 "Clipperz/PM/Components/Compact/LoginForm.js",
142 "Clipperz/PM/Components/Compact/CompactInterface.js",
143 "Clipperz/PM/Toll.js",
144 "Clipperz/PM/Proxy.js",
145 "Clipperz/PM/Proxy/Proxy.JSON.js",
146 "Clipperz/PM/Proxy/Proxy.Offline.js",
147 "Clipperz/PM/Proxy/Proxy.Offline.DataStore.js",
148 "Clipperz/PM/Connection.js",
149 "Clipperz/PM/Crypto.js",
150 "Clipperz/PM/BookmarkletProcessor.js",
151 "Clipperz/PM/DataModel/User.js",
152 "Clipperz/PM/DataModel/UserPreferences.js",
153 "Clipperz/PM/DataModel/Header.js",
154 "Clipperz/PM/DataModel/Statistics.js",
155 "Clipperz/PM/DataModel/Record.js",
156 "Clipperz/PM/DataModel/RecordField.js",
157 "Clipperz/PM/DataModel/RecordVersion.js",
158 "Clipperz/PM/DataModel/DirectLogin.js",
159 "Clipperz/PM/DataModel/DirectLoginReference.js",
160 "Clipperz/PM/DataModel/DirectLoginInput.js",
161 "Clipperz/PM/DataModel/DirectLoginBinding.js",
162 "Clipperz/PM/DataModel/OneTimePasswordManager.js",
163 "Clipperz/PM/DataModel/OneTimePassword.js",
164 "Clipperz/YUI/IBLayoutManager.js",
165 "Clipperz/YUI/IBLayoutRegion.js",
166 "Clipperz/YUI/Drawer.js",
167 "Clipperz/YUI/Collapser.js",
168 "Clipperz/YUI/MessageBox.js",
169 "Clipperz/YUI/DomHelper.js",
170
171 "Clipperz/PM/Main.js"
172 ],
173
174 "css": [
175 "yui-extensions/reset-min.css",
176 "yui-extensions/core.css",
177 "yui-extensions/basic-dialog.css",
178 "yui-extensions/button.css",
179 "clipperz/clipperz.css",
180 "clipperz/compact.css",
181 "clipperz/ytheme-clipperz.css"
182 ]
183} \ No newline at end of file
diff --git a/frontend/beta/properties/creditsAndCopyrights.txt b/frontend/beta/properties/creditsAndCopyrights.txt
new file mode 100644
index 0000000..c4548b3
--- a/dev/null
+++ b/frontend/beta/properties/creditsAndCopyrights.txt
@@ -0,0 +1,335 @@
1@clipperz.license@
2
3===============================================================================
4
5 This application is build using also the following libraries
6
7# MochiKit (http://www.mochikit.com)
8 - repository: @mochikit.repository@ (revision: @mochikit.version@)
9
10 * Software licence: http://svn.mochikit.com/mochikit/trunk/licence.txt
11
12 |MochiKit is dual-licensed software. It is available under the terms of the
13 |MIT License, or the Academic Free License version 2.1. The full text of
14 |each license is included below.
15 |
16 |MIT License
17 |===========
18 |
19 |Copyright (c) 2005 Bob Ippolito. All rights reserved.
20 |
21 |Permission is hereby granted, free of charge, to any person obtaining a copy of this
22 |software and associated documentation files (the "Software"), to deal in the Software
23 |without restriction, including without limitation the rights to use, copy, modify,
24 |merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
25 |permit persons to whom the Software is furnished to do so, subject to the following
26 |conditions:
27 |
28 |The above copyright notice and this permission notice shall be included in all copies
29 |or substantial portions of the Software.
30 |
31 |THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
32 |INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
33 |PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
34 |FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
35 |OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
36 |DEALINGS IN THE SOFTWARE.
37 |
38 |
39 |Academic Free License v. 2.1
40 |============================
41 |
42 |Copyright (c) 2005 Bob Ippolito. All rights reserved.
43 |
44 |This Academic Free License (the "License") applies to any original work of authorship (the
45 |"Original Work") whose owner (the "Licensor") has placed the following notice immediately
46 |following the copyright notice for the Original Work:
47 |
48 |Licensed under the Academic Free License version 2.1
49 |
50 |1) Grant of Copyright License. Licensor hereby grants You a world-wide, royalty-free,
51 |non-exclusive, perpetual, sublicenseable license to do the following:
52 |
53 |a) to reproduce the Original Work in copies;
54 |b) to prepare derivative works ("Derivative Works") based upon the Original Work;
55 |c) to distribute copies of the Original Work and Derivative Works to the public;
56 |d) to perform the Original Work publicly; and
57 |e) to display the Original Work publicly.
58 |
59 |2) Grant of Patent License. Licensor hereby grants You a world-wide, royalty-free,
60 |non-exclusive, perpetual, sublicenseable license, under patent claims owned or controlled
61 |by the Licensor that are embodied in the Original Work as furnished by the Licensor, to
62 |make, use, sell and offer for sale the Original Work and Derivative Works.
63 |
64 |3) Grant of Source Code License. The term "Source Code" means the preferred form of the
65 |Original Work for making modifications to it and all available documentation describing
66 |how to modify the Original Work. Licensor hereby agrees to provide a machine-readable copy
67 |of the Source Code of the Original Work along with each copy of the Original Work that
68 |Licensor distributes. Licensor reserves the right to satisfy this obligation by placing
69 |a machine-readable copy of the Source Code in an information repository reasonably
70 |calculated to permit inexpensive and convenient access by You for as long as Licensor
71 |continues to distribute the Original Work, and by publishing the address of that information
72 |repository in a notice immediately following the copyright notice that applies to the Original
73 |Work.
74 |
75 |4) Exclusions From License Grant. Neither the names of Licensor, nor the names of any
76 |contributors to the Original Work, nor any of their trademarks or service marks, may be used
77 |to endorse or promote products derived from this Original Work without express prior written
78 |permission of the Licensor. Nothing in this License shall be deemed to grant any rights to
79 |trademarks, copyrights, patents, trade secrets or any other intellectual property of Licensor
80 |except as expressly stated herein. No patent license is granted to make, use, sell or offer
81 |to sell embodiments of any patent claims other than the licensed claims defined in Section 2.
82 |No right is granted to the trademarks of Licensor even if such marks are included in the Original
83 |Work. Nothing in this License shall be interpreted to prohibit Licensor from licensing under
84 |different terms from this License any Original Work that Licensor otherwise would have a right
85 |to license.
86 |
87 |5) This section intentionally omitted.
88 |
89 |6) Attribution Rights. You must retain, in the Source Code of any Derivative Works that You
90 |create, all copyright, patent or trademark notices from the Source Code of the Original Work,
91 |as well as any notices of licensing and any descriptive text identified therein as an "Attribution
92 |Notice." You must cause the Source Code for any Derivative Works that You create to carry a
93 |prominent Attribution Notice reasonably calculated to inform recipients that You have modified the
94 |Original Work.
95 |
96 |7) Warranty of Provenance and Disclaimer of Warranty. Licensor warrants that the copyright in and
97 |to the Original Work and the patent rights granted herein by Licensor are owned by the Licensor or
98 |are sublicensed to You under the terms of this License with the permission of the contributor(s)
99 |of those copyrights and patent rights. Except as expressly stated in the immediately proceeding
100 |sentence, the Original Work is provided under this License on an "AS IS" BASIS and WITHOUT WARRANTY,
101 |either express or implied, including, without limitation, the warranties of NON-INFRINGEMENT,
102 |MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY OF THE ORIGINAL
103 |WORK IS WITH YOU. This DISCLAIMER OF WARRANTY constitutes an essential part of this License. No license
104 |to Original Work is granted hereunder except under this disclaimer.
105 |
106 |8) Limitation of Liability. Under no circumstances and under no legal theory, whether in tort (including
107 |negligence), contract, or otherwise, shall the Licensor be liable to any person for any direct, indirect,
108 |special, incidental, or consequential damages of any character arising as a result of this License or the
109 |use of the Original Work including, without limitation, damages for loss of goodwill, work stoppage,
110 |computer failure or malfunction, or any and all other commercial damages or losses. This limitation of
111 |liability shall not apply to liability for death or personal injury resulting from Licensor's negligence
112 |to the extent applicable law prohibits such limitation. Some jurisdictions do not allow the exclusion or
113 |limitation of incidental or consequential damages, so this exclusion and limitation may not apply to You.
114 |
115 |9) Acceptance and Termination. If You distribute copies of the Original Work or a Derivative Work, You must
116 |make a reasonable effort under the circumstances to obtain the express assent of recipients to the terms of
117 |this License. Nothing else but this License (or another written agreement between Licensor and You) grants
118 |You permission to create Derivative Works based upon the Original Work or to exercise any of the rights
119 |granted in Section 1 herein, and any attempt to do so except under the terms of this License (or another
120 |written agreement between Licensor and You) is expressly prohibited by U.S. copyright law, the equivalent
121 |laws of other countries, and by international treaty. Therefore, by exercising any of the rights granted
122 |to You in Section 1 herein, You indicate Your acceptance of this License and all of its terms and conditions.
123 |
124 |10) Termination for Patent Action. This License shall terminate automatically and You may no longer exercise
125 |any of the rights granted to You by this License as of the date You commence an action, including a cross-claim
126 |or counterclaim, against Licensor or any licensee alleging that the Original Work infringes a patent. This
127 |termination provision shall not apply for an action alleging patent infringement by combinations of the Original
128 |Work with other software or hardware.
129 |
130 |11) Jurisdiction, Venue and Governing Law. Any action or suit relating to this License may be brought only in
131 |the courts of a jurisdiction wherein the Licensor resides or in which Licensor conducts its primary business,
132 |and under the laws of that jurisdiction excluding its conflict-of-law provisions. The application of the United
133 |Nations Convention on Contracts for the International Sale of Goods is expressly excluded. Any use of the
134 |Original Work outside the scope of this License or after its termination shall be subject to the requirements
135 |and penalties of the U.S. Copyright Act, 17 U.S.C. § 101 et seq., the equivalent laws of other countries,
136 |and international treaty. This section shall survive the termination of this License.
137 |
138 |12) Attorneys Fees. In any action to enforce the terms of this License or seeking damages
139 |relating thereto, the prevailing party shall be entitled to recover its costs and expenses,
140 |including, without limitation, reasonable attorneys' fees and costs incurred in connection
141 |with such action, including any appeal of such action. This section shall survive the
142 |termination of this License.
143 |
144 |13) Miscellaneous. This License represents the complete agreement concerning the subject
145 |matter hereof. If any provision of this License is held to be unenforceable, such provision
146 |shall be reformed only to the extent necessary to make it enforceable.
147 |
148 |14) Definition of "You" in This License. "You" throughout this License, whether in upper
149 |or lower case, means an individual or a legal entity exercising rights under, and complying
150 |with all of the terms of, this License. For legal entities, "You" includes any entity that
151 |controls, is controlled by, or is under common control with you. For purposes of this
152 |definition, "control" means (i) the power, direct or indirect, to cause the direction or
153 |management of such entity, whether by contract or otherwise, or (ii) ownership of fifty
154 |percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity.
155 |
156 |15) Right to Use. You may use the Original Work in all ways not otherwise restricted or
157 |conditioned by this License or by law, and Licensor promises not to interfere with or be
158 |responsible for such uses by You.
159 |
160 |This license is Copyright (C) 2003-2004 Lawrence E. Rosen. All rights reserved. Permission
161 |is hereby granted to copy and distribute this license without modification. This license
162 |may not be modified without the express written permission of its copyright owner.
163
164
165# Yahoo! UI Library (http://developer.yahoo.com/yui/)
166 - package version: 0.12
167
168 Copyright © 2005-2006 Yahoo! Inc. All rights reserved
169 * Copyright notes: http://docs.yahoo.com/info/copyright/copyright.html
170 * Software licence: http://developer.yahoo.com/yui/license.txt
171
172 |Software License Agreement (BSD License)
173 |
174 |Copyright (c) 2006, Yahoo! Inc.
175 |All rights reserved.
176 |
177 |Redistribution and use of this software in source and binary forms, with or without modification, are
178 |permitted provided that the following conditions are met:
179 |
180 |* Redistributions of source code must retain the above
181 | copyright notice, this list of conditions and the
182 | following disclaimer.
183 |
184 |* Redistributions in binary form must reproduce the above
185 | copyright notice, this list of conditions and the
186 | following disclaimer in the documentation and/or other
187 | materials provided with the distribution.
188 |
189 |* Neither the name of Yahoo! Inc. nor the names of its
190 | contributors may be used to endorse or promote products
191 | derived from this software without specific prior
192 | written permission of Yahoo! Inc.
193 |
194 |THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
195 |WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
196 |PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
197 |ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
198 |LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
199 |INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
200 |TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
201 |ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
202
203
204
205# YUI-ext (http://www.yui-ext.com)
206 - repository: http://yui-ext.googlecode.com/svn/trunk/ (revision: 120)
207
208 * Software licence: http://yui-ext.googlecode.com/svn/trunk/src/licence.txt
209
210 |yui-ext
211 |Copyright (c) 2006, Jack Slocum
212 |All rights reserved.
213 |
214 |Redistribution and use in source and binary forms, with or without modification,
215 |are permitted provided that the following conditions are met:
216 |
217 | * Redistributions of source code must retain the above copyright notice,
218 | this list of conditions and the following disclaimer.
219 | * Redistributions in binary form must reproduce the above copyright notice,
220 | this list of conditions and the following disclaimer in the documentation
221 | and/or other materials provided with the distribution.
222 | * Neither the name yui-ext nor the names of its contributors
223 | may be used to endorse or promote products derived from this software
224 | without specific prior written permission.
225 |
226 |THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
227 |ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
228 |WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
229 |IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
230 |INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
231 |BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
232 |DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
233 |OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
234 |NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
235 |EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
236
237
238
239# iUI: iPhone User Interface Framework (http://code.google.com/p/iui/)
240 - package version: 282
241
242 Copyright (c) 2007-2009, iUI Project Members
243
244 |All rights reserved.
245 |
246 |Redistribution and use in source and binary forms, with or without modification,
247 |are permitted provided that the following conditions are met:
248 |
249 | * Redistributions of source code must retain the above copyright notice, this
250 | list of conditions and the following disclaimer.
251 | * Redistributions in binary form must reproduce the above copyright notice,
252 | this list of conditions and the following disclaimer in the documentation
253 | and/or other materials provided with the distribution.
254 | * Neither the name of the iUI Project nor the names of its contributors may
255 | be used to endorse or promote products derived from this software without
256 | specific prior written permission.
257 |
258 |THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
259 |"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
260 |LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
261 |A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
262 |CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
263 |EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
264 |PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
265 |PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
266 |LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
267 |NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
268 |SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
269
270
271
272# Big Integer Library v. 5.0
273 - code downloaded on March 5, 2007 from http://www.leemon.com/crypto/BigInt.js
274
275 |Big Integer Library v. 5.0
276 |Created 2000, last modified 2006
277 |Leemon Baird
278 |www.leemon.com
279 |
280 |This file is public domain. You can use it for any purpose without restriction.
281 |I do not guarantee that it is correct, so use it at your own risk. If you use
282 |it for something interesting, I'd appreciate hearing about it. If you find
283 |any bugs or make any improvements, I'd appreciate hearing about those too.
284 |It would also be nice if my name and address were left in the comments.
285 |But none of that is required.
286
287
288
289# JSON library
290 - code downloaded on October 13, 2008 from http://www.JSON.org/json2.js
291
292 |http://www.JSON.org/json2.js
293 |2008-09-01
294 |
295 |Public Domain.
296 |
297 |NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.
298 |
299 |See http://www.JSON.org/js.html
300
301
302
303# Other code snippets used in the first demo of the program, and still present just to be able to
304 read record previously written using these same functions:
305
306 - Code downloaded on March 30, 2006 from http://anmar.eu.org/projects/jssha2/files/jssha2-0.3.zip
307 File used: jsSha2/sha256.js
308
309 |A JavaScript implementation of the Secure Hash Algorithm, SHA-256
310 |Version 0.3 Copyright Angel Marin 2003-2004 - http://anmar.eu.org/
311 |Distributed under the BSD License
312 |Some bits taken from Paul Johnston's SHA-1 implementation
313
314
315 - Code downloaded on March 30, 2006 from http://www.fourmilab.ch/javascrypt/javascrypt.zip
316 Files used: entropy.js, aesprng.js, md5.js, aes.js, utf-8.js
317
318
319 - Code downloaded on April 26, 2006 from http://pajhome.org.uk/crypt/md5/md5.js
320
321 |A JavaScript implementation of the RSA Data Security, Inc. MD5 Message
322 |Digest Algorithm, as defined in RFC 1321.
323 |Version 2.1 Copyright (C) Paul Johnston 1999 - 2002.
324 |Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
325 |Distributed under the BSD License
326 |See http://pajhome.org.uk/crypt/md5 for more info.
327
328
329
330 #General notes
331 The code in this page has been processed with a JavaScript compressor and is thus
332 difficult to read.
333 To get the exact version of the code used to build this application you
334 can take a look here:
335 - http://www.clipperz.com/security_privacy/security_code_review