diff --git a/.hgignore b/.hgignore index 4a0311dcc..125eff13c 100644 --- a/.hgignore +++ b/.hgignore @@ -206,3 +206,5 @@ code/ryzom/server/src/ryzom_admin_service/ryzom_admin_service code/ryzom/server/src/ryzom_naming_service/ryzom_naming_service code/ryzom/server/src/ryzom_welcome_service/ryzom_welcome_service code/ryzom/server/src/tick_service/tick_service +# WebTT temp dir +code/ryzom/tools/server/www/webtt/app/tmp diff --git a/code/ryzom/tools/server/www/webtt/app/config/core.php b/code/ryzom/tools/server/www/webtt/app/config/core.php index 517e32d0d..6bd8d65c6 100644 --- a/code/ryzom/tools/server/www/webtt/app/config/core.php +++ b/code/ryzom/tools/server/www/webtt/app/config/core.php @@ -85,7 +85,7 @@ * * [Note Routing.admin is deprecated in 1.3. Use Routing.prefixes instead] */ - //Configure::write('Routing.prefixes', array('admin')); + Configure::write('Routing.prefixes', array('admin')); /** * Turn off all caching application-wide. @@ -201,12 +201,12 @@ /** * A random string used in security hashing methods. */ - Configure::write('Security.salt', 'DYhG93b0qyJfIxfs2guVoUubWwvniR2G0FgaC9mi'); + Configure::write('Security.salt', '3928c5uM398u4R39m4u8c3m493U49'); /** * A random numeric string (digits only) used to encrypt/decrypt strings. */ - Configure::write('Security.cipherSeed', '76859309657453542496749683645'); + Configure::write('Security.cipherSeed', '849713027853098175087095830289'); /** * Apply timestamps with the last modified time to static assets (js, css, images). diff --git a/code/ryzom/tools/server/www/webtt/app/config/database.php b/code/ryzom/tools/server/www/webtt/app/config/database.php new file mode 100644 index 000000000..ca5057ba0 --- /dev/null +++ b/code/ryzom/tools/server/www/webtt/app/config/database.php @@ -0,0 +1,18 @@ + 'mysqli', + 'persistent' => false, + 'host' => 'localhost', + 'login' => 'webtt', + 'password' => 'webtt77', + 'database' => 'webtt2', + 'encoding' => 'y' + ); + var $raw_files = array( + 'driver' => "", + 'datasource' => 'raw_files', + ); +} +?> \ No newline at end of file diff --git a/code/ryzom/tools/server/www/webtt/app/controllers/app_controller.php b/code/ryzom/tools/server/www/webtt/app/controllers/app_controller.php new file mode 100644 index 000000000..458137748 --- /dev/null +++ b/code/ryzom/tools/server/www/webtt/app/controllers/app_controller.php @@ -0,0 +1,37 @@ +FileIdentifier->recursive = 0; + $this->set('fileIdentifiers', $this->paginate()); + } + + function view($id = null) { + if (!$id) { + $this->Session->setFlash(__('Invalid file identifier', true)); + $this->redirect(array('action' => 'index')); + } + $this->set('fileIdentifier', $this->FileIdentifier->read(null, $id)); + } + + function add() { + if (!empty($this->data)) { + $this->FileIdentifier->create(); + if ($this->FileIdentifier->save($this->data)) { + $this->Session->setFlash(__('The file identifier has been saved', true)); + $this->redirect(array('action' => 'index')); + } else { + $this->Session->setFlash(__('The file identifier could not be saved. Please, try again.', true)); + } + } + $translationFiles = $this->FileIdentifier->TranslationFile->find('list'); + $identifiers = $this->FileIdentifier->Identifier->find('list'); + $this->set(compact('translationFiles', 'identifiers')); + } + + function edit($id = null) { + if (!$id && empty($this->data)) { + $this->Session->setFlash(__('Invalid file identifier', true)); + $this->redirect(array('action' => 'index')); + } + if (!empty($this->data)) { + if ($this->FileIdentifier->save($this->data)) { + $this->Session->setFlash(__('The file identifier has been saved', true)); + $this->redirect(array('action' => 'index')); + } else { + $this->Session->setFlash(__('The file identifier could not be saved. Please, try again.', true)); + } + } + if (empty($this->data)) { + $this->data = $this->FileIdentifier->read(null, $id); + } + $translationFiles = $this->FileIdentifier->TranslationFile->find('list'); + $identifiers = $this->FileIdentifier->Identifier->find('list'); + $this->set(compact('translationFiles', 'identifiers')); + } + + function delete($id = null) { + if (!$id) { + $this->Session->setFlash(__('Invalid id for file identifier', true)); + $this->redirect(array('action'=>'index')); + } + if ($this->FileIdentifier->delete($id)) { + $this->Session->setFlash(__('File identifier deleted', true)); + $this->redirect(array('action'=>'index')); + } + $this->Session->setFlash(__('File identifier was not deleted', true)); + $this->redirect(array('action' => 'index')); + } + function admin_index() { + $this->FileIdentifier->recursive = 0; + $this->set('fileIdentifiers', $this->paginate()); + } + + function admin_view($id = null) { + if (!$id) { + $this->Session->setFlash(__('Invalid file identifier', true)); + $this->redirect(array('action' => 'index')); + } + $this->set('fileIdentifier', $this->FileIdentifier->read(null, $id)); + } + + function admin_add() { + if (!empty($this->data)) { + $this->FileIdentifier->create(); + if ($this->FileIdentifier->save($this->data)) { + $this->Session->setFlash(__('The file identifier has been saved', true)); + $this->redirect(array('action' => 'index')); + } else { + $this->Session->setFlash(__('The file identifier could not be saved. Please, try again.', true)); + } + } + $translationFiles = $this->FileIdentifier->TranslationFile->find('list'); + $identifiers = $this->FileIdentifier->Identifier->find('list'); + $this->set(compact('translationFiles', 'identifiers')); + } + + function admin_edit($id = null) { + if (!$id && empty($this->data)) { + $this->Session->setFlash(__('Invalid file identifier', true)); + $this->redirect(array('action' => 'index')); + } + if (!empty($this->data)) { + if ($this->FileIdentifier->save($this->data)) { + $this->Session->setFlash(__('The file identifier has been saved', true)); + $this->redirect(array('action' => 'index')); + } else { + $this->Session->setFlash(__('The file identifier could not be saved. Please, try again.', true)); + } + } + if (empty($this->data)) { + $this->data = $this->FileIdentifier->read(null, $id); + } + $translationFiles = $this->FileIdentifier->TranslationFile->find('list'); + $identifiers = $this->FileIdentifier->Identifier->find('list'); + $this->set(compact('translationFiles', 'identifiers')); + } + + function admin_delete($id = null) { + if (!$id) { + $this->Session->setFlash(__('Invalid id for file identifier', true)); + $this->redirect(array('action'=>'index')); + } + if ($this->FileIdentifier->delete($id)) { + $this->Session->setFlash(__('File identifier deleted', true)); + $this->redirect(array('action'=>'index')); + } + $this->Session->setFlash(__('File identifier was not deleted', true)); + $this->redirect(array('action' => 'index')); + } +} diff --git a/code/ryzom/tools/server/www/webtt/app/controllers/identifiers_controller.php b/code/ryzom/tools/server/www/webtt/app/controllers/identifiers_controller.php new file mode 100644 index 000000000..cae46aa55 --- /dev/null +++ b/code/ryzom/tools/server/www/webtt/app/controllers/identifiers_controller.php @@ -0,0 +1,124 @@ +Identifier->recursive = 0; + $this->set('identifiers', $this->paginate()); + } + + function view($id = null) { + if (!$id) { + $this->Session->setFlash(__('Invalid identifier', true)); + $this->redirect(array('action' => 'index')); + } + $this->set('identifier', $this->Identifier->read(null, $id)); + } + + function add() { + if (!empty($this->data)) { + $this->Identifier->create(); + if ($this->Identifier->save($this->data)) { + $this->Session->setFlash(__('The identifier has been saved', true)); + $this->redirect(array('action' => 'index')); + } else { + $this->Session->setFlash(__('The identifier could not be saved. Please, try again.', true)); + } + } + $languages = $this->Identifier->Language->find('list'); + $this->set(compact('languages')); + } + + function edit($id = null) { + if (!$id && empty($this->data)) { + $this->Session->setFlash(__('Invalid identifier', true)); + $this->redirect(array('action' => 'index')); + } + if (!empty($this->data)) { + if ($this->Identifier->save($this->data)) { + $this->Session->setFlash(__('The identifier has been saved', true)); + $this->redirect(array('action' => 'index')); + } else { + $this->Session->setFlash(__('The identifier could not be saved. Please, try again.', true)); + } + } + if (empty($this->data)) { + $this->data = $this->Identifier->read(null, $id); + } + $languages = $this->Identifier->Language->find('list'); + $this->set(compact('languages')); + } + + function delete($id = null) { + if (!$id) { + $this->Session->setFlash(__('Invalid id for identifier', true)); + $this->redirect(array('action'=>'index')); + } + if ($this->Identifier->delete($id)) { + $this->Session->setFlash(__('Identifier deleted', true)); + $this->redirect(array('action'=>'index')); + } + $this->Session->setFlash(__('Identifier was not deleted', true)); + $this->redirect(array('action' => 'index')); + } + function admin_index() { + $this->Identifier->recursive = 0; + $this->set('identifiers', $this->paginate()); + } + + function admin_view($id = null) { + if (!$id) { + $this->Session->setFlash(__('Invalid identifier', true)); + $this->redirect(array('action' => 'index')); + } + $this->set('identifier', $this->Identifier->read(null, $id)); + } + + function admin_add() { + if (!empty($this->data)) { + $this->Identifier->create(); + if ($this->Identifier->save($this->data)) { + $this->Session->setFlash(__('The identifier has been saved', true)); + $this->redirect(array('action' => 'index')); + } else { + $this->Session->setFlash(__('The identifier could not be saved. Please, try again.', true)); + } + } + $languages = $this->Identifier->Language->find('list'); + $this->set(compact('languages')); + } + + function admin_edit($id = null) { + if (!$id && empty($this->data)) { + $this->Session->setFlash(__('Invalid identifier', true)); + $this->redirect(array('action' => 'index')); + } + if (!empty($this->data)) { + if ($this->Identifier->save($this->data)) { + $this->Session->setFlash(__('The identifier has been saved', true)); + $this->redirect(array('action' => 'index')); + } else { + $this->Session->setFlash(__('The identifier could not be saved. Please, try again.', true)); + } + } + if (empty($this->data)) { + $this->data = $this->Identifier->read(null, $id); + } + $languages = $this->Identifier->Language->find('list'); + $this->set(compact('languages')); + } + + function admin_delete($id = null) { + if (!$id) { + $this->Session->setFlash(__('Invalid id for identifier', true)); + $this->redirect(array('action'=>'index')); + } + if ($this->Identifier->delete($id)) { + $this->Session->setFlash(__('Identifier deleted', true)); + $this->redirect(array('action'=>'index')); + } + $this->Session->setFlash(__('Identifier was not deleted', true)); + $this->redirect(array('action' => 'index')); + } +} diff --git a/code/ryzom/tools/server/www/webtt/app/controllers/imported_translation_files_controller.php b/code/ryzom/tools/server/www/webtt/app/controllers/imported_translation_files_controller.php new file mode 100644 index 000000000..77576c003 --- /dev/null +++ b/code/ryzom/tools/server/www/webtt/app/controllers/imported_translation_files_controller.php @@ -0,0 +1,209 @@ +ImportedTranslationFile->recursive = 0; + $this->set('importedTranslationFiles', $this->paginate()); + } + + function view($id = null) { + if (!$id) { + $this->Session->setFlash(__('Invalid translation file', true)); + $this->redirect(array('action' => 'index')); + } + $this->set('importedTranslationFile', $this->ImportedTranslationFile->read(null, $id)); +// var_dump($this->ImportedTranslationFile->RawFile); + } + + function admin_import($filename = null) { +// $this->view = "index"; + App::import("Vendor","UxtParser", array("file" => 'UxtParser.php')); +/* if (!$filename) { + $this->Session->setFlash(__('Invalid file', true)); + $this->redirect(array('action' => 'index')); + return 0; + }*/ + $filename="diff/pl_diff_4DEC868A.uxt"; + $translationFile = $this->ImportedTranslationFile->find('first', array('conditions' => array('ImportedTranslationFile.filename' => $filename))); + if ($translationFile) + { + $this->Session->setFlash(__('Translation file already imported', true)); + $this->redirect(array('action' => 'index')); + return 0; + } +// var_dump($file); + $parser = new UxtParser(); + $parsedFile = $parser->parseFile($filename); +// var_dump($parsedFile); + $arr = explode("_", basename($filename, ".uxt")); +// var_dump($arr); + $language_id = 1; + + $this->ImportedTranslationFile->create(); + $data['ImportedTranslationFile']['language_id'] = $language_id; + $data['ImportedTranslationFile']['filename'] = $filename; + //$this->ImportedTranslationFile->save($data); + foreach ($parsedFile as $ent) + { + $fi_data = array(); + if ($ent['type'] != "string") + continue; + + + $i_data['language_id'] = $language_id; + $i_data['translation_index'] = $ent['index']; + $i_data['reference_string'] = $ent['string']; + unset($this->ImportedTranslationFile->Language->Identifier->id); + $identifier = $this->ImportedTranslationFile->Language->Identifier->find('first',array('conditions' => array('Identifier.identifier' => $ent['identifier'], 'Identifier.language_id' => $language_id))); + if ($identifier) + { +// var_dump($identifier); + $i_data['id']=$identifier['Identifier']['id']; + } + else + { + $i_data['identifier'] = $ent['identifier']; + $i_data['translated'] = false; + } + var_dump($i_data); + $this->ImportedTranslationFile->Language->Identifier->save(array('Identifier' => $i_data)); + $identifier_id = $this->ImportedTranslationFile->Language->Identifier->id; + var_dump($identifier_id); + + unset($this->ImportedTranslationFile->FileIdentifier->id); + //TODO - set FileIdentifier['id'] if we import already imported file (imported imported file temporarly disabled) +// $identifier = $this->ImportedTranslationFile->FileIdentifier->find('first',array('conditions' => array('FileIdentifier.identifier' => $ent['identifier'], 'FileIdentifier.translation_file_id' => $))); +// $data['FileIdentifier']['translation_file_id'] = $this->ImportedTranslationFile->id; + if ($ent['diff']) + $fi_data['command'] = "DIFF " . mb_strtoupper($ent['diff']); + $fi_data['translation_index'] = $ent['index']; +// $data['FileIdentifier']['identifier_id'] = ; + $fi_data['reference_string'] = $ent['string']; + $fi_data['identifier_id'] = $identifier_id; + +// $this->ImportedTranslationFile->FileIdentifier->create(); +// $this->ImportedTranslationFile->FileIdentifier->save($data); + $data['FileIdentifier'][] = $fi_data; +// $l_data['Language']['id'] = $language_id; +// $l_data['Identifier'][] = $i_data; +// $data['Identifier'][] = $i_data; + } +// var_dump($data); +// $this->ImportedTranslationFile->Language->saveAll($l_data); + $this->ImportedTranslationFile->saveAll($data); + $this->Session->setFlash(__('Translation file imported', true)); + $this->redirect(array('action' => 'view', $this->ImportedTranslationFile->id)); + $this->ImportedTranslationFile->recursive = 0; + $this->set('importedTranslationFiles', $this->paginate()); +// $this->render('index'); + } + + + function add() { + if (!empty($this->data)) { + $this->ImportedTranslationFile->create(); + if ($this->ImportedTranslationFile->save($this->data)) { + $this->Session->setFlash(__('The translation file has been saved', true)); + $this->redirect(array('action' => 'index')); + } else { + $this->Session->setFlash(__('The translation file could not be saved. Please, try again.', true)); + } + } + $languages = $this->ImportedTranslationFile->Language->find('list'); + $this->set(compact('languages')); + } + + function edit($id = null) { + if (!$id && empty($this->data)) { + $this->Session->setFlash(__('Invalid translation file', true)); + $this->redirect(array('action' => 'index')); + } + if (!empty($this->data)) { + if ($this->ImportedTranslationFile->save($this->data)) { + $this->Session->setFlash(__('The translation file has been saved', true)); + $this->redirect(array('action' => 'index')); + } else { + $this->Session->setFlash(__('The translation file could not be saved. Please, try again.', true)); + } + } + if (empty($this->data)) { + $this->data = $this->ImportedTranslationFile->read(null, $id); + } + $languages = $this->ImportedTranslationFile->Language->find('list'); + $this->set(compact('languages')); + } + + function delete($id = null) { + if (!$id) { + $this->Session->setFlash(__('Invalid id for translation file', true)); + $this->redirect(array('action'=>'index')); + } + if ($this->ImportedTranslationFile->delete($id)) { + $this->Session->setFlash(__('Translation file deleted', true)); + $this->redirect(array('action'=>'index')); + } + $this->Session->setFlash(__('Translation file was not deleted', true)); + $this->redirect(array('action' => 'index')); + } + function admin_index() { + $this->ImportedTranslationFile->recursive = 0; + $this->set('importedTranslationFiles', $this->paginate()); + } + + function admin_view($id = null) { + if (!$id) { + $this->Session->setFlash(__('Invalid translation file', true)); + $this->redirect(array('action' => 'index')); + } + $this->set('translationFile', $this->ImportedTranslationFile->read(null, $id)); + } + + function admin_add() { + if (!empty($this->data)) { + $this->ImportedTranslationFile->create(); + if ($this->ImportedTranslationFile->save($this->data)) { + $this->Session->setFlash(__('The translation file has been saved', true)); + $this->redirect(array('action' => 'index')); + } else { + $this->Session->setFlash(__('The translation file could not be saved. Please, try again.', true)); + } + } + $languages = $this->ImportedTranslationFile->Language->find('list'); + $this->set(compact('languages')); + } + + function admin_edit($id = null) { + if (!$id && empty($this->data)) { + $this->Session->setFlash(__('Invalid translation file', true)); + $this->redirect(array('action' => 'index')); + } + if (!empty($this->data)) { + if ($this->ImportedTranslationFile->save($this->data)) { + $this->Session->setFlash(__('The translation file has been saved', true)); + $this->redirect(array('action' => 'index')); + } else { + $this->Session->setFlash(__('The translation file could not be saved. Please, try again.', true)); + } + } + if (empty($this->data)) { + $this->data = $this->ImportedTranslationFile->read(null, $id); + } + $languages = $this->ImportedTranslationFile->Language->find('list'); + $this->set(compact('languages')); + } + + function admin_delete($id = null) { + if (!$id) { + $this->Session->setFlash(__('Invalid id for translation file', true)); + $this->redirect(array('action'=>'index')); + } + if ($this->ImportedTranslationFile->delete($id)) { + $this->Session->setFlash(__('Translation file deleted', true)); + $this->redirect(array('action'=>'index')); + } + $this->Session->setFlash(__('Translation file was not deleted', true)); + $this->redirect(array('action' => 'index')); + } +} diff --git a/code/ryzom/tools/server/www/webtt/app/controllers/languages_controller.php b/code/ryzom/tools/server/www/webtt/app/controllers/languages_controller.php new file mode 100644 index 000000000..f88ee9739 --- /dev/null +++ b/code/ryzom/tools/server/www/webtt/app/controllers/languages_controller.php @@ -0,0 +1,121 @@ +Language->recursive = 0; + $this->set('languages', $this->paginate()); + } + + function view($id = null) { + if (!$id) { + $this->Session->setFlash(__('Invalid language', true)); + $this->redirect(array('action' => 'index')); + } + $this->set('language', $this->Language->read(null, $id)); + } + + function add() { + if (!empty($this->data)) { + $this->Language->create(); + if ($this->Language->save($this->data)) { + $this->Session->setFlash(__('The language has been saved', true)); + $this->redirect(array('action' => 'index')); + } else { + $this->Session->setFlash(__('The language could not be saved. Please, try again.', true)); + } + } + } + + function edit($id = null) { + if (!$id && empty($this->data)) { + $this->Session->setFlash(__('Invalid language', true)); + $this->redirect(array('action' => 'index')); + } + if (!empty($this->data)) { + if ($this->Language->save($this->data)) { + $this->Session->setFlash(__('The language has been saved', true)); + $this->redirect(array('action' => 'index')); + } else { + $this->Session->setFlash(__('The language could not be saved. Please, try again.', true)); + } + } + if (empty($this->data)) { + $this->data = $this->Language->read(null, $id); + } + } + + function delete($id = null) { + if (!$id) { + $this->Session->setFlash(__('Invalid id for language', true)); + $this->redirect(array('action'=>'index')); + } + if ($this->Language->delete($id)) { + $this->Session->setFlash(__('Language deleted', true)); + $this->redirect(array('action'=>'index')); + } + $this->Session->setFlash(__('Language was not deleted', true)); + $this->redirect(array('action' => 'index')); + } + function admin_index() { + $this->Language->recursive = 0; + $this->set('languages', $this->paginate()); + } + + function admin_view($id = null) { + if (!$id) { + $this->Session->setFlash(__('Invalid language', true)); + $this->redirect(array('action' => 'index')); + } + $this->set('language', $this->Language->read(null, $id)); + } + + function admin_add() { + if (!empty($this->data)) { + $this->Language->create(); + if ($this->Language->save($this->data)) { + $this->Session->setFlash(__('The language has been saved', true)); + $this->redirect(array('action' => 'index')); + } else { + $this->Session->setFlash(__('The language could not be saved. Please, try again.', true)); + } + } + } + + function admin_edit($id = null) { + if (!$id && empty($this->data)) { + $this->Session->setFlash(__('Invalid language', true)); + $this->redirect(array('action' => 'index')); + } + if (!empty($this->data)) { + if ($this->Language->save($this->data)) { + $this->Session->setFlash(__('The language has been saved', true)); + $this->redirect(array('action' => 'index')); + } else { + $this->Session->setFlash(__('The language could not be saved. Please, try again.', true)); + } + } + if (empty($this->data)) { + $this->data = $this->Language->read(null, $id); + } + } + + function admin_delete($id = null) { + if (!$id) { + $this->Session->setFlash(__('Invalid id for language', true)); + $this->redirect(array('action'=>'index')); + } + if ($this->Language->delete($id)) { + $this->Session->setFlash(__('Language deleted', true)); + $this->redirect(array('action'=>'index')); + } + $this->Session->setFlash(__('Language was not deleted', true)); + $this->redirect(array('action' => 'index')); + } +} diff --git a/code/ryzom/tools/server/www/webtt/app/controllers/languages_controller.php.bak b/code/ryzom/tools/server/www/webtt/app/controllers/languages_controller.php.bak new file mode 100644 index 000000000..46234b733 --- /dev/null +++ b/code/ryzom/tools/server/www/webtt/app/controllers/languages_controller.php.bak @@ -0,0 +1,125 @@ +Language->recursive = 0; + $this->set('languages', $this->paginate()); + } + + function view($id = null) { + if (!$id) { + $this->Session->setFlash(__('Invalid language', true)); + $this->redirect(array('action' => 'index')); + } + $this->set('language', $this->Language->read(null, $id)); +/* $options = array('Language.id' => $id, 'recursive' => 1, + "joins" => array( + array('table' => ' + ), + ); + var_dump($this); + $this->set('language', $bumz = $this->Language->find('first', $options)); +var_dump($bumz);*/ +// $this->set('identifier', $this->Language->TranslationFile->read(null, $id)); + } + + function add() { + if (!empty($this->data)) { + $this->Language->create(); + if ($this->Language->save($this->data)) { + $this->Session->setFlash(__('The language has been saved', true)); + $this->redirect(array('action' => 'index')); + } else { + $this->Session->setFlash(__('The language could not be saved. Please, try again.', true)); + } + } + } + + function edit($id = null) { + if (!$id && empty($this->data)) { + $this->Session->setFlash(__('Invalid language', true)); + $this->redirect(array('action' => 'index')); + } + if (!empty($this->data)) { + if ($this->Language->save($this->data)) { + $this->Session->setFlash(__('The language has been saved', true)); + $this->redirect(array('action' => 'index')); + } else { + $this->Session->setFlash(__('The language could not be saved. Please, try again.', true)); + } + } + if (empty($this->data)) { + $this->data = $this->Language->read(null, $id); + } + } + + function delete($id = null) { + if (!$id) { + $this->Session->setFlash(__('Invalid id for language', true)); + $this->redirect(array('action'=>'index')); + } + if ($this->Language->delete($id)) { + $this->Session->setFlash(__('Language deleted', true)); + $this->redirect(array('action'=>'index')); + } + $this->Session->setFlash(__('Language was not deleted', true)); + $this->redirect(array('action' => 'index')); + } + function admin_index() { + $this->Language->recursive = 0; + $this->set('languages', $this->paginate()); + } + + function admin_view($id = null) { + if (!$id) { + $this->Session->setFlash(__('Invalid language', true)); + $this->redirect(array('action' => 'index')); + } + $this->set('language', $this->Language->read(null, $id)); + } + + function admin_add() { + if (!empty($this->data)) { + $this->Language->create(); + if ($this->Language->save($this->data)) { + $this->Session->setFlash(__('The language has been saved', true)); + $this->redirect(array('action' => 'index')); + } else { + $this->Session->setFlash(__('The language could not be saved. Please, try again.', true)); + } + } + } + + function admin_edit($id = null) { + if (!$id && empty($this->data)) { + $this->Session->setFlash(__('Invalid language', true)); + $this->redirect(array('action' => 'index')); + } + if (!empty($this->data)) { + if ($this->Language->save($this->data)) { + $this->Session->setFlash(__('The language has been saved', true)); + $this->redirect(array('action' => 'index')); + } else { + $this->Session->setFlash(__('The language could not be saved. Please, try again.', true)); + } + } + if (empty($this->data)) { + $this->data = $this->Language->read(null, $id); + } + } + + function admin_delete($id = null) { + if (!$id) { + $this->Session->setFlash(__('Invalid id for language', true)); + $this->redirect(array('action'=>'index')); + } + if ($this->Language->delete($id)) { + $this->Session->setFlash(__('Language deleted', true)); + $this->redirect(array('action'=>'index')); + } + $this->Session->setFlash(__('Language was not deleted', true)); + $this->redirect(array('action' => 'index')); + } +} diff --git a/code/ryzom/tools/server/www/webtt/app/controllers/raw_files_controller.php b/code/ryzom/tools/server/www/webtt/app/controllers/raw_files_controller.php new file mode 100644 index 000000000..e49bdf14f --- /dev/null +++ b/code/ryzom/tools/server/www/webtt/app/controllers/raw_files_controller.php @@ -0,0 +1,154 @@ +RawFile->recursive = 1; +// var_dump($this->RawFile->find('count')); +// $db =& ConnectionManager::getDataSource($this->RawFile->useDbConfig); +// var_dump($db->calculate($this->RawFile, 'count')); + $this->set('rawFiles', $this->paginate()); +// var_dump($this->paginate()); + } + + function admin_index() { + $this->index(); + } + + function listdir($ext = null) { + $this->RawFile->recursive = 0; + $this->set('rawFiles', $this->paginate(array("ext" => $ext))); +// var_dump($this->paginate()); + } + + function view($id = null) { + if (!$id) { + $this->Session->setFlash(__('Invalid raw file', true)); + $this->redirect(array('action' => 'index')); + } + $this->set('rawFile', $this->RawFiles->read(null, $id)); + } + + function admin_import($dir = null, $filename = null) { +// $this->view = "index"; +// App::import("Vendor","UxtParser", array("file" => 'UxtParser.php')); + if (!$filename) { + $this->Session->setFlash(__('Invalid file', true)); + $this->redirect(array('action' => 'index')); + return 0; + } + if (!$this->RawFile->open($dir, $filename)) + { + $this->Session->setFlash(__('Can\'t open file', true)); + $this->redirect(array('action' => 'index')); + return 0; + } + $importedTranslationFileModel = $this->RawFile->ImportedTranslationFile; + $languageModel = $importedTranslationFileModel->Language; + $identifierModel = $languageModel->Identifier; + $fileIdentifierModel = $importedTranslationFileModel->FileIdentifier; + +// $filename="diff/pl_diff_4DEC868A.uxt"; + $importedTranslationFile = $importedTranslationFileModel->find('first', array('conditions' => array('ImportedTranslationFile.filename' => $dir . DS . $filename))); +/* var_dump($translationFile); + return 0;*/ + if ($importedTranslationFile) + { + $this->Session->setFlash(__('Translation file already imported', true)); + $this->redirect(array('action' => 'index')); + return 0; + } +// var_dump($file); +// $parser = new UxtParser(); + $parsedFile = $this->RawFile->parseFile($filename); +// var_dump($parsedFile); +// $arr = explode("_", basename($filename, ".uxt")); +// var_dump($arr); + +// $language_id = 1; + $languageCode = $this->RawFile->getLanguageCode($filename); + if (!$languageCode) + { + $this->Session->setFlash(__('Can\'t identify language', true)); + $this->redirect(array('action' => 'index')); + return 0; + } + $language = $importedTranslationFileModel->Language->find('first', array('conditions' => array('code' => $languageCode))); + $language_id = $language['Language']['id']; + if (!$language_id) + { + $this->Session->setFlash(__('Can\'t find language in database', true)); + $this->redirect(array('action' => 'index')); + return 0; + } + else + { +// var_dump($language_id); + } + +// return 0; + + $importedTranslationFileModel->create(); + $data['ImportedTranslationFile']['language_id'] = $language_id; + $data['ImportedTranslationFile']['filename'] = $dir . DS . $filename; + //$this->ImportedTranslationFile->save($data); + foreach ($parsedFile as $ent) + { + $fi_data = array(); + if ($ent['type'] != "string") + continue; + + $i_data['language_id'] = $language_id; + $i_data['translation_index'] = $ent['index']; + $i_data['reference_string'] = $ent['string']; + + unset($identifierModel->id); + $identifier = $identifierModel->find('first',array('conditions' => array('Identifier.identifier' => $ent['identifier'], 'Identifier.language_id' => $language_id))); + if ($identifier) + { +// var_dump($identifier); + $i_data['id']=$identifier['Identifier']['id']; + } + else + { + $i_data['identifier'] = $ent['identifier']; + $i_data['translated'] = false; + } +// var_dump($i_data); + $identifierModel->save(array('Identifier' => $i_data)); + $identifier_id = $identifierModel->id; +// var_dump($identifier_id); + + unset($fileIdentifierModel->id); + //TODO - set FileIdentifier['id'] if we import already imported file (importing imported file temporarly disabled) +// $identifier = $this->ImportedTranslationFile->FileIdentifier->find('first',array('conditions' => array('FileIdentifier.identifier' => $ent['identifier'], 'FileIdentifier.translation_file_id' => $))); +// $data['FileIdentifier']['translation_file_id'] = $this->ImportedTranslationFile->id; + if ($ent['diff']) + $fi_data['command'] = "DIFF " . mb_strtoupper($ent['diff']); + $fi_data['translation_index'] = $ent['index']; +// $data['FileIdentifier']['identifier_id'] = ; + $fi_data['reference_string'] = $ent['string']; + $fi_data['identifier_id'] = $identifier_id; + +// $this->ImportedTranslationFile->FileIdentifier->create(); +// $this->ImportedTranslationFile->FileIdentifier->save($data); + $data['FileIdentifier'][] = $fi_data; +// $l_data['Language']['id'] = $language_id; +// $l_data['Identifier'][] = $i_data; +// $data['Identifier'][] = $i_data; + } +// var_dump($data); +// $this->ImportedTranslationFile->Language->saveAll($l_data); + $importedTranslationFileModel->saveAll($data); + $this->Session->setFlash(__('Translation file imported', true)); + $this->redirect(array('controller' => 'imported_translation_files', 'action' => 'view', $importedTranslationFileModel->id)); +// $this->ImportedTranslationFile->recursive = 0; +// $this->set('importedTranslationFiles', $this->paginate()); +// $this->render('index'); + } + + +} diff --git a/code/ryzom/tools/server/www/webtt/app/controllers/translations_controller.php b/code/ryzom/tools/server/www/webtt/app/controllers/translations_controller.php new file mode 100644 index 000000000..b565b925a --- /dev/null +++ b/code/ryzom/tools/server/www/webtt/app/controllers/translations_controller.php @@ -0,0 +1,130 @@ +Translation->recursive = 0; + $this->set('translations', $this->paginate()); + } + + function view($id = null) { + if (!$id) { + $this->Session->setFlash(__('Invalid translation', true)); + $this->redirect(array('action' => 'index')); + } +// $this->recursive=2; + $this->set('translation', $bumz = $this->Translation->read(null, $id)); +// var_dump($bumz); + } + + function add() { + if (!empty($this->data)) { + $this->Translation->create(); + if ($this->Translation->save($this->data)) { + $this->Session->setFlash(__('The translation has been saved', true)); + $this->redirect(array('action' => 'index')); + } else { + $this->Session->setFlash(__('The translation could not be saved. Please, try again.', true)); + } + } + $identifiers = $this->Translation->Identifier->find('list'); + $users = $this->Translation->User->find('list'); + $this->set(compact('identifiers', 'users')); + } + + function edit($id = null) { + if (!$id && empty($this->data)) { + $this->Session->setFlash(__('Invalid translation', true)); + $this->redirect(array('action' => 'index')); + } + if (!empty($this->data)) { + if ($this->Translation->save($this->data)) { + $this->Session->setFlash(__('The translation has been saved', true)); + $this->redirect(array('action' => 'index')); + } else { + $this->Session->setFlash(__('The translation could not be saved. Please, try again.', true)); + } + } + if (empty($this->data)) { + $this->data = $this->Translation->read(null, $id); + } + $identifiers = $this->Translation->Identifier->find('list'); + $users = $this->Translation->User->find('list'); + $this->set(compact('identifiers', 'users')); + } + + function delete($id = null) { + if (!$id) { + $this->Session->setFlash(__('Invalid id for translation', true)); + $this->redirect(array('action'=>'index')); + } + if ($this->Translation->delete($id)) { + $this->Session->setFlash(__('Translation deleted', true)); + $this->redirect(array('action'=>'index')); + } + $this->Session->setFlash(__('Translation was not deleted', true)); + $this->redirect(array('action' => 'index')); + } + function admin_index() { + $this->Translation->recursive = 0; + $this->set('translations', $this->paginate()); + } + + function admin_view($id = null) { + if (!$id) { + $this->Session->setFlash(__('Invalid translation', true)); + $this->redirect(array('action' => 'index')); + } + $this->set('translation', $this->Translation->read(null, $id)); + } + + function admin_add() { + if (!empty($this->data)) { + $this->Translation->create(); + if ($this->Translation->save($this->data)) { + $this->Session->setFlash(__('The translation has been saved', true)); + $this->redirect(array('action' => 'index')); + } else { + $this->Session->setFlash(__('The translation could not be saved. Please, try again.', true)); + } + } + $identifiers = $this->Translation->Identifier->find('list'); + $users = $this->Translation->User->find('list'); + $this->set(compact('identifiers', 'users')); + } + + function admin_edit($id = null) { + if (!$id && empty($this->data)) { + $this->Session->setFlash(__('Invalid translation', true)); + $this->redirect(array('action' => 'index')); + } + if (!empty($this->data)) { + if ($this->Translation->save($this->data)) { + $this->Session->setFlash(__('The translation has been saved', true)); + $this->redirect(array('action' => 'index')); + } else { + $this->Session->setFlash(__('The translation could not be saved. Please, try again.', true)); + } + } + if (empty($this->data)) { + $this->data = $this->Translation->read(null, $id); + } + $identifiers = $this->Translation->Identifier->find('list'); + $users = $this->Translation->User->find('list'); + $this->set(compact('identifiers', 'users')); + } + + function admin_delete($id = null) { + if (!$id) { + $this->Session->setFlash(__('Invalid id for translation', true)); + $this->redirect(array('action'=>'index')); + } + if ($this->Translation->delete($id)) { + $this->Session->setFlash(__('Translation deleted', true)); + $this->redirect(array('action'=>'index')); + } + $this->Session->setFlash(__('Translation was not deleted', true)); + $this->redirect(array('action' => 'index')); + } +} diff --git a/code/ryzom/tools/server/www/webtt/app/controllers/users_controller.php b/code/ryzom/tools/server/www/webtt/app/controllers/users_controller.php new file mode 100644 index 000000000..a7d996e70 --- /dev/null +++ b/code/ryzom/tools/server/www/webtt/app/controllers/users_controller.php @@ -0,0 +1,116 @@ +User->recursive = 0; + $this->set('users', $this->paginate()); + } + + function view($id = null) { + if (!$id) { + $this->Session->setFlash(__('Invalid user', true)); + $this->redirect(array('action' => 'index')); + } + $this->set('user', $this->User->read(null, $id)); + } + + function add() { + if (!empty($this->data)) { + $this->User->create(); + if ($this->User->save($this->data)) { + $this->Session->setFlash(__('The user has been saved', true)); + $this->redirect(array('action' => 'index')); + } else { + $this->Session->setFlash(__('The user could not be saved. Please, try again.', true)); + } + } + } + + function edit($id = null) { + if (!$id && empty($this->data)) { + $this->Session->setFlash(__('Invalid user', true)); + $this->redirect(array('action' => 'index')); + } + if (!empty($this->data)) { + if ($this->User->save($this->data)) { + $this->Session->setFlash(__('The user has been saved', true)); + $this->redirect(array('action' => 'index')); + } else { + $this->Session->setFlash(__('The user could not be saved. Please, try again.', true)); + } + } + if (empty($this->data)) { + $this->data = $this->User->read(null, $id); + } + } + + function delete($id = null) { + if (!$id) { + $this->Session->setFlash(__('Invalid id for user', true)); + $this->redirect(array('action'=>'index')); + } + if ($this->User->delete($id)) { + $this->Session->setFlash(__('User deleted', true)); + $this->redirect(array('action'=>'index')); + } + $this->Session->setFlash(__('User was not deleted', true)); + $this->redirect(array('action' => 'index')); + } + function admin_index() { + $this->User->recursive = 0; + $this->set('users', $this->paginate()); + } + + function admin_view($id = null) { + if (!$id) { + $this->Session->setFlash(__('Invalid user', true)); + $this->redirect(array('action' => 'index')); + } + $this->set('user', $this->User->read(null, $id)); + } + + function admin_add() { + if (!empty($this->data)) { + $this->User->create(); + if ($this->User->save($this->data)) { + $this->Session->setFlash(__('The user has been saved', true)); + $this->redirect(array('action' => 'index')); + } else { + $this->Session->setFlash(__('The user could not be saved. Please, try again.', true)); + } + } + } + + function admin_edit($id = null) { + if (!$id && empty($this->data)) { + $this->Session->setFlash(__('Invalid user', true)); + $this->redirect(array('action' => 'index')); + } + if (!empty($this->data)) { + if ($this->User->save($this->data)) { + $this->Session->setFlash(__('The user has been saved', true)); + $this->redirect(array('action' => 'index')); + } else { + $this->Session->setFlash(__('The user could not be saved. Please, try again.', true)); + } + } + if (empty($this->data)) { + $this->data = $this->User->read(null, $id); + } + } + + function admin_delete($id = null) { + if (!$id) { + $this->Session->setFlash(__('Invalid id for user', true)); + $this->redirect(array('action'=>'index')); + } + if ($this->User->delete($id)) { + $this->Session->setFlash(__('User deleted', true)); + $this->redirect(array('action'=>'index')); + } + $this->Session->setFlash(__('User was not deleted', true)); + $this->redirect(array('action' => 'index')); + } +} diff --git a/code/ryzom/tools/server/www/webtt/app/controllers/votes_controller.php b/code/ryzom/tools/server/www/webtt/app/controllers/votes_controller.php new file mode 100644 index 000000000..25e63147f --- /dev/null +++ b/code/ryzom/tools/server/www/webtt/app/controllers/votes_controller.php @@ -0,0 +1,128 @@ +Vote->recursive = 0; + $this->set('votes', $this->paginate()); + } + + function view($id = null) { + if (!$id) { + $this->Session->setFlash(__('Invalid vote', true)); + $this->redirect(array('action' => 'index')); + } + $this->set('vote', $this->Vote->read(null, $id)); + } + + function add() { + if (!empty($this->data)) { + $this->Vote->create(); + if ($this->Vote->save($this->data)) { + $this->Session->setFlash(__('The vote has been saved', true)); + $this->redirect(array('action' => 'index')); + } else { + $this->Session->setFlash(__('The vote could not be saved. Please, try again.', true)); + } + } + $translations = $this->Vote->Translation->find('list'); + $users = $this->Vote->User->find('list'); + $this->set(compact('translations', 'users')); + } + + function edit($id = null) { + if (!$id && empty($this->data)) { + $this->Session->setFlash(__('Invalid vote', true)); + $this->redirect(array('action' => 'index')); + } + if (!empty($this->data)) { + if ($this->Vote->save($this->data)) { + $this->Session->setFlash(__('The vote has been saved', true)); + $this->redirect(array('action' => 'index')); + } else { + $this->Session->setFlash(__('The vote could not be saved. Please, try again.', true)); + } + } + if (empty($this->data)) { + $this->data = $this->Vote->read(null, $id); + } + $translations = $this->Vote->Translation->find('list'); + $users = $this->Vote->User->find('list'); + $this->set(compact('translations', 'users')); + } + + function delete($id = null) { + if (!$id) { + $this->Session->setFlash(__('Invalid id for vote', true)); + $this->redirect(array('action'=>'index')); + } + if ($this->Vote->delete($id)) { + $this->Session->setFlash(__('Vote deleted', true)); + $this->redirect(array('action'=>'index')); + } + $this->Session->setFlash(__('Vote was not deleted', true)); + $this->redirect(array('action' => 'index')); + } + function admin_index() { + $this->Vote->recursive = 0; + $this->set('votes', $this->paginate()); + } + + function admin_view($id = null) { + if (!$id) { + $this->Session->setFlash(__('Invalid vote', true)); + $this->redirect(array('action' => 'index')); + } + $this->set('vote', $this->Vote->read(null, $id)); + } + + function admin_add() { + if (!empty($this->data)) { + $this->Vote->create(); + if ($this->Vote->save($this->data)) { + $this->Session->setFlash(__('The vote has been saved', true)); + $this->redirect(array('action' => 'index')); + } else { + $this->Session->setFlash(__('The vote could not be saved. Please, try again.', true)); + } + } + $translations = $this->Vote->Translation->find('list'); + $users = $this->Vote->User->find('list'); + $this->set(compact('translations', 'users')); + } + + function admin_edit($id = null) { + if (!$id && empty($this->data)) { + $this->Session->setFlash(__('Invalid vote', true)); + $this->redirect(array('action' => 'index')); + } + if (!empty($this->data)) { + if ($this->Vote->save($this->data)) { + $this->Session->setFlash(__('The vote has been saved', true)); + $this->redirect(array('action' => 'index')); + } else { + $this->Session->setFlash(__('The vote could not be saved. Please, try again.', true)); + } + } + if (empty($this->data)) { + $this->data = $this->Vote->read(null, $id); + } + $translations = $this->Vote->Translation->find('list'); + $users = $this->Vote->User->find('list'); + $this->set(compact('translations', 'users')); + } + + function admin_delete($id = null) { + if (!$id) { + $this->Session->setFlash(__('Invalid id for vote', true)); + $this->redirect(array('action'=>'index')); + } + if ($this->Vote->delete($id)) { + $this->Session->setFlash(__('Vote deleted', true)); + $this->redirect(array('action'=>'index')); + } + $this->Session->setFlash(__('Vote was not deleted', true)); + $this->redirect(array('action' => 'index')); + } +} diff --git a/code/ryzom/tools/server/www/webtt/app/models/app_model.php b/code/ryzom/tools/server/www/webtt/app/models/app_model.php new file mode 100644 index 000000000..6dd28c9e0 --- /dev/null +++ b/code/ryzom/tools/server/www/webtt/app/models/app_model.php @@ -0,0 +1,36 @@ + 'Datasources.CsvSource', + * 'path' => '/path/to/file', // Path + * 'extension' => 'csv', // File extension + * 'readonly' => true, // Mark for read only access + * 'recursive' => false // Only false is supported at the moment + * ); + */ + +if (!class_exists('Folder')) { + App::import('Core', 'Folder'); +} + +if (!class_exists('File')) { + App::import('Core', 'File'); +} + +/** + * CSVSource Datasource + * + * @package datasources + * @subpackage datasources.models.datasources + */ +class RawFilesSource extends DataSource { + +/** + * Description + * + * @var string + */ + public $description = 'File Data Source'; + +/** + * Column delimiter + * + * @var string + */ + public $delimiter = ';'; + +/** + * Maximum Columns + * + * @var integer + */ + public $maxCol = 0; + +/** + * Field Names + * + * @var mixed + */ + public $fields = null; + +/** + * File Handle + * + * @var mixed + */ + public $handle = false; + +/** + * Page to start on + * + * @var integer + */ + public $page = 1; + +/** + * Limit of records + * + * @var integer + */ + public $limit = 99999; + +/** + * Default configuration. + * + * @var array + */ + var $_baseConfig = array( + 'datasource' => 'raw_files', + 'path' => '/home/kaczorek/projects/webtt/distfiles/translation', + 'extension' => 'uxt', + 'readonly' => true, + 'recursive' => true); + + protected $_schema = array( + 'files' => array( + 'filename' => array( + 'type' => 'string', + 'null' => false, + 'key' => 'primary', + 'lenght' => 255 + ) + ) + ); +/** + * Constructor + * + * @param string $config Configuration array + * @param boolean $autoConnect Automatically connect to / open the file + */ + public function __construct($config = null, $autoConnect = true) { + $this->debug = Configure::read('debug') > 0; + $this->fullDebug = Configure::read('debug') > 1; + parent::__construct($config); + if ($autoConnect) { + $this->connect(); + } + } + +/** + * Connects to the mailbox using options in the given configuration array. + * + * @return boolean True if the file could be opened. + */ + public function connect() { + $this->connected = false; + + if ($this->config['readonly']) { + $create = false; + $mode = 0; + } else { + $create = true; + $mode = 0777; + } + + $this->connection =& new Folder($this->config['path'], $create, $mode); + if ($this->connection) { + $this->handle = array(); + $this->connected = true; + } + + return $this->connected; + } + +/** + * List available sources + * + * @return array of available CSV files + */ + public function listSources() { + $this->config['database'] = 'csv'; + $cache = parent::listSources(); + if ($cache !== null) { + return $cache; + } + + $extPattern = '\.' . preg_quote($this->config['extension']); + if ($this->config['recursive']) { + $list = $this->connection->findRecursive('.*' . $extPattern, true); + foreach($list as &$item) { + $item = mb_substr($item, mb_strlen($this->config['path'] . DS)); + } + } else { + $list = $this->connection->find('.*' . $extPattern, true); + } + + foreach ($list as &$item) { + $item = preg_replace('/' . $extPattern . '$/i', '', $item); + } + + parent::listSources($list); + unset($this->config['database']); + return $list; + } + +/** + * Returns a Model description (metadata) or null if none found. + * + * @return mixed + */ + public function describe($model) { + $this->__getDescriptionFromFirstLine($model); + return $this->fields; + } + +/** + * Get Description from First Line, and store into class vars + * + * @param Model $model + * @return boolean True, Success + */ + private function __getDescriptionFromFirstLine($model) { + $filename = $model->table . '.' . $this->config['extension']; + $handle = fopen($this->config['path'] . DS . $filename, 'r'); + $line = rtrim(fgets($handle)); + $data_comma = explode(',', $line); + $data_semicolon = explode(';', $line); + + if (count($data_comma) > count($data_semicolon)) { + $this->delimiter = ','; + $this->fields = $data_comma; + $this->maxCol = count($data_comma); + } else { + $this->delimiter = ';'; + $this->fields = $data_semicolon; + $this->maxCol = count($data_semicolon); + } + fclose($handle); + return true; + } + +/** + * Close file handle + * + * @return null + */ + public function close() { + if ($this->connected) { + if ($this->handle) { + foreach($this->handle as $h) { + @fclose($h); + } + $this->handle = false; + } + $this->connected = false; + } + } + + public function read(&$model, $queryData = array(), $recursive = null) { + if ($queryData["conditions"] && $queryData["conditions"]["ext"]) + $extension = $queryData["conditions"]["ext"]; + else + $extension = $this->config['extension']; + + $extPattern = '\.' . preg_quote($extension); + if ($this->config['recursive']) { + $list = $this->connection->findRecursive('.*' . $extPattern, true); + foreach($list as &$item) { + $item = mb_substr($item, mb_strlen($this->connection->realpath($this->config['path']) . DS)); + } + unset($item); + } else { + $list = $this->connection->find('.*' . $extPattern, true); + } + + $nlist = array(); + foreach ($list as $item) { + $file = new File($path = $this->config['path'] . DS . $item, false); +// var_dump($item); +// $item = preg_replace('/' . $extPattern . '$/i', '', $item); + $resultSet[] = array( + $model->alias => array( + 'filename' => $item, + 'size' => $file->size(), + 'modified' => $file->lastChange(), + ), + ); + } + if ($model->findQueryType === 'count') { + return array(array(array('count' => count($resultSet)))); + } + + return $resultSet; + } +/** + * Read Data + * + * @param Model $model + * @param array $queryData + * @param integer $recursive Number of levels of association + * @return mixed + */ + public function read_z(&$model, $queryData = array(), $recursive = null) { + $config = $this->config; + $filename = $config['path'] . DS . $model->table . '.' . $config['extension']; + if (!Set::extract($this->handle, $model->table)) { + $this->handle[$model->table] = fopen($filename, 'r'); + } else { + fseek($this->handle[$model->table], 0, SEEK_SET) ; + } + $queryData = $this->__scrubQueryData($queryData); + + if (isset($queryData['limit']) && !empty($queryData['limit'])) { + $this->limit = $queryData['limit']; + } + + if (isset($queryData['page']) && !empty($queryData['page'])) { + $this->page = $queryData['page']; + } + + if (empty($queryData['fields'])) { + $fields = $this->fields; + $allFields = true; + } else { + $fields = $queryData['fields']; + $allFields = false; + $_fieldIndex = array(); + $index = 0; + // generate an index array of all wanted fields + foreach($this->fields as $field) { + if (in_array($field, $fields)) { + $_fieldIndex[] = $index; + } + $index++; + } + } + + $lineCount = 0; + $recordCount = 0; + $findCount = 0; + $resultSet = array(); + + // Daten werden aus der Datei in ein Array $data gelesen + while (($data = fgetcsv($this->handle[$model->table], 8192, $this->delimiter)) !== FALSE) { + if ($lineCount == 0) { + $lineCount++; + continue; + } else { + // Skip over records, that are not complete + if (count($data) < $this->maxCol) { + continue; + } + + $record = array(); + $i = 0; + foreach($this->fields as $field) { + $record[$model->alias][$field] = $data[$i++]; + } + + if ($this->__checkConditions($record, $queryData['conditions'], $model)) { + // Compute the virtual pagenumber + $_page = floor($findCount / $this->limit) + 1; + if ($this->page <= $_page) { + if (!$allFields) { + $record = array(); + if (count($_fieldIndex) > 0) { + foreach($_fieldIndex as $i) { + $record[$model->alias][$this->fields[$i]] = $data[$i]; + } + } + } + $resultSet[] = $record ; + $recordCount++; + } + } + unset($record); + $findCount++; + + if ($recordCount >= $this->limit) { + break; + } + } + } + + if ($model->findQueryType === 'count') { + return array(array(array('count' => count($resultSet)))); + } + return $resultSet; + } + +/** + * Private helper method to remove query metadata in given data array. + * + * @param array $data Data + * @return array Cleaned Data + */ + private function __scrubQueryData($data) { + foreach (array('conditions', 'fields', 'joins', 'order', /*'limit', 'offset',*/ 'group') as $key) { + if (!isset($data[$key]) || empty($data[$key])) { + $data[$key] = array(); + } + } + if (!isset($data['limit']) || empty($data['limit'])) { + $data['limit'] = PHP_INT_MAX; + } + if (!isset($data['offset']) || empty($data['offset'])) { + $data['offset'] = 0; + } + return $data; + } + +/** + * Private helper method to check conditions. + * + * @param array $record + * @param array $conditions + * @return bool + */ + private function __checkConditions($record, $conditions, $model) { + $result = true; + foreach ($conditions as $name => $value) { + $alias = $model->alias; + if (strpos($name, '.') !== false) { + list($alias, $name) = explode('.', $name); + } + + if (strtolower($name) === 'or') { + $cond = $value; + $result = false; + foreach ($cond as $name => $value) { + if (Set::matches($this->__createRule($name, $value), $record[$alias])) { + return true; + } + } + } else { + if (!Set::matches($this->__createRule($name, $value), $record[$alias])) { + return false; + } + } + } + return $result; + } + +/** + * Private helper method to crete rule. + * + * @param string $name + * @param string $value + * @return string + */ + private function __createRule($name, $value) { + if (strpos($name, ' ') !== false) { + return array(str_replace(' ', '', $name) . $value); + } + return array("{$name}={$value}"); + } + +/** + * Calculate + * + * @param Model $model + * @param mixed $func + * @param array $params + * @return array + */ + public function calculate(&$model, $func, $params = array()) { + return array('count'); + } +} diff --git a/code/ryzom/tools/server/www/webtt/app/models/file_identifier.php b/code/ryzom/tools/server/www/webtt/app/models/file_identifier.php new file mode 100644 index 000000000..885749702 --- /dev/null +++ b/code/ryzom/tools/server/www/webtt/app/models/file_identifier.php @@ -0,0 +1,23 @@ + array( + 'className' => 'ImportedTranslationFile', + 'foreignKey' => 'imported_translation_file_id', + 'conditions' => '', + 'fields' => '', + 'order' => '' + ), + 'Identifier' => array( + 'className' => 'Identifier', + 'foreignKey' => 'identifier_id', + 'conditions' => '', + 'fields' => '', + 'order' => '' + ) + ); +} diff --git a/code/ryzom/tools/server/www/webtt/app/models/identifier.php b/code/ryzom/tools/server/www/webtt/app/models/identifier.php new file mode 100644 index 000000000..a3e1246a2 --- /dev/null +++ b/code/ryzom/tools/server/www/webtt/app/models/identifier.php @@ -0,0 +1,69 @@ + array( + 'numeric' => array( + 'rule' => array('numeric'), + //'message' => 'Your custom message here', + //'allowEmpty' => false, + //'required' => false, + //'last' => false, // Stop validation after this rule + //'on' => 'create', // Limit validation to 'create' or 'update' operations + ), + ), + 'identifier' => array( + 'A_Za_z0_9' => array( + 'rule' => '/[A-Za-z0-9_@]+/', + 'message' => 'Identifier must consist only of the following caracteres: "A-Z", "a-z", "0-9", "@" and "_"', + //'allowEmpty' => false, + //'required' => false, + //'last' => false, // Stop validation after this rule + //'on' => 'create', // Limit validation to 'create' or 'update' operations + ), + ), + ); + //The Associations below have been created with all possible keys, those that are not needed can be removed + + var $belongsTo = array( + 'Language' => array( + 'className' => 'Language', + 'foreignKey' => 'language_id', + 'conditions' => '', + 'fields' => '', + 'order' => '' + ) + ); + + var $hasMany = array( + 'Translation' => array( + 'className' => 'Translation', + 'foreignKey' => 'identifier_id', + 'dependent' => false, + 'conditions' => '', + 'fields' => '', + 'order' => '', + 'limit' => '', + 'offset' => '', + 'exclusive' => '', + 'finderQuery' => '', + 'counterQuery' => '' + ), + 'FileIdentifier' => array( + 'className' => 'FileIdentifier', + 'foreignKey' => 'identifier_id', + 'dependent' => false, + 'conditions' => '', + 'fields' => '', + 'order' => '', + 'limit' => '', + 'offset' => '', + 'exclusive' => '', + 'finderQuery' => '', + 'counterQuery' => '' + ) + ); + +} diff --git a/code/ryzom/tools/server/www/webtt/app/models/imported_translation_file.php b/code/ryzom/tools/server/www/webtt/app/models/imported_translation_file.php new file mode 100644 index 000000000..c45bc435f --- /dev/null +++ b/code/ryzom/tools/server/www/webtt/app/models/imported_translation_file.php @@ -0,0 +1,46 @@ + array( + 'className' => 'Language', + 'foreignKey' => 'language_id', + 'conditions' => '', + 'fields' => '', + 'order' => '' + ) + ); + + var $hasMany = array( + 'FileIdentifier' => array( + 'className' => 'FileIdentifier', + 'foreignKey' => 'imported_translation_file_id', + 'dependent' => true, + 'conditions' => '', + 'fields' => '', + 'order' => '', + 'limit' => '', + 'offset' => '', + 'exclusive' => '', + 'finderQuery' => '', + 'counterQuery' => '' + ) + ); + + var $hasOne = array( + 'RawFile' => array( + 'className' => 'RawFile', + 'foreignKey' => 'filename', + 'dependand' => false, + 'conditions' => '', + 'fields' => '', + 'order' => '', + ), + ); + +} diff --git a/code/ryzom/tools/server/www/webtt/app/models/language.php b/code/ryzom/tools/server/www/webtt/app/models/language.php new file mode 100644 index 000000000..eef16ce9e --- /dev/null +++ b/code/ryzom/tools/server/www/webtt/app/models/language.php @@ -0,0 +1,36 @@ + array( + 'className' => 'Identifier', + 'foreignKey' => 'language_id', + 'dependent' => false, + 'conditions' => '', + 'fields' => '', + 'order' => '', + 'limit' => '', + 'offset' => '', + 'exclusive' => '', + 'finderQuery' => '', + 'counterQuery' => '' + ), + 'ImportedTranslationFile' => array( + 'className' => 'ImportedTranslationFile', + 'foreignKey' => 'language_id', + 'dependent' => false, + 'conditions' => '', + 'fields' => '', + 'order' => '', + 'limit' => '', + 'offset' => '', + 'exclusive' => '', + 'finderQuery' => '', + 'counterQuery' => '' + ) + ); + +} diff --git a/code/ryzom/tools/server/www/webtt/app/models/raw_file.php b/code/ryzom/tools/server/www/webtt/app/models/raw_file.php new file mode 100644 index 000000000..cd77639e1 --- /dev/null +++ b/code/ryzom/tools/server/www/webtt/app/models/raw_file.php @@ -0,0 +1,67 @@ + array( + 'className' => 'ImportedTranslationFile', + 'foreignKey' => 'filename', + 'conditions' => '', + 'fields' => '', + 'order' => '' + ), + ); +/* var $hasOne = array( + 'FileIdentifier' => array( + 'className' => 'FileIdentifier', + 'foreignKey' => 'translation_file_id', + 'dependent' => true, + 'conditions' => '', + 'fields' => '', + 'order' => '', + 'limit' => '', + 'offset' => '', + 'exclusive' => '', + 'finderQuery' => '', + 'counterQuery' => '' + ) + );*/ + + public function open($dir, $filename) + { + $ds = $this->getDataSource(); + $file = new File($filepath = $ds->config['path'] . DS . $dir . DS . $filename, false); + if (!$file) + return false; + if (!$file->readable()) + return false; +// var_dump($filename); + $this->_currentFile = $file; + return $file; + } + + public function parseFile($file) + { + App::import("Vendor","UxtParser", array("file" => 'UxtParser.php')); + $parser = $this->_parser = new UxtParser(); + if (!$this->_currentFile) + return false; + $entities = $parser->parseFile($this->_currentFile->read()); + return $entities; + } + public function getLanguageCode($filename) + { +// var_dump($filename); + if (preg_match('|^([a-z]{2})_diff_[A-F0-9]{8}\.uxt$|', $filename, $matches)) + return $matches[1]; + else if (preg_match('|^([a-z]{2})\.uxt$|', $filename, $matches)) + return $matches[1]; + } +} diff --git a/code/ryzom/tools/server/www/webtt/app/models/translation.php b/code/ryzom/tools/server/www/webtt/app/models/translation.php new file mode 100644 index 000000000..1a1859261 --- /dev/null +++ b/code/ryzom/tools/server/www/webtt/app/models/translation.php @@ -0,0 +1,40 @@ + array( + 'className' => 'Identifier', + 'foreignKey' => 'identifier_id', + 'conditions' => '', + 'fields' => '', + 'order' => '' + ), + 'User' => array( + 'className' => 'User', + 'foreignKey' => 'user_id', + 'conditions' => '', + 'fields' => '', + 'order' => '' + ) + ); + + var $hasMany = array( + 'Vote' => array( + 'className' => 'Vote', + 'foreignKey' => 'translation_id', + 'dependent' => false, + 'conditions' => '', + 'fields' => '', + 'order' => '', + 'limit' => '', + 'offset' => '', + 'exclusive' => '', + 'finderQuery' => '', + 'counterQuery' => '' + ) + ); + +} diff --git a/code/ryzom/tools/server/www/webtt/app/models/user.php b/code/ryzom/tools/server/www/webtt/app/models/user.php new file mode 100644 index 000000000..fe5157be9 --- /dev/null +++ b/code/ryzom/tools/server/www/webtt/app/models/user.php @@ -0,0 +1,36 @@ + array( + 'className' => 'Translation', + 'foreignKey' => 'user_id', + 'dependent' => false, + 'conditions' => '', + 'fields' => '', + 'order' => '', + 'limit' => '', + 'offset' => '', + 'exclusive' => '', + 'finderQuery' => '', + 'counterQuery' => '' + ), + 'Vote' => array( + 'className' => 'Vote', + 'foreignKey' => 'user_id', + 'dependent' => false, + 'conditions' => '', + 'fields' => '', + 'order' => '', + 'limit' => '', + 'offset' => '', + 'exclusive' => '', + 'finderQuery' => '', + 'counterQuery' => '' + ) + ); + +} diff --git a/code/ryzom/tools/server/www/webtt/app/models/vote.php b/code/ryzom/tools/server/www/webtt/app/models/vote.php new file mode 100644 index 000000000..b3de691b0 --- /dev/null +++ b/code/ryzom/tools/server/www/webtt/app/models/vote.php @@ -0,0 +1,23 @@ + array( + 'className' => 'Translation', + 'foreignKey' => 'translation_id', + 'conditions' => '', + 'fields' => '', + 'order' => '' + ), + 'User' => array( + 'className' => 'User', + 'foreignKey' => 'user_id', + 'conditions' => '', + 'fields' => '', + 'order' => '' + ) + ); +} diff --git a/code/ryzom/tools/server/www/webtt/app/tests/cases/controllers/file_identifiers_controller.test.php b/code/ryzom/tools/server/www/webtt/app/tests/cases/controllers/file_identifiers_controller.test.php new file mode 100644 index 000000000..0c7298f47 --- /dev/null +++ b/code/ryzom/tools/server/www/webtt/app/tests/cases/controllers/file_identifiers_controller.test.php @@ -0,0 +1,66 @@ +redirectUrl = $url; + } +} + +class FileIdentifiersControllerTestCase extends CakeTestCase { + var $fixtures = array('app.file_identifier', 'app.translation_file', 'app.language', 'app.identifier', 'app.translation', 'app.user', 'app.vote'); + + function startTest() { + $this->FileIdentifiers =& new TestFileIdentifiersController(); + $this->FileIdentifiers->constructClasses(); + } + + function endTest() { + unset($this->FileIdentifiers); + ClassRegistry::flush(); + } + + function testIndex() { + + } + + function testView() { + + } + + function testAdd() { + + } + + function testEdit() { + + } + + function testDelete() { + + } + + function testAdminIndex() { + + } + + function testAdminView() { + + } + + function testAdminAdd() { + + } + + function testAdminEdit() { + + } + + function testAdminDelete() { + + } + +} diff --git a/code/ryzom/tools/server/www/webtt/app/tests/cases/controllers/identifiers_controller.test.php b/code/ryzom/tools/server/www/webtt/app/tests/cases/controllers/identifiers_controller.test.php new file mode 100644 index 000000000..72e3d7346 --- /dev/null +++ b/code/ryzom/tools/server/www/webtt/app/tests/cases/controllers/identifiers_controller.test.php @@ -0,0 +1,66 @@ +redirectUrl = $url; + } +} + +class IdentifiersControllerTestCase extends CakeTestCase { + var $fixtures = array('app.identifier', 'app.language', 'app.translation_file', 'app.file_identifier', 'app.translation', 'app.user', 'app.vote'); + + function startTest() { + $this->Identifiers =& new TestIdentifiersController(); + $this->Identifiers->constructClasses(); + } + + function endTest() { + unset($this->Identifiers); + ClassRegistry::flush(); + } + + function testIndex() { + + } + + function testView() { + + } + + function testAdd() { + + } + + function testEdit() { + + } + + function testDelete() { + + } + + function testAdminIndex() { + + } + + function testAdminView() { + + } + + function testAdminAdd() { + + } + + function testAdminEdit() { + + } + + function testAdminDelete() { + + } + +} diff --git a/code/ryzom/tools/server/www/webtt/app/tests/cases/controllers/languages_controller.test.php b/code/ryzom/tools/server/www/webtt/app/tests/cases/controllers/languages_controller.test.php new file mode 100644 index 000000000..1cc5063e8 --- /dev/null +++ b/code/ryzom/tools/server/www/webtt/app/tests/cases/controllers/languages_controller.test.php @@ -0,0 +1,66 @@ +redirectUrl = $url; + } +} + +class LanguagesControllerTestCase extends CakeTestCase { + var $fixtures = array('app.language', 'app.identifier', 'app.translation', 'app.user', 'app.vote', 'app.translation_file'); + + function startTest() { + $this->Languages =& new TestLanguagesController(); + $this->Languages->constructClasses(); + } + + function endTest() { + unset($this->Languages); + ClassRegistry::flush(); + } + + function testIndex() { + + } + + function testView() { + + } + + function testAdd() { + + } + + function testEdit() { + + } + + function testDelete() { + + } + + function testAdminIndex() { + + } + + function testAdminView() { + + } + + function testAdminAdd() { + + } + + function testAdminEdit() { + + } + + function testAdminDelete() { + + } + +} diff --git a/code/ryzom/tools/server/www/webtt/app/tests/cases/controllers/translation_files_controller.test.php b/code/ryzom/tools/server/www/webtt/app/tests/cases/controllers/translation_files_controller.test.php new file mode 100644 index 000000000..f60450a86 --- /dev/null +++ b/code/ryzom/tools/server/www/webtt/app/tests/cases/controllers/translation_files_controller.test.php @@ -0,0 +1,26 @@ +redirectUrl = $url; + } +} + +class TranslationFilesControllerTestCase extends CakeTestCase { + var $fixtures = array('app.translation_file', 'app.language', 'app.identifier', 'app.translation', 'app.user', 'app.vote'); + + function startTest() { + $this->TranslationFiles =& new TestTranslationFilesController(); + $this->TranslationFiles->constructClasses(); + } + + function endTest() { + unset($this->TranslationFiles); + ClassRegistry::flush(); + } + +} diff --git a/code/ryzom/tools/server/www/webtt/app/tests/cases/controllers/translations_controller.test.php b/code/ryzom/tools/server/www/webtt/app/tests/cases/controllers/translations_controller.test.php new file mode 100644 index 000000000..aaeb1ec5a --- /dev/null +++ b/code/ryzom/tools/server/www/webtt/app/tests/cases/controllers/translations_controller.test.php @@ -0,0 +1,66 @@ +redirectUrl = $url; + } +} + +class TranslationsControllerTestCase extends CakeTestCase { + var $fixtures = array('app.translation', 'app.identifier', 'app.translation_file', 'app.language', 'app.user', 'app.vote'); + + function startTest() { + $this->Translations =& new TestTranslationsController(); + $this->Translations->constructClasses(); + } + + function endTest() { + unset($this->Translations); + ClassRegistry::flush(); + } + + function testIndex() { + + } + + function testView() { + + } + + function testAdd() { + + } + + function testEdit() { + + } + + function testDelete() { + + } + + function testAdminIndex() { + + } + + function testAdminView() { + + } + + function testAdminAdd() { + + } + + function testAdminEdit() { + + } + + function testAdminDelete() { + + } + +} diff --git a/code/ryzom/tools/server/www/webtt/app/tests/cases/controllers/users_controller.test.php b/code/ryzom/tools/server/www/webtt/app/tests/cases/controllers/users_controller.test.php new file mode 100644 index 000000000..3e9700388 --- /dev/null +++ b/code/ryzom/tools/server/www/webtt/app/tests/cases/controllers/users_controller.test.php @@ -0,0 +1,66 @@ +redirectUrl = $url; + } +} + +class UsersControllerTestCase extends CakeTestCase { + var $fixtures = array('app.user', 'app.translation', 'app.identifier', 'app.translation_file', 'app.language', 'app.vote'); + + function startTest() { + $this->Users =& new TestUsersController(); + $this->Users->constructClasses(); + } + + function endTest() { + unset($this->Users); + ClassRegistry::flush(); + } + + function testIndex() { + + } + + function testView() { + + } + + function testAdd() { + + } + + function testEdit() { + + } + + function testDelete() { + + } + + function testAdminIndex() { + + } + + function testAdminView() { + + } + + function testAdminAdd() { + + } + + function testAdminEdit() { + + } + + function testAdminDelete() { + + } + +} diff --git a/code/ryzom/tools/server/www/webtt/app/tests/cases/controllers/votes_controller.test.php b/code/ryzom/tools/server/www/webtt/app/tests/cases/controllers/votes_controller.test.php new file mode 100644 index 000000000..027661fb2 --- /dev/null +++ b/code/ryzom/tools/server/www/webtt/app/tests/cases/controllers/votes_controller.test.php @@ -0,0 +1,66 @@ +redirectUrl = $url; + } +} + +class VotesControllerTestCase extends CakeTestCase { + var $fixtures = array('app.vote', 'app.translation', 'app.identifier', 'app.translation_file', 'app.language', 'app.user'); + + function startTest() { + $this->Votes =& new TestVotesController(); + $this->Votes->constructClasses(); + } + + function endTest() { + unset($this->Votes); + ClassRegistry::flush(); + } + + function testIndex() { + + } + + function testView() { + + } + + function testAdd() { + + } + + function testEdit() { + + } + + function testDelete() { + + } + + function testAdminIndex() { + + } + + function testAdminView() { + + } + + function testAdminAdd() { + + } + + function testAdminEdit() { + + } + + function testAdminDelete() { + + } + +} diff --git a/code/ryzom/tools/server/www/webtt/app/tests/cases/models/file_identifier.test.php b/code/ryzom/tools/server/www/webtt/app/tests/cases/models/file_identifier.test.php new file mode 100644 index 000000000..0b6374de0 --- /dev/null +++ b/code/ryzom/tools/server/www/webtt/app/tests/cases/models/file_identifier.test.php @@ -0,0 +1,17 @@ +FileIdentifier =& ClassRegistry::init('FileIdentifier'); + } + + function endTest() { + unset($this->FileIdentifier); + ClassRegistry::flush(); + } + +} diff --git a/code/ryzom/tools/server/www/webtt/app/tests/cases/models/identifier.test.php b/code/ryzom/tools/server/www/webtt/app/tests/cases/models/identifier.test.php new file mode 100644 index 000000000..45d94d4a8 --- /dev/null +++ b/code/ryzom/tools/server/www/webtt/app/tests/cases/models/identifier.test.php @@ -0,0 +1,17 @@ +Identifier =& ClassRegistry::init('Identifier'); + } + + function endTest() { + unset($this->Identifier); + ClassRegistry::flush(); + } + +} diff --git a/code/ryzom/tools/server/www/webtt/app/tests/cases/models/language.test.php b/code/ryzom/tools/server/www/webtt/app/tests/cases/models/language.test.php new file mode 100644 index 000000000..e4d2251aa --- /dev/null +++ b/code/ryzom/tools/server/www/webtt/app/tests/cases/models/language.test.php @@ -0,0 +1,17 @@ +Language =& ClassRegistry::init('Language'); + } + + function endTest() { + unset($this->Language); + ClassRegistry::flush(); + } + +} diff --git a/code/ryzom/tools/server/www/webtt/app/tests/cases/models/translation.test.php b/code/ryzom/tools/server/www/webtt/app/tests/cases/models/translation.test.php new file mode 100644 index 000000000..534258df9 --- /dev/null +++ b/code/ryzom/tools/server/www/webtt/app/tests/cases/models/translation.test.php @@ -0,0 +1,17 @@ +Translation =& ClassRegistry::init('Translation'); + } + + function endTest() { + unset($this->Translation); + ClassRegistry::flush(); + } + +} diff --git a/code/ryzom/tools/server/www/webtt/app/tests/cases/models/translation_file.test.php b/code/ryzom/tools/server/www/webtt/app/tests/cases/models/translation_file.test.php new file mode 100644 index 000000000..0ba6d97ee --- /dev/null +++ b/code/ryzom/tools/server/www/webtt/app/tests/cases/models/translation_file.test.php @@ -0,0 +1,17 @@ +TranslationFile =& ClassRegistry::init('TranslationFile'); + } + + function endTest() { + unset($this->TranslationFile); + ClassRegistry::flush(); + } + +} diff --git a/code/ryzom/tools/server/www/webtt/app/tests/cases/models/user.test.php b/code/ryzom/tools/server/www/webtt/app/tests/cases/models/user.test.php new file mode 100644 index 000000000..36660249d --- /dev/null +++ b/code/ryzom/tools/server/www/webtt/app/tests/cases/models/user.test.php @@ -0,0 +1,17 @@ +User =& ClassRegistry::init('User'); + } + + function endTest() { + unset($this->User); + ClassRegistry::flush(); + } + +} diff --git a/code/ryzom/tools/server/www/webtt/app/tests/cases/models/vote.test.php b/code/ryzom/tools/server/www/webtt/app/tests/cases/models/vote.test.php new file mode 100644 index 000000000..0c42bc5ec --- /dev/null +++ b/code/ryzom/tools/server/www/webtt/app/tests/cases/models/vote.test.php @@ -0,0 +1,17 @@ +Vote =& ClassRegistry::init('Vote'); + } + + function endTest() { + unset($this->Vote); + ClassRegistry::flush(); + } + +} diff --git a/code/ryzom/tools/server/www/webtt/app/tests/fixtures/file_identifier_fixture.php b/code/ryzom/tools/server/www/webtt/app/tests/fixtures/file_identifier_fixture.php new file mode 100644 index 000000000..6fca71e96 --- /dev/null +++ b/code/ryzom/tools/server/www/webtt/app/tests/fixtures/file_identifier_fixture.php @@ -0,0 +1,31 @@ + array('type' => 'integer', 'null' => false, 'default' => NULL, 'length' => 10, 'key' => 'primary'), + 'translation_file_id' => array('type' => 'integer', 'null' => true, 'default' => NULL, 'length' => 10), + 'command' => array('type' => 'string', 'null' => true, 'default' => NULL, 'length' => 50, 'collate' => 'utf8_general_ci', 'charset' => 'utf8'), + 'translation_index' => array('type' => 'integer', 'null' => true, 'default' => NULL, 'length' => 10), + 'identifier_id' => array('type' => 'integer', 'null' => true, 'default' => NULL, 'length' => 10), + 'reference_string' => array('type' => 'text', 'null' => true, 'default' => NULL, 'collate' => 'utf8_general_ci', 'charset' => 'utf8'), + 'created' => array('type' => 'datetime', 'null' => true, 'default' => NULL), + 'modified' => array('type' => 'datetime', 'null' => true, 'default' => NULL), + 'indexes' => array('PRIMARY' => array('column' => 'id', 'unique' => 1)), + 'tableParameters' => array('charset' => 'utf8', 'collate' => 'utf8_general_ci', 'engine' => 'MyISAM') + ); + + var $records = array( + array( + 'id' => 1, + 'translation_file_id' => 1, + 'command' => 'Lorem ipsum dolor sit amet', + 'translation_index' => 1, + 'identifier_id' => 1, + 'reference_string' => 'Lorem ipsum dolor sit amet, aliquet feugiat. Convallis morbi fringilla gravida, phasellus feugiat dapibus velit nunc, pulvinar eget sollicitudin venenatis cum nullam, vivamus ut a sed, mollitia lectus. Nulla vestibulum massa neque ut et, id hendrerit sit, feugiat in taciti enim proin nibh, tempor dignissim, rhoncus duis vestibulum nunc mattis convallis.', + 'created' => '2011-05-31 16:07:59', + 'modified' => '2011-05-31 16:07:59' + ), + ); +} diff --git a/code/ryzom/tools/server/www/webtt/app/tests/fixtures/identifier_fixture.php b/code/ryzom/tools/server/www/webtt/app/tests/fixtures/identifier_fixture.php new file mode 100644 index 000000000..156047ae6 --- /dev/null +++ b/code/ryzom/tools/server/www/webtt/app/tests/fixtures/identifier_fixture.php @@ -0,0 +1,31 @@ + array('type' => 'integer', 'null' => false, 'default' => NULL, 'length' => 10, 'key' => 'primary'), + 'translation_file_id' => array('type' => 'integer', 'null' => true, 'default' => NULL, 'length' => 10), + 'translation_index' => array('type' => 'integer', 'null' => true, 'default' => NULL, 'length' => 10), + 'identifier' => array('type' => 'string', 'null' => true, 'default' => NULL, 'collate' => 'utf8_general_ci', 'charset' => 'utf8'), + 'reference_string' => array('type' => 'text', 'null' => true, 'default' => NULL, 'collate' => 'utf8_general_ci', 'charset' => 'utf8'), + 'translated' => array('type' => 'boolean', 'null' => true, 'default' => '0'), + 'created' => array('type' => 'datetime', 'null' => true, 'default' => NULL), + 'modified' => array('type' => 'datetime', 'null' => true, 'default' => NULL), + 'indexes' => array('PRIMARY' => array('column' => 'id', 'unique' => 1)), + 'tableParameters' => array('charset' => 'utf8', 'collate' => 'utf8_general_ci', 'engine' => 'MyISAM') + ); + + var $records = array( + array( + 'id' => 1, + 'translation_file_id' => 1, + 'translation_index' => 1, + 'identifier' => 'Lorem ipsum dolor sit amet', + 'reference_string' => 'Lorem ipsum dolor sit amet, aliquet feugiat. Convallis morbi fringilla gravida, phasellus feugiat dapibus velit nunc, pulvinar eget sollicitudin venenatis cum nullam, vivamus ut a sed, mollitia lectus. Nulla vestibulum massa neque ut et, id hendrerit sit, feugiat in taciti enim proin nibh, tempor dignissim, rhoncus duis vestibulum nunc mattis convallis.', + 'translated' => 1, + 'created' => '2011-05-29 19:17:37', + 'modified' => '2011-05-29 19:17:37' + ), + ); +} diff --git a/code/ryzom/tools/server/www/webtt/app/tests/fixtures/language_fixture.php b/code/ryzom/tools/server/www/webtt/app/tests/fixtures/language_fixture.php new file mode 100644 index 000000000..91fe7fb76 --- /dev/null +++ b/code/ryzom/tools/server/www/webtt/app/tests/fixtures/language_fixture.php @@ -0,0 +1,25 @@ + array('type' => 'integer', 'null' => false, 'default' => NULL, 'length' => 10, 'key' => 'primary'), + 'name' => array('type' => 'string', 'null' => true, 'default' => NULL, 'length' => 50, 'collate' => 'utf8_general_ci', 'charset' => 'utf8'), + 'code' => array('type' => 'string', 'null' => true, 'default' => NULL, 'length' => 10, 'collate' => 'utf8_general_ci', 'charset' => 'utf8'), + 'created' => array('type' => 'datetime', 'null' => true, 'default' => NULL), + 'modified' => array('type' => 'datetime', 'null' => true, 'default' => NULL), + 'indexes' => array('PRIMARY' => array('column' => 'id', 'unique' => 1)), + 'tableParameters' => array('charset' => 'utf8', 'collate' => 'utf8_general_ci', 'engine' => 'MyISAM') + ); + + var $records = array( + array( + 'id' => 1, + 'name' => 'Lorem ipsum dolor sit amet', + 'code' => 'Lorem ip', + 'created' => '2011-05-31 15:48:42', + 'modified' => '2011-05-31 15:48:42' + ), + ); +} diff --git a/code/ryzom/tools/server/www/webtt/app/tests/fixtures/translation_file_fixture.php b/code/ryzom/tools/server/www/webtt/app/tests/fixtures/translation_file_fixture.php new file mode 100644 index 000000000..4b9440ea4 --- /dev/null +++ b/code/ryzom/tools/server/www/webtt/app/tests/fixtures/translation_file_fixture.php @@ -0,0 +1,25 @@ + array('type' => 'integer', 'null' => false, 'default' => NULL, 'length' => 10, 'key' => 'primary'), + 'language_id' => array('type' => 'integer', 'null' => true, 'default' => NULL, 'length' => 10), + 'filename' => array('type' => 'string', 'null' => true, 'default' => NULL, 'collate' => 'utf8_general_ci', 'charset' => 'utf8'), + 'created' => array('type' => 'datetime', 'null' => true, 'default' => NULL), + 'modified' => array('type' => 'datetime', 'null' => true, 'default' => NULL), + 'indexes' => array('PRIMARY' => array('column' => 'id', 'unique' => 1)), + 'tableParameters' => array('charset' => 'utf8', 'collate' => 'utf8_general_ci', 'engine' => 'MyISAM') + ); + + var $records = array( + array( + 'id' => 1, + 'language_id' => 1, + 'filename' => 'Lorem ipsum dolor sit amet', + 'created' => '2011-05-29 19:13:14', + 'modified' => '2011-05-29 19:13:14' + ), + ); +} diff --git a/code/ryzom/tools/server/www/webtt/app/tests/fixtures/translation_fixture.php b/code/ryzom/tools/server/www/webtt/app/tests/fixtures/translation_fixture.php new file mode 100644 index 000000000..fbe4bdaca --- /dev/null +++ b/code/ryzom/tools/server/www/webtt/app/tests/fixtures/translation_fixture.php @@ -0,0 +1,27 @@ + array('type' => 'integer', 'null' => false, 'default' => NULL, 'length' => 10, 'key' => 'primary'), + 'identifier_id' => array('type' => 'integer', 'null' => true, 'default' => NULL, 'length' => 10), + 'translation_text' => array('type' => 'text', 'null' => true, 'default' => NULL, 'collate' => 'utf8_general_ci', 'charset' => 'utf8'), + 'user_id' => array('type' => 'integer', 'null' => true, 'default' => NULL, 'length' => 10), + 'created' => array('type' => 'datetime', 'null' => true, 'default' => NULL), + 'modified' => array('type' => 'datetime', 'null' => true, 'default' => NULL), + 'indexes' => array('PRIMARY' => array('column' => 'id', 'unique' => 1)), + 'tableParameters' => array('charset' => 'utf8', 'collate' => 'utf8_general_ci', 'engine' => 'MyISAM') + ); + + var $records = array( + array( + 'id' => 1, + 'identifier_id' => 1, + 'translation_text' => 'Lorem ipsum dolor sit amet, aliquet feugiat. Convallis morbi fringilla gravida, phasellus feugiat dapibus velit nunc, pulvinar eget sollicitudin venenatis cum nullam, vivamus ut a sed, mollitia lectus. Nulla vestibulum massa neque ut et, id hendrerit sit, feugiat in taciti enim proin nibh, tempor dignissim, rhoncus duis vestibulum nunc mattis convallis.', + 'user_id' => 1, + 'created' => '2011-05-29 19:19:41', + 'modified' => '2011-05-29 19:19:41' + ), + ); +} diff --git a/code/ryzom/tools/server/www/webtt/app/tests/fixtures/user_fixture.php b/code/ryzom/tools/server/www/webtt/app/tests/fixtures/user_fixture.php new file mode 100644 index 000000000..5e0adfb2d --- /dev/null +++ b/code/ryzom/tools/server/www/webtt/app/tests/fixtures/user_fixture.php @@ -0,0 +1,23 @@ + array('type' => 'integer', 'null' => false, 'default' => NULL, 'length' => 10, 'key' => 'primary'), + 'name' => array('type' => 'string', 'null' => true, 'default' => NULL, 'length' => 100, 'collate' => 'utf8_general_ci', 'charset' => 'utf8'), + 'created' => array('type' => 'datetime', 'null' => true, 'default' => NULL), + 'modified' => array('type' => 'datetime', 'null' => true, 'default' => NULL), + 'indexes' => array('PRIMARY' => array('column' => 'id', 'unique' => 1)), + 'tableParameters' => array('charset' => 'utf8', 'collate' => 'utf8_general_ci', 'engine' => 'MyISAM') + ); + + var $records = array( + array( + 'id' => 1, + 'name' => 'Lorem ipsum dolor sit amet', + 'created' => '2011-05-29 19:20:07', + 'modified' => '2011-05-29 19:20:07' + ), + ); +} diff --git a/code/ryzom/tools/server/www/webtt/app/tests/fixtures/vote_fixture.php b/code/ryzom/tools/server/www/webtt/app/tests/fixtures/vote_fixture.php new file mode 100644 index 000000000..cbe5389d6 --- /dev/null +++ b/code/ryzom/tools/server/www/webtt/app/tests/fixtures/vote_fixture.php @@ -0,0 +1,25 @@ + array('type' => 'integer', 'null' => false, 'default' => NULL, 'length' => 10, 'key' => 'primary'), + 'translation_id' => array('type' => 'integer', 'null' => true, 'default' => NULL, 'length' => 10), + 'user_id' => array('type' => 'integer', 'null' => true, 'default' => NULL, 'length' => 10), + 'created' => array('type' => 'datetime', 'null' => true, 'default' => NULL), + 'modified' => array('type' => 'datetime', 'null' => true, 'default' => NULL), + 'indexes' => array('PRIMARY' => array('column' => 'id', 'unique' => 1)), + 'tableParameters' => array('charset' => 'utf8', 'collate' => 'utf8_general_ci', 'engine' => 'MyISAM') + ); + + var $records = array( + array( + 'id' => 1, + 'translation_id' => 1, + 'user_id' => 1, + 'created' => '2011-05-29 21:11:49', + 'modified' => '2011-05-29 21:11:49' + ), + ); +} diff --git a/code/ryzom/tools/server/www/webtt/app/tmp/cache/views/empty b/code/ryzom/tools/server/www/webtt/app/tmp/cache/views/empty deleted file mode 100755 index e69de29bb..000000000 diff --git a/code/ryzom/tools/server/www/webtt/app/tmp/logs/empty b/code/ryzom/tools/server/www/webtt/app/tmp/logs/empty deleted file mode 100755 index e69de29bb..000000000 diff --git a/code/ryzom/tools/server/www/webtt/app/tmp/sessions/empty b/code/ryzom/tools/server/www/webtt/app/tmp/sessions/empty deleted file mode 100755 index e69de29bb..000000000 diff --git a/code/ryzom/tools/server/www/webtt/app/tmp/tests/empty b/code/ryzom/tools/server/www/webtt/app/tmp/tests/empty deleted file mode 100755 index e69de29bb..000000000 diff --git a/code/ryzom/tools/server/www/webtt/app/vendors/UxtParser.php b/code/ryzom/tools/server/www/webtt/app/vendors/UxtParser.php new file mode 100644 index 000000000..6d1855632 --- /dev/null +++ b/code/ryzom/tools/server/www/webtt/app/vendors/UxtParser.php @@ -0,0 +1,180 @@ +################################\n"; + var_dump($str); + var_dump($arr); + echo "\n";*/ + return $arr; + } + + function parseFile($file) + { + $parsedEnt = array(); + $newEnt = false; + $entities = array(); + +// $file = file_get_contents($this->pipeline_directory . $file); +// var_dump(mb_substr($file, 0,3)); +// var_dump(substr($file, 0,3)); +// var_dump($file); + $file = $this->removeBOM($file); +// var_dump($file); + $file = $this->removeComments($file); +// var_dump($file); + $lines = explode("\n", $file); +// echo "
################################\n";
+		foreach ($lines as $line)
+		{
+			$line = rtrim($line);
+			$parsedLine = $this->parseLine($line);
+
+			if (!$parsedLine)
+				continue;
+
+			if ($parsedLine["type"] == "index")
+				$parsedEnt["index"] = $parsedLine["index"];
+
+			if ($parsedLine["type"] == "string")
+			{
+/*				echo "%%%% parsedEnt %%%%%\n";
+				var_dump($parsedEnt);
+
+				echo "%%%% parsedLine %%%%%\n";
+				var_dump($parsedLine);
+*/
+
+				if (!$parsedLine['identifier'])
+				{
+//					echo "ZLACZENIE \n";
+					$parsedEnt['string'] .= "\n" . $parsedLine['string'];
+				}
+				else
+				{
+//					echo "DODANIE \n";
+					$parsedEnt += $parsedLine;
+				}
+
+/*				echo "%%%% parsedEnt after %%%%%\n";
+				var_dump($parsedEnt);*/
+			}
+
+			if ($parsedLine["type"] == "diff" && $parsedEnt)
+			{
+				$newEnt = true;
+			}
+
+			if ($newEnt)
+			{
+//				var_dump($parsedEnt);
+				$entities[] = $parsedEnt;
+				$parsedEnt =array();
+				$newEnt = false;
+			}
+
+			if ($parsedLine["type"] == "diff")
+			{
+				$parsedEnt["diff"] = $parsedLine["command"];
+				$parsedEnt["index"] = $parsedLine["index"];
+			}
+		}
+		if ($parsedEnt)
+			$entities[] = $parsedEnt;
+/*		var_dump($entities);
+		echo "
\n";*/ + return $entities; + } +} +?> \ No newline at end of file diff --git a/code/ryzom/tools/server/www/webtt/app/vendors/shells/templates/960grid/views/form.ctp b/code/ryzom/tools/server/www/webtt/app/vendors/shells/templates/960grid/views/form.ctp new file mode 100644 index 000000000..373f86fdc --- /dev/null +++ b/code/ryzom/tools/server/www/webtt/app/vendors/shells/templates/960grid/views/form.ctp @@ -0,0 +1,83 @@ + +
+
+ +

+ Actions +

+
+
+ + $data) { + foreach ($data as $alias => $details) { + echo "\n\t\t\t
".Inflector::humanize($details['controller'])."
"; + echo "\n\t\t\t
    \n"; + if ($details['controller'] != $this->name && !in_array($details['controller'], $done)) { + echo "\t\t\t\t
  • Html->link(sprintf(__('List %s', true), __('" . Inflector::humanize($details['controller']) . "', true)), array('controller' => '{$details['controller']}', 'action' => 'index')); ?>
  • \n"; + echo "\t\t\t\t
  • Html->link(sprintf(__('New %s', true), __('" . Inflector::humanize(Inflector::underscore($alias)) . "', true)), array('controller' => '{$details['controller']}', 'action' => 'add')); ?>
  • \n"; + $done[] = $details['controller']; + } + echo "\t\t\t
\n"; + } + } + ?> +
+
+
+ +
+

";?>

+ +
+ Form->create('{$modelClass}');?>\n";?> +
+ ";?> + Form->input('{$field}');\n"; + } + } + if (!empty($associations['hasAndBelongsToMany'])) { + foreach ($associations['hasAndBelongsToMany'] as $assocName => $assocData) { + echo "\t\techo \$this->Form->input('{$assocName}');\n"; + } + } + echo "\t?>\n"; + ?> +
+ Form->end(__('Submit', true));?>\n"; + ?> +
+ +
+
diff --git a/code/ryzom/tools/server/www/webtt/app/vendors/shells/templates/960grid/views/home.ctp b/code/ryzom/tools/server/www/webtt/app/vendors/shells/templates/960grid/views/home.ctp new file mode 100644 index 000000000..89e973e25 --- /dev/null +++ b/code/ryzom/tools/server/www/webtt/app/vendors/shells/templates/960grid/views/home.ctp @@ -0,0 +1,89 @@ +
+ +Sweet, \"" . Inflector::humanize($app) . "\" got Baked by CakePHP!\n"; +$output .=" + 0): + Debugger::checkSecurityKeys(); +endif; +?> +

+'; + __('Your tmp directory is writable.'); + echo ''; + else: + echo ''; + __('Your tmp directory is NOT writable.'); + echo ''; + endif; +?> +

+

+'; + printf(__('The %s is being used for caching. To change the config edit APP/config/core.php ', true), ''. \$settings['engine'] . 'Engine'); + echo ''; + else: + echo ''; + __('Your cache is NOT working. Please check the settings in APP/config/core.php'); + echo ''; + endif; +?> +

+

+'; + __('Your database configuration file is present.'); + \$filePresent = true; + echo ''; + else: + echo ''; + __('Your database configuration file is NOT present.'); + echo '
'; + __('Rename config/database.php.default to config/database.php'); + echo '
'; + endif; +?> +

+getDataSource('default'); +?> +

+isConnected()): + echo ''; + __('Cake is able to connect to the database.'); + echo ''; + else: + echo ''; + __('Cake is NOT able to connect to the database.'); + echo ''; + endif; +?> +

\n"; +$output .= "\n"; +$output .= "

\n"; +$output .= "

\n"; +$output .= "', APP . 'views' . DS . 'layouts' . DS . 'default.ctp.
', APP . 'webroot' . DS . 'css');\n"; +$output .= "?>\n"; +$output .= "

\n"; +?> + +
+
diff --git a/code/ryzom/tools/server/www/webtt/app/vendors/shells/templates/960grid/views/index.ctp b/code/ryzom/tools/server/www/webtt/app/vendors/shells/templates/960grid/views/index.ctp new file mode 100644 index 000000000..1a98eba2a --- /dev/null +++ b/code/ryzom/tools/server/www/webtt/app/vendors/shells/templates/960grid/views/index.ctp @@ -0,0 +1,126 @@ + +
+
+ +

+ Actions +

+
+
+ + $data) { + foreach ($data as $alias => $details) { + echo "\n\t\t\t
".Inflector::humanize($details['controller'])."
"; + echo "\n\t\t\t
    \n"; + if ($details['controller'] != $this->name && !in_array($details['controller'], $done)) { + echo "\t\t\t\t
  • Html->link(sprintf(__('List %s', true), __('" . Inflector::humanize($details['controller']) . "', true)), array('controller' => '{$details['controller']}', 'action' => 'index')); ?>
  • \n"; + echo "\t\t\t\t
  • Html->link(sprintf(__('New %s', true), __('" . Inflector::humanize(Inflector::underscore($alias)) . "', true)), array('controller' => '{$details['controller']}', 'action' => 'add')); ?>
  • \n"; + $done[] = $details['controller']; + } + echo "\t\t\t
\n"; + } + } + ?> +
+
+
+ +
+

";?>

+ + + + + tableHeaders(array("; + + foreach($fields as $field) { + echo "\$paginator->sort('{$field}'),"; + } + echo "__('Actions', true),"; + echo "));\n"; + + echo "echo ''.\$tableHeaders.''; ?>\n\n"; + + //// TABLE ROWS + + echo "\n"; + echo "\t>\n"; + foreach ($fields as $field) { + $isKey = false; + if (!empty($associations['belongsTo'])) { + foreach ($associations['belongsTo'] as $alias => $details) { + if ($field === $details['foreignKey']) { + $isKey = true; + echo "\t\t\n"; + break; + } + } + } + if ($isKey !== true) { + echo "\t\t\n"; + } + } + + echo "\t\t\n"; + echo "\t\n"; + + echo "\n"; + + //// TABLE FOOTER + echo "'.\$tableHeaders.''; ?>"; + ?> +
\n\t\t\tHtml->link(\${$singularVar}['{$alias}']['{$details['displayField']}'], array('controller' => '{$details['controller']}', 'action' => 'view', \${$singularVar}['{$alias}']['{$details['primaryKey']}'])); ?>\n\t\t \n"; + echo "\t\t\tHtml->link(__('View', true), array('action' => 'view', \${$singularVar}['{$modelClass}']['{$primaryKey}'])); ?>\n"; + echo "\t\t\tHtml->link(__('Edit', true), array('action' => 'edit', \${$singularVar}['{$modelClass}']['{$primaryKey}'])); ?>\n"; + echo "\t\t\tHtml->link(__('Delete', true), array('action' => 'delete', \${$singularVar}['{$modelClass}']['{$primaryKey}']), null, sprintf(__('Are you sure you want to delete # %s?', true), \${$singularVar}['{$modelClass}']['{$primaryKey}'])); ?>\n"; + echo "\t\t
+ + + +

+ Paginator->counter(array( + 'format' => __('Page %page% of %pages%, showing %current% records out of %count% total, starting on record %start%, ending on %end%', true) + )); + ?>";?> +

+ +
+ Paginator->prev('<< '.__('previous', true), array(), null, array('class'=>'disabled'));?>\n";?> + | Paginator->numbers();?>\n"?> | + Paginator->next(__('next', true).' >>', array(), null, array('class' => 'disabled'));?>\n";?> +
+ +
+
diff --git a/code/ryzom/tools/server/www/webtt/app/vendors/shells/templates/960grid/views/view.ctp b/code/ryzom/tools/server/www/webtt/app/vendors/shells/templates/960grid/views/view.ctp new file mode 100644 index 000000000..fa7a17221 --- /dev/null +++ b/code/ryzom/tools/server/www/webtt/app/vendors/shells/templates/960grid/views/view.ctp @@ -0,0 +1,184 @@ + +
+
+ +

+ Actions +

+
+
+ + $data) { + foreach ($data as $alias => $details) { + echo "\n\t\t\t
".Inflector::humanize($details['controller'])."
"; + echo "\n\t\t\t
    \n"; + if ($details['controller'] != $this->name && !in_array($details['controller'], $done)) { + echo "\t\t\t\t
  • Html->link(sprintf(__('List %s', true), __('" . Inflector::humanize($details['controller']) . "', true)), array('controller' => '{$details['controller']}', 'action' => 'index')); ?>
  • \n"; + echo "\t\t\t\t
  • Html->link(sprintf(__('New %s', true), __('" . Inflector::humanize(Inflector::underscore($alias)) . "', true)), array('controller' => '{$details['controller']}', 'action' => 'add')); ?>
  • \n"; + $done[] = $details['controller']; + } + echo "\t\t\t
\n"; + } + } + ?> +
+
+
+ +
+ +
+
+

";?>

+
+
\n";?> + $details) { + if ($field === $details['foreignKey']) { + $isKey = true; + echo "\t\t>\n"; + echo "\t\t>\n\t\t\tHtml->link(\${$singularVar}['{$alias}']['{$details['displayField']}'], array('controller' => '{$details['controller']}', 'action' => 'view', \${$singularVar}['{$alias}']['{$details['primaryKey']}'])); ?>\n\t\t\t \n\t\t\n"; + break; + } + } + } + if ($isKey !== true) { + echo "\t\t>\n"; + echo "\t\t>\n\t\t\t\n\t\t\t \n\t\t\n"; + } + } + ?> +
+
+
+
+ + +
+

+ "; ?> +

+ +
+ + +
+
diff --git a/code/ryzom/tools/server/www/webtt/app/views/elements/admin_left_menu.ctp b/code/ryzom/tools/server/www/webtt/app/views/elements/admin_left_menu.ctp new file mode 100644 index 000000000..8cfaa41c4 --- /dev/null +++ b/code/ryzom/tools/server/www/webtt/app/views/elements/admin_left_menu.ctp @@ -0,0 +1,28 @@ +

+ Admin Menu +

+
+ +
diff --git a/code/ryzom/tools/server/www/webtt/app/views/elements/main_menu.ctp b/code/ryzom/tools/server/www/webtt/app/views/elements/main_menu.ctp new file mode 100644 index 000000000..7d6a70f97 --- /dev/null +++ b/code/ryzom/tools/server/www/webtt/app/views/elements/main_menu.ctp @@ -0,0 +1,22 @@ + diff --git a/code/ryzom/tools/server/www/webtt/app/views/file_identifiers/add.ctp b/code/ryzom/tools/server/www/webtt/app/views/file_identifiers/add.ctp new file mode 100644 index 000000000..fa9470120 --- /dev/null +++ b/code/ryzom/tools/server/www/webtt/app/views/file_identifiers/add.ctp @@ -0,0 +1,25 @@ +
+Form->create('FileIdentifier');?> +
+ + Form->input('translation_file_id'); + echo $this->Form->input('command'); + echo $this->Form->input('translation_index'); + echo $this->Form->input('identifier_id'); + echo $this->Form->input('reference_string'); + ?> +
+Form->end(__('Submit', true));?> +
+
+

+ +
\ No newline at end of file diff --git a/code/ryzom/tools/server/www/webtt/app/views/file_identifiers/admin_add.ctp b/code/ryzom/tools/server/www/webtt/app/views/file_identifiers/admin_add.ctp new file mode 100644 index 000000000..4f3898be9 --- /dev/null +++ b/code/ryzom/tools/server/www/webtt/app/views/file_identifiers/admin_add.ctp @@ -0,0 +1,25 @@ +
+Form->create('FileIdentifier');?> +
+ + Form->input('translation_file_id'); + echo $this->Form->input('command'); + echo $this->Form->input('translation_index'); + echo $this->Form->input('identifier_id'); + echo $this->Form->input('reference_string'); + ?> +
+Form->end(__('Submit', true));?> +
+
+

+ +
\ No newline at end of file diff --git a/code/ryzom/tools/server/www/webtt/app/views/file_identifiers/admin_edit.ctp b/code/ryzom/tools/server/www/webtt/app/views/file_identifiers/admin_edit.ctp new file mode 100644 index 000000000..9a6609be7 --- /dev/null +++ b/code/ryzom/tools/server/www/webtt/app/views/file_identifiers/admin_edit.ctp @@ -0,0 +1,27 @@ +
+Form->create('FileIdentifier');?> +
+ + Form->input('id'); + echo $this->Form->input('translation_file_id'); + echo $this->Form->input('command'); + echo $this->Form->input('translation_index'); + echo $this->Form->input('identifier_id'); + echo $this->Form->input('reference_string'); + ?> +
+Form->end(__('Submit', true));?> +
+
+

+ +
\ No newline at end of file diff --git a/code/ryzom/tools/server/www/webtt/app/views/file_identifiers/admin_index.ctp b/code/ryzom/tools/server/www/webtt/app/views/file_identifiers/admin_index.ctp new file mode 100644 index 000000000..c62d5dc8e --- /dev/null +++ b/code/ryzom/tools/server/www/webtt/app/views/file_identifiers/admin_index.ctp @@ -0,0 +1,67 @@ +
+

+ + + + + + + + + + + + + + > + + + + + + + + + + + +
Paginator->sort('id');?>Paginator->sort('translation_file_id');?>Paginator->sort('command');?>Paginator->sort('translation_index');?>Paginator->sort('identifier_id');?>Paginator->sort('reference_string');?>Paginator->sort('created');?>Paginator->sort('modified');?>
  + Html->link($fileIdentifier['TranslationFile']['filename'], array('controller' => 'translation_files', 'action' => 'view', $fileIdentifier['TranslationFile']['id'])); ?> +    + Html->link($fileIdentifier['Identifier']['identifier'], array('controller' => 'identifiers', 'action' => 'view', $fileIdentifier['Identifier']['id'])); ?> +     + Html->link(__('View', true), array('action' => 'view', $fileIdentifier['FileIdentifier']['id'])); ?> + Html->link(__('Edit', true), array('action' => 'edit', $fileIdentifier['FileIdentifier']['id'])); ?> + Html->link(__('Delete', true), array('action' => 'delete', $fileIdentifier['FileIdentifier']['id']), null, sprintf(__('Are you sure you want to delete # %s?', true), $fileIdentifier['FileIdentifier']['id'])); ?> +
+

+ Paginator->counter(array( + 'format' => __('Page %page% of %pages%, showing %current% records out of %count% total, starting on record %start%, ending on %end%', true) + )); + ?>

+ +
+ Paginator->prev('<< ' . __('previous', true), array(), null, array('class'=>'disabled'));?> + | Paginator->numbers();?> + | + Paginator->next(__('next', true) . ' >>', array(), null, array('class' => 'disabled'));?> +
+
+
+

+ +
\ No newline at end of file diff --git a/code/ryzom/tools/server/www/webtt/app/views/file_identifiers/admin_view.ctp b/code/ryzom/tools/server/www/webtt/app/views/file_identifiers/admin_view.ctp new file mode 100644 index 000000000..8f375c882 --- /dev/null +++ b/code/ryzom/tools/server/www/webtt/app/views/file_identifiers/admin_view.ctp @@ -0,0 +1,58 @@ +
+

+
+ > + > + +   + + > + > + Html->link($fileIdentifier['TranslationFile']['filename'], array('controller' => 'translation_files', 'action' => 'view', $fileIdentifier['TranslationFile']['id'])); ?> +   + + > + > + +   + + > + > + +   + + > + > + Html->link($fileIdentifier['Identifier']['identifier'], array('controller' => 'identifiers', 'action' => 'view', $fileIdentifier['Identifier']['id'])); ?> +   + + > + > + +   + + > + > + +   + + > + > + +   + +
+
+
+

+ +
diff --git a/code/ryzom/tools/server/www/webtt/app/views/file_identifiers/edit.ctp b/code/ryzom/tools/server/www/webtt/app/views/file_identifiers/edit.ctp new file mode 100644 index 000000000..d85d2e100 --- /dev/null +++ b/code/ryzom/tools/server/www/webtt/app/views/file_identifiers/edit.ctp @@ -0,0 +1,27 @@ +
+Form->create('FileIdentifier');?> +
+ + Form->input('id'); + echo $this->Form->input('translation_file_id'); + echo $this->Form->input('command'); + echo $this->Form->input('translation_index'); + echo $this->Form->input('identifier_id'); + echo $this->Form->input('reference_string'); + ?> +
+Form->end(__('Submit', true));?> +
+
+

+ +
\ No newline at end of file diff --git a/code/ryzom/tools/server/www/webtt/app/views/file_identifiers/index.ctp b/code/ryzom/tools/server/www/webtt/app/views/file_identifiers/index.ctp new file mode 100644 index 000000000..c62d5dc8e --- /dev/null +++ b/code/ryzom/tools/server/www/webtt/app/views/file_identifiers/index.ctp @@ -0,0 +1,67 @@ +
+

+ + + + + + + + + + + + + + > + + + + + + + + + + + +
Paginator->sort('id');?>Paginator->sort('translation_file_id');?>Paginator->sort('command');?>Paginator->sort('translation_index');?>Paginator->sort('identifier_id');?>Paginator->sort('reference_string');?>Paginator->sort('created');?>Paginator->sort('modified');?>
  + Html->link($fileIdentifier['TranslationFile']['filename'], array('controller' => 'translation_files', 'action' => 'view', $fileIdentifier['TranslationFile']['id'])); ?> +    + Html->link($fileIdentifier['Identifier']['identifier'], array('controller' => 'identifiers', 'action' => 'view', $fileIdentifier['Identifier']['id'])); ?> +     + Html->link(__('View', true), array('action' => 'view', $fileIdentifier['FileIdentifier']['id'])); ?> + Html->link(__('Edit', true), array('action' => 'edit', $fileIdentifier['FileIdentifier']['id'])); ?> + Html->link(__('Delete', true), array('action' => 'delete', $fileIdentifier['FileIdentifier']['id']), null, sprintf(__('Are you sure you want to delete # %s?', true), $fileIdentifier['FileIdentifier']['id'])); ?> +
+

+ Paginator->counter(array( + 'format' => __('Page %page% of %pages%, showing %current% records out of %count% total, starting on record %start%, ending on %end%', true) + )); + ?>

+ +
+ Paginator->prev('<< ' . __('previous', true), array(), null, array('class'=>'disabled'));?> + | Paginator->numbers();?> + | + Paginator->next(__('next', true) . ' >>', array(), null, array('class' => 'disabled'));?> +
+
+
+

+ +
\ No newline at end of file diff --git a/code/ryzom/tools/server/www/webtt/app/views/file_identifiers/view.ctp b/code/ryzom/tools/server/www/webtt/app/views/file_identifiers/view.ctp new file mode 100644 index 000000000..8f375c882 --- /dev/null +++ b/code/ryzom/tools/server/www/webtt/app/views/file_identifiers/view.ctp @@ -0,0 +1,58 @@ +
+

+
+ > + > + +   + + > + > + Html->link($fileIdentifier['TranslationFile']['filename'], array('controller' => 'translation_files', 'action' => 'view', $fileIdentifier['TranslationFile']['id'])); ?> +   + + > + > + +   + + > + > + +   + + > + > + Html->link($fileIdentifier['Identifier']['identifier'], array('controller' => 'identifiers', 'action' => 'view', $fileIdentifier['Identifier']['id'])); ?> +   + + > + > + +   + + > + > + +   + + > + > + +   + +
+
+
+

+ +
diff --git a/code/ryzom/tools/server/www/webtt/app/views/identifiers/add.ctp b/code/ryzom/tools/server/www/webtt/app/views/identifiers/add.ctp new file mode 100644 index 000000000..0ac7bb80b --- /dev/null +++ b/code/ryzom/tools/server/www/webtt/app/views/identifiers/add.ctp @@ -0,0 +1,25 @@ +
+Form->create('Identifier');?> +
+ + Form->input('language_id'); + echo $this->Form->input('translation_index'); + echo $this->Form->input('identifier'); + echo $this->Form->input('reference_string'); + echo $this->Form->input('translated'); + ?> +
+Form->end(__('Submit', true));?> +
+
+

+ +
\ No newline at end of file diff --git a/code/ryzom/tools/server/www/webtt/app/views/identifiers/admin_add.ctp b/code/ryzom/tools/server/www/webtt/app/views/identifiers/admin_add.ctp new file mode 100644 index 000000000..41b9cf94b --- /dev/null +++ b/code/ryzom/tools/server/www/webtt/app/views/identifiers/admin_add.ctp @@ -0,0 +1,25 @@ +
+Form->create('Identifier');?> +
+ + Form->input('language_id'); + echo $this->Form->input('translation_index'); + echo $this->Form->input('identifier'); + echo $this->Form->input('reference_string'); + echo $this->Form->input('translated'); + ?> +
+Form->end(__('Submit', true));?> +
+
+

+ +
\ No newline at end of file diff --git a/code/ryzom/tools/server/www/webtt/app/views/identifiers/admin_edit.ctp b/code/ryzom/tools/server/www/webtt/app/views/identifiers/admin_edit.ctp new file mode 100644 index 000000000..ab749fd75 --- /dev/null +++ b/code/ryzom/tools/server/www/webtt/app/views/identifiers/admin_edit.ctp @@ -0,0 +1,27 @@ +
+Form->create('Identifier');?> +
+ + Form->input('id'); + echo $this->Form->input('language_id'); + echo $this->Form->input('translation_index'); + echo $this->Form->input('identifier'); + echo $this->Form->input('reference_string'); + echo $this->Form->input('translated'); + ?> +
+Form->end(__('Submit', true));?> +
+
+

+ +
\ No newline at end of file diff --git a/code/ryzom/tools/server/www/webtt/app/views/identifiers/admin_index.ctp b/code/ryzom/tools/server/www/webtt/app/views/identifiers/admin_index.ctp new file mode 100644 index 000000000..7f5a60a26 --- /dev/null +++ b/code/ryzom/tools/server/www/webtt/app/views/identifiers/admin_index.ctp @@ -0,0 +1,65 @@ +
+

+ + + + + + + + + + + + + + > + + + + + + + + + + + +
Paginator->sort('id');?>Paginator->sort('language_id');?>Paginator->sort('translation_index');?>Paginator->sort('identifier');?>Paginator->sort('reference_string');?>Paginator->sort('translated');?>Paginator->sort('created');?>Paginator->sort('modified');?>
  + Html->link($identifier['Language']['name'], array('controller' => 'languages', 'action' => 'view', $identifier['Language']['id'])); ?> +        + Html->link(__('View', true), array('action' => 'view', $identifier['Identifier']['id'])); ?> + Html->link(__('Edit', true), array('action' => 'edit', $identifier['Identifier']['id'])); ?> + Html->link(__('Delete', true), array('action' => 'delete', $identifier['Identifier']['id']), null, sprintf(__('Are you sure you want to delete # %s?', true), $identifier['Identifier']['id'])); ?> +
+

+ Paginator->counter(array( + 'format' => __('Page %page% of %pages%, showing %current% records out of %count% total, starting on record %start%, ending on %end%', true) + )); + ?>

+ +
+ Paginator->prev('<< ' . __('previous', true), array(), null, array('class'=>'disabled'));?> + | Paginator->numbers();?> + | + Paginator->next(__('next', true) . ' >>', array(), null, array('class' => 'disabled'));?> +
+
+
+

+ +
\ No newline at end of file diff --git a/code/ryzom/tools/server/www/webtt/app/views/identifiers/admin_view.ctp b/code/ryzom/tools/server/www/webtt/app/views/identifiers/admin_view.ctp new file mode 100644 index 000000000..a75ccf2ca --- /dev/null +++ b/code/ryzom/tools/server/www/webtt/app/views/identifiers/admin_view.ctp @@ -0,0 +1,152 @@ +
+

+
+ > + > + +   + + > + > + Html->link($identifier['Language']['name'], array('controller' => 'languages', 'action' => 'view', $identifier['Language']['id'])); ?> +   + + > + > + +   + + > + > + +   + + > + > + +   + + > + > + +   + + > + > + +   + + > + > + +   + +
+
+
+

+ +
+ + diff --git a/code/ryzom/tools/server/www/webtt/app/views/identifiers/edit.ctp b/code/ryzom/tools/server/www/webtt/app/views/identifiers/edit.ctp new file mode 100644 index 000000000..9b069eb7b --- /dev/null +++ b/code/ryzom/tools/server/www/webtt/app/views/identifiers/edit.ctp @@ -0,0 +1,27 @@ +
+Form->create('Identifier');?> +
+ + Form->input('id'); + echo $this->Form->input('language_id'); + echo $this->Form->input('translation_index'); + echo $this->Form->input('identifier'); + echo $this->Form->input('reference_string'); + echo $this->Form->input('translated'); + ?> +
+Form->end(__('Submit', true));?> +
+
+

+ +
\ No newline at end of file diff --git a/code/ryzom/tools/server/www/webtt/app/views/identifiers/index.ctp b/code/ryzom/tools/server/www/webtt/app/views/identifiers/index.ctp new file mode 100644 index 000000000..254f72b4e --- /dev/null +++ b/code/ryzom/tools/server/www/webtt/app/views/identifiers/index.ctp @@ -0,0 +1,62 @@ +
+

+ + + + + + + + + + + + + + > + + + + + + + + + + + +
Paginator->sort('id');?>Paginator->sort('language_id');?>Paginator->sort('translation_index');?>Paginator->sort('identifier');?>Paginator->sort('reference_string');?>Paginator->sort('translated');?>Paginator->sort('created');?>Paginator->sort('modified');?>
  + Html->link($identifier['Language']['name'], array('controller' => 'languages', 'action' => 'view', $identifier['Language']['id'])); ?> +        + Html->link(__('View', true), array('action' => 'view', $identifier['Identifier']['id'])); ?> +
+

+ Paginator->counter(array( + 'format' => __('Page %page% of %pages%, showing %current% records out of %count% total, starting on record %start%, ending on %end%', true) + )); + ?>

+ +
+ Paginator->prev('<< ' . __('previous', true), array(), null, array('class'=>'disabled'));?> + | Paginator->numbers();?> + | + Paginator->next(__('next', true) . ' >>', array(), null, array('class' => 'disabled'));?> +
+
+
+

+ +
\ No newline at end of file diff --git a/code/ryzom/tools/server/www/webtt/app/views/identifiers/view.ctp b/code/ryzom/tools/server/www/webtt/app/views/identifiers/view.ctp new file mode 100644 index 000000000..7539a2e33 --- /dev/null +++ b/code/ryzom/tools/server/www/webtt/app/views/identifiers/view.ctp @@ -0,0 +1,141 @@ +
+

+
+ > + > + +   + + > + > + Html->link($identifier['Language']['name'], array('controller' => 'languages', 'action' => 'view', $identifier['Language']['id'])); ?> +   + + > + > + +   + + > + > + +   + + > + > + +   + + > + > + +   + + > + > + +   + + > + > + +   + +
+
+
+

+ +
+ + diff --git a/code/ryzom/tools/server/www/webtt/app/views/imported_translation_files/admin_add.ctp b/code/ryzom/tools/server/www/webtt/app/views/imported_translation_files/admin_add.ctp new file mode 100644 index 000000000..b87a6fdd6 --- /dev/null +++ b/code/ryzom/tools/server/www/webtt/app/views/imported_translation_files/admin_add.ctp @@ -0,0 +1,22 @@ +
+Form->create('TranslationFile');?> +
+ + Form->input('language_id'); + echo $this->Form->input('filename'); + ?> +
+Form->end(__('Submit', true));?> +
+
+

+ +
\ No newline at end of file diff --git a/code/ryzom/tools/server/www/webtt/app/views/imported_translation_files/admin_edit.ctp b/code/ryzom/tools/server/www/webtt/app/views/imported_translation_files/admin_edit.ctp new file mode 100644 index 000000000..d5691f4bb --- /dev/null +++ b/code/ryzom/tools/server/www/webtt/app/views/imported_translation_files/admin_edit.ctp @@ -0,0 +1,24 @@ +
+Form->create('TranslationFile');?> +
+ + Form->input('id'); + echo $this->Form->input('language_id'); + echo $this->Form->input('filename'); + ?> +
+Form->end(__('Submit', true));?> +
+
+

+ +
\ No newline at end of file diff --git a/code/ryzom/tools/server/www/webtt/app/views/imported_translation_files/admin_index.ctp b/code/ryzom/tools/server/www/webtt/app/views/imported_translation_files/admin_index.ctp new file mode 100644 index 000000000..390d6132e --- /dev/null +++ b/code/ryzom/tools/server/www/webtt/app/views/imported_translation_files/admin_index.ctp @@ -0,0 +1,59 @@ +
+

+ + + + + + + + + + + > + + + + + + + + +
Paginator->sort('id');?>Paginator->sort('language_id');?>Paginator->sort('filename');?>Paginator->sort('created');?>Paginator->sort('modified');?>
  + Html->link($importedTranslationFile['Language']['name'], array('controller' => 'languages', 'action' => 'view', $importedTranslationFile['Language']['id'])); ?> +     + Html->link(__('View', true), array('action' => 'view', $importedTranslationFile['ImportedTranslationFile']['id'])); ?> + Html->link(__('Edit', true), array('action' => 'edit', $importedTranslationFile['ImportedTranslationFile']['id'])); ?> + Html->link(__('Delete', true), array('action' => 'delete', $importedTranslationFile['ImportedTranslationFile']['id']), null, sprintf(__('Are you sure you want to delete # %s?', true), $importedTranslationFile['ImportedTranslationFile']['id'])); ?> +
+

+ Paginator->counter(array( + 'format' => __('Page %page% of %pages%, showing %current% records out of %count% total, starting on record %start%, ending on %end%', true) + )); + ?>

+ +
+ Paginator->prev('<< ' . __('previous', true), array(), null, array('class'=>'disabled'));?> + | Paginator->numbers();?> + | + Paginator->next(__('next', true) . ' >>', array(), null, array('class' => 'disabled'));?> +
+
+
+

+ +
\ No newline at end of file diff --git a/code/ryzom/tools/server/www/webtt/app/views/imported_translation_files/admin_view.ctp b/code/ryzom/tools/server/www/webtt/app/views/imported_translation_files/admin_view.ctp new file mode 100644 index 000000000..6e9496ba1 --- /dev/null +++ b/code/ryzom/tools/server/www/webtt/app/views/imported_translation_files/admin_view.ctp @@ -0,0 +1,91 @@ +
+

+
+ > + > + +   + + > + > + Html->link($translationFile['Language']['name'], array('controller' => 'languages', 'action' => 'view', $translationFile['Language']['id'])); ?> +   + + > + > + +   + + > + > + +   + + > + > + +   + +
+
+
+

+ +
+ diff --git a/code/ryzom/tools/server/www/webtt/app/views/imported_translation_files/index.ctp b/code/ryzom/tools/server/www/webtt/app/views/imported_translation_files/index.ctp new file mode 100644 index 000000000..a04448484 --- /dev/null +++ b/code/ryzom/tools/server/www/webtt/app/views/imported_translation_files/index.ctp @@ -0,0 +1,55 @@ +
+

+ + + + + + + + + + + > + + + + + + + + +
Paginator->sort('id');?>Paginator->sort('language_id');?>Paginator->sort('filename');?>Paginator->sort('created');?>Paginator->sort('modified');?>
  + Html->link($importedTranslationFile['Language']['name'], array('controller' => 'languages', 'action' => 'view', $importedTranslationFile['Language']['id'])); ?> +     + Html->link(__('View', true), array('action' => 'view', $importedTranslationFile['ImportedTranslationFile']['id'])); ?> +
+

+ Paginator->counter(array( + 'format' => __('Page %page% of %pages%, showing %current% records out of %count% total, starting on record %start%, ending on %end%', true) + )); + ?>

+ +
+ Paginator->prev('<< ' . __('previous', true), array(), null, array('class'=>'disabled'));?> + | Paginator->numbers();?> + | + Paginator->next(__('next', true) . ' >>', array(), null, array('class' => 'disabled'));?> +
+
+
+

+ +
\ No newline at end of file diff --git a/code/ryzom/tools/server/www/webtt/app/views/imported_translation_files/view.ctp b/code/ryzom/tools/server/www/webtt/app/views/imported_translation_files/view.ctp new file mode 100644 index 000000000..833367868 --- /dev/null +++ b/code/ryzom/tools/server/www/webtt/app/views/imported_translation_files/view.ctp @@ -0,0 +1,122 @@ +
+

+
+ > + > + +   + + > + > + Html->link($importedTranslationFile['Language']['name'], array('controller' => 'languages', 'action' => 'view', $importedTranslationFile['Language']['id'])); ?> +   + + > + > + +   + + > + > + +   + + > + > + +   + +
+
+
+

+ +
+ + \ No newline at end of file diff --git a/code/ryzom/tools/server/www/webtt/app/views/languages.bak/add.ctp b/code/ryzom/tools/server/www/webtt/app/views/languages.bak/add.ctp new file mode 100644 index 000000000..23eed9eb2 --- /dev/null +++ b/code/ryzom/tools/server/www/webtt/app/views/languages.bak/add.ctp @@ -0,0 +1,22 @@ +
+Form->create('Language');?> +
+ + Form->input('name'); + echo $this->Form->input('code'); + ?> +
+Form->end(__('Submit', true));?> +
+
+

+ +
\ No newline at end of file diff --git a/code/ryzom/tools/server/www/webtt/app/views/languages.bak/admin_add.ctp b/code/ryzom/tools/server/www/webtt/app/views/languages.bak/admin_add.ctp new file mode 100644 index 000000000..d4e5e1034 --- /dev/null +++ b/code/ryzom/tools/server/www/webtt/app/views/languages.bak/admin_add.ctp @@ -0,0 +1,22 @@ +
+Form->create('Language');?> +
+ + Form->input('name'); + echo $this->Form->input('code'); + ?> +
+Form->end(__('Submit', true));?> +
+
+

+ +
\ No newline at end of file diff --git a/code/ryzom/tools/server/www/webtt/app/views/languages.bak/admin_edit.ctp b/code/ryzom/tools/server/www/webtt/app/views/languages.bak/admin_edit.ctp new file mode 100644 index 000000000..f68d48baa --- /dev/null +++ b/code/ryzom/tools/server/www/webtt/app/views/languages.bak/admin_edit.ctp @@ -0,0 +1,24 @@ +
+Form->create('Language');?> +
+ + Form->input('id'); + echo $this->Form->input('name'); + echo $this->Form->input('code'); + ?> +
+Form->end(__('Submit', true));?> +
+
+

+ +
\ No newline at end of file diff --git a/code/ryzom/tools/server/www/webtt/app/views/languages.bak/admin_index.ctp b/code/ryzom/tools/server/www/webtt/app/views/languages.bak/admin_index.ctp new file mode 100644 index 000000000..e18bb771c --- /dev/null +++ b/code/ryzom/tools/server/www/webtt/app/views/languages.bak/admin_index.ctp @@ -0,0 +1,57 @@ +
+

+ + + + + + + + + + + > + + + + + + + + +
Paginator->sort('id');?>Paginator->sort('name');?>Paginator->sort('code');?>Paginator->sort('created');?>Paginator->sort('modified');?>
      + Html->link(__('View', true), array('action' => 'view', $language['Language']['id'])); ?> + Html->link(__('Edit', true), array('action' => 'edit', $language['Language']['id'])); ?> + Html->link(__('Delete', true), array('action' => 'delete', $language['Language']['id']), null, sprintf(__('Are you sure you want to delete # %s?', true), $language['Language']['id'])); ?> +
+

+ Paginator->counter(array( + 'format' => __('Page %page% of %pages%, showing %current% records out of %count% total, starting on record %start%, ending on %end%', true) + )); + ?>

+ +
+ Paginator->prev('<< ' . __('previous', true), array(), null, array('class'=>'disabled'));?> + | Paginator->numbers();?> + | + Paginator->next(__('next', true) . ' >>', array(), null, array('class' => 'disabled'));?> +
+
+
+

+ +
\ No newline at end of file diff --git a/code/ryzom/tools/server/www/webtt/app/views/languages.bak/admin_view.ctp b/code/ryzom/tools/server/www/webtt/app/views/languages.bak/admin_view.ctp new file mode 100644 index 000000000..aa7f2c923 --- /dev/null +++ b/code/ryzom/tools/server/www/webtt/app/views/languages.bak/admin_view.ctp @@ -0,0 +1,133 @@ +
+

+
+ > + > + +   + + > + > + +   + + > + > + +   + + > + > + +   + + > + > + +   + +
+
+
+

+ +
+ + diff --git a/code/ryzom/tools/server/www/webtt/app/views/languages.bak/edit.ctp b/code/ryzom/tools/server/www/webtt/app/views/languages.bak/edit.ctp new file mode 100644 index 000000000..5eab47bb4 --- /dev/null +++ b/code/ryzom/tools/server/www/webtt/app/views/languages.bak/edit.ctp @@ -0,0 +1,24 @@ +
+Form->create('Language');?> +
+ + Form->input('id'); + echo $this->Form->input('name'); + echo $this->Form->input('code'); + ?> +
+Form->end(__('Submit', true));?> +
+
+

+ +
\ No newline at end of file diff --git a/code/ryzom/tools/server/www/webtt/app/views/languages.bak/index.ctp b/code/ryzom/tools/server/www/webtt/app/views/languages.bak/index.ctp new file mode 100644 index 000000000..64cdf3bb4 --- /dev/null +++ b/code/ryzom/tools/server/www/webtt/app/views/languages.bak/index.ctp @@ -0,0 +1,53 @@ +
+

+ + + + + + + + + + + > + + + + + + + + +
Paginator->sort('id');?>Paginator->sort('name');?>Paginator->sort('code');?>Paginator->sort('created');?>Paginator->sort('modified');?>
      + Html->link(__('View', true), array('action' => 'view', $language['Language']['id'])); ?> +
+

+ Paginator->counter(array( + 'format' => __('Page %page% of %pages%, showing %current% records out of %count% total, starting on record %start%, ending on %end%', true) + )); + ?>

+ +
+ Paginator->prev('<< ' . __('previous', true), array(), null, array('class'=>'disabled'));?> + | Paginator->numbers();?> + | + Paginator->next(__('next', true) . ' >>', array(), null, array('class' => 'disabled'));?> +
+
+
+

+ +
\ No newline at end of file diff --git a/code/ryzom/tools/server/www/webtt/app/views/languages.bak/view.ctp b/code/ryzom/tools/server/www/webtt/app/views/languages.bak/view.ctp new file mode 100644 index 000000000..8560bc864 --- /dev/null +++ b/code/ryzom/tools/server/www/webtt/app/views/languages.bak/view.ctp @@ -0,0 +1,114 @@ +
+

+
+ > + > + +   + + > + > + +   + + > + > + +   + + > + > + +   + + > + > + +   + +
+
+
+

+ +
+ + diff --git a/code/ryzom/tools/server/www/webtt/app/views/languages/add.ctp b/code/ryzom/tools/server/www/webtt/app/views/languages/add.ctp new file mode 100644 index 000000000..d839e5c26 --- /dev/null +++ b/code/ryzom/tools/server/www/webtt/app/views/languages/add.ctp @@ -0,0 +1,43 @@ +
+
+

+ Actions +

+
+
Languages
+ + +
Identifiers
+ + +
Translation Files
+ +
+
+
+ +
+

+ +
+ Form->create('Language');?> +
+ + Form->input('name'); + echo $this->Form->input('code'); + ?> +
+ Form->end(__('Submit', true));?> +
+ +
+
diff --git a/code/ryzom/tools/server/www/webtt/app/views/languages/admin_add.ctp b/code/ryzom/tools/server/www/webtt/app/views/languages/admin_add.ctp new file mode 100644 index 000000000..5304881f2 --- /dev/null +++ b/code/ryzom/tools/server/www/webtt/app/views/languages/admin_add.ctp @@ -0,0 +1,43 @@ +
+
+

+ Actions +

+
+
Languages
+ + +
Identifiers
+ + +
Translation Files
+ +
+
+
+ +
+

+ +
+ Form->create('Language');?> +
+ + Form->input('name'); + echo $this->Form->input('code'); + ?> +
+ Form->end(__('Submit', true));?> +
+ +
+
diff --git a/code/ryzom/tools/server/www/webtt/app/views/languages/admin_edit.ctp b/code/ryzom/tools/server/www/webtt/app/views/languages/admin_edit.ctp new file mode 100644 index 000000000..3888cb2f2 --- /dev/null +++ b/code/ryzom/tools/server/www/webtt/app/views/languages/admin_edit.ctp @@ -0,0 +1,45 @@ +
+
+

+ Actions +

+
+
Languages
+ + +
Identifiers
+ + +
Translation Files
+ +
+
+
+ +
+

+ +
+ Form->create('Language');?> +
+ + Form->input('id'); + echo $this->Form->input('name'); + echo $this->Form->input('code'); + ?> +
+ Form->end(__('Submit', true));?> +
+ +
+
diff --git a/code/ryzom/tools/server/www/webtt/app/views/languages/admin_index.ctp b/code/ryzom/tools/server/www/webtt/app/views/languages/admin_index.ctp new file mode 100644 index 000000000..270a5b1f0 --- /dev/null +++ b/code/ryzom/tools/server/www/webtt/app/views/languages/admin_index.ctp @@ -0,0 +1,74 @@ +
+
+

+ Actions +

+
+
Languages
+ + +
Identifiers
+ + +
Translation Files
+ +
+
+
+ +
+

+ + + + tableHeaders(array($paginator->sort('id'),$paginator->sort('name'),$paginator->sort('code'),$paginator->sort('created'),$paginator->sort('modified'),__('Actions', true),)); +echo ''.$tableHeaders.''; ?> + + + > + + + + + + + + +'.$tableHeaders.''; ?>
      + Html->link(__('View', true), array('action' => 'view', $language['Language']['id'])); ?> + Html->link(__('Edit', true), array('action' => 'edit', $language['Language']['id'])); ?> + Html->link(__('Delete', true), array('action' => 'delete', $language['Language']['id']), null, sprintf(__('Are you sure you want to delete # %s?', true), $language['Language']['id'])); ?> +
+ + +

+ Paginator->counter(array( + 'format' => __('Page %page% of %pages%, showing %current% records out of %count% total, starting on record %start%, ending on %end%', true) + )); + ?>

+ +
+ Paginator->prev('<< '.__('previous', true), array(), null, array('class'=>'disabled'));?> + | Paginator->numbers();?> + | + Paginator->next(__('next', true).' >>', array(), null, array('class' => 'disabled'));?> +
+ +
+
diff --git a/code/ryzom/tools/server/www/webtt/app/views/languages/admin_view.ctp b/code/ryzom/tools/server/www/webtt/app/views/languages/admin_view.ctp new file mode 100644 index 000000000..202516a06 --- /dev/null +++ b/code/ryzom/tools/server/www/webtt/app/views/languages/admin_view.ctp @@ -0,0 +1,172 @@ +
+
+

+ Actions +

+
+
Languages
+ + +
Identifiers
+ + +
Translation Files
+ +
+
+
+ +
+ +
+
+

+
+
+ > + > + +   + + > + > + +   + + > + > + +   + + > + > + +   + + > + > + +   + +
+
+
+
+ +
+

+ +

+ +
+ +
+
diff --git a/code/ryzom/tools/server/www/webtt/app/views/languages/edit.ctp b/code/ryzom/tools/server/www/webtt/app/views/languages/edit.ctp new file mode 100644 index 000000000..ce5d275fb --- /dev/null +++ b/code/ryzom/tools/server/www/webtt/app/views/languages/edit.ctp @@ -0,0 +1,45 @@ +
+
+

+ Actions +

+
+
Languages
+ + +
Identifiers
+ + +
Translation Files
+ +
+
+
+ +
+

+ +
+ Form->create('Language');?> +
+ + Form->input('id'); + echo $this->Form->input('name'); + echo $this->Form->input('code'); + ?> +
+ Form->end(__('Submit', true));?> +
+ +
+
diff --git a/code/ryzom/tools/server/www/webtt/app/views/languages/index.ctp b/code/ryzom/tools/server/www/webtt/app/views/languages/index.ctp new file mode 100644 index 000000000..270a5b1f0 --- /dev/null +++ b/code/ryzom/tools/server/www/webtt/app/views/languages/index.ctp @@ -0,0 +1,74 @@ +
+
+

+ Actions +

+
+
Languages
+ + +
Identifiers
+ + +
Translation Files
+ +
+
+
+ +
+

+ + + + tableHeaders(array($paginator->sort('id'),$paginator->sort('name'),$paginator->sort('code'),$paginator->sort('created'),$paginator->sort('modified'),__('Actions', true),)); +echo ''.$tableHeaders.''; ?> + + + > + + + + + + + + +'.$tableHeaders.''; ?>
      + Html->link(__('View', true), array('action' => 'view', $language['Language']['id'])); ?> + Html->link(__('Edit', true), array('action' => 'edit', $language['Language']['id'])); ?> + Html->link(__('Delete', true), array('action' => 'delete', $language['Language']['id']), null, sprintf(__('Are you sure you want to delete # %s?', true), $language['Language']['id'])); ?> +
+ + +

+ Paginator->counter(array( + 'format' => __('Page %page% of %pages%, showing %current% records out of %count% total, starting on record %start%, ending on %end%', true) + )); + ?>

+ +
+ Paginator->prev('<< '.__('previous', true), array(), null, array('class'=>'disabled'));?> + | Paginator->numbers();?> + | + Paginator->next(__('next', true).' >>', array(), null, array('class' => 'disabled'));?> +
+ +
+
diff --git a/code/ryzom/tools/server/www/webtt/app/views/languages/view.ctp b/code/ryzom/tools/server/www/webtt/app/views/languages/view.ctp new file mode 100644 index 000000000..92ed15f28 --- /dev/null +++ b/code/ryzom/tools/server/www/webtt/app/views/languages/view.ctp @@ -0,0 +1,172 @@ +
+
+

+ Actions +

+
+
Languages
+ + +
Identifiers
+ + +
Translation Files
+ +
+
+
+ +
+ +
+
+

+
+
+ > + > + +   + + > + > + +   + + > + > + +   + + > + > + +   + + > + > + +   + +
+
+
+
+ +
+

+ +

+ +
+ +
+
diff --git a/code/ryzom/tools/server/www/webtt/app/views/layouts/admin.ctp b/code/ryzom/tools/server/www/webtt/app/views/layouts/admin.ctp new file mode 100644 index 000000000..68fba719a --- /dev/null +++ b/code/ryzom/tools/server/www/webtt/app/views/layouts/admin.ctp @@ -0,0 +1,41 @@ + + + + Html->charset(); ?> + + <?php __('Administration'); ?> - + <?php echo $title_for_layout; ?> + + Html->meta('icon'); + //echo $this->Html->css('cake.generic'); + echo $this->Html->css(array('reset', 'text', 'grid', 'layout', 'nav')); + echo ''; + echo ''; + echo $this->Html->script(array('jquery-1.3.2.min.js', 'jquery-ui.js', 'jquery-fluid16.js')); + echo $scripts_for_layout; + ?> + + +
+
+

+ Administration +

+
+
+
+ element('admin/main_menu'); ?> +
+ +
+ + Session->flash(); ?> + + + +
+
+ element('sql_dump'); ?> + + diff --git a/code/ryzom/tools/server/www/webtt/app/views/layouts/default.ctp b/code/ryzom/tools/server/www/webtt/app/views/layouts/default.ctp new file mode 100644 index 000000000..083a2a64c --- /dev/null +++ b/code/ryzom/tools/server/www/webtt/app/views/layouts/default.ctp @@ -0,0 +1,59 @@ + + + + + Html->charset(); ?> + + <?php __('Ryzom Core: Web Translation Tool :: '); ?> + <?php echo $title_for_layout; ?> + + Html->meta('icon'); + + echo $this->Html->css('cake.generic'); + + echo $scripts_for_layout; + ?> + + +
+ +
+ + Session->flash(); ?> + + + +
+ +
+ element('sql_dump'); ?> + + \ No newline at end of file diff --git a/code/ryzom/tools/server/www/webtt/app/views/layouts/default.ctp.bak b/code/ryzom/tools/server/www/webtt/app/views/layouts/default.ctp.bak new file mode 100644 index 000000000..ee4c977be --- /dev/null +++ b/code/ryzom/tools/server/www/webtt/app/views/layouts/default.ctp.bak @@ -0,0 +1,59 @@ + + + + + Html->charset(); ?> + + <?php __('Ryzom Core: Web Translation Tool :: '); ?> + <?php echo $title_for_layout; ?> + + Html->meta('icon'); + + echo $this->Html->css('cake.generic'); + + echo $scripts_for_layout; + ?> + + +
+ +
+ + Session->flash(); ?> + + + +
+ +
+ element('sql_dump'); ?> + + \ No newline at end of file diff --git a/code/ryzom/tools/server/www/webtt/app/views/layouts/default_debug.ctp b/code/ryzom/tools/server/www/webtt/app/views/layouts/default_debug.ctp new file mode 100644 index 000000000..5e06ca479 --- /dev/null +++ b/code/ryzom/tools/server/www/webtt/app/views/layouts/default_debug.ctp @@ -0,0 +1,59 @@ + + + + + Html->charset(); ?> + + <?php __('Ryzom Core: Web Translation Tool :: '); ?> + <?php echo $title_for_layout; ?> + + Html->meta('icon'); + + echo $this->Html->css('cake.generic'); + + echo $scripts_for_layout; + ?> + + +
+ +
+ + Session->flash(); ?> + + + +
+ +
+ element('sql_dump'); ?> + + \ No newline at end of file diff --git a/code/ryzom/tools/server/www/webtt/app/views/layouts/new.ctp b/code/ryzom/tools/server/www/webtt/app/views/layouts/new.ctp new file mode 100644 index 000000000..ccc9a96d4 --- /dev/null +++ b/code/ryzom/tools/server/www/webtt/app/views/layouts/new.ctp @@ -0,0 +1,38 @@ + + + + Html->charset(); ?> + <?php echo $title_for_layout; ?> + Html->meta('icon'); + //echo $this->Html->css('cake.generic'); + echo $this->Html->css(array('reset', 'text', 'grid', 'layout', 'nav')); + echo ''; + echo ''; + echo $this->Html->script(array('jquery-1.3.2.min.js', 'jquery-ui.js', 'jquery-fluid16.js')); + echo $scripts_for_layout; + ?> + + +
+
+

+ Site +

+
+
+
+ +
+ +
+ + Session->flash(); ?> + + + +
+
+ element('sql_dump'); ?> + + diff --git a/code/ryzom/tools/server/www/webtt/app/views/pages/home.ctp b/code/ryzom/tools/server/www/webtt/app/views/pages/home.ctp new file mode 100644 index 000000000..631b9f62c --- /dev/null +++ b/code/ryzom/tools/server/www/webtt/app/views/pages/home.ctp @@ -0,0 +1,23 @@ + +

+

+Html->link(__('List Languages', true), array('controller' => 'languages', 'action' => 'index')); ?> +

diff --git a/code/ryzom/tools/server/www/webtt/app/views/raw_files/admin_index.ctp b/code/ryzom/tools/server/www/webtt/app/views/raw_files/admin_index.ctp new file mode 120000 index 000000000..f5532221a --- /dev/null +++ b/code/ryzom/tools/server/www/webtt/app/views/raw_files/admin_index.ctp @@ -0,0 +1 @@ +index.ctp \ No newline at end of file diff --git a/code/ryzom/tools/server/www/webtt/app/views/raw_files/index.ctp b/code/ryzom/tools/server/www/webtt/app/views/raw_files/index.ctp new file mode 100644 index 000000000..4b0b8baef --- /dev/null +++ b/code/ryzom/tools/server/www/webtt/app/views/raw_files/index.ctp @@ -0,0 +1,52 @@ +
+

+ + + + + + + + + > + + + + + + +
Paginator->sort('filename');?>Paginator->sort('size');?>Paginator->sort('modified');?>
  Time->nice($object['RawFile']['modified']); ?>  + Html->link(__('View', true), array('action' => 'view', $object['RawFile']['filename'])); ?> + Html->link(__('Import', true), array('action' => 'import', $object['RawFile']['filename'])); ?> + Html->link(__('Export', true), array('action' => 'export', $object['RawFile']['filename']), null, sprintf(__('Are you sure you want to export # %s?', true), $object['RawFile']['filename'])); ?> +
+

+ Paginator->counter(array( + 'format' => __('Page %page% of %pages%, showing %current% records out of %count% total, starting on record %start%, ending on %end%', true) + )); + ?>

+ +
+ Paginator->prev('<< ' . __('previous', true), array(), null, array('class'=>'disabled'));?> + | Paginator->numbers();?> + | + Paginator->next(__('next', true) . ' >>', array(), null, array('class' => 'disabled'));?> +
+
+
+

+ +
\ No newline at end of file diff --git a/code/ryzom/tools/server/www/webtt/app/views/raw_files/listdir.ctp b/code/ryzom/tools/server/www/webtt/app/views/raw_files/listdir.ctp new file mode 120000 index 000000000..f5532221a --- /dev/null +++ b/code/ryzom/tools/server/www/webtt/app/views/raw_files/listdir.ctp @@ -0,0 +1 @@ +index.ctp \ No newline at end of file diff --git a/code/ryzom/tools/server/www/webtt/app/views/raw_files/view.ctp b/code/ryzom/tools/server/www/webtt/app/views/raw_files/view.ctp new file mode 100644 index 000000000..ee5e7e265 --- /dev/null +++ b/code/ryzom/tools/server/www/webtt/app/views/raw_files/view.ctp @@ -0,0 +1,43 @@ +
+

+
+ > + > + +   + + > + > + Html->link($vote['Translation']['translation_text'], array('controller' => 'translations', 'action' => 'view', $vote['Translation']['id'])); ?> +   + + > + > + Html->link($vote['User']['name'], array('controller' => 'users', 'action' => 'view', $vote['User']['id'])); ?> +   + + > + > + +   + + > + > + +   + +
+
+
+

+ +
diff --git a/code/ryzom/tools/server/www/webtt/app/views/scaffolds/edit.ctp b/code/ryzom/tools/server/www/webtt/app/views/scaffolds/edit.ctp new file mode 100644 index 000000000..34b570631 --- /dev/null +++ b/code/ryzom/tools/server/www/webtt/app/views/scaffolds/edit.ctp @@ -0,0 +1,47 @@ + +
+Form->create(); + echo $this->Form->inputs($scaffoldFields, array('created', 'modified', 'updated')); + echo $this->Form->end(__('Submit', true)); +?> +
+
+

+ +
\ No newline at end of file diff --git a/code/ryzom/tools/server/www/webtt/app/views/scaffolds/index.ctp b/code/ryzom/tools/server/www/webtt/app/views/scaffolds/index.ctp new file mode 100644 index 000000000..ce4a09a3d --- /dev/null +++ b/code/ryzom/tools/server/www/webtt/app/views/scaffolds/index.ctp @@ -0,0 +1,93 @@ + +
+

+ + + + + + + +\n"; + foreach ($scaffoldFields as $_field) { + $isKey = false; + if (!empty($associations['belongsTo'])) { + foreach ($associations['belongsTo'] as $_alias => $_details) { + if ($_field === $_details['foreignKey']) { + $isKey = true; + echo "\t\t\n"; + break; + } + } + } + if ($isKey !== true) { + echo "\t\t\n"; + } + } + + echo "\t\t\n"; + echo "\t\n"; + +endforeach; +echo "\n"; +?> +
Paginator->sort($_field);?>
\n\t\t\t" . $this->Html->link(${$singularVar}[$_alias][$_details['displayField']], array('controller' => $_details['controller'], 'action' => 'view', ${$singularVar}[$_alias][$_details['primaryKey']])) . "\n\t\t\n\t\t\t" . ${$singularVar}[$modelClass][$_field] . " \n\t\t\n"; + echo "\t\t\t" . $this->Html->link(__('View', true), array('action' => 'view', ${$singularVar}[$modelClass][$primaryKey])) . "\n"; + echo "\t\t\t" . $this->Html->link(__('Edit', true), array('action' => 'edit', ${$singularVar}[$modelClass][$primaryKey])) . "\n"; + echo "\t\t\t" . $this->Html->link(__('Delete', true), array('action' => 'delete', ${$singularVar}[$modelClass][$primaryKey]), null, __('Are you sure you want to delete', true).' #' . ${$singularVar}[$modelClass][$primaryKey]) . "\n"; + echo "\t\t
+

Paginator->counter(array( + 'format' => __('Page %page% of %pages%, showing %current% records out of %count% total, starting on record %start%, ending on %end%', true) + )); + ?>

+
+ Paginator->prev('<< ' . __('previous', true), array(), null, array('class' => 'disabled')) . "\n";?> + | Paginator->numbers() . "\n"?> + Paginator->next(__('next', true) .' >>', array(), null, array('class' => 'disabled')) . "\n";?> +
+
+
+

+ +
\ No newline at end of file diff --git a/code/ryzom/tools/server/www/webtt/app/views/scaffolds/view.ctp b/code/ryzom/tools/server/www/webtt/app/views/scaffolds/view.ctp new file mode 100644 index 000000000..ae898d1fa --- /dev/null +++ b/code/ryzom/tools/server/www/webtt/app/views/scaffolds/view.ctp @@ -0,0 +1,161 @@ + +
+

+
+ $_details) { + if ($_field === $_details['foreignKey']) { + $isKey = true; + echo "\t\t" . Inflector::humanize($_alias) . "\n"; + echo "\t\t\n\t\t\t" . $this->Html->link(${$singularVar}[$_alias][$_details['displayField']], array('controller' => $_details['controller'], 'action' => 'view', ${$singularVar}[$_alias][$_details['primaryKey']])) . "\n\t\t \n"; + break; + } + } + } + if ($isKey !== true) { + echo "\t\t" . Inflector::humanize($_field) . "\n"; + echo "\t\t\n\t\t\t{${$singularVar}[$modelClass][$_field]}\n \t\t\n"; + } +} +?> +
+
+
+

+ +
+ $_details): ?> + + $_details): +$otherSingularVar = Inflector::variable($_alias); +?> + + \ No newline at end of file diff --git a/code/ryzom/tools/server/www/webtt/app/views/translations/add.ctp b/code/ryzom/tools/server/www/webtt/app/views/translations/add.ctp new file mode 100644 index 000000000..eaa529564 --- /dev/null +++ b/code/ryzom/tools/server/www/webtt/app/views/translations/add.ctp @@ -0,0 +1,25 @@ +
+Form->create('Translation');?> +
+ + Form->input('identifier_id'); + echo $this->Form->input('translation_text'); + echo $this->Form->input('user_id'); + ?> +
+Form->end(__('Submit', true));?> +
+
+

+ +
\ No newline at end of file diff --git a/code/ryzom/tools/server/www/webtt/app/views/translations/admin_add.ctp b/code/ryzom/tools/server/www/webtt/app/views/translations/admin_add.ctp new file mode 100644 index 000000000..0313500b5 --- /dev/null +++ b/code/ryzom/tools/server/www/webtt/app/views/translations/admin_add.ctp @@ -0,0 +1,25 @@ +
+Form->create('Translation');?> +
+ + Form->input('identifier_id'); + echo $this->Form->input('translation_text'); + echo $this->Form->input('user_id'); + ?> +
+Form->end(__('Submit', true));?> +
+
+

+ +
\ No newline at end of file diff --git a/code/ryzom/tools/server/www/webtt/app/views/translations/admin_edit.ctp b/code/ryzom/tools/server/www/webtt/app/views/translations/admin_edit.ctp new file mode 100644 index 000000000..7387d0c59 --- /dev/null +++ b/code/ryzom/tools/server/www/webtt/app/views/translations/admin_edit.ctp @@ -0,0 +1,27 @@ +
+Form->create('Translation');?> +
+ + Form->input('id'); + echo $this->Form->input('identifier_id'); + echo $this->Form->input('translation_text'); + echo $this->Form->input('user_id'); + ?> +
+Form->end(__('Submit', true));?> +
+
+

+ +
\ No newline at end of file diff --git a/code/ryzom/tools/server/www/webtt/app/views/translations/admin_index.ctp b/code/ryzom/tools/server/www/webtt/app/views/translations/admin_index.ctp new file mode 100644 index 000000000..1a377991c --- /dev/null +++ b/code/ryzom/tools/server/www/webtt/app/views/translations/admin_index.ctp @@ -0,0 +1,68 @@ +
+

+ + + + + + + + + + + + > + + + + + + + + + +
Paginator->sort('id');?>Paginator->sort('identifier_id');?>Paginator->sort('translation_text');?>Paginator->sort('user_id');?>Paginator->sort('created');?>Paginator->sort('modified');?>
  + Html->link($translation['Identifier']['identifier'], array('controller' => 'identifiers', 'action' => 'view', $translation['Identifier']['id'])); ?> +   + Html->link($translation['User']['name'], array('controller' => 'users', 'action' => 'view', $translation['User']['id'])); ?> +    + Html->link(__('View', true), array('action' => 'view', $translation['Translation']['id'])); ?> + Html->link(__('Edit', true), array('action' => 'edit', $translation['Translation']['id'])); ?> + Html->link(__('Delete', true), array('action' => 'delete', $translation['Translation']['id']), null, sprintf(__('Are you sure you want to delete # %s?', true), $translation['Translation']['id'])); ?> +
+

+ Paginator->counter(array( + 'format' => __('Page %page% of %pages%, showing %current% records out of %count% total, starting on record %start%, ending on %end%', true) + )); + ?>

+ +
+ Paginator->prev('<< ' . __('previous', true), array(), null, array('class'=>'disabled'));?> + | Paginator->numbers();?> + | + Paginator->next(__('next', true) . ' >>', array(), null, array('class' => 'disabled'));?> +
+
+
+

+ +
\ No newline at end of file diff --git a/code/ryzom/tools/server/www/webtt/app/views/translations/admin_view.ctp b/code/ryzom/tools/server/www/webtt/app/views/translations/admin_view.ctp new file mode 100644 index 000000000..c21a808ab --- /dev/null +++ b/code/ryzom/tools/server/www/webtt/app/views/translations/admin_view.ctp @@ -0,0 +1,92 @@ +
+

+
+ > + > + +   + + > + > + Html->link($translation['Identifier']['identifier'], array('controller' => 'identifiers', 'action' => 'view', $translation['Identifier']['id'])); ?> +   + + > + > + +   + + > + > + Html->link($translation['User']['name'], array('controller' => 'users', 'action' => 'view', $translation['User']['id'])); ?> +   + + > + > + +   + + > + > + +   + +
+
+
+

+ +
+ diff --git a/code/ryzom/tools/server/www/webtt/app/views/translations/edit.ctp b/code/ryzom/tools/server/www/webtt/app/views/translations/edit.ctp new file mode 100644 index 000000000..0f84bd4bf --- /dev/null +++ b/code/ryzom/tools/server/www/webtt/app/views/translations/edit.ctp @@ -0,0 +1,28 @@ +
+Form->create('Translation');?> +
+ + Form->input('id'); + echo $this->Form->input('identifier_id'); + echo $this->Form->input('translation_text'); + echo $this->Form->input('user_id'); + ?> +
+Form->end(__('Submit', true));?> +
+
+

+ +
\ No newline at end of file diff --git a/code/ryzom/tools/server/www/webtt/app/views/translations/index.ctp b/code/ryzom/tools/server/www/webtt/app/views/translations/index.ctp new file mode 100644 index 000000000..2bf80c563 --- /dev/null +++ b/code/ryzom/tools/server/www/webtt/app/views/translations/index.ctp @@ -0,0 +1,63 @@ +
+

+ + + + + + + + + + + + > + + + + + + + + + +
Paginator->sort('id');?>Paginator->sort('identifier_id');?>Paginator->sort('translation_text');?>Paginator->sort('user_id');?>Paginator->sort('created');?>Paginator->sort('modified');?>
  + Html->link($translation['Identifier']['identifier'], array('controller' => 'identifiers', 'action' => 'view', $translation['Identifier']['id'])); ?> +   + Html->link($translation['User']['name'], array('controller' => 'users', 'action' => 'view', $translation['User']['id'])); ?> +    + Html->link(__('View', true), array('action' => 'view', $translation['Translation']['id'])); ?> +
+

+ Paginator->counter(array( + 'format' => __('Page %page% of %pages%, showing %current% records out of %count% total, starting on record %start%, ending on %end%', true) + )); + ?>

+ +
+ Paginator->prev('<< ' . __('previous', true), array(), null, array('class'=>'disabled'));?> + | Paginator->numbers();?> + | + Paginator->next(__('next', true) . ' >>', array(), null, array('class' => 'disabled'));?> +
+
+
+

+ +
\ No newline at end of file diff --git a/code/ryzom/tools/server/www/webtt/app/views/translations/view.ctp b/code/ryzom/tools/server/www/webtt/app/views/translations/view.ctp new file mode 100644 index 000000000..06302a251 --- /dev/null +++ b/code/ryzom/tools/server/www/webtt/app/views/translations/view.ctp @@ -0,0 +1,91 @@ +
+

+
+ > + > + +   + + > + > + Html->link($translation['Identifier']['identifier'], array('controller' => 'identifiers', 'action' => 'view', $translation['Identifier']['id'])); ?> + [] +   + + > + > + +   + + > + > + Html->link($translation['User']['name'], array('controller' => 'users', 'action' => 'view', $translation['User']['id'])); ?> +   + + > + > + +   + + > + > + +   + +
+
+
+

+ +
+ diff --git a/code/ryzom/tools/server/www/webtt/app/views/users/add.ctp b/code/ryzom/tools/server/www/webtt/app/views/users/add.ctp new file mode 100644 index 000000000..0fbe8bb8d --- /dev/null +++ b/code/ryzom/tools/server/www/webtt/app/views/users/add.ctp @@ -0,0 +1,21 @@ +
+Form->create('User');?> +
+ + Form->input('name'); + ?> +
+Form->end(__('Submit', true));?> +
+
+

+ +
\ No newline at end of file diff --git a/code/ryzom/tools/server/www/webtt/app/views/users/admin_add.ctp b/code/ryzom/tools/server/www/webtt/app/views/users/admin_add.ctp new file mode 100644 index 000000000..8272a80e3 --- /dev/null +++ b/code/ryzom/tools/server/www/webtt/app/views/users/admin_add.ctp @@ -0,0 +1,21 @@ +
+Form->create('User');?> +
+ + Form->input('name'); + ?> +
+Form->end(__('Submit', true));?> +
+
+

+ +
\ No newline at end of file diff --git a/code/ryzom/tools/server/www/webtt/app/views/users/admin_edit.ctp b/code/ryzom/tools/server/www/webtt/app/views/users/admin_edit.ctp new file mode 100644 index 000000000..276341ea1 --- /dev/null +++ b/code/ryzom/tools/server/www/webtt/app/views/users/admin_edit.ctp @@ -0,0 +1,23 @@ +
+Form->create('User');?> +
+ + Form->input('id'); + echo $this->Form->input('name'); + ?> +
+Form->end(__('Submit', true));?> +
+
+

+ +
\ No newline at end of file diff --git a/code/ryzom/tools/server/www/webtt/app/views/users/admin_index.ctp b/code/ryzom/tools/server/www/webtt/app/views/users/admin_index.ctp new file mode 100644 index 000000000..b517108b3 --- /dev/null +++ b/code/ryzom/tools/server/www/webtt/app/views/users/admin_index.ctp @@ -0,0 +1,57 @@ +
+

+ + + + + + + + + + > + + + + + + + +
Paginator->sort('id');?>Paginator->sort('name');?>Paginator->sort('created');?>Paginator->sort('modified');?>
     + Html->link(__('View', true), array('action' => 'view', $user['User']['id'])); ?> + Html->link(__('Edit', true), array('action' => 'edit', $user['User']['id'])); ?> + Html->link(__('Delete', true), array('action' => 'delete', $user['User']['id']), null, sprintf(__('Are you sure you want to delete # %s?', true), $user['User']['id'])); ?> +
+

+ Paginator->counter(array( + 'format' => __('Page %page% of %pages%, showing %current% records out of %count% total, starting on record %start%, ending on %end%', true) + )); + ?>

+ +
+ Paginator->prev('<< ' . __('previous', true), array(), null, array('class'=>'disabled'));?> + | Paginator->numbers();?> + | + Paginator->next(__('next', true) . ' >>', array(), null, array('class' => 'disabled'));?> +
+
+
+

+ +
\ No newline at end of file diff --git a/code/ryzom/tools/server/www/webtt/app/views/users/admin_view.ctp b/code/ryzom/tools/server/www/webtt/app/views/users/admin_view.ctp new file mode 100644 index 000000000..d43038c55 --- /dev/null +++ b/code/ryzom/tools/server/www/webtt/app/views/users/admin_view.ctp @@ -0,0 +1,124 @@ +
+

+
+ > + > + +   + + > + > + +   + + > + > + +   + + > + > + +   + +
+
+
+

+ +
+ + diff --git a/code/ryzom/tools/server/www/webtt/app/views/users/edit.ctp b/code/ryzom/tools/server/www/webtt/app/views/users/edit.ctp new file mode 100644 index 000000000..fb3782453 --- /dev/null +++ b/code/ryzom/tools/server/www/webtt/app/views/users/edit.ctp @@ -0,0 +1,23 @@ +
+Form->create('User');?> +
+ + Form->input('id'); + echo $this->Form->input('name'); + ?> +
+Form->end(__('Submit', true));?> +
+
+

+ +
\ No newline at end of file diff --git a/code/ryzom/tools/server/www/webtt/app/views/users/index.ctp b/code/ryzom/tools/server/www/webtt/app/views/users/index.ctp new file mode 100644 index 000000000..b517108b3 --- /dev/null +++ b/code/ryzom/tools/server/www/webtt/app/views/users/index.ctp @@ -0,0 +1,57 @@ +
+

+ + + + + + + + + + > + + + + + + + +
Paginator->sort('id');?>Paginator->sort('name');?>Paginator->sort('created');?>Paginator->sort('modified');?>
     + Html->link(__('View', true), array('action' => 'view', $user['User']['id'])); ?> + Html->link(__('Edit', true), array('action' => 'edit', $user['User']['id'])); ?> + Html->link(__('Delete', true), array('action' => 'delete', $user['User']['id']), null, sprintf(__('Are you sure you want to delete # %s?', true), $user['User']['id'])); ?> +
+

+ Paginator->counter(array( + 'format' => __('Page %page% of %pages%, showing %current% records out of %count% total, starting on record %start%, ending on %end%', true) + )); + ?>

+ +
+ Paginator->prev('<< ' . __('previous', true), array(), null, array('class'=>'disabled'));?> + | Paginator->numbers();?> + | + Paginator->next(__('next', true) . ' >>', array(), null, array('class' => 'disabled'));?> +
+
+
+

+ +
\ No newline at end of file diff --git a/code/ryzom/tools/server/www/webtt/app/views/users/view.ctp b/code/ryzom/tools/server/www/webtt/app/views/users/view.ctp new file mode 100644 index 000000000..d43038c55 --- /dev/null +++ b/code/ryzom/tools/server/www/webtt/app/views/users/view.ctp @@ -0,0 +1,124 @@ +
+

+
+ > + > + +   + + > + > + +   + + > + > + +   + + > + > + +   + +
+
+
+

+ +
+ + diff --git a/code/ryzom/tools/server/www/webtt/app/views/votes/add.ctp b/code/ryzom/tools/server/www/webtt/app/views/votes/add.ctp new file mode 100644 index 000000000..1c548858e --- /dev/null +++ b/code/ryzom/tools/server/www/webtt/app/views/votes/add.ctp @@ -0,0 +1,22 @@ +
+Form->create('Vote');?> +
+ + Form->input('translation_id'); + echo $this->Form->input('user_id'); + ?> +
+Form->end(__('Submit', true));?> +
+
+

+ +
\ No newline at end of file diff --git a/code/ryzom/tools/server/www/webtt/app/views/votes/admin_add.ctp b/code/ryzom/tools/server/www/webtt/app/views/votes/admin_add.ctp new file mode 100644 index 000000000..64b8b7b0f --- /dev/null +++ b/code/ryzom/tools/server/www/webtt/app/views/votes/admin_add.ctp @@ -0,0 +1,22 @@ +
+Form->create('Vote');?> +
+ + Form->input('translation_id'); + echo $this->Form->input('user_id'); + ?> +
+Form->end(__('Submit', true));?> +
+
+

+ +
\ No newline at end of file diff --git a/code/ryzom/tools/server/www/webtt/app/views/votes/admin_edit.ctp b/code/ryzom/tools/server/www/webtt/app/views/votes/admin_edit.ctp new file mode 100644 index 000000000..bfddacefb --- /dev/null +++ b/code/ryzom/tools/server/www/webtt/app/views/votes/admin_edit.ctp @@ -0,0 +1,24 @@ +
+Form->create('Vote');?> +
+ + Form->input('id'); + echo $this->Form->input('translation_id'); + echo $this->Form->input('user_id'); + ?> +
+Form->end(__('Submit', true));?> +
+
+

+ +
\ No newline at end of file diff --git a/code/ryzom/tools/server/www/webtt/app/views/votes/admin_index.ctp b/code/ryzom/tools/server/www/webtt/app/views/votes/admin_index.ctp new file mode 100644 index 000000000..ec5ae6db7 --- /dev/null +++ b/code/ryzom/tools/server/www/webtt/app/views/votes/admin_index.ctp @@ -0,0 +1,63 @@ +
+

+ + + + + + + + + + + > + + + + + + + + +
Paginator->sort('id');?>Paginator->sort('translation_id');?>Paginator->sort('user_id');?>Paginator->sort('created');?>Paginator->sort('modified');?>
  + Html->link($vote['Translation']['translation_text'], array('controller' => 'translations', 'action' => 'view', $vote['Translation']['id'])); ?> + + Html->link($vote['User']['name'], array('controller' => 'users', 'action' => 'view', $vote['User']['id'])); ?> +    + Html->link(__('View', true), array('action' => 'view', $vote['Vote']['id'])); ?> + Html->link(__('Edit', true), array('action' => 'edit', $vote['Vote']['id'])); ?> + Html->link(__('Delete', true), array('action' => 'delete', $vote['Vote']['id']), null, sprintf(__('Are you sure you want to delete # %s?', true), $vote['Vote']['id'])); ?> +
+

+ Paginator->counter(array( + 'format' => __('Page %page% of %pages%, showing %current% records out of %count% total, starting on record %start%, ending on %end%', true) + )); + ?>

+ +
+ Paginator->prev('<< ' . __('previous', true), array(), null, array('class'=>'disabled'));?> + | Paginator->numbers();?> + | + Paginator->next(__('next', true) . ' >>', array(), null, array('class' => 'disabled'));?> +
+
+
+

+ +
\ No newline at end of file diff --git a/code/ryzom/tools/server/www/webtt/app/views/votes/admin_view.ctp b/code/ryzom/tools/server/www/webtt/app/views/votes/admin_view.ctp new file mode 100644 index 000000000..ee5e7e265 --- /dev/null +++ b/code/ryzom/tools/server/www/webtt/app/views/votes/admin_view.ctp @@ -0,0 +1,43 @@ +
+

+
+ > + > + +   + + > + > + Html->link($vote['Translation']['translation_text'], array('controller' => 'translations', 'action' => 'view', $vote['Translation']['id'])); ?> +   + + > + > + Html->link($vote['User']['name'], array('controller' => 'users', 'action' => 'view', $vote['User']['id'])); ?> +   + + > + > + +   + + > + > + +   + +
+
+
+

+ +
diff --git a/code/ryzom/tools/server/www/webtt/app/views/votes/edit.ctp b/code/ryzom/tools/server/www/webtt/app/views/votes/edit.ctp new file mode 100644 index 000000000..4ddbab111 --- /dev/null +++ b/code/ryzom/tools/server/www/webtt/app/views/votes/edit.ctp @@ -0,0 +1,24 @@ +
+Form->create('Vote');?> +
+ + Form->input('id'); + echo $this->Form->input('translation_id'); + echo $this->Form->input('user_id'); + ?> +
+Form->end(__('Submit', true));?> +
+
+

+ +
\ No newline at end of file diff --git a/code/ryzom/tools/server/www/webtt/app/views/votes/index.ctp b/code/ryzom/tools/server/www/webtt/app/views/votes/index.ctp new file mode 100644 index 000000000..ec5ae6db7 --- /dev/null +++ b/code/ryzom/tools/server/www/webtt/app/views/votes/index.ctp @@ -0,0 +1,63 @@ +
+

+ + + + + + + + + + + > + + + + + + + + +
Paginator->sort('id');?>Paginator->sort('translation_id');?>Paginator->sort('user_id');?>Paginator->sort('created');?>Paginator->sort('modified');?>
  + Html->link($vote['Translation']['translation_text'], array('controller' => 'translations', 'action' => 'view', $vote['Translation']['id'])); ?> + + Html->link($vote['User']['name'], array('controller' => 'users', 'action' => 'view', $vote['User']['id'])); ?> +    + Html->link(__('View', true), array('action' => 'view', $vote['Vote']['id'])); ?> + Html->link(__('Edit', true), array('action' => 'edit', $vote['Vote']['id'])); ?> + Html->link(__('Delete', true), array('action' => 'delete', $vote['Vote']['id']), null, sprintf(__('Are you sure you want to delete # %s?', true), $vote['Vote']['id'])); ?> +
+

+ Paginator->counter(array( + 'format' => __('Page %page% of %pages%, showing %current% records out of %count% total, starting on record %start%, ending on %end%', true) + )); + ?>

+ +
+ Paginator->prev('<< ' . __('previous', true), array(), null, array('class'=>'disabled'));?> + | Paginator->numbers();?> + | + Paginator->next(__('next', true) . ' >>', array(), null, array('class' => 'disabled'));?> +
+
+
+

+ +
\ No newline at end of file diff --git a/code/ryzom/tools/server/www/webtt/app/views/votes/view.ctp b/code/ryzom/tools/server/www/webtt/app/views/votes/view.ctp new file mode 100644 index 000000000..ee5e7e265 --- /dev/null +++ b/code/ryzom/tools/server/www/webtt/app/views/votes/view.ctp @@ -0,0 +1,43 @@ +
+

+
+ > + > + +   + + > + > + Html->link($vote['Translation']['translation_text'], array('controller' => 'translations', 'action' => 'view', $vote['Translation']['id'])); ?> +   + + > + > + Html->link($vote['User']['name'], array('controller' => 'users', 'action' => 'view', $vote['User']['id'])); ?> +   + + > + > + +   + + > + > + +   + +
+
+
+

+ +
diff --git a/code/ryzom/tools/server/www/webtt/app/webroot/css/960.css b/code/ryzom/tools/server/www/webtt/app/webroot/css/960.css new file mode 100755 index 000000000..6db1bd34c --- /dev/null +++ b/code/ryzom/tools/server/www/webtt/app/webroot/css/960.css @@ -0,0 +1,491 @@ +/* + 960 Grid System ~ Core CSS. + Learn more ~ http://960.gs/ + + Licensed under GPL and MIT. +*/ + +/* =Containers +--------------------------------------------------------------------------------*/ + +.container_12, +.container_16 +{ + margin-left: auto; + margin-right: auto; + width: 960px; +} + +/* =Grid >> Global +--------------------------------------------------------------------------------*/ + +.grid_1, +.grid_2, +.grid_3, +.grid_4, +.grid_5, +.grid_6, +.grid_7, +.grid_8, +.grid_9, +.grid_10, +.grid_11, +.grid_12, +.grid_13, +.grid_14, +.grid_15, +.grid_16 +{ + display: inline; + float: left; + margin-left: 10px; + margin-right: 10px; +} + +.container_12 .grid_3, +.container_16 .grid_4 +{ + width: 220px; +} + +.container_12 .grid_6, +.container_16 .grid_8 +{ + width: 460px; +} + +.container_12 .grid_9, +.container_16 .grid_12 +{ + width: 700px; +} + +.container_12 .grid_12, +.container_16 .grid_16 +{ + width: 940px; +} + +/* =Grid >> Children (Alpha ~ First, Omega ~ Last) +--------------------------------------------------------------------------------*/ + +.alpha +{ + margin-left: 0; +} + +.omega +{ + margin-right: 0; +} + +/* =Grid >> 12 Columns +--------------------------------------------------------------------------------*/ + +.container_12 .grid_1 +{ + width: 60px; +} + +.container_12 .grid_2 +{ + width: 140px; +} + +.container_12 .grid_4 +{ + width: 300px; +} + +.container_12 .grid_5 +{ + width: 380px; +} + +.container_12 .grid_7 +{ + width: 540px; +} + +.container_12 .grid_8 +{ + width: 620px; +} + +.container_12 .grid_10 +{ + width: 780px; +} + +.container_12 .grid_11 +{ + width: 860px; +} + +/* =Grid >> 16 Columns +--------------------------------------------------------------------------------*/ + +.container_16 .grid_1 +{ + width: 40px; +} + +.container_16 .grid_2 +{ + width: 100px; +} + +.container_16 .grid_3 +{ + width: 160px; +} + +.container_16 .grid_5 +{ + width: 280px; +} + +.container_16 .grid_6 +{ + width: 340px; +} + +.container_16 .grid_7 +{ + width: 400px; +} + +.container_16 .grid_9 +{ + width: 520px; +} + +.container_16 .grid_10 +{ + width: 580px; +} + +.container_16 .grid_11 +{ + width: 640px; +} + +.container_16 .grid_13 +{ + width: 760px; +} + +.container_16 .grid_14 +{ + width: 820px; +} + +.container_16 .grid_15 +{ + width: 880px; +} + +/* =Prefix Extra Space >> Global +--------------------------------------------------------------------------------*/ + +.container_12 .prefix_3, +.container_16 .prefix_4 +{ + padding-left: 240px; +} + +.container_12 .prefix_6, +.container_16 .prefix_8 +{ + padding-left: 480px; +} + +.container_12 .prefix_9, +.container_16 .prefix_12 +{ + padding-left: 720px; +} + +/* =Prefix Extra Space >> 12 Columns +--------------------------------------------------------------------------------*/ + +.container_12 .prefix_1 +{ + padding-left: 80px; +} + +.container_12 .prefix_2 +{ + padding-left: 160px; +} + +.container_12 .prefix_4 +{ + padding-left: 320px; +} + +.container_12 .prefix_5 +{ + padding-left: 400px; +} + +.container_12 .prefix_7 +{ + padding-left: 560px; +} + +.container_12 .prefix_8 +{ + padding-left: 640px; +} + +.container_12 .prefix_10 +{ + padding-left: 800px; +} + +.container_12 .prefix_11 +{ + padding-left: 880px; +} + +/* =Prefix Extra Space >> 16 Columns +--------------------------------------------------------------------------------*/ + +.container_16 .prefix_1 +{ + padding-left: 60px; +} + +.container_16 .prefix_2 +{ + padding-left: 120px; +} + +.container_16 .prefix_3 +{ + padding-left: 180px; +} + +.container_16 .prefix_5 +{ + padding-left: 300px; +} + +.container_16 .prefix_6 +{ + padding-left: 360px; +} + +.container_16 .prefix_7 +{ + padding-left: 420px; +} + +.container_16 .prefix_9 +{ + padding-left: 540px; +} + +.container_16 .prefix_10 +{ + padding-left: 600px; +} + +.container_16 .prefix_11 +{ + padding-left: 660px; +} + +.container_16 .prefix_13 +{ + padding-left: 780px; +} + +.container_16 .prefix_14 +{ + padding-left: 840px; +} + +.container_16 .prefix_15 +{ + padding-left: 900px; +} + +/* =Suffix Extra Space >> Global +--------------------------------------------------------------------------------*/ + +.container_12 .suffix_3, +.container_16 .suffix_4 +{ + padding-right: 240px; +} + +.container_12 .suffix_6, +.container_16 .suffix_8 +{ + padding-right: 480px; +} + +.container_12 .suffix_9, +.container_16 .suffix_12 +{ + padding-right: 720px; +} + +/* =Suffix Extra Space >> 12 Columns +--------------------------------------------------------------------------------*/ + +.container_12 .suffix_1 +{ + padding-right: 80px; +} + +.container_12 .suffix_2 +{ + padding-right: 160px; +} + +.container_12 .suffix_4 +{ + padding-right: 320px; +} + +.container_12 .suffix_5 +{ + padding-right: 400px; +} + +.container_12 .suffix_7 +{ + padding-right: 560px; +} + +.container_12 .suffix_8 +{ + padding-right: 640px; +} + +.container_12 .suffix_10 +{ + padding-right: 800px; +} + +.container_12 .suffix_11 +{ + padding-right: 880px; +} + +/* =Suffix Extra Space >> 16 Columns +--------------------------------------------------------------------------------*/ + +.container_16 .suffix_1 +{ + padding-right: 60px; +} + +.container_16 .suffix_2 +{ + padding-right: 120px; +} + +.container_16 .suffix_3 +{ + padding-right: 180px; +} + +.container_16 .suffix_5 +{ + padding-right: 300px; +} + +.container_16 .suffix_6 +{ + padding-right: 360px; +} + +.container_16 .suffix_7 +{ + padding-right: 420px; +} + +.container_16 .suffix_9 +{ + padding-right: 540px; +} + +.container_16 .suffix_10 +{ + padding-right: 600px; +} + +.container_16 .suffix_11 +{ + padding-right: 660px; +} + +.container_16 .suffix_13 +{ + padding-right: 780px; +} + +.container_16 .suffix_14 +{ + padding-right: 840px; +} + +.container_16 .suffix_15 +{ + padding-right: 900px; +} + +/* =Clear Floated Elements +--------------------------------------------------------------------------------*/ + +/* http://sonspring.com/journal/clearing-floats */ + +html body * span.clear, +html body * div.clear, +html body * li.clear, +html body * dd.clear +{ + background: none; + border: 0; + clear: both; + display: block; + float: none; + font-size: 0; + list-style: none; + margin: 0; + padding: 0; + overflow: hidden; + visibility: hidden; + width: 0; + height: 0; +} + +/* http://www.positioniseverything.net/easyclearing.html */ + +.clearfix:after +{ + clear: both; + content: '.'; + display: block; + visibility: hidden; + height: 0; +} + +.clearfix +{ + display: inline-block; +} + +* html .clearfix +{ + height: 1%; +} + +.clearfix +{ + display: block; +} \ No newline at end of file diff --git a/code/ryzom/tools/server/www/webtt/app/webroot/css/grid.css b/code/ryzom/tools/server/www/webtt/app/webroot/css/grid.css new file mode 100755 index 000000000..dd21d4e56 --- /dev/null +++ b/code/ryzom/tools/server/www/webtt/app/webroot/css/grid.css @@ -0,0 +1,491 @@ +/* + 960 Grid System ~ Core CSS. + Learn more ~ http://960.gs/ + + Licensed under GPL and MIT. +*/ + +/* =Containers +--------------------------------------------------------------------------------*/ + +.container_12, +.container_16 +{ + width: 92%; + margin-left: 4%; + margin-right: 4%; +} + +/* =Grid >> Global +--------------------------------------------------------------------------------*/ + +.grid_1, +.grid_2, +.grid_3, +.grid_4, +.grid_5, +.grid_6, +.grid_7, +.grid_8, +.grid_9, +.grid_10, +.grid_11, +.grid_12, +.grid_13, +.grid_14, +.grid_15, +.grid_16 +{ + display: inline; + float: left; + margin-left: 1%; + margin-right: 1%; +} + +.container_12 .grid_3, +.container_16 .grid_4 +{ + width: 23%; +} + +.container_12 .grid_6, +.container_16 .grid_8 +{ + width: 48%; +} + +.container_12 .grid_9, +.container_16 .grid_12 +{ + width: 73%; +} + +.container_12 .grid_12, +.container_16 .grid_16 +{ + width: 98%; +} + +/* =Grid >> Children (Alpha ~ First, Omega ~ Last) +--------------------------------------------------------------------------------*/ + +.alpha +{ + margin-left: 0; +} + +.omega +{ + margin-right: 0; +} + +/* =Grid >> 12 Columns +--------------------------------------------------------------------------------*/ + +.container_12 .grid_1 +{ + width: 6.333%; +} + +.container_12 .grid_2 +{ + width: 14.666%; +} + +.container_12 .grid_4 +{ + width: 31.333%; +} + +.container_12 .grid_5 +{ + width: 39.666%; +} + +.container_12 .grid_7 +{ + width: 56.333%; +} + +.container_12 .grid_8 +{ + width: 64.666%; +} + +.container_12 .grid_10 +{ + width: 81.333%; +} + +.container_12 .grid_11 +{ + width: 89.666%; +} + +/* =Grid >> 16 Columns +--------------------------------------------------------------------------------*/ + +.container_16 .grid_1 +{ + width: 4.25%; +} + +.container_16 .grid_2 +{ + width: 10.5%; +} + +.container_16 .grid_3 +{ + width: 16.75%; +} + +.container_16 .grid_5 +{ + width: 29.25%; +} + +.container_16 .grid_6 +{ + width: 35.5%; +} + +.container_16 .grid_7 +{ + width: 41.75%; +} + +.container_16 .grid_9 +{ + width: 54.25%; +} + +.container_16 .grid_10 +{ + width: 60.5%; +} + +.container_16 .grid_11 +{ + width: 66.75%; +} + +.container_16 .grid_13 +{ + width: 79.25%; +} + +.container_16 .grid_14 +{ + width: 85.5%; +} + +.container_16 .grid_15 +{ + width: 91.75%; +} + +/* =Prefix Extra Space >> Global +--------------------------------------------------------------------------------*/ + +.container_12 .prefix_3, +.container_16 .prefix_4 +{ + padding-left: 25%; +} + +.container_12 .prefix_6, +.container_16 .prefix_8 +{ + padding-left: 50%; +} + +.container_12 .prefix_9, +.container_16 .prefix_12 +{ + padding-left: 75%; +} + +/* =Prefix Extra Space >> 12 Columns +--------------------------------------------------------------------------------*/ + +.container_12 .prefix_1 +{ + padding-left: 8.333%; +} + +.container_12 .prefix_2 +{ + padding-left: 16.666%; +} + +.container_12 .prefix_4 +{ + padding-left: 33.333%; +} + +.container_12 .prefix_5 +{ + padding-left: 41.666%; +} + +.container_12 .prefix_7 +{ + padding-left: 58.333%; +} + +.container_12 .prefix_8 +{ + padding-left: 66.666%; +} + +.container_12 .prefix_10 +{ + padding-left: 83.333%; +} + +.container_12 .prefix_11 +{ + padding-left: 91.666%; +} + +/* =Prefix Extra Space >> 16 Columns +--------------------------------------------------------------------------------*/ + +.container_16 .prefix_1 +{ + padding-left: 6.25%; +} + +.container_16 .prefix_2 +{ + padding-left: 12.5%; +} + +.container_16 .prefix_3 +{ + padding-left: 18.75%; +} + +.container_16 .prefix_5 +{ + padding-left: 31.25%; +} + +.container_16 .prefix_6 +{ + padding-left: 37.5%; +} + +.container_16 .prefix_7 +{ + padding-left: 43.75%; +} + +.container_16 .prefix_9 +{ + padding-left: 56.25%; +} + +.container_16 .prefix_10 +{ + padding-left: 62.5%; +} + +.container_16 .prefix_11 +{ + padding-left: 68.75%; +} + +.container_16 .prefix_13 +{ + padding-left: 81.25%; +} + +.container_16 .prefix_14 +{ + padding-left: 87.5%; +} + +.container_16 .prefix_15 +{ + padding-left: 93.75%; +} + +/* =Suffix Extra Space >> Global +--------------------------------------------------------------------------------*/ + +.container_12 .suffix_3, +.container_16 .suffix_4 +{ + padding-right: 25%; +} + +.container_12 .suffix_6, +.container_16 .suffix_8 +{ + padding-right: 50%; +} + +.container_12 .suffix_9, +.container_16 .suffix_12 +{ + padding-right: 75%; +} + +/* =Suffix Extra Space >> 12 Columns +--------------------------------------------------------------------------------*/ + +.container_12 .suffix_1 +{ + padding-right: 8.333%; +} + +.container_12 .suffix_2 +{ + padding-right: 16.666%; +} + +.container_12 .suffix_4 +{ + padding-right: 33.333%; +} + +.container_12 .suffix_5 +{ + padding-right: 41.666%; +} + +.container_12 .suffix_7 +{ + padding-right: 58.333%; +} + +.container_12 .suffix_8 +{ + padding-right: 66.666%; +} + +.container_12 .suffix_10 +{ + padding-right: 83.333%; +} + +.container_12 .suffix_11 +{ + padding-right: 91.666%; +} + +/* =Suffix Extra Space >> 16 Columns +--------------------------------------------------------------------------------*/ + +.container_16 .suffix_1 +{ + padding-right: 6.25%; +} + +.container_16 .suffix_2 +{ + padding-right: 16.5%; +} + +.container_16 .suffix_3 +{ + padding-right: 18.75%; +} + +.container_16 .suffix_5 +{ + padding-right: 31.25%; +} + +.container_16 .suffix_6 +{ + padding-right: 37.5%; +} + +.container_16 .suffix_7 +{ + padding-right: 43.75%; +} + +.container_16 .suffix_9 +{ + padding-right: 56.25%; +} + +.container_16 .suffix_10 +{ + padding-right: 62.5%; +} + +.container_16 .suffix_11 +{ + padding-right: 68.75%; +} + +.container_16 .suffix_13 +{ + padding-right: 81.25%; +} + +.container_16 .suffix_14 +{ + padding-right: 87.5%; +} + +.container_16 .suffix_15 +{ + padding-right: 93.75%; +} + +/* =Clear Floated Elements +--------------------------------------------------------------------------------*/ + +/* http://sonspring.com/journal/clearing-floats */ + +html body * span.clear, +html body * div.clear, +html body * li.clear, +html body * dd.clear +{ + background: none; + border: 0; + clear: both; + display: block; + float: none; + font-size: 0; + list-style: none; + margin: 0; + padding: 0; + overflow: hidden; + visibility: hidden; + width: 0; + height: 0; +} + +/* http://www.positioniseverything.net/easyclearing.html */ + +.clearfix:after +{ + clear: both; + content: '.'; + display: block; + visibility: hidden; + height: 0; +} + +.clearfix +{ + display: inline-block; +} + +* html .clearfix +{ + height: 1%; +} + +.clearfix +{ + display: block; +} \ No newline at end of file diff --git a/code/ryzom/tools/server/www/webtt/app/webroot/css/ie.css b/code/ryzom/tools/server/www/webtt/app/webroot/css/ie.css new file mode 100755 index 000000000..7fe61ff28 --- /dev/null +++ b/code/ryzom/tools/server/www/webtt/app/webroot/css/ie.css @@ -0,0 +1,31 @@ +/* + Fluid 960 Grid System - IE Fixes (IE7 and greater) + Learn more ~ http://www.designinfluences.com/ + + Licensed under GPL and MIT. +*/ + +/* =Grid >> Global +--------------------------------------------------------------------------------*/ + +.grid_1, +.grid_2, +.grid_3, +.grid_4, +.grid_5, +.grid_6, +.grid_7, +.grid_8, +.grid_9, +.grid_10, +.grid_11, +.grid_12, +.grid_13, +.grid_14, +.grid_15, +.grid_16 +{ + margin-left: .92%; + margin-right: .92%; +} + diff --git a/code/ryzom/tools/server/www/webtt/app/webroot/css/ie6.css b/code/ryzom/tools/server/www/webtt/app/webroot/css/ie6.css new file mode 100755 index 000000000..b1ff5b5ce --- /dev/null +++ b/code/ryzom/tools/server/www/webtt/app/webroot/css/ie6.css @@ -0,0 +1,31 @@ +/* + Fluid 960 Grid System - IE6 Fixes + Learn more ~ http://www.designinfluences.com/ + + Licensed under GPL and MIT. +*/ + +/* =Grid >> Global +--------------------------------------------------------------------------------*/ + +.grid_1, +.grid_2, +.grid_3, +.grid_4, +.grid_5, +.grid_6, +.grid_7, +.grid_8, +.grid_9, +.grid_10, +.grid_11, +.grid_12, +.grid_13, +.grid_14, +.grid_15, +.grid_16 +{ + margin-left: .8%; + margin-right: .8%; +} + diff --git a/code/ryzom/tools/server/www/webtt/app/webroot/css/layout.css b/code/ryzom/tools/server/www/webtt/app/webroot/css/layout.css new file mode 100755 index 000000000..1c88c6c95 --- /dev/null +++ b/code/ryzom/tools/server/www/webtt/app/webroot/css/layout.css @@ -0,0 +1,675 @@ +/* +----------------------------------------------- +Grey Box Method - Layout CSS +----------------------------------------------- */ + +body { + background: #eee; + border-top: 5px solid #000; + color: #333; + font-size: 11px; + padding: 0 0 40px; +} + + +/* anchors +----------------------------------------------- */ +a { + color: #000; + font-weight:bold; + text-decoration: none; +} +a:hover { + color:#333; +} + + +/* 960 grid system container background +----------------------------------------------- */ +.container_12, +.container_16 { + background:#fff; +} + + +/* headings +----------------------------------------------- */ +h1, h2, h3, h4, h5, h6 {line-height:1.2em; margin-bottom:.3em;} +h2 {margin-top:1em;} +h5 {font-size:1.2em;} +h6 {font-size:1em; text-transform:uppercase;} + + +h1 a { + font-weight:normal; +} + + +/* branding +----------------------------------------------- */ +h1#branding { + font-weight:normal; + font-size:3em; + text-align:left; + background:#aaa; + padding:.7em 1em; + margin-bottom:0; +} + + +/* page heading +----------------------------------------------- */ +h2#page-heading { + font-weight:normal; + padding:.5em; + margin:0 0 10px 0; + border-bottom:1px solid #ccc; +} + + +/* boxes +----------------------------------------------- */ +.box { + background:#ddd; + margin-bottom:20px; + padding:10px 10px 1px 10px; +} +.box h2 { + font-size:1em; + font-weight:normal; + text-transform:uppercase; + color:#fff; + background:#333; + margin:-10px -10px 0 -10px; + padding:6px 12px; +} +.box h2 a, +.box h2 a.visible { + color:#fff; + background:#333 url("../img/switch_minus.gif") 97% 50% no-repeat; + display:block; + padding:6px 12px; + margin:-6px -12px; + border:none; +} +.grid_4 .box h2 a { + background-position: 97% 50%; +} +.grid_5 .box h2 a { + background-position: 98% 50%; +} +.grid_12 .box h2 a { + background-position: 99% 50%; +} + + +.box h2 a.hidden, +.box h2 a.hidden:hover { + background-image: url("../img/switch_plus.gif"); +} +.box h2 a:hover { + background-color:#111; +} +.block { + padding-top:10px; +} +div.menu { + padding:0; +} +div.menu h2 { + margin:0; +} +div.menu .block { + padding-top:0; +} + + +/* paragraphs, quotes and lists +----------------------------------------------- */ +p { + margin-bottom:1em; +} +blockquote { + font-family: Georgia, 'Times New Roman', serif; + font-size:1.2em; + padding-left:1em; + border-left:4px solid #ccc; +} +blockquote cite { + font-size:.9em; +} +ul, ol { + padding-top:0; +} + + +/* menus +----------------------------------------------- */ +ul.menu { + list-style:none; + border-top:1px solid #bbb; +} +ul.menu li { + margin:0; +} +ul.menu li a { + display:block; + padding:4px 10px; + border-bottom:1px solid #ccc; +} +ul.menu li a:hover { + background:#eee; +} +ul.menu li a:active { + background:#ccc; +} + + +/* submenus +----------------------------------------------- */ +ul.menu ul { + list-style:none; + margin:0; +} +ul.menu ul li a { + padding-left:30px; +} + + +/* section menus +----------------------------------------------- */ +ul.section { + border-top:0; + margin-bottom:0; +} +ul.section li { + text-transform:uppercase; +} +ul.section li a { + background:#bbb; +} +ul.section li a:hover { + background:#aaa; +} +ul.section li a:active { + color:#fff; + background:#666; +} +ul.section li li a { + background:#ddd; + border-bottom:1px solid #eee; +} +ul.section li li a:hover { + background:#ccc; +} +ul.section li li a:active { + color:#000; + background:#fff; +} +ul.section ul li { + text-transform:none; +} +ul.section ul.current li a { + background:#eee; + border-bottom:1px solid #fff; +} +ul.section ul.current li a:hover { + background:#ddd; +} +ul.section ul.current li a:active { + background:#fff; +} +ul.section li a.current { + color:#fff; + background:#666; +} +ul.section li a.current:hover { + background:#555; +} +ul.section li a.current:active { + background:#444; +} +ul.section li a.active { + background:#fff; + cursor:default; +} +ul.section li.current > a.active, +ul.section li.current > a.active:hover { + color:#fff; + background:#666; + cursor:default; +} + + +/* table +----------------------------------------------- */ +table { + width:100%; + border:1px solid #bbb; + margin-bottom:10px; +} +col.colC { + width:8em; +} +th, td { + padding:.2em 1em; + text-align:left; +} +thead th { + border-bottom:2px solid #888; + background:#bbb; + padding:.4em 1em .2em; +} +thead th.table-head { + font-size:1em; + font-weight:normal; + text-transform:uppercase; + color:#fff; + background:#555; + border:1px solid #555; +} +tbody th, +tbody td { + border-top:1px solid #bbb; + border-bottom:1px solid #bbb; + background:#eee; +} +tbody tr.odd th, +tbody tr.odd td { + background:#fff; +} +tfoot th, +tfoot td { + border-top:2px solid #666; + background:#eee; +} +tfoot tr.total th, +tfoot tr.total td { + border-top:6px double #666; +} +tfoot tr.total th { + text-transform:uppercase; +} +th.currency, +td.currency { + text-align:right; +} +tfoot.dark th, tfoot.dark td { + background: #bbbbbb; +} + + +/* forms +----------------------------------------------- */ +form { + overflow:hidden; +} +fieldset { + border:1px solid #bbb; + padding:10px; + position:relative; + background:#e9e9e9; + margin-bottom:10px; +} +legend { + font-size:1.1em; + padding:.4em .8em; + background:#fff; + border:1px solid #bbb; +} +fieldset.login p { + margin-bottom:1em; + margin-top:0pt; +} +fieldset p label { + width:98%; +} +fieldset p input { + width:98%; +} +fieldset p select { + width:99%; +} +fieldset.login p label { + float:left; + line-height:2em; + margin-right:3%; + text-align:right; + width:32%; +} +fieldset.login p input { + width:60%; +} +fieldset.login input.button { + margin-left:35%; +} +form p.notice { + font-weight:bold; +} +input.search.text { + width:66%; +} +input.search.button { + width:28%; + margin-left:2%; +} + + +/* articles +----------------------------------------------- */ +.articles { + padding:0; +} +.articles h2 { + margin:0; +} +#articles { + padding-top:0; +} +.article { + border-top:1px solid #666; + padding-top:.5em; +} +.box .article { + border-top:3px solid #fff; + padding:13px 10px 0 10px; +} +.article h2 { + font-size:2em; + font-weight:normal; + text-transform:none; + color:#333; + background:transparent; + padding:0; + margin:0; + border:none; +} +.article h3 { + margin-bottom:.2em; + font-size:1.6em; +} +.box .first { + border-top:none; +} +.article h4 { + font-size:1.2em; + text-transform:uppercase; + margin-bottom:.5em; +} +.article a.image { + float:left; + margin:3px 10px 3px 0; + padding:4px; + border:1px solid #bbb; + background:#fff; +} +.article a.image:hover { + border:1px solid #666; +} +.article a.image img { + float:left; +} +.article p.meta { + color:#666; + border-top:1px dotted #999; + border-bottom:1px dotted #999; + padding:.3em 0; + margin-bottom:.8em; +} + + +/* site information +----------------------------------------------- */ +#site_info .box { + color:#ccc; + background:#666; + margin-bottom:10px; +} +#site_info a { + color:#fff; +} +#site_info a:hover { + color:#000; +} + + +/* AJAX sliding shelf +----------------------------------------------- */ +#loading {float:right; margin-right:14px; margin-top:-2px;} +.block {padding-bottom:1px;} + + +/* Accordian +----------------------------------------------- */ +.toggler { + color: #222; + margin: 0; + padding: 2px 5px; + background: #eee; + border-bottom: 1px solid #ddd; + border-right: 1px solid #ddd; + border-top: 1px solid #f5f5f5; + border-left: 1px solid #f5f5f5; + font-size:1.1em; + font-weight: normal; +} +.element h4 { + margin: 0; + padding:4px; + line-height:1.2em; +} +.element p { + margin: 0; + padding: 4px; +} +.float-right { + padding:10px 20px; + float:right; +} + +#accordian-block { + padding-bottom:10px; +} + + +/* Mootools Kwicks +----------------------------------------------- */ +#kwick-box { + padding:0; + overflow:hidden; +} +#kwick-box h2 { + margin:0; +} +#kwick { + position: relative; +} +#kwick .kwicks { + display: block; + background: #999; + height: 120px; + list-style:none; + margin:0; + overflow:hidden; +} +#kwick li { + float: left; + margin:0; + padding:0; +} +#kwick .kwick { + display: block; + cursor: pointer; + overflow: hidden; + height: 100px; + width: 215px; + padding: 10px; + background: #fff; +} +#kwick .kwick span { + color:#fff; +} +#kwick .one { + background: #666; +} +#kwick .two { + background: #777; +} +#kwick .three { + background: #888; +} +#kwick .four { + background: #999; +} +/* Main Nav Current States */ +ul.nav li a.current { + background: #888; +} + +/* CakePHP Specific */ +div#flashMessage { + padding: 10px; + margin: 0px 13px 10px 11px; + border: 1px dashed #888; + background: #eee; + font-size: 14px; +} +div.flash-error { + color: #bf0000; + background: #ffbfbf !important; + border-color: #bf0000 !important; +} +div.flash-warning { + color: #725600; + background: #ffffbf !important; + border-color: #bfbf00 !important; +} +div.flash-success { + color: #00bf00; + background: #dfffbf !important; + border-color: #00bf00 !important; +} +div.error-message { + color: #bf0000; + font-weight: bold; +} +.input { + margin: 0px 0px 5px 0px; +} +.text input { + width: 250px; +} +.input label { + width: 100px; + text-align: right; + display: block; + float: left; + margin: 0px 5px 0px 0px; + padding: 2px 0px 0px 0px; +} +.text label { + padding: 6px 0px 0px 0px; +} +.form-submit-group { + float: right; + margin: 0px 0px 5px 0px; +} +.form-submit-group .submit { + float: left; +} +.form-cancel { + float: left; + padding-top: 5px; + margin-right: 5px; +} +/** Scaffold View **/ +dl { + line-height: 2em; + margin: 0em 0em; + width: 60%; +} +dl .altrow { + background: #f4f4f4; +} +dt { + font-weight: bold; + padding-left: 4px; + vertical-align: top; +} +dd { + margin-left: 10em; + margin-top: -2em; + vertical-align: top; +} +/** CakePHP Notices and Errors **/ +div.message { + clear: both; + color: #333; + font-size: 140%; + font-weight: bold; + margin: 0 0 1em 0; + background: #c73e14; + padding: 5px; +} +div.error-message { + clear: both; + color: #bf0000; + background: #ffbfbf; + border-color: #bf0000; + font-weight: bold; +} +p.error { + color: #bf0000; + background: #ffbfbf; + border-color: #bf0000; + font-family: Courier, monospace; + font-size: 120%; + line-height: 140%; + padding: 0.8em; + margin: 1em 0; +} +p.error em { + color: #000; + font-weight: normal; + line-height: 140%; +} +.notice { + color: #725600; + background: #ffffbf; + border-color: #bfbf00; + display: block; + font-family: Courier, monospace; + font-size: 120%; + line-height: 140%; + padding: 0.8em; + margin: 1em 0; +} +.success { + color: #00bf00; + background: #dfffbf; + border-color: #00bf00; +} + +/* jQuery UI Stuff */ +#ui-datepicker-div { + background: #fff; + padding: 5px; + border: 1px solid #eee; +} +a.ui-datepicker-prev { + width: 35px; + float: left; + text-align: left; +} +a.ui-datepicker-next { + width: 35px; + float: right; + text-align: right; +} +div.ui-datepicker-title { + text-align: center; +} +table.ui-datepicker-calendar { + padding-bottom: 0px; + margin-bottom: 0px; +} diff --git a/code/ryzom/tools/server/www/webtt/app/webroot/css/nav.css b/code/ryzom/tools/server/www/webtt/app/webroot/css/nav.css new file mode 100755 index 000000000..53bff8d1e --- /dev/null +++ b/code/ryzom/tools/server/www/webtt/app/webroot/css/nav.css @@ -0,0 +1,167 @@ +/* +----------------------------------------------- +Navigation +----------------------------------------------- */ + +/* navigation (horizontal subnavigation) +----------------------------------------------- */ +ul.nav, +ul.nav * { margin:0;padding:0;} +ul.nav { + position:relative; + background:#666; + max-width:100%; + height:2.5em; + } +ul.nav li { + cursor:pointer; + float:left; + text-align:center; + list-style-type:none; + font-weight:normal; +} +ul.nav li ul { + cursor:default; + width:100%; + max-width:100%; + position:absolute; + height:auto; + top:2.5em; + background-position:0 0 !important; + left:-9000px; +} +ul.nav li ul li { + padding:0; + border:none; + width:auto; + max-width:none; +} +ul.nav li a { + color:#fff; + background:#666; + font-weight:bold; + text-decoration:none; + display:block; + float:left; + padding:0 1em; + height:2.4em; + line-height:2.5em; +} +ul.nav li ul li a { + position:relative !important; /* ie Mac */ + cursor:pointer !important; + white-space:nowrap; + line-height:2em; + height:2em; + font-weight:normal; + color:#666; + background-position:0 50% !important; +} + +ul.nav li:hover a, +ul.nav li a:hover, +ul.nav li a:focus {color:#000; background:#ccc;} +ul.nav li a:active {color:#666; background:#fff;} +ul.nav li:hover ul {left:0;z-index:10} +ul.nav li ul, +ul.nav li {background:#ccc !important} +ul.nav li:hover ul li a {color:#444;} +ul.nav li:hover ul li a:hover {color:#000; background:#fff;} +ul.nav li:hover ul li a:active {color:#666; background:#fff;} + +ul.nav li.current a {color:#666; background:#fff; cursor:default; font-weight:bold;} +ul.nav li.current ul {left:0;z-index:5} +ul.nav li.current ul, +ul.nav li.current {background:#ccc !important} +ul.nav li.current ul li a {color:#444; background:#ccc; font-weight:normal;} +ul.nav li.current ul li a:hover {color:#000; background:#fff;} +ul.nav li ul li.current a, +ul.nav li ul li.current a:hover, +ul.nav li.current:hover ul li a:active {color:#666; background:#fff;} + + +/* navigation (vertical subnavigation) +----------------------------------------------- */ +ul.nav { + background:#666; +} +ul.main li { + position:relative; + top:0; + left:0; +} +ul.main li ul { + border-top:0; +} +ul.main li ul li { + float:left; +} +ul.main li a { + height:2.5em; + line-height:2.5em; + border:0; + color:#fff; + background:#666; +} +ul.main li ul li a { + width:12em; + line-height:2em; + height:2em; + text-align:left; + color:#fff; + border-top:1px solid #444; + background:#444; +} +ul.main li a:focus {color:#fff; background:#666;} +ul.main li ul li a:hover { + color:#fff; + background:#555; +} +ul.main li:hover a { + color:#fff; + background:#555; +} +ul.main li:hover ul li a {color:#fff;} +ul.main li:hover ul li a:hover {color:#fff; background:#444;} +ul.main li:hover a:active {background:#444;} +ul.main li:hover ul li a:active {color:#fff; background:#222;} + + +/* secondary list +----------------------------------------------- */ +ul.nav li.secondary { + float:right; + color:#cde; + background:transparent !important; +} +ul.nav li.secondary span.status { + float:left; + padding:0 1em; + line-height:2.77em; + height:2.77em; + font-size:0.9em; +} +ul.nav li.secondary span.status a { + float:none; + display:inline; + padding:0; + height:auto; + line-height:auto; + color:#cde; + background:transparent; +} +ul.nav li.secondary span.status a:hover { + color:#fff; + background:transparent; +} +ul.nav li.secondary span.status span { + text-transform:capitalize; +} +ul.nav li.secondary:hover a { + color:#fff; + background:#666; +} +ul.nav li.secondary:hover a:hover { + background:#555; +} +ul.nav li.secondary:hover a:active {background:#444;} diff --git a/code/ryzom/tools/server/www/webtt/app/webroot/css/reset.css b/code/ryzom/tools/server/www/webtt/app/webroot/css/reset.css new file mode 100755 index 000000000..3aadd3dd6 --- /dev/null +++ b/code/ryzom/tools/server/www/webtt/app/webroot/css/reset.css @@ -0,0 +1,53 @@ +/* http://meyerweb.com/eric/tools/css/reset/ */ +/* v1.0 | 20080212 */ + +html, body, div, span, applet, object, iframe, +h1, h2, h3, h4, h5, h6, p, blockquote, pre, +a, abbr, acronym, address, big, cite, code, +del, dfn, em, font, img, ins, kbd, q, s, samp, +small, strike, strong, sub, sup, tt, var, +b, u, i, center, +dl, dt, dd, ol, ul, li, +fieldset, form, label, legend, +table, caption, tbody, tfoot, thead, tr, th, td { + margin: 0; + padding: 0; + border: 0; + outline: 0; + font-size: 100%; + vertical-align: baseline; + background: transparent; +} +body { + line-height: 1; +} +ol, ul { + list-style: none; +} +blockquote, q { + quotes: none; +} +blockquote:before, blockquote:after, +q:before, q:after { + content: ''; + content: none; +} + +/* remember to define focus styles! */ +:focus { + outline: 0; +} + +/* remember to highlight inserts somehow! */ +ins { + text-decoration: none; +} +del { + text-decoration: line-through; +} + +/* tables still need 'cellspacing="0"' in the markup */ +table { + border-collapse: collapse; + border-spacing: 0; +} \ No newline at end of file diff --git a/code/ryzom/tools/server/www/webtt/app/webroot/css/text.css b/code/ryzom/tools/server/www/webtt/app/webroot/css/text.css new file mode 100755 index 000000000..b6a687bba --- /dev/null +++ b/code/ryzom/tools/server/www/webtt/app/webroot/css/text.css @@ -0,0 +1,98 @@ +/* + 960 Grid System ~ Text CSS. + Learn more ~ http://960.gs/ + + Licensed under GPL and MIT. +*/ + +/* =Basic HTML +--------------------------------------------------------------------------------*/ + +body +{ + font: 13px/1.5 Helvetica, Arial, 'Liberation Sans', FreeSans, sans-serif; +} + +a:focus +{ + outline: 1px dotted invert; +} + +hr +{ + border-color: #ccc; + border-style: solid; + border-width: 1px 0 0; + clear: both; + height: 0; +} + +/* =Headings +--------------------------------------------------------------------------------*/ + +h1 +{ + font-size: 25px; +} + +h2 +{ + font-size: 23px; +} + +h3 +{ + font-size: 21px; +} + +h4 +{ + font-size: 19px; +} + +h5 +{ + font-size: 17px; +} + +h6 +{ + font-size: 15px; +} + +/* =Spacing +--------------------------------------------------------------------------------*/ + +ol +{ + list-style: decimal; +} + +ul +{ + list-style: square; +} + +li +{ + margin-left: 30px; +} + +p, +dl, +hr, +h1, +h2, +h3, +h4, +h5, +h6, +ol, +ul, +pre, +table, +address, +fieldset +{ + margin-bottom: 20px; +} \ No newline at end of file diff --git a/code/ryzom/tools/server/www/webtt/app/webroot/js/jquery-1.3.2.min.js b/code/ryzom/tools/server/www/webtt/app/webroot/js/jquery-1.3.2.min.js new file mode 100644 index 000000000..b1ae21d8b --- /dev/null +++ b/code/ryzom/tools/server/www/webtt/app/webroot/js/jquery-1.3.2.min.js @@ -0,0 +1,19 @@ +/* + * jQuery JavaScript Library v1.3.2 + * http://jquery.com/ + * + * Copyright (c) 2009 John Resig + * Dual licensed under the MIT and GPL licenses. + * http://docs.jquery.com/License + * + * Date: 2009-02-19 17:34:21 -0500 (Thu, 19 Feb 2009) + * Revision: 6246 + */ +(function(){var l=this,g,y=l.jQuery,p=l.$,o=l.jQuery=l.$=function(E,F){return new o.fn.init(E,F)},D=/^[^<]*(<(.|\s)+>)[^>]*$|^#([\w-]+)$/,f=/^.[^:#\[\.,]*$/;o.fn=o.prototype={init:function(E,H){E=E||document;if(E.nodeType){this[0]=E;this.length=1;this.context=E;return this}if(typeof E==="string"){var G=D.exec(E);if(G&&(G[1]||!H)){if(G[1]){E=o.clean([G[1]],H)}else{var I=document.getElementById(G[3]);if(I&&I.id!=G[3]){return o().find(E)}var F=o(I||[]);F.context=document;F.selector=E;return F}}else{return o(H).find(E)}}else{if(o.isFunction(E)){return o(document).ready(E)}}if(E.selector&&E.context){this.selector=E.selector;this.context=E.context}return this.setArray(o.isArray(E)?E:o.makeArray(E))},selector:"",jquery:"1.3.2",size:function(){return this.length},get:function(E){return E===g?Array.prototype.slice.call(this):this[E]},pushStack:function(F,H,E){var G=o(F);G.prevObject=this;G.context=this.context;if(H==="find"){G.selector=this.selector+(this.selector?" ":"")+E}else{if(H){G.selector=this.selector+"."+H+"("+E+")"}}return G},setArray:function(E){this.length=0;Array.prototype.push.apply(this,E);return this},each:function(F,E){return o.each(this,F,E)},index:function(E){return o.inArray(E&&E.jquery?E[0]:E,this)},attr:function(F,H,G){var E=F;if(typeof F==="string"){if(H===g){return this[0]&&o[G||"attr"](this[0],F)}else{E={};E[F]=H}}return this.each(function(I){for(F in E){o.attr(G?this.style:this,F,o.prop(this,E[F],G,I,F))}})},css:function(E,F){if((E=="width"||E=="height")&&parseFloat(F)<0){F=g}return this.attr(E,F,"curCSS")},text:function(F){if(typeof F!=="object"&&F!=null){return this.empty().append((this[0]&&this[0].ownerDocument||document).createTextNode(F))}var E="";o.each(F||this,function(){o.each(this.childNodes,function(){if(this.nodeType!=8){E+=this.nodeType!=1?this.nodeValue:o.fn.text([this])}})});return E},wrapAll:function(E){if(this[0]){var F=o(E,this[0].ownerDocument).clone();if(this[0].parentNode){F.insertBefore(this[0])}F.map(function(){var G=this;while(G.firstChild){G=G.firstChild}return G}).append(this)}return this},wrapInner:function(E){return this.each(function(){o(this).contents().wrapAll(E)})},wrap:function(E){return this.each(function(){o(this).wrapAll(E)})},append:function(){return this.domManip(arguments,true,function(E){if(this.nodeType==1){this.appendChild(E)}})},prepend:function(){return this.domManip(arguments,true,function(E){if(this.nodeType==1){this.insertBefore(E,this.firstChild)}})},before:function(){return this.domManip(arguments,false,function(E){this.parentNode.insertBefore(E,this)})},after:function(){return this.domManip(arguments,false,function(E){this.parentNode.insertBefore(E,this.nextSibling)})},end:function(){return this.prevObject||o([])},push:[].push,sort:[].sort,splice:[].splice,find:function(E){if(this.length===1){var F=this.pushStack([],"find",E);F.length=0;o.find(E,this[0],F);return F}else{return this.pushStack(o.unique(o.map(this,function(G){return o.find(E,G)})),"find",E)}},clone:function(G){var E=this.map(function(){if(!o.support.noCloneEvent&&!o.isXMLDoc(this)){var I=this.outerHTML;if(!I){var J=this.ownerDocument.createElement("div");J.appendChild(this.cloneNode(true));I=J.innerHTML}return o.clean([I.replace(/ jQuery\d+="(?:\d+|null)"/g,"").replace(/^\s*/,"")])[0]}else{return this.cloneNode(true)}});if(G===true){var H=this.find("*").andSelf(),F=0;E.find("*").andSelf().each(function(){if(this.nodeName!==H[F].nodeName){return}var I=o.data(H[F],"events");for(var K in I){for(var J in I[K]){o.event.add(this,K,I[K][J],I[K][J].data)}}F++})}return E},filter:function(E){return this.pushStack(o.isFunction(E)&&o.grep(this,function(G,F){return E.call(G,F)})||o.multiFilter(E,o.grep(this,function(F){return F.nodeType===1})),"filter",E)},closest:function(E){var G=o.expr.match.POS.test(E)?o(E):null,F=0;return this.map(function(){var H=this;while(H&&H.ownerDocument){if(G?G.index(H)>-1:o(H).is(E)){o.data(H,"closest",F);return H}H=H.parentNode;F++}})},not:function(E){if(typeof E==="string"){if(f.test(E)){return this.pushStack(o.multiFilter(E,this,true),"not",E)}else{E=o.multiFilter(E,this)}}var F=E.length&&E[E.length-1]!==g&&!E.nodeType;return this.filter(function(){return F?o.inArray(this,E)<0:this!=E})},add:function(E){return this.pushStack(o.unique(o.merge(this.get(),typeof E==="string"?o(E):o.makeArray(E))))},is:function(E){return !!E&&o.multiFilter(E,this).length>0},hasClass:function(E){return !!E&&this.is("."+E)},val:function(K){if(K===g){var E=this[0];if(E){if(o.nodeName(E,"option")){return(E.attributes.value||{}).specified?E.value:E.text}if(o.nodeName(E,"select")){var I=E.selectedIndex,L=[],M=E.options,H=E.type=="select-one";if(I<0){return null}for(var F=H?I:0,J=H?I+1:M.length;F=0||o.inArray(this.name,K)>=0)}else{if(o.nodeName(this,"select")){var N=o.makeArray(K);o("option",this).each(function(){this.selected=(o.inArray(this.value,N)>=0||o.inArray(this.text,N)>=0)});if(!N.length){this.selectedIndex=-1}}else{this.value=K}}})},html:function(E){return E===g?(this[0]?this[0].innerHTML.replace(/ jQuery\d+="(?:\d+|null)"/g,""):null):this.empty().append(E)},replaceWith:function(E){return this.after(E).remove()},eq:function(E){return this.slice(E,+E+1)},slice:function(){return this.pushStack(Array.prototype.slice.apply(this,arguments),"slice",Array.prototype.slice.call(arguments).join(","))},map:function(E){return this.pushStack(o.map(this,function(G,F){return E.call(G,F,G)}))},andSelf:function(){return this.add(this.prevObject)},domManip:function(J,M,L){if(this[0]){var I=(this[0].ownerDocument||this[0]).createDocumentFragment(),F=o.clean(J,(this[0].ownerDocument||this[0]),I),H=I.firstChild;if(H){for(var G=0,E=this.length;G1||G>0?I.cloneNode(true):I)}}if(F){o.each(F,z)}}return this;function K(N,O){return M&&o.nodeName(N,"table")&&o.nodeName(O,"tr")?(N.getElementsByTagName("tbody")[0]||N.appendChild(N.ownerDocument.createElement("tbody"))):N}}};o.fn.init.prototype=o.fn;function z(E,F){if(F.src){o.ajax({url:F.src,async:false,dataType:"script"})}else{o.globalEval(F.text||F.textContent||F.innerHTML||"")}if(F.parentNode){F.parentNode.removeChild(F)}}function e(){return +new Date}o.extend=o.fn.extend=function(){var J=arguments[0]||{},H=1,I=arguments.length,E=false,G;if(typeof J==="boolean"){E=J;J=arguments[1]||{};H=2}if(typeof J!=="object"&&!o.isFunction(J)){J={}}if(I==H){J=this;--H}for(;H-1}},swap:function(H,G,I){var E={};for(var F in G){E[F]=H.style[F];H.style[F]=G[F]}I.call(H);for(var F in G){H.style[F]=E[F]}},css:function(H,F,J,E){if(F=="width"||F=="height"){var L,G={position:"absolute",visibility:"hidden",display:"block"},K=F=="width"?["Left","Right"]:["Top","Bottom"];function I(){L=F=="width"?H.offsetWidth:H.offsetHeight;if(E==="border"){return}o.each(K,function(){if(!E){L-=parseFloat(o.curCSS(H,"padding"+this,true))||0}if(E==="margin"){L+=parseFloat(o.curCSS(H,"margin"+this,true))||0}else{L-=parseFloat(o.curCSS(H,"border"+this+"Width",true))||0}})}if(H.offsetWidth!==0){I()}else{o.swap(H,G,I)}return Math.max(0,Math.round(L))}return o.curCSS(H,F,J)},curCSS:function(I,F,G){var L,E=I.style;if(F=="opacity"&&!o.support.opacity){L=o.attr(E,"opacity");return L==""?"1":L}if(F.match(/float/i)){F=w}if(!G&&E&&E[F]){L=E[F]}else{if(q.getComputedStyle){if(F.match(/float/i)){F="float"}F=F.replace(/([A-Z])/g,"-$1").toLowerCase();var M=q.getComputedStyle(I,null);if(M){L=M.getPropertyValue(F)}if(F=="opacity"&&L==""){L="1"}}else{if(I.currentStyle){var J=F.replace(/\-(\w)/g,function(N,O){return O.toUpperCase()});L=I.currentStyle[F]||I.currentStyle[J];if(!/^\d+(px)?$/i.test(L)&&/^\d/.test(L)){var H=E.left,K=I.runtimeStyle.left;I.runtimeStyle.left=I.currentStyle.left;E.left=L||0;L=E.pixelLeft+"px";E.left=H;I.runtimeStyle.left=K}}}}return L},clean:function(F,K,I){K=K||document;if(typeof K.createElement==="undefined"){K=K.ownerDocument||K[0]&&K[0].ownerDocument||document}if(!I&&F.length===1&&typeof F[0]==="string"){var H=/^<(\w+)\s*\/?>$/.exec(F[0]);if(H){return[K.createElement(H[1])]}}var G=[],E=[],L=K.createElement("div");o.each(F,function(P,S){if(typeof S==="number"){S+=""}if(!S){return}if(typeof S==="string"){S=S.replace(/(<(\w+)[^>]*?)\/>/g,function(U,V,T){return T.match(/^(abbr|br|col|img|input|link|meta|param|hr|area|embed)$/i)?U:V+">"});var O=S.replace(/^\s+/,"").substring(0,10).toLowerCase();var Q=!O.indexOf("",""]||!O.indexOf("",""]||O.match(/^<(thead|tbody|tfoot|colg|cap)/)&&[1,"","
"]||!O.indexOf("",""]||(!O.indexOf("",""]||!O.indexOf("",""]||!o.support.htmlSerialize&&[1,"div
","
"]||[0,"",""];L.innerHTML=Q[1]+S+Q[2];while(Q[0]--){L=L.lastChild}if(!o.support.tbody){var R=/"&&!R?L.childNodes:[];for(var M=N.length-1;M>=0;--M){if(o.nodeName(N[M],"tbody")&&!N[M].childNodes.length){N[M].parentNode.removeChild(N[M])}}}if(!o.support.leadingWhitespace&&/^\s/.test(S)){L.insertBefore(K.createTextNode(S.match(/^\s*/)[0]),L.firstChild)}S=o.makeArray(L.childNodes)}if(S.nodeType){G.push(S)}else{G=o.merge(G,S)}});if(I){for(var J=0;G[J];J++){if(o.nodeName(G[J],"script")&&(!G[J].type||G[J].type.toLowerCase()==="text/javascript")){E.push(G[J].parentNode?G[J].parentNode.removeChild(G[J]):G[J])}else{if(G[J].nodeType===1){G.splice.apply(G,[J+1,0].concat(o.makeArray(G[J].getElementsByTagName("script"))))}I.appendChild(G[J])}}return E}return G},attr:function(J,G,K){if(!J||J.nodeType==3||J.nodeType==8){return g}var H=!o.isXMLDoc(J),L=K!==g;G=H&&o.props[G]||G;if(J.tagName){var F=/href|src|style/.test(G);if(G=="selected"&&J.parentNode){J.parentNode.selectedIndex}if(G in J&&H&&!F){if(L){if(G=="type"&&o.nodeName(J,"input")&&J.parentNode){throw"type property can't be changed"}J[G]=K}if(o.nodeName(J,"form")&&J.getAttributeNode(G)){return J.getAttributeNode(G).nodeValue}if(G=="tabIndex"){var I=J.getAttributeNode("tabIndex");return I&&I.specified?I.value:J.nodeName.match(/(button|input|object|select|textarea)/i)?0:J.nodeName.match(/^(a|area)$/i)&&J.href?0:g}return J[G]}if(!o.support.style&&H&&G=="style"){return o.attr(J.style,"cssText",K)}if(L){J.setAttribute(G,""+K)}var E=!o.support.hrefNormalized&&H&&F?J.getAttribute(G,2):J.getAttribute(G);return E===null?g:E}if(!o.support.opacity&&G=="opacity"){if(L){J.zoom=1;J.filter=(J.filter||"").replace(/alpha\([^)]*\)/,"")+(parseInt(K)+""=="NaN"?"":"alpha(opacity="+K*100+")")}return J.filter&&J.filter.indexOf("opacity=")>=0?(parseFloat(J.filter.match(/opacity=([^)]*)/)[1])/100)+"":""}G=G.replace(/-([a-z])/ig,function(M,N){return N.toUpperCase()});if(L){J[G]=K}return J[G]},trim:function(E){return(E||"").replace(/^\s+|\s+$/g,"")},makeArray:function(G){var E=[];if(G!=null){var F=G.length;if(F==null||typeof G==="string"||o.isFunction(G)||G.setInterval){E[0]=G}else{while(F){E[--F]=G[F]}}}return E},inArray:function(G,H){for(var E=0,F=H.length;E0?this.clone(true):this).get();o.fn[F].apply(o(L[K]),I);J=J.concat(I)}return this.pushStack(J,E,G)}});o.each({removeAttr:function(E){o.attr(this,E,"");if(this.nodeType==1){this.removeAttribute(E)}},addClass:function(E){o.className.add(this,E)},removeClass:function(E){o.className.remove(this,E)},toggleClass:function(F,E){if(typeof E!=="boolean"){E=!o.className.has(this,F)}o.className[E?"add":"remove"](this,F)},remove:function(E){if(!E||o.filter(E,[this]).length){o("*",this).add([this]).each(function(){o.event.remove(this);o.removeData(this)});if(this.parentNode){this.parentNode.removeChild(this)}}},empty:function(){o(this).children().remove();while(this.firstChild){this.removeChild(this.firstChild)}}},function(E,F){o.fn[E]=function(){return this.each(F,arguments)}});function j(E,F){return E[0]&&parseInt(o.curCSS(E[0],F,true),10)||0}var h="jQuery"+e(),v=0,A={};o.extend({cache:{},data:function(F,E,G){F=F==l?A:F;var H=F[h];if(!H){H=F[h]=++v}if(E&&!o.cache[H]){o.cache[H]={}}if(G!==g){o.cache[H][E]=G}return E?o.cache[H][E]:H},removeData:function(F,E){F=F==l?A:F;var H=F[h];if(E){if(o.cache[H]){delete o.cache[H][E];E="";for(E in o.cache[H]){break}if(!E){o.removeData(F)}}}else{try{delete F[h]}catch(G){if(F.removeAttribute){F.removeAttribute(h)}}delete o.cache[H]}},queue:function(F,E,H){if(F){E=(E||"fx")+"queue";var G=o.data(F,E);if(!G||o.isArray(H)){G=o.data(F,E,o.makeArray(H))}else{if(H){G.push(H)}}}return G},dequeue:function(H,G){var E=o.queue(H,G),F=E.shift();if(!G||G==="fx"){F=E[0]}if(F!==g){F.call(H)}}});o.fn.extend({data:function(E,G){var H=E.split(".");H[1]=H[1]?"."+H[1]:"";if(G===g){var F=this.triggerHandler("getData"+H[1]+"!",[H[0]]);if(F===g&&this.length){F=o.data(this[0],E)}return F===g&&H[1]?this.data(H[0]):F}else{return this.trigger("setData"+H[1]+"!",[H[0],G]).each(function(){o.data(this,E,G)})}},removeData:function(E){return this.each(function(){o.removeData(this,E)})},queue:function(E,F){if(typeof E!=="string"){F=E;E="fx"}if(F===g){return o.queue(this[0],E)}return this.each(function(){var G=o.queue(this,E,F);if(E=="fx"&&G.length==1){G[0].call(this)}})},dequeue:function(E){return this.each(function(){o.dequeue(this,E)})}}); +/* + * Sizzle CSS Selector Engine - v0.9.3 + * Copyright 2009, The Dojo Foundation + * Released under the MIT, BSD, and GPL Licenses. + * More information: http://sizzlejs.com/ + */ +(function(){var R=/((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^[\]]*\]|['"][^'"]*['"]|[^[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?/g,L=0,H=Object.prototype.toString;var F=function(Y,U,ab,ac){ab=ab||[];U=U||document;if(U.nodeType!==1&&U.nodeType!==9){return[]}if(!Y||typeof Y!=="string"){return ab}var Z=[],W,af,ai,T,ad,V,X=true;R.lastIndex=0;while((W=R.exec(Y))!==null){Z.push(W[1]);if(W[2]){V=RegExp.rightContext;break}}if(Z.length>1&&M.exec(Y)){if(Z.length===2&&I.relative[Z[0]]){af=J(Z[0]+Z[1],U)}else{af=I.relative[Z[0]]?[U]:F(Z.shift(),U);while(Z.length){Y=Z.shift();if(I.relative[Y]){Y+=Z.shift()}af=J(Y,af)}}}else{var ae=ac?{expr:Z.pop(),set:E(ac)}:F.find(Z.pop(),Z.length===1&&U.parentNode?U.parentNode:U,Q(U));af=F.filter(ae.expr,ae.set);if(Z.length>0){ai=E(af)}else{X=false}while(Z.length){var ah=Z.pop(),ag=ah;if(!I.relative[ah]){ah=""}else{ag=Z.pop()}if(ag==null){ag=U}I.relative[ah](ai,ag,Q(U))}}if(!ai){ai=af}if(!ai){throw"Syntax error, unrecognized expression: "+(ah||Y)}if(H.call(ai)==="[object Array]"){if(!X){ab.push.apply(ab,ai)}else{if(U.nodeType===1){for(var aa=0;ai[aa]!=null;aa++){if(ai[aa]&&(ai[aa]===true||ai[aa].nodeType===1&&K(U,ai[aa]))){ab.push(af[aa])}}}else{for(var aa=0;ai[aa]!=null;aa++){if(ai[aa]&&ai[aa].nodeType===1){ab.push(af[aa])}}}}}else{E(ai,ab)}if(V){F(V,U,ab,ac);if(G){hasDuplicate=false;ab.sort(G);if(hasDuplicate){for(var aa=1;aa":function(Z,U,aa){var X=typeof U==="string";if(X&&!/\W/.test(U)){U=aa?U:U.toUpperCase();for(var V=0,T=Z.length;V=0)){if(!V){T.push(Y)}}else{if(V){U[X]=false}}}}return false},ID:function(T){return T[1].replace(/\\/g,"")},TAG:function(U,T){for(var V=0;T[V]===false;V++){}return T[V]&&Q(T[V])?U[1]:U[1].toUpperCase()},CHILD:function(T){if(T[1]=="nth"){var U=/(-?)(\d*)n((?:\+|-)?\d*)/.exec(T[2]=="even"&&"2n"||T[2]=="odd"&&"2n+1"||!/\D/.test(T[2])&&"0n+"+T[2]||T[2]);T[2]=(U[1]+(U[2]||1))-0;T[3]=U[3]-0}T[0]=L++;return T},ATTR:function(X,U,V,T,Y,Z){var W=X[1].replace(/\\/g,"");if(!Z&&I.attrMap[W]){X[1]=I.attrMap[W]}if(X[2]==="~="){X[4]=" "+X[4]+" "}return X},PSEUDO:function(X,U,V,T,Y){if(X[1]==="not"){if(X[3].match(R).length>1||/^\w/.test(X[3])){X[3]=F(X[3],null,null,U)}else{var W=F.filter(X[3],U,V,true^Y);if(!V){T.push.apply(T,W)}return false}}else{if(I.match.POS.test(X[0])||I.match.CHILD.test(X[0])){return true}}return X},POS:function(T){T.unshift(true);return T}},filters:{enabled:function(T){return T.disabled===false&&T.type!=="hidden"},disabled:function(T){return T.disabled===true},checked:function(T){return T.checked===true},selected:function(T){T.parentNode.selectedIndex;return T.selected===true},parent:function(T){return !!T.firstChild},empty:function(T){return !T.firstChild},has:function(V,U,T){return !!F(T[3],V).length},header:function(T){return/h\d/i.test(T.nodeName)},text:function(T){return"text"===T.type},radio:function(T){return"radio"===T.type},checkbox:function(T){return"checkbox"===T.type},file:function(T){return"file"===T.type},password:function(T){return"password"===T.type},submit:function(T){return"submit"===T.type},image:function(T){return"image"===T.type},reset:function(T){return"reset"===T.type},button:function(T){return"button"===T.type||T.nodeName.toUpperCase()==="BUTTON"},input:function(T){return/input|select|textarea|button/i.test(T.nodeName)}},setFilters:{first:function(U,T){return T===0},last:function(V,U,T,W){return U===W.length-1},even:function(U,T){return T%2===0},odd:function(U,T){return T%2===1},lt:function(V,U,T){return UT[3]-0},nth:function(V,U,T){return T[3]-0==U},eq:function(V,U,T){return T[3]-0==U}},filter:{PSEUDO:function(Z,V,W,aa){var U=V[1],X=I.filters[U];if(X){return X(Z,W,V,aa)}else{if(U==="contains"){return(Z.textContent||Z.innerText||"").indexOf(V[3])>=0}else{if(U==="not"){var Y=V[3];for(var W=0,T=Y.length;W=0)}}},ID:function(U,T){return U.nodeType===1&&U.getAttribute("id")===T},TAG:function(U,T){return(T==="*"&&U.nodeType===1)||U.nodeName===T},CLASS:function(U,T){return(" "+(U.className||U.getAttribute("class"))+" ").indexOf(T)>-1},ATTR:function(Y,W){var V=W[1],T=I.attrHandle[V]?I.attrHandle[V](Y):Y[V]!=null?Y[V]:Y.getAttribute(V),Z=T+"",X=W[2],U=W[4];return T==null?X==="!=":X==="="?Z===U:X==="*="?Z.indexOf(U)>=0:X==="~="?(" "+Z+" ").indexOf(U)>=0:!U?Z&&T!==false:X==="!="?Z!=U:X==="^="?Z.indexOf(U)===0:X==="$="?Z.substr(Z.length-U.length)===U:X==="|="?Z===U||Z.substr(0,U.length+1)===U+"-":false},POS:function(X,U,V,Y){var T=U[2],W=I.setFilters[T];if(W){return W(X,V,U,Y)}}}};var M=I.match.POS;for(var O in I.match){I.match[O]=RegExp(I.match[O].source+/(?![^\[]*\])(?![^\(]*\))/.source)}var E=function(U,T){U=Array.prototype.slice.call(U);if(T){T.push.apply(T,U);return T}return U};try{Array.prototype.slice.call(document.documentElement.childNodes)}catch(N){E=function(X,W){var U=W||[];if(H.call(X)==="[object Array]"){Array.prototype.push.apply(U,X)}else{if(typeof X.length==="number"){for(var V=0,T=X.length;V";var T=document.documentElement;T.insertBefore(U,T.firstChild);if(!!document.getElementById(V)){I.find.ID=function(X,Y,Z){if(typeof Y.getElementById!=="undefined"&&!Z){var W=Y.getElementById(X[1]);return W?W.id===X[1]||typeof W.getAttributeNode!=="undefined"&&W.getAttributeNode("id").nodeValue===X[1]?[W]:g:[]}};I.filter.ID=function(Y,W){var X=typeof Y.getAttributeNode!=="undefined"&&Y.getAttributeNode("id");return Y.nodeType===1&&X&&X.nodeValue===W}}T.removeChild(U)})();(function(){var T=document.createElement("div");T.appendChild(document.createComment(""));if(T.getElementsByTagName("*").length>0){I.find.TAG=function(U,Y){var X=Y.getElementsByTagName(U[1]);if(U[1]==="*"){var W=[];for(var V=0;X[V];V++){if(X[V].nodeType===1){W.push(X[V])}}X=W}return X}}T.innerHTML="";if(T.firstChild&&typeof T.firstChild.getAttribute!=="undefined"&&T.firstChild.getAttribute("href")!=="#"){I.attrHandle.href=function(U){return U.getAttribute("href",2)}}})();if(document.querySelectorAll){(function(){var T=F,U=document.createElement("div");U.innerHTML="

";if(U.querySelectorAll&&U.querySelectorAll(".TEST").length===0){return}F=function(Y,X,V,W){X=X||document;if(!W&&X.nodeType===9&&!Q(X)){try{return E(X.querySelectorAll(Y),V)}catch(Z){}}return T(Y,X,V,W)};F.find=T.find;F.filter=T.filter;F.selectors=T.selectors;F.matches=T.matches})()}if(document.getElementsByClassName&&document.documentElement.getElementsByClassName){(function(){var T=document.createElement("div");T.innerHTML="
";if(T.getElementsByClassName("e").length===0){return}T.lastChild.className="e";if(T.getElementsByClassName("e").length===1){return}I.order.splice(1,0,"CLASS");I.find.CLASS=function(U,V,W){if(typeof V.getElementsByClassName!=="undefined"&&!W){return V.getElementsByClassName(U[1])}}})()}function P(U,Z,Y,ad,aa,ac){var ab=U=="previousSibling"&&!ac;for(var W=0,V=ad.length;W0){X=T;break}}}T=T[U]}ad[W]=X}}}var K=document.compareDocumentPosition?function(U,T){return U.compareDocumentPosition(T)&16}:function(U,T){return U!==T&&(U.contains?U.contains(T):true)};var Q=function(T){return T.nodeType===9&&T.documentElement.nodeName!=="HTML"||!!T.ownerDocument&&Q(T.ownerDocument)};var J=function(T,aa){var W=[],X="",Y,V=aa.nodeType?[aa]:aa;while((Y=I.match.PSEUDO.exec(T))){X+=Y[0];T=T.replace(I.match.PSEUDO,"")}T=I.relative[T]?T+"*":T;for(var Z=0,U=V.length;Z0||T.offsetHeight>0};F.selectors.filters.animated=function(T){return o.grep(o.timers,function(U){return T===U.elem}).length};o.multiFilter=function(V,T,U){if(U){V=":not("+V+")"}return F.matches(V,T)};o.dir=function(V,U){var T=[],W=V[U];while(W&&W!=document){if(W.nodeType==1){T.push(W)}W=W[U]}return T};o.nth=function(X,T,V,W){T=T||1;var U=0;for(;X;X=X[V]){if(X.nodeType==1&&++U==T){break}}return X};o.sibling=function(V,U){var T=[];for(;V;V=V.nextSibling){if(V.nodeType==1&&V!=U){T.push(V)}}return T};return;l.Sizzle=F})();o.event={add:function(I,F,H,K){if(I.nodeType==3||I.nodeType==8){return}if(I.setInterval&&I!=l){I=l}if(!H.guid){H.guid=this.guid++}if(K!==g){var G=H;H=this.proxy(G);H.data=K}var E=o.data(I,"events")||o.data(I,"events",{}),J=o.data(I,"handle")||o.data(I,"handle",function(){return typeof o!=="undefined"&&!o.event.triggered?o.event.handle.apply(arguments.callee.elem,arguments):g});J.elem=I;o.each(F.split(/\s+/),function(M,N){var O=N.split(".");N=O.shift();H.type=O.slice().sort().join(".");var L=E[N];if(o.event.specialAll[N]){o.event.specialAll[N].setup.call(I,K,O)}if(!L){L=E[N]={};if(!o.event.special[N]||o.event.special[N].setup.call(I,K,O)===false){if(I.addEventListener){I.addEventListener(N,J,false)}else{if(I.attachEvent){I.attachEvent("on"+N,J)}}}}L[H.guid]=H;o.event.global[N]=true});I=null},guid:1,global:{},remove:function(K,H,J){if(K.nodeType==3||K.nodeType==8){return}var G=o.data(K,"events"),F,E;if(G){if(H===g||(typeof H==="string"&&H.charAt(0)==".")){for(var I in G){this.remove(K,I+(H||""))}}else{if(H.type){J=H.handler;H=H.type}o.each(H.split(/\s+/),function(M,O){var Q=O.split(".");O=Q.shift();var N=RegExp("(^|\\.)"+Q.slice().sort().join(".*\\.")+"(\\.|$)");if(G[O]){if(J){delete G[O][J.guid]}else{for(var P in G[O]){if(N.test(G[O][P].type)){delete G[O][P]}}}if(o.event.specialAll[O]){o.event.specialAll[O].teardown.call(K,Q)}for(F in G[O]){break}if(!F){if(!o.event.special[O]||o.event.special[O].teardown.call(K,Q)===false){if(K.removeEventListener){K.removeEventListener(O,o.data(K,"handle"),false)}else{if(K.detachEvent){K.detachEvent("on"+O,o.data(K,"handle"))}}}F=null;delete G[O]}}})}for(F in G){break}if(!F){var L=o.data(K,"handle");if(L){L.elem=null}o.removeData(K,"events");o.removeData(K,"handle")}}},trigger:function(I,K,H,E){var G=I.type||I;if(!E){I=typeof I==="object"?I[h]?I:o.extend(o.Event(G),I):o.Event(G);if(G.indexOf("!")>=0){I.type=G=G.slice(0,-1);I.exclusive=true}if(!H){I.stopPropagation();if(this.global[G]){o.each(o.cache,function(){if(this.events&&this.events[G]){o.event.trigger(I,K,this.handle.elem)}})}}if(!H||H.nodeType==3||H.nodeType==8){return g}I.result=g;I.target=H;K=o.makeArray(K);K.unshift(I)}I.currentTarget=H;var J=o.data(H,"handle");if(J){J.apply(H,K)}if((!H[G]||(o.nodeName(H,"a")&&G=="click"))&&H["on"+G]&&H["on"+G].apply(H,K)===false){I.result=false}if(!E&&H[G]&&!I.isDefaultPrevented()&&!(o.nodeName(H,"a")&&G=="click")){this.triggered=true;try{H[G]()}catch(L){}}this.triggered=false;if(!I.isPropagationStopped()){var F=H.parentNode||H.ownerDocument;if(F){o.event.trigger(I,K,F,true)}}},handle:function(K){var J,E;K=arguments[0]=o.event.fix(K||l.event);K.currentTarget=this;var L=K.type.split(".");K.type=L.shift();J=!L.length&&!K.exclusive;var I=RegExp("(^|\\.)"+L.slice().sort().join(".*\\.")+"(\\.|$)");E=(o.data(this,"events")||{})[K.type];for(var G in E){var H=E[G];if(J||I.test(H.type)){K.handler=H;K.data=H.data;var F=H.apply(this,arguments);if(F!==g){K.result=F;if(F===false){K.preventDefault();K.stopPropagation()}}if(K.isImmediatePropagationStopped()){break}}}},props:"altKey attrChange attrName bubbles button cancelable charCode clientX clientY ctrlKey currentTarget data detail eventPhase fromElement handler keyCode metaKey newValue originalTarget pageX pageY prevValue relatedNode relatedTarget screenX screenY shiftKey srcElement target toElement view wheelDelta which".split(" "),fix:function(H){if(H[h]){return H}var F=H;H=o.Event(F);for(var G=this.props.length,J;G;){J=this.props[--G];H[J]=F[J]}if(!H.target){H.target=H.srcElement||document}if(H.target.nodeType==3){H.target=H.target.parentNode}if(!H.relatedTarget&&H.fromElement){H.relatedTarget=H.fromElement==H.target?H.toElement:H.fromElement}if(H.pageX==null&&H.clientX!=null){var I=document.documentElement,E=document.body;H.pageX=H.clientX+(I&&I.scrollLeft||E&&E.scrollLeft||0)-(I.clientLeft||0);H.pageY=H.clientY+(I&&I.scrollTop||E&&E.scrollTop||0)-(I.clientTop||0)}if(!H.which&&((H.charCode||H.charCode===0)?H.charCode:H.keyCode)){H.which=H.charCode||H.keyCode}if(!H.metaKey&&H.ctrlKey){H.metaKey=H.ctrlKey}if(!H.which&&H.button){H.which=(H.button&1?1:(H.button&2?3:(H.button&4?2:0)))}return H},proxy:function(F,E){E=E||function(){return F.apply(this,arguments)};E.guid=F.guid=F.guid||E.guid||this.guid++;return E},special:{ready:{setup:B,teardown:function(){}}},specialAll:{live:{setup:function(E,F){o.event.add(this,F[0],c)},teardown:function(G){if(G.length){var E=0,F=RegExp("(^|\\.)"+G[0]+"(\\.|$)");o.each((o.data(this,"events").live||{}),function(){if(F.test(this.type)){E++}});if(E<1){o.event.remove(this,G[0],c)}}}}}};o.Event=function(E){if(!this.preventDefault){return new o.Event(E)}if(E&&E.type){this.originalEvent=E;this.type=E.type}else{this.type=E}this.timeStamp=e();this[h]=true};function k(){return false}function u(){return true}o.Event.prototype={preventDefault:function(){this.isDefaultPrevented=u;var E=this.originalEvent;if(!E){return}if(E.preventDefault){E.preventDefault()}E.returnValue=false},stopPropagation:function(){this.isPropagationStopped=u;var E=this.originalEvent;if(!E){return}if(E.stopPropagation){E.stopPropagation()}E.cancelBubble=true},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=u;this.stopPropagation()},isDefaultPrevented:k,isPropagationStopped:k,isImmediatePropagationStopped:k};var a=function(F){var E=F.relatedTarget;while(E&&E!=this){try{E=E.parentNode}catch(G){E=this}}if(E!=this){F.type=F.data;o.event.handle.apply(this,arguments)}};o.each({mouseover:"mouseenter",mouseout:"mouseleave"},function(F,E){o.event.special[E]={setup:function(){o.event.add(this,F,a,E)},teardown:function(){o.event.remove(this,F,a)}}});o.fn.extend({bind:function(F,G,E){return F=="unload"?this.one(F,G,E):this.each(function(){o.event.add(this,F,E||G,E&&G)})},one:function(G,H,F){var E=o.event.proxy(F||H,function(I){o(this).unbind(I,E);return(F||H).apply(this,arguments)});return this.each(function(){o.event.add(this,G,E,F&&H)})},unbind:function(F,E){return this.each(function(){o.event.remove(this,F,E)})},trigger:function(E,F){return this.each(function(){o.event.trigger(E,F,this)})},triggerHandler:function(E,G){if(this[0]){var F=o.Event(E);F.preventDefault();F.stopPropagation();o.event.trigger(F,G,this[0]);return F.result}},toggle:function(G){var E=arguments,F=1;while(F=0){var E=G.slice(I,G.length);G=G.slice(0,I)}var H="GET";if(J){if(o.isFunction(J)){K=J;J=null}else{if(typeof J==="object"){J=o.param(J);H="POST"}}}var F=this;o.ajax({url:G,type:H,dataType:"html",data:J,complete:function(M,L){if(L=="success"||L=="notmodified"){F.html(E?o("
").append(M.responseText.replace(//g,"")).find(E):M.responseText)}if(K){F.each(K,[M.responseText,L,M])}}});return this},serialize:function(){return o.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?o.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||/select|textarea/i.test(this.nodeName)||/text|hidden|password|search/i.test(this.type))}).map(function(E,F){var G=o(this).val();return G==null?null:o.isArray(G)?o.map(G,function(I,H){return{name:F.name,value:I}}):{name:F.name,value:G}}).get()}});o.each("ajaxStart,ajaxStop,ajaxComplete,ajaxError,ajaxSuccess,ajaxSend".split(","),function(E,F){o.fn[F]=function(G){return this.bind(F,G)}});var r=e();o.extend({get:function(E,G,H,F){if(o.isFunction(G)){H=G;G=null}return o.ajax({type:"GET",url:E,data:G,success:H,dataType:F})},getScript:function(E,F){return o.get(E,null,F,"script")},getJSON:function(E,F,G){return o.get(E,F,G,"json")},post:function(E,G,H,F){if(o.isFunction(G)){H=G;G={}}return o.ajax({type:"POST",url:E,data:G,success:H,dataType:F})},ajaxSetup:function(E){o.extend(o.ajaxSettings,E)},ajaxSettings:{url:location.href,global:true,type:"GET",contentType:"application/x-www-form-urlencoded",processData:true,async:true,xhr:function(){return l.ActiveXObject?new ActiveXObject("Microsoft.XMLHTTP"):new XMLHttpRequest()},accepts:{xml:"application/xml, text/xml",html:"text/html",script:"text/javascript, application/javascript",json:"application/json, text/javascript",text:"text/plain",_default:"*/*"}},lastModified:{},ajax:function(M){M=o.extend(true,M,o.extend(true,{},o.ajaxSettings,M));var W,F=/=\?(&|$)/g,R,V,G=M.type.toUpperCase();if(M.data&&M.processData&&typeof M.data!=="string"){M.data=o.param(M.data)}if(M.dataType=="jsonp"){if(G=="GET"){if(!M.url.match(F)){M.url+=(M.url.match(/\?/)?"&":"?")+(M.jsonp||"callback")+"=?"}}else{if(!M.data||!M.data.match(F)){M.data=(M.data?M.data+"&":"")+(M.jsonp||"callback")+"=?"}}M.dataType="json"}if(M.dataType=="json"&&(M.data&&M.data.match(F)||M.url.match(F))){W="jsonp"+r++;if(M.data){M.data=(M.data+"").replace(F,"="+W+"$1")}M.url=M.url.replace(F,"="+W+"$1");M.dataType="script";l[W]=function(X){V=X;I();L();l[W]=g;try{delete l[W]}catch(Y){}if(H){H.removeChild(T)}}}if(M.dataType=="script"&&M.cache==null){M.cache=false}if(M.cache===false&&G=="GET"){var E=e();var U=M.url.replace(/(\?|&)_=.*?(&|$)/,"$1_="+E+"$2");M.url=U+((U==M.url)?(M.url.match(/\?/)?"&":"?")+"_="+E:"")}if(M.data&&G=="GET"){M.url+=(M.url.match(/\?/)?"&":"?")+M.data;M.data=null}if(M.global&&!o.active++){o.event.trigger("ajaxStart")}var Q=/^(\w+:)?\/\/([^\/?#]+)/.exec(M.url);if(M.dataType=="script"&&G=="GET"&&Q&&(Q[1]&&Q[1]!=location.protocol||Q[2]!=location.host)){var H=document.getElementsByTagName("head")[0];var T=document.createElement("script");T.src=M.url;if(M.scriptCharset){T.charset=M.scriptCharset}if(!W){var O=false;T.onload=T.onreadystatechange=function(){if(!O&&(!this.readyState||this.readyState=="loaded"||this.readyState=="complete")){O=true;I();L();T.onload=T.onreadystatechange=null;H.removeChild(T)}}}H.appendChild(T);return g}var K=false;var J=M.xhr();if(M.username){J.open(G,M.url,M.async,M.username,M.password)}else{J.open(G,M.url,M.async)}try{if(M.data){J.setRequestHeader("Content-Type",M.contentType)}if(M.ifModified){J.setRequestHeader("If-Modified-Since",o.lastModified[M.url]||"Thu, 01 Jan 1970 00:00:00 GMT")}J.setRequestHeader("X-Requested-With","XMLHttpRequest");J.setRequestHeader("Accept",M.dataType&&M.accepts[M.dataType]?M.accepts[M.dataType]+", */*":M.accepts._default)}catch(S){}if(M.beforeSend&&M.beforeSend(J,M)===false){if(M.global&&!--o.active){o.event.trigger("ajaxStop")}J.abort();return false}if(M.global){o.event.trigger("ajaxSend",[J,M])}var N=function(X){if(J.readyState==0){if(P){clearInterval(P);P=null;if(M.global&&!--o.active){o.event.trigger("ajaxStop")}}}else{if(!K&&J&&(J.readyState==4||X=="timeout")){K=true;if(P){clearInterval(P);P=null}R=X=="timeout"?"timeout":!o.httpSuccess(J)?"error":M.ifModified&&o.httpNotModified(J,M.url)?"notmodified":"success";if(R=="success"){try{V=o.httpData(J,M.dataType,M)}catch(Z){R="parsererror"}}if(R=="success"){var Y;try{Y=J.getResponseHeader("Last-Modified")}catch(Z){}if(M.ifModified&&Y){o.lastModified[M.url]=Y}if(!W){I()}}else{o.handleError(M,J,R)}L();if(X){J.abort()}if(M.async){J=null}}}};if(M.async){var P=setInterval(N,13);if(M.timeout>0){setTimeout(function(){if(J&&!K){N("timeout")}},M.timeout)}}try{J.send(M.data)}catch(S){o.handleError(M,J,null,S)}if(!M.async){N()}function I(){if(M.success){M.success(V,R)}if(M.global){o.event.trigger("ajaxSuccess",[J,M])}}function L(){if(M.complete){M.complete(J,R)}if(M.global){o.event.trigger("ajaxComplete",[J,M])}if(M.global&&!--o.active){o.event.trigger("ajaxStop")}}return J},handleError:function(F,H,E,G){if(F.error){F.error(H,E,G)}if(F.global){o.event.trigger("ajaxError",[H,F,G])}},active:0,httpSuccess:function(F){try{return !F.status&&location.protocol=="file:"||(F.status>=200&&F.status<300)||F.status==304||F.status==1223}catch(E){}return false},httpNotModified:function(G,E){try{var H=G.getResponseHeader("Last-Modified");return G.status==304||H==o.lastModified[E]}catch(F){}return false},httpData:function(J,H,G){var F=J.getResponseHeader("content-type"),E=H=="xml"||!H&&F&&F.indexOf("xml")>=0,I=E?J.responseXML:J.responseText;if(E&&I.documentElement.tagName=="parsererror"){throw"parsererror"}if(G&&G.dataFilter){I=G.dataFilter(I,H)}if(typeof I==="string"){if(H=="script"){o.globalEval(I)}if(H=="json"){I=l["eval"]("("+I+")")}}return I},param:function(E){var G=[];function H(I,J){G[G.length]=encodeURIComponent(I)+"="+encodeURIComponent(J)}if(o.isArray(E)||E.jquery){o.each(E,function(){H(this.name,this.value)})}else{for(var F in E){if(o.isArray(E[F])){o.each(E[F],function(){H(F,this)})}else{H(F,o.isFunction(E[F])?E[F]():E[F])}}}return G.join("&").replace(/%20/g,"+")}});var m={},n,d=[["height","marginTop","marginBottom","paddingTop","paddingBottom"],["width","marginLeft","marginRight","paddingLeft","paddingRight"],["opacity"]];function t(F,E){var G={};o.each(d.concat.apply([],d.slice(0,E)),function(){G[this]=F});return G}o.fn.extend({show:function(J,L){if(J){return this.animate(t("show",3),J,L)}else{for(var H=0,F=this.length;H").appendTo("body");K=I.css("display");if(K==="none"){K="block"}I.remove();m[G]=K}o.data(this[H],"olddisplay",K)}}for(var H=0,F=this.length;H=0;H--){if(G[H].elem==this){if(E){G[H](true)}G.splice(H,1)}}});if(!E){this.dequeue()}return this}});o.each({slideDown:t("show",1),slideUp:t("hide",1),slideToggle:t("toggle",1),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"}},function(E,F){o.fn[E]=function(G,H){return this.animate(F,G,H)}});o.extend({speed:function(G,H,F){var E=typeof G==="object"?G:{complete:F||!F&&H||o.isFunction(G)&&G,duration:G,easing:F&&H||H&&!o.isFunction(H)&&H};E.duration=o.fx.off?0:typeof E.duration==="number"?E.duration:o.fx.speeds[E.duration]||o.fx.speeds._default;E.old=E.complete;E.complete=function(){if(E.queue!==false){o(this).dequeue()}if(o.isFunction(E.old)){E.old.call(this)}};return E},easing:{linear:function(G,H,E,F){return E+F*G},swing:function(G,H,E,F){return((-Math.cos(G*Math.PI)/2)+0.5)*F+E}},timers:[],fx:function(F,E,G){this.options=E;this.elem=F;this.prop=G;if(!E.orig){E.orig={}}}});o.fx.prototype={update:function(){if(this.options.step){this.options.step.call(this.elem,this.now,this)}(o.fx.step[this.prop]||o.fx.step._default)(this);if((this.prop=="height"||this.prop=="width")&&this.elem.style){this.elem.style.display="block"}},cur:function(F){if(this.elem[this.prop]!=null&&(!this.elem.style||this.elem.style[this.prop]==null)){return this.elem[this.prop]}var E=parseFloat(o.css(this.elem,this.prop,F));return E&&E>-10000?E:parseFloat(o.curCSS(this.elem,this.prop))||0},custom:function(I,H,G){this.startTime=e();this.start=I;this.end=H;this.unit=G||this.unit||"px";this.now=this.start;this.pos=this.state=0;var E=this;function F(J){return E.step(J)}F.elem=this.elem;if(F()&&o.timers.push(F)&&!n){n=setInterval(function(){var K=o.timers;for(var J=0;J=this.options.duration+this.startTime){this.now=this.end;this.pos=this.state=1;this.update();this.options.curAnim[this.prop]=true;var E=true;for(var F in this.options.curAnim){if(this.options.curAnim[F]!==true){E=false}}if(E){if(this.options.display!=null){this.elem.style.overflow=this.options.overflow;this.elem.style.display=this.options.display;if(o.css(this.elem,"display")=="none"){this.elem.style.display="block"}}if(this.options.hide){o(this.elem).hide()}if(this.options.hide||this.options.show){for(var I in this.options.curAnim){o.attr(this.elem.style,I,this.options.orig[I])}}this.options.complete.call(this.elem)}return false}else{var J=G-this.startTime;this.state=J/this.options.duration;this.pos=o.easing[this.options.easing||(o.easing.swing?"swing":"linear")](this.state,J,0,1,this.options.duration);this.now=this.start+((this.end-this.start)*this.pos);this.update()}return true}};o.extend(o.fx,{speeds:{slow:600,fast:200,_default:400},step:{opacity:function(E){o.attr(E.elem.style,"opacity",E.now)},_default:function(E){if(E.elem.style&&E.elem.style[E.prop]!=null){E.elem.style[E.prop]=E.now+E.unit}else{E.elem[E.prop]=E.now}}}});if(document.documentElement.getBoundingClientRect){o.fn.offset=function(){if(!this[0]){return{top:0,left:0}}if(this[0]===this[0].ownerDocument.body){return o.offset.bodyOffset(this[0])}var G=this[0].getBoundingClientRect(),J=this[0].ownerDocument,F=J.body,E=J.documentElement,L=E.clientTop||F.clientTop||0,K=E.clientLeft||F.clientLeft||0,I=G.top+(self.pageYOffset||o.boxModel&&E.scrollTop||F.scrollTop)-L,H=G.left+(self.pageXOffset||o.boxModel&&E.scrollLeft||F.scrollLeft)-K;return{top:I,left:H}}}else{o.fn.offset=function(){if(!this[0]){return{top:0,left:0}}if(this[0]===this[0].ownerDocument.body){return o.offset.bodyOffset(this[0])}o.offset.initialized||o.offset.initialize();var J=this[0],G=J.offsetParent,F=J,O=J.ownerDocument,M,H=O.documentElement,K=O.body,L=O.defaultView,E=L.getComputedStyle(J,null),N=J.offsetTop,I=J.offsetLeft;while((J=J.parentNode)&&J!==K&&J!==H){M=L.getComputedStyle(J,null);N-=J.scrollTop,I-=J.scrollLeft;if(J===G){N+=J.offsetTop,I+=J.offsetLeft;if(o.offset.doesNotAddBorder&&!(o.offset.doesAddBorderForTableAndCells&&/^t(able|d|h)$/i.test(J.tagName))){N+=parseInt(M.borderTopWidth,10)||0,I+=parseInt(M.borderLeftWidth,10)||0}F=G,G=J.offsetParent}if(o.offset.subtractsBorderForOverflowNotVisible&&M.overflow!=="visible"){N+=parseInt(M.borderTopWidth,10)||0,I+=parseInt(M.borderLeftWidth,10)||0}E=M}if(E.position==="relative"||E.position==="static"){N+=K.offsetTop,I+=K.offsetLeft}if(E.position==="fixed"){N+=Math.max(H.scrollTop,K.scrollTop),I+=Math.max(H.scrollLeft,K.scrollLeft)}return{top:N,left:I}}}o.offset={initialize:function(){if(this.initialized){return}var L=document.body,F=document.createElement("div"),H,G,N,I,M,E,J=L.style.marginTop,K='
';M={position:"absolute",top:0,left:0,margin:0,border:0,width:"1px",height:"1px",visibility:"hidden"};for(E in M){F.style[E]=M[E]}F.innerHTML=K;L.insertBefore(F,L.firstChild);H=F.firstChild,G=H.firstChild,I=H.nextSibling.firstChild.firstChild;this.doesNotAddBorder=(G.offsetTop!==5);this.doesAddBorderForTableAndCells=(I.offsetTop===5);H.style.overflow="hidden",H.style.position="relative";this.subtractsBorderForOverflowNotVisible=(G.offsetTop===-5);L.style.marginTop="1px";this.doesNotIncludeMarginInBodyOffset=(L.offsetTop===0);L.style.marginTop=J;L.removeChild(F);this.initialized=true},bodyOffset:function(E){o.offset.initialized||o.offset.initialize();var G=E.offsetTop,F=E.offsetLeft;if(o.offset.doesNotIncludeMarginInBodyOffset){G+=parseInt(o.curCSS(E,"marginTop",true),10)||0,F+=parseInt(o.curCSS(E,"marginLeft",true),10)||0}return{top:G,left:F}}};o.fn.extend({position:function(){var I=0,H=0,F;if(this[0]){var G=this.offsetParent(),J=this.offset(),E=/^body|html$/i.test(G[0].tagName)?{top:0,left:0}:G.offset();J.top-=j(this,"marginTop");J.left-=j(this,"marginLeft");E.top+=j(G,"borderTopWidth");E.left+=j(G,"borderLeftWidth");F={top:J.top-E.top,left:J.left-E.left}}return F},offsetParent:function(){var E=this[0].offsetParent||document.body;while(E&&(!/^body|html$/i.test(E.tagName)&&o.css(E,"position")=="static")){E=E.offsetParent}return o(E)}});o.each(["Left","Top"],function(F,E){var G="scroll"+E;o.fn[G]=function(H){if(!this[0]){return null}return H!==g?this.each(function(){this==l||this==document?l.scrollTo(!F?H:o(l).scrollLeft(),F?H:o(l).scrollTop()):this[G]=H}):this[0]==l||this[0]==document?self[F?"pageYOffset":"pageXOffset"]||o.boxModel&&document.documentElement[G]||document.body[G]:this[0][G]}});o.each(["Height","Width"],function(I,G){var E=I?"Left":"Top",H=I?"Right":"Bottom",F=G.toLowerCase();o.fn["inner"+G]=function(){return this[0]?o.css(this[0],F,false,"padding"):null};o.fn["outer"+G]=function(K){return this[0]?o.css(this[0],F,false,K?"margin":"border"):null};var J=G.toLowerCase();o.fn[J]=function(K){return this[0]==l?document.compatMode=="CSS1Compat"&&document.documentElement["client"+G]||document.body["client"+G]:this[0]==document?Math.max(document.documentElement["client"+G],document.body["scroll"+G],document.documentElement["scroll"+G],document.body["offset"+G],document.documentElement["offset"+G]):K===g?(this.length?o.css(this[0],J):null):this.css(J,typeof K==="string"?K:K+"px")}})})(); \ No newline at end of file diff --git a/code/ryzom/tools/server/www/webtt/app/webroot/js/jquery-fluid16.js b/code/ryzom/tools/server/www/webtt/app/webroot/js/jquery-fluid16.js new file mode 100755 index 000000000..08ab73d70 --- /dev/null +++ b/code/ryzom/tools/server/www/webtt/app/webroot/js/jquery-fluid16.js @@ -0,0 +1,103 @@ +var fluid = { +Ajax : function(){ + $("#loading").hide(); + var content = $("#ajax-content").hide(); + $("#toggle-ajax").bind("click", function(e) { + if ( $(this).is(".hidden") ) { + $("#ajax-content").empty(); + + $("#loading").show(); + $("#ajax-content").load("/fluid960gs/data/ajax-response.html", function() { + $("#loading").hide(); + content.slideDown(); + }); + } + else { + content.slideUp(); + } + if ($(this).hasClass('hidden')){ + $(this).removeClass('hidden').addClass('visible'); + } + else { + $(this).removeClass('visible').addClass('hidden'); + } + e.preventDefault(); + }); +}, +Toggle : function(){ + var default_hide = {"grid": true, "filter": true }; + $.each( + ["admin-left-menu", "admin-actions", "help", "filter", "related-records", "grid", "paragraphs", "blockquote", "list-items", "section-menu", "tables", "forms", "login-forms", "search", "articles", "accordion"], + function() { + var el = $("#" + (this == 'accordon' ? 'accordion-block' : this) ); + if (default_hide[this]) { + el.hide(); + $("[id='toggle-"+this+"']").addClass("hidden") + } + $("[id='toggle-"+this+"']") + .bind("click", function(e) { + if ($(this).hasClass('hidden')){ + $(this).removeClass('hidden').addClass('visible'); + el.slideDown(); + } else { + $(this).removeClass('visible').addClass('hidden'); + el.slideUp(); + } + e.preventDefault(); + }); + } + ); +}, +Kwicks : function(){ + var animating = false; + $("#kwick .kwick") + .bind("mouseenter", function(e) { + if (animating) return false; + animating == true; + $("#kwick .kwick").not(this).animate({ "width": 125 }, 200); + $(this).animate({ "width": 485 }, 200, function() { + animating = false; + }); + }); + $("#kwick").bind("mouseleave", function(e) { + $(".kwick", this).animate({ "width": 215 }, 200); + }); +}, +SectionMenu : function(){ + $("#section-menu") + .accordion({ + "header": "a.menuitem" + }) + .bind("accordionchangestart", function(e, data) { + data.newHeader.next().andSelf().addClass("current"); + data.oldHeader.next().andSelf().removeClass("current"); + }) + .find("a.menuitem:first").addClass("current") + .next().addClass("current"); +}, +Accordion: function(){ + $("#accordion").accordion({ + 'header': "h3.atStart" + }).bind("accordionchangestart", function(e, data) { + data.newHeader.css({ + "font-weight": "bold", + "background": "#fff" + }); + + data.oldHeader.css({ + "font-weight": "normal", + "background": "#eee" + }); + }).find("h3.atStart:first").css({ + "font-weight": "bold", + "background": "#fff" + }); +} +} +jQuery(function ($) { + if($("#accordion").length){fluid.Accordion();} + if($("[id$='ajax']").length){fluid.Ajax();} + if($("[id^='toggle']").length){fluid.Toggle();} + if($("#kwick .kwick").length){fluid.Kwicks();} + if($("#section-menu").length){fluid.SectionMenu();} +}); diff --git a/code/ryzom/tools/server/www/webtt/app/webroot/js/jquery-ui.js b/code/ryzom/tools/server/www/webtt/app/webroot/js/jquery-ui.js new file mode 100755 index 000000000..e6d1c0de4 --- /dev/null +++ b/code/ryzom/tools/server/www/webtt/app/webroot/js/jquery-ui.js @@ -0,0 +1,298 @@ +/* + * jQuery UI 1.6rc6 + * + * Copyright (c) 2009 AUTHORS.txt (http://ui.jquery.com/about) + * Dual licensed under the MIT (MIT-LICENSE.txt) + * and GPL (GPL-LICENSE.txt) licenses. + * + * http://docs.jquery.com/UI + */ +(function(c){var i=c.fn.remove,d=c.browser.mozilla&&(parseFloat(c.browser.version)<1.9);c.ui={version:"1.6rc6",plugin:{add:function(k,l,n){var m=c.ui[k].prototype;for(var j in n){m.plugins[j]=m.plugins[j]||[];m.plugins[j].push([l,n[j]])}},call:function(j,l,k){var n=j.plugins[l];if(!n){return}for(var m=0;m
').addClass(j).css({position:"absolute",top:"-5000px",left:"-5000px",display:"block"}).appendTo("body");c.ui.cssCache[j]=!!((!(/auto|default/).test(k.css("cursor"))||(/^[1-9]/).test(k.css("height"))||(/^[1-9]/).test(k.css("width"))||!(/none/).test(k.css("backgroundImage"))||!(/transparent|rgba\(0, 0, 0, 0\)/).test(k.css("backgroundColor"))));try{c("body").get(0).removeChild(k.get(0))}catch(l){}return c.ui.cssCache[j]},hasScroll:function(m,k){if(c(m).css("overflow")=="hidden"){return false}var j=(k&&k=="left")?"scrollLeft":"scrollTop",l=false;if(m[j]>0){return true}m[j]=1;l=(m[j]>0);m[j]=0;return l},isOverAxis:function(k,j,l){return(k>j)&&(k<(j+l))},isOver:function(o,k,n,m,j,l){return c.ui.isOverAxis(o,n,j)&&c.ui.isOverAxis(k,m,l)},keyCode:{BACKSPACE:8,CAPS_LOCK:20,COMMA:188,CONTROL:17,DELETE:46,DOWN:40,END:35,ENTER:13,ESCAPE:27,HOME:36,INSERT:45,LEFT:37,NUMPAD_ADD:107,NUMPAD_DECIMAL:110,NUMPAD_DIVIDE:111,NUMPAD_ENTER:108,NUMPAD_MULTIPLY:106,NUMPAD_SUBTRACT:109,PAGE_DOWN:34,PAGE_UP:33,PERIOD:190,RIGHT:39,SHIFT:16,SPACE:32,TAB:9,UP:38}};if(d){var f=c.attr,e=c.fn.removeAttr,h="http://www.w3.org/2005/07/aaa",a=/^aria-/,b=/^wairole:/;c.attr=function(k,j,l){var m=l!==undefined;return(j=="role"?(m?f.call(this,k,j,"wairole:"+l):(f.apply(this,arguments)||"").replace(b,"")):(a.test(j)?(m?k.setAttributeNS(h,j.replace(a,"aaa:"),l):f.call(this,k,j.replace(a,"aaa:"))):f.apply(this,arguments)))};c.fn.removeAttr=function(j){return(a.test(j)?this.each(function(){this.removeAttributeNS(h,j.replace(a,""))}):e.call(this,j))}}c.fn.extend({remove:function(){c("*",this).add(this).each(function(){c(this).triggerHandler("remove")});return i.apply(this,arguments)},enableSelection:function(){return this.attr("unselectable","off").css("MozUserSelect","").unbind("selectstart.ui")},disableSelection:function(){return this.attr("unselectable","on").css("MozUserSelect","none").bind("selectstart.ui",function(){return false})},scrollParent:function(){var j;if((c.browser.msie&&(/(static|relative)/).test(this.css("position")))||(/absolute/).test(this.css("position"))){j=this.parents().filter(function(){return(/(relative|absolute|fixed)/).test(c.curCSS(this,"position",1))&&(/(auto|scroll)/).test(c.curCSS(this,"overflow",1)+c.curCSS(this,"overflow-y",1)+c.curCSS(this,"overflow-x",1))}).eq(0)}else{j=this.parents().filter(function(){return(/(auto|scroll)/).test(c.curCSS(this,"overflow",1)+c.curCSS(this,"overflow-y",1)+c.curCSS(this,"overflow-x",1))}).eq(0)}return(/fixed/).test(this.css("position"))||!j.length?c(document):j}});c.extend(c.expr[":"],{data:function(l,k,j){return !!c.data(l,j[3])},focusable:function(k){var l=k.nodeName.toLowerCase(),j=c.attr(k,"tabindex");return(/input|select|textarea|button|object/.test(l)?!k.disabled:"a"==l||"area"==l?k.href||!isNaN(j):!isNaN(j))&&!c(k)["area"==l?"parents":"closest"](":hidden").length},tabbable:function(k){var j=c.attr(k,"tabindex");return(isNaN(j)||j>=0)&&c(k).is(":focusable")}});function g(m,n,o,l){function k(q){var p=c[m][n][q]||[];return(typeof p=="string"?p.split(/,?\s+/):p)}var j=k("getter");if(l.length==1&&typeof l[0]=="string"){j=j.concat(k("getterSetter"))}return(c.inArray(o,j)!=-1)}c.widget=function(k,j){var l=k.split(".")[0];k=k.split(".")[1];c.fn[k]=function(p){var n=(typeof p=="string"),o=Array.prototype.slice.call(arguments,1);if(n&&p.substring(0,1)=="_"){return this}if(n&&g(l,k,p,o)){var m=c.data(this[0],k);return(m?m[p].apply(m,o):undefined)}return this.each(function(){var q=c.data(this,k);(!q&&!n&&c.data(this,k,new c[l][k](this,p))._init());(q&&n&&c.isFunction(q[p])&&q[p].apply(q,o))})};c[l]=c[l]||{};c[l][k]=function(o,n){var m=this;this.namespace=l;this.widgetName=k;this.widgetEventPrefix=c[l][k].eventPrefix||k;this.widgetBaseClass=l+"-"+k;this.options=c.extend({},c.widget.defaults,c[l][k].defaults,c.metadata&&c.metadata.get(o)[k],n);this.element=c(o).bind("setData."+k,function(q,p,r){if(q.target==o){return m._setData(p,r)}}).bind("getData."+k,function(q,p){if(q.target==o){return m._getData(p)}}).bind("remove",function(){return m.destroy()})};c[l][k].prototype=c.extend({},c.widget.prototype,j);c[l][k].getterSetter="option"};c.widget.prototype={_init:function(){},destroy:function(){this.element.removeData(this.widgetName).removeClass(this.widgetBaseClass+"-disabled "+this.namespace+"-state-disabled").removeAttr("aria-disabled")},option:function(l,m){var k=l,j=this;if(typeof l=="string"){if(m===undefined){return this._getData(l)}k={};k[l]=m}c.each(k,function(n,o){j._setData(n,o)})},_getData:function(j){return this.options[j]},_setData:function(j,k){this.options[j]=k;if(j=="disabled"){this.element[k?"addClass":"removeClass"](this.widgetBaseClass+"-disabled "+this.namespace+"-state-disabled").attr("aria-disabled",k)}},enable:function(){this._setData("disabled",false)},disable:function(){this._setData("disabled",true)},_trigger:function(l,m,n){var p=this.options[l],j=(l==this.widgetEventPrefix?l:this.widgetEventPrefix+l);m=c.Event(m);m.type=j;if(m.originalEvent){for(var k=c.event.props.length,o;k;){o=c.event.props[--k];m[o]=m.originalEvent[o]}}this.element.trigger(m,n);return !(c.isFunction(p)&&p.call(this.element[0],m,n)===false||m.isDefaultPrevented())}};c.widget.defaults={disabled:false};c.ui.mouse={_mouseInit:function(){var j=this;this.element.bind("mousedown."+this.widgetName,function(k){return j._mouseDown(k)}).bind("click."+this.widgetName,function(k){if(j._preventClickEvent){j._preventClickEvent=false;return false}});if(c.browser.msie){this._mouseUnselectable=this.element.attr("unselectable");this.element.attr("unselectable","on")}this.started=false},_mouseDestroy:function(){this.element.unbind("."+this.widgetName);(c.browser.msie&&this.element.attr("unselectable",this._mouseUnselectable))},_mouseDown:function(l){if(l.originalEvent.mouseHandled){return}(this._mouseStarted&&this._mouseUp(l));this._mouseDownEvent=l;var k=this,m=(l.which==1),j=(typeof this.options.cancel=="string"?c(l.target).parents().add(l.target).filter(this.options.cancel).length:false);if(!m||j||!this._mouseCapture(l)){return true}this.mouseDelayMet=!this.options.delay;if(!this.mouseDelayMet){this._mouseDelayTimer=setTimeout(function(){k.mouseDelayMet=true},this.options.delay)}if(this._mouseDistanceMet(l)&&this._mouseDelayMet(l)){this._mouseStarted=(this._mouseStart(l)!==false);if(!this._mouseStarted){l.preventDefault();return true}}this._mouseMoveDelegate=function(n){return k._mouseMove(n)};this._mouseUpDelegate=function(n){return k._mouseUp(n)};c(document).bind("mousemove."+this.widgetName,this._mouseMoveDelegate).bind("mouseup."+this.widgetName,this._mouseUpDelegate);(c.browser.safari||l.preventDefault());l.originalEvent.mouseHandled=true;return true},_mouseMove:function(j){if(c.browser.msie&&!j.button){return this._mouseUp(j)}if(this._mouseStarted){this._mouseDrag(j);return j.preventDefault()}if(this._mouseDistanceMet(j)&&this._mouseDelayMet(j)){this._mouseStarted=(this._mouseStart(this._mouseDownEvent,j)!==false);(this._mouseStarted?this._mouseDrag(j):this._mouseUp(j))}return !this._mouseStarted},_mouseUp:function(j){c(document).unbind("mousemove."+this.widgetName,this._mouseMoveDelegate).unbind("mouseup."+this.widgetName,this._mouseUpDelegate);if(this._mouseStarted){this._mouseStarted=false;this._preventClickEvent=true;this._mouseStop(j)}return false},_mouseDistanceMet:function(j){return(Math.max(Math.abs(this._mouseDownEvent.pageX-j.pageX),Math.abs(this._mouseDownEvent.pageY-j.pageY))>=this.options.distance)},_mouseDelayMet:function(j){return this.mouseDelayMet},_mouseStart:function(j){},_mouseDrag:function(j){},_mouseStop:function(j){},_mouseCapture:function(j){return true}};c.ui.mouse.defaults={cancel:null,distance:1,delay:0}})(jQuery);/* + * jQuery UI Draggable 1.6rc6 + * + * Copyright (c) 2009 AUTHORS.txt (http://ui.jquery.com/about) + * Dual licensed under the MIT (MIT-LICENSE.txt) + * and GPL (GPL-LICENSE.txt) licenses. + * + * http://docs.jquery.com/UI/Draggables + * + * Depends: + * ui.core.js + */ +(function(a){a.widget("ui.draggable",a.extend({},a.ui.mouse,{_init:function(){if(this.options.helper=="original"&&!(/^(?:r|a|f)/).test(this.element.css("position"))){this.element[0].style.position="relative"}(this.options.cssNamespace&&this.element.addClass(this.options.cssNamespace+"-draggable"));(this.options.disabled&&this.element.addClass(this.options.cssNamespace+"-draggable-disabled"));this._mouseInit()},destroy:function(){if(!this.element.data("draggable")){return}this.element.removeData("draggable").unbind(".draggable").removeClass(this.options.cssNamespace+"-draggable "+this.options.cssNamespace+"-draggable-dragging "+this.options.cssNamespace+"-draggable-disabled");this._mouseDestroy()},_mouseCapture:function(b){var c=this.options;if(this.helper||c.disabled||a(b.target).is("."+this.options.cssNamespace+"-resizable-handle")){return false}this.handle=this._getHandle(b);if(!this.handle){return false}return true},_mouseStart:function(b){var c=this.options;this.helper=this._createHelper(b);this._cacheHelperProportions();if(a.ui.ddmanager){a.ui.ddmanager.current=this}this._cacheMargins();this.cssPosition=this.helper.css("position");this.scrollParent=this.helper.scrollParent();this.offset=this.element.offset();this.offset={top:this.offset.top-this.margins.top,left:this.offset.left-this.margins.left};a.extend(this.offset,{click:{left:b.pageX-this.offset.left,top:b.pageY-this.offset.top},parent:this._getParentOffset(),relative:this._getRelativeOffset()});this.originalPosition=this._generatePosition(b);this.originalPageX=b.pageX;this.originalPageY=b.pageY;if(c.cursorAt){this._adjustOffsetFromHelper(c.cursorAt)}if(c.containment){this._setContainment()}this._trigger("start",b);this._cacheHelperProportions();if(a.ui.ddmanager&&!c.dropBehaviour){a.ui.ddmanager.prepareOffsets(this,b)}this.helper.addClass(c.cssNamespace+"-draggable-dragging");this._mouseDrag(b,true);return true},_mouseDrag:function(b,d){this.position=this._generatePosition(b);this.positionAbs=this._convertPositionTo("absolute");if(!d){var c=this._uiHash();this._trigger("drag",b,c);this.position=c.position}if(!this.options.axis||this.options.axis!="y"){this.helper[0].style.left=this.position.left+"px"}if(!this.options.axis||this.options.axis!="x"){this.helper[0].style.top=this.position.top+"px"}if(a.ui.ddmanager){a.ui.ddmanager.drag(this,b)}return false},_mouseStop:function(c){var d=false;if(a.ui.ddmanager&&!this.options.dropBehaviour){d=a.ui.ddmanager.drop(this,c)}if(this.dropped){d=this.dropped;this.dropped=false}if((this.options.revert=="invalid"&&!d)||(this.options.revert=="valid"&&d)||this.options.revert===true||(a.isFunction(this.options.revert)&&this.options.revert.call(this.element,d))){var b=this;a(this.helper).animate(this.originalPosition,parseInt(this.options.revertDuration,10),function(){b._trigger("stop",c);b._clear()})}else{this._trigger("stop",c);this._clear()}return false},_getHandle:function(b){var c=!this.options.handle||!a(this.options.handle,this.element).length?true:false;a(this.options.handle,this.element).find("*").andSelf().each(function(){if(this==b.target){c=true}});return c},_createHelper:function(c){var d=this.options;var b=a.isFunction(d.helper)?a(d.helper.apply(this.element[0],[c])):(d.helper=="clone"?this.element.clone():this.element);if(!b.parents("body").length){b.appendTo((d.appendTo=="parent"?this.element[0].parentNode:d.appendTo))}if(b[0]!=this.element[0]&&!(/(fixed|absolute)/).test(b.css("position"))){b.css("position","absolute")}return b},_adjustOffsetFromHelper:function(b){if(b.left!=undefined){this.offset.click.left=b.left+this.margins.left}if(b.right!=undefined){this.offset.click.left=this.helperProportions.width-b.right+this.margins.left}if(b.top!=undefined){this.offset.click.top=b.top+this.margins.top}if(b.bottom!=undefined){this.offset.click.top=this.helperProportions.height-b.bottom+this.margins.top}},_getParentOffset:function(){this.offsetParent=this.helper.offsetParent();var b=this.offsetParent.offset();if(this.cssPosition=="absolute"&&this.scrollParent[0]!=document&&a.ui.contains(this.scrollParent[0],this.offsetParent[0])){b.left+=this.scrollParent.scrollLeft();b.top+=this.scrollParent.scrollTop()}if((this.offsetParent[0]==document.body&&a.browser.mozilla)||(this.offsetParent[0].tagName&&this.offsetParent[0].tagName.toLowerCase()=="html"&&a.browser.msie)){b={top:0,left:0}}return{top:b.top+(parseInt(this.offsetParent.css("borderTopWidth"),10)||0),left:b.left+(parseInt(this.offsetParent.css("borderLeftWidth"),10)||0)}},_getRelativeOffset:function(){if(this.cssPosition=="relative"){var b=this.element.position();return{top:b.top-(parseInt(this.helper.css("top"),10)||0)+this.scrollParent.scrollTop(),left:b.left-(parseInt(this.helper.css("left"),10)||0)+this.scrollParent.scrollLeft()}}else{return{top:0,left:0}}},_cacheMargins:function(){this.margins={left:(parseInt(this.element.css("marginLeft"),10)||0),top:(parseInt(this.element.css("marginTop"),10)||0)}},_cacheHelperProportions:function(){this.helperProportions={width:this.helper.outerWidth(),height:this.helper.outerHeight()}},_setContainment:function(){var e=this.options;if(e.containment=="parent"){e.containment=this.helper[0].parentNode}if(e.containment=="document"||e.containment=="window"){this.containment=[0-this.offset.relative.left-this.offset.parent.left,0-this.offset.relative.top-this.offset.parent.top,a(e.containment=="document"?document:window).width()-this.helperProportions.width-this.margins.left,(a(e.containment=="document"?document:window).height()||document.body.parentNode.scrollHeight)-this.helperProportions.height-this.margins.top]}if(!(/^(document|window|parent)$/).test(e.containment)&&e.containment.constructor!=Array){var c=a(e.containment)[0];if(!c){return}var d=a(e.containment).offset();var b=(a(c).css("overflow")!="hidden");this.containment=[d.left+(parseInt(a(c).css("borderLeftWidth"),10)||0)+(parseInt(a(c).css("paddingLeft"),10)||0)-this.margins.left,d.top+(parseInt(a(c).css("borderTopWidth"),10)||0)+(parseInt(a(c).css("paddingTop"),10)||0)-this.margins.top,d.left+(b?Math.max(c.scrollWidth,c.offsetWidth):c.offsetWidth)-(parseInt(a(c).css("borderLeftWidth"),10)||0)-(parseInt(a(c).css("paddingRight"),10)||0)-this.helperProportions.width-this.margins.left,d.top+(b?Math.max(c.scrollHeight,c.offsetHeight):c.offsetHeight)-(parseInt(a(c).css("borderTopWidth"),10)||0)-(parseInt(a(c).css("paddingBottom"),10)||0)-this.helperProportions.height-this.margins.top]}else{if(e.containment.constructor==Array){this.containment=e.containment}}},_convertPositionTo:function(f,h){if(!h){h=this.position}var c=f=="absolute"?1:-1;var e=this.options,b=this.cssPosition=="absolute"&&!(this.scrollParent[0]!=document&&a.ui.contains(this.scrollParent[0],this.offsetParent[0]))?this.offsetParent:this.scrollParent,g=(/(html|body)/i).test(b[0].tagName);return{top:(h.top+this.offset.relative.top*c+this.offset.parent.top*c-(this.cssPosition=="fixed"?-this.scrollParent.scrollTop():(g?0:b.scrollTop()))*c),left:(h.left+this.offset.relative.left*c+this.offset.parent.left*c-(this.cssPosition=="fixed"?-this.scrollParent.scrollLeft():g?0:b.scrollLeft())*c)}},_generatePosition:function(e){var h=this.options,b=this.cssPosition=="absolute"&&!(this.scrollParent[0]!=document&&a.ui.contains(this.scrollParent[0],this.offsetParent[0]))?this.offsetParent:this.scrollParent,i=(/(html|body)/i).test(b[0].tagName);if(this.cssPosition=="relative"&&!(this.scrollParent[0]!=document&&this.scrollParent[0]!=this.offsetParent[0])){this.offset.relative=this._getRelativeOffset()}var d=e.pageX;var c=e.pageY;if(this.originalPosition){if(this.containment){if(e.pageX-this.offset.click.leftthis.containment[2]){d=this.containment[2]+this.offset.click.left}if(e.pageY-this.offset.click.top>this.containment[3]){c=this.containment[3]+this.offset.click.top}}if(h.grid){var g=this.originalPageY+Math.round((c-this.originalPageY)/h.grid[1])*h.grid[1];c=this.containment?(!(g-this.offset.click.topthis.containment[3])?g:(!(g-this.offset.click.topthis.containment[2])?f:(!(f-this.offset.click.left').css({width:this.offsetWidth+"px",height:this.offsetHeight+"px",position:"absolute",opacity:"0.001",zIndex:1000}).css(a(this).offset()).appendTo("body")})},stop:function(b,c){a("div.ui-draggable-iframeFix").each(function(){this.parentNode.removeChild(this)})}});a.ui.plugin.add("draggable","opacity",{start:function(c,d){var b=a(d.helper),e=a(this).data("draggable").options;if(b.css("opacity")){e._opacity=b.css("opacity")}b.css("opacity",e.opacity)},stop:function(b,c){var d=a(this).data("draggable").options;if(d._opacity){a(c.helper).css("opacity",d._opacity)}}});a.ui.plugin.add("draggable","scroll",{start:function(c,d){var b=a(this).data("draggable");if(b.scrollParent[0]!=document&&b.scrollParent[0].tagName!="HTML"){b.overflowOffset=b.scrollParent.offset()}},drag:function(d,e){var c=a(this).data("draggable"),f=c.options,b=false;if(c.scrollParent[0]!=document&&c.scrollParent[0].tagName!="HTML"){if(!f.axis||f.axis!="x"){if((c.overflowOffset.top+c.scrollParent[0].offsetHeight)-d.pageY=0;v--){var s=g.snapElements[v].left,n=s+g.snapElements[v].width,m=g.snapElements[v].top,A=m+g.snapElements[v].height;if(!((s-y=p&&n<=k)||(m>=p&&m<=k)||(nk))&&((e>=g&&e<=c)||(d>=g&&d<=c)||(ec));break;default:return false;break}};a.ui.ddmanager={current:null,droppables:{"default":[]},prepareOffsets:function(e,g){var b=a.ui.ddmanager.droppables[e.options.scope];var f=g?g.type:null;var h=(e.currentItem||e.element).find(":data(droppable)").andSelf();droppablesLoop:for(var d=0;d').css({position:this.element.css("position"),width:this.element.outerWidth(),height:this.element.outerHeight(),top:this.element.css("top"),left:this.element.css("left")}));this.element=this.element.parent();this.elementIsWrapper=true;this.element.css({marginLeft:this.originalElement.css("marginLeft"),marginTop:this.originalElement.css("marginTop"),marginRight:this.originalElement.css("marginRight"),marginBottom:this.originalElement.css("marginBottom")});this.originalElement.css({marginLeft:0,marginTop:0,marginRight:0,marginBottom:0});if(b.browser.safari&&h.preventDefault){this.originalElement.css("resize","none")}this.proportionallyResize.push(this.originalElement.css({position:"static",zoom:1,display:"block"}));this.originalElement.css({margin:this.originalElement.css("margin")});this._proportionallyResize()}this.handles=h.handles||(!b(".ui-resizable-handle",this.element).length?"e,s,se":{n:".ui-resizable-n",e:".ui-resizable-e",s:".ui-resizable-s",w:".ui-resizable-w",se:".ui-resizable-se",sw:".ui-resizable-sw",ne:".ui-resizable-ne",nw:".ui-resizable-nw"});if(this.handles.constructor==String){if(this.handles=="all"){this.handles="n,e,s,w,se,sw,ne,nw"}var j=this.handles.split(",");this.handles={};for(var e=0;e');if(/sw|se|ne|nw/.test(g)){f.css({zIndex:++h.zIndex})}if("se"==g){f.addClass("ui-icon ui-icon-gripsmall-diagonal-se")}this.handles[g]=".ui-resizable-"+g;this.element.append(f)}}this._renderAxis=function(o){o=o||this.element;for(var l in this.handles){if(this.handles[l].constructor==String){this.handles[l]=b(this.handles[l],this.element).show()}if(h.transparent){this.handles[l].css({opacity:0})}if(this.elementIsWrapper&&this.originalElement[0].nodeName.match(/textarea|input|select|button/i)){var m=b(this.handles[l],this.element),n=0;n=/sw|ne|nw|se|n|s/.test(l)?m.outerHeight():m.outerWidth();var k=["padding",/ne|nw|n/.test(l)?"Top":/se|sw|s/.test(l)?"Bottom":/^e$/.test(l)?"Right":"Left"].join("");if(!h.transparent){o.css(k,n)}this._proportionallyResize()}if(!b(this.handles[l]).length){continue}}};this._renderAxis(this.element);this._handles=b(".ui-resizable-handle",this.element);if(h.disableSelection){this._handles.disableSelection()}this._handles.mouseover(function(){if(!d.resizing){if(this.className){var i=this.className.match(/ui-resizable-(se|sw|ne|nw|n|e|s|w)/i)}d.axis=i&&i[1]?i[1]:"se"}});if(h.autoHide){this._handles.hide();b(this.element).addClass("ui-resizable-autohide").hover(function(){b(this).removeClass("ui-resizable-autohide");d._handles.show()},function(){if(!d.resizing){b(this).addClass("ui-resizable-autohide");d._handles.hide()}})}this._mouseInit()},destroy:function(){this._mouseDestroy();var c=function(d){b(d).removeClass("ui-resizable ui-resizable-disabled").removeData("resizable").unbind(".resizable").find(".ui-resizable-handle").remove()};if(this.elementIsWrapper){c(this.element);this.wrapper.parent().append(this.originalElement.css({position:this.wrapper.css("position"),width:this.wrapper.outerWidth(),height:this.wrapper.outerHeight(),top:this.wrapper.css("top"),left:this.wrapper.css("left")})).end().remove()}c(this.originalElement)},_mouseCapture:function(d){var e=false;for(var c in this.handles){if(b(this.handles[c])[0]==d.target){e=true}}return this.options.disabled||!!e},_mouseStart:function(e){var h=this.options,d=this.element.position(),c=this.element;this.resizing=true;this.documentScroll={top:b(document).scrollTop(),left:b(document).scrollLeft()};if(c.is(".ui-draggable")||(/absolute/).test(c.css("position"))){c.css({position:"absolute",top:d.top,left:d.left})}if(b.browser.opera&&(/relative/).test(c.css("position"))){c.css({position:"relative",top:"auto",left:"auto"})}this._renderProxy();var i=a(this.helper.css("left")),f=a(this.helper.css("top"));if(h.containment){i+=b(h.containment).scrollLeft()||0;f+=b(h.containment).scrollTop()||0}this.offset=this.helper.offset();this.position={left:i,top:f};this.size=this._helper?{width:c.outerWidth(),height:c.outerHeight()}:{width:c.width(),height:c.height()};this.originalSize=this._helper?{width:c.outerWidth(),height:c.outerHeight()}:{width:c.width(),height:c.height()};this.originalPosition={left:i,top:f};this.sizeDiff={width:c.outerWidth()-c.width(),height:c.outerHeight()-c.height()};this.originalMousePosition={left:e.pageX,top:e.pageY};this.aspectRatio=(typeof h.aspectRatio=="number")?h.aspectRatio:((this.originalSize.width/this.originalSize.height)||1);if(h.preserveCursor){var g=b(".ui-resizable-"+this.axis).css("cursor");b("body").css("cursor",g=="auto"?this.axis+"-resize":g)}this._propagate("start",e);return true},_mouseDrag:function(c){var f=this.helper,e=this.options,k={},n=this,h=this.originalMousePosition,l=this.axis;var p=(c.pageX-h.left)||0,m=(c.pageY-h.top)||0;var g=this._change[l];if(!g){return false}var j=g.apply(this,[c,p,m]),i=b.browser.msie&&b.browser.version<7,d=this.sizeDiff;if(this._aspectRatio||c.shiftKey){j=this._updateRatio(j,c)}j=this._respectSize(j,c);this._propagate("resize",c);f.css({top:this.position.top+"px",left:this.position.left+"px",width:this.size.width+"px",height:this.size.height+"px"});if(!this._helper&&this.proportionallyResize.length){this._proportionallyResize()}this._updateCache(j);this._trigger("resize",c,this.ui());return false},_mouseStop:function(f){this.resizing=false;var g=this.options,k=this;if(this._helper){var e=this.proportionallyResize,c=e.length&&(/textarea/i).test(e[0].nodeName),d=c&&b.ui.hasScroll(e[0],"left")?0:k.sizeDiff.height,i=c?0:k.sizeDiff.width;var l={width:(k.size.width-i),height:(k.size.height-d)},h=(parseInt(k.element.css("left"),10)+(k.position.left-k.originalPosition.left))||null,j=(parseInt(k.element.css("top"),10)+(k.position.top-k.originalPosition.top))||null;if(!g.animate){this.element.css(b.extend(l,{top:j,left:h}))}if(this._helper&&!g.animate){this._proportionallyResize()}}if(g.preserveCursor){b("body").css("cursor","auto")}this._propagate("stop",f);if(this._helper){this.helper.remove()}return false},_updateCache:function(c){var d=this.options;this.offset=this.helper.offset();if(c.left){this.position.left=c.left}if(c.top){this.position.top=c.top}if(c.height){this.size.height=c.height}if(c.width){this.size.width=c.width}},_updateRatio:function(f,e){var g=this.options,h=this.position,d=this.size,c=this.axis;if(f.height){f.width=(d.height*this.aspectRatio)}else{if(f.width){f.height=(d.width/this.aspectRatio)}}if(c=="sw"){f.left=h.left+(d.width-f.width);f.top=null}if(c=="nw"){f.top=h.top+(d.height-f.height);f.left=h.left+(d.width-f.width)}return f},_respectSize:function(j,e){var r=function(o){return !isNaN(parseInt(o,10))};var h=this.helper,g=this.options,p=this._aspectRatio||e.shiftKey,n=this.axis,s=r(j.width)&&g.maxWidth&&(g.maxWidthj.width),q=r(j.height)&&g.minHeight&&(g.minHeight>j.height);if(f){j.width=g.minWidth}if(q){j.height=g.minHeight}if(s){j.width=g.maxWidth}if(k){j.height=g.maxHeight}var d=this.originalPosition.left+this.originalSize.width,m=this.position.top+this.size.height;var i=/sw|nw|w/.test(n),c=/nw|ne|n/.test(n);if(f&&i){j.left=d-g.minWidth}if(s&&i){j.left=d-g.maxWidth}if(q&&c){j.top=m-g.minHeight}if(k&&c){j.top=m-g.maxHeight}var l=!j.width&&!j.height;if(l&&!j.left&&j.top){j.top=null}else{if(l&&!j.top&&j.left){j.left=null}}return j},_proportionallyResize:function(){var h=this.options;if(!this.proportionallyResize.length){return}var e=this.helper||this.element;for(var d=0;d');var c=b.browser.msie&&b.browser.version<7,e=(c?1:0),f=(c?2:-1);this.helper.addClass(this._helper).css({width:this.element.outerWidth()+f,height:this.element.outerHeight()+f,position:"absolute",left:this.elementOffset.left-e+"px",top:this.elementOffset.top-e+"px",zIndex:++g.zIndex});this.helper.appendTo("body");if(g.disableSelection){this.helper.disableSelection()}}else{this.helper=this.element}},_change:{e:function(e,d,c){return{width:this.originalSize.width+d}},w:function(f,d,c){var h=this.options,e=this.originalSize,g=this.originalPosition;return{left:g.left+d,width:e.width-d}},n:function(f,d,c){var h=this.options,e=this.originalSize,g=this.originalPosition;return{top:g.top+c,height:e.height-c}},s:function(e,d,c){return{height:this.originalSize.height+c}},se:function(e,d,c){return b.extend(this._change.s.apply(this,arguments),this._change.e.apply(this,[e,d,c]))},sw:function(e,d,c){return b.extend(this._change.s.apply(this,arguments),this._change.w.apply(this,[e,d,c]))},ne:function(e,d,c){return b.extend(this._change.n.apply(this,arguments),this._change.e.apply(this,[e,d,c]))},nw:function(e,d,c){return b.extend(this._change.n.apply(this,arguments),this._change.w.apply(this,[e,d,c]))}},_propagate:function(d,c){b.ui.plugin.call(this,d,[c,this.ui()]);(d!="resize"&&this._trigger(d,c,this.ui()))},plugins:{},ui:function(){return{originalElement:this.originalElement,element:this.element,helper:this.helper,position:this.position,size:this.size,originalSize:this.originalSize,originalPosition:this.originalPosition}}}));b.extend(b.ui.resizable,{version:"1.6rc6",eventPrefix:"resize",defaults:{alsoResize:false,animate:false,animateDuration:"slow",animateEasing:"swing",aspectRatio:false,autoHide:false,cancel:":input,option",containment:false,delay:0,disableSelection:true,distance:1,ghost:false,grid:false,handles:"e,s,se",helper:false,maxHeight:null,maxWidth:null,minHeight:10,minWidth:10,preserveCursor:true,preventDefault:true,proportionallyResize:false,transparent:false,zIndex:1000}});b.ui.plugin.add("resizable","alsoResize",{start:function(d,e){var c=b(this).data("resizable"),f=c.options;_store=function(g){b(g).each(function(){b(this).data("resizable-alsoresize",{width:parseInt(b(this).width(),10),height:parseInt(b(this).height(),10),left:parseInt(b(this).css("left"),10),top:parseInt(b(this).css("top"),10)})})};if(typeof(f.alsoResize)=="object"&&!f.alsoResize.parentNode){if(f.alsoResize.length){f.alsoResize=f.alsoResize[0];_store(f.alsoResize)}else{b.each(f.alsoResize,function(g,h){_store(g)})}}else{_store(f.alsoResize)}},resize:function(e,g){var d=b(this).data("resizable"),h=d.options,f=d.originalSize,j=d.originalPosition;var i={height:(d.size.height-f.height)||0,width:(d.size.width-f.width)||0,top:(d.position.top-j.top)||0,left:(d.position.left-j.left)||0},c=function(k,l){b(k).each(function(){var o=b(this),p=b(this).data("resizable-alsoresize"),n={},m=l&&l.length?l:["width","height","top","left"];b.each(m||["width","height","top","left"],function(q,s){var r=(p[s]||0)+(i[s]||0);if(r&&r>=0){n[s]=r||null}});if(/relative/.test(o.css("position"))&&b.browser.opera){d._revertToRelativePosition=true;o.css({position:"absolute",top:"auto",left:"auto"})}o.css(n)})};if(typeof(h.alsoResize)=="object"&&!h.alsoResize.nodeType){b.each(h.alsoResize,function(k,l){c(k,l)})}else{c(h.alsoResize)}},stop:function(d,e){var c=b(this).data("resizable");if(c._revertToRelativePosition&&b.browser.opera){c._revertToRelativePosition=false;el.css({position:"relative"})}b(this).removeData("resizable-alsoresize-start")}});b.ui.plugin.add("resizable","animate",{stop:function(g,l){var m=b(this).data("resizable"),h=m.options;var f=h.proportionallyResize,c=f&&(/textarea/i).test(f.get(0).nodeName),d=c&&b.ui.hasScroll(f.get(0),"left")?0:m.sizeDiff.height,j=c?0:m.sizeDiff.width;var e={width:(m.size.width-j),height:(m.size.height-d)},i=(parseInt(m.element.css("left"),10)+(m.position.left-m.originalPosition.left))||null,k=(parseInt(m.element.css("top"),10)+(m.position.top-m.originalPosition.top))||null;m.element.animate(b.extend(e,k&&i?{top:k,left:i}:{}),{duration:h.animateDuration,easing:h.animateEasing,step:function(){var n={width:parseInt(m.element.css("width"),10),height:parseInt(m.element.css("height"),10),top:parseInt(m.element.css("top"),10),left:parseInt(m.element.css("left"),10)};if(f){f.css({width:n.width,height:n.height})}m._updateCache(n);m._propagate("resize",g)}})}});b.ui.plugin.add("resizable","containment",{start:function(d,n){var r=b(this).data("resizable"),h=r.options,j=r.element;var e=h.containment,i=(e instanceof b)?e.get(0):(/parent/.test(e))?j.parent().get(0):e;if(!i){return}r.containerElement=b(i);if(/document/.test(e)||e==document){r.containerOffset={left:0,top:0};r.containerPosition={left:0,top:0};r.parentData={element:b(document),left:0,top:0,width:b(document).width(),height:b(document).height()||document.body.parentNode.scrollHeight}}else{var l=b(i),g=[];b(["Top","Right","Left","Bottom"]).each(function(p,o){g[p]=a(l.css("padding"+o))});r.containerOffset=l.offset();r.containerPosition=l.position();r.containerSize={height:(l.innerHeight()-g[3]),width:(l.innerWidth()-g[1])};var m=r.containerOffset,c=r.containerSize.height,k=r.containerSize.width,f=(b.ui.hasScroll(i,"left")?i.scrollWidth:k),q=(b.ui.hasScroll(i)?i.scrollHeight:c);r.parentData={element:i,left:m.left,top:m.top,width:f,height:q}}},resize:function(e,l){var p=b(this).data("resizable"),g=p.options,d=p.containerSize,k=p.containerOffset,i=p.size,j=p.position,m=g._aspectRatio||e.shiftKey,c={top:0,left:0},f=p.containerElement;if(f[0]!=document&&(/static/).test(f.css("position"))){c=k}if(j.left<(p._helper?k.left:0)){p.size.width=p.size.width+(p._helper?(p.position.left-k.left):(p.position.left-c.left));if(m){p.size.height=p.size.width/g.aspectRatio}p.position.left=g.helper?k.left:0}if(j.top<(p._helper?k.top:0)){p.size.height=p.size.height+(p._helper?(p.position.top-k.top):p.position.top);if(m){p.size.width=p.size.height*g.aspectRatio}p.position.top=p._helper?k.top:0}var h=Math.abs((p._helper?p.offset.left-c.left:(p.offset.left-c.left))+p.sizeDiff.width),n=Math.abs((p._helper?p.offset.top-c.top:(p.offset.top-k.top))+p.sizeDiff.height);if(h+p.size.width>=p.parentData.width){p.size.width=p.parentData.width-h;if(m){p.size.height=p.size.width/g.aspectRatio}}if(n+p.size.height>=p.parentData.height){p.size.height=p.parentData.height-n;if(m){p.size.width=p.size.height*g.aspectRatio}}},stop:function(d,l){var n=b(this).data("resizable"),e=n.options,j=n.position,k=n.containerOffset,c=n.containerPosition,f=n.containerElement;var g=b(n.helper),p=g.offset(),m=g.outerWidth()-n.sizeDiff.width,i=g.outerHeight()-n.sizeDiff.height;if(n._helper&&!e.animate&&(/relative/).test(f.css("position"))){b(this).css({left:p.left-c.left-k.left,width:m,height:i})}if(n._helper&&!e.animate&&(/static/).test(f.css("position"))){b(this).css({left:p.left-c.left-k.left,width:m,height:i})}}});b.ui.plugin.add("resizable","ghost",{start:function(e,f){var c=b(this).data("resizable"),g=c.options,h=g.proportionallyResize,d=c.size;c.ghost=c.originalElement.clone();c.ghost.css({opacity:0.25,display:"block",position:"relative",height:d.height,width:d.width,margin:0,left:0,top:0}).addClass("ui-resizable-ghost").addClass(typeof g.ghost=="string"?g.ghost:"");c.ghost.appendTo(c.helper)},resize:function(d,e){var c=b(this).data("resizable"),f=c.options;if(c.ghost){c.ghost.css({position:"relative",height:c.size.height,width:c.size.width})}},stop:function(d,e){var c=b(this).data("resizable"),f=c.options;if(c.ghost&&c.helper){c.helper.get(0).removeChild(c.ghost.get(0))}}});b.ui.plugin.add("resizable","grid",{resize:function(c,k){var m=b(this).data("resizable"),f=m.options,i=m.size,g=m.originalSize,h=m.originalPosition,l=m.axis,j=f._aspectRatio||c.shiftKey;f.grid=typeof f.grid=="number"?[f.grid,f.grid]:f.grid;var e=Math.round((i.width-g.width)/(f.grid[0]||1))*(f.grid[0]||1),d=Math.round((i.height-g.height)/(f.grid[1]||1))*(f.grid[1]||1);if(/^(se|s|e)$/.test(l)){m.size.width=g.width+e;m.size.height=g.height+d}else{if(/^(ne)$/.test(l)){m.size.width=g.width+e;m.size.height=g.height+d;m.position.top=h.top-d}else{if(/^(sw)$/.test(l)){m.size.width=g.width+e;m.size.height=g.height+d;m.position.left=h.left-e}else{m.size.width=g.width+e;m.size.height=g.height+d;m.position.top=h.top-d;m.position.left=h.left-e}}}}});var a=function(c){return parseInt(c,10)||0}})(jQuery);/* + * jQuery UI Selectable 1.6rc6 + * + * Copyright (c) 2009 AUTHORS.txt (http://ui.jquery.com/about) + * Dual licensed under the MIT (MIT-LICENSE.txt) + * and GPL (GPL-LICENSE.txt) licenses. + * + * http://docs.jquery.com/UI/Selectables + * + * Depends: + * ui.core.js + */ +(function(a){a.widget("ui.selectable",a.extend({},a.ui.mouse,{_init:function(){var b=this;this.element.addClass("ui-selectable");this.dragged=false;var c;this.refresh=function(){c=a(b.options.filter,b.element[0]);c.each(function(){var d=a(this);var e=d.offset();a.data(this,"selectable-item",{element:this,$element:d,left:e.left,top:e.top,right:e.left+d.outerWidth(),bottom:e.top+d.outerHeight(),startselected:false,selected:d.hasClass("ui-selected"),selecting:d.hasClass("ui-selecting"),unselecting:d.hasClass("ui-unselecting")})})};this.refresh();this.selectees=c.addClass("ui-selectee");this._mouseInit();this.helper=a(document.createElement("div")).css({border:"1px dotted black"}).addClass("ui-selectable-helper")},destroy:function(){this.element.removeClass("ui-selectable ui-selectable-disabled").removeData("selectable").unbind(".selectable");this._mouseDestroy()},_mouseStart:function(d){var b=this;this.opos=[d.pageX,d.pageY];if(this.options.disabled){return}var c=this.options;this.selectees=a(c.filter,this.element[0]);this._trigger("start",d);a("body").append(this.helper);this.helper.css({"z-index":100,position:"absolute",left:d.clientX,top:d.clientY,width:0,height:0});if(c.autoRefresh){this.refresh()}this.selectees.filter(".ui-selected").each(function(){var e=a.data(this,"selectable-item");e.startselected=true;if(!d.metaKey){e.$element.removeClass("ui-selected");e.selected=false;e.$element.addClass("ui-unselecting");e.unselecting=true;b._trigger("unselecting",d,{unselecting:e.element})}});a(d.target).parents().andSelf().each(function(){var e=a.data(this,"selectable-item");if(e){e.$element.removeClass("ui-unselecting").addClass("ui-selecting");e.unselecting=false;e.selecting=true;e.selected=true;b._trigger("selecting",d,{selecting:e.element});return false}})},_mouseDrag:function(i){var c=this;this.dragged=true;if(this.options.disabled){return}var e=this.options;var d=this.opos[0],h=this.opos[1],b=i.pageX,g=i.pageY;if(d>b){var f=b;b=d;d=f}if(h>g){var f=g;g=h;h=f}this.helper.css({left:d,top:h,width:b-d,height:g-h});this.selectees.each(function(){var j=a.data(this,"selectable-item");if(!j||j.element==c.element[0]){return}var k=false;if(e.tolerance=="touch"){k=(!(j.left>b||j.rightg||j.bottomd&&j.righth&&j.bottom=0;b--){this.items[b].item.removeData("sortable-item")}},_mouseCapture:function(e,f){if(this.reverting){return false}if(this.options.disabled||this.options.type=="static"){return false}this._refreshItems(e);var d=null,c=this,b=a(e.target).parents().each(function(){if(a.data(this,"sortable-item")==c){d=a(this);return false}});if(a.data(e.target,"sortable-item")==c){d=a(e.target)}if(!d){return false}if(this.options.handle&&!f){var g=false;a(this.options.handle,d).find("*").andSelf().each(function(){if(this==e.target){g=true}});if(!g){return false}}this.currentItem=d;this._removeCurrentsFromItems();return true},_mouseStart:function(e,f,b){var g=this.options,c=this;this.currentContainer=this;this.refreshPositions();this.helper=this._createHelper(e);this._cacheHelperProportions();this._cacheMargins();this.scrollParent=this.helper.scrollParent();this.offset=this.currentItem.offset();this.offset={top:this.offset.top-this.margins.top,left:this.offset.left-this.margins.left};this.helper.css("position","absolute");this.cssPosition=this.helper.css("position");a.extend(this.offset,{click:{left:e.pageX-this.offset.left,top:e.pageY-this.offset.top},parent:this._getParentOffset(),relative:this._getRelativeOffset()});this.originalPosition=this._generatePosition(e);this.originalPageX=e.pageX;this.originalPageY=e.pageY;if(g.cursorAt){this._adjustOffsetFromHelper(g.cursorAt)}this.domPosition={prev:this.currentItem.prev()[0],parent:this.currentItem.parent()[0]};if(this.helper[0]!=this.currentItem[0]){this.currentItem.hide()}this._createPlaceholder();if(g.containment){this._setContainment()}if(g.cursor){if(a("body").css("cursor")){this._storedCursor=a("body").css("cursor")}a("body").css("cursor",g.cursor)}if(g.opacity){if(this.helper.css("opacity")){this._storedOpacity=this.helper.css("opacity")}this.helper.css("opacity",g.opacity)}if(g.zIndex){if(this.helper.css("zIndex")){this._storedZIndex=this.helper.css("zIndex")}this.helper.css("zIndex",g.zIndex)}if(this.scrollParent[0]!=document&&this.scrollParent[0].tagName!="HTML"){this.overflowOffset=this.scrollParent.offset()}this._trigger("start",e,this._uiHash());if(!this._preserveHelperProportions){this._cacheHelperProportions()}if(!b){for(var d=this.containers.length-1;d>=0;d--){this.containers[d]._trigger("activate",e,c._uiHash(this))}}if(a.ui.ddmanager){a.ui.ddmanager.current=this}if(a.ui.ddmanager&&!g.dropBehaviour){a.ui.ddmanager.prepareOffsets(this,e)}this.dragging=true;this.helper.addClass(g.cssNamespace+"-sortable-helper");this._mouseDrag(e);return true},_mouseDrag:function(f){this.position=this._generatePosition(f);this.positionAbs=this._convertPositionTo("absolute");if(!this.lastPositionAbs){this.lastPositionAbs=this.positionAbs}if(this.options.scroll){var g=this.options,b=false;if(this.scrollParent[0]!=document&&this.scrollParent[0].tagName!="HTML"){if((this.overflowOffset.top+this.scrollParent[0].offsetHeight)-f.pageY=0;d--){var e=this.items[d],c=e.item[0],h=this._intersectsWithPointer(e);if(!h){continue}if(c!=this.currentItem[0]&&this.placeholder[h==1?"next":"prev"]()[0]!=c&&!a.ui.contains(this.placeholder[0],c)&&(this.options.type=="semi-dynamic"?!a.ui.contains(this.element[0],c):true)){this.direction=h==1?"down":"up";if(this.options.tolerance=="pointer"||this._intersectsWithSides(e)){this.options.sortIndicator.call(this,f,e)}else{break}this._trigger("change",f,this._uiHash());break}}this._contactContainers(f);if(a.ui.ddmanager){a.ui.ddmanager.drag(this,f)}this._trigger("sort",f,this._uiHash());this.lastPositionAbs=this.positionAbs;return false},_mouseStop:function(c,d){if(!c){return}if(a.ui.ddmanager&&!this.options.dropBehaviour){a.ui.ddmanager.drop(this,c)}if(this.options.revert){var b=this;var e=b.placeholder.offset();b.reverting=true;a(this.helper).animate({left:e.left-this.offset.parent.left-b.margins.left+(this.offsetParent[0]==document.body?0:this.offsetParent[0].scrollLeft),top:e.top-this.offset.parent.top-b.margins.top+(this.offsetParent[0]==document.body?0:this.offsetParent[0].scrollTop)},parseInt(this.options.revert,10)||500,function(){b._clear(c)})}else{this._clear(c,d)}return false},cancel:function(){var b=this;if(this.dragging){this._mouseUp();if(this.options.helper=="original"){this.currentItem.css(this._storedCSS).removeClass(this.options.cssNamespace+"-sortable-helper")}else{this.currentItem.show()}for(var c=this.containers.length-1;c>=0;c--){this.containers[c]._trigger("deactivate",null,b._uiHash(this));if(this.containers[c].containerCache.over){this.containers[c]._trigger("out",null,b._uiHash(this));this.containers[c].containerCache.over=0}}}if(this.placeholder[0].parentNode){this.placeholder[0].parentNode.removeChild(this.placeholder[0])}if(this.options.helper!="original"&&this.helper&&this.helper[0].parentNode){this.helper.remove()}a.extend(this,{helper:null,dragging:false,reverting:false,_noFinalSort:null});if(this.domPosition.prev){a(this.domPosition.prev).after(this.currentItem)}else{a(this.domPosition.parent).prepend(this.currentItem)}return true},serialize:function(d){var b=this._getItemsAsjQuery(d&&d.connected);var c=[];d=d||{};a(b).each(function(){var e=(a(d.item||this).attr(d.attribute||"id")||"").match(d.expression||(/(.+)[-=_](.+)/));if(e){c.push((d.key||e[1]+"[]")+"="+(d.key&&d.expression?e[1]:e[2]))}});return c.join("&")},toArray:function(d){var b=this._getItemsAsjQuery(d&&d.connected);var c=[];d=d||{};b.each(function(){c.push(a(d.item||this).attr(d.attribute||"id")||"")});return c},_intersectsWith:function(m){var e=this.positionAbs.left,d=e+this.helperProportions.width,k=this.positionAbs.top,j=k+this.helperProportions.height;var f=m.left,c=f+m.width,n=m.top,i=n+m.height;var o=this.offset.click.top,h=this.offset.click.left;var g=(k+o)>n&&(k+o)f&&(e+h)m[this.floating?"width":"height"])){return g}else{return(f0?"down":"up")},_getDragHorizontalDirection:function(){var b=this.positionAbs.left-this.lastPositionAbs.left;return b!=0&&(b>0?"right":"left")},refresh:function(b){this._refreshItems(b);this.refreshPositions()},_getItemsAsjQuery:function(b){var l=this;var g=[];var e=[];if(this.options.connectWith&&b){var h=this.options.connectWith.constructor==String?[this.options.connectWith]:this.options.connectWith;for(var d=h.length-1;d>=0;d--){var k=a(h[d]);for(var c=k.length-1;c>=0;c--){var f=a.data(k[c],"sortable");if(f&&f!=this&&!f.options.disabled){e.push([a.isFunction(f.options.items)?f.options.items.call(f.element):a(f.options.items,f.element).not("."+f.options.cssNamespace+"-sortable-helper"),f])}}}}e.push([a.isFunction(this.options.items)?this.options.items.call(this.element,null,{options:this.options,item:this.currentItem}):a(this.options.items,this.element).not("."+this.options.cssNamespace+"-sortable-helper"),this]);for(var d=e.length-1;d>=0;d--){e[d][0].each(function(){g.push(this)})}return a(g)},_removeCurrentsFromItems:function(){var d=this.currentItem.find(":data(sortable-item)");for(var c=0;c=0;e--){var l=a(this.options.connectWith[e]);for(var d=l.length-1;d>=0;d--){var g=a.data(l[d],"sortable");if(g&&g!=this&&!g.options.disabled){f.push([a.isFunction(g.options.items)?g.options.items.call(g.element[0],b,{item:this.currentItem}):a(g.options.items,g.element),g]);this.containers.push(g)}}}}for(var e=f.length-1;e>=0;e--){var k=f[e][1];var c=f[e][0];for(var d=0,m=c.length;d=0;d--){var e=this.items[d];if(e.instance!=this.currentContainer&&this.currentContainer&&e.item[0]!=this.currentItem[0]){continue}var c=this.options.toleranceElement?a(this.options.toleranceElement,e.item):e.item;if(!b){if(this.options.accurateIntersection){e.width=c.outerWidth();e.height=c.outerHeight()}else{e.width=c[0].offsetWidth;e.height=c[0].offsetHeight}}var f=c.offset();e.left=f.left;e.top=f.top}if(this.options.custom&&this.options.custom.refreshContainers){this.options.custom.refreshContainers.call(this)}else{for(var d=this.containers.length-1;d>=0;d--){var f=this.containers[d].element.offset();this.containers[d].containerCache.left=f.left;this.containers[d].containerCache.top=f.top;this.containers[d].containerCache.width=this.containers[d].element.outerWidth();this.containers[d].containerCache.height=this.containers[d].element.outerHeight()}}},_createPlaceholder:function(d){var b=d||this,e=b.options;if(!e.placeholder||e.placeholder.constructor==String){var c=e.placeholder;e.placeholder={element:function(){var f=a(document.createElement(b.currentItem[0].nodeName)).addClass(c||b.currentItem[0].className+" "+b.options.cssNamespace+"-sortable-placeholder").removeClass(b.options.cssNamespace+"-sortable-helper")[0];if(!c){f.style.visibility="hidden"}return f},update:function(f,g){if(c&&!e.forcePlaceholderSize){return}if(!g.height()){g.height(b.currentItem.innerHeight()-parseInt(b.currentItem.css("paddingTop")||0,10)-parseInt(b.currentItem.css("paddingBottom")||0,10))}if(!g.width()){g.width(b.currentItem.innerWidth()-parseInt(b.currentItem.css("paddingLeft")||0,10)-parseInt(b.currentItem.css("paddingRight")||0,10))}}}}b.placeholder=a(e.placeholder.element.call(b.element,b.currentItem));b.currentItem.after(b.placeholder);e.placeholder.update(b,b.placeholder)},_contactContainers:function(d){for(var c=this.containers.length-1;c>=0;c--){if(this._intersectsWith(this.containers[c].containerCache)){if(!this.containers[c].containerCache.over){if(this.currentContainer!=this.containers[c]){var h=10000;var g=null;var e=this.positionAbs[this.containers[c].floating?"left":"top"];for(var b=this.items.length-1;b>=0;b--){if(!a.ui.contains(this.containers[c].element[0],this.items[b].item[0])){continue}var f=this.items[b][this.containers[c].floating?"left":"top"];if(Math.abs(f-e)this.containment[2]){d=this.containment[2]+this.offset.click.left}if(e.pageY-this.offset.click.top>this.containment[3]){c=this.containment[3]+this.offset.click.top}}if(h.grid){var g=this.originalPageY+Math.round((c-this.originalPageY)/h.grid[1])*h.grid[1];c=this.containment?(!(g-this.offset.click.topthis.containment[3])?g:(!(g-this.offset.click.topthis.containment[2])?f:(!(f-this.offset.click.left=0;c--){if(a.ui.contains(this.containers[c].element[0],this.currentItem[0])&&!e){f.push((function(g){return function(h){g._trigger("receive",h,this._uiHash(this))}}).call(this,this.containers[c]));f.push((function(g){return function(h){g._trigger("update",h,this._uiHash(this))}}).call(this,this.containers[c]))}}}for(var c=this.containers.length-1;c>=0;c--){if(!e){f.push((function(g){return function(h){g._trigger("deactivate",h,this._uiHash(this))}}).call(this,this.containers[c]))}if(this.containers[c].containerCache.over){f.push((function(g){return function(h){g._trigger("out",h,this._uiHash(this))}}).call(this,this.containers[c]));this.containers[c].containerCache.over=0}}if(this._storedCursor){a("body").css("cursor",this._storedCursor)}if(this._storedOpacity){this.helper.css("opacity",this._storedCursor)}if(this._storedZIndex){this.helper.css("zIndex",this._storedZIndex=="auto"?"":this._storedZIndex)}this.dragging=false;if(this.cancelHelperRemoval){if(!e){this._trigger("beforeStop",d,this._uiHash());for(var c=0;c *",placeholder:false,scope:"default",scroll:true,scrollSensitivity:20,scrollSpeed:20,sortIndicator:a.ui.sortable.prototype._rearrange,tolerance:"intersect",zIndex:1000}})})(jQuery);/* + * jQuery UI Accordion 1.6rc6 + * + * Copyright (c) 2009 AUTHORS.txt (http://ui.jquery.com/about) + * Dual licensed under the MIT (MIT-LICENSE.txt) + * and GPL (GPL-LICENSE.txt) licenses. + * + * http://docs.jquery.com/UI/Accordion + * + * Depends: + * ui.core.js + */ +(function(a){a.widget("ui.accordion",{_init:function(){var d=this.options,b=this;this.running=0;if(d.navigation){var c=this.element.find("a").filter(d.navigationFilter);if(c.length){if(c.filter(d.header).length){this.active=c}else{this.active=c.parent().parent().prev();c.addClass("ui-accordion-content-active")}}}this.element.addClass("ui-accordion ui-widget ui-helper-reset");this.headers=this.element.find(d.header).addClass("ui-accordion-header ui-helper-reset ui-state-default ui-corner-all").bind("mouseenter.accordion",function(){a(this).addClass("ui-state-hover")}).bind("mouseleave.accordion",function(){a(this).removeClass("ui-state-hover")});this.headers.next().addClass("ui-accordion-content ui-helper-reset ui-widget-content ui-corner-bottom");this.active=this._findActive(this.active||d.active).toggleClass("ui-state-default").toggleClass("ui-state-active").toggleClass("ui-corner-all").toggleClass("ui-corner-top");this.active.next().addClass("ui-accordion-content-active");a("").addClass("ui-icon "+d.icons.header).prependTo(this.headers);this.active.find(".ui-icon").toggleClass(d.icons.header).toggleClass(d.icons.headerSelected);if(a.browser.msie){this.element.find("a").css("zoom","1")}this.resize();this.element.attr("role","tablist");this.headers.attr("role","tab").bind("keydown",function(e){return b._keydown(e)}).next().attr("role","tabpanel");this.headers.not(this.active||"").attr("aria-expanded","false").attr("tabIndex","-1").next().hide();if(!this.active.length){this.headers.eq(0).attr("tabIndex","0")}else{this.active.attr("aria-expanded","true").attr("tabIndex","0")}if(!a.browser.safari){this.headers.find("a").attr("tabIndex","-1")}if(d.event){this.element.bind((d.event)+".accordion",function(e){return b._clickHandler.call(b,e)})}},destroy:function(){this.element.removeClass("ui-accordion ui-widget ui-helper-reset").removeAttr("role").unbind(".accordion").removeData("accordion");this.headers.unbind(".accordion").removeClass("ui-accordion-header ui-helper-reset ui-state-default ui-corner-all ui-state-active ui-corner-top").removeAttr("role").removeAttr("aria-expanded").removeAttr("tabindex");this.headers.find("a").removeAttr("tabindex");this.headers.children(".ui-icon").remove();this.headers.next().removeClass("ui-accordion-content ui-accordion-content-active")},_keydown:function(e){var g=this.options,f=a.ui.keyCode;if(g.disabled||e.altKey||e.ctrlKey){return}var d=this.headers.length;var b=this.headers.index(e.target);var c=false;switch(e.keyCode){case f.RIGHT:case f.DOWN:c=this.headers[(b+1)%d];break;case f.LEFT:case f.UP:c=this.headers[(b-1+d)%d];break;case f.SPACE:case f.ENTER:return this._clickHandler({target:e.target})}if(c){a(e.target).attr("tabIndex","-1");a(c).attr("tabIndex","0");c.focus();return false}return true},resize:function(){var e=this.options,d;if(e.fillSpace){if(a.browser.msie){var b=this.element.parent().css("overflow");this.element.parent().css("overflow","hidden")}d=this.element.parent().height();if(a.browser.msie){this.element.parent().css("overflow",b)}this.headers.each(function(){d-=a(this).outerHeight()});var c=0;this.headers.next().each(function(){c=Math.max(c,a(this).innerHeight()-a(this).height())}).height(d-c).css("overflow","auto")}else{if(e.autoHeight){d=0;this.headers.next().each(function(){d=Math.max(d,a(this).outerHeight())}).height(d)}}},activate:function(b){this._clickHandler({target:this._findActive(b)[0]})},_findActive:function(b){return b?typeof b=="number"?this.headers.filter(":eq("+b+")"):this.headers.not(this.headers.not(b)):b===false?a([]):this.headers.filter(":eq(0)")},_clickHandler:function(f){var h=this.options;if(h.disabled){return false}if(!f.target&&!h.alwaysOpen){this.active.removeClass("ui-state-active ui-corner-top").addClass("ui-state-default ui-corner-all").find(".ui-icon").removeClass(h.icons.headerSelected).addClass(h.icons.header);this.active.next().addClass("ui-accordion-content-active");var c=this.active.next(),g={options:h,newHeader:a([]),oldHeader:h.active,newContent:a([]),oldContent:c},b=(this.active=a([]));this._toggle(b,c,g);return false}var d=a(f.target);d=a(d.parents(h.header)[0]||d);var e=d[0]==this.active[0];if(this.running||(h.alwaysOpen&&e)){return false}if(!d.is(h.header)){return}this.active.removeClass("ui-state-active ui-corner-top").addClass("ui-state-default ui-corner-all").find(".ui-icon").removeClass(h.icons.headerSelected).addClass(h.icons.header);this.active.next().addClass("ui-accordion-content-active");if(!e){d.removeClass("ui-state-default ui-corner-all").addClass("ui-state-active ui-corner-top").find(".ui-icon").removeClass(h.icons.header).addClass(h.icons.headerSelected);d.next().addClass("ui-accordion-content-active")}var b=d.next(),c=this.active.next(),g={options:h,newHeader:e&&!h.alwaysOpen?a([]):d,oldHeader:this.active,newContent:e&&!h.alwaysOpen?a([]):b.find("> *"),oldContent:c.find("> *")},i=this.headers.index(this.active[0])>this.headers.index(d[0]);this.active=e?a([]):d;this._toggle(b,c,g,e,i);return false},_toggle:function(b,i,g,j,k){var d=this.options,m=this;this.toShow=b;this.toHide=i;this.data=g;var c=function(){if(!m){return}return m._completed.apply(m,arguments)};this._trigger("changestart",null,this.data);this.running=i.size()===0?b.size():i.size();if(d.animated){var f={};if(!d.alwaysOpen&&j){f={toShow:a([]),toHide:i,complete:c,down:k,autoHeight:d.autoHeight||d.fillSpace}}else{f={toShow:b,toHide:i,complete:c,down:k,autoHeight:d.autoHeight||d.fillSpace}}if(!d.proxied){d.proxied=d.animated}if(!d.proxiedDuration){d.proxiedDuration=d.duration}d.animated=a.isFunction(d.proxied)?d.proxied(f):d.proxied;d.duration=a.isFunction(d.proxiedDuration)?d.proxiedDuration(f):d.proxiedDuration;var l=a.ui.accordion.animations,e=d.duration,h=d.animated;if(!l[h]){l[h]=function(n){this.slide(n,{easing:h,duration:e||700})}}l[h](f)}else{if(!d.alwaysOpen&&j){b.toggle()}else{i.hide();b.show()}c(true)}i.prev().attr("aria-expanded","false").attr("tabIndex","-1");b.prev().attr("aria-expanded","true").attr("tabIndex","0").focus()},_completed:function(b){var c=this.options;this.running=b?0:--this.running;if(this.running){return}if(c.clearStyle){this.toShow.add(this.toHide).css({height:"",overflow:""})}this._trigger("change",null,this.data)}});a.extend(a.ui.accordion,{version:"1.6rc6",defaults:{active:null,autoHeight:true,alwaysOpen:true,animated:"slide",clearStyle:false,event:"click",fillSpace:false,header:"a",icons:{header:"ui-icon-triangle-1-e",headerSelected:"ui-icon-triangle-1-s"},navigation:false,navigationFilter:function(){return this.href.toLowerCase()==location.href.toLowerCase()}},animations:{slide:function(j,h){j=a.extend({easing:"swing",duration:300},j,h);if(!j.toHide.size()){j.toShow.animate({height:"show"},j);return}var b=j.toHide.height(),i=j.toShow.height(),c=i/b,d=j.toShow.css("overflow"),e={},g={},f=["height","paddingTop","paddingBottom"];a.each(f,function(k,l){g[l]="hide";e[l]=parseFloat(j.toShow.css(l))});j.toShow.css({height:0,overflow:"hidden"}).show();j.toHide.filter(":hidden").each(j.complete).end().filter(":visible").animate(g,{step:function(l,m){if(!j.toShow[0]){return}var k=m.start!=m.end?(m.now-m.start)/(m.end-m.start):0,n=k*e[m.prop];if(a.browser.msie||a.browser.opera){n=Math.ceil(n)}j.toShow[0].style[m.prop]=n+"px"},duration:j.duration,easing:j.easing,complete:function(){if(!j.autoHeight){j.toShow.css("height","auto")}j.toShow.css({overflow:d});j.complete()}})},bounceslide:function(b){this.slide(b,{easing:b.down?"easeOutBounce":"swing",duration:b.down?1000:200})},easeslide:function(b){this.slide(b,{easing:"easeinout",duration:700})}}})})(jQuery);/* + * jQuery UI Dialog 1.6rc6 + * + * Copyright (c) 2009 AUTHORS.txt (http://ui.jquery.com/about) + * Dual licensed under the MIT (MIT-LICENSE.txt) + * and GPL (GPL-LICENSE.txt) licenses. + * + * http://docs.jquery.com/UI/Dialog + * + * Depends: + * ui.core.js + * ui.draggable.js + * ui.resizable.js + */ +(function(b){var a={dragStart:"start.draggable",drag:"drag.draggable",dragStop:"stop.draggable",maxHeight:"maxHeight.resizable",minHeight:"minHeight.resizable",maxWidth:"maxWidth.resizable",minWidth:"minWidth.resizable",resizeStart:"start.resizable",resize:"drag.resizable",resizeStop:"stop.resizable"};b.widget("ui.dialog",{_init:function(){this.originalTitle=this.element.attr("title");var k=this,l=this.options,i=l.title||this.originalTitle||" ",d=b.ui.dialog.getTitleId(this.element),j=(this.uiDialog=b("
")).appendTo(document.body).hide().addClass("ui-dialog ui-widget ui-widget-content ui-corner-all "+l.dialogClass).css({position:"absolute",overflow:"hidden",zIndex:l.zIndex}).attr("tabIndex",-1).css("outline",0).keydown(function(m){(l.closeOnEscape&&m.keyCode&&m.keyCode==b.ui.keyCode.ESCAPE&&k.close(m))}).attr({role:"dialog","aria-labelledby":d}).mousedown(function(m){k.moveToTop(m)}),f=this.element.show().removeAttr("title").addClass("ui-dialog-content ui-widget-content").appendTo(j),e=(this.uiDialogTitlebar=b("
")).addClass("ui-dialog-titlebar ui-widget-header ui-corner-all ui-helper-clearfix").prependTo(j),h=b('').addClass("ui-dialog-titlebar-close ui-corner-all").attr("role","button").hover(function(){h.addClass("ui-state-hover")},function(){h.removeClass("ui-state-hover")}).focus(function(){h.addClass("ui-state-focus")}).blur(function(){h.removeClass("ui-state-focus")}).mousedown(function(m){m.stopPropagation()}).click(function(m){k.close(m);return false}).appendTo(e),g=(this.uiDialogTitlebarCloseText=b("")).addClass("ui-icon ui-icon-closethick").text(l.closeText).appendTo(h),c=b("").addClass("ui-dialog-title").attr("id",d).html(i).prependTo(e);e.find("*").add(e).disableSelection();(l.draggable&&b.fn.draggable&&this._makeDraggable());(l.resizable&&b.fn.resizable&&this._makeResizable());this._createButtons(l.buttons);this._isOpen=false;(l.bgiframe&&b.fn.bgiframe&&j.bgiframe());(l.autoOpen&&this.open())},destroy:function(){(this.overlay&&this.overlay.destroy());(this.shadow&&this._destroyShadow());this.uiDialog.hide();this.element.unbind(".dialog").removeData("dialog").removeClass("ui-dialog-content ui-widget-content").hide().appendTo("body");this.uiDialog.remove();(this.originalTitle&&this.element.attr("title",this.originalTitle))},close:function(c){if(false===this._trigger("beforeclose",c)){return}(this.overlay&&this.overlay.destroy());(this.shadow&&this._destroyShadow());this.uiDialog.hide(this.options.hide).unbind("keypress.ui-dialog");this._trigger("close",c);b.ui.dialog.overlay.resize();this._isOpen=false},isOpen:function(){return this._isOpen},moveToTop:function(g,f){if((this.options.modal&&!g)||(!this.options.stack&&!this.options.modal)){return this._trigger("focus",f)}var e=this.options.zIndex,d=this.options;b(".ui-dialog:visible").each(function(){e=Math.max(e,parseInt(b(this).css("z-index"),10)||d.zIndex)});(this.overlay&&this.overlay.$el.css("z-index",++e));(this.shadow&&this.shadow.css("z-index",++e));var c={scrollTop:this.element.attr("scrollTop"),scrollLeft:this.element.attr("scrollLeft")};this.uiDialog.css("z-index",++e);this.element.attr(c);this._trigger("focus",f)},open:function(e){if(this._isOpen){return}var d=this.options,c=this.uiDialog;this.overlay=d.modal?new b.ui.dialog.overlay(this):null;(c.next().length&&c.appendTo("body"));this._size();this._position(d.position);c.show(d.show);this.moveToTop(true,e);(d.modal&&c.bind("keypress.ui-dialog",function(h){if(h.keyCode!=b.ui.keyCode.TAB){return}var g=b(":tabbable",this),i=g.filter(":first")[0],f=g.filter(":last")[0];if(h.target==f&&!h.shiftKey){setTimeout(function(){i.focus()},1)}else{if(h.target==i&&h.shiftKey){setTimeout(function(){f.focus()},1)}}}));b([]).add(c.find(".ui-dialog-content :tabbable:first")).add(c.find(".ui-dialog-buttonpane :tabbable:first")).add(c.find(".ui-dialog-titlebar :tabbable:first")).filter(":first").focus();if(d.shadow){this._createShadow()}this._trigger("open",e);this._isOpen=true},_createButtons:function(f){var e=this,c=false,d=b("
").addClass("ui-dialog-buttonpane ui-widget-content ui-helper-clearfix");this.uiDialog.find(".ui-dialog-buttonpane").remove();(typeof f=="object"&&f!==null&&b.each(f,function(){return !(c=true)}));if(c){b.each(f,function(g,h){b('').addClass("ui-state-default ui-corner-all").text(g).click(function(){h.apply(e.element[0],arguments)}).hover(function(){b(this).addClass("ui-state-hover")},function(){b(this).removeClass("ui-state-hover")}).focus(function(){b(this).addClass("ui-state-focus")}).blur(function(){b(this).removeClass("ui-state-focus")}).appendTo(d)});d.appendTo(this.uiDialog)}},_makeDraggable:function(){var c=this,d=this.options;this.uiDialog.draggable({cancel:".ui-dialog-content",helper:d.dragHelper,handle:".ui-dialog-titlebar",containment:"document",start:function(){(d.dragStart&&d.dragStart.apply(c.element[0],arguments));if(b.browser.msie&&b.browser.version<7&&c.shadow){c.shadow.hide()}},drag:function(){(d.drag&&d.drag.apply(c.element[0],arguments));c._refreshShadow(1)},stop:function(){(d.dragStop&&d.dragStop.apply(c.element[0],arguments));b.ui.dialog.overlay.resize();if(b.browser.msie&&b.browser.version<7&&c.shadow){c.shadow.show()}c._refreshShadow()}})},_makeResizable:function(f){f=(f===undefined?this.options.resizable:f);var c=this,e=this.options,d=typeof f=="string"?f:"n,e,s,w,se,sw,ne,nw";this.uiDialog.resizable({cancel:".ui-dialog-content",alsoResize:this.element,helper:e.resizeHelper,maxWidth:e.maxWidth,maxHeight:e.maxHeight,minWidth:e.minWidth,minHeight:e.minHeight,start:function(){(e.resizeStart&&e.resizeStart.apply(c.element[0],arguments));if(b.browser.msie&&b.browser.version<7&&c.shadow){c.shadow.hide()}},resize:function(){(e.resize&&e.resize.apply(c.element[0],arguments));c._refreshShadow(1)},handles:d,stop:function(){(e.resizeStop&&e.resizeStop.apply(c.element[0],arguments));b.ui.dialog.overlay.resize();if(b.browser.msie&&b.browser.version<7&&c.shadow){c.shadow.show()}c._refreshShadow()}}).find(".ui-resizable-se").addClass("ui-icon ui-icon-grip-diagonal-se")},_position:function(h){var d=b(window),e=b(document),f=e.scrollTop(),c=e.scrollLeft(),g=f;if(b.inArray(h,["center","top","right","bottom","left"])>=0){h=[h=="right"||h=="left"?h:"center",h=="top"||h=="bottom"?h:"middle"]}if(h.constructor!=Array){h=["center","middle"]}if(h[0].constructor==Number){c+=h[0]}else{switch(h[0]){case"left":c+=0;break;case"right":c+=d.width()-this.uiDialog.outerWidth();break;default:case"center":c+=(d.width()-this.uiDialog.outerWidth())/2}}if(h[1].constructor==Number){f+=h[1]}else{switch(h[1]){case"top":f+=0;break;case"bottom":f+=d.height()-this.uiDialog.outerHeight();break;default:case"middle":f+=(d.height()-this.uiDialog.outerHeight())/2}}f=Math.max(f,g);this.uiDialog.css({top:f,left:c})},_setData:function(d,e){(a[d]&&this.uiDialog.data(a[d],e));switch(d){case"buttons":this._createButtons(e);break;case"closeText":this.uiDialogTitlebarCloseText.text(e);break;case"draggable":(e?this._makeDraggable():this.uiDialog.draggable("destroy"));break;case"height":this.uiDialog.height(e);break;case"position":this._position(e);break;case"resizable":var c=this.uiDialog,f=this.uiDialog.is(":data(resizable)");(f&&!e&&c.resizable("destroy"));(f&&typeof e=="string"&&c.resizable("option","handles",e));(f||this._makeResizable(e));break;case"title":b(".ui-dialog-title",this.uiDialogTitlebar).html(e||" ");break;case"width":this.uiDialog.width(e);break}b.widget.prototype._setData.apply(this,arguments)},_size:function(){var d=this.options;this.element.css({height:0,minHeight:0,width:"auto"});var c=this.uiDialog.css({height:"auto",width:d.width}).height();this.element.css({minHeight:Math.max(d.minHeight-c,0),height:d.height=="auto"?"auto":d.height-c})},_createShadow:function(){this.shadow=b('
').css("position","absolute").appendTo(document.body);this._refreshShadow();return this.shadow},_refreshShadow:function(c){if(c&&b.browser.msie&&b.browser.version<7){return}var d=this.uiDialog.offset();this.shadow.css({left:d.left,top:d.top,width:this.uiDialog.outerWidth(),height:this.uiDialog.outerHeight()})},_destroyShadow:function(){this.shadow.remove();this.shadow=null}});b.extend(b.ui.dialog,{version:"1.6rc6",defaults:{autoOpen:true,bgiframe:false,buttons:{},closeOnEscape:true,closeText:"close",draggable:true,height:"auto",minHeight:150,minWidth:150,modal:false,position:"center",resizable:true,shadow:true,stack:true,title:"",width:300,zIndex:1000},getter:"isOpen",uuid:0,getTitleId:function(c){return"ui-dialog-title-"+(c.attr("id")||++this.uuid)},overlay:function(c){this.$el=b.ui.dialog.overlay.create(c)}});b.extend(b.ui.dialog.overlay,{instances:[],events:b.map("focus,mousedown,mouseup,keydown,keypress,click".split(","),function(c){return c+".dialog-overlay"}).join(" "),create:function(d){if(this.instances.length===0){setTimeout(function(){b("a, :input").bind(b.ui.dialog.overlay.events,function(){var f=false;var h=b(this).parents(".ui-dialog");if(h.length){var e=b(".ui-dialog-overlay");if(e.length){var g=parseInt(e.css("z-index"),10);e.each(function(){g=Math.max(g,parseInt(b(this).css("z-index"),10))});f=parseInt(h.css("z-index"),10)>g}else{f=true}}return f})},1);b(document).bind("keydown.dialog-overlay",function(e){(d.options.closeOnEscape&&e.keyCode&&e.keyCode==b.ui.keyCode.ESCAPE&&d.close(e))});b(window).bind("resize.dialog-overlay",b.ui.dialog.overlay.resize)}var c=b("
").appendTo(document.body).addClass("ui-widget-overlay").css({width:this.width(),height:this.height()});(d.options.bgiframe&&b.fn.bgiframe&&c.bgiframe());this.instances.push(c);return c},destroy:function(c){this.instances.splice(b.inArray(this.instances,c),1);if(this.instances.length===0){b("a, :input").add([document,window]).unbind(".dialog-overlay")}c.remove()},height:function(){if(b.browser.msie&&b.browser.version<7){var d=Math.max(document.documentElement.scrollHeight,document.body.scrollHeight);var c=Math.max(document.documentElement.offsetHeight,document.body.offsetHeight);if(d
");if(!c.values){c.values=[this._valueMin(),this._valueMin()]}if(c.values.length&&c.values.length!=2){c.values=[c.values[0],c.values[0]]}}else{this.range=a("
")}this.range.appendTo(this.element).addClass("ui-slider-range ui-widget-header");(c.range=="min")&&(this.orientation=="horizontal")&&this.range.css({left:0});(c.range=="max")&&(this.orientation=="horizontal")&&this.range.css({right:0});(c.range=="min")&&(this.orientation=="vertical")&&this.range.css({bottom:0});(c.range=="max")&&(this.orientation=="vertical")&&this.range.css({top:0})}if(a(".ui-slider-handle",this.element).length==0){a('
').appendTo(this.element).addClass("ui-slider-handle")}if(c.values&&c.values.length){while(a(".ui-slider-handle",this.element).length').appendTo(this.element).addClass("ui-slider-handle")}}this.handles=a(".ui-slider-handle",this.element).addClass("ui-state-default ui-corner-all");this.handle=this.handles.eq(0);this.handles.add(this.range).filter("a").click(function(d){d.preventDefault()}).hover(function(){a(this).addClass("ui-state-hover")},function(){a(this).removeClass("ui-state-hover")}).focus(function(){b.handles.removeClass("ui-state-focus");a(this).addClass("ui-state-focus")}).blur(function(){a(this).removeClass("ui-state-focus")});this.handles.each(function(d){a(this).data("index.ui-slider-handle",d)});this.handles.keydown(function(h){var e=a(this).data("index.ui-slider-handle");if(b.options.disabled){return}switch(h.keyCode){case a.ui.keyCode.HOME:case a.ui.keyCode.END:case a.ui.keyCode.UP:case a.ui.keyCode.RIGHT:case a.ui.keyCode.DOWN:case a.ui.keyCode.LEFT:if(!b._keySliding){b._keySliding=true;a(this).addClass("ui-state-active");b._start(h)}break}var f,d,g=b._step();if(b.options.values&&b.options.values.length){f=d=b.values(e)}else{f=d=b.value()}switch(h.keyCode){case a.ui.keyCode.HOME:d=b._valueMin();break;case a.ui.keyCode.END:d=b._valueMax();break;case a.ui.keyCode.UP:case a.ui.keyCode.RIGHT:if(f==b._valueMax()){return}d=f+g;break;case a.ui.keyCode.DOWN:case a.ui.keyCode.LEFT:if(f==b._valueMin()){return}d=f-g;break}b._slide(h,e,d)}).keyup(function(d){if(b._keySliding){b._stop(d);b._change(d);b._keySliding=false;a(this).removeClass("ui-state-active")}});this._refreshValue()},destroy:function(){this.handles.remove();this.element.removeClass("ui-slider ui-slider-horizontal ui-slider-vertical ui-slider-disabled ui-widget ui-widget-content ui-corner-all").removeData("slider").unbind(".slider");this._mouseDestroy()},_mouseCapture:function(d){var e=this.options;if(e.disabled){return false}this._start(d);this.elementSize={width:this.element.outerWidth(),height:this.element.outerHeight()};this.elementOffset=this.element.offset();var h={x:d.pageX,y:d.pageY};var j=this._normValueFromMouse(h);var c=this._valueMax()+1,f;var k=this,i;this.handles.each(function(l){var m=Math.abs(j-k.values(l));if(c>m){c=m;f=a(this);i=l}});if(e.range&&(this.values(0)+this.values(1))==0){f=a(this.handles[++i])}k._handleIndex=i;f.addClass("ui-state-active").focus();var g=f.offset();var b=!a(d.target).parents().andSelf().is(".ui-slider-handle");this._clickOffset=b?{left:0,top:0}:{left:d.pageX-g.left+(parseInt(f.css("marginLeft"),10)||0),top:d.pageY-g.top+(parseInt(f.css("marginTop"),10)||0)};j=this._normValueFromMouse(h);this._slide(d,i,j);return true},_mouseStart:function(b){return true},_mouseDrag:function(d){var b={x:d.pageX,y:d.pageY};var c=this._normValueFromMouse(b);this._slide(d,this._handleIndex,c);return false},_mouseStop:function(b){this.handles.removeClass("ui-state-active");this._stop(b);this._change(b);this._handleIndex=null;this._clickOffset=null;return false},_detectOrientation:function(){this.orientation=this.options.orientation=="auto"?(this.element[0].offsetWidth/this.element[0].offsetHeight>1?"horizontal":"vertical"):this.options.orientation},_normValueFromMouse:function(d){var c,h;if("horizontal"==this.orientation){c=this.elementSize.width;h=d.x-this.elementOffset.left-(this._clickOffset?this._clickOffset.left:0)}else{c=this.elementSize.height;h=d.y-this.elementOffset.top-(this._clickOffset?this._clickOffset.top:0)}var f=(h/c);if(f>1){f=1}if(f<0){f=0}if("vertical"==this.orientation){f=1-f}var e=this._valueMax()-this._valueMin(),i=f*e,b=i%this.options.step,g=this._valueMin()+i-b;if(b>(this.options.step/2)){g+=this.options.step}return g},_start:function(b){this._trigger("start",b,{value:this.value()})},_slide:function(f,e,d){var g=this.handles[e];if(this.options.values&&this.options.values.length){var b=this.values(e?0:1);if((e==0&&d>=b)||(e==1&&d<=b)){d=b}if(d!=this.values(e)){var c=this.values();c[e]=d;var h=this._trigger("slide",f,{handle:g,value:d,values:c});var b=this.values(e?0:1);if(h!==false){this.values(e,d,!(f.type=="mousedown"&&this.options.animate))}}}else{if(d!=this.value()){var h=this._trigger("slide",f,{handle:g,value:d});if(h!==false){this._setData("value",d,(f.type=="mousedown"&&this.options.animate))}}}},_stop:function(b){this._trigger("stop",b,{value:this.value()})},_change:function(b){this._trigger("change",b,{value:this.value()})},value:function(b){if(arguments.length){this._setData("value",b);this._change()}return this._value()},values:function(c,d,b){if(!this.options.animate){b=true}if(arguments.length>1){this.options.values[c]=d;this._refreshValue(!b);this._change()}if(arguments.length){if(this.options.values&&this.options.values.length){return this._values(c)}else{return this.value()}}else{return this._values()}},_setData:function(b,c){a.widget.prototype._setData.apply(this,arguments);switch(b){case"orientation":this._detectOrientation();this.element.removeClass("ui-slider-horizontal ui-slider-vertical").addClass("ui-slider-"+this.orientation);this._refreshValue();break;case"value":this._refreshValue();break}},_step:function(){var b=this.options.step;return b},_value:function(){var b=this.options.value;if(bthis._valueMax()){b=this._valueMax()}return b},_values:function(b){if(arguments.length){var c=this.options.values[b];if(cthis._valueMax()){c=this._valueMax()}return c}else{return this.options.values}},_valueMin:function(){var b=this.options.min;return b},_valueMax:function(){var b=this.options.max;return b},_refreshValue:function(e){var h=this.options.range,g=this.options,d=this;if(this.options.values&&this.options.values.length){var c,i;this.handles.each(function(n,l){var m=(d.values(n)-d._valueMin())/(d._valueMax()-d._valueMin())*100;var k={};k[d.orientation=="horizontal"?"left":"bottom"]=m+"%";a(this).stop(1,1)[e?"animate":"css"](k,g.animate);if(d.options.range===true){if(d.orientation=="horizontal"){(n==0)&&d.range.stop(1,1)[e?"animate":"css"]({left:m+"%"},g.animate);(n==1)&&d.range[e?"animate":"css"]({width:(m-lastValPercent)+"%"},{queue:false,duration:g.animate})}else{(n==0)&&d.range.stop(1,1)[e?"animate":"css"]({bottom:(m)+"%"},g.animate);(n==1)&&d.range[e?"animate":"css"]({height:(m-lastValPercent)+"%"},{queue:false,duration:g.animate})}}lastValPercent=m})}else{var f=(this.value()-this._valueMin())/(this._valueMax()-this._valueMin())*100;var b={};b[d.orientation=="horizontal"?"left":"bottom"]=f+"%";this.handle.stop(1,1)[e?"animate":"css"](b,g.animate);(h=="min")&&(this.orientation=="horizontal")&&this.range.stop(1,1)[e?"animate":"css"]({left:0,width:f+"%"},g.animate);(h=="max")&&(this.orientation=="horizontal")&&this.range[e?"animate":"css"]({left:f+"%",width:(100-f)+"%"},{queue:false,duration:g.animate});(h=="min")&&(this.orientation=="vertical")&&this.range.stop(1,1)[e?"animate":"css"]({top:(100-f)+"%",height:f+"%"},g.animate);(h=="max")&&(this.orientation=="vertical")&&this.range[e?"animate":"css"]({bottom:f+"%",height:(100-f)+"%"},{queue:false,duration:g.animate})}}}));a.extend(a.ui.slider,{getter:"value values",version:"1.6rc6",eventPrefix:"slide",defaults:{animate:false,delay:0,distance:0,max:100,min:0,orientation:"auto",range:false,step:1,value:0,values:null}})})(jQuery);/* + * jQuery UI Tabs 1.6rc6 + * + * Copyright (c) 2009 AUTHORS.txt (http://ui.jquery.com/about) + * Dual licensed under the MIT (MIT-LICENSE.txt) + * and GPL (GPL-LICENSE.txt) licenses. + * + * http://docs.jquery.com/UI/Tabs + * + * Depends: + * ui.core.js + */ +(function(a){a.widget("ui.tabs",{_init:function(){this._tabify(true)},_setData:function(b,c){if((/^selected/).test(b)){this.select(c)}else{this.options[b]=c;this._tabify()}},_tabId:function(b){return b.title&&b.title.replace(/\s/g,"_").replace(/[^A-Za-z0-9\-_:\.]/g,"")||this.options.idPrefix+a.data(b)},_sanitizeSelector:function(b){return b.replace(/:/g,"\\:")},_cookie:function(){var b=this.cookie||(this.cookie=this.options.cookie.name||"ui-tabs-"+a.data(this.list[0]));return a.cookie.apply(null,[b].concat(a.makeArray(arguments)))},_ui:function(c,b){return{tab:c,panel:b,index:this.$tabs.index(c)}},_tabify:function(q){this.list=this.element.is("div")?this.element.children("ul:first, ol:first").eq(0):this.element;this.$lis=a("li:has(a[href])",this.list);this.$tabs=this.$lis.map(function(){return a("a",this)[0]});this.$panels=a([]);var r=this,d=this.options;var c=/^#.+/;this.$tabs.each(function(t,o){var s=a(o).attr("href");if(c.test(s)){r.$panels=r.$panels.add(r._sanitizeSelector(s))}else{if(s!="#"){a.data(o,"href.tabs",s);a.data(o,"load.tabs",s.replace(/#.*$/,""));var v=r._tabId(o);o.href="#"+v;var u=a("#"+v);if(!u.length){u=a(d.panelTemplate).attr("id",v).addClass("ui-tabs-panel ui-widget-content ui-corner-bottom").insertAfter(r.$panels[t-1]||r.list);u.data("destroy.tabs",true)}r.$panels=r.$panels.add(u)}else{d.disabled.push(t+1)}}});if(q){if(this.element.is("div")){this.element.addClass("ui-tabs ui-widget ui-widget-content ui-corner-all")}this.list.addClass("ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all");this.$lis.addClass("ui-state-default ui-corner-top");this.$panels.addClass("ui-tabs-panel ui-widget-content ui-corner-bottom");if(d.selected===undefined){if(location.hash){this.$tabs.each(function(s,o){if(o.hash==location.hash){d.selected=s;return false}})}else{if(d.cookie){d.selected=parseInt(r._cookie(),10)}else{if(this.$lis.filter(".ui-tabs-selected").length){d.selected=this.$lis.index(this.$lis.filter(".ui-tabs-selected"))}else{d.selected=0}}}}else{if(d.selected===null){d.selected=-1}}d.selected=((d.selected>=0&&this.$tabs[d.selected])||d.selected<0)?d.selected:0;d.disabled=a.unique(d.disabled.concat(a.map(this.$lis.filter(".ui-state-disabled"),function(s,o){return r.$lis.index(s)}))).sort();if(a.inArray(d.selected,d.disabled)!=-1){d.disabled.splice(a.inArray(d.selected,d.disabled),1)}this.$panels.addClass("ui-tabs-hide");this.$lis.removeClass("ui-tabs-selected ui-state-active");if(d.selected>=0&&this.$tabs.length){this.$panels.eq(d.selected).removeClass("ui-tabs-hide");var f=["ui-tabs-selected ui-state-active"];if(d.deselectable){f.push("ui-tabs-deselectable")}this.$lis.eq(d.selected).addClass(f.join(" "));var k=function(){r._trigger("show",null,r._ui(r.$tabs[d.selected],r.$panels[d.selected]))};if(a.data(this.$tabs[d.selected],"load.tabs")){this.load(d.selected,k)}else{k()}}if(d.event!="mouseover"){var l=function(o,i){if(i.is(":not(.ui-state-disabled)")){i.toggleClass("ui-state-"+o)}};this.$lis.bind("mouseover.tabs mouseout.tabs",function(){l("hover",a(this))});this.$tabs.bind("focus.tabs blur.tabs",function(){l("focus",a(this).parents("li:first"))})}a(window).bind("unload",function(){r.$lis.add(r.$tabs).unbind(".tabs");r.$lis=r.$tabs=r.$panels=null})}else{d.selected=this.$lis.index(this.$lis.filter(".ui-tabs-selected"))}if(d.cookie){this._cookie(d.selected,d.cookie)}for(var h=0,p;p=this.$lis[h];h++){a(p)[a.inArray(h,d.disabled)!=-1&&!a(p).hasClass("ui-tabs-selected")?"addClass":"removeClass"]("ui-state-disabled")}if(d.cache===false){this.$tabs.removeData("cache.tabs")}var b,j;if(d.fx){if(a.isArray(d.fx)){b=d.fx[0];j=d.fx[1]}else{b=j=d.fx}}function e(i,o){i.css({display:""});if(a.browser.msie&&o.opacity){i[0].style.removeAttribute("filter")}}var m=j?function(i,o){o.hide().removeClass("ui-tabs-hide").animate(j,500,function(){e(o,j);r._trigger("show",null,r._ui(i,o[0]))})}:function(i,o){o.removeClass("ui-tabs-hide");r._trigger("show",null,r._ui(i,o[0]))};var n=b?function(o,i,s){i.animate(b,b.duration||"normal",function(){i.addClass("ui-tabs-hide");e(i,b);if(s){m(o,s)}})}:function(o,i,s){i.addClass("ui-tabs-hide");if(s){m(o,s)}};function g(s,u,i,t){var o=["ui-tabs-selected ui-state-active"];if(d.deselectable){o.push("ui-tabs-deselectable")}u.removeClass("ui-state-default").addClass(o.join(" ")).siblings().removeClass(o.join(" ")).addClass("ui-state-default");n(s,i,t)}this.$tabs.unbind(".tabs").bind(d.event+".tabs",function(){var t=a(this).parents("li:eq(0)"),i=r.$panels.filter(":visible"),s=a(r._sanitizeSelector(this.hash));if((t.hasClass("ui-state-active")&&!d.deselectable)||t.hasClass("ui-state-disabled")||a(this).hasClass("ui-tabs-loading")||r._trigger("select",null,r._ui(this,s[0]))===false){this.blur();return false}d.selected=r.$tabs.index(this);if(d.deselectable){if(t.hasClass("ui-state-active")){d.selected=-1;if(d.cookie){r._cookie(d.selected,d.cookie)}t.removeClass("ui-tabs-selected ui-state-active ui-tabs-deselectable").addClass("ui-state-default");r.$panels.stop();n(this,i);this.blur();return false}else{if(!i.length){if(d.cookie){r._cookie(d.selected,d.cookie)}r.$panels.stop();var o=this;r.load(r.$tabs.index(this),function(){t.addClass("ui-tabs-selected ui-state-active ui-tabs-deselectable").removeClass("ui-state-default");m(o,s)});this.blur();return false}}}if(d.cookie){r._cookie(d.selected,d.cookie)}r.$panels.stop();if(s.length){var o=this;r.load(r.$tabs.index(this),i.length?function(){g(o,t,i,s)}:function(){t.addClass("ui-tabs-selected ui-state-active").removeClass("ui-state-default");m(o,s)})}else{throw"jQuery UI Tabs: Mismatching fragment identifier."}if(a.browser.msie){this.blur()}return false});if(d.event!="click"){this.$tabs.bind("click.tabs",function(){return false})}},destroy:function(){var b=this.options;this.element.removeClass("ui-tabs ui-widget ui-widget-content ui-corner-all");this.list.unbind(".tabs").removeClass("ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all").removeData("tabs");this.$tabs.each(function(){var c=a.data(this,"href.tabs");if(c){this.href=c}var d=a(this).unbind(".tabs");a.each(["href","load","cache"],function(e,f){d.removeData(f+".tabs")})});this.$lis.unbind(".tabs").add(this.$panels).each(function(){if(a.data(this,"destroy.tabs")){a(this).remove()}else{a(this).removeClass("ui-state-default ui-corner-top ui-tabs-selected ui-state-active ui-tabs-deselectable ui-state-disabled ui-tabs-panel ui-widget-content ui-corner-bottom ui-tabs-hide")}});if(b.cookie){this._cookie(null,b.cookie)}},add:function(c,h,f){if(f==undefined){f=this.$tabs.length}var i=this,e=this.options;var g=a(e.tabTemplate.replace(/#\{href\}/g,c).replace(/#\{label\}/g,h));g.addClass("ui-state-default ui-corner-top").data("destroy.tabs",true);var d=c.indexOf("#")==0?c.replace("#",""):this._tabId(a("a:first-child",g)[0]);var j=a("#"+d);if(!j.length){j=a(e.panelTemplate).attr("id",d).data("destroy.tabs",true)}j.addClass("ui-tabs-panel ui-widget-content ui-corner-bottom ui-tabs-hide");if(f>=this.$lis.length){g.appendTo(this.list);j.appendTo(this.list[0].parentNode)}else{g.insertBefore(this.$lis[f]);j.insertBefore(this.$panels[f])}e.disabled=a.map(e.disabled,function(l,k){return l>=f?++l:l});this._tabify();if(this.$tabs.length==1){g.addClass("ui-tabs-selected ui-state-active");j.removeClass("ui-tabs-hide");var b=a.data(this.$tabs[0],"load.tabs");if(b){this.load(0,function(){i._trigger("show",null,i._ui(i.$tabs[0],i.$panels[0]))})}}this._trigger("add",null,this._ui(this.$tabs[f],this.$panels[f]))},remove:function(b){var d=this.options,e=this.$lis.eq(b).remove(),c=this.$panels.eq(b).remove();if(e.hasClass("ui-tabs-selected")&&this.$tabs.length>1){this.select(b+(b+1=b?--g:g});this._tabify();this._trigger("remove",null,this._ui(e.find("a")[0],c[0]))},enable:function(b){var c=this.options;if(a.inArray(b,c.disabled)==-1){return}this.$lis.eq(b).removeClass("ui-state-disabled");c.disabled=a.grep(c.disabled,function(e,d){return e!=b});this._trigger("enable",null,this._ui(this.$tabs[b],this.$panels[b]))},disable:function(c){var b=this,d=this.options;if(c!=d.selected){this.$lis.eq(c).addClass("ui-state-disabled");d.disabled.push(c);d.disabled.sort();this._trigger("disable",null,this._ui(this.$tabs[c],this.$panels[c]))}},select:function(b){if(typeof b=="string"){b=this.$tabs.index(this.$tabs.filter("[href$="+b+"]"))}this.$tabs.eq(b).trigger(this.options.event+".tabs")},load:function(g,k){var l=this,d=this.options,e=this.$tabs.eq(g),j=e[0],h=k==undefined||k===false,b=e.data("load.tabs");k=k||function(){};if(!b||!h&&a.data(j,"cache.tabs")){k();return}var m=function(n){var o=a(n),p=o.find("*:last");return p.length&&p.is(":not(img)")&&p||o};var c=function(){l.$tabs.filter(".ui-tabs-loading").removeClass("ui-tabs-loading").each(function(){if(d.spinner){m(this).parent().html(m(this).data("label.tabs"))}});l.xhr=null};if(d.spinner){var i=m(j).html();m(j).wrapInner("").find("em").data("label.tabs",i).html(d.spinner)}var f=a.extend({},d.ajaxOptions,{url:b,success:function(o,n){a(l._sanitizeSelector(j.hash)).html(o);c();if(d.cache){a.data(j,"cache.tabs",true)}l._trigger("load",null,l._ui(l.$tabs[g],l.$panels[g]));try{d.ajaxOptions.success(o,n)}catch(p){}k()}});if(this.xhr){this.xhr.abort();c()}e.addClass("ui-tabs-loading");l.xhr=a.ajax(f)},url:function(c,b){this.$tabs.eq(c).removeData("cache.tabs").data("load.tabs",b)},length:function(){return this.$tabs.length}});a.extend(a.ui.tabs,{version:"1.6rc6",getter:"length",defaults:{ajaxOptions:null,cache:false,cookie:null,deselectable:false,disabled:[],event:"click",fx:null,idPrefix:"ui-tabs-",panelTemplate:"
",spinner:"Loading…",tabTemplate:'
  • #{label}
  • '}});a.extend(a.ui.tabs.prototype,{rotation:null,rotate:function(d,f){var b=this,e=this.options.selected;function c(){clearTimeout(b.rotation);b.rotation=setTimeout(function(){e=++e')}$.extend(Datepicker.prototype,{markerClassName:"hasDatepicker",log:function(){if(this.debug){console.log.apply("",arguments)}},setDefaults:function(settings){extendRemove(this._defaults,settings||{});return this},_attachDatepicker:function(target,settings){var inlineSettings=null;for(var attrName in this._defaults){var attrValue=target.getAttribute("date:"+attrName);if(attrValue){inlineSettings=inlineSettings||{};try{inlineSettings[attrName]=eval(attrValue)}catch(err){inlineSettings[attrName]=attrValue}}}var nodeName=target.nodeName.toLowerCase();var inline=(nodeName=="div"||nodeName=="span");if(!target.id){target.id="dp"+(++this.uuid)}var inst=this._newInst($(target),inline);inst.settings=$.extend({},settings||{},inlineSettings||{});if(nodeName=="input"){this._connectDatepicker(target,inst)}else{if(inline){this._inlineDatepicker(target,inst)}}},_newInst:function(target,inline){var id=target[0].id.replace(/([:\[\]\.])/g,"\\\\$1");return{id:id,input:target,selectedDay:0,selectedMonth:0,selectedYear:0,drawMonth:0,drawYear:0,inline:inline,dpDiv:(!inline?this.dpDiv:$('
    '))}},_connectDatepicker:function(target,inst){var input=$(target);if(input.hasClass(this.markerClassName)){return}var appendText=this._get(inst,"appendText");var isRTL=this._get(inst,"isRTL");if(appendText){input[isRTL?"before":"after"](''+appendText+"")}var showOn=this._get(inst,"showOn");if(showOn=="focus"||showOn=="both"){input.focus(this._showDatepicker)}if(showOn=="button"||showOn=="both"){var buttonText=this._get(inst,"buttonText");var buttonImage=this._get(inst,"buttonImage");var trigger=$(this._get(inst,"buttonImageOnly")?$("").addClass(this._triggerClass).attr({src:buttonImage,alt:buttonText,title:buttonText}):$('').addClass(this._triggerClass).html(buttonImage==""?buttonText:$("").attr({src:buttonImage,alt:buttonText,title:buttonText})));input[isRTL?"before":"after"](trigger);trigger.click(function(){if($.datepicker._datepickerShowing&&$.datepicker._lastInput==target){$.datepicker._hideDatepicker()}else{$.datepicker._showDatepicker(target)}return false})}input.addClass(this.markerClassName).keydown(this._doKeyDown).keypress(this._doKeyPress).bind("setData.datepicker",function(event,key,value){inst.settings[key]=value}).bind("getData.datepicker",function(event,key){return this._get(inst,key)});$.data(target,PROP_NAME,inst)},_inlineDatepicker:function(target,inst){var divSpan=$(target);if(divSpan.hasClass(this.markerClassName)){return}divSpan.addClass(this.markerClassName).append(inst.dpDiv).bind("setData.datepicker",function(event,key,value){inst.settings[key]=value}).bind("getData.datepicker",function(event,key){return this._get(inst,key)});$.data(target,PROP_NAME,inst);this._setDate(inst,this._getDefaultDate(inst));this._updateDatepicker(inst);this._updateAlternate(inst)},_dialogDatepicker:function(input,dateText,onSelect,settings,pos){var inst=this._dialogInst;if(!inst){var id="dp"+(++this.uuid);this._dialogInput=$('');this._dialogInput.keydown(this._doKeyDown);$("body").append(this._dialogInput);inst=this._dialogInst=this._newInst(this._dialogInput,false);inst.settings={};$.data(this._dialogInput[0],PROP_NAME,inst)}extendRemove(inst.settings,settings||{});this._dialogInput.val(dateText);this._pos=(pos?(pos.length?pos:[pos.pageX,pos.pageY]):null);if(!this._pos){var browserWidth=window.innerWidth||document.documentElement.clientWidth||document.body.clientWidth;var browserHeight=window.innerHeight||document.documentElement.clientHeight||document.body.clientHeight;var scrollX=document.documentElement.scrollLeft||document.body.scrollLeft;var scrollY=document.documentElement.scrollTop||document.body.scrollTop;this._pos=[(browserWidth/2)-100+scrollX,(browserHeight/2)-150+scrollY]}this._dialogInput.css("left",this._pos[0]+"px").css("top",this._pos[1]+"px");inst.settings.onSelect=onSelect;this._inDialog=true;this.dpDiv.addClass(this._dialogClass);this._showDatepicker(this._dialogInput[0]);if($.blockUI){$.blockUI(this.dpDiv)}$.data(this._dialogInput[0],PROP_NAME,inst);return this},_destroyDatepicker:function(target){var $target=$(target);if(!$target.hasClass(this.markerClassName)){return}var nodeName=target.nodeName.toLowerCase();$.removeData(target,PROP_NAME);if(nodeName=="input"){$target.siblings("."+this._appendClass).remove().end().siblings("."+this._triggerClass).remove().end().removeClass(this.markerClassName).unbind("focus",this._showDatepicker).unbind("keydown",this._doKeyDown).unbind("keypress",this._doKeyPress)}else{if(nodeName=="div"||nodeName=="span"){$target.removeClass(this.markerClassName).empty()}}},_enableDatepicker:function(target){var $target=$(target);if(!$target.hasClass(this.markerClassName)){return}var nodeName=target.nodeName.toLowerCase();if(nodeName=="input"){target.disabled=false;$target.siblings("button."+this._triggerClass).each(function(){this.disabled=false}).end().siblings("img."+this._triggerClass).css({opacity:"1.0",cursor:""})}else{if(nodeName=="div"||nodeName=="span"){var inline=$target.children("."+this._inlineClass);inline.children().removeClass("ui-state-disabled")}}this._disabledInputs=$.map(this._disabledInputs,function(value){return(value==target?null:value)})},_disableDatepicker:function(target){var $target=$(target);if(!$target.hasClass(this.markerClassName)){return}var nodeName=target.nodeName.toLowerCase();if(nodeName=="input"){target.disabled=true;$target.siblings("button."+this._triggerClass).each(function(){this.disabled=true}).end().siblings("img."+this._triggerClass).css({opacity:"0.5",cursor:"default"})}else{if(nodeName=="div"||nodeName=="span"){var inline=$target.children("."+this._inlineClass);inline.children().addClass("ui-state-disabled")}}this._disabledInputs=$.map(this._disabledInputs,function(value){return(value==target?null:value)});this._disabledInputs[this._disabledInputs.length]=target},_isDisabledDatepicker:function(target){if(!target){return false}for(var i=0;i-1)}},_showDatepicker:function(input){input=input.target||input;if(input.nodeName.toLowerCase()!="input"){input=$("input",input.parentNode)[0]}if($.datepicker._isDisabledDatepicker(input)||$.datepicker._lastInput==input){return}var inst=$.datepicker._getInst(input);var beforeShow=$.datepicker._get(inst,"beforeShow");extendRemove(inst.settings,(beforeShow?beforeShow.apply(input,[input,inst]):{}));$.datepicker._hideDatepicker(null,"");$.datepicker._lastInput=input;$.datepicker._setDateFromField(inst);if($.datepicker._inDialog){input.value=""}if(!$.datepicker._pos){$.datepicker._pos=$.datepicker._findPos(input);$.datepicker._pos[1]+=input.offsetHeight}var isFixed=false;$(input).parents().each(function(){isFixed|=$(this).css("position")=="fixed";return !isFixed});if(isFixed&&$.browser.opera){$.datepicker._pos[0]-=document.documentElement.scrollLeft;$.datepicker._pos[1]-=document.documentElement.scrollTop}var offset={left:$.datepicker._pos[0],top:$.datepicker._pos[1]};$.datepicker._pos=null;inst.rangeStart=null;inst.dpDiv.css({position:"absolute",display:"block",top:"-1000px"});$.datepicker._updateDatepicker(inst);offset=$.datepicker._checkOffset(inst,offset,isFixed);inst.dpDiv.css({position:($.datepicker._inDialog&&$.blockUI?"static":(isFixed?"fixed":"absolute")),display:"none",left:offset.left+"px",top:offset.top+"px"});if(!inst.inline){var showAnim=$.datepicker._get(inst,"showAnim")||"show";var duration=$.datepicker._get(inst,"duration");var postProcess=function(){$.datepicker._datepickerShowing=true;if($.browser.msie&&parseInt($.browser.version,10)<7){$("iframe.ui-datepicker-cover").css({width:inst.dpDiv.width()+4,height:inst.dpDiv.height()+4})}};if($.effects&&$.effects[showAnim]){inst.dpDiv.show(showAnim,$.datepicker._get(inst,"showOptions"),duration,postProcess)}else{inst.dpDiv[showAnim](duration,postProcess)}if(duration==""){postProcess()}if(inst.input[0].type!="hidden"){inst.input[0].focus()}$.datepicker._curInst=inst}},_updateDatepicker:function(inst){var dims={width:inst.dpDiv.width()+4,height:inst.dpDiv.height()+4};var self=this;inst.dpDiv.empty().append(this._generateHTML(inst)).find("iframe.ui-datepicker-cover").css({width:dims.width,height:dims.height}).end().find("button, .ui-datepicker-prev, .ui-datepicker-next, .ui-datepicker-calendar td a").bind("mouseout",function(){$(this).removeClass("ui-state-hover");if(this.className.indexOf("ui-datepicker-prev")!=-1){$(this).removeClass("ui-datepicker-prev-hover")}if(this.className.indexOf("ui-datepicker-next")!=-1){$(this).removeClass("ui-datepicker-next-hover")}}).bind("mouseover",function(){if(!self._isDisabledDatepicker(inst.inline?inst.dpDiv.parent()[0]:inst.input[0])){$(this).parents(".ui-datepicker-calendar").find("a").removeClass("ui-state-hover");$(this).addClass("ui-state-hover");if(this.className.indexOf("ui-datepicker-prev")!=-1){$(this).addClass("ui-datepicker-prev-hover")}if(this.className.indexOf("ui-datepicker-next")!=-1){$(this).addClass("ui-datepicker-next-hover")}}}).end().find("."+this._dayOverClass+" a").trigger("mouseover").end();var numMonths=this._getNumberOfMonths(inst);var cols=numMonths[1];var width=17;if(cols>1){inst.dpDiv.addClass("ui-datepicker-multi-"+cols).css("width",(width*cols)+"em")}else{inst.dpDiv.removeClass("ui-datepicker-multi-2 ui-datepicker-multi-3 ui-datepicker-multi-4").width("")}inst.dpDiv[(numMonths[0]!=1||numMonths[1]!=1?"add":"remove")+"Class"]("ui-datepicker-multi");inst.dpDiv[(this._get(inst,"isRTL")?"add":"remove")+"Class"]("ui-datepicker-rtl");if(inst.input&&inst.input[0].type!="hidden"&&inst==$.datepicker._curInst){$(inst.input[0]).focus()}},_checkOffset:function(inst,offset,isFixed){var dpWidth=inst.dpDiv.outerWidth();var dpHeight=inst.dpDiv.outerHeight();var inputWidth=inst.input?inst.input.outerWidth():0;var inputHeight=inst.input?inst.input.outerHeight():0;var viewWidth=(window.innerWidth||document.documentElement.clientWidth||document.body.clientWidth)+$(document).scrollLeft();var viewHeight=(window.innerHeight||document.documentElement.clientHeight||document.body.clientHeight)+$(document).scrollTop();offset.left-=(this._get(inst,"isRTL")?(dpWidth-inputWidth):0);offset.left-=(isFixed&&offset.left==inst.input.offset().left)?$(document).scrollLeft():0;offset.top-=(isFixed&&offset.top==(inst.input.offset().top+inputHeight))?$(document).scrollTop():0;offset.left-=(offset.left+dpWidth>viewWidth&&viewWidth>dpWidth)?Math.abs(offset.left+dpWidth-viewWidth):0;offset.top-=(offset.top+dpHeight>viewHeight&&viewHeight>dpHeight)?Math.abs(offset.top+dpHeight+inputHeight*2-viewHeight):0;return offset},_findPos:function(obj){while(obj&&(obj.type=="hidden"||obj.nodeType!=1)){obj=obj.nextSibling}var position=$(obj).offset();return[position.left,position.top]},_hideDatepicker:function(input,duration){var inst=this._curInst;if(!inst||(input&&inst!=$.data(input,PROP_NAME))){return}if(inst.stayOpen){this._selectDate("#"+inst.id,this._formatDate(inst,inst.currentDay,inst.currentMonth,inst.currentYear))}inst.stayOpen=false;if(this._datepickerShowing){duration=(duration!=null?duration:this._get(inst,"duration"));var showAnim=this._get(inst,"showAnim");var postProcess=function(){$.datepicker._tidyDialog(inst)};if(duration!=""&&$.effects&&$.effects[showAnim]){inst.dpDiv.hide(showAnim,$.datepicker._get(inst,"showOptions"),duration,postProcess)}else{inst.dpDiv[(duration==""?"hide":(showAnim=="slideDown"?"slideUp":(showAnim=="fadeIn"?"fadeOut":"hide")))](duration,postProcess)}if(duration==""){this._tidyDialog(inst)}var onClose=this._get(inst,"onClose");if(onClose){onClose.apply((inst.input?inst.input[0]:null),[(inst.input?inst.input.val():""),inst])}this._datepickerShowing=false;this._lastInput=null;if(this._inDialog){this._dialogInput.css({position:"absolute",left:"0",top:"-100px"});if($.blockUI){$.unblockUI();$("body").append(this.dpDiv)}}this._inDialog=false}this._curInst=null},_tidyDialog:function(inst){inst.dpDiv.removeClass(this._dialogClass).unbind(".ui-datepicker-calendar")},_checkExternalClick:function(event){if(!$.datepicker._curInst){return}var $target=$(event.target);if(($target.parents("#"+$.datepicker._mainDivId).length==0)&&!$target.hasClass($.datepicker.markerClassName)&&!$target.hasClass($.datepicker._triggerClass)&&$.datepicker._datepickerShowing&&!($.datepicker._inDialog&&$.blockUI)){$.datepicker._hideDatepicker(null,"")}},_adjustDate:function(id,offset,period){var target=$(id);var inst=this._getInst(target[0]);if(this._isDisabledDatepicker(target[0])){return}this._adjustInstDate(inst,offset+(period=="M"?this._get(inst,"showCurrentAtPos"):0),period);this._updateDatepicker(inst)},_gotoToday:function(id){var target=$(id);var inst=this._getInst(target[0]);if(this._get(inst,"gotoCurrent")&&inst.currentDay){inst.selectedDay=inst.currentDay;inst.drawMonth=inst.selectedMonth=inst.currentMonth;inst.drawYear=inst.selectedYear=inst.currentYear}else{var date=new Date();inst.selectedDay=date.getDate();inst.drawMonth=inst.selectedMonth=date.getMonth();inst.drawYear=inst.selectedYear=date.getFullYear()}this._notifyChange(inst);this._adjustDate(target)},_selectMonthYear:function(id,select,period){var target=$(id);var inst=this._getInst(target[0]);inst._selectingMonthYear=false;inst["selected"+(period=="M"?"Month":"Year")]=inst["draw"+(period=="M"?"Month":"Year")]=parseInt(select.options[select.selectedIndex].value,10);this._notifyChange(inst);this._adjustDate(target)},_clickMonthYear:function(id){var target=$(id);var inst=this._getInst(target[0]);if(inst.input&&inst._selectingMonthYear&&!$.browser.msie){inst.input[0].focus()}inst._selectingMonthYear=!inst._selectingMonthYear},_selectDay:function(id,month,year,td){var target=$(id);if($(td).hasClass(this._unselectableClass)||this._isDisabledDatepicker(target[0])){return}var inst=this._getInst(target[0]);inst.selectedDay=inst.currentDay=$("a",td).html();inst.selectedMonth=inst.currentMonth=month;inst.selectedYear=inst.currentYear=year;if(inst.stayOpen){inst.endDay=inst.endMonth=inst.endYear=null}this._selectDate(id,this._formatDate(inst,inst.currentDay,inst.currentMonth,inst.currentYear));if(inst.stayOpen){inst.rangeStart=this._daylightSavingAdjust(new Date(inst.currentYear,inst.currentMonth,inst.currentDay));this._updateDatepicker(inst)}},_clearDate:function(id){var target=$(id);var inst=this._getInst(target[0]);inst.stayOpen=false;inst.endDay=inst.endMonth=inst.endYear=inst.rangeStart=null;this._selectDate(target,"")},_selectDate:function(id,dateStr){var target=$(id);var inst=this._getInst(target[0]);dateStr=(dateStr!=null?dateStr:this._formatDate(inst));if(inst.input){inst.input.val(dateStr)}this._updateAlternate(inst);var onSelect=this._get(inst,"onSelect");if(onSelect){onSelect.apply((inst.input?inst.input[0]:null),[dateStr,inst])}else{if(inst.input){inst.input.trigger("change")}}if(inst.inline){this._updateDatepicker(inst)}else{if(!inst.stayOpen){this._hideDatepicker(null,this._get(inst,"duration"));this._lastInput=inst.input[0];if(typeof(inst.input[0])!="object"){inst.input[0].focus()}this._lastInput=null}}},_updateAlternate:function(inst){var altField=this._get(inst,"altField");if(altField){var altFormat=this._get(inst,"altFormat")||this._get(inst,"dateFormat");var date=this._getDate(inst);dateStr=this.formatDate(altFormat,date,this._getFormatConfig(inst));$(altField).each(function(){$(this).val(dateStr)})}},noWeekends:function(date){var day=date.getDay();return[(day>0&&day<6),""]},iso8601Week:function(date){var checkDate=new Date(date.getFullYear(),date.getMonth(),date.getDate());var firstMon=new Date(checkDate.getFullYear(),1-1,4);var firstDay=firstMon.getDay()||7;firstMon.setDate(firstMon.getDate()+1-firstDay);if(firstDay<4&&checkDatenew Date(checkDate.getFullYear(),12-1,28)){firstDay=new Date(checkDate.getFullYear()+1,1-1,4).getDay()||7;if(firstDay>4&&(checkDate.getDay()||7)0&&iValue="0"&&value.charAt(iValue)<="9"){num=num*10+parseInt(value.charAt(iValue++),10);size--}if(size==origSize){throw"Missing number at position "+iValue}return num};var getName=function(match,shortNames,longNames){var names=(lookAhead(match)?longNames:shortNames);var size=0;for(var j=0;j0&&iValue-1){month=1;day=doy;do{var dim=this._getDaysInMonth(year,month-1);if(day<=dim){break}month++;day-=dim}while(true)}var date=this._daylightSavingAdjust(new Date(year,month-1,day));if(date.getFullYear()!=year||date.getMonth()+1!=month||date.getDate()!=day){throw"Invalid date"}return date},ATOM:"yy-mm-dd",COOKIE:"D, dd M yy",ISO_8601:"yy-mm-dd",RFC_822:"D, d M y",RFC_850:"DD, dd-M-y",RFC_1036:"D, d M y",RFC_1123:"D, d M yy",RFC_2822:"D, d M yy",RSS:"D, d M y",TIMESTAMP:"@",W3C:"yy-mm-dd",formatDate:function(format,date,settings){if(!date){return""}var dayNamesShort=(settings?settings.dayNamesShort:null)||this._defaults.dayNamesShort;var dayNames=(settings?settings.dayNames:null)||this._defaults.dayNames;var monthNamesShort=(settings?settings.monthNamesShort:null)||this._defaults.monthNamesShort;var monthNames=(settings?settings.monthNames:null)||this._defaults.monthNames;var lookAhead=function(match){var matches=(iFormat+1=0;m--){doy+=this._getDaysInMonth(date.getFullYear(),m)}output+=formatNumber("o",doy,3);break;case"m":output+=formatNumber("m",date.getMonth()+1,2);break;case"M":output+=formatName("M",date.getMonth(),monthNamesShort,monthNames);break;case"y":output+=(lookAhead("y")?date.getFullYear():(date.getYear()%100<10?"0":"")+date.getYear()%100);break;case"@":output+=date.getTime();break;case"'":if(lookAhead("'")){output+="'"}else{literal=true}break;default:output+=format.charAt(iFormat)}}}}return output},_possibleChars:function(format){var chars="";var literal=false;for(var iFormat=0;iFormatmaxDate?maxDate:date);return date},_determineDate:function(date,defaultDate){var offsetNumeric=function(offset){var date=new Date();date.setDate(date.getDate()+offset);return date};var offsetString=function(offset,getDaysInMonth){var date=new Date();var year=date.getFullYear();var month=date.getMonth();var day=date.getDate();var pattern=/([+-]?[0-9]+)\s*(d|D|w|W|m|M|y|Y)?/g;var matches=pattern.exec(offset);while(matches){switch(matches[2]||"d"){case"d":case"D":day+=parseInt(matches[1],10);break;case"w":case"W":day+=parseInt(matches[1],10)*7;break;case"m":case"M":month+=parseInt(matches[1],10);day=Math.min(day,getDaysInMonth(year,month));break;case"y":case"Y":year+=parseInt(matches[1],10);day=Math.min(day,getDaysInMonth(year,month));break}matches=pattern.exec(offset)}return new Date(year,month,day)};date=(date==null?defaultDate:(typeof date=="string"?offsetString(date,this._getDaysInMonth):(typeof date=="number"?(isNaN(date)?defaultDate:offsetNumeric(date)):date)));date=(date&&date.toString()=="Invalid Date"?defaultDate:date);if(date){date.setHours(0);date.setMinutes(0);date.setSeconds(0);date.setMilliseconds(0)}return this._daylightSavingAdjust(date)},_daylightSavingAdjust:function(date){if(!date){return null}date.setHours(date.getHours()>12?date.getHours()+2:0);return date},_setDate:function(inst,date,endDate){var clear=!(date);var origMonth=inst.selectedMonth;var origYear=inst.selectedYear;date=this._determineDate(date,new Date());inst.selectedDay=inst.currentDay=date.getDate();inst.drawMonth=inst.selectedMonth=inst.currentMonth=date.getMonth();inst.drawYear=inst.selectedYear=inst.currentYear=date.getFullYear();if(origMonth!=inst.selectedMonth||origYear!=inst.selectedYear){this._notifyChange(inst)}this._adjustInstDate(inst);if(inst.input){inst.input.val(clear?"":this._formatDate(inst))}},_getDate:function(inst){var startDate=(!inst.currentYear||(inst.input&&inst.input.val()=="")?null:this._daylightSavingAdjust(new Date(inst.currentYear,inst.currentMonth,inst.currentDay)));return startDate},_generateHTML:function(inst){var today=new Date();today=this._daylightSavingAdjust(new Date(today.getFullYear(),today.getMonth(),today.getDate()));var isRTL=this._get(inst,"isRTL");var showButtonPanel=this._get(inst,"showButtonPanel");var hideIfNoPrevNext=this._get(inst,"hideIfNoPrevNext");var navigationAsDateFormat=this._get(inst,"navigationAsDateFormat");var numMonths=this._getNumberOfMonths(inst);var showCurrentAtPos=this._get(inst,"showCurrentAtPos");var stepMonths=this._get(inst,"stepMonths");var stepBigMonths=this._get(inst,"stepBigMonths");var isMultiMonth=(numMonths[0]!=1||numMonths[1]!=1);var currentDate=this._daylightSavingAdjust((!inst.currentDay?new Date(9999,9,9):new Date(inst.currentYear,inst.currentMonth,inst.currentDay)));var minDate=this._getMinMaxDate(inst,"min",true);var maxDate=this._getMinMaxDate(inst,"max");var drawMonth=inst.drawMonth-showCurrentAtPos;var drawYear=inst.drawYear;if(drawMonth<0){drawMonth+=12;drawYear--}if(maxDate){var maxDraw=this._daylightSavingAdjust(new Date(maxDate.getFullYear(),maxDate.getMonth()-numMonths[1]+1,maxDate.getDate()));maxDraw=(minDate&&maxDrawmaxDraw){drawMonth--;if(drawMonth<0){drawMonth=11;drawYear--}}}inst.drawMonth=drawMonth;inst.drawYear=drawYear;var prevText=this._get(inst,"prevText");prevText=(!navigationAsDateFormat?prevText:this.formatDate(prevText,this._daylightSavingAdjust(new Date(drawYear,drawMonth-stepMonths,1)),this._getFormatConfig(inst)));var prev=(this._canAdjustMonth(inst,-1,drawYear,drawMonth)?''+prevText+"":(hideIfNoPrevNext?"":''+prevText+""));var nextText=this._get(inst,"nextText");nextText=(!navigationAsDateFormat?nextText:this.formatDate(nextText,this._daylightSavingAdjust(new Date(drawYear,drawMonth+stepMonths,1)),this._getFormatConfig(inst)));var next=(this._canAdjustMonth(inst,+1,drawYear,drawMonth)?''+nextText+"":(hideIfNoPrevNext?"":''+nextText+""));var currentText=this._get(inst,"currentText");var gotoDate=(this._get(inst,"gotoCurrent")&&inst.currentDay?currentDate:today);currentText=(!navigationAsDateFormat?currentText:this.formatDate(currentText,gotoDate,this._getFormatConfig(inst)));var controls='";var buttonPanel=(showButtonPanel)?'
    '+(isRTL?controls:"")+(this._isInRange(inst,gotoDate)?'":"")+(isRTL?"":controls)+"
    ":"";var firstDay=parseInt(this._get(inst,"firstDay"),10);firstDay=(isNaN(firstDay)?0:firstDay);var dayNames=this._get(inst,"dayNames");var dayNamesShort=this._get(inst,"dayNamesShort");var dayNamesMin=this._get(inst,"dayNamesMin");var monthNames=this._get(inst,"monthNames");var monthNamesShort=this._get(inst,"monthNamesShort");var beforeShowDay=this._get(inst,"beforeShowDay");var showOtherMonths=this._get(inst,"showOtherMonths");var calculateWeek=this._get(inst,"calculateWeek")||this.iso8601Week;var endDate=inst.endDay?this._daylightSavingAdjust(new Date(inst.endYear,inst.endMonth,inst.endDay)):currentDate;var defaultDate=this._getDefaultDate(inst);var html="";for(var row=0;row'+(/all|left/.test(cornerClass)&&row==0?(isRTL?next:prev):"")+(/all|right/.test(cornerClass)&&row==0?(isRTL?prev:next):"")+this._generateMonthYearHeader(inst,drawMonth,drawYear,minDate,maxDate,selectedDate,row>0||col>0,monthNames,monthNamesShort)+'';var thead="";for(var dow=0;dow<7;dow++){var day=(dow+firstDay)%7;thead+="=5?' class="ui-datepicker-week-end"':"")+'>'+dayNamesMin[day]+""}calender+=thead+"";var daysInMonth=this._getDaysInMonth(drawYear,drawMonth);if(drawYear==inst.selectedYear&&drawMonth==inst.selectedMonth){inst.selectedDay=Math.min(inst.selectedDay,daysInMonth)}var leadDays=(this._getFirstDayOfMonth(drawYear,drawMonth)-firstDay+7)%7;var numRows=(isMultiMonth?6:Math.ceil((leadDays+daysInMonth)/7));var printDate=this._daylightSavingAdjust(new Date(drawYear,drawMonth,1-leadDays));for(var dRow=0;dRow";var tbody="";for(var dow=0;dow<7;dow++){var daySettings=(beforeShowDay?beforeShowDay.apply((inst.input?inst.input[0]:null),[printDate]):[true,""]);var otherMonth=(printDate.getMonth()!=drawMonth);var unselectable=otherMonth||!daySettings[0]||(minDate&&printDatemaxDate);tbody+='";printDate.setDate(printDate.getDate()+1);printDate=this._daylightSavingAdjust(printDate)}calender+=tbody+""}drawMonth++;if(drawMonth>11){drawMonth=0;drawYear++}calender+="
    =currentDate.getTime()&&printDate.getTime()<=endDate.getTime()?" "+this._currentClass:"")+(printDate.getTime()==today.getTime()?" ui-datepicker-today":""))+'"'+((!otherMonth||showOtherMonths)&&daySettings[2]?' title="'+daySettings[2]+'"':"")+(unselectable?"":" onclick=\"jQuery.datepicker._selectDay('#"+inst.id+"',"+drawMonth+","+drawYear+', this);return false;"')+">"+(otherMonth?(showOtherMonths?printDate.getDate():" "):(unselectable?''+printDate.getDate()+"":'=currentDate.getTime()&&printDate.getTime()<=endDate.getTime()?" ui-state-active":"")+'" href="#">'+printDate.getDate()+""))+"
    "+(isMultiMonth?"":"");group+=calender}html+=group}html+=(!inst.inline?buttonPanel:"")+($.browser.msie&&parseInt($.browser.version,10)<7&&!inst.inline?'':"");inst._keyEvent=false;return html},_generateMonthYearHeader:function(inst,drawMonth,drawYear,minDate,maxDate,selectedDate,secondary,monthNames,monthNamesShort){minDate=(inst.rangeStart&&minDate&&selectedDate "}else{var inMinYear=(minDate&&minDate.getFullYear()==drawYear);var inMaxYear=(maxDate&&maxDate.getFullYear()==drawYear);monthHtml+='"}if(!showMonthAfterYear){html+=monthHtml+((secondary||changeMonth||changeYear)&&(!(changeMonth&&changeYear))?" ":"")}if(secondary||!changeYear){html+=''+drawYear+""}else{var years=this._get(inst,"yearRange").split(":");var year=0;var endYear=0;if(years.length!=2){year=drawYear-10;endYear=drawYear+10}else{if(years[0].charAt(0)=="+"||years[0].charAt(0)=="-"){year=drawYear+parseInt(years[0],10);endYear=drawYear+parseInt(years[1],10)}else{year=parseInt(years[0],10);endYear=parseInt(years[1],10)}}year=(minDate?Math.max(year,minDate.getFullYear()):year);endYear=(maxDate?Math.min(endYear,maxDate.getFullYear()):endYear);html+='"}if(showMonthAfterYear){html+=(secondary||changeMonth||changeYear?" ":"")+monthHtml}html+="";return html},_adjustInstDate:function(inst,offset,period){var year=inst.drawYear+(period=="Y"?offset:0);var month=inst.drawMonth+(period=="M"?offset:0);var day=Math.min(inst.selectedDay,this._getDaysInMonth(year,month))+(period=="D"?offset:0);var date=this._daylightSavingAdjust(new Date(year,month,day));var minDate=this._getMinMaxDate(inst,"min",true);var maxDate=this._getMinMaxDate(inst,"max");date=(minDate&&datemaxDate?maxDate:date);inst.selectedDay=date.getDate();inst.drawMonth=inst.selectedMonth=date.getMonth();inst.drawYear=inst.selectedYear=date.getFullYear();if(period=="M"||period=="Y"){this._notifyChange(inst)}},_notifyChange:function(inst){var onChange=this._get(inst,"onChangeMonthYear");if(onChange){onChange.apply((inst.input?inst.input[0]:null),[inst.selectedYear,inst.selectedMonth+1,inst])}},_getNumberOfMonths:function(inst){var numMonths=this._get(inst,"numberOfMonths");return(numMonths==null?[1,1]:(typeof numMonths=="number"?[1,numMonths]:numMonths))},_getMinMaxDate:function(inst,minMax,checkRange){var date=this._determineDate(this._get(inst,minMax+"Date"),null);return(!checkRange||!inst.rangeStart?date:(!date||inst.rangeStart>date?inst.rangeStart:date))},_getDaysInMonth:function(year,month){return 32-new Date(year,month,32).getDate()},_getFirstDayOfMonth:function(year,month){return new Date(year,month,1).getDay()},_canAdjustMonth:function(inst,offset,curYear,curMonth){var numMonths=this._getNumberOfMonths(inst);var date=this._daylightSavingAdjust(new Date(curYear,curMonth+(offset<0?offset:numMonths[1]),1));if(offset<0){date.setDate(this._getDaysInMonth(date.getFullYear(),date.getMonth()))}return this._isInRange(inst,date)},_isInRange:function(inst,date){var newMinDate=(!inst.rangeStart?null:this._daylightSavingAdjust(new Date(inst.selectedYear,inst.selectedMonth,inst.selectedDay)));newMinDate=(newMinDate&&inst.rangeStart=minDate)&&(!maxDate||date<=maxDate))},_getFormatConfig:function(inst){var shortYearCutoff=this._get(inst,"shortYearCutoff");shortYearCutoff=(typeof shortYearCutoff!="string"?shortYearCutoff:new Date().getFullYear()%100+parseInt(shortYearCutoff,10));return{shortYearCutoff:shortYearCutoff,dayNamesShort:this._get(inst,"dayNamesShort"),dayNames:this._get(inst,"dayNames"),monthNamesShort:this._get(inst,"monthNamesShort"),monthNames:this._get(inst,"monthNames")}},_formatDate:function(inst,day,month,year){if(!day){inst.currentDay=inst.selectedDay;inst.currentMonth=inst.selectedMonth;inst.currentYear=inst.selectedYear}var date=(day?(typeof day=="object"?day:this._daylightSavingAdjust(new Date(year,month,day))):this._daylightSavingAdjust(new Date(inst.currentYear,inst.currentMonth,inst.currentDay)));return this.formatDate(this._get(inst,"dateFormat"),date,this._getFormatConfig(inst))}});function extendRemove(target,props){$.extend(target,props);for(var name in props){if(props[name]==null||props[name]==undefined){target[name]=props[name]}}return target}function isArray(a){return(a&&(($.browser.safari&&typeof a=="object"&&a.length)||(a.constructor&&a.constructor.toString().match(/\Array\(\)/))))}$.fn.datepicker=function(options){if(!$.datepicker.initialized){$(document).mousedown($.datepicker._checkExternalClick).find("body").append($.datepicker.dpDiv);$.datepicker.initialized=true}var otherArgs=Array.prototype.slice.call(arguments,1);if(typeof options=="string"&&(options=="isDisabled"||options=="getDate")){return $.datepicker["_"+options+"Datepicker"].apply($.datepicker,[this[0]].concat(otherArgs))}return this.each(function(){typeof options=="string"?$.datepicker["_"+options+"Datepicker"].apply($.datepicker,[this].concat(otherArgs)):$.datepicker._attachDatepicker(this,options)})};$.datepicker=new Datepicker();$.datepicker.initialized=false;$.datepicker.uuid=new Date().getTime();$.datepicker.version="1.6rc6"})(jQuery);/* + * jQuery UI Progressbar 1.6rc6 + * + * Copyright (c) 2009 AUTHORS.txt (http://ui.jquery.com/about) + * Dual licensed under the MIT (MIT-LICENSE.txt) + * and GPL (GPL-LICENSE.txt) licenses. + * + * http://docs.jquery.com/UI/Progressbar + * + * Depends: + * ui.core.js + */ +(function(a){a.widget("ui.progressbar",{_init:function(){var b=this,c=this.options;this.element.addClass("ui-progressbar ui-widget ui-widget-content ui-corner-all").attr({role:"progressbar","aria-valuemin":this._valueMin(),"aria-valuemax":this._valueMax(),"aria-valuenow":this._value()});this.valueDiv=a('
    ').appendTo(this.element);this._refreshValue()},destroy:function(){this.element.removeClass("ui-progressbar ui-widget ui-widget-content ui-corner-all").removeAttr("role").removeAttr("aria-valuemin").removeAttr("aria-valuemax").removeAttr("aria-valuenow").removeData("progressbar").unbind(".progressbar");this.valueDiv.remove();a.widget.prototype.destroy.apply(this,arguments)},value:function(b){arguments.length&&this._setData("value",b);return this._value()},_setData:function(b,c){switch(b){case"value":this.options.value=c;this._refreshValue();this._trigger("change",null,{});break}a.widget.prototype._setData.apply(this,arguments)},_value:function(){var b=this.options.value;if(bthis._valueMax()){b=this._valueMax()}return b},_valueMin:function(){var b=0;return b},_valueMax:function(){var b=100;return b},_refreshValue:function(){var b=this.value();this.valueDiv[b==this._valueMax()?"addClass":"removeClass"]("ui-corner-right");this.valueDiv.width(b+"%");this.element.attr("aria-valuenow",b)}});a.extend(a.ui.progressbar,{version:"1.6rc6",defaults:{value:0}})})(jQuery);/* + * jQuery UI Effects 1.6rc6 + * + * Copyright (c) 2009 AUTHORS.txt (http://ui.jquery.com/about) + * Dual licensed under the MIT (MIT-LICENSE.txt) + * and GPL (GPL-LICENSE.txt) licenses. + * + * http://docs.jquery.com/UI/Effects/ + */ +(function(d){d.effects=d.effects||{};d.extend(d.effects,{version:"1.6rc6",save:function(g,h){for(var f=0;f');var j=f.parent();if(f.css("position")=="static"){j.css({position:"relative"});f.css({position:"relative"})}else{var i=f.css("top");if(isNaN(parseInt(i,10))){i="auto"}var h=f.css("left");if(isNaN(parseInt(h,10))){h="auto"}j.css({position:f.css("position"),top:i,left:h,zIndex:f.css("z-index")}).show();f.css({position:"relative",top:0,left:0})}j.css(g);return j},removeWrapper:function(f){if(f.parent().is(".ui-effects-wrapper")){return f.parent().replaceWith(f)}return f},setTransition:function(g,i,f,h){h=h||{};d.each(i,function(k,j){unit=g.cssUnit(j);if(unit[0]>0){h[j]=unit[0]*f+unit[1]}});return h},animateClass:function(h,i,k,j){var f=(typeof k=="function"?k:(j?j:null));var g=(typeof k=="string"?k:null);return this.each(function(){var q={};var o=d(this);var p=o.attr("style")||"";if(typeof p=="object"){p=p.cssText}if(h.toggle){o.hasClass(h.toggle)?h.remove=h.toggle:h.add=h.toggle}var l=d.extend({},(document.defaultView?document.defaultView.getComputedStyle(this,null):this.currentStyle));if(h.add){o.addClass(h.add)}if(h.remove){o.removeClass(h.remove)}var m=d.extend({},(document.defaultView?document.defaultView.getComputedStyle(this,null):this.currentStyle));if(h.add){o.removeClass(h.add)}if(h.remove){o.addClass(h.remove)}for(var r in m){if(typeof m[r]!="function"&&m[r]&&r.indexOf("Moz")==-1&&r.indexOf("length")==-1&&m[r]!=l[r]&&(r.match(/color/i)||(!r.match(/color/i)&&!isNaN(parseInt(m[r],10))))&&(l.position!="static"||(l.position=="static"&&!r.match(/left|top|bottom|right/)))){q[r]=m[r]}}o.animate(q,i,g,function(){if(typeof d(this).attr("style")=="object"){d(this).attr("style")["cssText"]="";d(this).attr("style")["cssText"]=p}else{d(this).attr("style",p)}if(h.add){d(this).addClass(h.add)}if(h.remove){d(this).removeClass(h.remove)}if(f){f.apply(this,arguments)}})})}});function c(g,f){var i=g[1]&&g[1].constructor==Object?g[1]:{};if(f){i.mode=f}var h=g[1]&&g[1].constructor!=Object?g[1]:i.duration;h=d.fx.off?0:typeof h==="number"?h:d.fx.speeds[h]||d.fx.speeds._default;var j=i.callback||(d.isFunction(g[2])&&g[2])||(d.isFunction(g[3])&&g[3]);return[g[0],i,h,j]}d.fn.extend({_show:d.fn.show,_hide:d.fn.hide,__toggle:d.fn.toggle,_addClass:d.fn.addClass,_removeClass:d.fn.removeClass,_toggleClass:d.fn.toggleClass,effect:function(g,f,h,i){return d.effects[g]?d.effects[g].call(this,{method:g,options:f||{},duration:h,callback:i}):null},show:function(){if(!arguments[0]||(arguments[0].constructor==Number||(/(slow|normal|fast)/).test(arguments[0]))){return this._show.apply(this,arguments)}else{return this.effect.apply(this,c(arguments,"show"))}},hide:function(){if(!arguments[0]||(arguments[0].constructor==Number||(/(slow|normal|fast)/).test(arguments[0]))){return this._hide.apply(this,arguments)}else{return this.effect.apply(this,c(arguments,"hide"))}},toggle:function(){if(!arguments[0]||(arguments[0].constructor==Number||(/(slow|normal|fast)/).test(arguments[0]))||(arguments[0].constructor==Function)){return this.__toggle.apply(this,arguments)}else{return this.effect.apply(this,c(arguments,"toggle"))}},addClass:function(g,f,i,h){return f?d.effects.animateClass.apply(this,[{add:g},f,i,h]):this._addClass(g)},removeClass:function(g,f,i,h){return f?d.effects.animateClass.apply(this,[{remove:g},f,i,h]):this._removeClass(g)},toggleClass:function(g,f,i,h){return((typeof f!=="boolean")&&f)?d.effects.animateClass.apply(this,[{toggle:g},f,i,h]):this._toggleClass(g,f)},morph:function(f,h,g,j,i){return d.effects.animateClass.apply(this,[{add:h,remove:f},g,j,i])},switchClass:function(){return this.morph.apply(this,arguments)},cssUnit:function(f){var g=this.css(f),h=[];d.each(["em","px","%","pt"],function(j,k){if(g.indexOf(k)>0){h=[parseFloat(g),k]}});return h}});d.each(["backgroundColor","borderBottomColor","borderLeftColor","borderRightColor","borderTopColor","color","outlineColor"],function(g,f){d.fx.step[f]=function(h){if(h.state==0){h.start=e(h.elem,f);h.end=b(h.end)}h.elem.style[f]="rgb("+[Math.max(Math.min(parseInt((h.pos*(h.end[0]-h.start[0]))+h.start[0],10),255),0),Math.max(Math.min(parseInt((h.pos*(h.end[1]-h.start[1]))+h.start[1],10),255),0),Math.max(Math.min(parseInt((h.pos*(h.end[2]-h.start[2]))+h.start[2],10),255),0)].join(",")+")"}});function b(g){var f;if(g&&g.constructor==Array&&g.length==3){return g}if(f=/rgb\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*\)/.exec(g)){return[parseInt(f[1],10),parseInt(f[2],10),parseInt(f[3],10)]}if(f=/rgb\(\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*\)/.exec(g)){return[parseFloat(f[1])*2.55,parseFloat(f[2])*2.55,parseFloat(f[3])*2.55]}if(f=/#([a-fA-F0-9]{2})([a-fA-F0-9]{2})([a-fA-F0-9]{2})/.exec(g)){return[parseInt(f[1],16),parseInt(f[2],16),parseInt(f[3],16)]}if(f=/#([a-fA-F0-9])([a-fA-F0-9])([a-fA-F0-9])/.exec(g)){return[parseInt(f[1]+f[1],16),parseInt(f[2]+f[2],16),parseInt(f[3]+f[3],16)]}if(f=/rgba\(0, 0, 0, 0\)/.exec(g)){return a.transparent}return a[d.trim(g).toLowerCase()]}function e(h,f){var g;do{g=d.curCSS(h,f);if(g!=""&&g!="transparent"||d.nodeName(h,"body")){break}f="backgroundColor"}while(h=h.parentNode);return b(g)}var a={aqua:[0,255,255],azure:[240,255,255],beige:[245,245,220],black:[0,0,0],blue:[0,0,255],brown:[165,42,42],cyan:[0,255,255],darkblue:[0,0,139],darkcyan:[0,139,139],darkgrey:[169,169,169],darkgreen:[0,100,0],darkkhaki:[189,183,107],darkmagenta:[139,0,139],darkolivegreen:[85,107,47],darkorange:[255,140,0],darkorchid:[153,50,204],darkred:[139,0,0],darksalmon:[233,150,122],darkviolet:[148,0,211],fuchsia:[255,0,255],gold:[255,215,0],green:[0,128,0],indigo:[75,0,130],khaki:[240,230,140],lightblue:[173,216,230],lightcyan:[224,255,255],lightgreen:[144,238,144],lightgrey:[211,211,211],lightpink:[255,182,193],lightyellow:[255,255,224],lime:[0,255,0],magenta:[255,0,255],maroon:[128,0,0],navy:[0,0,128],olive:[128,128,0],orange:[255,165,0],pink:[255,192,203],purple:[128,0,128],violet:[128,0,128],red:[255,0,0],silver:[192,192,192],white:[255,255,255],yellow:[255,255,0],transparent:[255,255,255]};d.easing.jswing=d.easing.swing;d.extend(d.easing,{def:"easeOutQuad",swing:function(g,h,f,j,i){return d.easing[d.easing.def](g,h,f,j,i)},easeInQuad:function(g,h,f,j,i){return j*(h/=i)*h+f},easeOutQuad:function(g,h,f,j,i){return -j*(h/=i)*(h-2)+f},easeInOutQuad:function(g,h,f,j,i){if((h/=i/2)<1){return j/2*h*h+f}return -j/2*((--h)*(h-2)-1)+f},easeInCubic:function(g,h,f,j,i){return j*(h/=i)*h*h+f},easeOutCubic:function(g,h,f,j,i){return j*((h=h/i-1)*h*h+1)+f},easeInOutCubic:function(g,h,f,j,i){if((h/=i/2)<1){return j/2*h*h*h+f}return j/2*((h-=2)*h*h+2)+f},easeInQuart:function(g,h,f,j,i){return j*(h/=i)*h*h*h+f},easeOutQuart:function(g,h,f,j,i){return -j*((h=h/i-1)*h*h*h-1)+f},easeInOutQuart:function(g,h,f,j,i){if((h/=i/2)<1){return j/2*h*h*h*h+f}return -j/2*((h-=2)*h*h*h-2)+f},easeInQuint:function(g,h,f,j,i){return j*(h/=i)*h*h*h*h+f},easeOutQuint:function(g,h,f,j,i){return j*((h=h/i-1)*h*h*h*h+1)+f},easeInOutQuint:function(g,h,f,j,i){if((h/=i/2)<1){return j/2*h*h*h*h*h+f}return j/2*((h-=2)*h*h*h*h+2)+f},easeInSine:function(g,h,f,j,i){return -j*Math.cos(h/i*(Math.PI/2))+j+f},easeOutSine:function(g,h,f,j,i){return j*Math.sin(h/i*(Math.PI/2))+f},easeInOutSine:function(g,h,f,j,i){return -j/2*(Math.cos(Math.PI*h/i)-1)+f},easeInExpo:function(g,h,f,j,i){return(h==0)?f:j*Math.pow(2,10*(h/i-1))+f},easeOutExpo:function(g,h,f,j,i){return(h==i)?f+j:j*(-Math.pow(2,-10*h/i)+1)+f},easeInOutExpo:function(g,h,f,j,i){if(h==0){return f}if(h==i){return f+j}if((h/=i/2)<1){return j/2*Math.pow(2,10*(h-1))+f}return j/2*(-Math.pow(2,-10*--h)+2)+f},easeInCirc:function(g,h,f,j,i){return -j*(Math.sqrt(1-(h/=i)*h)-1)+f},easeOutCirc:function(g,h,f,j,i){return j*Math.sqrt(1-(h=h/i-1)*h)+f},easeInOutCirc:function(g,h,f,j,i){if((h/=i/2)<1){return -j/2*(Math.sqrt(1-h*h)-1)+f}return j/2*(Math.sqrt(1-(h-=2)*h)+1)+f},easeInElastic:function(g,i,f,m,l){var j=1.70158;var k=0;var h=m;if(i==0){return f}if((i/=l)==1){return f+m}if(!k){k=l*0.3}if(h").css({position:"absolute",visibility:"visible",left:-d*(g/e),top:-f*(c/k)}).parent().addClass("ui-effects-explode").css({position:"absolute",overflow:"hidden",width:g/e,height:c/k,left:l.left+d*(g/e)+(b.options.mode=="show"?(d-Math.floor(e/2))*(g/e):0),top:l.top+f*(c/k)+(b.options.mode=="show"?(f-Math.floor(k/2))*(c/k):0),opacity:b.options.mode=="show"?0:1}).animate({left:l.left+d*(g/e)+(b.options.mode=="show"?0:(d-Math.floor(e/2))*(g/e)),top:l.top+f*(c/k)+(b.options.mode=="show"?0:(f-Math.floor(k/2))*(c/k)),opacity:b.options.mode=="show"?1:0},b.duration||500)}}setTimeout(function(){b.options.mode=="show"?h.css({visibility:"visible"}):h.css({visibility:"visible"}).hide();if(b.callback){b.callback.apply(h[0])}h.dequeue();a("div.ui-effects-explode").remove()},b.duration||500)})}})(jQuery);/* + * jQuery UI Effects Fold 1.6rc6 + * + * Copyright (c) 2009 AUTHORS.txt (http://ui.jquery.com/about) + * Dual licensed under the MIT (MIT-LICENSE.txt) + * and GPL (GPL-LICENSE.txt) licenses. + * + * http://docs.jquery.com/UI/Effects/Fold + * + * Depends: + * effects.core.js + */ +(function(a){a.effects.fold=function(b){return this.queue(function(){var e=a(this),k=["position","top","left"];var h=a.effects.setMode(e,b.options.mode||"hide");var o=b.options.size||15;var n=!(!b.options.horizFirst);var g=b.duration?b.duration/2:a.fx.speeds._default/2;a.effects.save(e,k);e.show();var d=a.effects.createWrapper(e).css({overflow:"hidden"});var i=((h=="show")!=n);var f=i?["width","height"]:["height","width"];var c=i?[d.width(),d.height()]:[d.height(),d.width()];var j=/([0-9]+)%/.exec(o);if(j){o=parseInt(j[1])/100*c[h=="hide"?0:1]}if(h=="show"){d.css(n?{height:0,width:o}:{height:o,width:0})}var m={},l={};m[f[0]]=h=="show"?c[0]:o;l[f[1]]=h=="show"?c[1]:0;d.animate(m,g,b.options.easing).animate(l,g,b.options.easing,function(){if(h=="hide"){e.hide()}a.effects.restore(e,k);a.effects.removeWrapper(e);if(b.callback){b.callback.apply(e[0],arguments)}e.dequeue()})})}})(jQuery);/* + * jQuery UI Effects Highlight 1.6rc6 + * + * Copyright (c) 2009 AUTHORS.txt (http://ui.jquery.com/about) + * Dual licensed under the MIT (MIT-LICENSE.txt) + * and GPL (GPL-LICENSE.txt) licenses. + * + * http://docs.jquery.com/UI/Effects/Highlight + * + * Depends: + * effects.core.js + */ +(function(a){a.effects.highlight=function(b){return this.queue(function(){var e=a(this),d=["backgroundImage","backgroundColor","opacity"];var h=a.effects.setMode(e,b.options.mode||"show");var c=b.options.color||"#ffff99";var g=e.css("backgroundColor");a.effects.save(e,d);e.show();e.css({backgroundImage:"none",backgroundColor:c});var f={backgroundColor:g};if(h=="hide"){f.opacity=0}e.animate(f,{queue:false,duration:b.duration,easing:b.options.easing,complete:function(){if(h=="hide"){e.hide()}a.effects.restore(e,d);if(h=="show"&&a.browser.msie){this.style.removeAttribute("filter")}if(b.callback){b.callback.apply(this,arguments)}e.dequeue()}})})}})(jQuery);/* + * jQuery UI Effects Pulsate 1.6rc6 + * + * Copyright (c) 2009 AUTHORS.txt (http://ui.jquery.com/about) + * Dual licensed under the MIT (MIT-LICENSE.txt) + * and GPL (GPL-LICENSE.txt) licenses. + * + * http://docs.jquery.com/UI/Effects/Pulsate + * + * Depends: + * effects.core.js + */ +(function(a){a.effects.pulsate=function(b){return this.queue(function(){var d=a(this);var g=a.effects.setMode(d,b.options.mode||"show");var f=b.options.times||5;var e=b.duration?b.duration/2:a.fx.speeds._default/2;if(g=="hide"){f--}if(d.is(":hidden")){d.css("opacity",0);d.show();d.animate({opacity:1},e,b.options.easing);f=f-2}for(var c=0;c').appendTo(document.body);if(b.options.className){d.addClass(b.options.className)}d.addClass(b.options.className);d.css({top:c.top,left:c.left,height:e.outerHeight()-parseInt(d.css("borderTopWidth"))-parseInt(d.css("borderBottomWidth")),width:e.outerWidth()-parseInt(d.css("borderLeftWidth"))-parseInt(d.css("borderRightWidth")),position:"absolute"});c=f.offset();animation={top:c.top,left:c.left,height:f.outerHeight()-parseInt(d.css("borderTopWidth"))-parseInt(d.css("borderBottomWidth")),width:f.outerWidth()-parseInt(d.css("borderLeftWidth"))-parseInt(d.css("borderRightWidth"))};d.animate(animation,b.duration,b.options.easing,function(){d.remove();if(b.callback){b.callback.apply(e[0],arguments)}e.dequeue()})})}})(jQuery); \ No newline at end of file diff --git a/code/ryzom/tools/server/www/webtt/app/tmp/cache/models/empty b/code/ryzom/tools/server/www/webtt/app/webroot/testfiles/raw_testfile.csv old mode 100755 new mode 100644 similarity index 100% rename from code/ryzom/tools/server/www/webtt/app/tmp/cache/models/empty rename to code/ryzom/tools/server/www/webtt/app/webroot/testfiles/raw_testfile.csv diff --git a/code/ryzom/tools/server/www/webtt/app/webroot/testfiles/testdir/ugatestindir.csv b/code/ryzom/tools/server/www/webtt/app/webroot/testfiles/testdir/ugatestindir.csv new file mode 100644 index 000000000..a65b80e40 --- /dev/null +++ b/code/ryzom/tools/server/www/webtt/app/webroot/testfiles/testdir/ugatestindir.csv @@ -0,0 +1,6 @@ +fdg +dfg +dfg +sd +fgsd +gsd diff --git a/code/ryzom/tools/server/www/webtt/app/tmp/cache/persistent/empty b/code/ryzom/tools/server/www/webtt/app/webroot/testfiles/ugabla.csv similarity index 100% rename from code/ryzom/tools/server/www/webtt/app/tmp/cache/persistent/empty rename to code/ryzom/tools/server/www/webtt/app/webroot/testfiles/ugabla.csv diff --git a/code/ryzom/tools/server/www/webtt/cake/dispatcher.php b/code/ryzom/tools/server/www/webtt/cake/dispatcher.php index 4cf709f19..d1e79c4d3 100644 --- a/code/ryzom/tools/server/www/webtt/cake/dispatcher.php +++ b/code/ryzom/tools/server/www/webtt/cake/dispatcher.php @@ -265,7 +265,7 @@ class Dispatcher extends Object { extract($namedExpressions); include CONFIGS . 'routes.php'; $params = array_merge(array('controller' => '', 'action' => ''), Router::parse($fromUrl), $params); - + if (empty($params['action'])) { $params['action'] = 'index'; } @@ -507,6 +507,7 @@ class Dispatcher extends Object { } } else { $url = $_GET['url']; + } if ($url{0} == '/') { $url = substr($url, 1); diff --git a/code/ryzom/tools/server/www/webtt/cake/libs/controller/controller.php b/code/ryzom/tools/server/www/webtt/cake/libs/controller/controller.php index f7dc039f7..d0cad823b 100644 --- a/code/ryzom/tools/server/www/webtt/cake/libs/controller/controller.php +++ b/code/ryzom/tools/server/www/webtt/cake/libs/controller/controller.php @@ -1202,6 +1202,7 @@ class Controller extends Object { $parameters['recursive'] = $recursive; } $count = $object->find('count', array_merge($parameters, $extra)); +// var_dump(array_merge($parameters, $extra)); } $pageCount = intval(ceil($count / $limit)); diff --git a/code/ryzom/tools/server/www/webtt/cake/libs/model/datasources/dbo_source.php.bak b/code/ryzom/tools/server/www/webtt/cake/libs/model/datasources/dbo_source.php.bak new file mode 100755 index 000000000..a851123e9 --- /dev/null +++ b/code/ryzom/tools/server/www/webtt/cake/libs/model/datasources/dbo_source.php.bak @@ -0,0 +1,2925 @@ + 'primary', 'MUL' => 'index', 'UNI' => 'unique'); + +/** + * Database keyword used to assign aliases to identifiers. + * + * @var string + * @access public + */ + var $alias = 'AS '; + +/** + * Caches result from query parsing operations. Cached results for both DboSource::name() and + * DboSource::conditions() will be stored here. Method caching uses `crc32()` which is + * fast but can collisions more easily than other hashing algorithms. If you have problems + * with collisions, set DboSource::$cacheMethods to false. + * + * @var array + * @access public + */ + var $methodCache = array(); + +/** + * Whether or not to cache the results of DboSource::name() and DboSource::conditions() + * into the memory cache. Set to false to disable the use of the memory cache. + * + * @var boolean. + * @access public + */ + var $cacheMethods = true ; + +/** + * Bypass automatic adding of joined fields/associations. + * + * @var boolean + * @access private + */ + var $__bypass = false; + +/** + * The set of valid SQL operations usable in a WHERE statement + * + * @var array + * @access private + */ + var $__sqlOps = array('like', 'ilike', 'or', 'not', 'in', 'between', 'regexp', 'similar to'); + +/** + * Index of basic SQL commands + * + * @var array + * @access protected + */ + var $_commands = array( + 'begin' => 'BEGIN', + 'commit' => 'COMMIT', + 'rollback' => 'ROLLBACK' + ); + +/** + * Separator string for virtualField composition + * + * @var string + */ + var $virtualFieldSeparator = '__'; + +/** + * List of table engine specific parameters used on table creating + * + * @var array + * @access public + */ + var $tableParameters = array(); + +/** + * List of engine specific additional field parameters used on table creating + * + * @var array + * @access public + */ + var $fieldParameters = array(); + +/** + * Constructor + * + * @param array $config Array of configuration information for the Datasource. + * @param boolean $autoConnect Whether or not the datasource should automatically connect. + * @access public + */ + function __construct($config = null, $autoConnect = true) { + if (!isset($config['prefix'])) { + $config['prefix'] = ''; + } + parent::__construct($config); + $this->fullDebug = Configure::read() > 1; + if (!$this->enabled()) { + return false; + } + if ($autoConnect) { + return $this->connect(); + } else { + return true; + } + } + +/** + * Reconnects to database server with optional new settings + * + * @param array $config An array defining the new configuration settings + * @return boolean True on success, false on failure + * @access public + */ + function reconnect($config = array()) { + $this->disconnect(); + $this->setConfig($config); + $this->_sources = null; + + return $this->connect(); + } + +/** + * Prepares a value, or an array of values for database queries by quoting and escaping them. + * + * @param mixed $data A value or an array of values to prepare. + * @param string $column The column into which this data will be inserted + * @param boolean $read Value to be used in READ or WRITE context + * @return mixed Prepared value or array of values. + * @access public + */ + function value($data, $column = null, $read = true) { + if (is_array($data) && !empty($data)) { + return array_map( + array(&$this, 'value'), + $data, array_fill(0, count($data), $column), array_fill(0, count($data), $read) + ); + } elseif (is_object($data) && isset($data->type)) { + if ($data->type == 'identifier') { + return $this->name($data->value); + } elseif ($data->type == 'expression') { + return $data->value; + } + } elseif (in_array($data, array('{$__cakeID__$}', '{$__cakeForeignKey__$}'), true)) { + return $data; + } else { + return null; + } + } + +/** + * Returns an object to represent a database identifier in a query + * + * @param string $identifier + * @return object An object representing a database identifier to be used in a query + * @access public + */ + function identifier($identifier) { + $obj = new stdClass(); + $obj->type = 'identifier'; + $obj->value = $identifier; + return $obj; + } + +/** + * Returns an object to represent a database expression in a query + * + * @param string $expression + * @return object An object representing a database expression to be used in a query + * @access public + */ + function expression($expression) { + $obj = new stdClass(); + $obj->type = 'expression'; + $obj->value = $expression; + return $obj; + } + +/** + * Executes given SQL statement. + * + * @param string $sql SQL statement + * @return boolean + * @access public + */ + function rawQuery($sql) { + $this->took = $this->error = $this->numRows = false; + return $this->execute($sql); + } + +/** + * Queries the database with given SQL statement, and obtains some metadata about the result + * (rows affected, timing, any errors, number of rows in resultset). The query is also logged. + * If Configure::read('debug') is set, the log is shown all the time, else it is only shown on errors. + * + * ### Options + * + * - stats - Collect meta data stats for this query. Stats include time take, rows affected, + * any errors, and number of rows returned. Defaults to `true`. + * - log - Whether or not the query should be logged to the memory log. + * + * @param string $sql + * @param array $options + * @return mixed Resource or object representing the result set, or false on failure + * @access public + */ + function execute($sql, $options = array()) { + $defaults = array('stats' => true, 'log' => $this->fullDebug); + $options = array_merge($defaults, $options); + + $t = getMicrotime(); + $this->_result = $this->_execute($sql); + if ($options['stats']) { + $this->took = round((getMicrotime() - $t) * 1000, 0); + $this->affected = $this->lastAffected(); + $this->error = $this->lastError(); + $this->numRows = $this->lastNumRows(); + } + + if ($options['log']) { + $this->logQuery($sql); + } + + if ($this->error) { + $this->showQuery($sql); + return false; + } + return $this->_result; + } + +/** + * DataSource Query abstraction + * + * @return resource Result resource identifier. + * @access public + */ + function query() { + $args = func_get_args(); + $fields = null; + $order = null; + $limit = null; + $page = null; + $recursive = null; + + if (count($args) == 1) { + return $this->fetchAll($args[0]); + + } elseif (count($args) > 1 && (strpos(strtolower($args[0]), 'findby') === 0 || strpos(strtolower($args[0]), 'findallby') === 0)) { + $params = $args[1]; + + if (strpos(strtolower($args[0]), 'findby') === 0) { + $all = false; + $field = Inflector::underscore(preg_replace('/^findBy/i', '', $args[0])); + } else { + $all = true; + $field = Inflector::underscore(preg_replace('/^findAllBy/i', '', $args[0])); + } + + $or = (strpos($field, '_or_') !== false); + if ($or) { + $field = explode('_or_', $field); + } else { + $field = explode('_and_', $field); + } + $off = count($field) - 1; + + if (isset($params[1 + $off])) { + $fields = $params[1 + $off]; + } + + if (isset($params[2 + $off])) { + $order = $params[2 + $off]; + } + + if (!array_key_exists(0, $params)) { + return false; + } + + $c = 0; + $conditions = array(); + + foreach ($field as $f) { + $conditions[$args[2]->alias . '.' . $f] = $params[$c]; + $c++; + } + + if ($or) { + $conditions = array('OR' => $conditions); + } + + if ($all) { + if (isset($params[3 + $off])) { + $limit = $params[3 + $off]; + } + + if (isset($params[4 + $off])) { + $page = $params[4 + $off]; + } + + if (isset($params[5 + $off])) { + $recursive = $params[5 + $off]; + } + return $args[2]->find('all', compact('conditions', 'fields', 'order', 'limit', 'page', 'recursive')); + } else { + if (isset($params[3 + $off])) { + $recursive = $params[3 + $off]; + } + return $args[2]->find('first', compact('conditions', 'fields', 'order', 'recursive')); + } + } else { + if (isset($args[1]) && $args[1] === true) { + return $this->fetchAll($args[0], true); + } else if (isset($args[1]) && !is_array($args[1]) ) { + return $this->fetchAll($args[0], false); + } else if (isset($args[1]) && is_array($args[1])) { + $offset = 0; + if (isset($args[2])) { + $cache = $args[2]; + } else { + $cache = true; + } + $args[1] = array_map(array(&$this, 'value'), $args[1]); + return $this->fetchAll(String::insert($args[0], $args[1]), $cache); + } + } + } + +/** + * Returns a row from current resultset as an array + * + * @return array The fetched row as an array + * @access public + */ + function fetchRow($sql = null) { + if (!empty($sql) && is_string($sql) && strlen($sql) > 5) { + if (!$this->execute($sql)) { + return null; + } + } + + if ($this->hasResult()) { + $this->resultSet($this->_result); + $resultRow = $this->fetchResult(); + if (!empty($resultRow)) { + $this->fetchVirtualField($resultRow); + } + return $resultRow; + } else { + return null; + } + } + +/** + * Returns an array of all result rows for a given SQL query. + * Returns false if no rows matched. + * + * @param string $sql SQL statement + * @param boolean $cache Enables returning/storing cached query results + * @return array Array of resultset rows, or false if no rows matched + * @access public + */ + function fetchAll($sql, $cache = true, $modelName = null) { + if ($cache && isset($this->_queryCache[$sql])) { + if (preg_match('/^\s*select/i', $sql)) { + return $this->_queryCache[$sql]; + } + } + + if ($this->execute($sql)) { + $out = array(); + + $first = $this->fetchRow(); + if ($first != null) { + $out[] = $first; + } + while ($this->hasResult() && $item = $this->fetchResult()) { + $this->fetchVirtualField($item); + $out[] = $item; + } + + if ($cache) { + if (strpos(trim(strtolower($sql)), 'select') !== false) { + $this->_queryCache[$sql] = $out; + } + } + if (empty($out) && is_bool($this->_result)) { + return $this->_result; + } + return $out; + } else { + return false; + } + } + +/** + * Modifies $result array to place virtual fields in model entry where they belongs to + * + * @param array $resut REference to the fetched row + * @return void + */ + function fetchVirtualField(&$result) { + if (isset($result[0]) && is_array($result[0])) { + foreach ($result[0] as $field => $value) { + if (strpos($field, $this->virtualFieldSeparator) === false) { + continue; + } + list($alias, $virtual) = explode($this->virtualFieldSeparator, $field); + + if (!ClassRegistry::isKeySet($alias)) { + return; + } + $model = ClassRegistry::getObject($alias); + if ($model->isVirtualField($virtual)) { + $result[$alias][$virtual] = $value; + unset($result[0][$field]); + } + } + if (empty($result[0])) { + unset($result[0]); + } + } + } + +/** + * Returns a single field of the first of query results for a given SQL query, or false if empty. + * + * @param string $name Name of the field + * @param string $sql SQL query + * @return mixed Value of field read. + * @access public + */ + function field($name, $sql) { + $data = $this->fetchRow($sql); + if (!isset($data[$name]) || empty($data[$name])) { + return false; + } else { + return $data[$name]; + } + } + +/** + * Empties the method caches. + * These caches are used by DboSource::name() and DboSource::conditions() + * + * @return void + */ + function flushMethodCache() { + $this->methodCache = array(); + } + +/** + * Cache a value into the methodCaches. Will respect the value of DboSource::$cacheMethods. + * Will retrieve a value from the cache if $value is null. + * + * If caching is disabled and a write is attempted, the $value will be returned. + * A read will either return the value or null. + * + * @param string $method Name of the method being cached. + * @param string $key The keyname for the cache operation. + * @param mixed $value The value to cache into memory. + * @return mixed Either null on failure, or the value if its set. + */ + function cacheMethod($method, $key, $value = null) { + if ($this->cacheMethods === false) { + return $value; + } + if ($value === null) { + return (isset($this->methodCache[$method][$key])) ? $this->methodCache[$method][$key] : null; + } + return $this->methodCache[$method][$key] = $value; + } + +/** + * Returns a quoted name of $data for use in an SQL statement. + * Strips fields out of SQL functions before quoting. + * + * Results of this method are stored in a memory cache. This improves performance, but + * because the method uses a simple hashing algorithm it can infrequently have collisions. + * Setting DboSource::$cacheMethods to false will disable the memory cache. + * + * @param mixed $data Either a string with a column to quote. An array of columns to quote or an + * object from DboSource::expression() or DboSource::identifier() + * @return string SQL field + * @access public + */ + function name($data) { + if (is_object($data) && isset($data->type)) { + return $data->value; + } + if ($data === '*') { + return '*'; + } + if (is_array($data)) { + foreach ($data as $i => $dataItem) { + $data[$i] = $this->name($dataItem); + } + return $data; + } + $cacheKey = crc32($this->startQuote.$data.$this->endQuote); + if ($return = $this->cacheMethod(__FUNCTION__, $cacheKey)) { + return $return; + } + $data = trim($data); + if (preg_match('/^[\w-]+(?:\.[^ \*]*)*$/', $data)) { // string, string.string + if (strpos($data, '.') === false) { // string + return $this->cacheMethod(__FUNCTION__, $cacheKey, $this->startQuote . $data . $this->endQuote); + } + $items = explode('.', $data); + return $this->cacheMethod(__FUNCTION__, $cacheKey, + $this->startQuote . implode($this->endQuote . '.' . $this->startQuote, $items) . $this->endQuote + ); + } + if (preg_match('/^[\w-]+\.\*$/', $data)) { // string.* + return $this->cacheMethod(__FUNCTION__, $cacheKey, + $this->startQuote . str_replace('.*', $this->endQuote . '.*', $data) + ); + } + if (preg_match('/^([\w-]+)\((.*)\)$/', $data, $matches)) { // Functions + return $this->cacheMethod(__FUNCTION__, $cacheKey, + $matches[1] . '(' . $this->name($matches[2]) . ')' + ); + } + if ( + preg_match('/^([\w-]+(\.[\w-]+|\(.*\))*)\s+' . preg_quote($this->alias) . '\s*([\w-]+)$/i', $data, $matches + )) { + return $this->cacheMethod( + __FUNCTION__, $cacheKey, + preg_replace( + '/\s{2,}/', ' ', $this->name($matches[1]) . ' ' . $this->alias . ' ' . $this->name($matches[3]) + ) + ); + } + if (preg_match('/^[\w-_\s]*[\w-_]+/', $data)) { + return $this->cacheMethod(__FUNCTION__, $cacheKey, $this->startQuote . $data . $this->endQuote); + } + return $this->cacheMethod(__FUNCTION__, $cacheKey, $data); + } + +/** + * Checks if the source is connected to the database. + * + * @return boolean True if the database is connected, else false + * @access public + */ + function isConnected() { + return $this->connected; + } + +/** + * Checks if the result is valid + * + * @return boolean True if the result is valid else false + * @access public + */ + function hasResult() { + return is_resource($this->_result); + } + +/** + * Get the query log as an array. + * + * @param boolean $sorted Get the queries sorted by time taken, defaults to false. + * @return array Array of queries run as an array + * @access public + */ + function getLog($sorted = false, $clear = true) { + if ($sorted) { + $log = sortByKey($this->_queriesLog, 'took', 'desc', SORT_NUMERIC); + } else { + $log = $this->_queriesLog; + } + if ($clear) { + $this->_queriesLog = array(); + } + return array('log' => $log, 'count' => $this->_queriesCnt, 'time' => $this->_queriesTime); + } + +/** + * Outputs the contents of the queries log. If in a non-CLI environment the sql_log element + * will be rendered and output. If in a CLI environment, a plain text log is generated. + * + * @param boolean $sorted Get the queries sorted by time taken, defaults to false. + * @return void + */ + function showLog($sorted = false) { + $log = $this->getLog($sorted, false); + if (empty($log['log'])) { + return; + } + if (PHP_SAPI != 'cli') { + App::import('Core', 'View'); + $controller = null; + $View =& new View($controller, false); + $View->set('logs', array($this->configKeyName => $log)); + echo $View->element('sql_dump', array('_forced_from_dbo_' => true)); + } else { + foreach ($log['log'] as $k => $i) { + print (($k + 1) . ". {$i['query']} {$i['error']}\n"); + } + } + } + +/** + * Log given SQL query. + * + * @param string $sql SQL statement + * @todo: Add hook to log errors instead of returning false + * @access public + */ + function logQuery($sql) { + $this->_queriesCnt++; + $this->_queriesTime += $this->took; + $this->_queriesLog[] = array( + 'query' => $sql, + 'error' => $this->error, + 'affected' => $this->affected, + 'numRows' => $this->numRows, + 'took' => $this->took + ); + if (count($this->_queriesLog) > $this->_queriesLogMax) { + array_pop($this->_queriesLog); + } + if ($this->error) { + return false; + } + } + +/** + * Output information about an SQL query. The SQL statement, number of rows in resultset, + * and execution time in microseconds. If the query fails, an error is output instead. + * + * @param string $sql Query to show information on. + * @access public + */ + function showQuery($sql) { + $error = $this->error; + if (strlen($sql) > 200 && !$this->fullDebug && Configure::read() > 1) { + $sql = substr($sql, 0, 200) . '[...]'; + } + if (Configure::read() > 0) { + $out = null; + if ($error) { + trigger_error('' . __('SQL Error:', true) . " {$this->error}", E_USER_WARNING); + } else { + $out = ('[' . sprintf(__('Aff:%s Num:%s Took:%sms', true), $this->affected, $this->numRows, $this->took) . ']'); + } + pr(sprintf('

    ' . __('Query:', true) . ' %s %s

    ', $sql, $out)); + } + } + +/** + * Gets full table name including prefix + * + * @param mixed $model Either a Model object or a string table name. + * @param boolean $quote Whether you want the table name quoted. + * @return string Full quoted table name + * @access public + */ + function fullTableName($model, $quote = true) { + if (is_object($model)) { + $table = $model->tablePrefix . $model->table; + } elseif (isset($this->config['prefix'])) { + $table = $this->config['prefix'] . strval($model); + } else { + $table = strval($model); + } + if ($quote) { + return $this->name($table); + } + return $table; + } + +/** + * The "C" in CRUD + * + * Creates new records in the database. + * + * @param Model $model Model object that the record is for. + * @param array $fields An array of field names to insert. If null, $model->data will be + * used to generate field names. + * @param array $values An array of values with keys matching the fields. If null, $model->data will + * be used to generate values. + * @return boolean Success + * @access public + */ + function create(&$model, $fields = null, $values = null) { + $id = null; + + if ($fields == null) { + unset($fields, $values); + $fields = array_keys($model->data); + $values = array_values($model->data); + } + $count = count($fields); + + for ($i = 0; $i < $count; $i++) { + $valueInsert[] = $this->value($values[$i], $model->getColumnType($fields[$i]), false); + } + for ($i = 0; $i < $count; $i++) { + $fieldInsert[] = $this->name($fields[$i]); + if ($fields[$i] == $model->primaryKey) { + $id = $values[$i]; + } + } + $query = array( + 'table' => $this->fullTableName($model), + 'fields' => implode(', ', $fieldInsert), + 'values' => implode(', ', $valueInsert) + ); + + if ($this->execute($this->renderStatement('create', $query))) { + if (empty($id)) { + $id = $this->lastInsertId($this->fullTableName($model, false), $model->primaryKey); + } + $model->setInsertID($id); + $model->id = $id; + return true; + } else { + $model->onError(); + return false; + } + } + +/** + * The "R" in CRUD + * + * Reads record(s) from the database. + * + * @param Model $model A Model object that the query is for. + * @param array $queryData An array of queryData information containing keys similar to Model::find() + * @param integer $recursive Number of levels of association + * @return mixed boolean false on error/failure. An array of results on success. + */ + function read(&$model, $queryData = array(), $recursive = null) { + $queryData = $this->__scrubQueryData($queryData); + + $null = null; + $array = array(); + $linkedModels = array(); + $this->__bypass = false; + $this->__booleans = array(); + + if ($recursive === null && isset($queryData['recursive'])) { + $recursive = $queryData['recursive']; + } + + if (!is_null($recursive)) { + $_recursive = $model->recursive; + $model->recursive = $recursive; + } + + if (!empty($queryData['fields'])) { + $this->__bypass = true; + $queryData['fields'] = $this->fields($model, null, $queryData['fields']); + } else { + $queryData['fields'] = $this->fields($model); + } + + $_associations = $model->__associations; + + if ($model->recursive == -1) { + $_associations = array(); + } else if ($model->recursive == 0) { + unset($_associations[2], $_associations[3]); + } + + foreach ($_associations as $type) { + foreach ($model->{$type} as $assoc => $assocData) { + $linkModel =& $model->{$assoc}; + $external = isset($assocData['external']); + + if ($model->useDbConfig == $linkModel->useDbConfig) { + if (true === $this->generateAssociationQuery($model, $linkModel, $type, $assoc, $assocData, $queryData, $external, $null)) { + $linkedModels[$type . '/' . $assoc] = true; + } + } + } + } + + $query = $this->generateAssociationQuery($model, $null, null, null, null, $queryData, false, $null); + + $resultSet = $this->fetchAll($query, $model->cacheQueries, $model->alias); + + if ($resultSet === false) { + $model->onError(); + return false; + } + + $filtered = $this->__filterResults($resultSet, $model); + + if ($model->recursive > -1) { + foreach ($_associations as $type) { + foreach ($model->{$type} as $assoc => $assocData) { + $linkModel =& $model->{$assoc}; + + if (empty($linkedModels[$type . '/' . $assoc])) { + if ($model->useDbConfig == $linkModel->useDbConfig) { + $db =& $this; + } else { + $db =& ConnectionManager::getDataSource($linkModel->useDbConfig); + } + } elseif ($model->recursive > 1 && ($type == 'belongsTo' || $type == 'hasOne')) { + $db =& $this; + } + + if (isset($db) && method_exists($db, 'queryAssociation')) { + $stack = array($assoc); + $db->queryAssociation($model, $linkModel, $type, $assoc, $assocData, $array, true, $resultSet, $model->recursive - 1, $stack); + unset($db); + + if ($type === 'hasMany') { + $filtered []= $assoc; + } + } + } + } + $this->__filterResults($resultSet, $model, $filtered); + } + + if (!is_null($recursive)) { + $model->recursive = $_recursive; + } + return $resultSet; + } + +/** + * Passes association results thru afterFind filters of corresponding model + * + * @param array $results Reference of resultset to be filtered + * @param object $model Instance of model to operate against + * @param array $filtered List of classes already filtered, to be skipped + * @return array Array of results that have been filtered through $model->afterFind + * @access private + */ + function __filterResults(&$results, &$model, $filtered = array()) { + $filtering = array(); + $count = count($results); + + for ($i = 0; $i < $count; $i++) { + if (is_array($results[$i])) { + $classNames = array_keys($results[$i]); + $count2 = count($classNames); + + for ($j = 0; $j < $count2; $j++) { + $className = $classNames[$j]; + if ($model->alias != $className && !in_array($className, $filtered)) { + if (!in_array($className, $filtering)) { + $filtering[] = $className; + } + + if (isset($model->{$className}) && is_object($model->{$className})) { + $data = $model->{$className}->afterFind(array(array($className => $results[$i][$className])), false); + } + if (isset($data[0][$className])) { + $results[$i][$className] = $data[0][$className]; + } + } + } + } + } + return $filtering; + } + +/** + * Queries associations. Used to fetch results on recursive models. + * + * @param Model $model Primary Model object + * @param Model $linkModel Linked model that + * @param string $type Association type, one of the model association types ie. hasMany + * @param unknown_type $association + * @param unknown_type $assocData + * @param array $queryData + * @param boolean $external Whether or not the association query is on an external datasource. + * @param array $resultSet Existing results + * @param integer $recursive Number of levels of association + * @param array $stack + */ + function queryAssociation(&$model, &$linkModel, $type, $association, $assocData, &$queryData, $external = false, &$resultSet, $recursive, $stack) { + if ($query = $this->generateAssociationQuery($model, $linkModel, $type, $association, $assocData, $queryData, $external, $resultSet)) { + if (!isset($resultSet) || !is_array($resultSet)) { + if (Configure::read() > 0) { + echo '
    ' . sprintf(__('SQL Error in model %s:', true), $model->alias) . ' '; + if (isset($this->error) && $this->error != null) { + echo $this->error; + } + echo '
    '; + } + return null; + } + $count = count($resultSet); + + if ($type === 'hasMany' && empty($assocData['limit']) && !empty($assocData['foreignKey'])) { + $ins = $fetch = array(); + for ($i = 0; $i < $count; $i++) { + if ($in = $this->insertQueryData('{$__cakeID__$}', $resultSet[$i], $association, $assocData, $model, $linkModel, $stack)) { + $ins[] = $in; + } + } + + if (!empty($ins)) { + $ins = array_unique($ins); + $fetch = $this->fetchAssociated($model, $query, $ins); + } + + if (!empty($fetch) && is_array($fetch)) { + if ($recursive > 0) { + foreach ($linkModel->__associations as $type1) { + foreach ($linkModel->{$type1} as $assoc1 => $assocData1) { + $deepModel =& $linkModel->{$assoc1}; + $tmpStack = $stack; + $tmpStack[] = $assoc1; + + if ($linkModel->useDbConfig === $deepModel->useDbConfig) { + $db =& $this; + } else { + $db =& ConnectionManager::getDataSource($deepModel->useDbConfig); + } + $db->queryAssociation($linkModel, $deepModel, $type1, $assoc1, $assocData1, $queryData, true, $fetch, $recursive - 1, $tmpStack); + } + } + } + } + $this->__filterResults($fetch, $model); + return $this->__mergeHasMany($resultSet, $fetch, $association, $model, $linkModel, $recursive); + } elseif ($type === 'hasAndBelongsToMany') { + $ins = $fetch = array(); + for ($i = 0; $i < $count; $i++) { + if ($in = $this->insertQueryData('{$__cakeID__$}', $resultSet[$i], $association, $assocData, $model, $linkModel, $stack)) { + $ins[] = $in; + } + } + if (!empty($ins)) { + $ins = array_unique($ins); + if (count($ins) > 1) { + $query = str_replace('{$__cakeID__$}', '(' .implode(', ', $ins) .')', $query); + $query = str_replace('= (', 'IN (', $query); + } else { + $query = str_replace('{$__cakeID__$}',$ins[0], $query); + } + + $query = str_replace(' WHERE 1 = 1', '', $query); + } + + $foreignKey = $model->hasAndBelongsToMany[$association]['foreignKey']; + $joinKeys = array($foreignKey, $model->hasAndBelongsToMany[$association]['associationForeignKey']); + list($with, $habtmFields) = $model->joinModel($model->hasAndBelongsToMany[$association]['with'], $joinKeys); + $habtmFieldsCount = count($habtmFields); + $q = $this->insertQueryData($query, null, $association, $assocData, $model, $linkModel, $stack); + + if ($q != false) { + $fetch = $this->fetchAll($q, $model->cacheQueries, $model->alias); + } else { + $fetch = null; + } + } + + for ($i = 0; $i < $count; $i++) { + $row =& $resultSet[$i]; + + if ($type !== 'hasAndBelongsToMany') { + $q = $this->insertQueryData($query, $resultSet[$i], $association, $assocData, $model, $linkModel, $stack); + if ($q != false) { + $fetch = $this->fetchAll($q, $model->cacheQueries, $model->alias); + } else { + $fetch = null; + } + } + $selfJoin = false; + + if ($linkModel->name === $model->name) { + $selfJoin = true; + } + + if (!empty($fetch) && is_array($fetch)) { + if ($recursive > 0) { + foreach ($linkModel->__associations as $type1) { + foreach ($linkModel->{$type1} as $assoc1 => $assocData1) { + $deepModel =& $linkModel->{$assoc1}; + + if (($type1 === 'belongsTo') || ($deepModel->alias === $model->alias && $type === 'belongsTo') || ($deepModel->alias != $model->alias)) { + $tmpStack = $stack; + $tmpStack[] = $assoc1; + if ($linkModel->useDbConfig == $deepModel->useDbConfig) { + $db =& $this; + } else { + $db =& ConnectionManager::getDataSource($deepModel->useDbConfig); + } + $db->queryAssociation($linkModel, $deepModel, $type1, $assoc1, $assocData1, $queryData, true, $fetch, $recursive - 1, $tmpStack); + } + } + } + } + if ($type == 'hasAndBelongsToMany') { + $uniqueIds = $merge = array(); + + foreach ($fetch as $j => $data) { + if ( + (isset($data[$with]) && $data[$with][$foreignKey] === $row[$model->alias][$model->primaryKey]) + ) { + if ($habtmFieldsCount <= 2) { + unset($data[$with]); + } + $merge[] = $data; + } + } + if (empty($merge) && !isset($row[$association])) { + $row[$association] = $merge; + } else { + $this->__mergeAssociation($resultSet[$i], $merge, $association, $type); + } + } else { + $this->__mergeAssociation($resultSet[$i], $fetch, $association, $type, $selfJoin); + } + if (isset($resultSet[$i][$association])) { + $resultSet[$i][$association] = $linkModel->afterFind($resultSet[$i][$association], false); + } + } else { + $tempArray[0][$association] = false; + $this->__mergeAssociation($resultSet[$i], $tempArray, $association, $type, $selfJoin); + } + } + } + } + +/** + * A more efficient way to fetch associations. Woohoo! + * + * @param model $model Primary model object + * @param string $query Association query + * @param array $ids Array of IDs of associated records + * @return array Association results + * @access public + */ + function fetchAssociated($model, $query, $ids) { + $query = str_replace('{$__cakeID__$}', implode(', ', $ids), $query); + if (count($ids) > 1) { + $query = str_replace('= (', 'IN (', $query); + } + return $this->fetchAll($query, $model->cacheQueries, $model->alias); + } + +/** + * mergeHasMany - Merge the results of hasMany relations. + * + * + * @param array $resultSet Data to merge into + * @param array $merge Data to merge + * @param string $association Name of Model being Merged + * @param object $model Model being merged onto + * @param object $linkModel Model being merged + * @return void + */ + function __mergeHasMany(&$resultSet, $merge, $association, &$model, &$linkModel) { + foreach ($resultSet as $i => $value) { + $count = 0; + $merged[$association] = array(); + foreach ($merge as $j => $data) { + if (isset($value[$model->alias]) && $value[$model->alias][$model->primaryKey] === $data[$association][$model->hasMany[$association]['foreignKey']]) { + if (count($data) > 1) { + $data = array_merge($data[$association], $data); + unset($data[$association]); + foreach ($data as $key => $name) { + if (is_numeric($key)) { + $data[$association][] = $name; + unset($data[$key]); + } + } + $merged[$association][] = $data; + } else { + $merged[$association][] = $data[$association]; + } + } + $count++; + } + if (isset($value[$model->alias])) { + $resultSet[$i] = Set::pushDiff($resultSet[$i], $merged); + unset($merged); + } + } + } + +/** + * Enter description here... + * + * @param unknown_type $data + * @param unknown_type $merge + * @param unknown_type $association + * @param unknown_type $type + * @param boolean $selfJoin + * @access private + */ + function __mergeAssociation(&$data, $merge, $association, $type, $selfJoin = false) { + if (isset($merge[0]) && !isset($merge[0][$association])) { + $association = Inflector::pluralize($association); + } + + if ($type == 'belongsTo' || $type == 'hasOne') { + if (isset($merge[$association])) { + $data[$association] = $merge[$association][0]; + } else { + if (count($merge[0][$association]) > 1) { + foreach ($merge[0] as $assoc => $data2) { + if ($assoc != $association) { + $merge[0][$association][$assoc] = $data2; + } + } + } + if (!isset($data[$association])) { + if ($merge[0][$association] != null) { + $data[$association] = $merge[0][$association]; + } else { + $data[$association] = array(); + } + } else { + if (is_array($merge[0][$association])) { + foreach ($data[$association] as $k => $v) { + if (!is_array($v)) { + $dataAssocTmp[$k] = $v; + } + } + + foreach ($merge[0][$association] as $k => $v) { + if (!is_array($v)) { + $mergeAssocTmp[$k] = $v; + } + } + $dataKeys = array_keys($data); + $mergeKeys = array_keys($merge[0]); + + if ($mergeKeys[0] === $dataKeys[0] || $mergeKeys === $dataKeys) { + $data[$association][$association] = $merge[0][$association]; + } else { + $diff = Set::diff($dataAssocTmp, $mergeAssocTmp); + $data[$association] = array_merge($merge[0][$association], $diff); + } + } elseif ($selfJoin && array_key_exists($association, $merge[0])) { + $data[$association] = array_merge($data[$association], array($association => array())); + } + } + } + } else { + if (isset($merge[0][$association]) && $merge[0][$association] === false) { + if (!isset($data[$association])) { + $data[$association] = array(); + } + } else { + foreach ($merge as $i => $row) { + if (count($row) == 1) { + if (empty($data[$association]) || (isset($data[$association]) && !in_array($row[$association], $data[$association]))) { + $data[$association][] = $row[$association]; + } + } else if (!empty($row)) { + $tmp = array_merge($row[$association], $row); + unset($tmp[$association]); + $data[$association][] = $tmp; + } + } + } + } + } + +/** + * Generates an array representing a query or part of a query from a single model or two associated models + * + * @param Model $model + * @param Model $linkModel + * @param string $type + * @param string $association + * @param array $assocData + * @param array $queryData + * @param boolean $external + * @param array $resultSet + * @return mixed + * @access public + */ + function generateAssociationQuery(&$model, &$linkModel, $type, $association = null, $assocData = array(), &$queryData, $external = false, &$resultSet) { + $queryData = $this->__scrubQueryData($queryData); + $assocData = $this->__scrubQueryData($assocData); + + if (empty($queryData['fields'])) { + $queryData['fields'] = $this->fields($model, $model->alias); + } elseif (!empty($model->hasMany) && $model->recursive > -1) { + $assocFields = $this->fields($model, $model->alias, array("{$model->alias}.{$model->primaryKey}")); + $passedFields = $this->fields($model, $model->alias, $queryData['fields']); + if (count($passedFields) === 1) { + $match = strpos($passedFields[0], $assocFields[0]); + $match1 = (bool)preg_match('/^[a-z]+\(/i', $passedFields[0]); + + if ($match === false && $match1 === false) { + $queryData['fields'] = array_merge($passedFields, $assocFields); + } else { + $queryData['fields'] = $passedFields; + } + } else { + $queryData['fields'] = array_merge($passedFields, $assocFields); + } + unset($assocFields, $passedFields); + } + + if ($linkModel == null) { + return $this->buildStatement( + array( + 'fields' => array_unique($queryData['fields']), + 'table' => $this->fullTableName($model), + 'alias' => $model->alias, + 'limit' => $queryData['limit'], + 'offset' => $queryData['offset'], + 'joins' => $queryData['joins'], + 'conditions' => $queryData['conditions'], + 'order' => $queryData['order'], + 'group' => $queryData['group'] + ), + $model + ); + } + if ($external && !empty($assocData['finderQuery'])) { + return $assocData['finderQuery']; + } + + $alias = $association; + $self = ($model->name == $linkModel->name); + $fields = array(); + + if ((!$external && in_array($type, array('hasOne', 'belongsTo')) && $this->__bypass === false) || $external) { + $fields = $this->fields($linkModel, $alias, $assocData['fields']); + } + if (empty($assocData['offset']) && !empty($assocData['page'])) { + $assocData['offset'] = ($assocData['page'] - 1) * $assocData['limit']; + } + $assocData['limit'] = $this->limit($assocData['limit'], $assocData['offset']); + + switch ($type) { + case 'hasOne': + case 'belongsTo': + $conditions = $this->__mergeConditions( + $assocData['conditions'], + $this->getConstraint($type, $model, $linkModel, $alias, array_merge($assocData, compact('external', 'self'))) + ); + + if (!$self && $external) { + foreach ($conditions as $key => $condition) { + if (is_numeric($key) && strpos($condition, $model->alias . '.') !== false) { + unset($conditions[$key]); + } + } + } + + if ($external) { + $query = array_merge($assocData, array( + 'conditions' => $conditions, + 'table' => $this->fullTableName($linkModel), + 'fields' => $fields, + 'alias' => $alias, + 'group' => null + )); + $query = array_merge(array('order' => $assocData['order'], 'limit' => $assocData['limit']), $query); + } else { + $join = array( + 'table' => $this->fullTableName($linkModel), + 'alias' => $alias, + 'type' => isset($assocData['type']) ? $assocData['type'] : 'LEFT', + 'conditions' => trim($this->conditions($conditions, true, false, $model)) + ); + $queryData['fields'] = array_merge($queryData['fields'], $fields); + + if (!empty($assocData['order'])) { + $queryData['order'][] = $assocData['order']; + } + if (!in_array($join, $queryData['joins'])) { + $queryData['joins'][] = $join; + } + return true; + } + break; + case 'hasMany': + $assocData['fields'] = $this->fields($linkModel, $alias, $assocData['fields']); + if (!empty($assocData['foreignKey'])) { + $assocData['fields'] = array_merge($assocData['fields'], $this->fields($linkModel, $alias, array("{$alias}.{$assocData['foreignKey']}"))); + } + $query = array( + 'conditions' => $this->__mergeConditions($this->getConstraint('hasMany', $model, $linkModel, $alias, $assocData), $assocData['conditions']), + 'fields' => array_unique($assocData['fields']), + 'table' => $this->fullTableName($linkModel), + 'alias' => $alias, + 'order' => $assocData['order'], + 'limit' => $assocData['limit'], + 'group' => null + ); + break; + case 'hasAndBelongsToMany': + $joinFields = array(); + $joinAssoc = null; + + if (isset($assocData['with']) && !empty($assocData['with'])) { + $joinKeys = array($assocData['foreignKey'], $assocData['associationForeignKey']); + list($with, $joinFields) = $model->joinModel($assocData['with'], $joinKeys); + + $joinTbl = $this->fullTableName($model->{$with}); + $joinAlias = $joinTbl; + + if (is_array($joinFields) && !empty($joinFields)) { + $joinFields = $this->fields($model->{$with}, $model->{$with}->alias, $joinFields); + $joinAssoc = $joinAlias = $model->{$with}->alias; + } else { + $joinFields = array(); + } + } else { + $joinTbl = $this->fullTableName($assocData['joinTable']); + $joinAlias = $joinTbl; + } + $query = array( + 'conditions' => $assocData['conditions'], + 'limit' => $assocData['limit'], + 'table' => $this->fullTableName($linkModel), + 'alias' => $alias, + 'fields' => array_merge($this->fields($linkModel, $alias, $assocData['fields']), $joinFields), + 'order' => $assocData['order'], + 'group' => null, + 'joins' => array(array( + 'table' => $joinTbl, + 'alias' => $joinAssoc, + 'conditions' => $this->getConstraint('hasAndBelongsToMany', $model, $linkModel, $joinAlias, $assocData, $alias) + )) + ); + break; + } + if (isset($query)) { + return $this->buildStatement($query, $model); + } + return null; + } + +/** + * Returns a conditions array for the constraint between two models + * + * @param string $type Association type + * @param object $model Model object + * @param array $association Association array + * @return array Conditions array defining the constraint between $model and $association + * @access public + */ + function getConstraint($type, $model, $linkModel, $alias, $assoc, $alias2 = null) { + $assoc = array_merge(array('external' => false, 'self' => false), $assoc); + + if (array_key_exists('foreignKey', $assoc) && empty($assoc['foreignKey'])) { + return array(); + } + + switch (true) { + case ($assoc['external'] && $type == 'hasOne'): + return array("{$alias}.{$assoc['foreignKey']}" => '{$__cakeID__$}'); + break; + case ($assoc['external'] && $type == 'belongsTo'): + return array("{$alias}.{$linkModel->primaryKey}" => '{$__cakeForeignKey__$}'); + break; + case (!$assoc['external'] && $type == 'hasOne'): + return array("{$alias}.{$assoc['foreignKey']}" => $this->identifier("{$model->alias}.{$model->primaryKey}")); + break; + case (!$assoc['external'] && $type == 'belongsTo'): + return array("{$model->alias}.{$assoc['foreignKey']}" => $this->identifier("{$alias}.{$linkModel->primaryKey}")); + break; + case ($type == 'hasMany'): + return array("{$alias}.{$assoc['foreignKey']}" => array('{$__cakeID__$}')); + break; + case ($type == 'hasAndBelongsToMany'): + return array( + array("{$alias}.{$assoc['foreignKey']}" => '{$__cakeID__$}'), + array("{$alias}.{$assoc['associationForeignKey']}" => $this->identifier("{$alias2}.{$linkModel->primaryKey}")) + ); + break; + } + return array(); + } + +/** + * Builds and generates a JOIN statement from an array. Handles final clean-up before conversion. + * + * @param array $join An array defining a JOIN statement in a query + * @return string An SQL JOIN statement to be used in a query + * @access public + * @see DboSource::renderJoinStatement() + * @see DboSource::buildStatement() + */ + function buildJoinStatement($join) { + $data = array_merge(array( + 'type' => null, + 'alias' => null, + 'table' => 'join_table', + 'conditions' => array() + ), $join); + + if (!empty($data['alias'])) { + $data['alias'] = $this->alias . $this->name($data['alias']); + } + if (!empty($data['conditions'])) { + $data['conditions'] = trim($this->conditions($data['conditions'], true, false)); + } + return $this->renderJoinStatement($data); + } + +/** + * Builds and generates an SQL statement from an array. Handles final clean-up before conversion. + * + * @param array $query An array defining an SQL query + * @param object $model The model object which initiated the query + * @return string An executable SQL statement + * @access public + * @see DboSource::renderStatement() + */ + function buildStatement($query, &$model) { + $query = array_merge(array('offset' => null, 'joins' => array()), $query); + if (!empty($query['joins'])) { + $count = count($query['joins']); + for ($i = 0; $i < $count; $i++) { + if (is_array($query['joins'][$i])) { + $query['joins'][$i] = $this->buildJoinStatement($query['joins'][$i]); + } + } + } + return $this->renderStatement('select', array( + 'conditions' => $this->conditions($query['conditions'], true, true, $model), + 'fields' => implode(', ', $query['fields']), + 'table' => $query['table'], + 'alias' => $this->alias . $this->name($query['alias']), + 'order' => $this->order($query['order'], 'ASC', $model), + 'limit' => $this->limit($query['limit'], $query['offset']), + 'joins' => implode(' ', $query['joins']), + 'group' => $this->group($query['group'], $model) + )); + } + +/** + * Renders a final SQL JOIN statement + * + * @param array $data + * @return string + * @access public + */ + function renderJoinStatement($data) { + extract($data); + return trim("{$type} JOIN {$table} {$alias} ON ({$conditions})"); + } + +/** + * Renders a final SQL statement by putting together the component parts in the correct order + * + * @param string $type type of query being run. e.g select, create, update, delete, schema, alter. + * @param array $data Array of data to insert into the query. + * @return string Rendered SQL expression to be run. + * @access public + */ + function renderStatement($type, $data) { + extract($data); + $aliases = null; + + switch (strtolower($type)) { + case 'select': + return "SELECT {$fields} FROM {$table} {$alias} {$joins} {$conditions} {$group} {$order} {$limit}"; + break; + case 'create': + return "INSERT INTO {$table} ({$fields}) VALUES ({$values})"; + break; + case 'update': + if (!empty($alias)) { + $aliases = "{$this->alias}{$alias} {$joins} "; + } + return "UPDATE {$table} {$aliases}SET {$fields} {$conditions}"; + break; + case 'delete': + if (!empty($alias)) { + $aliases = "{$this->alias}{$alias} {$joins} "; + } + return "DELETE {$alias} FROM {$table} {$aliases}{$conditions}"; + break; + case 'schema': + foreach (array('columns', 'indexes', 'tableParameters') as $var) { + if (is_array(${$var})) { + ${$var} = "\t" . join(",\n\t", array_filter(${$var})); + } else { + ${$var} = ''; + } + } + if (trim($indexes) != '') { + $columns .= ','; + } + return "CREATE TABLE {$table} (\n{$columns}{$indexes}){$tableParameters};"; + break; + case 'alter': + break; + } + } + +/** + * Merges a mixed set of string/array conditions + * + * @return array + * @access private + */ + function __mergeConditions($query, $assoc) { + if (empty($assoc)) { + return $query; + } + + if (is_array($query)) { + return array_merge((array)$assoc, $query); + } + + if (!empty($query)) { + $query = array($query); + if (is_array($assoc)) { + $query = array_merge($query, $assoc); + } else { + $query[] = $assoc; + } + return $query; + } + + return $assoc; + } + +/** + * Generates and executes an SQL UPDATE statement for given model, fields, and values. + * For databases that do not support aliases in UPDATE queries. + * + * @param Model $model + * @param array $fields + * @param array $values + * @param mixed $conditions + * @return boolean Success + * @access public + */ + function update(&$model, $fields = array(), $values = null, $conditions = null) { + if ($values == null) { + $combined = $fields; + } else { + $combined = array_combine($fields, $values); + } + + $fields = implode(', ', $this->_prepareUpdateFields($model, $combined, empty($conditions))); + + $alias = $joins = null; + $table = $this->fullTableName($model); + $conditions = $this->_matchRecords($model, $conditions); + + if ($conditions === false) { + return false; + } + $query = compact('table', 'alias', 'joins', 'fields', 'conditions'); + + if (!$this->execute($this->renderStatement('update', $query))) { + $model->onError(); + return false; + } + return true; + } + +/** + * Quotes and prepares fields and values for an SQL UPDATE statement + * + * @param Model $model + * @param array $fields + * @param boolean $quoteValues If values should be quoted, or treated as SQL snippets + * @param boolean $alias Include the model alias in the field name + * @return array Fields and values, quoted and preparted + * @access protected + */ + function _prepareUpdateFields(&$model, $fields, $quoteValues = true, $alias = false) { + $quotedAlias = $this->startQuote . $model->alias . $this->endQuote; + + $updates = array(); + foreach ($fields as $field => $value) { + if ($alias && strpos($field, '.') === false) { + $quoted = $model->escapeField($field); + } elseif (!$alias && strpos($field, '.') !== false) { + $quoted = $this->name(str_replace($quotedAlias . '.', '', str_replace( + $model->alias . '.', '', $field + ))); + } else { + $quoted = $this->name($field); + } + + if ($value === null) { + $updates[] = $quoted . ' = NULL'; + continue; + } + $update = $quoted . ' = '; + + if ($quoteValues) { + $update .= $this->value($value, $model->getColumnType($field), false); + } elseif (!$alias) { + $update .= str_replace($quotedAlias . '.', '', str_replace( + $model->alias . '.', '', $value + )); + } else { + $update .= $value; + } + $updates[] = $update; + } + return $updates; + } + +/** + * Generates and executes an SQL DELETE statement. + * For databases that do not support aliases in UPDATE queries. + * + * @param Model $model + * @param mixed $conditions + * @return boolean Success + * @access public + */ + function delete(&$model, $conditions = null) { + $alias = $joins = null; + $table = $this->fullTableName($model); + $conditions = $this->_matchRecords($model, $conditions); + + if ($conditions === false) { + return false; + } + + if ($this->execute($this->renderStatement('delete', compact('alias', 'table', 'joins', 'conditions'))) === false) { + $model->onError(); + return false; + } + return true; + } + +/** + * Gets a list of record IDs for the given conditions. Used for multi-record updates and deletes + * in databases that do not support aliases in UPDATE/DELETE queries. + * + * @param Model $model + * @param mixed $conditions + * @return array List of record IDs + * @access protected + */ + function _matchRecords(&$model, $conditions = null) { + if ($conditions === true) { + $conditions = $this->conditions(true); + } elseif ($conditions === null) { + $conditions = $this->conditions($this->defaultConditions($model, $conditions, false), true, true, $model); + } else { + $noJoin = true; + foreach ($conditions as $field => $value) { + $originalField = $field; + if (strpos($field, '.') !== false) { + list($alias, $field) = explode('.', $field); + $field = ltrim($field, $this->startQuote); + $field = rtrim($field, $this->endQuote); + } + if (!$model->hasField($field)) { + $noJoin = false; + break; + } + if ($field !== $originalField) { + $conditions[$field] = $value; + unset($conditions[$originalField]); + } + } + if ($noJoin === true) { + return $this->conditions($conditions); + } + $idList = $model->find('all', array( + 'fields' => "{$model->alias}.{$model->primaryKey}", + 'conditions' => $conditions + )); + + if (empty($idList)) { + return false; + } + $conditions = $this->conditions(array( + $model->primaryKey => Set::extract($idList, "{n}.{$model->alias}.{$model->primaryKey}") + )); + } + return $conditions; + } + +/** + * Returns an array of SQL JOIN fragments from a model's associations + * + * @param object $model + * @return array + * @access protected + */ + function _getJoins($model) { + $join = array(); + $joins = array_merge($model->getAssociated('hasOne'), $model->getAssociated('belongsTo')); + + foreach ($joins as $assoc) { + if (isset($model->{$assoc}) && $model->useDbConfig == $model->{$assoc}->useDbConfig) { + $assocData = $model->getAssociated($assoc); + $join[] = $this->buildJoinStatement(array( + 'table' => $this->fullTableName($model->{$assoc}), + 'alias' => $assoc, + 'type' => isset($assocData['type']) ? $assocData['type'] : 'LEFT', + 'conditions' => trim($this->conditions( + $this->__mergeConditions($assocData['conditions'], $this->getConstraint($assocData['association'], $model, $model->{$assoc}, $assoc, $assocData)), + true, false, $model + )) + )); + } + } + return $join; + } + +/** + * Returns an SQL calculation, i.e. COUNT() or MAX() + * + * @param model $model + * @param string $func Lowercase name of SQL function, i.e. 'count' or 'max' + * @param array $params Function parameters (any values must be quoted manually) + * @return string An SQL calculation function + * @access public + */ + function calculate(&$model, $func, $params = array()) { + $params = (array)$params; + + switch (strtolower($func)) { + case 'count': + if (!isset($params[0])) { + $params[0] = '*'; + } + if (!isset($params[1])) { + $params[1] = 'count'; + } + if (is_object($model) && $model->isVirtualField($params[0])){ + $arg = $this->__quoteFields($model->getVirtualField($params[0])); + } else { + $arg = $this->name($params[0]); + } + return 'COUNT(' . $arg . ') AS ' . $this->name($params[1]); + case 'max': + case 'min': + if (!isset($params[1])) { + $params[1] = $params[0]; + } + if (is_object($model) && $model->isVirtualField($params[0])) { + $arg = $this->__quoteFields($model->getVirtualField($params[0])); + } else { + $arg = $this->name($params[0]); + } + return strtoupper($func) . '(' . $arg . ') AS ' . $this->name($params[1]); + break; + } + } + +/** + * Deletes all the records in a table and resets the count of the auto-incrementing + * primary key, where applicable. + * + * @param mixed $table A string or model class representing the table to be truncated + * @return boolean SQL TRUNCATE TABLE statement, false if not applicable. + * @access public + */ + function truncate($table) { + return $this->execute('TRUNCATE TABLE ' . $this->fullTableName($table)); + } + +/** + * Begin a transaction + * + * @param model $model + * @return boolean True on success, false on fail + * (i.e. if the database/model does not support transactions, + * or a transaction has not started). + * @access public + */ + function begin(&$model) { + if (parent::begin($model) && $this->execute($this->_commands['begin'])) { + $this->_transactionStarted = true; + return true; + } + return false; + } + +/** + * Commit a transaction + * + * @param model $model + * @return boolean True on success, false on fail + * (i.e. if the database/model does not support transactions, + * or a transaction has not started). + * @access public + */ + function commit(&$model) { + if (parent::commit($model) && $this->execute($this->_commands['commit'])) { + $this->_transactionStarted = false; + return true; + } + return false; + } + +/** + * Rollback a transaction + * + * @param model $model + * @return boolean True on success, false on fail + * (i.e. if the database/model does not support transactions, + * or a transaction has not started). + * @access public + */ + function rollback(&$model) { + if (parent::rollback($model) && $this->execute($this->_commands['rollback'])) { + $this->_transactionStarted = false; + return true; + } + return false; + } + +/** + * Creates a default set of conditions from the model if $conditions is null/empty. + * If conditions are supplied then they will be returned. If a model doesn't exist and no conditions + * were provided either null or false will be returned based on what was input. + * + * @param object $model + * @param mixed $conditions Array of conditions, conditions string, null or false. If an array of conditions, + * or string conditions those conditions will be returned. With other values the model's existance will be checked. + * If the model doesn't exist a null or false will be returned depending on the input value. + * @param boolean $useAlias Use model aliases rather than table names when generating conditions + * @return mixed Either null, false, $conditions or an array of default conditions to use. + * @see DboSource::update() + * @see DboSource::conditions() + * @access public + */ + function defaultConditions(&$model, $conditions, $useAlias = true) { + if (!empty($conditions)) { + return $conditions; + } + $exists = $model->exists(); + if (!$exists && $conditions !== null) { + return false; + } elseif (!$exists) { + return null; + } + $alias = $model->alias; + + if (!$useAlias) { + $alias = $this->fullTableName($model, false); + } + return array("{$alias}.{$model->primaryKey}" => $model->getID()); + } + +/** + * Returns a key formatted like a string Model.fieldname(i.e. Post.title, or Country.name) + * + * @param unknown_type $model + * @param unknown_type $key + * @param unknown_type $assoc + * @return string + * @access public + */ + function resolveKey($model, $key, $assoc = null) { + if (empty($assoc)) { + $assoc = $model->alias; + } + if (!strpos('.', $key)) { + return $this->name($model->alias) . '.' . $this->name($key); + } + return $key; + } + +/** + * Private helper method to remove query metadata in given data array. + * + * @param array $data + * @return array + * @access public + */ + function __scrubQueryData($data) { + foreach (array('conditions', 'fields', 'joins', 'order', 'limit', 'offset', 'group') as $key) { + if (empty($data[$key])) { + $data[$key] = array(); + } + } + return $data; + } + +/** + * Converts model virtual fields into sql expressions to be fetched later + * + * @param Model $model + * @param string $alias Alias tablename + * @param mixed $fields virtual fields to be used on query + * @return array + */ + function _constructVirtualFields(&$model, $alias, $fields) { + $virtual = array(); + foreach ($fields as $field) { + $virtualField = $this->name($alias . $this->virtualFieldSeparator . $field); + $expression = $this->__quoteFields($model->getVirtualField($field)); + $virtual[] = '(' . $expression . ") {$this->alias} {$virtualField}"; + } + return $virtual; + } + +/** + * Generates the fields list of an SQL query. + * + * @param Model $model + * @param string $alias Alias tablename + * @param mixed $fields + * @param boolean $quote If false, returns fields array unquoted + * @return array + * @access public + */ + function fields(&$model, $alias = null, $fields = array(), $quote = true) { + if (empty($alias)) { + $alias = $model->alias; + } + $cacheKey = array( + $model->useDbConfig, + $model->table, + array_keys($model->schema()), + $model->name, + $model->getVirtualField(), + $alias, + $fields, + $quote + ); + $cacheKey = crc32(serialize($cacheKey)); + if ($return = $this->cacheMethod(__FUNCTION__, $cacheKey)) { + return $return; + } + $allFields = empty($fields); + if ($allFields) { + $fields = array_keys($model->schema()); + } elseif (!is_array($fields)) { + $fields = String::tokenize($fields); + } + $fields = array_values(array_filter($fields)); + $allFields = $allFields || in_array('*', $fields) || in_array($model->alias . '.*', $fields); + + $virtual = array(); + $virtualFields = $model->getVirtualField(); + if (!empty($virtualFields)) { + $virtualKeys = array_keys($virtualFields); + foreach ($virtualKeys as $field) { + $virtualKeys[] = $model->alias . '.' . $field; + } + $virtual = ($allFields) ? $virtualKeys : array_intersect($virtualKeys, $fields); + foreach ($virtual as $i => $field) { + if (strpos($field, '.') !== false) { + $virtual[$i] = str_replace($model->alias . '.', '', $field); + } + $fields = array_diff($fields, array($field)); + } + $fields = array_values($fields); + } + + if (!$quote) { + if (!empty($virtual)) { + $fields = array_merge($fields, $this->_constructVirtualFields($model, $alias, $virtual)); + } + return $fields; + } + $count = count($fields); + + if ($count >= 1 && !in_array($fields[0], array('*', 'COUNT(*)'))) { + for ($i = 0; $i < $count; $i++) { + if (is_string($fields[$i]) && in_array($fields[$i], $virtual)) { + unset($fields[$i]); + continue; + } + if (is_object($fields[$i]) && isset($fields[$i]->type) && $fields[$i]->type === 'expression') { + $fields[$i] = $fields[$i]->value; + } elseif (preg_match('/^\(.*\)\s' . $this->alias . '.*/i', $fields[$i])){ + continue; + } elseif (!preg_match('/^.+\\(.*\\)/', $fields[$i])) { + $prepend = ''; + + if (strpos($fields[$i], 'DISTINCT') !== false) { + $prepend = 'DISTINCT '; + $fields[$i] = trim(str_replace('DISTINCT', '', $fields[$i])); + } + $dot = strpos($fields[$i], '.'); + + if ($dot === false) { + $prefix = !( + strpos($fields[$i], ' ') !== false || + strpos($fields[$i], '(') !== false + ); + $fields[$i] = $this->name(($prefix ? $alias . '.' : '') . $fields[$i]); + } else { + $value = array(); + $comma = strpos($fields[$i], ','); + if ($comma === false) { + $build = explode('.', $fields[$i]); + if (!Set::numeric($build)) { + $fields[$i] = $this->name(implode('.', $build)); + } + } + } + $fields[$i] = $prepend . $fields[$i]; + } elseif (preg_match('/\(([\.\w]+)\)/', $fields[$i], $field)) { + if (isset($field[1])) { + if (strpos($field[1], '.') === false) { + $field[1] = $this->name($alias . '.' . $field[1]); + } else { + $field[0] = explode('.', $field[1]); + if (!Set::numeric($field[0])) { + $field[0] = implode('.', array_map(array(&$this, 'name'), $field[0])); + $fields[$i] = preg_replace('/\(' . $field[1] . '\)/', '(' . $field[0] . ')', $fields[$i], 1); + } + } + } + } + } + } + if (!empty($virtual)) { + $fields = array_merge($fields, $this->_constructVirtualFields($model, $alias, $virtual)); + } + return $this->cacheMethod(__FUNCTION__, $cacheKey, array_unique($fields)); + } + +/** + * Creates a WHERE clause by parsing given conditions data. If an array or string + * conditions are provided those conditions will be parsed and quoted. If a boolean + * is given it will be integer cast as condition. Null will return 1 = 1. + * + * Results of this method are stored in a memory cache. This improves performance, but + * because the method uses a simple hashing algorithm it can infrequently have collisions. + * Setting DboSource::$cacheMethods to false will disable the memory cache. + * + * @param mixed $conditions Array or string of conditions, or any value. + * @param boolean $quoteValues If true, values should be quoted + * @param boolean $where If true, "WHERE " will be prepended to the return value + * @param Model $model A reference to the Model instance making the query + * @return string SQL fragment + * @access public + */ + function conditions($conditions, $quoteValues = true, $where = true, $model = null) { + if (is_object($model)) { + $cacheKey = array( + $model->useDbConfig, + $model->table, + $model->schema(), + $model->name, + $model->getVirtualField(), + $conditions, + $quoteValues, + $where + ); + } else { + $cacheKey = array($conditions, $quoteValues, $where); + } + $cacheKey = crc32(serialize($cacheKey)); + if ($return = $this->cacheMethod(__FUNCTION__, $cacheKey)) { + return $return; + } + + $clause = $out = ''; + + if ($where) { + $clause = ' WHERE '; + } + + if (is_array($conditions) && !empty($conditions)) { + $out = $this->conditionKeysToString($conditions, $quoteValues, $model); + + if (empty($out)) { + return $this->cacheMethod(__FUNCTION__, $cacheKey, $clause . ' 1 = 1'); + } + return $this->cacheMethod(__FUNCTION__, $cacheKey, $clause . implode(' AND ', $out)); + } + if ($conditions === false || $conditions === true) { + return $this->cacheMethod(__FUNCTION__, $cacheKey, $clause . (int)$conditions . ' = 1'); + } + + if (empty($conditions) || trim($conditions) == '') { + return $this->cacheMethod(__FUNCTION__, $cacheKey, $clause . '1 = 1'); + } + $clauses = '/^WHERE\\x20|^GROUP\\x20BY\\x20|^HAVING\\x20|^ORDER\\x20BY\\x20/i'; + + if (preg_match($clauses, $conditions, $match)) { + $clause = ''; + } + if (trim($conditions) == '') { + $conditions = ' 1 = 1'; + } else { + $conditions = $this->__quoteFields($conditions); + } + return $this->cacheMethod(__FUNCTION__, $cacheKey, $clause . $conditions); + } + +/** + * Creates a WHERE clause by parsing given conditions array. Used by DboSource::conditions(). + * + * @param array $conditions Array or string of conditions + * @param boolean $quoteValues If true, values should be quoted + * @param Model $model A reference to the Model instance making the query + * @return string SQL fragment + * @access public + */ + function conditionKeysToString($conditions, $quoteValues = true, $model = null) { + $c = 0; + $out = array(); + $data = $columnType = null; + $bool = array('and', 'or', 'not', 'and not', 'or not', 'xor', '||', '&&'); + + foreach ($conditions as $key => $value) { + $join = ' AND '; + $not = null; + + if (is_array($value)) { + $valueInsert = ( + !empty($value) && + (substr_count($key, '?') == count($value) || substr_count($key, ':') == count($value)) + ); + } + + if (is_numeric($key) && empty($value)) { + continue; + } elseif (is_numeric($key) && is_string($value)) { + $out[] = $not . $this->__quoteFields($value); + } elseif ((is_numeric($key) && is_array($value)) || in_array(strtolower(trim($key)), $bool)) { + if (in_array(strtolower(trim($key)), $bool)) { + $join = ' ' . strtoupper($key) . ' '; + } else { + $key = $join; + } + $value = $this->conditionKeysToString($value, $quoteValues, $model); + + if (strpos($join, 'NOT') !== false) { + if (strtoupper(trim($key)) == 'NOT') { + $key = 'AND ' . trim($key); + } + $not = 'NOT '; + } + + if (empty($value[1])) { + if ($not) { + $out[] = $not . '(' . $value[0] . ')'; + } else { + $out[] = $value[0] ; + } + } else { + $out[] = '(' . $not . '(' . implode(') ' . strtoupper($key) . ' (', $value) . '))'; + } + + } else { + if (is_object($value) && isset($value->type)) { + if ($value->type == 'identifier') { + $data .= $this->name($key) . ' = ' . $this->name($value->value); + } elseif ($value->type == 'expression') { + if (is_numeric($key)) { + $data .= $value->value; + } else { + $data .= $this->name($key) . ' = ' . $value->value; + } + } + } elseif (is_array($value) && !empty($value) && !$valueInsert) { + $keys = array_keys($value); + if ($keys === array_values($keys)) { + $count = count($value); + if ($count === 1) { + $data = $this->__quoteFields($key) . ' = ('; + } else { + $data = $this->__quoteFields($key) . ' IN ('; + } + if ($quoteValues) { + if (is_object($model)) { + $columnType = $model->getColumnType($key); + } + $data .= implode(', ', $this->value($value, $columnType)); + } + $data .= ')'; + } else { + $ret = $this->conditionKeysToString($value, $quoteValues, $model); + if (count($ret) > 1) { + $data = '(' . implode(') AND (', $ret) . ')'; + } elseif (isset($ret[0])) { + $data = $ret[0]; + } + } + } elseif (is_numeric($key) && !empty($value)) { + $data = $this->__quoteFields($value); + } else { + $data = $this->__parseKey($model, trim($key), $value); + } + + if ($data != null) { + $out[] = $data; + $data = null; + } + } + $c++; + } + return $out; + } + +/** + * Extracts a Model.field identifier and an SQL condition operator from a string, formats + * and inserts values, and composes them into an SQL snippet. + * + * @param Model $model Model object initiating the query + * @param string $key An SQL key snippet containing a field and optional SQL operator + * @param mixed $value The value(s) to be inserted in the string + * @return string + * @access private + */ + function __parseKey(&$model, $key, $value) { + $operatorMatch = '/^((' . implode(')|(', $this->__sqlOps); + $operatorMatch .= '\\x20)|<[>=]?(?![^>]+>)\\x20?|[>=!]{1,3}(?!<)\\x20?)/is'; + $bound = (strpos($key, '?') !== false || (is_array($value) && strpos($key, ':') !== false)); + + if (!strpos($key, ' ')) { + $operator = '='; + } else { + list($key, $operator) = explode(' ', trim($key), 2); + + if (!preg_match($operatorMatch, trim($operator)) && strpos($operator, ' ') !== false) { + $key = $key . ' ' . $operator; + $split = strrpos($key, ' '); + $operator = substr($key, $split); + $key = substr($key, 0, $split); + } + } + + $virtual = false; + if (is_object($model) && $model->isVirtualField($key)) { + $key = $this->__quoteFields($model->getVirtualField($key)); + $virtual = true; + } + + $type = (is_object($model) ? $model->getColumnType($key) : null); + + $null = ($value === null || (is_array($value) && empty($value))); + + if (strtolower($operator) === 'not') { + $data = $this->conditionKeysToString( + array($operator => array($key => $value)), true, $model + ); + return $data[0]; + } + + $value = $this->value($value, $type); + + if (!$virtual && $key !== '?') { + $isKey = (strpos($key, '(') !== false || strpos($key, ')') !== false); + $key = $isKey ? $this->__quoteFields($key) : $this->name($key); + } + + if ($bound) { + return String::insert($key . ' ' . trim($operator), $value); + } + + if (!preg_match($operatorMatch, trim($operator))) { + $operator .= ' ='; + } + $operator = trim($operator); + + if (is_array($value)) { + $value = implode(', ', $value); + + switch ($operator) { + case '=': + $operator = 'IN'; + break; + case '!=': + case '<>': + $operator = 'NOT IN'; + break; + } + $value = "({$value})"; + } elseif ($null) { + switch ($operator) { + case '=': + $operator = 'IS'; + break; + case '!=': + case '<>': + $operator = 'IS NOT'; + break; + } + } + if ($virtual) { + return "({$key}) {$operator} {$value}"; + } + return "{$key} {$operator} {$value}"; + } + +/** + * Quotes Model.fields + * + * @param string $conditions + * @return string or false if no match + * @access private + */ + function __quoteFields($conditions) { + $start = $end = null; + $original = $conditions; + + if (!empty($this->startQuote)) { + $start = preg_quote($this->startQuote); + } + if (!empty($this->endQuote)) { + $end = preg_quote($this->endQuote); + } + $conditions = str_replace(array($start, $end), '', $conditions); + $conditions = preg_replace_callback('/(?:[\'\"][^\'\"\\\]*(?:\\\.[^\'\"\\\]*)*[\'\"])|([a-z0-9_' . $start . $end . ']*\\.[a-z0-9_' . $start . $end . ']*)/i', array(&$this, '__quoteMatchedField'), $conditions); + + if ($conditions !== null) { + return $conditions; + } + return $original; + } + +/** + * Auxiliary function to quote matches `Model.fields` from a preg_replace_callback call + * + * @param string matched string + * @return string quoted strig + * @access private + */ + function __quoteMatchedField($match) { + if (is_numeric($match[0])) { + return $match[0]; + } + return $this->name($match[0]); + } + +/** + * Returns a limit statement in the correct format for the particular database. + * + * @param integer $limit Limit of results returned + * @param integer $offset Offset from which to start results + * @return string SQL limit/offset statement + * @access public + */ + function limit($limit, $offset = null) { + if ($limit) { + $rt = ''; + if (!strpos(strtolower($limit), 'limit') || strpos(strtolower($limit), 'limit') === 0) { + $rt = ' LIMIT'; + } + + if ($offset) { + $rt .= ' ' . $offset . ','; + } + + $rt .= ' ' . $limit; + return $rt; + } + return null; + } + +/** + * Returns an ORDER BY clause as a string. + * + * @param string $key Field reference, as a key (i.e. Post.title) + * @param string $direction Direction (ASC or DESC) + * @param object $model model reference (used to look for virtual field) + * @return string ORDER BY clause + * @access public + */ + function order($keys, $direction = 'ASC', $model = null) { + if (!is_array($keys)) { + $keys = array($keys); + } + $keys = array_filter($keys); + $result = array(); + while (!empty($keys)) { + list($key, $dir) = each($keys); + array_shift($keys); + + if (is_numeric($key)) { + $key = $dir; + $dir = $direction; + } + + if (is_string($key) && strpos($key, ',') && !preg_match('/\(.+\,.+\)/', $key)) { + $key = array_map('trim', explode(',', $key)); + } + if (is_array($key)) { + //Flatten the array + $key = array_reverse($key, true); + foreach ($key as $k => $v) { + if (is_numeric($k)) { + array_unshift($keys, $v); + } else { + $keys = array($k => $v) + $keys; + } + } + continue; + } elseif (is_object($key) && isset($key->type) && $key->type === 'expression') { + $result[] = $key->value; + continue; + } + + if (preg_match('/\\x20(ASC|DESC).*/i', $key, $_dir)) { + $dir = $_dir[0]; + $key = preg_replace('/\\x20(ASC|DESC).*/i', '', $key); + } + + $key = trim($key); + + if (is_object($model) && $model->isVirtualField($key)) { + $key = '(' . $this->__quoteFields($model->getVirtualField($key)) . ')'; + } + + if (strpos($key, '.')) { + $key = preg_replace_callback('/([a-zA-Z0-9_-]{1,})\\.([a-zA-Z0-9_-]{1,})/', array(&$this, '__quoteMatchedField'), $key); + } + if (!preg_match('/\s/', $key) && !strpos($key, '.')) { + $key = $this->name($key); + } + $key .= ' ' . trim($dir); + $result[] = $key; + } + if (!empty($result)) { + return ' ORDER BY ' . implode(', ', $result); + } + return ''; + } + +/** + * Create a GROUP BY SQL clause + * + * @param string $group Group By Condition + * @return mixed string condition or null + * @access public + */ + function group($group, $model = null) { + if ($group) { + if (!is_array($group)) { + $group = array($group); + } + foreach($group as $index => $key) { + if (is_object($model) && $model->isVirtualField($key)) { + $group[$index] = '(' . $model->getVirtualField($key) . ')'; + } + } + $group = implode(', ', $group); + return ' GROUP BY ' . $this->__quoteFields($group); + } + return null; + } + +/** + * Disconnects database, kills the connection and says the connection is closed. + * + * @return void + * @access public + */ + function close() { + $this->disconnect(); + } + +/** + * Checks if the specified table contains any record matching specified SQL + * + * @param Model $model Model to search + * @param string $sql SQL WHERE clause (condition only, not the "WHERE" part) + * @return boolean True if the table has a matching record, else false + * @access public + */ + function hasAny(&$Model, $sql) { + $sql = $this->conditions($sql); + $table = $this->fullTableName($Model); + $alias = $this->alias . $this->name($Model->alias); + $where = $sql ? "{$sql}" : ' WHERE 1 = 1'; + $id = $Model->escapeField(); + + $out = $this->fetchRow("SELECT COUNT({$id}) {$this->alias}count FROM {$table} {$alias}{$where}"); + + if (is_array($out)) { + return $out[0]['count']; + } + return false; + } + +/** + * Gets the length of a database-native column description, or null if no length + * + * @param string $real Real database-layer column type (i.e. "varchar(255)") + * @return mixed An integer or string representing the length of the column + * @access public + */ + function length($real) { + if (!preg_match_all('/([\w\s]+)(?:\((\d+)(?:,(\d+))?\))?(\sunsigned)?(\szerofill)?/', $real, $result)) { + trigger_error(__("FIXME: Can't parse field: " . $real, true), E_USER_WARNING); + $col = str_replace(array(')', 'unsigned'), '', $real); + $limit = null; + + if (strpos($col, '(') !== false) { + list($col, $limit) = explode('(', $col); + } + if ($limit != null) { + return intval($limit); + } + return null; + } + + $types = array( + 'int' => 1, 'tinyint' => 1, 'smallint' => 1, 'mediumint' => 1, 'integer' => 1, 'bigint' => 1 + ); + + list($real, $type, $length, $offset, $sign, $zerofill) = $result; + $typeArr = $type; + $type = $type[0]; + $length = $length[0]; + $offset = $offset[0]; + + $isFloat = in_array($type, array('dec', 'decimal', 'float', 'numeric', 'double')); + if ($isFloat && $offset) { + return $length.','.$offset; + } + + if (($real[0] == $type) && (count($real) == 1)) { + return null; + } + + if (isset($types[$type])) { + $length += $types[$type]; + if (!empty($sign)) { + $length--; + } + } elseif (in_array($type, array('enum', 'set'))) { + $length = 0; + foreach ($typeArr as $key => $enumValue) { + if ($key == 0) { + continue; + } + $tmpLength = strlen($enumValue); + if ($tmpLength > $length) { + $length = $tmpLength; + } + } + } + return intval($length); + } + +/** + * Translates between PHP boolean values and Database (faked) boolean values + * + * @param mixed $data Value to be translated + * @return mixed Converted boolean value + * @access public + */ + function boolean($data) { + if ($data === true || $data === false) { + if ($data === true) { + return 1; + } + return 0; + } else { + return !empty($data); + } + } + +/** + * Inserts multiple values into a table + * + * @param string $table + * @param string $fields + * @param array $values + * @access protected + */ + function insertMulti($table, $fields, $values) { + $table = $this->fullTableName($table); + if (is_array($fields)) { + $fields = implode(', ', array_map(array(&$this, 'name'), $fields)); + } + $count = count($values); + for ($x = 0; $x < $count; $x++) { + $this->query("INSERT INTO {$table} ({$fields}) VALUES {$values[$x]}"); + } + } + +/** + * Returns an array of the indexes in given datasource name. + * + * @param string $model Name of model to inspect + * @return array Fields in table. Keys are column and unique + * @access public + */ + function index($model) { + return false; + } + +/** + * Generate a database-native schema for the given Schema object + * + * @param object $schema An instance of a subclass of CakeSchema + * @param string $tableName Optional. If specified only the table name given will be generated. + * Otherwise, all tables defined in the schema are generated. + * @return string + * @access public + */ + function createSchema($schema, $tableName = null) { + if (!is_a($schema, 'CakeSchema')) { + trigger_error(__('Invalid schema object', true), E_USER_WARNING); + return null; + } + $out = ''; + + foreach ($schema->tables as $curTable => $columns) { + if (!$tableName || $tableName == $curTable) { + $cols = $colList = $indexes = $tableParameters = array(); + $primary = null; + $table = $this->fullTableName($curTable); + + foreach ($columns as $name => $col) { + if (is_string($col)) { + $col = array('type' => $col); + } + if (isset($col['key']) && $col['key'] == 'primary') { + $primary = $name; + } + if ($name !== 'indexes' && $name !== 'tableParameters') { + $col['name'] = $name; + if (!isset($col['type'])) { + $col['type'] = 'string'; + } + $cols[] = $this->buildColumn($col); + } elseif ($name == 'indexes') { + $indexes = array_merge($indexes, $this->buildIndex($col, $table)); + } elseif ($name == 'tableParameters') { + $tableParameters = array_merge($tableParameters, $this->buildTableParameters($col, $table)); + } + } + if (empty($indexes) && !empty($primary)) { + $col = array('PRIMARY' => array('column' => $primary, 'unique' => 1)); + $indexes = array_merge($indexes, $this->buildIndex($col, $table)); + } + $columns = $cols; + $out .= $this->renderStatement('schema', compact('table', 'columns', 'indexes', 'tableParameters')) . "\n\n"; + } + } + return $out; + } + +/** + * Generate a alter syntax from CakeSchema::compare() + * + * @param unknown_type $schema + * @return boolean + */ + function alterSchema($compare, $table = null) { + return false; + } + +/** + * Generate a "drop table" statement for the given Schema object + * + * @param object $schema An instance of a subclass of CakeSchema + * @param string $table Optional. If specified only the table name given will be generated. + * Otherwise, all tables defined in the schema are generated. + * @return string + * @access public + */ + function dropSchema($schema, $table = null) { + if (!is_a($schema, 'CakeSchema')) { + trigger_error(__('Invalid schema object', true), E_USER_WARNING); + return null; + } + $out = ''; + + foreach ($schema->tables as $curTable => $columns) { + if (!$table || $table == $curTable) { + $out .= 'DROP TABLE ' . $this->fullTableName($curTable) . ";\n"; + } + } + return $out; + } + +/** + * Generate a database-native column schema string + * + * @param array $column An array structured like the following: array('name'=>'value', 'type'=>'value'[, options]), + * where options can be 'default', 'length', or 'key'. + * @return string + * @access public + */ + function buildColumn($column) { + $name = $type = null; + extract(array_merge(array('null' => true), $column)); + + if (empty($name) || empty($type)) { + trigger_error(__('Column name or type not defined in schema', true), E_USER_WARNING); + return null; + } + + if (!isset($this->columns[$type])) { + trigger_error(sprintf(__('Column type %s does not exist', true), $type), E_USER_WARNING); + return null; + } + + $real = $this->columns[$type]; + $out = $this->name($name) . ' ' . $real['name']; + + if (isset($real['limit']) || isset($real['length']) || isset($column['limit']) || isset($column['length'])) { + if (isset($column['length'])) { + $length = $column['length']; + } elseif (isset($column['limit'])) { + $length = $column['limit']; + } elseif (isset($real['length'])) { + $length = $real['length']; + } else { + $length = $real['limit']; + } + $out .= '(' . $length . ')'; + } + + if (($column['type'] == 'integer' || $column['type'] == 'float' ) && isset($column['default']) && $column['default'] === '') { + $column['default'] = null; + } + $out = $this->_buildFieldParameters($out, $column, 'beforeDefault'); + + if (isset($column['key']) && $column['key'] == 'primary' && $type == 'integer') { + $out .= ' ' . $this->columns['primary_key']['name']; + } elseif (isset($column['key']) && $column['key'] == 'primary') { + $out .= ' NOT NULL'; + } elseif (isset($column['default']) && isset($column['null']) && $column['null'] == false) { + $out .= ' DEFAULT ' . $this->value($column['default'], $type) . ' NOT NULL'; + } elseif (isset($column['default'])) { + $out .= ' DEFAULT ' . $this->value($column['default'], $type); + } elseif ($type !== 'timestamp' && !empty($column['null'])) { + $out .= ' DEFAULT NULL'; + } elseif ($type === 'timestamp' && !empty($column['null'])) { + $out .= ' NULL'; + } elseif (isset($column['null']) && $column['null'] == false) { + $out .= ' NOT NULL'; + } + if ($type == 'timestamp' && isset($column['default']) && strtolower($column['default']) == 'current_timestamp') { + $out = str_replace(array("'CURRENT_TIMESTAMP'", "'current_timestamp'"), 'CURRENT_TIMESTAMP', $out); + } + $out = $this->_buildFieldParameters($out, $column, 'afterDefault'); + return $out; + } + +/** + * Build the field parameters, in a position + * + * @param string $columnString The partially built column string + * @param array $columnData The array of column data. + * @param string $position The position type to use. 'beforeDefault' or 'afterDefault' are common + * @return string a built column with the field parameters added. + * @access public + */ + function _buildFieldParameters($columnString, $columnData, $position) { + foreach ($this->fieldParameters as $paramName => $value) { + if (isset($columnData[$paramName]) && $value['position'] == $position) { + if (isset($value['options']) && !in_array($columnData[$paramName], $value['options'])) { + continue; + } + $val = $columnData[$paramName]; + if ($value['quote']) { + $val = $this->value($val); + } + $columnString .= ' ' . $value['value'] . $value['join'] . $val; + } + } + return $columnString; + } + +/** + * Format indexes for create table + * + * @param array $indexes + * @param string $table + * @return array + * @access public + */ + function buildIndex($indexes, $table = null) { + $join = array(); + foreach ($indexes as $name => $value) { + $out = ''; + if ($name == 'PRIMARY') { + $out .= 'PRIMARY '; + $name = null; + } else { + if (!empty($value['unique'])) { + $out .= 'UNIQUE '; + } + $name = $this->startQuote . $name . $this->endQuote; + } + if (is_array($value['column'])) { + $out .= 'KEY ' . $name . ' (' . implode(', ', array_map(array(&$this, 'name'), $value['column'])) . ')'; + } else { + $out .= 'KEY ' . $name . ' (' . $this->name($value['column']) . ')'; + } + $join[] = $out; + } + return $join; + } + +/** + * Read additional table parameters + * + * @param array $parameters + * @param string $table + * @return array + * @access public + */ + function readTableParameters($name) { + $parameters = array(); + if ($this->isInterfaceSupported('listDetailedSources')) { + $currentTableDetails = $this->listDetailedSources($name); + foreach ($this->tableParameters as $paramName => $parameter) { + if (!empty($parameter['column']) && !empty($currentTableDetails[$parameter['column']])) { + $parameters[$paramName] = $currentTableDetails[$parameter['column']]; + } + } + } + return $parameters; + } + +/** + * Format parameters for create table + * + * @param array $parameters + * @param string $table + * @return array + * @access public + */ + function buildTableParameters($parameters, $table = null) { + $result = array(); + foreach ($parameters as $name => $value) { + if (isset($this->tableParameters[$name])) { + if ($this->tableParameters[$name]['quote']) { + $value = $this->value($value); + } + $result[] = $this->tableParameters[$name]['value'] . $this->tableParameters[$name]['join'] . $value; + } + } + return $result; + } + +/** + * Guesses the data type of an array + * + * @param string $value + * @return void + * @access public + */ + function introspectType($value) { + if (!is_array($value)) { + if ($value === true || $value === false) { + return 'boolean'; + } + if (is_float($value) && floatval($value) === $value) { + return 'float'; + } + if (is_int($value) && intval($value) === $value) { + return 'integer'; + } + if (is_string($value) && strlen($value) > 255) { + return 'text'; + } + return 'string'; + } + + $isAllFloat = $isAllInt = true; + $containsFloat = $containsInt = $containsString = false; + foreach ($value as $key => $valElement) { + $valElement = trim($valElement); + if (!is_float($valElement) && !preg_match('/^[\d]+\.[\d]+$/', $valElement)) { + $isAllFloat = false; + } else { + $containsFloat = true; + continue; + } + if (!is_int($valElement) && !preg_match('/^[\d]+$/', $valElement)) { + $isAllInt = false; + } else { + $containsInt = true; + continue; + } + $containsString = true; + } + + if ($isAllFloat) { + return 'float'; + } + if ($isAllInt) { + return 'integer'; + } + + if ($containsInt && !$containsString) { + return 'integer'; + } + return 'string'; + } +} diff --git a/code/ryzom/tools/server/www/webtt/cake/libs/model/model.php b/code/ryzom/tools/server/www/webtt/cake/libs/model/model.php index 8906676fd..e6226e0e8 100644 --- a/code/ryzom/tools/server/www/webtt/cake/libs/model/model.php +++ b/code/ryzom/tools/server/www/webtt/cake/libs/model/model.php @@ -760,6 +760,7 @@ class Model extends Overloadable { * @access public */ function setSource($tableName) { +// debug_print_backtrace(); $this->setDataSource($this->useDbConfig); $db =& ConnectionManager::getDataSource($this->useDbConfig); $db->cacheSources = ($this->cacheSources && $db->cacheSources); @@ -2090,7 +2091,6 @@ class Model extends Overloadable { $query = $this->{'_find' . ucfirst($type)}('before', $query); } } - if (!is_numeric($query['page']) || intval($query['page']) < 1) { $query['page'] = 1; } @@ -2123,7 +2123,6 @@ class Model extends Overloadable { if (!$db =& ConnectionManager::getDataSource($this->useDbConfig)) { return false; } - $results = $db->read($this, $query); $this->resetAssociations(); @@ -2132,7 +2131,6 @@ class Model extends Overloadable { } $this->findQueryType = null; - if ($type === 'all') { return $results; } else { diff --git a/code/ryzom/tools/server/www/webtt/cake/libs/router.php b/code/ryzom/tools/server/www/webtt/cake/libs/router.php index 86e77daae..362cef2d2 100644 --- a/code/ryzom/tools/server/www/webtt/cake/libs/router.php +++ b/code/ryzom/tools/server/www/webtt/cake/libs/router.php @@ -465,7 +465,6 @@ class Router { $url = substr($url, 0, strpos($url, '?')); } extract($self->__parseExtension($url)); - for ($i = 0, $len = count($self->routes); $i < $len; $i++) { $route =& $self->routes[$i]; if (($r = $route->parse($url)) !== false) { diff --git a/code/ryzom/tools/server/www/webtt/cake/libs/view/helpers/paginator.php b/code/ryzom/tools/server/www/webtt/cake/libs/view/helpers/paginator.php index df41d5ba1..363ed6e6c 100644 --- a/code/ryzom/tools/server/www/webtt/cake/libs/view/helpers/paginator.php +++ b/code/ryzom/tools/server/www/webtt/cake/libs/view/helpers/paginator.php @@ -536,6 +536,7 @@ class PaginatorHelper extends AppHelper { $options); $paging = $this->params($options['model']); +// var_dump($paging['count']); if ($paging['pageCount'] == 0) { $paging['pageCount'] = 1; } @@ -544,6 +545,7 @@ class PaginatorHelper extends AppHelper { $start = (($paging['page'] - 1) * $paging['options']['limit']) + 1; } $end = $start + $paging['options']['limit'] - 1; + if ($paging['count'] < $end) { $end = $paging['count']; } diff --git a/code/ryzom/tools/server/www/webtt/cake/libs/view/scaffolds/view.ctp b/code/ryzom/tools/server/www/webtt/cake/libs/view/scaffolds/view.ctp index 3669d9ac9..ba14d3a6f 100644 --- a/code/ryzom/tools/server/www/webtt/cake/libs/view/scaffolds/view.ctp +++ b/code/ryzom/tools/server/www/webtt/cake/libs/view/scaffolds/view.ctp @@ -105,6 +105,7 @@ if (empty($associations['hasMany'])) { if (empty($associations['hasAndBelongsToMany'])) { $associations['hasAndBelongsToMany'] = array(); } + $relations = array_merge($associations['hasMany'], $associations['hasAndBelongsToMany']); $i = 0; foreach ($relations as $_alias => $_details): diff --git a/code/ryzom/tools/server/www/webtt/plugins/debug_kit/.gitignore b/code/ryzom/tools/server/www/webtt/plugins/debug_kit/.gitignore new file mode 100644 index 000000000..983a9993d --- /dev/null +++ b/code/ryzom/tools/server/www/webtt/plugins/debug_kit/.gitignore @@ -0,0 +1,15 @@ +*.diff +*.err +*.orig +*.rej +*.swo +*.swp +*.vi +*~ +.DS_Store +.cache +.project +.settings +.svn +errors.err +tags \ No newline at end of file diff --git a/code/ryzom/tools/server/www/webtt/plugins/debug_kit/README.mdown b/code/ryzom/tools/server/www/webtt/plugins/debug_kit/README.mdown new file mode 100644 index 000000000..10a386c7a --- /dev/null +++ b/code/ryzom/tools/server/www/webtt/plugins/debug_kit/README.mdown @@ -0,0 +1,31 @@ +# CakePHP DebugKit + +DebugKit provides a debugging toolbar and enhanced debugging tools for CakePHP applications. + +## Installation + +* Clone/Copy the files in this directory into `app/plugins/debug_kit` +* Include the toolbar component in your `app_controller.php`: + * `var $components = array('DebugKit.Toolbar');` +* Set debug mode to at least 1. +* Make sure to remove the 'sql_dump' element from your layout if you want to experience the awesome that is the debug kit SQL log. + +## Documentation + +Further documentation including additional configuration and ways of extending DebugKit can be found in the [Lighthouse wiki](http://cakephp.lighthouseapp.com/projects/42880-debug-kit/overview) + +## Reporting issues + +If you have an issues with DebugKit please open a ticket on lighthouse http://cakephp.lighthouseapp.com/projects/42880-debug-kit/overview + +## Contributing + +If you'd like to contribute to DebugKit, check out the [Roadmap](http://cakephp.lighthouseapp.com/projects/42880/roadmap) for any planned features. You can fork the project add features and send pull requests, or open tickets on lighthouse. + +## Versions + +DebugKit has several versions, they are compatible with different release of CakePHP. + +* `1.0 -> 1.2` are compatible with CakePHP 1.2.x. These releases of DebugKit will not work with CakePHP 1.3. +* `1.3` is compatible with CakePHP 1.3.x only. It will not work with CakePHP 1.2. + diff --git a/code/ryzom/tools/server/www/webtt/plugins/debug_kit/build.py b/code/ryzom/tools/server/www/webtt/plugins/debug_kit/build.py new file mode 100755 index 000000000..ba75dcf62 --- /dev/null +++ b/code/ryzom/tools/server/www/webtt/plugins/debug_kit/build.py @@ -0,0 +1,130 @@ +#! /usr/bin/env python + +import sys, os +import tarfile, zipfile, gzip, bz2 +from optparse import OptionParser + +""" +Builds packaged releases of DebugKit so I don't have to do things manually. + +Excludes itself (build.py), .gitignore, .DS_Store and the .git folder from the archives. +""" +def main(): + parser = OptionParser(); + parser.add_option('-o', '--output-dir', dest="output_dir", + help="write the packages to DIR", metavar="DIR") + parser.add_option('-p', '--prefix-name', dest="prefix", + help="prefix used for the generated files") + parser.add_option('-k', '--skip', dest="skip", default="", + help="A comma separated list of files to skip") + parser.add_option('-s', '--source-dir', dest="source", default=".", + help="The source directory for the build process") + + (options, args) = parser.parse_args() + + if options.output_dir == '' or options.output_dir == options.source: + print 'Requires an output dir, and that output dir cannot be the same as the source one!' + exit() + + # append .git and build.py to the skip files + skip = options.skip.split(',') + skip.extend(['.git', '.gitignore', '.DS_Store', 'build.py']) + + # get list of files in top level dir. + files = os.listdir(options.source) + + os.chdir(options.source) + + # filter the files, I couldn't figure out how to do it in a more concise way. + for f in files[:]: + try: + skip.index(f) + files.remove(f) + except ValueError: + pass + + # make a boring tar file + destfile = ''.join([options.output_dir, options.prefix]) + tar_file_name = destfile + '.tar' + tar = tarfile.open(tar_file_name, 'w'); + for f in files: + tar.add(f) + tar.close() + print "Generated tar file" + + # make the gzip + if make_gzip(tar_file_name, destfile): + print "Generated gzip file" + else: + print "Could not generate gzip file" + + # make the bz2 + if make_bz2(tar_file_name, destfile): + print "Generated bz2 file" + else: + print "Could not generate bz2 file" + + # make the zip file + zip_recursive(destfile + '.zip', options.source, files) + print "Generated zip file\n" + +def make_gzip(tar_file, destination): + """ + Takes a tar_file and destination. Compressess the tar file and creates + a .tar.gzip + """ + tar_contents = open(tar_file, 'rb') + gzipfile = gzip.open(destination + '.tar.gz', 'wb') + gzipfile.writelines(tar_contents) + gzipfile.close() + tar_contents.close() + return True + +def make_bz2(tar_file, destination): + """ + Takes a tar_file and destination. Compressess the tar file and creates + a .tar.bz2 + """ + tar_contents = open(tar_file, 'rb') + bz2file = bz2.BZ2File(destination + '.tar.bz2', 'wb') + bz2file.writelines(tar_contents) + bz2file.close() + tar_contents.close() + return True + +def zip_recursive(destination, source_dir, rootfiles): + """ + Recursively zips source_dir into destination. + rootfiles should contain a list of files in the top level directory that + are to be included. Any top level files not in rootfiles will be omitted + from the zip file. + """ + zipped = zipfile.ZipFile(destination, 'w', zipfile.ZIP_DEFLATED) + + for root, dirs, files in os.walk(source_dir): + inRoot = False + if root == source_dir: + inRoot = True + + if inRoot: + for d in dirs: + try: + rootfiles.index(d) + except ValueError: + dirs.remove(d) + + for f in files[:]: + if inRoot: + try: + rootfiles.index(f) + except ValueError: + continue + + fullpath = os.path.join(root, f) + zipped.write(fullpath) + zipped.close() + return destination + + +if __name__ == '__main__': + main() \ No newline at end of file diff --git a/code/ryzom/tools/server/www/webtt/plugins/debug_kit/controllers/components/toolbar.php b/code/ryzom/tools/server/www/webtt/plugins/debug_kit/controllers/components/toolbar.php new file mode 100644 index 000000000..1066cf75f --- /dev/null +++ b/code/ryzom/tools/server/www/webtt/plugins/debug_kit/controllers/components/toolbar.php @@ -0,0 +1,700 @@ + false, + 'autoRun' => true + ); + +/** + * Controller instance reference + * + * @var object + */ + var $controller; + +/** + * Components used by DebugToolbar + * + * @var array + */ + var $components = array('RequestHandler', 'Session'); + +/** + * The default panels the toolbar uses. + * which panels are used can be configured when attaching the component + * + * @var array + */ + var $_defaultPanels = array('history', 'session', 'request', 'sqlLog', 'timer', 'log', 'variables'); + +/** + * Loaded panel objects. + * + * @var array + */ + var $panels = array(); + +/** + * javascript files component will be using + * + * @var array + **/ + var $javascript = array( + 'behavior' => '/debug_kit/js/js_debug_toolbar' + ); + +/** + * CacheKey used for the cache file. + * + * @var string + **/ + var $cacheKey = 'toolbar_cache'; + +/** + * Duration of the debug kit history cache + * + * @var string + **/ + var $cacheDuration = '+4 hours'; + +/** + * initialize + * + * If debug is off the component will be disabled and not do any further time tracking + * or load the toolbar helper. + * + * @return bool + **/ + function initialize(&$controller, $settings) { + $this->settings = am($this->settings, $settings); + if (!Configure::read('debug') && empty($this->settings['forceEnable'])) { + $this->enabled = false; + return false; + } + if ($this->settings['autoRun'] == false && !isset($controller->params['url']['debug'])) { + $this->enabled = false; + return false; + } + App::import('Vendor', 'DebugKit.DebugKitDebugger'); + + DebugKitDebugger::setMemoryPoint(__d('debug_kit', 'Component initialization', true)); + DebugKitDebugger::startTimer('componentInit', __d('debug_kit', 'Component initialization and startup', true)); + + $panels = $this->_defaultPanels; + if (isset($settings['panels'])) { + $panels = $this->_makePanelList($settings['panels']); + unset($settings['panels']); + } + + $this->cacheKey .= $this->Session->read('Config.userAgent'); + if (in_array('history', $panels) || (isset($settings['history']) && $settings['history'] !== false)) { + $this->_createCacheConfig(); + } + + $this->_loadPanels($panels, $settings); + + $this->_set($settings); + $this->controller =& $controller; + return false; + } + +/** + * Go through user panels and remove default panels as indicated. + * + * @param array $userPanels The list of panels ther user has added removed. + * @return array Array of panels to use. + **/ + function _makePanelList($userPanels) { + $panels = $this->_defaultPanels; + foreach ($userPanels as $key => $value) { + if (is_numeric($key)) { + $panels[] = $value; + } + if (is_string($key) && $value === false) { + $index = array_search($key, $panels); + if ($index !== false) { + unset($panels[$index]); + } + } + } + return $panels; + } + +/** + * Component Startup + * + * @return bool + **/ + function startup(&$controller) { + $currentViewClass = $controller->view; + $this->_makeViewClass($currentViewClass); + $controller->view = 'DebugKit.Debug'; + $isHtml = ( + !isset($controller->params['url']['ext']) || + (isset($controller->params['url']['ext']) && $controller->params['url']['ext'] == 'html') + ); + + if (!$this->RequestHandler->isAjax() && $isHtml) { + $format = 'Html'; + } else { + $format = 'FirePhp'; + } + $controller->helpers['DebugKit.Toolbar'] = array( + 'output' => sprintf('DebugKit.%sToolbar', $format), + 'cacheKey' => $this->cacheKey, + 'cacheConfig' => 'debug_kit', + 'forceEnable' => $this->settings['forceEnable'], + ); + $panels = array_keys($this->panels); + foreach ($panels as $panelName) { + $this->panels[$panelName]->startup($controller); + } + DebugKitDebugger::stopTimer('componentInit'); + DebugKitDebugger::startTimer('controllerAction', __d('debug_kit', 'Controller action', true)); + DebugKitDebugger::setMemoryPoint(__d('debug_kit', 'Controller action start', true)); + } + +/** + * beforeRedirect callback + * + * @return void + **/ + function beforeRedirect(&$controller) { + if (!class_exists('DebugKitDebugger')) { + return null; + } + DebugKitDebugger::stopTimer('controllerAction'); + $vars = $this->_gatherVars($controller); + $this->_saveState($controller, $vars); + } + +/** + * beforeRender callback + * + * Calls beforeRender on all the panels and set the aggregate to the controller. + * + * @return void + **/ + function beforeRender(&$controller) { + if (!class_exists('DebugKitDebugger')) { + return null; + } + DebugKitDebugger::stopTimer('controllerAction'); + $vars = $this->_gatherVars($controller); + $this->_saveState($controller, $vars); + + $controller->set(array('debugToolbarPanels' => $vars, 'debugToolbarJavascript' => $this->javascript)); + DebugKitDebugger::startTimer('controllerRender', __d('debug_kit', 'Render Controller Action', true)); + DebugKitDebugger::setMemoryPoint(__d('debug_kit', 'Controller render start', true)); + } + +/** + * Load a toolbar state from cache + * + * @param int $key + * @return array + **/ + function loadState($key) { + $history = Cache::read($this->cacheKey, 'debug_kit'); + if (isset($history[$key])) { + return $history[$key]; + } + return array(); + } + +/** + * Create the cache config for the history + * + * @return void + * @access protected + **/ + function _createCacheConfig() { + if (Configure::read('Cache.disable') !== true) { + Cache::config('debug_kit', array( + 'duration' => $this->cacheDuration, + 'engine' => 'File', + 'path' => CACHE + )); + Cache::config('default'); + } + } + +/** + * collects the panel contents + * + * @return array Array of all panel beforeRender() + * @access protected + **/ + function _gatherVars(&$controller) { + $vars = array(); + $panels = array_keys($this->panels); + + foreach ($panels as $panelName) { + $panel =& $this->panels[$panelName]; + $panelName = Inflector::underscore($panelName); + $vars[$panelName]['content'] = $panel->beforeRender($controller); + $elementName = Inflector::underscore($panelName) . '_panel'; + if (isset($panel->elementName)) { + $elementName = $panel->elementName; + } + $vars[$panelName]['elementName'] = $elementName; + $vars[$panelName]['plugin'] = $panel->plugin; + $vars[$panelName]['title'] = $panel->title; + $vars[$panelName]['disableTimer'] = true; + } + return $vars; + } + +/** + * Load Panels used in the debug toolbar + * + * @return void + * @access protected + **/ + function _loadPanels($panels, $settings) { + foreach ($panels as $panel) { + $className = $panel . 'Panel'; + if (!class_exists($className) && !App::import('Vendor', $className)) { + trigger_error(sprintf(__d('debug_kit', 'Could not load DebugToolbar panel %s', true), $panel), E_USER_WARNING); + continue; + } + list($plugin, $className) = pluginSplit($className); + $panelObj =& new $className($settings); + if (is_subclass_of($panelObj, 'DebugPanel') || is_subclass_of($panelObj, 'debugpanel')) { + list(, $panel) = pluginSplit($panel); + $this->panels[$panel] =& $panelObj; + } + } + } +/** + * Makes the DoppleGangerView class if it doesn't already exist. + * This allows DebugView to be compatible with all view classes. + * + * @param string $baseClassName + * @access protected + * @return void + */ + function _makeViewClass($baseClassName) { + if (!class_exists('DoppelGangerView')) { + $parent = strtolower($baseClassName) === 'view' ? false : true; + App::import('View', $baseClassName, $parent); + if (strpos($baseClassName, '.') !== false) { + list($plugin, $baseClassName) = explode('.', $baseClassName); + } + if (strpos($baseClassName, 'View') === false) { + $baseClassName .= 'View'; + } + $class = "class DoppelGangerView extends $baseClassName {}"; + $this->_eval($class); + } + } + +/** + * Method wrapper for eval() for testing uses. + * + * @return void + **/ + function _eval($code) { + eval($code); + } + +/** + * Save the current state of the toolbar varibles to the cache file. + * + * @param object $controller Controller instance + * @param array $vars Vars to save. + * @access protected + * @return void + **/ + function _saveState(&$controller, $vars) { + $config = Cache::config('debug_kit'); + if (empty($config) || !isset($this->panels['history'])) { + return; + } + $history = Cache::read($this->cacheKey, 'debug_kit'); + if (empty($history)) { + $history = array(); + } + if (count($history) == $this->panels['history']->history) { + array_pop($history); + } + unset($vars['history']); + array_unshift($history, $vars); + Cache::write($this->cacheKey, $history, 'debug_kit'); + } +} + +/** + * Debug Panel + * + * Abstract class for debug panels. + * + * @package cake.debug_kit + */ +class DebugPanel extends Object { +/** + * Defines which plugin this panel is from so the element can be located. + * + * @var string + */ + var $plugin = null; + +/** + * Defines the title for displaying on the toolbar. If null, the class name will be used. + * Overriding this allows you to define a custom name in the toolbar. + * + * @var string + */ + var $title = null; + +/** + * Provide a custom element name for this panel. If null, the underscored version of the class + * name will be used. + * + * @var string + */ + var $elementName = null; + +/** + * startup the panel + * + * Pull information from the controller / request + * + * @param object $controller Controller reference. + * @return void + **/ + function startup(&$controller) { } + +/** + * Prepare output vars before Controller Rendering. + * + * @param object $controller Controller reference. + * @return void + **/ + function beforeRender(&$controller) { } +} + +/** + * History Panel + * + * Provides debug information on previous requests. + * + * @package cake.debug_kit.panels + **/ +class HistoryPanel extends DebugPanel { + + var $plugin = 'debug_kit'; + +/** + * Number of history elements to keep + * + * @var string + **/ + var $history = 5; + +/** + * Constructor + * + * @param array $settings Array of settings. + * @return void + **/ + function __construct($settings) { + if (isset($settings['history'])) { + $this->history = $settings['history']; + } + } + +/** + * beforeRender callback function + * + * @return array contents for panel + **/ + function beforeRender(&$controller) { + $cacheKey = $controller->Toolbar->cacheKey; + $toolbarHistory = Cache::read($cacheKey, 'debug_kit'); + $historyStates = array(); + if (is_array($toolbarHistory) && !empty($toolbarHistory)) { + $prefix = array(); + if (!empty($controller->params['prefix'])) { + $prefix[$controller->params['prefix']] = false; + } + foreach ($toolbarHistory as $i => $state) { + if (!isset($state['request']['content']['params']['url']['url'])) { + continue; + } + $historyStates[] = array( + 'title' => $state['request']['content']['params']['url']['url'], + 'url' => array_merge($prefix, array( + 'plugin' => 'debug_kit', + 'controller' => 'toolbar_access', + 'action' => 'history_state', + $i + 1)) + ); + } + } + if (count($historyStates) >= $this->history) { + array_pop($historyStates); + } + return $historyStates; + } +} + +/** + * Variables Panel + * + * Provides debug information on the View variables. + * + * @package cake.debug_kit.panels + **/ +class VariablesPanel extends DebugPanel { + + var $plugin = 'debug_kit'; + +/** + * beforeRender callback + * + * @return array + **/ + function beforeRender(&$controller) { + return array_merge($controller->viewVars, array('$this->data' => $controller->data)); + } +} + +/** + * Session Panel + * + * Provides debug information on the Session contents. + * + * @package cake.debug_kit.panels + **/ +class SessionPanel extends DebugPanel { + + var $plugin = 'debug_kit'; + +/** + * beforeRender callback + * + * @param object $controller + * @access public + * @return array + */ + function beforeRender(&$controller) { + $sessions = $controller->Toolbar->Session->read(); + return $sessions; + } +} + +/** + * Request Panel + * + * Provides debug information on the Current request params. + * + * @package cake.debug_kit.panels + **/ +class RequestPanel extends DebugPanel { + + var $plugin = 'debug_kit'; + +/** + * beforeRender callback - grabs request params + * + * @return array + **/ + function beforeRender(&$controller) { + $out = array(); + $out['params'] = $controller->params; + if (isset($controller->Cookie)) { + $out['cookie'] = $controller->Cookie->read(); + } + $out['get'] = $_GET; + $out['currentRoute'] = Router::currentRoute(); + return $out; + } +} + +/** + * Timer Panel + * + * Provides debug information on all timers used in a request. + * + * @package cake.debug_kit.panels + **/ +class TimerPanel extends DebugPanel { + + var $plugin = 'debug_kit'; + +/** + * startup - add in necessary helpers + * + * @return void + **/ + function startup(&$controller) { + if (!in_array('Number', $controller->helpers)) { + $controller->helpers[] = 'Number'; + } + if (!in_array('SimpleGraph', $controller->helpers)) { + $controller->helpers[] = 'DebugKit.SimpleGraph'; + } + } +} + +/** + * SqlLog Panel + * + * Provides debug information on the SQL logs and provides links to an ajax explain interface. + * + * @package cake.debug_kit.panels + **/ +class SqlLogPanel extends DebugPanel { + + var $plugin = 'debug_kit'; + +/** + * Minimum number of Rows Per Millisecond that must be returned by a query before an explain + * is done. + * + * @var int + **/ + var $slowRate = 20; + +/** + * Gets the connection names that should have logs + dumps generated. + * + * @param string $controller + * @access public + * @return void + */ + function beforeRender(&$controller) { + if (!class_exists('ConnectionManager')) { + return array(); + } + $connections = array(); + + $dbConfigs = ConnectionManager::sourceList(); + foreach ($dbConfigs as $configName) { + $driver = null; + $db =& ConnectionManager::getDataSource($configName); + if ( + (empty($db->config['driver']) && empty($db->config['datasource'])) || + !$db->isInterfaceSupported('getLog') + ) { + continue; + } + + if (isset($db->config['driver'])) { + $driver = $db->config['driver']; + } + if (empty($driver) && isset($db->config['datasource'])) { + $driver = $db->config['datasource']; + } + $explain = false; + $isExplainable = ($driver === 'mysql' || $driver === 'mysqli' || $driver === 'postgres'); + if ($isExplainable) { + $explain = true; + } + $connections[$configName] = $explain; + } + return array('connections' => $connections, 'threshold' => $this->slowRate); + } +} + +/** + * Log Panel - Reads log entries made this request. + * + * @package cake.debug_kit.panels + */ +class LogPanel extends DebugPanel { + + var $plugin = 'debug_kit'; + +/** + * Constructor - sets up the log listener. + * + * @return void + */ + function __construct($settings) { + parent::__construct(); + if (!class_exists('CakeLog')) { + App::import('Core', 'CakeLog'); + } + $existing = CakeLog::configured(); + if (empty($existing)) { + CakeLog::config('default', array( + 'engine' => 'FileLog' + )); + } + CakeLog::config('debug_kit_log_panel', array( + 'engine' => 'DebugKitLogListener', + 'panel' => $this + )); + } + +/** + * beforeRender Callback + * + * @return array + **/ + function beforeRender(&$controller) { + $logs = $this->logger->logs; + return $logs; + } +} + +/** + * A CakeLog listener which saves having to munge files or other configured loggers. + * + * @package debug_kit.components + */ +class DebugKitLogListener { + + var $logs = array(); + +/** + * Makes the reverse link needed to get the logs later. + * + * @return void + */ + function DebugKitLogListener($options) { + $options['panel']->logger =& $this; + } + +/** + * Captures log messages in memory + * + * @return void + */ + function write($type, $message) { + if (!isset($this->logs[$type])) { + $this->logs[$type] = array(); + } + $this->logs[$type][] = array(date('Y-m-d H:i:s'), $message); + } +} + diff --git a/code/ryzom/tools/server/www/webtt/plugins/debug_kit/controllers/toolbar_access_controller.php b/code/ryzom/tools/server/www/webtt/plugins/debug_kit/controllers/toolbar_access_controller.php new file mode 100644 index 000000000..5e6afdf31 --- /dev/null +++ b/code/ryzom/tools/server/www/webtt/plugins/debug_kit/controllers/toolbar_access_controller.php @@ -0,0 +1,111 @@ + array('output' => 'DebugKit.HtmlToolbar'), + 'Javascript', 'Number', 'DebugKit.SimpleGraph' + ); + +/** + * Components + * + * @var array + **/ + var $components = array('RequestHandler', 'DebugKit.Toolbar'); + +/** + * Uses + * + * @var array + **/ + var $uses = array('DebugKit.ToolbarAccess'); + +/** + * beforeFilter callback + * + * @return void + **/ + function beforeFilter() { + parent::beforeFilter(); + if (isset($this->Toolbar)) { + $this->Toolbar->enabled = false; + } + $this->helpers['DebugKit.Toolbar']['cacheKey'] = $this->Toolbar->cacheKey; + $this->helpers['DebugKit.Toolbar']['cacheConfig'] = 'debug_kit'; + } + +/** + * Get a stored history state from the toolbar cache. + * + * @return void + **/ + function history_state($key = null) { + if (Configure::read('debug') == 0) { + return $this->redirect($this->referer()); + } + $oldState = $this->Toolbar->loadState($key); + $this->set('toolbarState', $oldState); + $this->set('debugKitInHistoryMode', true); + } + +/** + * Run SQL explain/profiling on queries. Checks the hash + the hashed queries, + * if there is mismatch a 404 will be rendered. If debug == 0 a 404 will also be + * rendered. No explain will be run if a 404 is made. + * + * @return void + */ + function sql_explain() { + if ( + !$this->RequestHandler->isPost() || + empty($this->data['log']['sql']) || + empty($this->data['log']['ds']) || + empty($this->data['log']['hash']) || + Configure::read('debug') == 0 + ) { + $this->cakeError('error404', array(array( + 'message' => 'Invalid parameters' + ))); + } + App::import('Core', 'Security'); + $hash = Security::hash($this->data['log']['sql'] . $this->data['log']['ds'], null, true); + if ($hash !== $this->data['log']['hash']) { + $this->cakeError('error404', array(array( + 'message' => 'Invalid parameters' + ))); + } + $result = $this->ToolbarAccess->explainQuery($this->data['log']['ds'], $this->data['log']['sql']); + $this->set(compact('result')); + } +} \ No newline at end of file diff --git a/code/ryzom/tools/server/www/webtt/plugins/debug_kit/debug_kit_app_controller.php b/code/ryzom/tools/server/www/webtt/plugins/debug_kit/debug_kit_app_controller.php new file mode 100644 index 000000000..3592cb5ed --- /dev/null +++ b/code/ryzom/tools/server/www/webtt/plugins/debug_kit/debug_kit_app_controller.php @@ -0,0 +1,22 @@ + +# No version information was available in the source files. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: debug_kit-\n" +"POT-Creation-Date: 2009-05-27 09:47+0200\n" +"PO-Revision-Date: YYYY-mm-DD HH:MM+ZZZZ\n" +"Last-Translator: Andy Dawson \n" +"Language-Team:\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=utf-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Poedit-Basepath: ../../../\n" + +#: controllers/components/toolbar.php:91 +msgid "Component initialization and startup" +msgstr "" + +#: controllers/components/toolbar.php:140 +msgid "Controller Action" +msgstr "" + +#: controllers/components/toolbar.php:167 +msgid "Render Controller Action" +msgstr "" + +#: controllers/components/toolbar.php:231 +msgid "Could not load DebugToolbar panel %s" +msgstr "" + +#: views/elements/debug_toolbar.ctp:25 +msgid "There are no active panels. You must enable a panel to see its output." +msgstr "" + +#: views/elements/history_panel.ctp:21 +msgid "Request History" +msgstr "" + +#: views/elements/history_panel.ctp:23 +msgid "No previous requests logged." +msgstr "" + +#: views/elements/history_panel.ctp:25 +msgid "previous requests available" +msgstr "" + +#: views/elements/history_panel.ctp:27 +msgid "Restore to current request" +msgstr "" + +#: views/elements/log_panel.ctp:21 +msgid "Logs" +msgstr "" + +#: views/elements/log_panel.ctp:28 +msgid "Time" +msgstr "" + +#: views/elements/log_panel.ctp:28 +#: views/elements/timer_panel.ctp:54 +msgid "Message" +msgstr "" + +#: views/elements/log_panel.ctp:37 +msgid "There were no log entries made this request" +msgstr "" + +#: views/elements/request_panel.ctp:21 +msgid "Request" +msgstr "" + +#: views/elements/request_panel.ctp:35 +msgid "Current Route" +msgstr "" + +#: views/elements/session_panel.ctp:21 +msgid "Session" +msgstr "" + +#: views/elements/sql_log_panel.ctp:21 +msgid "Sql Logs" +msgstr "" + +#: views/elements/sql_log_panel.ctp:31 +msgid "toggle (%s) query explains for %s" +msgstr "" + +#: views/elements/sql_log_panel.ctp:39 +msgid "No slow queries!, or your database does not support EXPLAIN" +msgstr "" + +#: views/elements/sql_log_panel.ctp:44 +msgid "No active database connections" +msgstr "" + +#: views/elements/timer_panel.ctp:33 +msgid "Memory" +msgstr "" + +#: views/elements/timer_panel.ctp:35 +msgid "Current Memory Use" +msgstr "" + +#: views/elements/timer_panel.ctp:39 +msgid "Peak Memory Use" +msgstr "" + +#: views/elements/timer_panel.ctp:43 +msgid "Timers" +msgstr "" + +#: views/elements/timer_panel.ctp:45 +msgid "%s (ms)" +msgstr "" + +#: views/elements/timer_panel.ctp:46 +msgid "Total Request Time:" +msgstr "" + +#: views/elements/timer_panel.ctp:54 +msgid "Time in ms" +msgstr "" + +#: views/elements/timer_panel.ctp:54 +msgid "Graph" +msgstr "" + +#: views/elements/variables_panel.ctp:21 +msgid "View Variables" +msgstr "" + +#: views/helpers/simple_graph.php:79 +msgid "Starting %sms into the request, taking %sms" +msgstr "" + diff --git a/code/ryzom/tools/server/www/webtt/plugins/debug_kit/locale/eng/LC_MESSAGES/debug_kit.po b/code/ryzom/tools/server/www/webtt/plugins/debug_kit/locale/eng/LC_MESSAGES/debug_kit.po new file mode 100644 index 000000000..9aec83297 --- /dev/null +++ b/code/ryzom/tools/server/www/webtt/plugins/debug_kit/locale/eng/LC_MESSAGES/debug_kit.po @@ -0,0 +1,135 @@ +# LANGUAGE translation of CakePHP Application +# Copyright YEAR NAME +# No version information was available in the source files. +# +#, fuzzy +msgid "" +msgstr "Project-Id-Version: PROJECT VERSION\n" + "POT-Creation-Date: 2009-05-27 09:47+0200\n" + "PO-Revision-Date: YYYY-mm-DD HH:MM+ZZZZ\n" + "Last-Translator: NAME \n" + "Language-Team: LANGUAGE \n" + "MIME-Version: 1.0\n" + "Content-Type: text/plain; charset=UTF-8\n" + "Content-Transfer-Encoding: 8bit\n" + "Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n" + +#: controllers/components/toolbar.php:91 +msgid "Component initialization and startup" +msgstr "" + +#: controllers/components/toolbar.php:140 +msgid "Controller Action" +msgstr "" + +#: controllers/components/toolbar.php:167 +msgid "Render Controller Action" +msgstr "" + +#: controllers/components/toolbar.php:231 +msgid "Could not load DebugToolbar panel %s" +msgstr "" + +#: views/elements/debug_toolbar.ctp:25 +msgid "There are no active panels. You must enable a panel to see its output." +msgstr "" + +#: views/elements/history_panel.ctp:21 +msgid "Request History" +msgstr "" + +#: views/elements/history_panel.ctp:23 +msgid "No previous requests logged." +msgstr "" + +#: views/elements/history_panel.ctp:25 +msgid "previous requests available" +msgstr "" + +#: views/elements/history_panel.ctp:27 +msgid "Restore to current request" +msgstr "" + +#: views/elements/log_panel.ctp:21 +msgid "Logs" +msgstr "" + +#: views/elements/log_panel.ctp:28 +msgid "Time" +msgstr "" + +#: views/elements/log_panel.ctp:28 views/elements/timer_panel.ctp:54 +msgid "Message" +msgstr "" + +#: views/elements/log_panel.ctp:37 +msgid "There were no log entries made this request" +msgstr "" + +#: views/elements/request_panel.ctp:21 +msgid "Request" +msgstr "" + +#: views/elements/request_panel.ctp:35 +msgid "Current Route" +msgstr "" + +#: views/elements/session_panel.ctp:21 +msgid "Session" +msgstr "" + +#: views/elements/sql_log_panel.ctp:21 +msgid "Sql Logs" +msgstr "" + +#: views/elements/sql_log_panel.ctp:31 +msgid "toggle (%s) query explains for %s" +msgstr "" + +#: views/elements/sql_log_panel.ctp:39 +msgid "No slow queries!, or your database does not support EXPLAIN" +msgstr "" + +#: views/elements/sql_log_panel.ctp:44 +msgid "No active database connections" +msgstr "" + +#: views/elements/timer_panel.ctp:33 +msgid "Memory" +msgstr "" + +#: views/elements/timer_panel.ctp:35 +msgid "Current Memory Use" +msgstr "" + +#: views/elements/timer_panel.ctp:39 +msgid "Peak Memory Use" +msgstr "" + +#: views/elements/timer_panel.ctp:43 +msgid "Timers" +msgstr "" + +#: views/elements/timer_panel.ctp:45 +msgid "%s (ms)" +msgstr "" + +#: views/elements/timer_panel.ctp:46 +msgid "Total Request Time:" +msgstr "" + +#: views/elements/timer_panel.ctp:54 +msgid "Time in ms" +msgstr "" + +#: views/elements/timer_panel.ctp:54 +msgid "Graph" +msgstr "" + +#: views/elements/variables_panel.ctp:21 +msgid "View Variables" +msgstr "" + +#: views/helpers/simple_graph.php:79 +msgid "Starting %sms into the request, taking %sms" +msgstr "" diff --git a/code/ryzom/tools/server/www/webtt/plugins/debug_kit/locale/spa/LC_MESSAGES/debug_kit.po b/code/ryzom/tools/server/www/webtt/plugins/debug_kit/locale/spa/LC_MESSAGES/debug_kit.po new file mode 100644 index 000000000..0833a4942 --- /dev/null +++ b/code/ryzom/tools/server/www/webtt/plugins/debug_kit/locale/spa/LC_MESSAGES/debug_kit.po @@ -0,0 +1,135 @@ +# LANGUAGE translation of CakePHP Application +# Copyright YEAR NAME +# No version information was available in the source files. +# +#, fuzzy +msgid "" +msgstr "Project-Id-Version: PROJECT VERSION\n" + "POT-Creation-Date: 2009-05-27 09:47+0200\n" + "PO-Revision-Date: YYYY-mm-DD HH:MM+ZZZZ\n" + "Last-Translator: NAME \n" + "Language-Team: LANGUAGE \n" + "MIME-Version: 1.0\n" + "Content-Type: text/plain; charset=UTF-8\n" + "Content-Transfer-Encoding: 8bit\n" + "Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n" + +#: controllers/components/toolbar.php:91 +msgid "Component initialization and startup" +msgstr "" + +#: controllers/components/toolbar.php:140 +msgid "Controller Action" +msgstr "" + +#: controllers/components/toolbar.php:167 +msgid "Render Controller Action" +msgstr "" + +#: controllers/components/toolbar.php:231 +msgid "Could not load DebugToolbar panel %s" +msgstr "" + +#: views/elements/debug_toolbar.ctp:25 +msgid "There are no active panels. You must enable a panel to see its output." +msgstr "" + +#: views/elements/history_panel.ctp:21 +msgid "Request History" +msgstr "" + +#: views/elements/history_panel.ctp:23 +msgid "No previous requests logged." +msgstr "" + +#: views/elements/history_panel.ctp:25 +msgid "previous requests available" +msgstr "" + +#: views/elements/history_panel.ctp:27 +msgid "Restore to current request" +msgstr "" + +#: views/elements/log_panel.ctp:21 +msgid "Logs" +msgstr "" + +#: views/elements/log_panel.ctp:28 +msgid "Time" +msgstr "" + +#: views/elements/log_panel.ctp:28 views/elements/timer_panel.ctp:54 +msgid "Message" +msgstr "" + +#: views/elements/log_panel.ctp:37 +msgid "There were no log entries made this request" +msgstr "" + +#: views/elements/request_panel.ctp:21 +msgid "Request" +msgstr "" + +#: views/elements/request_panel.ctp:35 +msgid "Current Route" +msgstr "" + +#: views/elements/session_panel.ctp:21 +msgid "Session" +msgstr "" + +#: views/elements/sql_log_panel.ctp:21 +msgid "Sql Logs" +msgstr "" + +#: views/elements/sql_log_panel.ctp:31 +msgid "toggle (%s) query explains for %s" +msgstr "" + +#: views/elements/sql_log_panel.ctp:39 +msgid "No slow queries!, or your database does not support EXPLAIN" +msgstr "" + +#: views/elements/sql_log_panel.ctp:44 +msgid "No active database connections" +msgstr "" + +#: views/elements/timer_panel.ctp:33 +msgid "Memory" +msgstr "" + +#: views/elements/timer_panel.ctp:35 +msgid "Current Memory Use" +msgstr "" + +#: views/elements/timer_panel.ctp:39 +msgid "Peak Memory Use" +msgstr "" + +#: views/elements/timer_panel.ctp:43 +msgid "Timers" +msgstr "" + +#: views/elements/timer_panel.ctp:45 +msgid "%s (ms)" +msgstr "" + +#: views/elements/timer_panel.ctp:46 +msgid "Total Request Time:" +msgstr "" + +#: views/elements/timer_panel.ctp:54 +msgid "Time in ms" +msgstr "" + +#: views/elements/timer_panel.ctp:54 +msgid "Graph" +msgstr "" + +#: views/elements/variables_panel.ctp:21 +msgid "View Variables" +msgstr "" + +#: views/helpers/simple_graph.php:79 +msgid "Starting %sms into the request, taking %sms" +msgstr "" \ No newline at end of file diff --git a/code/ryzom/tools/server/www/webtt/plugins/debug_kit/models/behaviors/timed.php b/code/ryzom/tools/server/www/webtt/plugins/debug_kit/models/behaviors/timed.php new file mode 100644 index 000000000..28eadec74 --- /dev/null +++ b/code/ryzom/tools/server/www/webtt/plugins/debug_kit/models/behaviors/timed.php @@ -0,0 +1,105 @@ +settings[$Model->alias] = array_merge($this->_defaults, $settings); + } else { + $this->settings[$Model->alias] = $this->_defaults; + } + } + +/** + * beforeFind, starts a timer for a find operation. + * + * @param Model $Model + * @param array $queryData Array of query data (not modified) + * @return boolean true + */ + function beforeFind(&$Model, $queryData){ + DebugKitDebugger::startTimer($Model->alias . '_find', $Model->alias . '->find()'); + return true; + } + +/** + * afterFind, stops a timer for a find operation. + * + * @param Model $Model + * @param array $results Array of results + * @return boolean true. + */ + function afterFind(&$Model, $results){ + DebugKitDebugger::stopTimer($Model->alias . '_find'); + return true; + } + +/** + * beforeSave, starts a time before a save is initiated. + * + * @param Model $Model + * @return boolean true + */ + function beforeSave(&$Model){ + DebugKitDebugger::startTimer($Model->alias . '_save', $Model->alias . '->save()'); + return true; + } + +/** + * afterSave, stop the timer started from a save. + * + * @param string $Model + * @param string $created + * @return void + */ + function afterSave(&$Model, $created) { + DebugKitDebugger::stopTimer($Model->alias . '_save'); + return true; + } + } + diff --git a/code/ryzom/tools/server/www/webtt/plugins/debug_kit/models/toolbar_access.php b/code/ryzom/tools/server/www/webtt/plugins/debug_kit/models/toolbar_access.php new file mode 100644 index 000000000..ab1fea99b --- /dev/null +++ b/code/ryzom/tools/server/www/webtt/plugins/debug_kit/models/toolbar_access.php @@ -0,0 +1,56 @@ +config['driver']; + + $return = array(); + if ($driver === 'mysqli' || $driver === 'mysql' || $driver === 'postgres') { + $explained = $db->query('EXPLAIN ' . $query); + if ($driver === 'postgres') { + $queryPlan = array(); + foreach ($explained as $postgreValue) { + $queryPlan[] = array($postgreValue[0]['QUERY PLAN']); + } + $return = array_merge(array(array('')), $queryPlan); + } else { + $keys = array_keys($explained[0][0]); + foreach ($explained as $mysqlValue) { + $queryPlan[] = array_values($mysqlValue[0]); + } + $return = array_merge(array($keys), $queryPlan); + } + } + return $return; + } +} \ No newline at end of file diff --git a/code/ryzom/tools/server/www/webtt/plugins/debug_kit/tests/cases/behaviors/timed.test.php b/code/ryzom/tools/server/www/webtt/plugins/debug_kit/tests/cases/behaviors/timed.test.php new file mode 100644 index 000000000..3fbbd614b --- /dev/null +++ b/code/ryzom/tools/server/www/webtt/plugins/debug_kit/tests/cases/behaviors/timed.test.php @@ -0,0 +1,77 @@ +Article =& new Model(array('ds' => 'test_suite', 'table' => 'articles', 'name' => 'Article')); + $this->Article->Behaviors->attach('DebugKit.Timed'); + } + +/** + * end a test + * + * @return void + */ + function endTest() { + unset($this->Article); + ClassRegistry::flush(); + DebugKitDebugger::clearTimers(); + } + +/** + * test find timers + * + * @return void + */ + function testFindTimers() { + $timers = DebugKitDebugger::getTimers(false); + $this->assertEqual(count($timers), 1); + + $this->Article->find('all'); + $result = DebugKitDebugger::getTimers(false); + $this->assertEqual(count($result), 2); + + $this->Article->find('all'); + $result = DebugKitDebugger::getTimers(false); + $this->assertEqual(count($result), 3); + } + +/** + * test save timers + * + * @return void + */ + function testSaveTimers() { + $timers = DebugKitDebugger::getTimers(false); + $this->assertEqual(count($timers), 1); + + $this->Article->save(array('user_id' => 1, 'title' => 'test', 'body' => 'test')); + $result = DebugKitDebugger::getTimers(false); + $this->assertEqual(count($result), 2); + } +} \ No newline at end of file diff --git a/code/ryzom/tools/server/www/webtt/plugins/debug_kit/tests/cases/controllers/components/toolbar.test.php b/code/ryzom/tools/server/www/webtt/plugins/debug_kit/tests/cases/controllers/components/toolbar.test.php new file mode 100644 index 000000000..05f464ed6 --- /dev/null +++ b/code/ryzom/tools/server/www/webtt/plugins/debug_kit/tests/cases/controllers/components/toolbar.test.php @@ -0,0 +1,580 @@ +_loadPanels($panels, $settings); + } + + function _eval($code) { + if ($this->evalTest) { + $this->evalCode = $code; + return; + } + eval($code); + } +} + +Mock::generate('DebugPanel'); + +if (!class_exists('AppController')) { + class AppController extends Controller { + + } +} + +class TestPanel extends DebugPanel { + +} + +/** +* DebugToolbar Test case +*/ +class DebugToolbarTestCase extends CakeTestCase { +/** + * fixtures. + * + * @var array + **/ + var $fixtures = array('core.article'); +/** + * Start test callback + * + * @access public + * @return void + **/ + function startTest() { + Router::connect('/', array('controller' => 'pages', 'action' => 'display', 'home')); + $this->Controller =& new Controller(); + $this->Controller->params = Router::parse('/'); + $this->Controller->params['url']['url'] = '/'; + $this->Controller->uses = array(); + $this->Controller->components = array('TestToolBar'); + $this->Controller->constructClasses(); + $this->Controller->Toolbar =& $this->Controller->TestToolBar; + + $this->_server = $_SERVER; + $this->_paths = array(); + $this->_paths['plugins'] = App::path('plugins'); + $this->_paths['views'] = App::path('views'); + $this->_paths['vendors'] = App::path('vendors'); + $this->_paths['controllers'] = App::path('controllers'); + Configure::write('Cache.disable', false); + } +/** + * endTest + * + * @return void + **/ + function endTest() { + $_SERVER = $this->_server; + App::build(array( + 'plugins' => $this->_paths['plugins'], + 'views' => $this->_paths['views'], + 'controllers' => $this->_paths['controllers'], + 'vendors' => $this->_paths['vendors'] + ), true); + Configure::write('Cache.disable', true); + + unset($this->Controller); + if (class_exists('DebugKitDebugger')) { + DebugKitDebugger::clearTimers(); + DebugKitDebugger::clearMemoryPoints(); + } + } +/** + * test Loading of panel classes + * + * @return void + **/ + function testLoadPanels() { + $this->Controller->Toolbar->loadPanels(array('session', 'request')); + $this->assertTrue(is_a($this->Controller->Toolbar->panels['session'], 'SessionPanel')); + $this->assertTrue(is_a($this->Controller->Toolbar->panels['request'], 'RequestPanel')); + + $this->Controller->Toolbar->loadPanels(array('history'), array('history' => 10)); + $this->assertEqual($this->Controller->Toolbar->panels['history']->history, 10); + + $this->expectError(); + $this->Controller->Toolbar->loadPanels(array('randomNonExisting', 'request')); + } +/** + * test Loading of panel classes from a plugin + * + * @return void + **/ + function testLoadPluginPanels() { + $this->Controller->Toolbar->loadPanels(array('plugin.test')); + $this->assertTrue(is_a($this->Controller->Toolbar->panels['test'], 'TestPanel')); + } +/** + * test generating a DoppelGangerView with a pluginView. + * + * If $this->Controller->Toolbar->startup() has been previously called, + * DoppelGangerView class has already been defined. + * + * @return void + **/ + function testPluginViewParsing() { + if (class_exists('DoppelGangerView')) { + $this->skipIf(true, 'Class DoppelGangerView already defined, skipping %s'); + return; + } + App::import('Vendor', 'DebugKit.DebugKitDebugger'); + $this->Controller->Toolbar->evalTest = true; + $this->Controller->view = 'Plugin.OtherView'; + $this->Controller->Toolbar->startup($this->Controller); + $this->assertPattern('/class DoppelGangerView extends OtherView/', $this->Controller->Toolbar->evalCode); + } +/** + * test loading of vendor panels from test_app folder + * + * @access public + * @return void + */ + function testVendorPanels() { + $debugKitPath = App::pluginPath('DebugKit'); + $noDir = (empty($debugKitPath) || !file_exists($debugKitPath)); + $skip = $this->skipIf($noDir, 'Could not find debug_kit in plugin paths, skipping %s'); + if ($skip) { + return; + } + + App::build(array( + 'vendors' => array($debugKitPath . 'tests' . DS . 'test_app' . DS . 'vendors' . DS) + )); + $this->Controller->components = array( + 'DebugKit.Toolbar' => array( + 'panels' => array('test'), + ) + ); + $this->Controller->Component->init($this->Controller); + $this->Controller->Component->initialize($this->Controller); + $this->Controller->Component->startup($this->Controller); + $this->assertTrue(isset($this->Controller->Toolbar->panels['test'])); + $this->assertTrue(is_a($this->Controller->Toolbar->panels['test'], 'TestPanel')); + } +/** + * test initialize + * + * @return void + * @access public + **/ + function testInitialize() { + $this->Controller->components = array('DebugKit.Toolbar'); + $this->Controller->Component->init($this->Controller); + $this->Controller->Component->initialize($this->Controller); + + $this->assertFalse(empty($this->Controller->Toolbar->panels)); + + $timers = DebugKitDebugger::getTimers(); + $this->assertTrue(isset($timers['componentInit'])); + $memory = DebugKitDebugger::getMemoryPoints(); + $this->assertTrue(isset($memory['Component initialization'])); + } +/** + * test initialize w/ custom panels and defaults + * + * @return void + * @access public + **/ + function testInitializeCustomPanelsWithDefaults() { + $this->Controller->components = array( + 'DebugKit.Toolbar' => array('panels' => array('test')) + ); + $this->Controller->Component->init($this->Controller); + $this->Controller->Component->initialize($this->Controller); + + $expected = array('history', 'session', 'request', 'sqlLog', 'timer', 'log', 'variables', 'test'); + $this->assertEqual($expected, array_keys($this->Controller->Toolbar->panels)); + } + +/** + * test syntax for removing panels + * + * @return void + **/ + function testInitializeRemovingPanels() { + unset($this->Controller->Toolbar); + $this->Controller->components = array( + 'DebugKit.Toolbar' => array('panels' => array('session' => false, 'history' => false, 'test')) + ); + $this->Controller->Component->init($this->Controller); + $this->Controller->Component->initialize($this->Controller); + + $expected = array('request', 'sqlLog', 'timer', 'log', 'variables', 'test'); + $this->assertEqual($expected, array_keys($this->Controller->Toolbar->panels)); + } +/** + * ensure that enabled = false when debug == 0 on initialize + * + * @return void + **/ + function testDebugDisableOnInitialize() { + $_debug = Configure::read('debug'); + Configure::write('debug', 0); + $this->Controller->components = array('DebugKit.Toolbar'); + $this->Controller->Component->init($this->Controller); + $this->Controller->Component->initialize($this->Controller); + $this->assertFalse($this->Controller->Toolbar->enabled); + + Configure::write('debug', $_debug); + } +/** + * test that passing in forceEnable will enable the toolbar even if debug = 0 + * + * @return void + **/ + function testForceEnable() { + unset($this->Controller->Toolbar); + $_debug = Configure::read('debug'); + Configure::write('debug', 0); + $this->Controller->components = array('DebugKit.Toolbar' => array('forceEnable' => true)); + $this->Controller->Component->init($this->Controller); + $this->Controller->Component->initialize($this->Controller); + $this->assertTrue($this->Controller->Toolbar->enabled); + + Configure::write('debug', $_debug); + } +/** + * Test disabling autoRunning of toolbar + * + * @return void + **/ + function testAutoRunSettingFalse() { + $this->Controller->components = array('DebugKit.Toolbar' => array('autoRun' => false)); + $this->Controller->Component->init($this->Controller); + $this->Controller->Component->initialize($this->Controller); + $this->assertFalse($this->Controller->Toolbar->enabled); + } +/** + * test autorun = false with query string param + * + * @return void + **/ + function testAutoRunSettingWithQueryString() { + $this->Controller->params['url']['debug'] = true; + $this->Controller->components = array('DebugKit.Toolbar' => array('autoRun' => false)); + $this->Controller->Component->init($this->Controller); + $this->Controller->Component->initialize($this->Controller); + $this->assertTrue($this->Controller->Toolbar->enabled); + } +/** + * test startup + * + * @return void + **/ + function testStartup() { + $this->Controller->components = array( + 'DebugKit.Toolbar' => array( + 'panels' => array('MockDebug') + ) + ); + $this->Controller->Component->init($this->Controller); + $this->Controller->Component->initialize($this->Controller); + $this->Controller->Toolbar->panels['MockDebug']->expectOnce('startup'); + $this->Controller->Toolbar->startup($this->Controller); + + $this->assertEqual($this->Controller->view, 'DebugKit.Debug'); + $this->assertTrue(isset($this->Controller->helpers['DebugKit.Toolbar'])); + + $this->assertEqual($this->Controller->helpers['DebugKit.Toolbar']['output'], 'DebugKit.HtmlToolbar'); + $this->assertEqual($this->Controller->helpers['DebugKit.Toolbar']['cacheConfig'], 'debug_kit'); + $this->assertTrue(isset($this->Controller->helpers['DebugKit.Toolbar']['cacheKey'])); + + $timers = DebugKitDebugger::getTimers(); + $this->assertTrue(isset($timers['controllerAction'])); + $memory = DebugKitDebugger::getMemoryPoints(); + $this->assertTrue(isset($memory['Controller action start'])); + } +/** + * Test that cache config generation works. + * + * @return void + **/ + function testCacheConfigGeneration() { + $this->Controller->components = array('DebugKit.Toolbar'); + $this->Controller->Component->init($this->Controller); + $this->Controller->Component->initialize($this->Controller); + $this->Controller->Component->startup($this->Controller); + + $results = Cache::config('debug_kit'); + $this->assertTrue(is_array($results)); + } +/** + * test state saving of toolbar + * + * @return void + **/ + function testStateSaving() { + $this->Controller->components = array('DebugKit.Toolbar'); + $this->Controller->Component->init($this->Controller); + $this->Controller->Component->initialize($this->Controller); + $configName = 'debug_kit'; + $this->Controller->Toolbar->cacheKey = 'toolbar_history'; + + $this->Controller->Component->startup($this->Controller); + $this->Controller->set('test', 'testing'); + $this->Controller->Component->beforeRender($this->Controller); + + $result = Cache::read('toolbar_history', $configName); + $this->assertEqual($result[0]['variables']['content']['test'], 'testing'); + Cache::delete('toolbar_history', $configName); + } +/** + * Test Before Render callback + * + * @return void + **/ + function testBeforeRender() { + $this->Controller->components = array( + 'DebugKit.Toolbar' => array( + 'panels' => array('MockDebug', 'session') + ) + ); + $this->Controller->Component->init($this->Controller); + $this->Controller->Component->initialize($this->Controller); + $this->Controller->Toolbar->panels['MockDebug']->expectOnce('beforeRender'); + $this->Controller->Toolbar->beforeRender($this->Controller); + + $this->assertTrue(isset($this->Controller->viewVars['debugToolbarPanels'])); + $vars = $this->Controller->viewVars['debugToolbarPanels']; + + $expected = array( + 'plugin' => 'debug_kit', + 'elementName' => 'session_panel', + 'content' => $this->Controller->Toolbar->Session->read(), + 'disableTimer' => true, + 'title' => '' + ); + $this->assertEqual($expected, $vars['session']); + + $memory = DebugKitDebugger::getMemoryPoints(); + $this->assertTrue(isset($memory['Controller render start'])); + } +/** + * test that vars are gathered and state is saved on beforeRedirect + * + * @return void + **/ + function testBeforeRedirect() { + $this->Controller->components = array( + 'DebugKit.Toolbar' => array( + 'panels' => array('MockDebug', 'session', 'history') + ) + ); + $this->Controller->Component->init($this->Controller); + $this->Controller->Component->initialize($this->Controller); + + $configName = 'debug_kit'; + $this->Controller->Toolbar->cacheKey = 'toolbar_history'; + Cache::delete('toolbar_history', $configName); + + DebugKitDebugger::startTimer('controllerAction', 'testing beforeRedirect'); + $this->Controller->Toolbar->panels['MockDebug']->expectOnce('beforeRender'); + $this->Controller->Toolbar->beforeRedirect($this->Controller); + + $result = Cache::read('toolbar_history', $configName); + $this->assertTrue(isset($result[0]['session'])); + $this->assertTrue(isset($result[0]['mock_debug'])); + + $timers = DebugKitDebugger::getTimers(); + $this->assertTrue(isset($timers['controllerAction'])); + } +/** + * test that loading state (accessing cache) works. + * + * @return void + **/ + function testLoadState() { + $this->Controller->Toolbar->cacheKey = 'toolbar_history'; + + $data = array(0 => array('my data')); + Cache::write('toolbar_history', $data, 'debug_kit'); + $result = $this->Controller->Toolbar->loadState(0); + $this->assertEqual($result, $data[0]); + } +/** + * test the Log panel log reading. + * + * @return void + **/ + function testLogPanel() { + $this->Controller->components = array( + 'DebugKit.Toolbar' => array( + 'panels' => array('log', 'session', 'history' => false, 'variables' => false, 'sqlLog' => false, + 'timer' => false) + ) + ); + $this->Controller->Component->init($this->Controller); + $this->Controller->Component->initialize($this->Controller); + + sleep(1); + $this->Controller->log('This is a log I made this request'); + $this->Controller->log('This is the second log I made this request'); + $this->Controller->log('This time in the debug log!', LOG_DEBUG); + + $this->Controller->Component->startup($this->Controller); + $this->Controller->Component->beforeRender($this->Controller); + $result = $this->Controller->viewVars['debugToolbarPanels']['log']; + + $this->assertEqual(count($result['content']), 2); + $this->assertEqual(count($result['content']['error']), 2); + $this->assertEqual(count($result['content']['debug']), 1); + + $this->assertEqual(trim($result['content']['debug'][0][1]), 'This time in the debug log!'); + $this->assertEqual(trim($result['content']['error'][0][1]), 'This is a log I made this request'); + + $data = array( + 'Post' => array( + 'id' => 1, + 'title' => 'post!', + 'body' => 'some text here', + 'created' => '2009-11-07 23:23:23' + ), + 'Comment' => array( + 'id' => 23 + ) + ); + $this->Controller->log($data); + $this->Controller->Component->beforeRender($this->Controller); + $result = $this->Controller->viewVars['debugToolbarPanels']['log']; + $this->assertPattern('/\[created\] => 2009-11-07 23:23:23/', $result['content']['error'][2][1]); + $this->assertPattern('/\[Comment\] => Array/', $result['content']['error'][2][1]); + } + +/** + * test that creating the log panel creates the default file logger if none + * are configured. This stops DebugKit from mucking with the default auto-magic log config + * + * @return void + */ + function testLogPanelConstructCreatingDefaultLogConfiguration() { + CakeLog::drop('default'); + CakeLog::drop('debug_kit_log_panel'); + + $panel =& new LogPanel(array()); + $configured = CakeLog::configured(); + + $this->assertTrue(in_array('default', $configured)); + $this->assertTrue(in_array('debug_kit_log_panel', $configured)); + } + +/** + * Test that history state urls set prefix = null and admin = null so generated urls do not + * adopt these params. + * + * @return void + **/ + function testHistoryUrlGenerationWithPrefixes() { + $configName = 'debug_kit'; + $this->Controller->params = array( + 'controller' => 'posts', + 'action' => 'edit', + 'admin' => 1, + 'prefix' => 'admin', + 'plugin' => 'cms', + 'url' => array( + 'url' => '/admin/cms/posts/edit/' + ) + ); + $this->Controller->Component->initialize($this->Controller); + $this->Controller->Toolbar->cacheKey = 'url_test'; + $this->Controller->Component->beforeRender($this->Controller); + + $result = $this->Controller->Toolbar->panels['history']->beforeRender($this->Controller); + $expected = array( + 'plugin' => 'debug_kit', 'controller' => 'toolbar_access', 'action' => 'history_state', + 0 => 1, 'admin' => false + ); + $this->assertEqual($result[0]['url'], $expected); + Cache::delete('url_test', $configName); + } +/** + * Test that the FireCake toolbar is used on AJAX requests + * + * @return void + **/ + function testAjaxToolbar() { + $_SERVER['HTTP_X_REQUESTED_WITH'] = 'XMLHttpRequest'; + $this->Controller->components = array('DebugKit.Toolbar'); + $this->Controller->Component->init($this->Controller); + $this->Controller->Component->initialize($this->Controller); + $this->Controller->Component->startup($this->Controller); + $this->assertEqual($this->Controller->helpers['DebugKit.Toolbar']['output'], 'DebugKit.FirePhpToolbar'); + } +/** + * Test that the toolbar does not interfere with requestAction + * + * @return void + **/ + function testNoRequestActionInterference() { + $debugKitPath = App::pluginPath('DebugKit'); + $noDir = (empty($debugKitPath) || !file_exists($debugKitPath)); + $skip = $this->skipIf($noDir, 'Could not find debug_kit in plugin paths, skipping %s'); + if ($skip) { + return; + } + + App::build(array( + 'controllers' => $debugKitPath . 'tests' . DS . 'test_app' . DS . 'controllers' . DS, + 'views' => array( + $debugKitPath . 'tests' . DS . 'test_app' . DS . 'views' . DS, + CAKE_CORE_INCLUDE_PATH . DS . 'cake' . DS . 'libs' . DS . 'view' . DS + ), + 'plugins' => $this->_paths['plugins'] + )); + Router::reload(); + + $result = $this->Controller->requestAction('/debug_kit_test/request_action_return', array('return')); + $this->assertEqual($result, 'I am some value from requestAction.'); + + $result = $this->Controller->requestAction('/debug_kit_test/request_action_render', array('return')); + $this->assertEqual($result, 'I have been rendered.'); + } +/** + * test the sqlLog panel parsing of db->showLog + * + * @return void + **/ + function testSqlLogPanel() { + App::import('Core', 'Model'); + $Article =& new Model(array('ds' => 'test_suite', 'name' => 'Article')); + $Article->find('first', array('conditions' => array('Article.id' => 1))); + + $this->Controller->components = array( + 'DebugKit.Toolbar' => array( + 'panels' => array('SqlLog') + ) + ); + $this->Controller->Component->init($this->Controller); + $this->Controller->Component->initialize($this->Controller); + $this->Controller->Component->startup($this->Controller); + $this->Controller->Component->beforeRender($this->Controller); + $result = $this->Controller->viewVars['debugToolbarPanels']['sql_log']; + + $this->assertTrue(isset($result['content']['connections']['test_suite'])); + $this->assertTrue(isset($result['content']['threshold'])); + } +} diff --git a/code/ryzom/tools/server/www/webtt/plugins/debug_kit/tests/cases/models/toolbar_access.test.php b/code/ryzom/tools/server/www/webtt/plugins/debug_kit/tests/cases/models/toolbar_access.test.php new file mode 100644 index 000000000..008f4fe10 --- /dev/null +++ b/code/ryzom/tools/server/www/webtt/plugins/debug_kit/tests/cases/models/toolbar_access.test.php @@ -0,0 +1,65 @@ +Model =& new ToolbarAccess(); + } + +/** + * endTest + * + * @return void + */ + function endTest() { + unset($this->Model); + } + +/** + * test that explain query returns arrays of query information. + * + * @return void + */ + function testExplainQuery() { + $db =& ConnectionManager::getDataSource('test_suite'); + $sql = 'SELECT * FROM ' . $db->fullTableName('posts') . ';'; + $result = $this->Model->explainQuery('test_suite', $sql); + + $this->assertTrue(is_array($result)); + $this->assertFalse(empty($result)); + } +} diff --git a/code/ryzom/tools/server/www/webtt/plugins/debug_kit/tests/cases/test_objects.php b/code/ryzom/tools/server/www/webtt/plugins/debug_kit/tests/cases/test_objects.php new file mode 100644 index 000000000..67b01a7df --- /dev/null +++ b/code/ryzom/tools/server/www/webtt/plugins/debug_kit/tests/cases/test_objects.php @@ -0,0 +1,53 @@ +sentHeaders[$name] = $value; + } +/** + * skip client detection as headers are not being sent. + * + * @access public + * @return void + */ + function detectClientExtension() { + return true; + } +/** + * Reset the fireCake + * + * @return void + **/ + function reset() { + $_this =& FireCake::getInstance(); + $_this->sentHeaders = array(); + $_this->_messageIndex = 1; + } +} + + diff --git a/code/ryzom/tools/server/www/webtt/plugins/debug_kit/tests/cases/vendors/debug_kit_debugger.test.php b/code/ryzom/tools/server/www/webtt/plugins/debug_kit/tests/cases/vendors/debug_kit_debugger.test.php new file mode 100644 index 000000000..536e89922 --- /dev/null +++ b/code/ryzom/tools/server/www/webtt/plugins/debug_kit/tests/cases/vendors/debug_kit_debugger.test.php @@ -0,0 +1,232 @@ +assertTrue(DebugKitDebugger::startTimer('test1', 'this is my first test')); + usleep(5000); + $this->assertTrue(DebugKitDebugger::stopTimer('test1')); + $elapsed = DebugKitDebugger::elapsedTime('test1'); + $this->assertTrue($elapsed > 0.0050); + + $this->assertTrue(DebugKitDebugger::startTimer('test2', 'this is my second test')); + sleep(1); + $this->assertTrue(DebugKitDebugger::stopTimer('test2')); + $elapsed = DebugKitDebugger::elapsedTime('test2'); + $this->assertTrue($elapsed > 1); + + DebugKitDebugger::startTimer('test3'); + $this->assertFalse(DebugKitDebugger::elapsedTime('test3')); + $this->assertFalse(DebugKitDebugger::stopTimer('wrong')); + } +/** + * test timers with no names. + * + * @return void + **/ + function testAnonymousTimers() { + $this->assertTrue(DebugKitDebugger::startTimer()); + usleep(2000); + $this->assertTrue(DebugKitDebugger::stopTimer()); + $timers = DebugKitDebugger::getTimers(); + + $this->assertEqual(count($timers), 2); + end($timers); + $key = key($timers); + $lineNo = __LINE__ - 8; + + $file = Debugger::trimPath(__FILE__); + $expected = $file . ' line ' . $lineNo; + $this->assertEqual($key, $expected); + + $timer = $timers[$expected]; + $this->assertTrue($timer['time'] > 0.0020); + $this->assertEqual($timers[$expected]['message'], $expected); + } +/** + * Assert that nested anonymous timers don't get mixed up. + * + * @return void + **/ + function testNestedAnonymousTimers() { + $this->assertTrue(DebugKitDebugger::startTimer()); + usleep(100); + $this->assertTrue(DebugKitDebugger::startTimer()); + usleep(100); + $this->assertTrue(DebugKitDebugger::stopTimer()); + $this->assertTrue(DebugKitDebugger::stopTimer()); + + $timers = DebugKitDebugger::getTimers(); + $this->assertEqual(count($timers), 3, 'incorrect number of timers %s'); + $firstTimerLine = __LINE__ -9; + $secondTimerLine = __LINE__ -8; + $file = Debugger::trimPath(__FILE__); + + $this->assertTrue(isset($timers[$file . ' line ' . $firstTimerLine]), 'first timer is not set %s'); + $this->assertTrue(isset($timers[$file . ' line ' . $secondTimerLine]), 'second timer is not set %s'); + + $firstTimer = $timers[$file . ' line ' . $firstTimerLine]; + $secondTimer = $timers[$file . ' line ' . $secondTimerLine]; + $this->assertTrue($firstTimer['time'] > $secondTimer['time']); + } +/** + * test that calling startTimer with the same name does not overwrite previous timers + * and instead adds new ones. + * + * @return void + **/ + function testRepeatTimers() { + DebugKitDebugger::startTimer('my timer', 'This is the first call'); + usleep(100); + DebugKitDebugger::startTimer('my timer', 'This is the second call'); + usleep(100); + + DebugKitDebugger::stopTimer('my timer'); + DebugKitDebugger::stopTimer('my timer'); + + $timers = DebugKitDebugger::getTimers(); + $this->assertEqual(count($timers), 3, 'wrong timer count %s'); + + $this->assertTrue(isset($timers['my timer'])); + $this->assertTrue(isset($timers['my timer #2'])); + + $this->assertTrue($timers['my timer']['time'] > $timers['my timer #2']['time'], 'timer 2 is longer? %s'); + $this->assertEqual($timers['my timer']['message'], 'This is the first call'); + $this->assertEqual($timers['my timer #2']['message'], 'This is the second call #2'); + } +/** + * testRequestTime + * + * @access public + * @return void + */ + function testRequestTime() { + $result1 = DebugKitDebugger::requestTime(); + usleep(50); + $result2 = DebugKitDebugger::requestTime(); + $this->assertTrue($result1 < $result2); + } +/** + * test getting all the set timers. + * + * @return void + **/ + function testGetTimers() { + DebugKitDebugger::startTimer('test1', 'this is my first test'); + DebugKitDebugger::stopTimer('test1'); + usleep(50); + DebugKitDebugger::startTimer('test2'); + DebugKitDebugger::stopTimer('test2'); + $timers = DebugKitDebugger::getTimers(); + + $this->assertEqual(count($timers), 3); + $this->assertTrue(is_float($timers['test1']['time'])); + $this->assertTrue(isset($timers['test1']['message'])); + $this->assertTrue(isset($timers['test2']['message'])); + } +/** + * test memory usage + * + * @return void + **/ + function testMemoryUsage() { + $result = DebugKitDebugger::getMemoryUse(); + $this->assertTrue(is_int($result)); + + $result = DebugKitDebugger::getPeakMemoryUse(); + $this->assertTrue(is_int($result)); + } +/** + * test _output switch to firePHP + * + * @return void + */ + function testOutput() { + $firecake =& FireCake::getInstance('TestFireCake'); + Debugger::invoke(DebugKitDebugger::getInstance('DebugKitDebugger')); + Debugger::output('fb'); + $foo .= ''; + $result = $firecake->sentHeaders; + + $this->assertPattern('/GROUP_START/', $result['X-Wf-1-1-1-1']); + $this->assertPattern('/ERROR/', $result['X-Wf-1-1-1-2']); + $this->assertPattern('/GROUP_END/', $result['X-Wf-1-1-1-5']); + + Debugger::invoke(Debugger::getInstance('Debugger')); + Debugger::output(); + } +/** + * test making memory use markers. + * + * @return void + **/ + function testMemorySettingAndGetting() { + $result = DebugKitDebugger::setMemoryPoint('test marker'); + $this->assertTrue($result); + + $result = DebugKitDebugger::getMemoryPoints(true); + $this->assertEqual(count($result), 1); + $this->assertTrue(isset($result['test marker'])); + $this->assertTrue(is_numeric($result['test marker'])); + + $result = DebugKitDebugger::getMemoryPoints(); + $this->assertTrue(empty($result)); + + DebugKitDebugger::setMemoryPoint('test marker'); + DebugKitDebugger::setMemoryPoint('test marker'); + $result = DebugKitDebugger::getMemoryPoints(); + $this->assertEqual(count($result), 2); + $this->assertTrue(isset($result['test marker'])); + $this->assertTrue(isset($result['test marker #2'])); + } + +} diff --git a/code/ryzom/tools/server/www/webtt/plugins/debug_kit/tests/cases/vendors/fire_cake.test.php b/code/ryzom/tools/server/www/webtt/plugins/debug_kit/tests/cases/vendors/fire_cake.test.php new file mode 100644 index 000000000..80abdfc73 --- /dev/null +++ b/code/ryzom/tools/server/www/webtt/plugins/debug_kit/tests/cases/vendors/fire_cake.test.php @@ -0,0 +1,340 @@ +firecake =& FireCake::getInstance('TestFireCake'); + } +/** + * test getInstance cheat. + * + * If this fails the rest of the test is going to fail too. + * + * @return void + **/ + function testGetInstanceOverride() { + $instance =& FireCake::getInstance(); + $instance2 =& FireCake::getInstance(); + $this->assertReference($instance, $instance2); + $this->assertIsA($instance, 'FireCake'); + $this->assertIsA($instance, 'TestFireCake', 'Stored instance is not a copy of TestFireCake, test case is broken.'); + } +/** + * testsetoption + * + * @return void + **/ + function testSetOptions() { + FireCake::setOptions(array('includeLineNumbers' => false)); + $this->assertEqual($this->firecake->options['includeLineNumbers'], false); + } +/** + * test Log() + * + * @access public + * @return void + */ + function testLog() { + FireCake::setOptions(array('includeLineNumbers' => false)); + FireCake::log('Testing'); + $this->assertTrue(isset($this->firecake->sentHeaders['X-Wf-Protocol-1'])); + $this->assertTrue(isset($this->firecake->sentHeaders['X-Wf-1-Plugin-1'])); + $this->assertTrue(isset($this->firecake->sentHeaders['X-Wf-1-Structure-1'])); + $this->assertEqual($this->firecake->sentHeaders['X-Wf-1-Index'], 1); + $this->assertEqual($this->firecake->sentHeaders['X-Wf-1-1-1-1'], '26|[{"Type":"LOG"},"Testing"]|'); + + FireCake::log('Testing', 'log-info'); + $this->assertEqual($this->firecake->sentHeaders['X-Wf-1-1-1-2'], '45|[{"Type":"LOG","Label":"log-info"},"Testing"]|'); + } +/** + * test info() + * + * @access public + * @return void + */ + function testInfo() { + FireCake::setOptions(array('includeLineNumbers' => false)); + FireCake::info('I have information'); + $this->assertTrue(isset($this->firecake->sentHeaders['X-Wf-Protocol-1'])); + $this->assertTrue(isset($this->firecake->sentHeaders['X-Wf-1-Plugin-1'])); + $this->assertTrue(isset($this->firecake->sentHeaders['X-Wf-1-Structure-1'])); + $this->assertEqual($this->firecake->sentHeaders['X-Wf-1-Index'], 1); + $this->assertEqual($this->firecake->sentHeaders['X-Wf-1-1-1-1'], '38|[{"Type":"INFO"},"I have information"]|'); + + FireCake::info('I have information', 'info-label'); + $this->assertEqual($this->firecake->sentHeaders['X-Wf-1-1-1-2'], '59|[{"Type":"INFO","Label":"info-label"},"I have information"]|'); + } +/** + * test info() + * + * @access public + * @return void + */ + function testWarn() { + FireCake::setOptions(array('includeLineNumbers' => false)); + FireCake::warn('A Warning'); + $this->assertTrue(isset($this->firecake->sentHeaders['X-Wf-Protocol-1'])); + $this->assertTrue(isset($this->firecake->sentHeaders['X-Wf-1-Plugin-1'])); + $this->assertTrue(isset($this->firecake->sentHeaders['X-Wf-1-Structure-1'])); + $this->assertEqual($this->firecake->sentHeaders['X-Wf-1-Index'], 1); + $this->assertEqual($this->firecake->sentHeaders['X-Wf-1-1-1-1'], '29|[{"Type":"WARN"},"A Warning"]|'); + + FireCake::warn('A Warning', 'Bzzz'); + $this->assertEqual($this->firecake->sentHeaders['X-Wf-1-1-1-2'], '44|[{"Type":"WARN","Label":"Bzzz"},"A Warning"]|'); + } +/** + * test error() + * + * @access public + * @return void + **/ + function testError() { + FireCake::setOptions(array('includeLineNumbers' => false)); + FireCake::error('An error'); + $this->assertTrue(isset($this->firecake->sentHeaders['X-Wf-Protocol-1'])); + $this->assertTrue(isset($this->firecake->sentHeaders['X-Wf-1-Plugin-1'])); + $this->assertTrue(isset($this->firecake->sentHeaders['X-Wf-1-Structure-1'])); + $this->assertEqual($this->firecake->sentHeaders['X-Wf-1-Index'], 1); + $this->assertEqual($this->firecake->sentHeaders['X-Wf-1-1-1-1'], '29|[{"Type":"ERROR"},"An error"]|'); + + FireCake::error('An error', 'wonky'); + $this->assertEqual($this->firecake->sentHeaders['X-Wf-1-1-1-2'], '45|[{"Type":"ERROR","Label":"wonky"},"An error"]|'); + } +/** + * test dump() + * + * @return void + **/ + function testDump() { + FireCake::dump('mydump', array('one' => 1, 'two' => 2)); + $this->assertEqual($this->firecake->sentHeaders['X-Wf-1-2-1-1'], '28|{"mydump":{"one":1,"two":2}}|'); + $this->assertTrue(isset($this->firecake->sentHeaders['X-Wf-1-Structure-2'])); + } +/** + * test table() generation + * + * @return void + **/ + function testTable() { + $table[] = array('Col 1 Heading','Col 2 Heading'); + $table[] = array('Row 1 Col 1','Row 1 Col 2'); + $table[] = array('Row 2 Col 1','Row 2 Col 2'); + $table[] = array('Row 3 Col 1','Row 3 Col 2'); + FireCake::table('myTrace', $table); + $expected = '162|[{"Type":"TABLE","Label":"myTrace"},[["Col 1 Heading","Col 2 Heading"],["Row 1 Col 1","Row 1 Col 2"],["Row 2 Col 1","Row 2 Col 2"],["Row 3 Col 1","Row 3 Col 2"]]]|'; + $this->assertEqual($this->firecake->sentHeaders['X-Wf-1-1-1-1'], $expected); + } +/** + * testStringEncoding + * + * @return void + **/ + function testStringEncode() { + $vars = array(1,2,3); + $result = $this->firecake->stringEncode($vars); + $this->assertEqual($result, array(1,2,3)); + + $this->firecake->setOptions(array('maxArrayDepth' => 3)); + $deep = array(1 => array(2 => array(3))); + $result = $this->firecake->stringEncode($deep); + $this->assertEqual($result, array(1 => array(2 => '** Max Array Depth (3) **'))); + } +/** + * test object encoding + * + * @return void + **/ + function testStringEncodeObjects() { + $obj =& FireCake::getInstance(); + $result = $this->firecake->stringEncode($obj); + + $this->assertTrue(is_array($result)); + $this->assertEqual($result['_defaultOptions']['useNativeJsonEncode'], true); + $this->assertEqual($result['_encodedObjects'][0], '** Recursion (TestFireCake) **'); + } +/** + * test trace() + * + * @return void + **/ + function testTrace() { + FireCake::trace('myTrace'); + $this->assertTrue(isset($this->firecake->sentHeaders['X-Wf-Protocol-1'])); + $this->assertTrue(isset($this->firecake->sentHeaders['X-Wf-1-Plugin-1'])); + $this->assertTrue(isset($this->firecake->sentHeaders['X-Wf-1-Structure-1'])); + $dump = $this->firecake->sentHeaders['X-Wf-1-1-1-1']; + $this->assertPattern('/"Message":"myTrace"/', $dump); + $this->assertPattern('/"Trace":\[/', $dump); + } +/** + * test enabling and disabling of FireCake output + * + * @return void + **/ + function testEnableDisable() { + FireCake::disable(); + FireCake::trace('myTrace'); + $this->assertTrue(empty($this->firecake->sentHeaders)); + + FireCake::enable(); + FireCake::trace('myTrace'); + $this->assertFalse(empty($this->firecake->sentHeaders)); + } + +/** + * test correct line continuation markers on multi line headers. + * + * @access public + * @return void + */ + function testMultiLineOutput() { + $skip = $this->skipIf(!PHP5, 'Output is not long enough with PHP4'); + if ($skip) { + return; + } + FireCake::trace('myTrace'); + $this->assertEqual($this->firecake->sentHeaders['X-Wf-1-Index'], 4); + $header = $this->firecake->sentHeaders['X-Wf-1-1-1-1']; + $this->assertEqual(substr($header, -2), '|\\'); + + $header = $this->firecake->sentHeaders['X-Wf-1-1-1-2']; + $this->assertEqual(substr($header, -2), '|\\'); + + $header = $this->firecake->sentHeaders['X-Wf-1-1-1-3']; + $this->assertEqual(substr($header, -2), '|\\'); + + $header = $this->firecake->sentHeaders['X-Wf-1-1-1-4']; + $this->assertEqual(substr($header, -1), '|'); + } +/** + * test inclusion of line numbers + * + * @return void + **/ + function testIncludeLineNumbers() { + FireCake::setOptions(array('includeLineNumbers' => true)); + FireCake::info('Testing'); + $result = $this->firecake->sentHeaders['X-Wf-1-1-1-1']; + $this->assertPattern('/"File"\:".*fire_cake.test.php/', $result); + $this->assertPattern('/"Line"\:\d+/', $result); + } +/** + * test Group messages + * + * @return void + **/ + function testGroup() { + FireCake::setOptions(array('includeLineNumbers' => false)); + FireCake::group('test'); + FireCake::info('my info'); + FireCake::groupEnd(); + $this->assertEqual($this->firecake->sentHeaders['X-Wf-1-1-1-1'], '63|[{"Collapsed":"true","Type":"GROUP_START","Label":"test"},null]|'); + $this->assertEqual($this->firecake->sentHeaders['X-Wf-1-1-1-3'], '27|[{"Type":"GROUP_END"},null]|'); + $this->assertEqual($this->firecake->sentHeaders['X-Wf-1-Index'], 3); + } +/** + * test fb() parameter parsing + * + * @return void + **/ + function testFbParameterParsing() { + FireCake::setOptions(array('includeLineNumbers' => false)); + FireCake::fb('Test'); + $this->assertEqual($this->firecake->sentHeaders['X-Wf-1-1-1-1'], '23|[{"Type":"LOG"},"Test"]|'); + + FireCake::fb('Test', 'warn'); + $this->assertEqual($this->firecake->sentHeaders['X-Wf-1-1-1-2'], '24|[{"Type":"WARN"},"Test"]|'); + + FireCake::fb('Test', 'Custom label', 'warn'); + $this->assertEqual($this->firecake->sentHeaders['X-Wf-1-1-1-3'], '47|[{"Type":"WARN","Label":"Custom label"},"Test"]|'); + + $this->expectError(); + $this->assertFalse(FireCake::fb('Test', 'Custom label', 'warn', 'more parameters')); + + $this->assertEqual($this->firecake->sentHeaders['X-Wf-1-Index'], 3); + } +/** + * Test defaulting to log if incorrect message type is used + * + * @return void + **/ + function testIncorrectMessageType() { + FireCake::setOptions(array('includeLineNumbers' => false)); + FireCake::fb('Hello World', 'foobared'); + $this->assertEqual($this->firecake->sentHeaders['X-Wf-1-1-1-1'], '30|[{"Type":"LOG"},"Hello World"]|'); + } +/** + * testClientExtensionDetection. + * + * @return void + **/ + function testDetectClientExtension() { + $back = env('HTTP_USER_AGENT'); + $_SERVER['HTTP_USER_AGENT'] = 'Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.0.4) Gecko/2008102920 Firefox/3.0.4 FirePHP/0.2.1'; + $this->assertTrue(FireCake::detectClientExtension()); + + $_SERVER['HTTP_USER_AGENT'] = 'Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.0.4) Gecko/2008102920 Firefox/3.0.4 FirePHP/0.0.4'; + $this->assertFalse(FireCake::detectClientExtension()); + + $_SERVER['HTTP_USER_AGENT'] = 'Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.0.4) Gecko/2008102920 Firefox/3.0.4'; + $this->assertFalse(FireCake::detectClientExtension()); + $_SERVER['HTTP_USER_AGENT'] = $back; + } +/** + * test of Non Native JSON encoding. + * + * @return void + **/ + function testNonNativeEncoding() { + FireCake::setOptions(array('useNativeJsonEncode' => false)); + $json = FireCake::jsonEncode(array('one' => 1, 'two' => 2)); + $this->assertEqual($json, '{"one":1,"two":2}'); + + $json = FireCake::jsonEncode(array(1,2,3)); + $this->assertEqual($json, '[1,2,3]'); + + $json = FireCake::jsonEncode(FireCake::getInstance()); + $this->assertPattern('/"options"\:\{"maxObjectDepth"\:\d*,/', $json); + } +/** + * reset the FireCake counters and headers. + * + * @access public + * @return void + */ + function tearDown() { + TestFireCake::reset(); + } +} diff --git a/code/ryzom/tools/server/www/webtt/plugins/debug_kit/tests/cases/views/debug.test.php b/code/ryzom/tools/server/www/webtt/plugins/debug_kit/tests/cases/views/debug.test.php new file mode 100644 index 000000000..606ab0630 --- /dev/null +++ b/code/ryzom/tools/server/www/webtt/plugins/debug_kit/tests/cases/views/debug.test.php @@ -0,0 +1,161 @@ + 'pages', 'action' => 'display', 'home')); + Router::parse('/'); + $this->Controller =& new Controller(); + $this->View =& new DebugView($this->Controller, false); + $this->_debug = Configure::read('debug'); + $this->_paths = array(); + $this->_paths['plugins'] = App::path('plugins'); + $this->_paths['views'] = App::path('views'); + $this->_paths['vendors'] = App::path('vendors'); + $this->_paths['controllers'] = App::path('controllers'); + } +/** + * tear down function + * + * @return void + **/ + function endTest() { + App::build(array( + 'plugins' => $this->_paths['plugins'], + 'views' => $this->_paths['views'], + 'vendors' => $this->_paths['vendors'], + 'controllers' => $this->_paths['controllers'] + )); + + unset($this->View, $this->Controller); + DebugKitDebugger::clearTimers(); + Configure::write('debug', $this->_debug); + } +/** + * start Case - switch view paths + * + * @return void + **/ + function startCase() { + App::build(array( + 'views' => array( + TEST_CAKE_CORE_INCLUDE_PATH . 'tests' . DS . 'test_app' . DS . 'views'. DS, + APP . 'plugins' . DS . 'debug_kit' . DS . 'views'. DS, + ROOT . DS . LIBS . 'view' . DS + ) + ), true); + } +/** + * test that element timers are working + * + * @return void + **/ + function testElementTimers() { + $result = $this->View->element('test_element'); + $expected = << +this is the test element + + +TEXT; + $this->assertEqual($result, $expected); + + $result = DebugKitDebugger::getTimers(); + $this->assertTrue(isset($result['render_test_element.ctp'])); + } +/** + * test rendering and ensure that timers are being set. + * + * @access public + * @return void + */ + function testRenderTimers() { + $this->Controller->viewPath = 'posts'; + $this->Controller->action = 'index'; + $this->Controller->params = array( + 'action' => 'index', + 'controller' => 'posts', + 'plugin' => null, + 'url' => array('url' => 'posts/index'), + 'base' => null, + 'here' => '/posts/index', + ); + $this->Controller->layout = 'default'; + $View =& new DebugView($this->Controller, false); + $View->render('index'); + + $result = DebugKitDebugger::getTimers(); + $this->assertEqual(count($result), 4); + $this->assertTrue(isset($result['viewRender'])); + $this->assertTrue(isset($result['render_default.ctp'])); + $this->assertTrue(isset($result['render_index.ctp'])); + + $result = DebugKitDebugger::getMemoryPoints(); + $this->assertTrue(isset($result['View render complete'])); + } +/** + * Test for correct loading of helpers into custom view + * + * @return void + */ + function testLoadHelpers() { + $loaded = array(); + $result = $this->View->_loadHelpers($loaded, array('Html', 'Javascript', 'Number')); + $this->assertTrue(is_object($result['Html'])); + $this->assertTrue(is_object($result['Javascript'])); + $this->assertTrue(is_object($result['Number'])); + } +/** + * test that $out is returned when a layout is rendered instead of the empty + * $this->output. As this causes issues with requestAction() + * + * @return void + **/ + function testProperReturnUnderRequestAction() { + $testapp = App::pluginPath('DebugKit') . 'tests' . DS . 'test_app' . DS . 'views' . DS; + App::build(array('views' => array($testapp))); + + $this->View->set('test', 'I have been rendered.'); + $this->View->action = 'request_action_render'; + $this->View->name = 'DebugKitTest'; + $this->View->viewPath = 'debug_kit_test'; + $this->View->layout = false; + $result = $this->View->render('request_action_render'); + + $this->assertEqual($result, 'I have been rendered.'); + } +} diff --git a/code/ryzom/tools/server/www/webtt/plugins/debug_kit/tests/cases/views/helpers/fire_php_toolbar.test.php b/code/ryzom/tools/server/www/webtt/plugins/debug_kit/tests/cases/views/helpers/fire_php_toolbar.test.php new file mode 100644 index 000000000..dd269483b --- /dev/null +++ b/code/ryzom/tools/server/www/webtt/plugins/debug_kit/tests/cases/views/helpers/fire_php_toolbar.test.php @@ -0,0 +1,149 @@ + 'pages', 'action' => 'display', 'home')); + Router::parse('/'); + + $this->Toolbar =& new ToolbarHelper(array('output' => 'DebugKit.FirePhpToolbar')); + $this->Toolbar->FirePhpToolbar =& new FirePhpToolbarHelper(); + + $this->Controller =& new Controller(); + if (isset($this->_debug)) { + Configure::write('debug', $this->_debug); + } + } +/** + * start Case - switch view paths + * + * @return void + **/ + function startCase() { + $this->_viewPaths = App::build('views'); + App::build(array( + 'views' => array( + TEST_CAKE_CORE_INCLUDE_PATH . 'tests' . DS . 'test_app' . DS . 'views'. DS, + APP . 'plugins' . DS . 'debug_kit' . DS . 'views'. DS, + ROOT . DS . LIBS . 'view' . DS + )), true); + $this->_debug = Configure::read('debug'); + $this->firecake =& FireCake::getInstance(); + } +/** + * test neat array (dump)creation + * + * @return void + */ + function testMakeNeatArray() { + $this->Toolbar->makeNeatArray(array(1,2,3)); + $result = $this->firecake->sentHeaders; + $this->assertTrue(isset($result['X-Wf-1-1-1-1'])); + $this->assertPattern('/\[1,2,3\]/', $result['X-Wf-1-1-1-1']); + } +/** + * testAfterlayout element rendering + * + * @return void + */ + function testAfterLayout(){ + $this->Controller->viewPath = 'posts'; + $this->Controller->action = 'index'; + $this->Controller->params = array( + 'action' => 'index', + 'controller' => 'posts', + 'plugin' => null, + 'url' => array('url' => 'posts/index', 'ext' => 'xml'), + 'base' => null, + 'here' => '/posts/index', + ); + $this->Controller->layout = 'default'; + $this->Controller->uses = null; + $this->Controller->components = array('DebugKit.Toolbar'); + $this->Controller->constructClasses(); + $this->Controller->Component->initialize($this->Controller); + $this->Controller->Component->startup($this->Controller); + $this->Controller->Component->beforeRender($this->Controller); + $result = $this->Controller->render(); + $this->assertNoPattern('/debug-toolbar/', $result); + $result = $this->firecake->sentHeaders; + $this->assertTrue(is_array($result)); + } +/** + * test starting a panel + * + * @return void + **/ + function testPanelStart() { + $this->Toolbar->panelStart('My Panel', 'my_panel'); + $result = $this->firecake->sentHeaders; + $this->assertPattern('/GROUP_START.+My Panel/', $result['X-Wf-1-1-1-1']); + } +/** + * test ending a panel + * + * @return void + **/ + function testPanelEnd() { + $this->Toolbar->panelEnd(); + $result = $this->firecake->sentHeaders; + $this->assertPattern('/GROUP_END/', $result['X-Wf-1-1-1-1']); + } +/** + * endTest() + * + * @return void + */ + function endTest() { + TestFireCake::reset(); + } +/** + * reset the view paths + * + * @return void + **/ + function endCase() { + Configure::write('viewPaths', $this->_viewPaths); + } +/** + * tearDown + * + * @access public + * @return void + */ + function tearDown() { + unset($this->Toolbar, $this->Controller); + ClassRegistry::removeObject('view'); + ClassRegistry::flush(); + Router::reload(); + } +} diff --git a/code/ryzom/tools/server/www/webtt/plugins/debug_kit/tests/cases/views/helpers/html_toolbar.test.php b/code/ryzom/tools/server/www/webtt/plugins/debug_kit/tests/cases/views/helpers/html_toolbar.test.php new file mode 100644 index 000000000..766edd621 --- /dev/null +++ b/code/ryzom/tools/server/www/webtt/plugins/debug_kit/tests/cases/views/helpers/html_toolbar.test.php @@ -0,0 +1,352 @@ + 'pages', 'action' => 'display', 'home')); + Router::parse('/'); + + $this->Toolbar =& new ToolbarHelper(array('output' => 'DebugKit.HtmlToolbar')); + $this->Toolbar->HtmlToolbar =& new HtmlToolbarHelper(); + $this->Toolbar->HtmlToolbar->Html =& new HtmlHelper(); + $this->Toolbar->HtmlToolbar->Form =& new FormHelper(); + + $this->Controller =& new Controller(); + if (isset($this->_debug)) { + Configure::write('debug', $this->_debug); + } + } +/** + * start Case - switch view paths + * + * @return void + **/ + function startCase() { + $this->_viewPaths = App::path('views'); + App::build(array( + 'views' => array( + TEST_CAKE_CORE_INCLUDE_PATH . 'tests' . DS . 'test_app' . DS . 'views'. DS, + APP . 'plugins' . DS . 'debug_kit' . DS . 'views'. DS, + ROOT . DS . LIBS . 'view' . DS + )), true); + $this->_debug = Configure::read('debug'); + } +/** + * test Neat Array formatting + * + * @return void + **/ + function testMakeNeatArray() { + $in = false; + $result = $this->Toolbar->makeNeatArray($in); + $expected = array( + 'ul' => array('class' => 'neat-array depth-0'), + 'assertTags($result, $expected); + + $in = null; + $result = $this->Toolbar->makeNeatArray($in); + $expected = array( + 'ul' => array('class' => 'neat-array depth-0'), + 'assertTags($result, $expected); + + $in = true; + $result = $this->Toolbar->makeNeatArray($in); + $expected = array( + 'ul' => array('class' => 'neat-array depth-0'), + 'assertTags($result, $expected); + + $in = array(); + $result = $this->Toolbar->makeNeatArray($in); + $expected = array( + 'ul' => array('class' => 'neat-array depth-0'), + 'assertTags($result, $expected); + + $in = array('key' => 'value'); + $result = $this->Toolbar->makeNeatArray($in); + $expected = array( + 'ul' => array('class' => 'neat-array depth-0'), + 'assertTags($result, $expected); + + $in = array('key' => null); + $result = $this->Toolbar->makeNeatArray($in); + $expected = array( + 'ul' => array('class' => 'neat-array depth-0'), + 'assertTags($result, $expected); + + $in = array('key' => 'value', 'foo' => 'bar'); + $result = $this->Toolbar->makeNeatArray($in); + $expected = array( + 'ul' => array('class' => 'neat-array depth-0'), + 'assertTags($result, $expected); + + $in = array( + 'key' => 'value', + 'foo' => array( + 'this' => 'deep', + 'another' => 'value' + ) + ); + $result = $this->Toolbar->makeNeatArray($in); + $expected = array( + 'ul' => array('class' => 'neat-array depth-0'), + ' array('class' => 'neat-array depth-1')), + 'assertTags($result, $expected); + + $in = array( + 'key' => 'value', + 'foo' => array( + 'this' => 'deep', + 'another' => 'value' + ), + 'lotr' => array( + 'gandalf' => 'wizard', + 'bilbo' => 'hobbit' + ) + ); + $result = $this->Toolbar->makeNeatArray($in, 1); + $expected = array( + 'ul' => array('class' => 'neat-array depth-0 expanded'), + ' array('class' => 'neat-array depth-1')), + ' array('class' => 'neat-array depth-1')), + 'assertTags($result, $expected); + + $result = $this->Toolbar->makeNeatArray($in, 2); + $expected = array( + 'ul' => array('class' => 'neat-array depth-0 expanded'), + ' array('class' => 'neat-array depth-1 expanded')), + ' array('class' => 'neat-array depth-1 expanded')), + 'assertTags($result, $expected); + + $in = array('key' => 'value', 'array' => array()); + $result = $this->Toolbar->makeNeatArray($in); + $expected = array( + 'ul' => array('class' => 'neat-array depth-0'), + 'assertTags($result, $expected); + } + +/** + * Test injection of toolbar + * + * @return void + **/ + function testInjectToolbar() { + $this->Controller->viewPath = 'posts'; + $this->Controller->action = 'index'; + $this->Controller->params = array( + 'action' => 'index', + 'controller' => 'posts', + 'plugin' => null, + 'url' => array('url' => 'posts/index'), + 'base' => null, + 'here' => '/posts/index', + ); + $this->Controller->helpers = array('Html', 'Javascript', 'Session', 'DebugKit.Toolbar'); + $this->Controller->layout = 'default'; + $this->Controller->uses = null; + $this->Controller->components = array('DebugKit.Toolbar'); + $this->Controller->constructClasses(); + $this->Controller->Component->initialize($this->Controller); + $this->Controller->Component->startup($this->Controller); + $this->Controller->Component->beforeRender($this->Controller); + $result = $this->Controller->render(); + $result = str_replace(array("\n", "\r"), '', $result); + $this->assertPattern('#
    .+
    .*#', $result); + } + +/** + * test injection of javascript + * + * @return void + **/ + function testJavascriptInjection() { + $this->Controller->viewPath = 'posts'; + $this->Controller->uses = null; + $this->Controller->action = 'index'; + $this->Controller->params = array( + 'action' => 'index', + 'controller' => 'posts', + 'plugin' => null, + 'url' => array('url' => 'posts/index'), + 'base' => '/', + 'here' => '/posts/index', + ); + $this->Controller->helpers = array('Javascript', 'Html', 'Session'); + $this->Controller->components = array('DebugKit.Toolbar'); + $this->Controller->layout = 'default'; + $this->Controller->constructClasses(); + $this->Controller->Component->initialize($this->Controller); + $this->Controller->Component->startup($this->Controller); + $this->Controller->Component->beforeRender($this->Controller); + $result = $this->Controller->render(); + $result = str_replace(array("\n", "\r"), '', $result); + $this->assertPattern('#\s?#', $result); + } + +/** + * test message creation + * + * @return void + */ + function testMessage() { + $result = $this->Toolbar->message('test', 'one, two'); + $expected = array( + 'assertTags($result, $expected); + } +/** + * Test Table generation + * + * @return void + */ + function testTable() { + $rows = array( + array(1,2), + array(3,4), + ); + $result = $this->Toolbar->table($rows); + $expected = array( + 'table' => array('class' =>'debug-table'), + array('tr' => array('class' => 'odd')), + ' array('class' => 'even')), + 'assertTags($result, $expected); + } +/** + * test starting a panel + * + * @return void + **/ + function testStartPanel() { + $result = $this->Toolbar->panelStart('My Panel', 'my_panel'); + $expected = array( + 'a' => array('href' => '#my_panel'), + 'My Panel', + '/a' + ); + $this->assertTags($result, $expected); + } +/** + * test ending a panel + * + * @return void + **/ + function testPanelEnd() { + $result = $this->Toolbar->panelEnd(); + $this->assertNull($result); + } +/** + * reset the view paths + * + * @return void + **/ + function endCase() { + App::build(); + } + +/** + * tearDown + * + * @access public + * @return void + */ + function tearDown() { + unset($this->Toolbar, $this->Controller); + ClassRegistry::removeObject('view'); + ClassRegistry::flush(); + } +} diff --git a/code/ryzom/tools/server/www/webtt/plugins/debug_kit/tests/cases/views/helpers/toolbar.test.php b/code/ryzom/tools/server/www/webtt/plugins/debug_kit/tests/cases/views/helpers/toolbar.test.php new file mode 100644 index 000000000..81c914e73 --- /dev/null +++ b/code/ryzom/tools/server/www/webtt/plugins/debug_kit/tests/cases/views/helpers/toolbar.test.php @@ -0,0 +1,170 @@ + 'pages', 'action' => 'display', 'home')); + Router::parse('/'); + + $this->Toolbar =& new ToolbarHelper(array( + 'output' => 'MockBackendHelper', + 'cacheKey' => 'debug_kit_toolbar_test_case', + 'cacheConfig' => 'default' + )); + $this->Toolbar->MockBackend = new MockBackendHelper(); + + $this->Controller =& ClassRegistry::init('Controller'); + if (isset($this->_debug)) { + Configure::write('debug', $this->_debug); + } + } +/** + * start Case - switch view paths + * + * @return void + **/ + function startCase() { + $this->_viewPaths = App::path('views'); + App::build(array( + 'views' => array( + TEST_CAKE_CORE_INCLUDE_PATH . 'tests' . DS . 'test_app' . DS . 'views'. DS, + APP . 'plugins' . DS . 'debug_kit' . DS . 'views'. DS, + ROOT . DS . LIBS . 'view' . DS + )), true); + $this->_debug = Configure::read('debug'); + } +/** + * test cache writing for views. + * + * @return void + **/ + function testCacheWrite() { + $result = $this->Toolbar->writeCache('test', array('stuff', 'to', 'cache')); + $this->assertTrue($result); + } +/** + * Ensure that the cache writing only affects the + * top most level of the history stack. As this is where the current request is stored. + * + * @return void + **/ + function testOnlyWritingToFirstElement() { + $values = array( + array('test' => array('content' => array('first', 'values'))), + array('test' => array('content' => array('second', 'values'))), + ); + Cache::write('debug_kit_toolbar_test_case', $values, 'default'); + $this->Toolbar->writeCache('test', array('new', 'values')); + + $result = $this->Toolbar->readCache('test'); + $this->assertEqual($result, array('new', 'values')); + + $result = $this->Toolbar->readCache('test', 1); + $this->assertEqual($result, array('second', 'values')); + } +/** + * test cache reading for views + * + * @return void + **/ + function testCacheRead() { + $result = $this->Toolbar->writeCache('test', array('stuff', 'to', 'cache')); + $this->assertTrue($result, 'Cache write failed %s'); + + $result = $this->Toolbar->readCache('test'); + $this->assertEqual($result, array('stuff', 'to', 'cache'), 'Cache value is wrong %s'); + + $result = $this->Toolbar->writeCache('test', array('new', 'stuff')); + $this->assertTrue($result, 'Cache write failed %s'); + + $result = $this->Toolbar->readCache('test'); + $this->assertEqual($result, array('new', 'stuff'), 'Cache value is wrong %s'); + } +/** + * Test that reading/writing doesn't work with no cache config. + * + * @return void + **/ + function testNoCacheConfigPresent() { + $this->Toolbar = new ToolbarHelper(array('output' => 'MockBackendHelper')); + + $result = $this->Toolbar->writeCache('test', array('stuff', 'to', 'cache')); + $this->assertFalse($result, 'Writing to cache succeeded with no cache config %s'); + + $result = $this->Toolbar->readCache('test'); + $this->assertFalse($result, 'Reading cache succeeded with no cache config %s'); + } +/** + * ensure that getQueryLogs works and writes to the cache so the history panel will + * work. + * + * @return void + */ + function testGetQueryLogs() { + $model =& new Model(array('ds' => 'test_suite', 'table' => 'posts', 'name' => 'Post')); + $model->find('all'); + $model->find('first'); + + $result = $this->Toolbar->getQueryLogs('test_suite', array('cache' => false)); + $this->assertTrue(is_array($result)); + $this->assertTrue(count($result) >= 2, 'Should be more than 2 queries in the log %s'); + $this->assertTrue(isset($result[0]['actions'])); + + $model->find('first'); + Cache::delete('debug_kit_toolbar_test_case', 'default'); + $result = $this->Toolbar->getQueryLogs('test_suite', array('cache' => true)); + + $cached = $this->Toolbar->readCache('sql_log'); + $this->assertTrue(isset($cached['test_suite'])); + $this->assertEqual($cached['test_suite'][0], $result[0]); + } +/** + * reset the view paths + * + * @return void + **/ + function endCase() { + App::build(array('views' => $this->_viewPaths), true); + Cache::delete('debug_kit_toolbar_test_case', 'default'); + } +/** + * endTest + * + * @access public + * @return void + */ + function endTest() { + unset($this->Toolbar, $this->Controller); + ClassRegistry::removeObject('view'); + ClassRegistry::flush(); + } +} diff --git a/code/ryzom/tools/server/www/webtt/plugins/debug_kit/tests/groups/view_group.group.php b/code/ryzom/tools/server/www/webtt/plugins/debug_kit/tests/groups/view_group.group.php new file mode 100644 index 000000000..4f5625545 --- /dev/null +++ b/code/ryzom/tools/server/www/webtt/plugins/debug_kit/tests/groups/view_group.group.php @@ -0,0 +1,44 @@ +autoRender = false; + return 'I am some value from requestAction.'; + } + + function request_action_render() { + $this->set('test', 'I have been rendered.'); + } + +} \ No newline at end of file diff --git a/code/ryzom/tools/server/www/webtt/plugins/debug_kit/tests/test_app/vendors/test_panel.php b/code/ryzom/tools/server/www/webtt/plugins/debug_kit/tests/test_app/vendors/test_panel.php new file mode 100644 index 000000000..3b004d3f7 --- /dev/null +++ b/code/ryzom/tools/server/www/webtt/plugins/debug_kit/tests/test_app/vendors/test_panel.php @@ -0,0 +1,24 @@ +testPanel = true; + } +} diff --git a/code/ryzom/tools/server/www/webtt/plugins/debug_kit/tests/test_app/views/debug_kit_test/request_action_render.ctp b/code/ryzom/tools/server/www/webtt/plugins/debug_kit/tests/test_app/views/debug_kit_test/request_action_render.ctp new file mode 100644 index 000000000..172d541d7 --- /dev/null +++ b/code/ryzom/tools/server/www/webtt/plugins/debug_kit/tests/test_app/views/debug_kit_test/request_action_render.ctp @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/code/ryzom/tools/server/www/webtt/plugins/debug_kit/vendors/debug_kit_debugger.php b/code/ryzom/tools/server/www/webtt/plugins/debug_kit/vendors/debug_kit_debugger.php new file mode 100644 index 000000000..862ce627d --- /dev/null +++ b/code/ryzom/tools/server/www/webtt/plugins/debug_kit/vendors/debug_kit_debugger.php @@ -0,0 +1,400 @@ +__benchmarks) { + return; + } + $timers = array_values(DebugKitDebugger::getTimers()); + $end = end($timers); + echo ''; + echo ''; + echo ''; + $i = 0; + foreach ($timers as $timer) { + $indent = 0; + for ($j = 0; $j < $i; $j++) { + if (($timers[$j]['end']) > ($timer['start']) && ($timers[$j]['end']) > ($timer['end'])) { + $indent++; + } + } + $indent = str_repeat(' » ', $indent); + + extract($timer); + $start = round($start * 1000, 0); + $end = round($end * 1000, 0); + $time = round($time * 1000, 0); + echo ""; + $i++; + } + echo '
    Debug timer info
    MessageStart Time (ms)End Time (ms)Duration (ms)
    {$indent}$message$start$end$time
    '; + } +/** + * Start an benchmarking timer. + * + * @param string $name The name of the timer to start. + * @param string $message A message for your timer + * @return bool true + * @static + **/ + function startTimer($name = null, $message = null) { + $start = getMicrotime(); + $_this =& DebugKitDebugger::getInstance(); + + if (!$name) { + $named = false; + $calledFrom = debug_backtrace(); + $_name = $name = Debugger::trimpath($calledFrom[0]['file']) . ' line ' . $calledFrom[0]['line']; + } else { + $named = true; + } + + if (!$message) { + $message = $name; + } + + $_name = $name; + $i = 1; + while (isset($_this->__benchmarks[$name])) { + $i++; + $name = $_name . ' #' . $i; + } + + if ($i > 1) { + $message .= ' #' . $i; + } + + $_this->__benchmarks[$name] = array( + 'start' => $start, + 'message' => $message, + 'named' => $named + ); + return true; + } +/** + * Stop a benchmarking timer. + * + * $name should be the same as the $name used in startTimer(). + * + * @param string $name The name of the timer to end. + * @access public + * @return boolean true if timer was ended, false if timer was not started. + * @static + */ + function stopTimer($name = null) { + $end = getMicrotime(); + $_this =& DebugKitDebugger::getInstance(); + if (!$name) { + $names = array_reverse(array_keys($_this->__benchmarks)); + foreach($names as $name) { + if (!empty($_this->__benchmarks[$name]['end'])) { + continue; + } + if (empty($_this->__benchmarks[$name]['named'])) { + break; + } + } + } else { + $i = 1; + $_name = $name; + while (isset($_this->__benchmarks[$name])) { + if (empty($_this->__benchmarks[$name]['end'])) { + break; + } + $i++; + $name = $_name . ' #' . $i; + } + } + if (!isset($_this->__benchmarks[$name])) { + return false; + } + $_this->__benchmarks[$name]['end'] = $end; + return true; + } +/** + * Get all timers that have been started and stopped. + * Calculates elapsed time for each timer. If clear is true, will delete existing timers + * + * @param bool $clear false + * @return array + * @access public + **/ + function getTimers($clear = false) { + $_this =& DebugKitDebugger::getInstance(); + $start = DebugKitDebugger::requestStartTime(); + $now = getMicrotime(); + + $times = array(); + if (!empty($_this->__benchmarks)) { + $firstTimer = current($_this->__benchmarks); + $_end = $firstTimer['start']; + } else { + $_end = $now; + } + $times['Core Processing (Derived)'] = array( + 'message' => __d('debug_kit', 'Core Processing (Derived)', true), + 'start' => 0, + 'end' => $_end - $start, + 'time' => round($_end - $start, 6), + 'named' => null + ); + foreach ($_this->__benchmarks as $name => $timer) { + if (!isset($timer['end'])) { + $timer['end'] = $now; + } + $times[$name] = array_merge($timer, array( + 'start' => $timer['start'] - $start, + 'end' => $timer['end'] - $start, + 'time' => DebugKitDebugger::elapsedTime($name) + )); + } + if ($clear) { + $_this->__benchmarks = array(); + } + return $times; + } +/** + * Clear all existing timers + * + * @return bool true + **/ + function clearTimers() { + $_this =& DebugKitDebugger::getInstance(); + $_this->__benchmarks = array(); + return true; + } +/** + * Get the difference in time between the timer start and timer end. + * + * @param $name string the name of the timer you want elapsed time for. + * @param $precision int the number of decimal places to return, defaults to 5. + * @return float number of seconds elapsed for timer name, 0 on missing key + * @static + **/ + function elapsedTime($name = 'default', $precision = 5) { + $_this =& DebugKitDebugger::getInstance(); + if (!isset($_this->__benchmarks[$name]['start']) || !isset($_this->__benchmarks[$name]['end'])) { + return 0; + } + return round($_this->__benchmarks[$name]['end'] - $_this->__benchmarks[$name]['start'], $precision); + } +/** + * Get the total execution time until this point + * + * @access public + * @return float elapsed time in seconds since script start. + * @static + */ + function requestTime() { + $start = DebugKitDebugger::requestStartTime(); + $now = getMicroTime(); + return ($now - $start); + } +/** + * get the time the current request started. + * + * @access public + * @return float time of request start + * @static + */ + function requestStartTime() { + if (defined('TIME_START')) { + $startTime = TIME_START; + } else if (isset($GLOBALS['TIME_START'])) { + $startTime = $GLOBALS['TIME_START']; + } else { + $startTime = env('REQUEST_TIME'); + } + return $startTime; + } +/** + * get current memory usage + * + * @return integer number of bytes ram currently in use. 0 if memory_get_usage() is not available. + * @static + **/ + function getMemoryUse() { + if (!function_exists('memory_get_usage')) { + return 0; + } + return memory_get_usage(); + } +/** + * Get peak memory use + * + * @return integer peak memory use (in bytes). Returns 0 if memory_get_peak_usage() is not available + * @static + **/ + function getPeakMemoryUse() { + if (!function_exists('memory_get_peak_usage')) { + return 0; + } + return memory_get_peak_usage(); + } +/** + * Stores a memory point in the internal tracker. + * Takes a optional message name which can be used to identify the memory point. + * If no message is supplied a debug_backtrace will be done to identifty the memory point. + * If you don't have memory_get_xx methods this will not work. + * + * @param string $message Message to identify this memory point. + * @return boolean + **/ + function setMemoryPoint($message = null) { + $memoryUse = DebugKitDebugger::getMemoryUse(); + if (!$message) { + $named = false; + $trace = debug_backtrace(); + $message = Debugger::trimpath($trace[0]['file']) . ' line ' . $trace[0]['line']; + } + $self =& DebugKitDebugger::getInstance(); + if (isset($self->__memoryPoints[$message])) { + $originalMessage = $message; + $i = 1; + while (isset($self->__memoryPoints[$message])) { + $i++; + $message = $originalMessage . ' #' . $i; + } + } + $self->__memoryPoints[$message] = $memoryUse; + return true; + } +/** + * Get all the stored memory points + * + * @param boolean $clear Whether you want to clear the memory points as well. Defaults to false. + * @return array Array of memory marks stored so far. + **/ + function getMemoryPoints($clear = false) { + $self =& DebugKitDebugger::getInstance(); + $marks = $self->__memoryPoints; + if ($clear) { + $self->__memoryPoints = array(); + } + return $marks; + } +/** + * Clear out any existing memory points + * + * @return void + **/ + function clearMemoryPoints() { + $self =& DebugKitDebugger::getInstance(); + $self->__memoryPoints = array(); + } +/** + * Handles object conversion to debug string. + * + * @param string $var Object to convert + * @access protected + */ + function _output($data = array()) { + extract($data); + if (is_array($level)) { + $error = $level['error']; + $code = $level['code']; + if (isset($level['helpID'])) { + $helpID = $level['helpID']; + } else { + $helpID = ''; + } + $description = $level['description']; + $file = $level['file']; + $line = $level['line']; + $context = $level['context']; + $level = $level['level']; + } + $files = $this->trace(array('start' => 2, 'format' => 'points')); + $listing = $this->excerpt($files[0]['file'], $files[0]['line'] - 1, 1); + $trace = $this->trace(array('start' => 2, 'depth' => '20')); + + if ($this->_outputFormat == 'fb') { + $kontext = array(); + foreach ((array)$context as $var => $value) { + $kontext[] = "\${$var}\t=\t" . $this->exportVar($value, 1); + } + $this->_fireError($error, $code, $description, $file, $line, $trace, $kontext); + } else { + $data = compact( + 'level', 'error', 'code', 'helpID', 'description', 'file', 'path', 'line', 'context' + ); + echo parent::_output($data); + } + } +/** + * Create a FirePHP error message + * + * @param string $error Name of error + * @param string $code Code of error + * @param string $description Description of error + * @param string $file File error occured in + * @param string $line Line error occured on + * @param string $trace Stack trace at time of error + * @param string $context context of error + * @return void + * @access protected + */ + function _fireError($error, $code, $description, $file, $line, $trace, $context) { + $name = $error . ' - ' . $description; + $message = "$error $code $description on line: $line in file: $file"; + FireCake::group($name); + FireCake::error($message, $name); + FireCake::log($context, 'Context'); + FireCake::log($trace, 'Trace'); + FireCake::groupEnd(); + } +} + + +Debugger::invoke(DebugKitDebugger::getInstance('DebugKitDebugger')); +Debugger::getInstance('DebugKitDebugger'); diff --git a/code/ryzom/tools/server/www/webtt/plugins/debug_kit/vendors/fire_cake.php b/code/ryzom/tools/server/www/webtt/plugins/debug_kit/vendors/fire_cake.php new file mode 100644 index 000000000..1b7835ccb --- /dev/null +++ b/code/ryzom/tools/server/www/webtt/plugins/debug_kit/vendors/fire_cake.php @@ -0,0 +1,546 @@ + 10, + 'maxArrayDepth' => 20, + 'useNativeJsonEncode' => true, + 'includeLineNumbers' => true, + ); +/** + * Message Levels for messages sent via FirePHP + * + * @var array + */ + var $_levels = array( + 'log' => 'LOG', + 'info' => 'INFO', + 'warn' => 'WARN', + 'error' => 'ERROR', + 'dump' => 'DUMP', + 'trace' => 'TRACE', + 'exception' => 'EXCEPTION', + 'table' => 'TABLE', + 'groupStart' => 'GROUP_START', + 'groupEnd' => 'GROUP_END', + ); + + var $_version = '0.2.1'; +/** + * internal messageIndex counter + * + * @var int + * @access protected + */ + var $_messageIndex = 1; +/** + * stack of objects encoded by stringEncode() + * + * @var array + **/ + var $_encodedObjects = array(); +/** + * methodIndex to include in tracebacks when using includeLineNumbers + * + * @var array + **/ + var $_methodIndex = array('info', 'log', 'warn', 'error', 'table', 'trace'); +/** + * FireCake output status + * + * @var bool + **/ + var $_enabled = true; +/** + * get Instance of the singleton + * + * @param string $class Class instance to store in the singleton. Used with subclasses and Tests. + * @access public + * @static + * @return void + */ + function &getInstance($class = null) { + static $instance = array(); + if (!empty($class)) { + if (!$instance || strtolower($class) != strtolower(get_class($instance[0]))) { + $instance[0] =& new $class(); + $instance[0]->setOptions(); + } + } + if (!isset($instance[0]) || !$instance[0]) { + $instance[0] =& new FireCake(); + $instance[0]->setOptions(); + } + return $instance[0]; + } +/** + * setOptions + * + * @param array $options Array of options to set. + * @access public + * @static + * @return void + */ + function setOptions($options = array()) { + $_this =& FireCake::getInstance(); + if (empty($_this->options)) { + $_this->options = array_merge($_this->_defaultOptions, $options); + } else { + $_this->options = array_merge($_this->options, $options); + } + } +/** + * Return boolean based on presence of FirePHP extension + * + * @access public + * @return boolean + **/ + function detectClientExtension() { + $ua = FireCake::getUserAgent(); + if (!preg_match('/\sFirePHP\/([\.|\d]*)\s?/si', $ua, $match) || !version_compare($match[1], '0.0.6', '>=')) { + return false; + } + return true; + } +/** + * Get the Current UserAgent + * + * @access public + * @static + * @return string UserAgent string of active client connection + **/ + function getUserAgent() { + return env('HTTP_USER_AGENT'); + } +/** + * Disable FireCake output + * All subsequent output calls will not be run. + * + * @return void + **/ + function disable() { + $_this =& FireCake::getInstance(); + $_this->_enabled = false; + } +/** + * Enable FireCake output + * + * @return void + **/ + function enable() { + $_this =& FireCake::getInstance(); + $_this->_enabled = true; + } +/** + * Convenience wrapper for LOG messages + * + * @param string $message Message to log + * @param string $label Label for message (optional) + * @access public + * @static + * @return void + */ + function log($message, $label = null) { + FireCake::fb($message, $label, 'log'); + } +/** + * Convenience wrapper for WARN messages + * + * @param string $message Message to log + * @param string $label Label for message (optional) + * @access public + * @static + * @return void + */ + function warn($message, $label = null) { + FireCake::fb($message, $label, 'warn'); + } +/** + * Convenience wrapper for INFO messages + * + * @param string $message Message to log + * @param string $label Label for message (optional) + * @access public + * @static + * @return void + */ + function info($message, $label = null) { + FireCake::fb($message, $label, 'info'); + } +/** + * Convenience wrapper for ERROR messages + * + * @param string $message Message to log + * @param string $label Label for message (optional) + * @access public + * @static + * @return void + */ + function error($message, $label = null) { + FireCake::fb($message, $label, 'error'); + } +/** + * Convenience wrapper for TABLE messages + * + * @param string $message Message to log + * @param string $label Label for message (optional) + * @access public + * @static + * @return void + */ + function table($label, $message) { + FireCake::fb($message, $label, 'table'); + } +/** + * Convenience wrapper for DUMP messages + * + * @param string $message Message to log + * @param string $label Unique label for message + * @access public + * @static + * @return void + */ + function dump($label, $message) { + FireCake::fb($message, $label, 'dump'); + } +/** + * Convenience wrapper for TRACE messages + * + * @param string $label Label for message (optional) + * @access public + * @return void + */ + function trace($label) { + FireCake::fb($label, 'trace'); + } +/** + * Convenience wrapper for GROUP messages + * Messages following the group call will be nested in a group block + * + * @param string $label Label for group (optional) + * @access public + * @return void + */ + function group($label) { + FireCake::fb(null, $label, 'groupStart'); + } +/** + * Convenience wrapper for GROUPEND messages + * Closes a group block + * + * @param string $label Label for group (optional) + * @access public + * @return void + */ + function groupEnd() { + FireCake::fb(null, null, 'groupEnd'); + } +/** + * fb - Send messages with FireCake to FirePHP + * + * Much like FirePHP's fb() this method can be called with various parameter counts + * fb($message) - Just send a message defaults to LOG type + * fb($message, $type) - Send a message with a specific type + * fb($message, $label, $type) - Send a message with a custom label and type. + * + * @param mixed $message Message to output. For other parameters see usage above. + * @static + * @return void + **/ + function fb($message) { + $_this =& FireCake::getInstance(); + + if (headers_sent($filename, $linenum)) { + trigger_error(sprintf(__d('debug_kit', 'Headers already sent in %s on line %s. Cannot send log data to FirePHP.', true), $filename, $linenum), E_USER_WARNING); + return false; + } + if (!$_this->_enabled || !$_this->detectClientExtension()) { + return false; + } + + $args = func_get_args(); + $type = $label = null; + switch (count($args)) { + case 1: + $type = $_this->_levels['log']; + break; + case 2: + $type = $args[1]; + break; + case 3: + $type = $args[2]; + $label = $args[1]; + break; + default: + trigger_error(__d('debug_kit', 'Incorrect parameter count for FireCake::fb()', true), E_USER_WARNING); + return false; + } + if (isset($_this->_levels[$type])) { + $type = $_this->_levels[$type]; + } else { + $type = $_this->_levels['log']; + } + + $meta = array(); + $skipFinalObjectEncode = false; + if ($type == $_this->_levels['trace']) { + $trace = debug_backtrace(); + if (!$trace) { + return false; + } + $message = $_this->_parseTrace($trace, $args[0]); + $skipFinalObjectEncode = true; + } + + if ($_this->options['includeLineNumbers']) { + if (!isset($meta['file']) || !isset($meta['line'])) { + $trace = debug_backtrace(); + for ($i = 0, $len = count($trace); $i < $len ; $i++) { + $keySet = (isset($trace[$i]['class']) && isset($trace[$i]['function'])); + $selfCall = ($keySet && + strtolower($trace[$i]['class']) == 'firecake' && + in_array($trace[$i]['function'], $_this->_methodIndex) + ); + if ($selfCall) { + $meta['File'] = isset($trace[$i]['file']) ? Debugger::trimPath($trace[$i]['file']) : ''; + $meta['Line'] = isset($trace[$i]['line']) ? $trace[$i]['line'] : ''; + break; + } + } + } + } + + $structureIndex = 1; + if ($type == $_this->_levels['dump']) { + $structureIndex = 2; + $_this->_sendHeader('X-Wf-1-Structure-2','http://meta.firephp.org/Wildfire/Structure/FirePHP/Dump/0.1'); + } else { + $_this->_sendHeader('X-Wf-1-Structure-1','http://meta.firephp.org/Wildfire/Structure/FirePHP/FirebugConsole/0.1'); + } + + $_this->_sendHeader('X-Wf-Protocol-1', 'http://meta.wildfirehq.org/Protocol/JsonStream/0.2'); + $_this->_sendHeader('X-Wf-1-Plugin-1', 'http://meta.firephp.org/Wildfire/Plugin/FirePHP/Library-FirePHPCore/'. $_this->_version); + if ($type == $_this->_levels['groupStart']) { + $meta['Collapsed'] = 'true'; + } + if ($type == $_this->_levels['dump']) { + $dump = $_this->jsonEncode($message); + $msg = '{"' . $label .'":' . $dump .'}'; + } else { + $meta['Type'] = $type; + if ($label !== null) { + $meta['Label'] = $label; + } + $msg = '[' . $_this->jsonEncode($meta) . ',' . $_this->jsonEncode($message, $skipFinalObjectEncode).']'; + } + + $lines = explode("\n", chunk_split($msg, 5000, "\n")); + + foreach ($lines as $i => $line) { + if (empty($line)) { + continue; + } + $header = 'X-Wf-1-' . $structureIndex . '-1-' . $_this->_messageIndex; + if (count($lines) > 2) { + $first = ($i == 0) ? strlen($msg) : ''; + $end = ($i < count($lines) - 2) ? '\\' : ''; + $message = $first . '|' . $line . '|' . $end; + $_this->_sendHeader($header, $message); + } else { + $_this->_sendHeader($header, strlen($line) . '|' . $line . '|'); + } + $_this->_messageIndex++; + if ($_this->_messageIndex > 99999) { + trigger_error(__d('debug_kit', 'Maximum number (99,999) of messages reached!', true), E_USER_WARNING); + } + } + $_this->_sendHeader('X-Wf-1-Index', $_this->_messageIndex - 1); + return true; + } +/** + * Parse a debug backtrace + * + * @param array $trace Debug backtrace output + * @access protected + * @return array + **/ + function _parseTrace($trace, $messageName) { + $message = array(); + for ($i = 0, $len = count($trace); $i < $len ; $i++) { + $keySet = (isset($trace[$i]['class']) && isset($trace[$i]['function'])); + $selfCall = ($keySet && $trace[$i]['class'] == 'FireCake'); + if (!$selfCall) { + $message = array( + 'Class' => isset($trace[$i]['class']) ? $trace[$i]['class'] : '', + 'Type' => isset($trace[$i]['type']) ? $trace[$i]['type'] : '', + 'Function' => isset($trace[$i]['function']) ? $trace[$i]['function'] : '', + 'Message' => $messageName, + 'File' => isset($trace[$i]['file']) ? Debugger::trimPath($trace[$i]['file']) : '', + 'Line' => isset($trace[$i]['line']) ? $trace[$i]['line'] : '', + 'Args' => isset($trace[$i]['args']) ? $this->stringEncode($trace[$i]['args']) : '', + 'Trace' => $this->_escapeTrace(array_splice($trace, $i + 1)) + ); + break; + } + } + return $message; + } +/** + * Fix a trace for use in output + * + * @param mixed $trace Trace to fix + * @access protected + * @static + * @return string + **/ + function _escapeTrace($trace) { + for ($i = 0, $len = count($trace); $i < $len; $i++) { + if (isset($trace[$i]['file'])) { + $trace[$i]['file'] = Debugger::trimPath($trace[$i]['file']); + } + if (isset($trace[$i]['args'])) { + $trace[$i]['args'] = $this->stringEncode($trace[$i]['args']); + } + } + return $trace; + } +/** + * Encode non string objects to string. + * Filter out recursion, so no errors are raised by json_encode or $javascript->object() + * + * @param mixed $object Object or variable to encode to string. + * @param int $objectDepth Current Depth in object chains. + * @param int $arrayDepth Current Depth in array chains. + * @static + * @return void + **/ + function stringEncode($object, $objectDepth = 1, $arrayDepth = 1) { + $_this =& FireCake::getInstance(); + $return = array(); + if (is_resource($object)) { + return '** ' . (string)$object . '**'; + } + if (is_object($object)) { + if ($objectDepth == $_this->options['maxObjectDepth']) { + return '** Max Object Depth (' . $_this->options['maxObjectDepth'] . ') **'; + } + foreach ($_this->_encodedObjects as $encoded) { + if ($encoded === $object) { + return '** Recursion (' . get_class($object) . ') **'; + } + } + $_this->_encodedObjects[] =& $object; + + $return['__className'] = $class = get_class($object); + $properties = (array)$object; + foreach ($properties as $name => $property) { + $return[$name] = FireCake::stringEncode($property, 1, $objectDepth + 1); + } + array_pop($_this->_encodedObjects); + } + if (is_array($object)) { + if ($arrayDepth == $_this->options['maxArrayDepth']) { + return '** Max Array Depth ('. $_this->options['maxArrayDepth'] . ') **'; + } + foreach ($object as $key => $value) { + $return[$key] = FireCake::stringEncode($value, 1, $arrayDepth + 1); + } + } + if (is_string($object) || is_numeric($object) || is_bool($object) || is_null($object)) { + return $object; + } + return $return; + } +/** + * Encode an object into JSON + * + * @param mixed $object Object or array to json encode + * @param boolean $doIt + * @access public + * @static + * @return string + **/ + function jsonEncode($object, $skipEncode = false) { + $_this =& FireCake::getInstance(); + if (!$skipEncode) { + $object = FireCake::stringEncode($object); + } + + if (function_exists('json_encode') && $_this->options['useNativeJsonEncode']) { + return json_encode($object); + } else { + return FireCake::_jsonEncode($object); + } + } +/** + * jsonEncode Helper method for PHP4 compatibility + * + * @param mixed $object Something to encode + * @access protected + * @static + * @return string + **/ + function _jsonEncode($object) { + if (!class_exists('JavascriptHelper')) { + App::import('Helper', 'Javascript'); + } + $javascript =& new JavascriptHelper(); + $javascript->useNative = false; + if (is_string($object)) { + return '"' . $javascript->escapeString($object) . '"'; + } + return $javascript->object($object); + } +/** + * Send Headers - write headers. + * + * @access protected + * @return void + **/ + function _sendHeader($name, $value) { + header($name . ': ' . $value); + } +} diff --git a/code/ryzom/tools/server/www/webtt/plugins/debug_kit/vendors/shells/benchmark.php b/code/ryzom/tools/server/www/webtt/plugins/debug_kit/vendors/shells/benchmark.php new file mode 100644 index 000000000..eb2a3dcc4 --- /dev/null +++ b/code/ryzom/tools/server/www/webtt/plugins/debug_kit/vendors/shells/benchmark.php @@ -0,0 +1,167 @@ +args) || count($this->args) > 1) { + return $this->help(); + } + + $url = $this->args[0]; + $defaults = array('t' => 100, 'n' => 10); + $options = array_merge($defaults, $this->params); + $times = array(); + + $this->out(String::insert(__d('debug_kit', '-> Testing :url', true), compact('url'))); + $this->out(""); + for ($i = 0; $i < $options['n']; $i++) { + if (floor($options['t'] - array_sum($times)) <= 0 || $options['n'] <= 1) { + break; + } + + $start = microtime(true); + file_get_contents($url); + $stop = microtime(true); + + $times[] = $stop - $start; + } + $this->_results($times); + } +/** + * Prints calculated results + * + * @param array $times Array of time values + * @return void + * @access protected + */ + function _results($times) { + $duration = array_sum($times); + $requests = count($times); + + $this->out(String::insert(__d('debug_kit', 'Total Requests made: :requests', true), compact('requests'))); + $this->out(String::insert(__d('debug_kit', 'Total Time elapsed: :duration (seconds)', true), compact('duration'))); + + $this->out(""); + + $this->out(String::insert(__d('debug_kit', 'Requests/Second: :rps req/sec', true), array( + 'rps' => round($requests / $duration, 3) + ))); + + $this->out(String::insert(__d('debug_kit', 'Average request time: :average-time seconds', true), array( + 'average-time' => round($duration / $requests, 3) + ))); + + $this->out(String::insert(__d('debug_kit', 'Standard deviation of average request time: :std-dev', true), array( + 'std-dev' => round($this->_deviation($times, true), 3) + ))); + + $this->out(String::insert(__d('debug_kit', 'Longest/shortest request: :longest sec/:shortest sec', true), array( + 'longest' => round(max($times), 3), + 'shortest' => round(min($times), 3) + ))); + + $this->out(""); + + } +/** + * One-pass, numerically stable calculation of population variance. + * + * Donald E. Knuth (1998). + * The Art of Computer Programming, volume 2: Seminumerical Algorithms, 3rd edn., + * p. 232. Boston: Addison-Wesley. + * + * @param array $times Array of values + * @param boolean $sample If true, calculates an unbiased estimate of the population + * variance from a finite sample. + * @return float Variance + * @access protected + */ + function _variance($times, $sample = true) { + $n = $mean = $M2 = 0; + + foreach($times as $time){ + $n += 1; + $delta = $time - $mean; + $mean = $mean + $delta/$n; + $M2 = $M2 + $delta*($time - $mean); + } + + if ($sample) $n -= 1; + + return $M2/$n; + } +/** + * Calculate the standard deviation. + * + * @param array $times Array of values + * @return float Standard deviation + * @access protected + */ + function _deviation($times, $sample = true) { + return sqrt($this->_variance($times, $sample)); + } +/** + * Help for Benchmark shell + * + * @return void + * @access public + */ + function help() { + $this->out(__d('debug_kit', "DebugKit Benchmark Shell", true)); + $this->out(""); + $this->out(__d('debug_kit', "\tAllows you to obtain some rough benchmarking statistics \n\tabout a fully qualified URL.", true)); + $this->out(""); + $this->out(__d('debug_kit', "\tUse:", true)); + $this->out(__d('debug_kit', "\t\tcake benchmark [-n iterations] [-t timeout] url", true)); + $this->out(""); + $this->out(__d('debug_kit', "\tParams:", true)); + $this->out(__d('debug_kit', "\t\t-n Number of iterations to perform. Defaults to 10. \n\t\t Must be an integer.", true)); + $this->out(__d('debug_kit', "\t\t-t Maximum total time for all iterations, in seconds. \n\t\t Defaults to 100. Must be an integer.", true)); + $this->out(""); + $this->out(__d('debug_kit', "\tIf a single iteration takes more than the \n\ttimeout specified, only one request will be made.", true)); + $this->out(""); + $this->out(__d('debug_kit', "\tExample Use:", true)); + $this->out(__d('debug_kit', "\t\tcake benchmark -n 10 -t 100 http://localhost/testsite", true)); + $this->out(""); + $this->out(__d('debug_kit', "\tNote that this benchmark does not include browser render time", true)); + $this->out(""); + $this->hr(); + $this->out(""); + } +} + diff --git a/code/ryzom/tools/server/www/webtt/plugins/debug_kit/vendors/shells/whitespace.php b/code/ryzom/tools/server/www/webtt/plugins/debug_kit/vendors/shells/whitespace.php new file mode 100644 index 000000000..d5185d454 --- /dev/null +++ b/code/ryzom/tools/server/www/webtt/plugins/debug_kit/vendors/shells/whitespace.php @@ -0,0 +1,69 @@ +findRecursive('.*\.php'); + $this->out("Checking *.php in ".ROOT); + foreach($r as $file) { + $c = file_get_contents($file); + if (preg_match('/^[\n\r|\n\r|\n|\r|\s]+\<\?php/',$c)) { + $this->out('!!!contains leading whitespaces: '.$this->shortPath($file)); + } + if (preg_match('/\?\>[\n\r|\n\r|\n|\r|\s]+$/',$c)) { + $this->out('!!!contains trailing whitespaces: '.$this->shortPath($file)); + } + } + } + +/** + * Much like main() except files are modified. Be sure to have + * backups or use version control. + * + * @return void + */ + function trim() { + $siteRoot = new Folder(ROOT); + + $r = $siteRoot->findRecursive('.*\.php'); + $this->out("Checking *.php in ".ROOT); + foreach($r as $file) { + $c = file_get_contents($file); + if (preg_match('/^[\n\r|\n\r|\n|\r|\s]+\<\?php/', $c) || preg_match('/\?\>[\n\r|\n\r|\n|\r|\s]+$/', $c)) { + $this->out('trimming' . $this->shortPath($file)); + $c = preg_replace('/^[\n\r|\n\r|\n|\r|\s]+\<\?php/', '[\n\r|\n\r|\n|\r|\s]+$/', '?>', $c); + file_put_contents($file, $c); + } + } + } +} diff --git a/code/ryzom/tools/server/www/webtt/plugins/debug_kit/views/debug.php b/code/ryzom/tools/server/www/webtt/plugins/debug_kit/views/debug.php new file mode 100644 index 000000000..43601e72d --- /dev/null +++ b/code/ryzom/tools/server/www/webtt/plugins/debug_kit/views/debug.php @@ -0,0 +1,100 @@ +params['url']['ext']) && $this->params['url']['ext'] === 'html') || + !isset($this->params['url']['ext']) + ); + if ($isHtml) { + $out .= sprintf("\n", __d('debug_kit', 'Starting to render', true), $name); + } + $out .= parent::element($name, $params, $loadHelpers); + if ($isHtml) { + $out .= sprintf("\n\n", __d('debug_kit', 'Finished', true), $name); + } + return $out; + } + +/** + * Renders view for given action and layout. If $file is given, that is used + * for a view filename (e.g. customFunkyView.ctp). + * Adds timers, for all subsequent rendering, and injects the debugKit toolbar. + * + * @param string $action Name of action to render for + * @param string $layout Layout to use + * @param string $file Custom filename for view + * @return string Rendered Element + */ + function render($action = null, $layout = null, $file = null) { + DebugKitDebugger::startTimer('viewRender', __d('debug_kit', 'Rendering View', true)); + + $out = parent::render($action, $layout, $file); + + DebugKitDebugger::stopTimer('viewRender'); + DebugKitDebugger::stopTimer('controllerRender'); + DebugKitDebugger::setMemoryPoint(__d('debug_kit', 'View render complete', true)); + + if (empty($this->params['requested']) && isset($this->loaded['toolbar'])) { + $backend = $this->loaded['toolbar']->getName(); + $this->loaded['toolbar']->{$backend}->send(); + } + if (empty($this->output)) { + return $out; + } + return $this->output; + } +} diff --git a/code/ryzom/tools/server/www/webtt/plugins/debug_kit/views/elements/debug_toolbar.ctp b/code/ryzom/tools/server/www/webtt/plugins/debug_kit/views/elements/debug_toolbar.ctp new file mode 100644 index 000000000..327f0eb85 --- /dev/null +++ b/code/ryzom/tools/server/www/webtt/plugins/debug_kit/views/elements/debug_toolbar.ctp @@ -0,0 +1,58 @@ + +
    + +

    + + + +
    diff --git a/code/ryzom/tools/server/www/webtt/plugins/debug_kit/views/elements/history_panel.ctp b/code/ryzom/tools/server/www/webtt/plugins/debug_kit/views/elements/history_panel.ctp new file mode 100644 index 000000000..8f4cdab4d --- /dev/null +++ b/code/ryzom/tools/server/www/webtt/plugins/debug_kit/views/elements/history_panel.ctp @@ -0,0 +1,195 @@ + +

    + +

    + + +
      +
    • link(__d('debug_kit', 'Restore to current request', true), + '#', array('class' => 'history-link', 'id' => 'history-restore-current')); ?> +
    • + +
    • link($previous['title'], $previous['url'], array('class' => 'history-link')); ?>
    • + +
    + + + \ No newline at end of file diff --git a/code/ryzom/tools/server/www/webtt/plugins/debug_kit/views/elements/log_panel.ctp b/code/ryzom/tools/server/www/webtt/plugins/debug_kit/views/elements/log_panel.ctp new file mode 100644 index 000000000..ae8a406e2 --- /dev/null +++ b/code/ryzom/tools/server/www/webtt/plugins/debug_kit/views/elements/log_panel.ctp @@ -0,0 +1,40 @@ + +

    +
    + $logs): ?> +

    + 0): + $headers = array(__d('debug_kit', 'Time', true), __d('debug_kit', 'Message', true)); + $rows = array(); + for ($i = 0; $i < $len; $i += 2): + $rows[] = array( + $logs[$i][0], h($logs[$i][1]) + ); + endfor; + echo $toolbar->table($rows, $headers, array('title' => $logName)); + else: ?> +

    + + +
    \ No newline at end of file diff --git a/code/ryzom/tools/server/www/webtt/plugins/debug_kit/views/elements/request_panel.ctp b/code/ryzom/tools/server/www/webtt/plugins/debug_kit/views/elements/request_panel.ctp new file mode 100644 index 000000000..310090ea9 --- /dev/null +++ b/code/ryzom/tools/server/www/webtt/plugins/debug_kit/views/elements/request_panel.ctp @@ -0,0 +1,36 @@ + +

    +

    Cake Params

    +makeNeatArray($content['params']); ?> + +

    $_GET

    +makeNeatArray($content['get']); ?> + +

    Cookie

    + + makeNeatArray($content['cookie']); ?> + +

    To view Cookies, add CookieComponent to Controller

    + + +

    +makeNeatArray($content['currentRoute']); ?> \ No newline at end of file diff --git a/code/ryzom/tools/server/www/webtt/plugins/debug_kit/views/elements/session_panel.ctp b/code/ryzom/tools/server/www/webtt/plugins/debug_kit/views/elements/session_panel.ctp new file mode 100644 index 000000000..c729a8273 --- /dev/null +++ b/code/ryzom/tools/server/www/webtt/plugins/debug_kit/views/elements/session_panel.ctp @@ -0,0 +1,22 @@ + +

    +makeNeatArray($content); ?> \ No newline at end of file diff --git a/code/ryzom/tools/server/www/webtt/plugins/debug_kit/views/elements/sql_log_panel.ctp b/code/ryzom/tools/server/www/webtt/plugins/debug_kit/views/elements/sql_log_panel.ctp new file mode 100755 index 000000000..148c694dc --- /dev/null +++ b/code/ryzom/tools/server/www/webtt/plugins/debug_kit/views/elements/sql_log_panel.ctp @@ -0,0 +1,105 @@ +readCache('sql_log', $this->params['pass'][0]); +} +?> +

    + + $explain): ?> +
    +

    + getQueryLogs($dbName, array( + 'explain' => $explain, 'threshold' => $content['threshold'] + )); + else: + $queryLog = $content[$dbName]; + endif; + echo $toolbar->table($queryLog, $headers, array('title' => 'SQL Log ' . $dbName)); + ?> +

    +
    + +

    +
    +
    + +message('Warning', __d('debug_kit', 'No active database connections', true)); +endif; ?> + + \ No newline at end of file diff --git a/code/ryzom/tools/server/www/webtt/plugins/debug_kit/views/elements/timer_panel.ctp b/code/ryzom/tools/server/www/webtt/plugins/debug_kit/views/elements/timer_panel.ctp new file mode 100644 index 000000000..c5c010937 --- /dev/null +++ b/code/ryzom/tools/server/www/webtt/plugins/debug_kit/views/elements/timer_panel.ctp @@ -0,0 +1,108 @@ +readCache('timer', $this->params['pass'][0]); + if (is_array($content)): + extract($content); + endif; +endif; +?> +
    +

    +
    + message(__d('debug_kit', 'Peak Memory Use', true), $number->toReadableSize($peakMemory)); ?> +
    + + $value): + $rows[] = array($key, $number->toReadableSize($value)); + endforeach; + + echo $toolbar->table($rows, $headers); + ?> +
    + +
    +

    +
    + precision($requestTime * 1000, 0)); ?> + message(__d('debug_kit', 'Total Request Time:', true), $totalTime)?> +
    + $timeInfo): + $indent = 0; + for ($j = 0; $j < $i; $j++) { + if (($values[$j]['end'] > $timeInfo['start']) && ($values[$j]['end']) > ($timeInfo['end'])) { + $indent++; + } + } + $indent = str_repeat(' » ', $indent); + $rows[] = array( + $indent . $timeInfo['message'], + $number->precision($timeInfo['time'] * 1000, 2), + $simpleGraph->bar( + $number->precision($timeInfo['time'] * 1000, 2), + $number->precision($timeInfo['start'] * 1000, 2), + array( + 'max' => $maxTime * 1000, + 'requestTime' => $requestTime * 1000, + ) + ) + ); + $i++; +endforeach; + +if (strtolower($toolbar->getName()) == 'firephptoolbar'): + for ($i = 0, $len = count($rows); $i < $len; $i++): + unset($rows[$i][2]); + endfor; + unset($headers[2]); +endif; + +echo $toolbar->table($rows, $headers, array('title' => 'Timers')); + +if (!isset($debugKitInHistoryMode)): + $toolbar->writeCache('timer', compact('timers', 'currentMemory', 'peakMemory', 'requestTime')); +endif; +?> +
    \ No newline at end of file diff --git a/code/ryzom/tools/server/www/webtt/plugins/debug_kit/views/elements/variables_panel.ctp b/code/ryzom/tools/server/www/webtt/plugins/debug_kit/views/elements/variables_panel.ctp new file mode 100644 index 000000000..3be537d6a --- /dev/null +++ b/code/ryzom/tools/server/www/webtt/plugins/debug_kit/views/elements/variables_panel.ctp @@ -0,0 +1,25 @@ + +

    +validationErrors'] = $this->validationErrors; +$content['Loaded Helpers'] = array_keys($this->loaded); +echo $toolbar->makeNeatArray($content); ?> \ No newline at end of file diff --git a/code/ryzom/tools/server/www/webtt/plugins/debug_kit/views/helpers/fire_php_toolbar.php b/code/ryzom/tools/server/www/webtt/plugins/debug_kit/views/helpers/fire_php_toolbar.php new file mode 100644 index 000000000..e8bb814af --- /dev/null +++ b/code/ryzom/tools/server/www/webtt/plugins/debug_kit/views/helpers/fire_php_toolbar.php @@ -0,0 +1,99 @@ + 'firePHP', 'forceEnable' => false); +/** + * send method + * + * @return void + * @access protected + */ + function send() { + $view =& ClassRegistry::getObject('view'); + $view->element('debug_toolbar', array('plugin' => 'debug_kit', 'disableTimer' => true)); + } +/** + * makeNeatArray. + * + * wraps FireCake::dump() allowing panel elements to continue functioning + * + * @param string $values + * @return void + */ + function makeNeatArray($values) { + FireCake::info($values); + } +/** + * Create a simple message + * + * @param string $label Label of message + * @param string $message Message content + * @return void + */ + function message($label, $message) { + FireCake::log($message, $label); + } +/** + * Generate a table with FireCake + * + * @param array $rows Rows to print + * @param array $headers Headers for table + * @param array $options Additional options and params + * @return void + */ + function table($rows, $headers, $options = array()) { + $title = $headers[0]; + if (isset($options['title'])) { + $title = $options['title']; + } + foreach ($rows as $i => $row) { + $rows[$i] = array_values($row); + } + array_unshift($rows, $headers); + FireCake::table($title, $rows); + } +/** + * Start a panel which is a 'Group' in FirePHP + * + * @return void + **/ + function panelStart($title, $anchor) { + FireCake::group($title); + } +/** + * End a panel (Group) + * + * @return void + **/ + function panelEnd() { + FireCake::groupEnd(); + } +} diff --git a/code/ryzom/tools/server/www/webtt/plugins/debug_kit/views/helpers/html_toolbar.php b/code/ryzom/tools/server/www/webtt/plugins/debug_kit/views/helpers/html_toolbar.php new file mode 100755 index 000000000..f772870ce --- /dev/null +++ b/code/ryzom/tools/server/www/webtt/plugins/debug_kit/views/helpers/html_toolbar.php @@ -0,0 +1,191 @@ + 'html', 'forceEnable' => false); +/** + * Recursively goes through an array and makes neat HTML out of it. + * + * @param mixed $values Array to make pretty. + * @param int $openDepth Depth to add open class + * @param int $currentDepth current depth. + * @return string + **/ + function makeNeatArray($values, $openDepth = 0, $currentDepth = 0) { + $className ="neat-array depth-$currentDepth"; + if ($openDepth > $currentDepth) { + $className .= ' expanded'; + } + $nextDepth = $currentDepth + 1; + $out = "
      "; + if (!is_array($values)) { + if (is_bool($values)) { + $values = array($values); + } + if (is_null($values)) { + $values = array(null); + } + } + if (empty($values)) { + $values[] = '(empty)'; + } + foreach ($values as $key => $value) { + $out .= '
    • ' . $key . ''; + if ($value === null) { + $value = '(null)'; + } + if ($value === false) { + $value = '(false)'; + } + if ($value === true) { + $value = '(true)'; + } + if (empty($value) && $value != 0) { + $value = '(empty)'; + } + + if (is_object($value)) { + $value = Set::reverse($value, true); + } + + if (is_array($value) && !empty($value)) { + $out .= $this->makeNeatArray($value, $openDepth, $nextDepth); + } else { + $out .= h($value); + } + $out .= '
    • '; + } + $out .= '
    '; + return $out; + } +/** + * Create an HTML message + * + * @param string $label label content + * @param string $message message content + * @return string + */ + function message($label, $message) { + return sprintf('

    %s %s

    ', $label, $message); + } +/** + * Start a panel. + * make a link and anchor. + * + * @return void + **/ + function panelStart($title, $anchor) { + $link = $this->Html->link($title, '#' . $anchor); + return $link; + } +/** + * Create a table. + * + * @param array $rows Rows to make. + * @param array $headers Optional header row. + * @return string + */ + function table($rows, $headers = array()) { + $out = ''; + if (!empty($headers)) { + $out .= $this->Html->tableHeaders($headers); + } + $out .= $this->Html->tableCells($rows, array('class' => 'odd'), array('class' => 'even'), false, false); + $out .= '
    '; + return $out; + } +/** + * send method + * + * @return void + * @access public + */ + function send() { + if (!$this->settings['forceEnable'] && Configure::read('debug') == 0) { + return; + } + $view =& ClassRegistry::getObject('view'); + $head = $this->Html->css('/debug_kit/css/debug_toolbar'); + if (isset($view->viewVars['debugToolbarJavascript'])) { + foreach ($view->viewVars['debugToolbarJavascript'] as $script) { + if ($script) { + $head .= $this->Html->script($script); + } + } + } + if (preg_match('##', $view->output)) { + $view->output = preg_replace('##', $head . "\n", $view->output, 1); + } + $toolbar = $view->element('debug_toolbar', array('plugin' => 'debug_kit', 'disableTimer' => true)); + if (preg_match('##', $view->output)) { + $view->output = preg_replace('##', $toolbar . "\n", $view->output, 1); + } + } +/** + * Generates a SQL explain link for a given query + * + * @param string $sql SQL query string you want an explain link for. + * @return string Rendered Html link or '' if the query is not a select/describe + */ + function explainLink($sql, $connection) { + if (!preg_match('/^(SELECT)/i', $sql)) { + return ''; + } + App::import('Core', 'Security'); + $hash = Security::hash($sql . $connection, null, true); + $url = array( + 'plugin' => 'debug_kit', + 'controller' => 'toolbar_access', + 'action' => 'sql_explain' + ); + foreach (Router::prefixes() as $prefix) { + $url[$prefix] = false; + } + $this->explainLinkUid = (isset($this->explainLinkUid) ? $this->explainLinkUid + 1 : 0); + $uid = $this->explainLinkUid . '_' . rand(0, 10000); + $form = $this->Form->create('log', array('url' => $url, 'id' => "logForm{$uid}")); + $form .= $this->Form->hidden('log.ds', array('id' => "logDs{$uid}", 'value' => $connection)); + $form .= $this->Form->hidden('log.sql', array('id' => "logSql{$uid}", 'value' => $sql)); + $form .= $this->Form->hidden('log.hash', array('id' => "logHash{$uid}", 'value' => $hash)); + $form .= $this->Form->submit(__d('debug_kit', 'Explain', true), array( + 'div' => false, + 'class' => 'sql-explain-link' + )); + $form .= $this->Form->end(); + return $form; + } +} diff --git a/code/ryzom/tools/server/www/webtt/plugins/debug_kit/views/helpers/simple_graph.php b/code/ryzom/tools/server/www/webtt/plugins/debug_kit/views/helpers/simple_graph.php new file mode 100644 index 000000000..22c17865c --- /dev/null +++ b/code/ryzom/tools/server/www/webtt/plugins/debug_kit/views/helpers/simple_graph.php @@ -0,0 +1,84 @@ + (int) Maximum value in the graphs + * - width => (int) + * - valueType => string (value, percentage) + * - style => array + * + * @var array + */ + var $__defaultSettings = array( + 'max' => 100, + 'width' => 350, + 'valueType' => 'value', + ); +/** + * bar method + * + * @param $value Value to be graphed + * @param $offset how much indentation + * @param $options Graph options + * @return string Html graph + * @access public + */ + function bar($value, $offset, $options = array()) { + $settings = array_merge($this->__defaultSettings, $options); + extract($settings); + + $graphValue = ($value / $max) * $width; + $graphValue = max(round($graphValue), 1); + + if ($valueType == 'percentage') { + $graphOffset = 0; + } else { + $graphOffset = ($offset / $max) * $width; + $graphOffset = round($graphOffset); + } + return $this->Html->div( + 'debug-kit-graph-bar', + $this->Html->div( + 'debug-kit-graph-bar-value', + ' ', + array( + 'style' => "margin-left: {$graphOffset}px; width: {$graphValue}px", + 'title' => sprintf(__d('debug_kit', "Starting %sms into the request, taking %sms", true), $offset, $value), + ) + ), + array('style' => "width: {$width}px;"), + false + ); + } +} diff --git a/code/ryzom/tools/server/www/webtt/plugins/debug_kit/views/helpers/toolbar.php b/code/ryzom/tools/server/www/webtt/plugins/debug_kit/views/helpers/toolbar.php new file mode 100644 index 000000000..1ae3a9734 --- /dev/null +++ b/code/ryzom/tools/server/www/webtt/plugins/debug_kit/views/helpers/toolbar.php @@ -0,0 +1,182 @@ +_myName = strtolower(get_class($this)); + $this->settings = am($this->settings, $options); + + if ($this->_myName !== 'toolbarhelper') { + return; + } + + if (!isset($options['output'])) { + $options['output'] = 'DebugKit.HtmlToolbar'; + } + App::import('Helper', $options['output']); + $className = $options['output']; + if (strpos($options['output'], '.') !== false) { + list($plugin, $className) = explode('.', $options['output']); + } + $this->_backEndClassName = $className; + $this->helpers[$options['output']] = $options; + if (isset($options['cacheKey']) && isset($options['cacheConfig'])) { + $this->_cacheKey = $options['cacheKey']; + $this->_cacheConfig = $options['cacheConfig']; + $this->_cacheEnabled = true; + } + } +/** + * Get the name of the backend Helper + * used to conditionally trigger toolbar output + * + * @return string + **/ + function getName() { + return $this->_backEndClassName; + } +/** + * call__ + * + * Allows method calls on backend helper + * + * @param string $method + * @param mixed $params + * @access public + * @return void + */ + function call__($method, $params) { + if (method_exists($this->{$this->_backEndClassName}, $method)) { + return $this->{$this->_backEndClassName}->dispatchMethod($method, $params); + } + } +/** + * Allows for writing to panel cache from view. + * Some panels generate all variables in the view by + * necessity ie. Timer. Using this method, will allow you to replace in full + * the content for a panel. + * + * @param string $name Name of the panel you are replacing. + * @param string $content Content to write to the panel. + * @return boolean Sucess of write. + **/ + function writeCache($name, $content) { + if (!$this->_cacheEnabled) { + return false; + } + $existing = (array)Cache::read($this->_cacheKey, $this->_cacheConfig); + $existing[0][$name]['content'] = $content; + return Cache::write($this->_cacheKey, $existing, $this->_cacheConfig); + } +/** + * Read the toolbar + * + * @param string $name Name of the panel you want cached data for + * @return mixed Boolean false on failure, array of data otherwise. + **/ + function readCache($name, $index = 0) { + if (!$this->_cacheEnabled) { + return false; + } + $existing = (array)Cache::read($this->_cacheKey, $this->_cacheConfig); + if (!isset($existing[$index][$name]['content'])) { + return false; + } + return $existing[$index][$name]['content']; + } +/** + * Gets the query logs for the given connection names. + * + * ### Options + * + * - explain - Whether explain links should be generated for this connection. + * - cache - Whether the toolbar_state Cache should be updated. + * - threshold - The threshold at which a visual 'maybe slow' flag should be added. + * results with rows/ms lower than $threshold will be marked. + * + * @param string $connection Connection name to get logs for. + * @param array $options Options for the query log retrieval. + * @return array Array of data to be converted into a table. + */ + function getQueryLogs($connection, $options = array()) { + $options += array('explain' => false, 'cache' => true, 'threshold' => 20); + App::import('Model', 'ConnectionManager'); + $db =& ConnectionManager::getDataSource($connection); + + if (!$db->isInterfaceSupported('getLog')) { + return array(); + } + + $out = array(); + $log = $db->getLog(); + foreach ($log['log'] as $i => $query) { + $isSlow = ( + $query['took'] > 0 && + $query['numRows'] / $query['took'] != 1 && + $query['numRows'] / $query['took'] <= $options['threshold'] + ); + $query['actions'] = ''; + $isHtml = ($this->getName() == 'HtmlToolbar'); + if ($isSlow && $isHtml) { + $query['actions'] = sprintf( + '%s', + __d('debug_kit', 'maybe slow', true) + ); + } elseif ($isSlow) { + $query['actions'] = '*'; + } + if ($options['explain'] && $isHtml) { + $query['actions'] .= $this->explainLink($query['query'], $connection); + } + if ($isHtml) { + $query['query'] = h($query['query']); + } + $out[] = $query; + } + if ($options['cache']) { + $existing = $this->readCache('sql_log'); + $existing[$connection] = $out; + $this->writeCache('sql_log', $existing); + } + return $out; + } +} diff --git a/code/ryzom/tools/server/www/webtt/plugins/debug_kit/views/toolbar_access/history_state.ctp b/code/ryzom/tools/server/www/webtt/plugins/debug_kit/views/toolbar_access/history_state.ctp new file mode 100644 index 000000000..21a1dcfef --- /dev/null +++ b/code/ryzom/tools/server/www/webtt/plugins/debug_kit/views/toolbar_access/history_state.ctp @@ -0,0 +1,29 @@ + $panel) { + $panels[$panelName] = $this->element($panel['elementName'], array( + 'content' => $panel['content'], + 'plugin' => $panel['plugin'] + )); +} +echo $javascript->object($panels); +Configure::write('debug', 0); +?> \ No newline at end of file diff --git a/code/ryzom/tools/server/www/webtt/plugins/debug_kit/views/toolbar_access/sql_explain.ctp b/code/ryzom/tools/server/www/webtt/plugins/debug_kit/views/toolbar_access/sql_explain.ctp new file mode 100644 index 000000000..a38939005 --- /dev/null +++ b/code/ryzom/tools/server/www/webtt/plugins/debug_kit/views/toolbar_access/sql_explain.ctp @@ -0,0 +1,12 @@ + +tableHeaders($headers); +echo $html->tableCells($result); +?> +
    + \ No newline at end of file diff --git a/code/ryzom/tools/server/www/webtt/plugins/debug_kit/webroot/css/debug_toolbar.css b/code/ryzom/tools/server/www/webtt/plugins/debug_kit/webroot/css/debug_toolbar.css new file mode 100644 index 000000000..46939561a --- /dev/null +++ b/code/ryzom/tools/server/www/webtt/plugins/debug_kit/webroot/css/debug_toolbar.css @@ -0,0 +1,377 @@ +/* @override http://localhost/mark_story/site/debug_kit/css/debug_toolbar.css */ +#debug-kit-toolbar { + position: fixed; + top: 0px; + right:0px; + width: 100%; + height: 1%; + overflow: visible; + z-index:10000; + font-family: helvetica, arial, sans-serif; + font-size: 12px; + direction: ltr; +} +#debug-kit-toolbar img { + border:0; + outline:0; +} + +/* panel tabs */ +#debug-kit-toolbar #panel-tabs { + float: right; + list-style: none; + margin: 0; +} +#debug-kit-toolbar .panel-tab { + clear: none; + float: left; + margin: 0; + padding: 0; + list-style: none; +} +#debug-kit-toolbar .panel-tab > a { + float: left; + clear: none; + background: #efefef; + background: -webkit-gradient(linear, left top, left bottom, from(#efefef), to(#cacaca)); + background: -moz-linear-gradient(top, #efefef, #cacaca); + color: #222; + padding: 6px; + border-right: 1px solid #ccc; + border-bottom: 1px solid #aaa; + font-size: 12px; + line-height: 16px; + margin: 0; + display: block; + text-decoration:none; + text-shadow:1px 1px #eee; + -moz-text-shadow:1px 1px #eee; + -webkit-text-shadow:1px 1px #eee; +} +#debug-kit-toolbar .panel-tab .active { + background: #fff; + background: -webkit-gradient(linear, left top, left bottom, from(#f5f5f5), to(#fff)); + background: -moz-linear-gradient(top, #f5f5f5, #fff); +} +#debug-kit-toolbar .panel-tab > a:hover { + background: #fff; + background: -webkit-gradient(linear, left top, left bottom, from(#f5f5f5), to(#fff)); + background: -moz-linear-gradient(top, #f5f5f5, #fff); + text-decoration:underline; +} +#debug-kit-toolbar .panel-tab.icon a { + padding: 4px; +} +#debug-kit-toolbar .panel-tab a.edit-value { + float: none; + display: inline; +} + +/* Hovering over link shows tab, useful for no js */ +#debug-kit-toolbar .panel-tab a:hover + .panel-content, +#debug-kit-toolbar .panel-tab a + .panel-content:hover { + display: block; +} +#debug-kit-toolbar .panel-tab.icon a { + -webkit-border-top-left-radius: 8px 8px; + -webkit-border-bottom-left-radius: 8px 8px; + -moz-border-radius-topleft: 8px; + -moz-border-radius-bottomleft: 8px +} +#debug-kit-toolbar .panel-tab.icon img { + display:block; +} + +/* panel content */ +#debug-kit-toolbar .panel-content { + position: absolute; + text-align: left; + width: auto; + top:28px; + right:0px; + background: #fff; + color: #000; + width:100%; + box-shadow:0px 5px 6px #ccc; + height: 200px; + overflow: hidden; +} + +#debug-kit-toolbar .panel-resize-region { + padding:15px; + position: absolute; + top: 0px; + bottom: 14px; + left: 0px; + right: 0px; + overflow: auto; +} + +#debug-kit-toolbar .ui-control { + background:#ccc; + background: -webkit-gradient(linear, left top, left bottom, from(#d6d6d6), to(#c2c2c2)); + background: -moz-linear-gradient(top, #d6d6d6, #c2c2c2); + text-align:center; + border-top:1px solid #afafaf; + border-bottom:1px solid #7c7c7c; + color:#666; + text-shadow: 1px 1px #eee; + -webkit-text-shadow: 1px 1px #eee; + -moz-text-shadow: 1px 1px #eee; +} +#debug-kit-toolbar .ui-button { + -webkit-border-radius: 5px; + -moz-border-radius: 5px; + border-radius: 5px; +} +#debug-kit-toolbar .ui-button:hover { + text-decoration: none; + background:#ccc; + background: -webkit-gradient(linear, left top, left bottom, from(#c2c2c2), to(#d6d6d6)); + background: -moz-linear-gradient(top, #c2c2c2, #d6d6d6); +} +#debug-kit-toolbar .panel-resize-handle { + cursor: row-resize; + height:14px; + line-height: 14px; + position: absolute; + bottom: 0px; + left: 0px; + right: 0px; +} +#debug-kit-toolbar .panel-maximize, +#debug-kit-toolbar .panel-minimize { + float: right; + display: block; + width: 12px; + height: 12px; + line-height: 12px; + border-left: 1px solid #afafaf; + border-right: 1px solid #7c7c7c; +} +#debug-kit-toolbar .panel-maximize { + float: right; + margin: 10px 20px 0 0; + z-index: 999; + position: relative; +} +#debug-kit-toolbar .panel-minimize { + float: right; + margin: 10px 10px 0 0; + z-index: 999; + position: relative; +} + +/* Hide panel content by default */ +#debug-kit-toolbar .panel-content { + display: none; +} +.panel-content p { + margin: 1em 0; +} +.panel-content h2 { + padding: 0; + margin-top:0; +} +.panel-content h3 { + padding: 0; + margin-top: 1em; +} +.panel-content .info { + padding: 4px; + border-top: 1px dashed #6c6cff; + border-bottom: 1px dashed #6c6cff; +} +#debug-kit-toolbar h1, +#debug-kit-toolbar h2, +#debug-kit-toolbar h3, +#debug-kit-toolbar h4, +#debug-kit-toolbar h5, +#debug-kit-toolbar th { + color: #5d1717; + font-family: "Trebuchet MS", trebuchet, helvetica, arial, sans-serif; + margin-bottom:0.6em; + background:none; +} +#debug-kit-toolbar h1 { + font-size: 18px; +} +#debug-kit-toolbar h2 { + font-size: 16px; +} +#debug-kit-toolbar h4 { + font-size: 14px; +} + + +/* panel tables */ +#debug-kit-toolbar table.debug-table { + width: 100%; + border: 0; + clear:both; + margin-bottom: 20px; +} +#debug-kit-toolbar table.debug-table td, +#debug-kit-toolbar table.debug-table th { + text-align: left; + border: 0; + padding: 3px; +} +#debug-kit-toolbar table.debug-table th { + border-bottom: 1px solid #222; + background: 0; + color: #252525; +} +#debug-kit-toolbar table.debug-table tr:nth-child(2n+1) td { + background:#f6f6f6; +} +#debug-kit-toolbar table.debug-table tr.even td { + background:#f7f7f7; +} +#debug-kit-toolbar .debug-timers .debug-table td:nth-child(2), +#debug-kit-toolbar .debug-timers .debug-table th:nth-child(2) { + text-align:right; +} + +/** code tables **/ +#debug-kit-toolbar .code-table td { + white-space: pre; + font-family: monaco, Consolas, "courier new", courier, monospaced; +} +#debug-kit-toolbar .code-table td:first-child { + width: 15%; +} +#debug-kit-toolbar .code-table td:last-child { + width: 80%; +} + +#debug-kit-toolbar .panel-content.request { + display: block; +} + +/** Neat Array styles **/ +#debug-kit-toolbar .neat-array, +#debug-kit-toolbar .neat-array li { + list-style:none; + list-style-image:none; +} +.neat-array { + padding: 1px 2px 1px 20px; + background: #CE9E23; + list-style: none; + margin: 0 0 1em 0; +} +.neat-array .neat-array { + padding: 0 0 0 20px; + margin:0; + border-top:1px solid #CE9E23; +} +.neat-array li { + background: #FEF6E5; + border-top: 1px solid #CE9E23; + border-bottom: 1px solid #CE9E23; + margin: 0; + line-height: 1.5em; +} +.neat-array li:hover { + background: #fff; +} +.neat-array li strong { + padding: 0 8px; + font-weight: bold; +} + + +/* expandable sections */ +.neat-array li.expandable { + cursor: pointer; +} +.neat-array .expanded { + border-bottom:0; +} +.neat-array li.expandable.expanded > strong:before { + content: 'v '; +} +.neat-array li.expandable.collapsed > strong:before, +.neat-array li.expandable.expanded .expandable.collapsed > strong:before { + content: '> '; +} +.neat-array li { + cursor: default; +} + +#debug-kit-toolbar .debug-kit-graph-bar, +#debug-kit-toolbar .debug-kit-graph-bar-value { + margin: 0; + padding: 0px; + border: none; + overflow: hidden; + height: 10px; +} +#debug-kit-toolbar .debug-kit-graph-bar { + background-color: #ddd; + padding:2px; +} +#debug-kit-toolbar .debug-kit-graph-bar-value { + background-color: #CE9E23; +} + +/* Sql Log */ +#sql_log-tab td, +#sql_log-tab .slow-query-container p { + font-family: Monaco, 'Consolas', "Courier New", Courier, monospaced; +} +#debug-kit-toolbar #sql_log-tab a.show-slow { + display:block; + margin: 3px; + float:none; +} +#sql_log-tab .slow-query-container p { + display:block; + clear:both; + margin: 20px 0 5px; +} +#debug-kit-toolbar #sql_log-tab .panel-content-data a { + background: none; + border:none; +} +#sql_log-tab .slow-query { + background:#e79302; + font-size:9px; + color:#fff; + padding: 2px; + white-space:nowrap; +} +#sql_log-tab input[type=submit] { + border: 0; + background: transparent; + cursor: pointer; + font-size: 12px; + font-family: Monaco, 'Consolas', "Courier New", Courier, monospaced; +} +#sql_log-tab input[type=submit]:hover { + color: darkred; +} + +/* previous panels */ +#debug-kit-toolbar .panel-history { + display: none; + background:#eeffff; +} +#debug-kit-toolbar #history-tab ul { + margin: 20px 0 0 20px; +} +#debug-kit-toolbar #history-tab li { + margin: 0 0 5px 0; +} +#debug-kit-toolbar #history-tab .panel-content-data a { + float: none; + display:block; +} +#debug-kit-toolbar #history-tab a.active { + background: #FEF6E5; +} +#debug-kit-toolbar #history-tab a.loading:after { + content : ' Loading...'; + font-style:italic; +} diff --git a/code/ryzom/tools/server/www/webtt/plugins/debug_kit/webroot/img/cake.icon.png b/code/ryzom/tools/server/www/webtt/plugins/debug_kit/webroot/img/cake.icon.png new file mode 100644 index 000000000..394fa42d5 Binary files /dev/null and b/code/ryzom/tools/server/www/webtt/plugins/debug_kit/webroot/img/cake.icon.png differ diff --git a/code/ryzom/tools/server/www/webtt/plugins/debug_kit/webroot/js/js_debug_toolbar.js b/code/ryzom/tools/server/www/webtt/plugins/debug_kit/webroot/js/js_debug_toolbar.js new file mode 100644 index 000000000..57cc1cc08 --- /dev/null +++ b/code/ryzom/tools/server/www/webtt/plugins/debug_kit/webroot/js/js_debug_toolbar.js @@ -0,0 +1,767 @@ +/** + * Debug Toolbar Javascript. + * + * Creates the DEBUGKIT namespace and provides methods for extending + * and enhancing the Html toolbar. Includes library agnostic Event, Element, + * Cookie and Request wrappers. + * + * + * CakePHP(tm) : Rapid Development Framework (http://cakephp.org) + * Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org) + * + * Licensed under The MIT License + * Redistributions of files must retain the above copyright notice. + * + * @copyright Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org) + * @link http://cakephp.org + * @package debug_kit + * @subpackage debug_kit.views.helpers + * @since DebugKit 0.1 + * @license MIT License (http://www.opensource.org/licenses/mit-license.php) + */ +var DEBUGKIT = function () { + var undef; + return { + module: function (newmodule) { + if (this[newmodule] === undef) { + this[newmodule] = {}; + return this[newmodule]; + } + return this[newmodule]; + } + }; +}() ; + +DEBUGKIT.loader = function () { + return { + //list of methods to run on startup. + _startup: [], + + //register a new method to be run on dom ready. + register: function (method) { + this._startup.push(method); + }, + + init: function () { + for (var i = 0, callback; callback = this._startup[i]; i++) { + callback.init(); + } + } + }; +}(); + +//Util module and Element utility class. +DEBUGKIT.module('Util'); +DEBUGKIT.Util.Element = { + + //test if an element is a name node. + nodeName: function (element, name) { + return element.nodeName && element.nodeName.toLowerCase() == name.toLowerCase(); + }, + + //return a boolean if the element has the classname + hasClass: function (element, className) { + if (!element.className) { + return false; + } + return element.className.indexOf(className) > -1; + }, + + addClass: function (element, className) { + if (!element.className) { + element.className = className; + return; + } + element.className = element.className.replace(/^(.*)$/, '$1 ' + className); + }, + + removeClass: function (element, className) { + if (DEBUGKIT.Util.isArray(element)) { + DEBUGKIT.Util.Collection.apply(element, function (element) { + DEBUGKIT.Util.Element.removeClass(element, className); + }); + } + if (!element.className) { + return false; + } + element.className = element.className.replace(new RegExp(' ?(' + className +') ?'), ''); + }, + + swapClass: function (element, removeClass, addClass) { + if (!element.className) { + return false; + } + element.className = element.className.replace(removeClass, addClass); + }, + + show: function (element) { + element.style.display = 'block'; + }, + + hide: function (element) { + element.style.display = 'none'; + }, + + //go between hide() and show() depending on element.style.display + toggle: function (element) { + if (element.style.display == 'none') { + this.show(element); + return; + } + this.hide(element); + }, + + _walk: function (element, walk) { + var sibling = element[walk]; + while (true) { + if (sibling.nodeType == 1) { + break; + } + sibling = sibling[walk]; + } + return sibling; + }, + + getNext: function (element) { + return this._walk(element, 'nextSibling'); + }, + + getPrevious: function (element) { + return this._walk(element, 'previousSibling'); + }, + + //get or set an element's height, omit value to get, add value (integer) to set. + height: function (element, value) { + //get value + if (value === undefined) { + return parseInt(this.getStyle(element, 'height')); + } + element.style.height = value + 'px'; + }, + + //gets the style in css format for property + getStyle: function (element, property) { + if (element.currentStyle) { + property = property.replace(/-[a-z]/g, function (match) { + return match.charAt(1).toUpperCase(); + }); + return element.currentStyle[property]; + } + if (window.getComputedStyle) { + return document.defaultView.getComputedStyle(element, null).getPropertyValue(property); + } + } +}; + +DEBUGKIT.Util.Collection = { + /* + Apply the passed function to each item in the collection. + The current element in the collection will be `this` in the callback + The callback is also passed the element and the index as arguments. + Optionally you can supply a binding parameter to change `this` in the callback. + */ + apply: function (collection, callback, binding) { + var name, thisVar, i = 0, len = collection.length; + + if (len === undefined) { + for (name in collection) { + thisVar = (binding === undefined) ? collection[name] : binding; + callback.apply(thisVar, [collection[name], name]); + } + } else { + for (; i < len; i++) { + thisVar = (binding === undefined) ? collection[i] : binding; + callback.apply(thisVar, [collection[i], i]); + } + } + } +} + + +//Event binding +DEBUGKIT.Util.Event = function () { + var _listeners = {}, + _eventId = 0; + + var preventDefault = function () { + this.returnValue = false; + } + + var stopPropagation = function () { + this.cancelBubble = true; + } + + // Fixes IE's broken event object, adds in common methods + properties. + var fixEvent = function (event) { + if (!event.preventDefault) { + event.preventDefault = preventDefault; + } + if (!event.stopPropagation) { + event.stopPropagation = stopPropagation; + } + if (!event.target) { + event.target = event.srcElement || document; + } + if (event.pageX == null && event.clientX != null) { + var doc = document.body; + event.pageX = event.clientX + (doc.scrollLeft || 0) - (doc.clientLeft || 0); + event.pageY = event.clientY + (doc.scrollTop || 0) - (doc.clientTop || 0); + } + return event; + } + + return { + // bind an event listener of type to element, handler is your method. + addEvent: function(element, type, handler, capture) { + capture = (capture === undefined) ? false : capture; + + var callback = function (event) { + event = fixEvent(event || window.event); + handler.apply(element, [event]); + }; + + if (element.addEventListener) { + element.addEventListener(type, callback, capture); + } else if (element.attachEvent) { + type = 'on' + type; + element.attachEvent(type, callback); + } else { + type = 'on' + type; + element[type] = callback; + } + _listeners[++_eventId] = {element: element, type: type, handler: callback}; + }, + + // destroy an event listener. requires the exact same function as was used for attaching + // the event. + removeEvent: function (element, type, handler) { + if (element.removeEventListener) { + element.removeEventListener(type, handler, false); + } else if (element.detachEvent) { + type = 'on' + type; + element.detachEvent(type, handler); + } else { + type = 'on' + type; + element[type] = null; + } + }, + + // bind an event to the DOMContentLoaded or other similar event. + domready: function(callback) { + if (document.addEventListener) { + return document.addEventListener("DOMContentLoaded", callback, false); + } + + if (document.all && !window.opera) { + //Define a "blank" external JavaScript tag + document.write('', 'js'); + $this->mapHandler('comment', 'ignore'); + $this->addEntryPattern('', 'comment'); + } + + /** + * Pattern matches to start and end a tag. + * @param string $tag Name of tag to scan for. + * @access private + */ + protected function addTag($tag) { + $this->addSpecialPattern("", 'text', 'acceptEndToken'); + $this->addEntryPattern("<$tag", 'text', 'tag'); + } + + /** + * Pattern matches to parse the inside of a tag + * including the attributes and their quoting. + * @access private + */ + protected function addInTagTokens() { + $this->mapHandler('tag', 'acceptStartToken'); + $this->addSpecialPattern('\s+', 'tag', 'ignore'); + $this->addAttributeTokens(); + $this->addExitPattern('/>', 'tag'); + $this->addExitPattern('>', 'tag'); + } + + /** + * Matches attributes that are either single quoted, + * double quoted or unquoted. + * @access private + */ + protected function addAttributeTokens() { + $this->mapHandler('dq_attribute', 'acceptAttributeToken'); + $this->addEntryPattern('=\s*"', 'tag', 'dq_attribute'); + $this->addPattern("\\\\\"", 'dq_attribute'); + $this->addExitPattern('"', 'dq_attribute'); + $this->mapHandler('sq_attribute', 'acceptAttributeToken'); + $this->addEntryPattern("=\s*'", 'tag', 'sq_attribute'); + $this->addPattern("\\\\'", 'sq_attribute'); + $this->addExitPattern("'", 'sq_attribute'); + $this->mapHandler('uq_attribute', 'acceptAttributeToken'); + $this->addSpecialPattern('=\s*[^>\s]*', 'tag', 'uq_attribute'); + } +} + +/** + * Converts HTML tokens into selected SAX events. + * @package SimpleTest + * @subpackage WebTester + */ +class SimpleHtmlSaxParser { + private $lexer; + private $listener; + private $tag; + private $attributes; + private $current_attribute; + + /** + * Sets the listener. + * @param SimplePhpPageBuilder $listener SAX event handler. + * @access public + */ + function __construct($listener) { + $this->listener = $listener; + $this->lexer = $this->createLexer($this); + $this->tag = ''; + $this->attributes = array(); + $this->current_attribute = ''; + } + + /** + * Runs the content through the lexer which + * should call back to the acceptors. + * @param string $raw Page text to parse. + * @return boolean False if parse error. + * @access public + */ + function parse($raw) { + return $this->lexer->parse($raw); + } + + /** + * Sets up the matching lexer. Starts in 'text' mode. + * @param SimpleSaxParser $parser Event generator, usually $self. + * @return SimpleLexer Lexer suitable for this parser. + * @access public + */ + static function createLexer(&$parser) { + return new SimpleHtmlLexer($parser); + } + + /** + * Accepts a token from the tag mode. If the + * starting element completes then the element + * is dispatched and the current attributes + * set back to empty. The element or attribute + * name is converted to lower case. + * @param string $token Incoming characters. + * @param integer $event Lexer event type. + * @return boolean False if parse error. + * @access public + */ + function acceptStartToken($token, $event) { + if ($event == LEXER_ENTER) { + $this->tag = strtolower(substr($token, 1)); + return true; + } + if ($event == LEXER_EXIT) { + $success = $this->listener->startElement( + $this->tag, + $this->attributes); + $this->tag = ''; + $this->attributes = array(); + return $success; + } + if ($token != '=') { + $this->current_attribute = strtolower(html_entity_decode($token, ENT_QUOTES)); + $this->attributes[$this->current_attribute] = ''; + } + return true; + } + + /** + * Accepts a token from the end tag mode. + * The element name is converted to lower case. + * @param string $token Incoming characters. + * @param integer $event Lexer event type. + * @return boolean False if parse error. + * @access public + */ + function acceptEndToken($token, $event) { + if (! preg_match('/<\/(.*)>/', $token, $matches)) { + return false; + } + return $this->listener->endElement(strtolower($matches[1])); + } + + /** + * Part of the tag data. + * @param string $token Incoming characters. + * @param integer $event Lexer event type. + * @return boolean False if parse error. + * @access public + */ + function acceptAttributeToken($token, $event) { + if ($this->current_attribute) { + if ($event == LEXER_UNMATCHED) { + $this->attributes[$this->current_attribute] .= + html_entity_decode($token, ENT_QUOTES); + } + if ($event == LEXER_SPECIAL) { + $this->attributes[$this->current_attribute] .= + preg_replace('/^=\s*/' , '', html_entity_decode($token, ENT_QUOTES)); + } + } + return true; + } + + /** + * A character entity. + * @param string $token Incoming characters. + * @param integer $event Lexer event type. + * @return boolean False if parse error. + * @access public + */ + function acceptEntityToken($token, $event) { + } + + /** + * Character data between tags regarded as + * important. + * @param string $token Incoming characters. + * @param integer $event Lexer event type. + * @return boolean False if parse error. + * @access public + */ + function acceptTextToken($token, $event) { + return $this->listener->addContent($token); + } + + /** + * Incoming data to be ignored. + * @param string $token Incoming characters. + * @param integer $event Lexer event type. + * @return boolean False if parse error. + * @access public + */ + function ignore($token, $event) { + return true; + } +} + +/** + * SAX event handler. Maintains a list of + * open tags and dispatches them as they close. + * @package SimpleTest + * @subpackage WebTester + */ +class SimplePhpPageBuilder { + private $tags; + private $page; + private $private_content_tag; + private $open_forms = array(); + private $complete_forms = array(); + private $frameset = false; + private $loading_frames = array(); + private $frameset_nesting_level = 0; + private $left_over_labels = array(); + + /** + * Frees up any references so as to allow the PHP garbage + * collection from unset() to work. + * @access public + */ + function free() { + unset($this->tags); + unset($this->page); + unset($this->private_content_tags); + $this->open_forms = array(); + $this->complete_forms = array(); + $this->frameset = false; + $this->loading_frames = array(); + $this->frameset_nesting_level = 0; + $this->left_over_labels = array(); + } + + /** + * This builder is always available. + * @return boolean Always true. + */ + function can() { + return true; + } + + /** + * Reads the raw content and send events + * into the page to be built. + * @param $response SimpleHttpResponse Fetched response. + * @return SimplePage Newly parsed page. + * @access public + */ + function parse($response) { + $this->tags = array(); + $this->page = $this->createPage($response); + $parser = $this->createParser($this); + $parser->parse($response->getContent()); + $this->acceptPageEnd(); + $page = $this->page; + $this->free(); + return $page; + } + + /** + * Creates an empty page. + * @return SimplePage New unparsed page. + * @access protected + */ + protected function createPage($response) { + return new SimplePage($response); + } + + /** + * Creates the parser used with the builder. + * @param SimplePhpPageBuilder $listener Target of parser. + * @return SimpleSaxParser Parser to generate + * events for the builder. + * @access protected + */ + protected function createParser(&$listener) { + return new SimpleHtmlSaxParser($listener); + } + + /** + * Start of element event. Opens a new tag. + * @param string $name Element name. + * @param hash $attributes Attributes without content + * are marked as true. + * @return boolean False on parse error. + * @access public + */ + function startElement($name, $attributes) { + $factory = new SimpleTagBuilder(); + $tag = $factory->createTag($name, $attributes); + if (! $tag) { + return true; + } + if ($tag->getTagName() == 'label') { + $this->acceptLabelStart($tag); + $this->openTag($tag); + return true; + } + if ($tag->getTagName() == 'form') { + $this->acceptFormStart($tag); + return true; + } + if ($tag->getTagName() == 'frameset') { + $this->acceptFramesetStart($tag); + return true; + } + if ($tag->getTagName() == 'frame') { + $this->acceptFrame($tag); + return true; + } + if ($tag->isPrivateContent() && ! isset($this->private_content_tag)) { + $this->private_content_tag = &$tag; + } + if ($tag->expectEndTag()) { + $this->openTag($tag); + return true; + } + $this->acceptTag($tag); + return true; + } + + /** + * End of element event. + * @param string $name Element name. + * @return boolean False on parse error. + * @access public + */ + function endElement($name) { + if ($name == 'label') { + $this->acceptLabelEnd(); + return true; + } + if ($name == 'form') { + $this->acceptFormEnd(); + return true; + } + if ($name == 'frameset') { + $this->acceptFramesetEnd(); + return true; + } + if ($this->hasNamedTagOnOpenTagStack($name)) { + $tag = array_pop($this->tags[$name]); + if ($tag->isPrivateContent() && $this->private_content_tag->getTagName() == $name) { + unset($this->private_content_tag); + } + $this->addContentTagToOpenTags($tag); + $this->acceptTag($tag); + return true; + } + return true; + } + + /** + * Test to see if there are any open tags awaiting + * closure that match the tag name. + * @param string $name Element name. + * @return boolean True if any are still open. + * @access private + */ + protected function hasNamedTagOnOpenTagStack($name) { + return isset($this->tags[$name]) && (count($this->tags[$name]) > 0); + } + + /** + * Unparsed, but relevant data. The data is added + * to every open tag. + * @param string $text May include unparsed tags. + * @return boolean False on parse error. + * @access public + */ + function addContent($text) { + if (isset($this->private_content_tag)) { + $this->private_content_tag->addContent($text); + } else { + $this->addContentToAllOpenTags($text); + } + return true; + } + + /** + * Any content fills all currently open tags unless it + * is part of an option tag. + * @param string $text May include unparsed tags. + * @access private + */ + protected function addContentToAllOpenTags($text) { + foreach (array_keys($this->tags) as $name) { + for ($i = 0, $count = count($this->tags[$name]); $i < $count; $i++) { + $this->tags[$name][$i]->addContent($text); + } + } + } + + /** + * Parsed data in tag form. The parsed tag is added + * to every open tag. Used for adding options to select + * fields only. + * @param SimpleTag $tag Option tags only. + * @access private + */ + protected function addContentTagToOpenTags(&$tag) { + if ($tag->getTagName() != 'option') { + return; + } + foreach (array_keys($this->tags) as $name) { + for ($i = 0, $count = count($this->tags[$name]); $i < $count; $i++) { + $this->tags[$name][$i]->addTag($tag); + } + } + } + + /** + * Opens a tag for receiving content. Multiple tags + * will be receiving input at the same time. + * @param SimpleTag $tag New content tag. + * @access private + */ + protected function openTag($tag) { + $name = $tag->getTagName(); + if (! in_array($name, array_keys($this->tags))) { + $this->tags[$name] = array(); + } + $this->tags[$name][] = $tag; + } + + /** + * Adds a tag to the page. + * @param SimpleTag $tag Tag to accept. + * @access public + */ + protected function acceptTag($tag) { + if ($tag->getTagName() == "a") { + $this->page->addLink($tag); + } elseif ($tag->getTagName() == "base") { + $this->page->setBase($tag->getAttribute('href')); + } elseif ($tag->getTagName() == "title") { + $this->page->setTitle($tag); + } elseif ($this->isFormElement($tag->getTagName())) { + for ($i = 0; $i < count($this->open_forms); $i++) { + $this->open_forms[$i]->addWidget($tag); + } + $this->last_widget = $tag; + } + } + + /** + * Opens a label for a described widget. + * @param SimpleFormTag $tag Tag to accept. + * @access public + */ + protected function acceptLabelStart($tag) { + $this->label = $tag; + unset($this->last_widget); + } + + /** + * Closes the most recently opened label. + * @access public + */ + protected function acceptLabelEnd() { + if (isset($this->label)) { + if (isset($this->last_widget)) { + $this->last_widget->setLabel($this->label->getText()); + unset($this->last_widget); + } else { + $this->left_over_labels[] = SimpleTestCompatibility::copy($this->label); + } + unset($this->label); + } + } + + /** + * Tests to see if a tag is a possible form + * element. + * @param string $name HTML element name. + * @return boolean True if form element. + * @access private + */ + protected function isFormElement($name) { + return in_array($name, array('input', 'button', 'textarea', 'select')); + } + + /** + * Opens a form. New widgets go here. + * @param SimpleFormTag $tag Tag to accept. + * @access public + */ + protected function acceptFormStart($tag) { + $this->open_forms[] = new SimpleForm($tag, $this->page); + } + + /** + * Closes the most recently opened form. + * @access public + */ + protected function acceptFormEnd() { + if (count($this->open_forms)) { + $this->complete_forms[] = array_pop($this->open_forms); + } + } + + /** + * Opens a frameset. A frameset may contain nested + * frameset tags. + * @param SimpleFramesetTag $tag Tag to accept. + * @access public + */ + protected function acceptFramesetStart($tag) { + if (! $this->isLoadingFrames()) { + $this->frameset = $tag; + } + $this->frameset_nesting_level++; + } + + /** + * Closes the most recently opened frameset. + * @access public + */ + protected function acceptFramesetEnd() { + if ($this->isLoadingFrames()) { + $this->frameset_nesting_level--; + } + } + + /** + * Takes a single frame tag and stashes it in + * the current frame set. + * @param SimpleFrameTag $tag Tag to accept. + * @access public + */ + protected function acceptFrame($tag) { + if ($this->isLoadingFrames()) { + if ($tag->getAttribute('src')) { + $this->loading_frames[] = $tag; + } + } + } + + /** + * Test to see if in the middle of reading + * a frameset. + * @return boolean True if inframeset. + * @access private + */ + protected function isLoadingFrames() { + return $this->frameset and $this->frameset_nesting_level > 0; + } + + /** + * Marker for end of complete page. Any work in + * progress can now be closed. + * @access public + */ + protected function acceptPageEnd() { + while (count($this->open_forms)) { + $this->complete_forms[] = array_pop($this->open_forms); + } + foreach ($this->left_over_labels as $label) { + for ($i = 0, $count = count($this->complete_forms); $i < $count; $i++) { + $this->complete_forms[$i]->attachLabelBySelector( + new SimpleById($label->getFor()), + $label->getText()); + } + } + $this->page->setForms($this->complete_forms); + $this->page->setFrames($this->loading_frames); + } +} +?> \ No newline at end of file diff --git a/code/ryzom/tools/server/www/webtt/vendors/simpletest/reflection_php4.php b/code/ryzom/tools/server/www/webtt/vendors/simpletest/reflection_php4.php new file mode 100644 index 000000000..39801ea1b --- /dev/null +++ b/code/ryzom/tools/server/www/webtt/vendors/simpletest/reflection_php4.php @@ -0,0 +1,136 @@ +_interface = $interface; + } + + /** + * Checks that a class has been declared. + * @return boolean True if defined. + * @access public + */ + function classExists() { + return class_exists($this->_interface); + } + + /** + * Needed to kill the autoload feature in PHP5 + * for classes created dynamically. + * @return boolean True if defined. + * @access public + */ + function classExistsSansAutoload() { + return class_exists($this->_interface); + } + + /** + * Checks that a class or interface has been + * declared. + * @return boolean True if defined. + * @access public + */ + function classOrInterfaceExists() { + return class_exists($this->_interface); + } + + /** + * Needed to kill the autoload feature in PHP5 + * for classes created dynamically. + * @return boolean True if defined. + * @access public + */ + function classOrInterfaceExistsSansAutoload() { + return class_exists($this->_interface); + } + + /** + * Gets the list of methods on a class or + * interface. + * @returns array List of method names. + * @access public + */ + function getMethods() { + return get_class_methods($this->_interface); + } + + /** + * Gets the list of interfaces from a class. If the + * class name is actually an interface then just that + * interface is returned. + * @returns array List of interfaces. + * @access public + */ + function getInterfaces() { + return array(); + } + + /** + * Finds the parent class name. + * @returns string Parent class name. + * @access public + */ + function getParent() { + return strtolower(get_parent_class($this->_interface)); + } + + /** + * Determines if the class is abstract, which for PHP 4 + * will never be the case. + * @returns boolean True if abstract. + * @access public + */ + function isAbstract() { + return false; + } + + /** + * Determines if the the entity is an interface, which for PHP 4 + * will never be the case. + * @returns boolean True if interface. + * @access public + */ + function isInterface() { + return false; + } + + /** + * Scans for final methods, but as it's PHP 4 there + * aren't any. + * @returns boolean True if the class has a final method. + * @access public + */ + function hasFinal() { + return false; + } + + /** + * Gets the source code matching the declaration + * of a method. + * @param string $method Method name. + * @access public + */ + function getSignature($method) { + return "function &$method()"; + } +} +?> \ No newline at end of file diff --git a/code/ryzom/tools/server/www/webtt/vendors/simpletest/reflection_php5.php b/code/ryzom/tools/server/www/webtt/vendors/simpletest/reflection_php5.php new file mode 100644 index 000000000..43d8a7b28 --- /dev/null +++ b/code/ryzom/tools/server/www/webtt/vendors/simpletest/reflection_php5.php @@ -0,0 +1,386 @@ +interface = $interface; + } + + /** + * Checks that a class has been declared. Versions + * before PHP5.0.2 need a check that it's not really + * an interface. + * @return boolean True if defined. + * @access public + */ + function classExists() { + if (! class_exists($this->interface)) { + return false; + } + $reflection = new ReflectionClass($this->interface); + return ! $reflection->isInterface(); + } + + /** + * Needed to kill the autoload feature in PHP5 + * for classes created dynamically. + * @return boolean True if defined. + * @access public + */ + function classExistsSansAutoload() { + return class_exists($this->interface, false); + } + + /** + * Checks that a class or interface has been + * declared. + * @return boolean True if defined. + * @access public + */ + function classOrInterfaceExists() { + return $this->classOrInterfaceExistsWithAutoload($this->interface, true); + } + + /** + * Needed to kill the autoload feature in PHP5 + * for classes created dynamically. + * @return boolean True if defined. + * @access public + */ + function classOrInterfaceExistsSansAutoload() { + return $this->classOrInterfaceExistsWithAutoload($this->interface, false); + } + + /** + * Needed to select the autoload feature in PHP5 + * for classes created dynamically. + * @param string $interface Class or interface name. + * @param boolean $autoload True totriggerautoload. + * @return boolean True if interface defined. + * @access private + */ + protected function classOrInterfaceExistsWithAutoload($interface, $autoload) { + if (function_exists('interface_exists')) { + if (interface_exists($this->interface, $autoload)) { + return true; + } + } + return class_exists($this->interface, $autoload); + } + + /** + * Gets the list of methods on a class or + * interface. + * @returns array List of method names. + * @access public + */ + function getMethods() { + return array_unique(get_class_methods($this->interface)); + } + + /** + * Gets the list of interfaces from a class. If the + * class name is actually an interface then just that + * interface is returned. + * @returns array List of interfaces. + * @access public + */ + function getInterfaces() { + $reflection = new ReflectionClass($this->interface); + if ($reflection->isInterface()) { + return array($this->interface); + } + return $this->onlyParents($reflection->getInterfaces()); + } + + /** + * Gets the list of methods for the implemented + * interfaces only. + * @returns array List of enforced method signatures. + * @access public + */ + function getInterfaceMethods() { + $methods = array(); + foreach ($this->getInterfaces() as $interface) { + $methods = array_merge($methods, get_class_methods($interface)); + } + return array_unique($methods); + } + + /** + * Checks to see if the method signature has to be tightly + * specified. + * @param string $method Method name. + * @returns boolean True if enforced. + * @access private + */ + protected function isInterfaceMethod($method) { + return in_array($method, $this->getInterfaceMethods()); + } + + /** + * Finds the parent class name. + * @returns string Parent class name. + * @access public + */ + function getParent() { + $reflection = new ReflectionClass($this->interface); + $parent = $reflection->getParentClass(); + if ($parent) { + return $parent->getName(); + } + return false; + } + + /** + * Trivially determines if the class is abstract. + * @returns boolean True if abstract. + * @access public + */ + function isAbstract() { + $reflection = new ReflectionClass($this->interface); + return $reflection->isAbstract(); + } + + /** + * Trivially determines if the class is an interface. + * @returns boolean True if interface. + * @access public + */ + function isInterface() { + $reflection = new ReflectionClass($this->interface); + return $reflection->isInterface(); + } + + /** + * Scans for final methods, as they screw up inherited + * mocks by not allowing you to override them. + * @returns boolean True if the class has a final method. + * @access public + */ + function hasFinal() { + $reflection = new ReflectionClass($this->interface); + foreach ($reflection->getMethods() as $method) { + if ($method->isFinal()) { + return true; + } + } + return false; + } + + /** + * Whittles a list of interfaces down to only the + * necessary top level parents. + * @param array $interfaces Reflection API interfaces + * to reduce. + * @returns array List of parent interface names. + * @access private + */ + protected function onlyParents($interfaces) { + $parents = array(); + $blacklist = array(); + foreach ($interfaces as $interface) { + foreach($interfaces as $possible_parent) { + if ($interface->getName() == $possible_parent->getName()) { + continue; + } + if ($interface->isSubClassOf($possible_parent)) { + $blacklist[$possible_parent->getName()] = true; + } + } + if (!isset($blacklist[$interface->getName()])) { + $parents[] = $interface->getName(); + } + } + return $parents; + } + + /** + * Checks whether a method is abstract or not. + * @param string $name Method name. + * @return bool true if method is abstract, else false + * @access private + */ + protected function isAbstractMethod($name) { + $interface = new ReflectionClass($this->interface); + if (! $interface->hasMethod($name)) { + return false; + } + return $interface->getMethod($name)->isAbstract(); + } + + /** + * Checks whether a method is the constructor. + * @param string $name Method name. + * @return bool true if method is the constructor + * @access private + */ + protected function isConstructor($name) { + return ($name == '__construct') || ($name == $this->interface); + } + + /** + * Checks whether a method is abstract in all parents or not. + * @param string $name Method name. + * @return bool true if method is abstract in parent, else false + * @access private + */ + protected function isAbstractMethodInParents($name) { + $interface = new ReflectionClass($this->interface); + $parent = $interface->getParentClass(); + while($parent) { + if (! $parent->hasMethod($name)) { + return false; + } + if ($parent->getMethod($name)->isAbstract()) { + return true; + } + $parent = $parent->getParentClass(); + } + return false; + } + + /** + * Checks whether a method is static or not. + * @param string $name Method name + * @return bool true if method is static, else false + * @access private + */ + protected function isStaticMethod($name) { + $interface = new ReflectionClass($this->interface); + if (! $interface->hasMethod($name)) { + return false; + } + return $interface->getMethod($name)->isStatic(); + } + + /** + * Writes the source code matching the declaration + * of a method. + * @param string $name Method name. + * @return string Method signature up to last + * bracket. + * @access public + */ + function getSignature($name) { + if ($name == '__set') { + return 'function __set($key, $value)'; + } + if ($name == '__call') { + return 'function __call($method, $arguments)'; + } + if (version_compare(phpversion(), '5.1.0', '>=')) { + if (in_array($name, array('__get', '__isset', $name == '__unset'))) { + return "function {$name}(\$key)"; + } + } + if ($name == '__toString') { + return "function $name()"; + } + + // This wonky try-catch is a work around for a faulty method_exists() + // in early versions of PHP 5 which would return false for static + // methods. The Reflection classes work fine, but hasMethod() + // doesn't exist prior to PHP 5.1.0, so we need to use a more crude + // detection method. + try { + $interface = new ReflectionClass($this->interface); + $interface->getMethod($name); + } catch (ReflectionException $e) { + return "function $name()"; + } + return $this->getFullSignature($name); + } + + /** + * For a signature specified in an interface, full + * details must be replicated to be a valid implementation. + * @param string $name Method name. + * @return string Method signature up to last + * bracket. + * @access private + */ + protected function getFullSignature($name) { + $interface = new ReflectionClass($this->interface); + $method = $interface->getMethod($name); + $reference = $method->returnsReference() ? '&' : ''; + $static = $method->isStatic() ? 'static ' : ''; + return "{$static}function $reference$name(" . + implode(', ', $this->getParameterSignatures($method)) . + ")"; + } + + /** + * Gets the source code for each parameter. + * @param ReflectionMethod $method Method object from + * reflection API + * @return array List of strings, each + * a snippet of code. + * @access private + */ + protected function getParameterSignatures($method) { + $signatures = array(); + foreach ($method->getParameters() as $parameter) { + $signature = ''; + $type = $parameter->getClass(); + if (is_null($type) && version_compare(phpversion(), '5.1.0', '>=') && $parameter->isArray()) { + $signature .= 'array '; + } elseif (!is_null($type)) { + $signature .= $type->getName() . ' '; + } + if ($parameter->isPassedByReference()) { + $signature .= '&'; + } + $signature .= '$' . $this->suppressSpurious($parameter->getName()); + if ($this->isOptional($parameter)) { + $signature .= ' = null'; + } + $signatures[] = $signature; + } + return $signatures; + } + + /** + * The SPL library has problems with the + * Reflection library. In particular, you can + * get extra characters in parameter names :(. + * @param string $name Parameter name. + * @return string Cleaner name. + * @access private + */ + protected function suppressSpurious($name) { + return str_replace(array('[', ']', ' '), '', $name); + } + + /** + * Test of a reflection parameter being optional + * that works with early versions of PHP5. + * @param reflectionParameter $parameter Is this optional. + * @return boolean True if optional. + * @access private + */ + protected function isOptional($parameter) { + if (method_exists($parameter, 'isOptional')) { + return $parameter->isOptional(); + } + return false; + } +} +?> \ No newline at end of file diff --git a/code/ryzom/tools/server/www/webtt/vendors/simpletest/remote.php b/code/ryzom/tools/server/www/webtt/vendors/simpletest/remote.php new file mode 100644 index 000000000..4bb37b7c5 --- /dev/null +++ b/code/ryzom/tools/server/www/webtt/vendors/simpletest/remote.php @@ -0,0 +1,115 @@ +url = $url; + $this->dry_url = $dry_url ? $dry_url : $url; + $this->size = false; + } + + /** + * Accessor for the test name for subclasses. + * @return string Name of the test. + * @access public + */ + function getLabel() { + return $this->url; + } + + /** + * Runs the top level test for this class. Currently + * reads the data as a single chunk. I'll fix this + * once I have added iteration to the browser. + * @param SimpleReporter $reporter Target of test results. + * @returns boolean True if no failures. + * @access public + */ + function run($reporter) { + $browser = $this->createBrowser(); + $xml = $browser->get($this->url); + if (! $xml) { + trigger_error('Cannot read remote test URL [' . $this->url . ']'); + return false; + } + $parser = $this->createParser($reporter); + if (! $parser->parse($xml)) { + trigger_error('Cannot parse incoming XML from [' . $this->url . ']'); + return false; + } + return true; + } + + /** + * Creates a new web browser object for fetching + * the XML report. + * @return SimpleBrowser New browser. + * @access protected + */ + protected function createBrowser() { + return new SimpleBrowser(); + } + + /** + * Creates the XML parser. + * @param SimpleReporter $reporter Target of test results. + * @return SimpleTestXmlListener XML reader. + * @access protected + */ + protected function createParser($reporter) { + return new SimpleTestXmlParser($reporter); + } + + /** + * Accessor for the number of subtests. + * @return integer Number of test cases. + * @access public + */ + function getSize() { + if ($this->size === false) { + $browser = $this->createBrowser(); + $xml = $browser->get($this->dry_url); + if (! $xml) { + trigger_error('Cannot read remote test URL [' . $this->dry_url . ']'); + return false; + } + $reporter = new SimpleReporter(); + $parser = $this->createParser($reporter); + if (! $parser->parse($xml)) { + trigger_error('Cannot parse incoming XML from [' . $this->dry_url . ']'); + return false; + } + $this->size = $reporter->getTestCaseCount(); + } + return $this->size; + } +} +?> \ No newline at end of file diff --git a/code/ryzom/tools/server/www/webtt/vendors/simpletest/reporter.php b/code/ryzom/tools/server/www/webtt/vendors/simpletest/reporter.php new file mode 100644 index 000000000..bf8d2ac11 --- /dev/null +++ b/code/ryzom/tools/server/www/webtt/vendors/simpletest/reporter.php @@ -0,0 +1,445 @@ +character_set = $character_set; + } + + /** + * Paints the top of the web page setting the + * title to the name of the starting test. + * @param string $test_name Name class of test. + * @access public + */ + function paintHeader($test_name) { + $this->sendNoCacheHeaders(); + print ""; + print "\n\n$test_name\n"; + print "\n"; + print "\n"; + print "\n\n"; + print "

    $test_name

    \n"; + flush(); + } + + /** + * Send the headers necessary to ensure the page is + * reloaded on every request. Otherwise you could be + * scratching your head over out of date test data. + * @access public + */ + static function sendNoCacheHeaders() { + if (! headers_sent()) { + header("Expires: Mon, 26 Jul 1997 05:00:00 GMT"); + header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT"); + header("Cache-Control: no-store, no-cache, must-revalidate"); + header("Cache-Control: post-check=0, pre-check=0", false); + header("Pragma: no-cache"); + } + } + + /** + * Paints the CSS. Add additional styles here. + * @return string CSS code as text. + * @access protected + */ + protected function getCss() { + return ".fail { background-color: inherit; color: red; }" . + ".pass { background-color: inherit; color: green; }" . + " pre { background-color: lightgray; color: inherit; }"; + } + + /** + * Paints the end of the test with a summary of + * the passes and failures. + * @param string $test_name Name class of test. + * @access public + */ + function paintFooter($test_name) { + $colour = ($this->getFailCount() + $this->getExceptionCount() > 0 ? "red" : "green"); + print "
    "; + print $this->getTestCaseProgress() . "/" . $this->getTestCaseCount(); + print " test cases complete:\n"; + print "" . $this->getPassCount() . " passes, "; + print "" . $this->getFailCount() . " fails and "; + print "" . $this->getExceptionCount() . " exceptions."; + print "
    \n"; + print "\n\n"; + } + + /** + * Paints the test failure with a breadcrumbs + * trail of the nesting test suites below the + * top level test. + * @param string $message Failure message displayed in + * the context of the other tests. + */ + function paintFail($message) { + parent::paintFail($message); + print "Fail: "; + $breadcrumb = $this->getTestList(); + array_shift($breadcrumb); + print implode(" -> ", $breadcrumb); + print " -> " . $this->htmlEntities($message) . "
    \n"; + } + + /** + * Paints a PHP error. + * @param string $message Message is ignored. + * @access public + */ + function paintError($message) { + parent::paintError($message); + print "Exception: "; + $breadcrumb = $this->getTestList(); + array_shift($breadcrumb); + print implode(" -> ", $breadcrumb); + print " -> " . $this->htmlEntities($message) . "
    \n"; + } + + /** + * Paints a PHP exception. + * @param Exception $exception Exception to display. + * @access public + */ + function paintException($exception) { + parent::paintException($exception); + print "Exception: "; + $breadcrumb = $this->getTestList(); + array_shift($breadcrumb); + print implode(" -> ", $breadcrumb); + $message = 'Unexpected exception of type [' . get_class($exception) . + '] with message ['. $exception->getMessage() . + '] in ['. $exception->getFile() . + ' line ' . $exception->getLine() . ']'; + print " -> " . $this->htmlEntities($message) . "
    \n"; + } + + /** + * Prints the message for skipping tests. + * @param string $message Text of skip condition. + * @access public + */ + function paintSkip($message) { + parent::paintSkip($message); + print "Skipped: "; + $breadcrumb = $this->getTestList(); + array_shift($breadcrumb); + print implode(" -> ", $breadcrumb); + print " -> " . $this->htmlEntities($message) . "
    \n"; + } + + /** + * Paints formatted text such as dumped privateiables. + * @param string $message Text to show. + * @access public + */ + function paintFormattedMessage($message) { + print '
    ' . $this->htmlEntities($message) . '
    '; + } + + /** + * Character set adjusted entity conversion. + * @param string $message Plain text or Unicode message. + * @return string Browser readable message. + * @access protected + */ + protected function htmlEntities($message) { + return htmlentities($message, ENT_COMPAT, $this->character_set); + } +} + +/** + * Sample minimal test displayer. Generates only + * failure messages and a pass count. For command + * line use. I've tried to make it look like JUnit, + * but I wanted to output the errors as they arrived + * which meant dropping the dots. + * @package SimpleTest + * @subpackage UnitTester + */ +class TextReporter extends SimpleReporter { + + /** + * Does nothing yet. The first output will + * be sent on the first test start. + */ + function __construct() { + parent::__construct(); + } + + /** + * Paints the title only. + * @param string $test_name Name class of test. + * @access public + */ + function paintHeader($test_name) { + if (! SimpleReporter::inCli()) { + header('Content-type: text/plain'); + } + print "$test_name\n"; + flush(); + } + + /** + * Paints the end of the test with a summary of + * the passes and failures. + * @param string $test_name Name class of test. + * @access public + */ + function paintFooter($test_name) { + if ($this->getFailCount() + $this->getExceptionCount() == 0) { + print "OK\n"; + } else { + print "FAILURES!!!\n"; + } + print "Test cases run: " . $this->getTestCaseProgress() . + "/" . $this->getTestCaseCount() . + ", Passes: " . $this->getPassCount() . + ", Failures: " . $this->getFailCount() . + ", Exceptions: " . $this->getExceptionCount() . "\n"; + } + + /** + * Paints the test failure as a stack trace. + * @param string $message Failure message displayed in + * the context of the other tests. + * @access public + */ + function paintFail($message) { + parent::paintFail($message); + print $this->getFailCount() . ") $message\n"; + $breadcrumb = $this->getTestList(); + array_shift($breadcrumb); + print "\tin " . implode("\n\tin ", array_reverse($breadcrumb)); + print "\n"; + } + + /** + * Paints a PHP error or exception. + * @param string $message Message to be shown. + * @access public + * @abstract + */ + function paintError($message) { + parent::paintError($message); + print "Exception " . $this->getExceptionCount() . "!\n$message\n"; + $breadcrumb = $this->getTestList(); + array_shift($breadcrumb); + print "\tin " . implode("\n\tin ", array_reverse($breadcrumb)); + print "\n"; + } + + /** + * Paints a PHP error or exception. + * @param Exception $exception Exception to describe. + * @access public + * @abstract + */ + function paintException($exception) { + parent::paintException($exception); + $message = 'Unexpected exception of type [' . get_class($exception) . + '] with message ['. $exception->getMessage() . + '] in ['. $exception->getFile() . + ' line ' . $exception->getLine() . ']'; + print "Exception " . $this->getExceptionCount() . "!\n$message\n"; + $breadcrumb = $this->getTestList(); + array_shift($breadcrumb); + print "\tin " . implode("\n\tin ", array_reverse($breadcrumb)); + print "\n"; + } + + /** + * Prints the message for skipping tests. + * @param string $message Text of skip condition. + * @access public + */ + function paintSkip($message) { + parent::paintSkip($message); + print "Skip: $message\n"; + } + + /** + * Paints formatted text such as dumped privateiables. + * @param string $message Text to show. + * @access public + */ + function paintFormattedMessage($message) { + print "$message\n"; + flush(); + } +} + +/** + * Runs just a single test group, a single case or + * even a single test within that case. + * @package SimpleTest + * @subpackage UnitTester + */ +class SelectiveReporter extends SimpleReporterDecorator { + private $just_this_case = false; + private $just_this_test = false; + private $on; + + /** + * Selects the test case or group to be run, + * and optionally a specific test. + * @param SimpleScorer $reporter Reporter to receive events. + * @param string $just_this_case Only this case or group will run. + * @param string $just_this_test Only this test method will run. + */ + function __construct($reporter, $just_this_case = false, $just_this_test = false) { + if (isset($just_this_case) && $just_this_case) { + $this->just_this_case = strtolower($just_this_case); + $this->off(); + } else { + $this->on(); + } + if (isset($just_this_test) && $just_this_test) { + $this->just_this_test = strtolower($just_this_test); + } + parent::__construct($reporter); + } + + /** + * Compares criteria to actual the case/group name. + * @param string $test_case The incoming test. + * @return boolean True if matched. + * @access protected + */ + protected function matchesTestCase($test_case) { + return $this->just_this_case == strtolower($test_case); + } + + /** + * Compares criteria to actual the test name. If no + * name was specified at the beginning, then all tests + * can run. + * @param string $method The incoming test method. + * @return boolean True if matched. + * @access protected + */ + protected function shouldRunTest($test_case, $method) { + if ($this->isOn() || $this->matchesTestCase($test_case)) { + if ($this->just_this_test) { + return $this->just_this_test == strtolower($method); + } else { + return true; + } + } + return false; + } + + /** + * Switch on testing for the group or subgroup. + * @access private + */ + protected function on() { + $this->on = true; + } + + /** + * Switch off testing for the group or subgroup. + * @access private + */ + protected function off() { + $this->on = false; + } + + /** + * Is this group actually being tested? + * @return boolean True if the current test group is active. + * @access private + */ + protected function isOn() { + return $this->on; + } + + /** + * Veto everything that doesn't match the method wanted. + * @param string $test_case Name of test case. + * @param string $method Name of test method. + * @return boolean True if test should be run. + * @access public + */ + function shouldInvoke($test_case, $method) { + if ($this->shouldRunTest($test_case, $method)) { + return $this->reporter->shouldInvoke($test_case, $method); + } + return false; + } + + /** + * Paints the start of a group test. + * @param string $test_case Name of test or other label. + * @param integer $size Number of test cases starting. + * @access public + */ + function paintGroupStart($test_case, $size) { + if ($this->just_this_case && $this->matchesTestCase($test_case)) { + $this->on(); + } + $this->reporter->paintGroupStart($test_case, $size); + } + + /** + * Paints the end of a group test. + * @param string $test_case Name of test or other label. + * @access public + */ + function paintGroupEnd($test_case) { + $this->reporter->paintGroupEnd($test_case); + if ($this->just_this_case && $this->matchesTestCase($test_case)) { + $this->off(); + } + } +} + +/** + * Suppresses skip messages. + * @package SimpleTest + * @subpackage UnitTester + */ +class NoSkipsReporter extends SimpleReporterDecorator { + + /** + * Does nothing. + * @param string $message Text of skip condition. + * @access public + */ + function paintSkip($message) { } +} +?> \ No newline at end of file diff --git a/code/ryzom/tools/server/www/webtt/vendors/simpletest/scorer.php b/code/ryzom/tools/server/www/webtt/vendors/simpletest/scorer.php new file mode 100644 index 000000000..27776f4b6 --- /dev/null +++ b/code/ryzom/tools/server/www/webtt/vendors/simpletest/scorer.php @@ -0,0 +1,875 @@ +passes = 0; + $this->fails = 0; + $this->exceptions = 0; + $this->is_dry_run = false; + } + + /** + * Signals that the next evaluation will be a dry + * run. That is, the structure events will be + * recorded, but no tests will be run. + * @param boolean $is_dry Dry run if true. + * @access public + */ + function makeDry($is_dry = true) { + $this->is_dry_run = $is_dry; + } + + /** + * The reporter has a veto on what should be run. + * @param string $test_case_name name of test case. + * @param string $method Name of test method. + * @access public + */ + function shouldInvoke($test_case_name, $method) { + return ! $this->is_dry_run; + } + + /** + * Can wrap the invoker in preperation for running + * a test. + * @param SimpleInvoker $invoker Individual test runner. + * @return SimpleInvoker Wrapped test runner. + * @access public + */ + function createInvoker($invoker) { + return $invoker; + } + + /** + * Accessor for current status. Will be false + * if there have been any failures or exceptions. + * Used for command line tools. + * @return boolean True if no failures. + * @access public + */ + function getStatus() { + if ($this->exceptions + $this->fails > 0) { + return false; + } + return true; + } + + /** + * Paints the start of a group test. + * @param string $test_name Name of test or other label. + * @param integer $size Number of test cases starting. + * @access public + */ + function paintGroupStart($test_name, $size) { + } + + /** + * Paints the end of a group test. + * @param string $test_name Name of test or other label. + * @access public + */ + function paintGroupEnd($test_name) { + } + + /** + * Paints the start of a test case. + * @param string $test_name Name of test or other label. + * @access public + */ + function paintCaseStart($test_name) { + } + + /** + * Paints the end of a test case. + * @param string $test_name Name of test or other label. + * @access public + */ + function paintCaseEnd($test_name) { + } + + /** + * Paints the start of a test method. + * @param string $test_name Name of test or other label. + * @access public + */ + function paintMethodStart($test_name) { + } + + /** + * Paints the end of a test method. + * @param string $test_name Name of test or other label. + * @access public + */ + function paintMethodEnd($test_name) { + } + + /** + * Increments the pass count. + * @param string $message Message is ignored. + * @access public + */ + function paintPass($message) { + $this->passes++; + } + + /** + * Increments the fail count. + * @param string $message Message is ignored. + * @access public + */ + function paintFail($message) { + $this->fails++; + } + + /** + * Deals with PHP 4 throwing an error. + * @param string $message Text of error formatted by + * the test case. + * @access public + */ + function paintError($message) { + $this->exceptions++; + } + + /** + * Deals with PHP 5 throwing an exception. + * @param Exception $exception The actual exception thrown. + * @access public + */ + function paintException($exception) { + $this->exceptions++; + } + + /** + * Prints the message for skipping tests. + * @param string $message Text of skip condition. + * @access public + */ + function paintSkip($message) { + } + + /** + * Accessor for the number of passes so far. + * @return integer Number of passes. + * @access public + */ + function getPassCount() { + return $this->passes; + } + + /** + * Accessor for the number of fails so far. + * @return integer Number of fails. + * @access public + */ + function getFailCount() { + return $this->fails; + } + + /** + * Accessor for the number of untrapped errors + * so far. + * @return integer Number of exceptions. + * @access public + */ + function getExceptionCount() { + return $this->exceptions; + } + + /** + * Paints a simple supplementary message. + * @param string $message Text to display. + * @access public + */ + function paintMessage($message) { + } + + /** + * Paints a formatted ASCII message such as a + * privateiable dump. + * @param string $message Text to display. + * @access public + */ + function paintFormattedMessage($message) { + } + + /** + * By default just ignores user generated events. + * @param string $type Event type as text. + * @param mixed $payload Message or object. + * @access public + */ + function paintSignal($type, $payload) { + } +} + +/** + * Recipient of generated test messages that can display + * page footers and headers. Also keeps track of the + * test nesting. This is the main base class on which + * to build the finished test (page based) displays. + * @package SimpleTest + * @subpackage UnitTester + */ +class SimpleReporter extends SimpleScorer { + private $test_stack; + private $size; + private $progress; + + /** + * Starts the display with no results in. + * @access public + */ + function __construct() { + parent::__construct(); + $this->test_stack = array(); + $this->size = null; + $this->progress = 0; + } + + /** + * Gets the formatter for small generic data items. + * @return SimpleDumper Formatter. + * @access public + */ + function getDumper() { + return new SimpleDumper(); + } + + /** + * Paints the start of a group test. Will also paint + * the page header and footer if this is the + * first test. Will stash the size if the first + * start. + * @param string $test_name Name of test that is starting. + * @param integer $size Number of test cases starting. + * @access public + */ + function paintGroupStart($test_name, $size) { + if (! isset($this->size)) { + $this->size = $size; + } + if (count($this->test_stack) == 0) { + $this->paintHeader($test_name); + } + $this->test_stack[] = $test_name; + } + + /** + * Paints the end of a group test. Will paint the page + * footer if the stack of tests has unwound. + * @param string $test_name Name of test that is ending. + * @param integer $progress Number of test cases ending. + * @access public + */ + function paintGroupEnd($test_name) { + array_pop($this->test_stack); + if (count($this->test_stack) == 0) { + $this->paintFooter($test_name); + } + } + + /** + * Paints the start of a test case. Will also paint + * the page header and footer if this is the + * first test. Will stash the size if the first + * start. + * @param string $test_name Name of test that is starting. + * @access public + */ + function paintCaseStart($test_name) { + if (! isset($this->size)) { + $this->size = 1; + } + if (count($this->test_stack) == 0) { + $this->paintHeader($test_name); + } + $this->test_stack[] = $test_name; + } + + /** + * Paints the end of a test case. Will paint the page + * footer if the stack of tests has unwound. + * @param string $test_name Name of test that is ending. + * @access public + */ + function paintCaseEnd($test_name) { + $this->progress++; + array_pop($this->test_stack); + if (count($this->test_stack) == 0) { + $this->paintFooter($test_name); + } + } + + /** + * Paints the start of a test method. + * @param string $test_name Name of test that is starting. + * @access public + */ + function paintMethodStart($test_name) { + $this->test_stack[] = $test_name; + } + + /** + * Paints the end of a test method. Will paint the page + * footer if the stack of tests has unwound. + * @param string $test_name Name of test that is ending. + * @access public + */ + function paintMethodEnd($test_name) { + array_pop($this->test_stack); + } + + /** + * Paints the test document header. + * @param string $test_name First test top level + * to start. + * @access public + * @abstract + */ + function paintHeader($test_name) { + } + + /** + * Paints the test document footer. + * @param string $test_name The top level test. + * @access public + * @abstract + */ + function paintFooter($test_name) { + } + + /** + * Accessor for internal test stack. For + * subclasses that need to see the whole test + * history for display purposes. + * @return array List of methods in nesting order. + * @access public + */ + function getTestList() { + return $this->test_stack; + } + + /** + * Accessor for total test size in number + * of test cases. Null until the first + * test is started. + * @return integer Total number of cases at start. + * @access public + */ + function getTestCaseCount() { + return $this->size; + } + + /** + * Accessor for the number of test cases + * completed so far. + * @return integer Number of ended cases. + * @access public + */ + function getTestCaseProgress() { + return $this->progress; + } + + /** + * Static check for running in the comand line. + * @return boolean True if CLI. + * @access public + */ + static function inCli() { + return php_sapi_name() == 'cli'; + } +} + +/** + * For modifying the behaviour of the visual reporters. + * @package SimpleTest + * @subpackage UnitTester + */ +class SimpleReporterDecorator { + protected $reporter; + + /** + * Mediates between the reporter and the test case. + * @param SimpleScorer $reporter Reporter to receive events. + */ + function __construct($reporter) { + $this->reporter = $reporter; + } + + /** + * Signals that the next evaluation will be a dry + * run. That is, the structure events will be + * recorded, but no tests will be run. + * @param boolean $is_dry Dry run if true. + * @access public + */ + function makeDry($is_dry = true) { + $this->reporter->makeDry($is_dry); + } + + /** + * Accessor for current status. Will be false + * if there have been any failures or exceptions. + * Used for command line tools. + * @return boolean True if no failures. + * @access public + */ + function getStatus() { + return $this->reporter->getStatus(); + } + + /** + * The nesting of the test cases so far. Not + * all reporters have this facility. + * @return array Test list if accessible. + * @access public + */ + function getTestList() { + if (method_exists($this->reporter, 'getTestList')) { + return $this->reporter->getTestList(); + } else { + return array(); + } + } + + /** + * The reporter has a veto on what should be run. + * @param string $test_case_name Name of test case. + * @param string $method Name of test method. + * @return boolean True if test should be run. + * @access public + */ + function shouldInvoke($test_case_name, $method) { + return $this->reporter->shouldInvoke($test_case_name, $method); + } + + /** + * Can wrap the invoker in preparation for running + * a test. + * @param SimpleInvoker $invoker Individual test runner. + * @return SimpleInvoker Wrapped test runner. + * @access public + */ + function createInvoker($invoker) { + return $this->reporter->createInvoker($invoker); + } + + /** + * Gets the formatter for privateiables and other small + * generic data items. + * @return SimpleDumper Formatter. + * @access public + */ + function getDumper() { + return $this->reporter->getDumper(); + } + + /** + * Paints the start of a group test. + * @param string $test_name Name of test or other label. + * @param integer $size Number of test cases starting. + * @access public + */ + function paintGroupStart($test_name, $size) { + $this->reporter->paintGroupStart($test_name, $size); + } + + /** + * Paints the end of a group test. + * @param string $test_name Name of test or other label. + * @access public + */ + function paintGroupEnd($test_name) { + $this->reporter->paintGroupEnd($test_name); + } + + /** + * Paints the start of a test case. + * @param string $test_name Name of test or other label. + * @access public + */ + function paintCaseStart($test_name) { + $this->reporter->paintCaseStart($test_name); + } + + /** + * Paints the end of a test case. + * @param string $test_name Name of test or other label. + * @access public + */ + function paintCaseEnd($test_name) { + $this->reporter->paintCaseEnd($test_name); + } + + /** + * Paints the start of a test method. + * @param string $test_name Name of test or other label. + * @access public + */ + function paintMethodStart($test_name) { + $this->reporter->paintMethodStart($test_name); + } + + /** + * Paints the end of a test method. + * @param string $test_name Name of test or other label. + * @access public + */ + function paintMethodEnd($test_name) { + $this->reporter->paintMethodEnd($test_name); + } + + /** + * Chains to the wrapped reporter. + * @param string $message Message is ignored. + * @access public + */ + function paintPass($message) { + $this->reporter->paintPass($message); + } + + /** + * Chains to the wrapped reporter. + * @param string $message Message is ignored. + * @access public + */ + function paintFail($message) { + $this->reporter->paintFail($message); + } + + /** + * Chains to the wrapped reporter. + * @param string $message Text of error formatted by + * the test case. + * @access public + */ + function paintError($message) { + $this->reporter->paintError($message); + } + + /** + * Chains to the wrapped reporter. + * @param Exception $exception Exception to show. + * @access public + */ + function paintException($exception) { + $this->reporter->paintException($exception); + } + + /** + * Prints the message for skipping tests. + * @param string $message Text of skip condition. + * @access public + */ + function paintSkip($message) { + $this->reporter->paintSkip($message); + } + + /** + * Chains to the wrapped reporter. + * @param string $message Text to display. + * @access public + */ + function paintMessage($message) { + $this->reporter->paintMessage($message); + } + + /** + * Chains to the wrapped reporter. + * @param string $message Text to display. + * @access public + */ + function paintFormattedMessage($message) { + $this->reporter->paintFormattedMessage($message); + } + + /** + * Chains to the wrapped reporter. + * @param string $type Event type as text. + * @param mixed $payload Message or object. + * @return boolean Should return false if this + * type of signal should fail the + * test suite. + * @access public + */ + function paintSignal($type, $payload) { + $this->reporter->paintSignal($type, $payload); + } +} + +/** + * For sending messages to multiple reporters at + * the same time. + * @package SimpleTest + * @subpackage UnitTester + */ +class MultipleReporter { + private $reporters = array(); + + /** + * Adds a reporter to the subscriber list. + * @param SimpleScorer $reporter Reporter to receive events. + * @access public + */ + function attachReporter($reporter) { + $this->reporters[] = $reporter; + } + + /** + * Signals that the next evaluation will be a dry + * run. That is, the structure events will be + * recorded, but no tests will be run. + * @param boolean $is_dry Dry run if true. + * @access public + */ + function makeDry($is_dry = true) { + for ($i = 0; $i < count($this->reporters); $i++) { + $this->reporters[$i]->makeDry($is_dry); + } + } + + /** + * Accessor for current status. Will be false + * if there have been any failures or exceptions. + * If any reporter reports a failure, the whole + * suite fails. + * @return boolean True if no failures. + * @access public + */ + function getStatus() { + for ($i = 0; $i < count($this->reporters); $i++) { + if (! $this->reporters[$i]->getStatus()) { + return false; + } + } + return true; + } + + /** + * The reporter has a veto on what should be run. + * It requires all reporters to want to run the method. + * @param string $test_case_name name of test case. + * @param string $method Name of test method. + * @access public + */ + function shouldInvoke($test_case_name, $method) { + for ($i = 0; $i < count($this->reporters); $i++) { + if (! $this->reporters[$i]->shouldInvoke($test_case_name, $method)) { + return false; + } + } + return true; + } + + /** + * Every reporter gets a chance to wrap the invoker. + * @param SimpleInvoker $invoker Individual test runner. + * @return SimpleInvoker Wrapped test runner. + * @access public + */ + function createInvoker($invoker) { + for ($i = 0; $i < count($this->reporters); $i++) { + $invoker = $this->reporters[$i]->createInvoker($invoker); + } + return $invoker; + } + + /** + * Gets the formatter for privateiables and other small + * generic data items. + * @return SimpleDumper Formatter. + * @access public + */ + function getDumper() { + return new SimpleDumper(); + } + + /** + * Paints the start of a group test. + * @param string $test_name Name of test or other label. + * @param integer $size Number of test cases starting. + * @access public + */ + function paintGroupStart($test_name, $size) { + for ($i = 0; $i < count($this->reporters); $i++) { + $this->reporters[$i]->paintGroupStart($test_name, $size); + } + } + + /** + * Paints the end of a group test. + * @param string $test_name Name of test or other label. + * @access public + */ + function paintGroupEnd($test_name) { + for ($i = 0; $i < count($this->reporters); $i++) { + $this->reporters[$i]->paintGroupEnd($test_name); + } + } + + /** + * Paints the start of a test case. + * @param string $test_name Name of test or other label. + * @access public + */ + function paintCaseStart($test_name) { + for ($i = 0; $i < count($this->reporters); $i++) { + $this->reporters[$i]->paintCaseStart($test_name); + } + } + + /** + * Paints the end of a test case. + * @param string $test_name Name of test or other label. + * @access public + */ + function paintCaseEnd($test_name) { + for ($i = 0; $i < count($this->reporters); $i++) { + $this->reporters[$i]->paintCaseEnd($test_name); + } + } + + /** + * Paints the start of a test method. + * @param string $test_name Name of test or other label. + * @access public + */ + function paintMethodStart($test_name) { + for ($i = 0; $i < count($this->reporters); $i++) { + $this->reporters[$i]->paintMethodStart($test_name); + } + } + + /** + * Paints the end of a test method. + * @param string $test_name Name of test or other label. + * @access public + */ + function paintMethodEnd($test_name) { + for ($i = 0; $i < count($this->reporters); $i++) { + $this->reporters[$i]->paintMethodEnd($test_name); + } + } + + /** + * Chains to the wrapped reporter. + * @param string $message Message is ignored. + * @access public + */ + function paintPass($message) { + for ($i = 0; $i < count($this->reporters); $i++) { + $this->reporters[$i]->paintPass($message); + } + } + + /** + * Chains to the wrapped reporter. + * @param string $message Message is ignored. + * @access public + */ + function paintFail($message) { + for ($i = 0; $i < count($this->reporters); $i++) { + $this->reporters[$i]->paintFail($message); + } + } + + /** + * Chains to the wrapped reporter. + * @param string $message Text of error formatted by + * the test case. + * @access public + */ + function paintError($message) { + for ($i = 0; $i < count($this->reporters); $i++) { + $this->reporters[$i]->paintError($message); + } + } + + /** + * Chains to the wrapped reporter. + * @param Exception $exception Exception to display. + * @access public + */ + function paintException($exception) { + for ($i = 0; $i < count($this->reporters); $i++) { + $this->reporters[$i]->paintException($exception); + } + } + + /** + * Prints the message for skipping tests. + * @param string $message Text of skip condition. + * @access public + */ + function paintSkip($message) { + for ($i = 0; $i < count($this->reporters); $i++) { + $this->reporters[$i]->paintSkip($message); + } + } + + /** + * Chains to the wrapped reporter. + * @param string $message Text to display. + * @access public + */ + function paintMessage($message) { + for ($i = 0; $i < count($this->reporters); $i++) { + $this->reporters[$i]->paintMessage($message); + } + } + + /** + * Chains to the wrapped reporter. + * @param string $message Text to display. + * @access public + */ + function paintFormattedMessage($message) { + for ($i = 0; $i < count($this->reporters); $i++) { + $this->reporters[$i]->paintFormattedMessage($message); + } + } + + /** + * Chains to the wrapped reporter. + * @param string $type Event type as text. + * @param mixed $payload Message or object. + * @return boolean Should return false if this + * type of signal should fail the + * test suite. + * @access public + */ + function paintSignal($type, $payload) { + for ($i = 0; $i < count($this->reporters); $i++) { + $this->reporters[$i]->paintSignal($type, $payload); + } + } +} +?> \ No newline at end of file diff --git a/code/ryzom/tools/server/www/webtt/vendors/simpletest/selector.php b/code/ryzom/tools/server/www/webtt/vendors/simpletest/selector.php new file mode 100644 index 000000000..ba2fed312 --- /dev/null +++ b/code/ryzom/tools/server/www/webtt/vendors/simpletest/selector.php @@ -0,0 +1,141 @@ +name = $name; + } + + /** + * Accessor for name. + * @returns string $name Name to match. + */ + function getName() { + return $this->name; + } + + /** + * Compares with name attribute of widget. + * @param SimpleWidget $widget Control to compare. + * @access public + */ + function isMatch($widget) { + return ($widget->getName() == $this->name); + } +} + +/** + * Used to extract form elements for testing against. + * Searches by visible label or alt text. + * @package SimpleTest + * @subpackage WebTester + */ +class SimpleByLabel { + private $label; + + /** + * Stashes the name for later comparison. + * @param string $label Visible text to match. + */ + function __construct($label) { + $this->label = $label; + } + + /** + * Comparison. Compares visible text of widget or + * related label. + * @param SimpleWidget $widget Control to compare. + * @access public + */ + function isMatch($widget) { + if (! method_exists($widget, 'isLabel')) { + return false; + } + return $widget->isLabel($this->label); + } +} + +/** + * Used to extract form elements for testing against. + * Searches dy id attribute. + * @package SimpleTest + * @subpackage WebTester + */ +class SimpleById { + private $id; + + /** + * Stashes the name for later comparison. + * @param string $id ID atribute to match. + */ + function __construct($id) { + $this->id = $id; + } + + /** + * Comparison. Compares id attribute of widget. + * @param SimpleWidget $widget Control to compare. + * @access public + */ + function isMatch($widget) { + return $widget->isId($this->id); + } +} + +/** + * Used to extract form elements for testing against. + * Searches by visible label, name or alt text. + * @package SimpleTest + * @subpackage WebTester + */ +class SimpleByLabelOrName { + private $label; + + /** + * Stashes the name/label for later comparison. + * @param string $label Visible text to match. + */ + function __construct($label) { + $this->label = $label; + } + + /** + * Comparison. Compares visible text of widget or + * related label or name. + * @param SimpleWidget $widget Control to compare. + * @access public + */ + function isMatch($widget) { + if (method_exists($widget, 'isLabel')) { + if ($widget->isLabel($this->label)) { + return true; + } + } + return ($widget->getName() == $this->label); + } +} +?> \ No newline at end of file diff --git a/code/ryzom/tools/server/www/webtt/vendors/simpletest/shell_tester.php b/code/ryzom/tools/server/www/webtt/vendors/simpletest/shell_tester.php new file mode 100644 index 000000000..9a3bd389e --- /dev/null +++ b/code/ryzom/tools/server/www/webtt/vendors/simpletest/shell_tester.php @@ -0,0 +1,330 @@ +output = false; + } + + /** + * Actually runs the command. Does not trap the + * error stream output as this need PHP 4.3+. + * @param string $command The actual command line + * to run. + * @return integer Exit code. + * @access public + */ + function execute($command) { + $this->output = false; + exec($command, $this->output, $ret); + return $ret; + } + + /** + * Accessor for the last output. + * @return string Output as text. + * @access public + */ + function getOutput() { + return implode("\n", $this->output); + } + + /** + * Accessor for the last output. + * @return array Output as array of lines. + * @access public + */ + function getOutputAsList() { + return $this->output; + } +} + +/** + * Test case for testing of command line scripts and + * utilities. Usually scripts that are external to the + * PHP code, but support it in some way. + * @package SimpleTest + * @subpackage UnitTester + */ +class ShellTestCase extends SimpleTestCase { + private $current_shell; + private $last_status; + private $last_command; + + /** + * Creates an empty test case. Should be subclassed + * with test methods for a functional test case. + * @param string $label Name of test case. Will use + * the class name if none specified. + * @access public + */ + function __construct($label = false) { + parent::__construct($label); + $this->current_shell = $this->createShell(); + $this->last_status = false; + $this->last_command = ''; + } + + /** + * Executes a command and buffers the results. + * @param string $command Command to run. + * @return boolean True if zero exit code. + * @access public + */ + function execute($command) { + $shell = $this->getShell(); + $this->last_status = $shell->execute($command); + $this->last_command = $command; + return ($this->last_status === 0); + } + + /** + * Dumps the output of the last command. + * @access public + */ + function dumpOutput() { + $this->dump($this->getOutput()); + } + + /** + * Accessor for the last output. + * @return string Output as text. + * @access public + */ + function getOutput() { + $shell = $this->getShell(); + return $shell->getOutput(); + } + + /** + * Accessor for the last output. + * @return array Output as array of lines. + * @access public + */ + function getOutputAsList() { + $shell = $this->getShell(); + return $shell->getOutputAsList(); + } + + /** + * Called from within the test methods to register + * passes and failures. + * @param boolean $result Pass on true. + * @param string $message Message to display describing + * the test state. + * @return boolean True on pass + * @access public + */ + function assertTrue($result, $message = false) { + return $this->assert(new TrueExpectation(), $result, $message); + } + + /** + * Will be true on false and vice versa. False + * is the PHP definition of false, so that null, + * empty strings, zero and an empty array all count + * as false. + * @param boolean $result Pass on false. + * @param string $message Message to display. + * @return boolean True on pass + * @access public + */ + function assertFalse($result, $message = '%s') { + return $this->assert(new FalseExpectation(), $result, $message); + } + + /** + * Will trigger a pass if the two parameters have + * the same value only. Otherwise a fail. This + * is for testing hand extracted text, etc. + * @param mixed $first Value to compare. + * @param mixed $second Value to compare. + * @param string $message Message to display. + * @return boolean True on pass + * @access public + */ + function assertEqual($first, $second, $message = "%s") { + return $this->assert( + new EqualExpectation($first), + $second, + $message); + } + + /** + * Will trigger a pass if the two parameters have + * a different value. Otherwise a fail. This + * is for testing hand extracted text, etc. + * @param mixed $first Value to compare. + * @param mixed $second Value to compare. + * @param string $message Message to display. + * @return boolean True on pass + * @access public + */ + function assertNotEqual($first, $second, $message = "%s") { + return $this->assert( + new NotEqualExpectation($first), + $second, + $message); + } + + /** + * Tests the last status code from the shell. + * @param integer $status Expected status of last + * command. + * @param string $message Message to display. + * @return boolean True if pass. + * @access public + */ + function assertExitCode($status, $message = "%s") { + $message = sprintf($message, "Expected status code of [$status] from [" . + $this->last_command . "], but got [" . + $this->last_status . "]"); + return $this->assertTrue($status === $this->last_status, $message); + } + + /** + * Attempt to exactly match the combined STDERR and + * STDOUT output. + * @param string $expected Expected output. + * @param string $message Message to display. + * @return boolean True if pass. + * @access public + */ + function assertOutput($expected, $message = "%s") { + $shell = $this->getShell(); + return $this->assert( + new EqualExpectation($expected), + $shell->getOutput(), + $message); + } + + /** + * Scans the output for a Perl regex. If found + * anywhere it passes, else it fails. + * @param string $pattern Regex to search for. + * @param string $message Message to display. + * @return boolean True if pass. + * @access public + */ + function assertOutputPattern($pattern, $message = "%s") { + $shell = $this->getShell(); + return $this->assert( + new PatternExpectation($pattern), + $shell->getOutput(), + $message); + } + + /** + * If a Perl regex is found anywhere in the current + * output then a failure is generated, else a pass. + * @param string $pattern Regex to search for. + * @param $message Message to display. + * @return boolean True if pass. + * @access public + */ + function assertNoOutputPattern($pattern, $message = "%s") { + $shell = $this->getShell(); + return $this->assert( + new NoPatternExpectation($pattern), + $shell->getOutput(), + $message); + } + + /** + * File existence check. + * @param string $path Full filename and path. + * @param string $message Message to display. + * @return boolean True if pass. + * @access public + */ + function assertFileExists($path, $message = "%s") { + $message = sprintf($message, "File [$path] should exist"); + return $this->assertTrue(file_exists($path), $message); + } + + /** + * File non-existence check. + * @param string $path Full filename and path. + * @param string $message Message to display. + * @return boolean True if pass. + * @access public + */ + function assertFileNotExists($path, $message = "%s") { + $message = sprintf($message, "File [$path] should not exist"); + return $this->assertFalse(file_exists($path), $message); + } + + /** + * Scans a file for a Perl regex. If found + * anywhere it passes, else it fails. + * @param string $pattern Regex to search for. + * @param string $path Full filename and path. + * @param string $message Message to display. + * @return boolean True if pass. + * @access public + */ + function assertFilePattern($pattern, $path, $message = "%s") { + return $this->assert( + new PatternExpectation($pattern), + implode('', file($path)), + $message); + } + + /** + * If a Perl regex is found anywhere in the named + * file then a failure is generated, else a pass. + * @param string $pattern Regex to search for. + * @param string $path Full filename and path. + * @param string $message Message to display. + * @return boolean True if pass. + * @access public + */ + function assertNoFilePattern($pattern, $path, $message = "%s") { + return $this->assert( + new NoPatternExpectation($pattern), + implode('', file($path)), + $message); + } + + /** + * Accessor for current shell. Used for testing the + * the tester itself. + * @return Shell Current shell. + * @access protected + */ + protected function getShell() { + return $this->current_shell; + } + + /** + * Factory for the shell to run the command on. + * @return Shell New shell object. + * @access protected + */ + protected function createShell() { + return new SimpleShell(); + } +} +?> \ No newline at end of file diff --git a/code/ryzom/tools/server/www/webtt/vendors/simpletest/simpletest.php b/code/ryzom/tools/server/www/webtt/vendors/simpletest/simpletest.php new file mode 100644 index 000000000..425c869a8 --- /dev/null +++ b/code/ryzom/tools/server/www/webtt/vendors/simpletest/simpletest.php @@ -0,0 +1,391 @@ +getParent()) { + SimpleTest::ignore($parent); + } + } + } + } + + /** + * Puts the object to the global pool of 'preferred' objects + * which can be retrieved with SimpleTest :: preferred() method. + * Instances of the same class are overwritten. + * @param object $object Preferred object + * @see preferred() + */ + static function prefer($object) { + $registry = &SimpleTest::getRegistry(); + $registry['Preferred'][] = $object; + } + + /** + * Retrieves 'preferred' objects from global pool. Class filter + * can be applied in order to retrieve the object of the specific + * class + * @param array|string $classes Allowed classes or interfaces. + * @return array|object|null + * @see prefer() + */ + static function preferred($classes) { + if (! is_array($classes)) { + $classes = array($classes); + } + $registry = &SimpleTest::getRegistry(); + for ($i = count($registry['Preferred']) - 1; $i >= 0; $i--) { + foreach ($classes as $class) { + if (SimpleTestCompatibility::isA($registry['Preferred'][$i], $class)) { + return $registry['Preferred'][$i]; + } + } + } + return null; + } + + /** + * Test to see if a test case is in the ignore + * list. Quite obviously the ignore list should + * be a separate object and will be one day. + * This method is internal to SimpleTest. Don't + * use it. + * @param string $class Class name to test. + * @return boolean True if should not be run. + */ + static function isIgnored($class) { + $registry = &SimpleTest::getRegistry(); + return isset($registry['IgnoreList'][strtolower($class)]); + } + + /** + * Sets proxy to use on all requests for when + * testing from behind a firewall. Set host + * to false to disable. This will take effect + * if there are no other proxy settings. + * @param string $proxy Proxy host as URL. + * @param string $username Proxy username for authentication. + * @param string $password Proxy password for authentication. + */ + static function useProxy($proxy, $username = false, $password = false) { + $registry = &SimpleTest::getRegistry(); + $registry['DefaultProxy'] = $proxy; + $registry['DefaultProxyUsername'] = $username; + $registry['DefaultProxyPassword'] = $password; + } + + /** + * Accessor for default proxy host. + * @return string Proxy URL. + */ + static function getDefaultProxy() { + $registry = &SimpleTest::getRegistry(); + return $registry['DefaultProxy']; + } + + /** + * Accessor for default proxy username. + * @return string Proxy username for authentication. + */ + static function getDefaultProxyUsername() { + $registry = &SimpleTest::getRegistry(); + return $registry['DefaultProxyUsername']; + } + + /** + * Accessor for default proxy password. + * @return string Proxy password for authentication. + */ + static function getDefaultProxyPassword() { + $registry = &SimpleTest::getRegistry(); + return $registry['DefaultProxyPassword']; + } + + /** + * Accessor for default HTML parsers. + * @return array List of parsers to try in + * order until one responds true + * to can(). + */ + static function getParsers() { + $registry = &SimpleTest::getRegistry(); + return $registry['Parsers']; + } + + /** + * Set the list of HTML parsers to attempt to use by default. + * @param array $parsers List of parsers to try in + * order until one responds true + * to can(). + */ + static function setParsers($parsers) { + $registry = &SimpleTest::getRegistry(); + $registry['Parsers'] = $parsers; + } + + /** + * Accessor for global registry of options. + * @return hash All stored values. + */ + protected static function &getRegistry() { + static $registry = false; + if (! $registry) { + $registry = SimpleTest::getDefaults(); + } + return $registry; + } + + /** + * Accessor for the context of the current + * test run. + * @return SimpleTestContext Current test run. + */ + static function getContext() { + static $context = false; + if (! $context) { + $context = new SimpleTestContext(); + } + return $context; + } + + /** + * Constant default values. + * @return hash All registry defaults. + */ + protected static function getDefaults() { + return array( + 'Parsers' => false, + 'MockBaseClass' => 'SimpleMock', + 'IgnoreList' => array(), + 'DefaultProxy' => false, + 'DefaultProxyUsername' => false, + 'DefaultProxyPassword' => false, + 'Preferred' => array(new HtmlReporter(), new TextReporter(), new XmlReporter())); + } + + /** + * @deprecated + */ + static function setMockBaseClass($mock_base) { + $registry = &SimpleTest::getRegistry(); + $registry['MockBaseClass'] = $mock_base; + } + + /** + * @deprecated + */ + static function getMockBaseClass() { + $registry = &SimpleTest::getRegistry(); + return $registry['MockBaseClass']; + } +} + +/** + * Container for all components for a specific + * test run. Makes things like error queues + * available to PHP event handlers, and also + * gets around some nasty reference issues in + * the mocks. + * @package SimpleTest + */ +class SimpleTestContext { + private $test; + private $reporter; + private $resources; + + /** + * Clears down the current context. + * @access public + */ + function clear() { + $this->resources = array(); + } + + /** + * Sets the current test case instance. This + * global instance can be used by the mock objects + * to send message to the test cases. + * @param SimpleTestCase $test Test case to register. + */ + function setTest($test) { + $this->clear(); + $this->test = $test; + } + + /** + * Accessor for currently running test case. + * @return SimpleTestCase Current test. + */ + function getTest() { + return $this->test; + } + + /** + * Sets the current reporter. This + * global instance can be used by the mock objects + * to send messages. + * @param SimpleReporter $reporter Reporter to register. + */ + function setReporter($reporter) { + $this->clear(); + $this->reporter = $reporter; + } + + /** + * Accessor for current reporter. + * @return SimpleReporter Current reporter. + */ + function getReporter() { + return $this->reporter; + } + + /** + * Accessor for the Singleton resource. + * @return object Global resource. + */ + function get($resource) { + if (! isset($this->resources[$resource])) { + $this->resources[$resource] = new $resource(); + } + return $this->resources[$resource]; + } +} + +/** + * Interrogates the stack trace to recover the + * failure point. + * @package SimpleTest + * @subpackage UnitTester + */ +class SimpleStackTrace { + private $prefixes; + + /** + * Stashes the list of target prefixes. + * @param array $prefixes List of method prefixes + * to search for. + */ + function __construct($prefixes) { + $this->prefixes = $prefixes; + } + + /** + * Extracts the last method name that was not within + * Simpletest itself. Captures a stack trace if none given. + * @param array $stack List of stack frames. + * @return string Snippet of test report with line + * number and file. + */ + function traceMethod($stack = false) { + $stack = $stack ? $stack : $this->captureTrace(); + foreach ($stack as $frame) { + if ($this->frameLiesWithinSimpleTestFolder($frame)) { + continue; + } + if ($this->frameMatchesPrefix($frame)) { + return ' at [' . $frame['file'] . ' line ' . $frame['line'] . ']'; + } + } + return ''; + } + + /** + * Test to see if error is generated by SimpleTest itself. + * @param array $frame PHP stack frame. + * @return boolean True if a SimpleTest file. + */ + protected function frameLiesWithinSimpleTestFolder($frame) { + if (isset($frame['file'])) { + $path = substr(SIMPLE_TEST, 0, -1); + if (strpos($frame['file'], $path) === 0) { + if (dirname($frame['file']) == $path) { + return true; + } + } + } + return false; + } + + /** + * Tries to determine if the method call is an assert, etc. + * @param array $frame PHP stack frame. + * @return boolean True if matches a target. + */ + protected function frameMatchesPrefix($frame) { + foreach ($this->prefixes as $prefix) { + if (strncmp($frame['function'], $prefix, strlen($prefix)) == 0) { + return true; + } + } + return false; + } + + /** + * Grabs a current stack trace. + * @return array Fulle trace. + */ + protected function captureTrace() { + if (function_exists('debug_backtrace')) { + return array_reverse(debug_backtrace()); + } + return array(); + } +} +?> \ No newline at end of file diff --git a/code/ryzom/tools/server/www/webtt/vendors/simpletest/socket.php b/code/ryzom/tools/server/www/webtt/vendors/simpletest/socket.php new file mode 100644 index 000000000..06e8ca62d --- /dev/null +++ b/code/ryzom/tools/server/www/webtt/vendors/simpletest/socket.php @@ -0,0 +1,312 @@ +clearError(); + } + + /** + * Test for an outstanding error. + * @return boolean True if there is an error. + * @access public + */ + function isError() { + return ($this->error != ''); + } + + /** + * Accessor for an outstanding error. + * @return string Empty string if no error otherwise + * the error message. + * @access public + */ + function getError() { + return $this->error; + } + + /** + * Sets the internal error. + * @param string Error message to stash. + * @access protected + */ + function setError($error) { + $this->error = $error; + } + + /** + * Resets the error state to no error. + * @access protected + */ + function clearError() { + $this->setError(''); + } +} + +/** + * @package SimpleTest + * @subpackage WebTester + */ +class SimpleFileSocket extends SimpleStickyError { + private $handle; + private $is_open = false; + private $sent = ''; + private $block_size; + + /** + * Opens a socket for reading and writing. + * @param SimpleUrl $file Target URI to fetch. + * @param integer $block_size Size of chunk to read. + * @access public + */ + function __construct($file, $block_size = 1024) { + parent::__construct(); + if (! ($this->handle = $this->openFile($file, $error))) { + $file_string = $file->asString(); + $this->setError("Cannot open [$file_string] with [$error]"); + return; + } + $this->is_open = true; + $this->block_size = $block_size; + } + + /** + * Writes some data to the socket and saves alocal copy. + * @param string $message String to send to socket. + * @return boolean True if successful. + * @access public + */ + function write($message) { + return true; + } + + /** + * Reads data from the socket. The error suppresion + * is a workaround for PHP4 always throwing a warning + * with a secure socket. + * @return integer/boolean Incoming bytes. False + * on error. + * @access public + */ + function read() { + $raw = @fread($this->handle, $this->block_size); + if ($raw === false) { + $this->setError('Cannot read from socket'); + $this->close(); + } + return $raw; + } + + /** + * Accessor for socket open state. + * @return boolean True if open. + * @access public + */ + function isOpen() { + return $this->is_open; + } + + /** + * Closes the socket preventing further reads. + * Cannot be reopened once closed. + * @return boolean True if successful. + * @access public + */ + function close() { + if (!$this->is_open) return false; + $this->is_open = false; + return fclose($this->handle); + } + + /** + * Accessor for content so far. + * @return string Bytes sent only. + * @access public + */ + function getSent() { + return $this->sent; + } + + /** + * Actually opens the low level socket. + * @param SimpleUrl $file SimpleUrl file target. + * @param string $error Recipient of error message. + * @param integer $timeout Maximum time to wait for connection. + * @access protected + */ + protected function openFile($file, &$error) { + return @fopen($file->asString(), 'r'); + } +} + +/** + * Wrapper for TCP/IP socket. + * @package SimpleTest + * @subpackage WebTester + */ +class SimpleSocket extends SimpleStickyError { + private $handle; + private $is_open = false; + private $sent = ''; + private $lock_size; + + /** + * Opens a socket for reading and writing. + * @param string $host Hostname to send request to. + * @param integer $port Port on remote machine to open. + * @param integer $timeout Connection timeout in seconds. + * @param integer $block_size Size of chunk to read. + * @access public + */ + function __construct($host, $port, $timeout, $block_size = 255) { + parent::__construct(); + if (! ($this->handle = $this->openSocket($host, $port, $error_number, $error, $timeout))) { + $this->setError("Cannot open [$host:$port] with [$error] within [$timeout] seconds"); + return; + } + $this->is_open = true; + $this->block_size = $block_size; + SimpleTestCompatibility::setTimeout($this->handle, $timeout); + } + + /** + * Writes some data to the socket and saves alocal copy. + * @param string $message String to send to socket. + * @return boolean True if successful. + * @access public + */ + function write($message) { + if ($this->isError() || ! $this->isOpen()) { + return false; + } + $count = fwrite($this->handle, $message); + if (! $count) { + if ($count === false) { + $this->setError('Cannot write to socket'); + $this->close(); + } + return false; + } + fflush($this->handle); + $this->sent .= $message; + return true; + } + + /** + * Reads data from the socket. The error suppresion + * is a workaround for PHP4 always throwing a warning + * with a secure socket. + * @return integer/boolean Incoming bytes. False + * on error. + * @access public + */ + function read() { + if ($this->isError() || ! $this->isOpen()) { + return false; + } + $raw = @fread($this->handle, $this->block_size); + if ($raw === false) { + $this->setError('Cannot read from socket'); + $this->close(); + } + return $raw; + } + + /** + * Accessor for socket open state. + * @return boolean True if open. + * @access public + */ + function isOpen() { + return $this->is_open; + } + + /** + * Closes the socket preventing further reads. + * Cannot be reopened once closed. + * @return boolean True if successful. + * @access public + */ + function close() { + $this->is_open = false; + return fclose($this->handle); + } + + /** + * Accessor for content so far. + * @return string Bytes sent only. + * @access public + */ + function getSent() { + return $this->sent; + } + + /** + * Actually opens the low level socket. + * @param string $host Host to connect to. + * @param integer $port Port on host. + * @param integer $error_number Recipient of error code. + * @param string $error Recipoent of error message. + * @param integer $timeout Maximum time to wait for connection. + * @access protected + */ + protected function openSocket($host, $port, &$error_number, &$error, $timeout) { + return @fsockopen($host, $port, $error_number, $error, $timeout); + } +} + +/** + * Wrapper for TCP/IP socket over TLS. + * @package SimpleTest + * @subpackage WebTester + */ +class SimpleSecureSocket extends SimpleSocket { + + /** + * Opens a secure socket for reading and writing. + * @param string $host Hostname to send request to. + * @param integer $port Port on remote machine to open. + * @param integer $timeout Connection timeout in seconds. + * @access public + */ + function __construct($host, $port, $timeout) { + parent::__construct($host, $port, $timeout); + } + + /** + * Actually opens the low level socket. + * @param string $host Host to connect to. + * @param integer $port Port on host. + * @param integer $error_number Recipient of error code. + * @param string $error Recipient of error message. + * @param integer $timeout Maximum time to wait for connection. + * @access protected + */ + function openSocket($host, $port, &$error_number, &$error, $timeout) { + return parent::openSocket("tls://$host", $port, $error_number, $error, $timeout); + } +} +?> \ No newline at end of file diff --git a/code/ryzom/tools/server/www/webtt/vendors/simpletest/tag.php b/code/ryzom/tools/server/www/webtt/vendors/simpletest/tag.php new file mode 100644 index 000000000..afe649ec5 --- /dev/null +++ b/code/ryzom/tools/server/www/webtt/vendors/simpletest/tag.php @@ -0,0 +1,1527 @@ + 'SimpleAnchorTag', + 'title' => 'SimpleTitleTag', + 'base' => 'SimpleBaseTag', + 'button' => 'SimpleButtonTag', + 'textarea' => 'SimpleTextAreaTag', + 'option' => 'SimpleOptionTag', + 'label' => 'SimpleLabelTag', + 'form' => 'SimpleFormTag', + 'frame' => 'SimpleFrameTag'); + $attributes = $this->keysToLowerCase($attributes); + if (array_key_exists($name, $map)) { + $tag_class = $map[$name]; + return new $tag_class($attributes); + } elseif ($name == 'select') { + return $this->createSelectionTag($attributes); + } elseif ($name == 'input') { + return $this->createInputTag($attributes); + } + return new SimpleTag($name, $attributes); + } + + /** + * Factory for selection fields. + * @param hash $attributes Element attributes. + * @return SimpleTag Tag object. + * @access protected + */ + protected function createSelectionTag($attributes) { + if (isset($attributes['multiple'])) { + return new MultipleSelectionTag($attributes); + } + return new SimpleSelectionTag($attributes); + } + + /** + * Factory for input tags. + * @param hash $attributes Element attributes. + * @return SimpleTag Tag object. + * @access protected + */ + protected function createInputTag($attributes) { + if (! isset($attributes['type'])) { + return new SimpleTextTag($attributes); + } + $type = strtolower(trim($attributes['type'])); + $map = array( + 'submit' => 'SimpleSubmitTag', + 'image' => 'SimpleImageSubmitTag', + 'checkbox' => 'SimpleCheckboxTag', + 'radio' => 'SimpleRadioButtonTag', + 'text' => 'SimpleTextTag', + 'hidden' => 'SimpleTextTag', + 'password' => 'SimpleTextTag', + 'file' => 'SimpleUploadTag'); + if (array_key_exists($type, $map)) { + $tag_class = $map[$type]; + return new $tag_class($attributes); + } + return false; + } + + /** + * Make the keys lower case for case insensitive look-ups. + * @param hash $map Hash to convert. + * @return hash Unchanged values, but keys lower case. + * @access private + */ + protected function keysToLowerCase($map) { + $lower = array(); + foreach ($map as $key => $value) { + $lower[strtolower($key)] = $value; + } + return $lower; + } +} + +/** + * HTML or XML tag. + * @package SimpleTest + * @subpackage WebTester + */ +class SimpleTag { + private $name; + private $attributes; + private $content; + + /** + * Starts with a named tag with attributes only. + * @param string $name Tag name. + * @param hash $attributes Attribute names and + * string values. Note that + * the keys must have been + * converted to lower case. + */ + function __construct($name, $attributes) { + $this->name = strtolower(trim($name)); + $this->attributes = $attributes; + $this->content = ''; + } + + /** + * Check to see if the tag can have both start and + * end tags with content in between. + * @return boolean True if content allowed. + * @access public + */ + function expectEndTag() { + return true; + } + + /** + * The current tag should not swallow all content for + * itself as it's searchable page content. Private + * content tags are usually widgets that contain default + * values. + * @return boolean False as content is available + * to other tags by default. + * @access public + */ + function isPrivateContent() { + return false; + } + + /** + * Appends string content to the current content. + * @param string $content Additional text. + * @access public + */ + function addContent($content) { + $this->content .= (string)$content; + return $this; + } + + /** + * Adds an enclosed tag to the content. + * @param SimpleTag $tag New tag. + * @access public + */ + function addTag($tag) { + } + + /** + * Adds multiple enclosed tags to the content. + * @param array List of SimpleTag objects to be added. + */ + function addTags($tags) { + foreach ($tags as $tag) { + $this->addTag($tag); + } + } + + /** + * Accessor for tag name. + * @return string Name of tag. + * @access public + */ + function getTagName() { + return $this->name; + } + + /** + * List of legal child elements. + * @return array List of element names. + * @access public + */ + function getChildElements() { + return array(); + } + + /** + * Accessor for an attribute. + * @param string $label Attribute name. + * @return string Attribute value. + * @access public + */ + function getAttribute($label) { + $label = strtolower($label); + if (! isset($this->attributes[$label])) { + return false; + } + return (string)$this->attributes[$label]; + } + + /** + * Sets an attribute. + * @param string $label Attribute name. + * @return string $value New attribute value. + * @access protected + */ + protected function setAttribute($label, $value) { + $this->attributes[strtolower($label)] = $value; + } + + /** + * Accessor for the whole content so far. + * @return string Content as big raw string. + * @access public + */ + function getContent() { + return $this->content; + } + + /** + * Accessor for content reduced to visible text. Acts + * like a text mode browser, normalising space and + * reducing images to their alt text. + * @return string Content as plain text. + * @access public + */ + function getText() { + return SimplePage::normalise($this->content); + } + + /** + * Test to see if id attribute matches. + * @param string $id ID to test against. + * @return boolean True on match. + * @access public + */ + function isId($id) { + return ($this->getAttribute('id') == $id); + } +} + +/** + * Base url. + * @package SimpleTest + * @subpackage WebTester + */ +class SimpleBaseTag extends SimpleTag { + + /** + * Starts with a named tag with attributes only. + * @param hash $attributes Attribute names and + * string values. + */ + function __construct($attributes) { + parent::__construct('base', $attributes); + } + + /** + * Base tag is not a block tag. + * @return boolean false + * @access public + */ + function expectEndTag() { + return false; + } +} + +/** + * Page title. + * @package SimpleTest + * @subpackage WebTester + */ +class SimpleTitleTag extends SimpleTag { + + /** + * Starts with a named tag with attributes only. + * @param hash $attributes Attribute names and + * string values. + */ + function __construct($attributes) { + parent::__construct('title', $attributes); + } +} + +/** + * Link. + * @package SimpleTest + * @subpackage WebTester + */ +class SimpleAnchorTag extends SimpleTag { + + /** + * Starts with a named tag with attributes only. + * @param hash $attributes Attribute names and + * string values. + */ + function __construct($attributes) { + parent::__construct('a', $attributes); + } + + /** + * Accessor for URL as string. + * @return string Coerced as string. + * @access public + */ + function getHref() { + $url = $this->getAttribute('href'); + if (is_bool($url)) { + $url = ''; + } + return $url; + } +} + +/** + * Form element. + * @package SimpleTest + * @subpackage WebTester + */ +class SimpleWidget extends SimpleTag { + private $value; + private $label; + private $is_set; + + /** + * Starts with a named tag with attributes only. + * @param string $name Tag name. + * @param hash $attributes Attribute names and + * string values. + */ + function __construct($name, $attributes) { + parent::__construct($name, $attributes); + $this->value = false; + $this->label = false; + $this->is_set = false; + } + + /** + * Accessor for name submitted as the key in + * GET/POST privateiables hash. + * @return string Parsed value. + * @access public + */ + function getName() { + return $this->getAttribute('name'); + } + + /** + * Accessor for default value parsed with the tag. + * @return string Parsed value. + * @access public + */ + function getDefault() { + return $this->getAttribute('value'); + } + + /** + * Accessor for currently set value or default if + * none. + * @return string Value set by form or default + * if none. + * @access public + */ + function getValue() { + if (! $this->is_set) { + return $this->getDefault(); + } + return $this->value; + } + + /** + * Sets the current form element value. + * @param string $value New value. + * @return boolean True if allowed. + * @access public + */ + function setValue($value) { + $this->value = $value; + $this->is_set = true; + return true; + } + + /** + * Resets the form element value back to the + * default. + * @access public + */ + function resetValue() { + $this->is_set = false; + } + + /** + * Allows setting of a label externally, say by a + * label tag. + * @param string $label Label to attach. + * @access public + */ + function setLabel($label) { + $this->label = trim($label); + return $this; + } + + /** + * Reads external or internal label. + * @param string $label Label to test. + * @return boolean True is match. + * @access public + */ + function isLabel($label) { + return $this->label == trim($label); + } + + /** + * Dispatches the value into the form encoded packet. + * @param SimpleEncoding $encoding Form packet. + * @access public + */ + function write($encoding) { + if ($this->getName()) { + $encoding->add($this->getName(), $this->getValue()); + } + } +} + +/** + * Text, password and hidden field. + * @package SimpleTest + * @subpackage WebTester + */ +class SimpleTextTag extends SimpleWidget { + + /** + * Starts with a named tag with attributes only. + * @param hash $attributes Attribute names and + * string values. + */ + function __construct($attributes) { + parent::__construct('input', $attributes); + if ($this->getAttribute('value') === false) { + $this->setAttribute('value', ''); + } + } + + /** + * Tag contains no content. + * @return boolean False. + * @access public + */ + function expectEndTag() { + return false; + } + + /** + * Sets the current form element value. Cannot + * change the value of a hidden field. + * @param string $value New value. + * @return boolean True if allowed. + * @access public + */ + function setValue($value) { + if ($this->getAttribute('type') == 'hidden') { + return false; + } + return parent::setValue($value); + } +} + +/** + * Submit button as input tag. + * @package SimpleTest + * @subpackage WebTester + */ +class SimpleSubmitTag extends SimpleWidget { + + /** + * Starts with a named tag with attributes only. + * @param hash $attributes Attribute names and + * string values. + */ + function __construct($attributes) { + parent::__construct('input', $attributes); + if ($this->getAttribute('value') === false) { + $this->setAttribute('value', 'Submit'); + } + } + + /** + * Tag contains no end element. + * @return boolean False. + * @access public + */ + function expectEndTag() { + return false; + } + + /** + * Disables the setting of the button value. + * @param string $value Ignored. + * @return boolean True if allowed. + * @access public + */ + function setValue($value) { + return false; + } + + /** + * Value of browser visible text. + * @return string Visible label. + * @access public + */ + function getLabel() { + return $this->getValue(); + } + + /** + * Test for a label match when searching. + * @param string $label Label to test. + * @return boolean True on match. + * @access public + */ + function isLabel($label) { + return trim($label) == trim($this->getLabel()); + } +} + +/** + * Image button as input tag. + * @package SimpleTest + * @subpackage WebTester + */ +class SimpleImageSubmitTag extends SimpleWidget { + + /** + * Starts with a named tag with attributes only. + * @param hash $attributes Attribute names and + * string values. + */ + function __construct($attributes) { + parent::__construct('input', $attributes); + } + + /** + * Tag contains no end element. + * @return boolean False. + * @access public + */ + function expectEndTag() { + return false; + } + + /** + * Disables the setting of the button value. + * @param string $value Ignored. + * @return boolean True if allowed. + * @access public + */ + function setValue($value) { + return false; + } + + /** + * Value of browser visible text. + * @return string Visible label. + * @access public + */ + function getLabel() { + if ($this->getAttribute('title')) { + return $this->getAttribute('title'); + } + return $this->getAttribute('alt'); + } + + /** + * Test for a label match when searching. + * @param string $label Label to test. + * @return boolean True on match. + * @access public + */ + function isLabel($label) { + return trim($label) == trim($this->getLabel()); + } + + /** + * Dispatches the value into the form encoded packet. + * @param SimpleEncoding $encoding Form packet. + * @param integer $x X coordinate of click. + * @param integer $y Y coordinate of click. + * @access public + */ + function write($encoding, $x = 1, $y = 1) { + if ($this->getName()) { + $encoding->add($this->getName() . '.x', $x); + $encoding->add($this->getName() . '.y', $y); + } else { + $encoding->add('x', $x); + $encoding->add('y', $y); + } + } +} + +/** + * Submit button as button tag. + * @package SimpleTest + * @subpackage WebTester + */ +class SimpleButtonTag extends SimpleWidget { + + /** + * Starts with a named tag with attributes only. + * Defaults are very browser dependent. + * @param hash $attributes Attribute names and + * string values. + */ + function __construct($attributes) { + parent::__construct('button', $attributes); + } + + /** + * Check to see if the tag can have both start and + * end tags with content in between. + * @return boolean True if content allowed. + * @access public + */ + function expectEndTag() { + return true; + } + + /** + * Disables the setting of the button value. + * @param string $value Ignored. + * @return boolean True if allowed. + * @access public + */ + function setValue($value) { + return false; + } + + /** + * Value of browser visible text. + * @return string Visible label. + * @access public + */ + function getLabel() { + return $this->getContent(); + } + + /** + * Test for a label match when searching. + * @param string $label Label to test. + * @return boolean True on match. + * @access public + */ + function isLabel($label) { + return trim($label) == trim($this->getLabel()); + } +} + +/** + * Content tag for text area. + * @package SimpleTest + * @subpackage WebTester + */ +class SimpleTextAreaTag extends SimpleWidget { + + /** + * Starts with a named tag with attributes only. + * @param hash $attributes Attribute names and + * string values. + */ + function __construct($attributes) { + parent::__construct('textarea', $attributes); + } + + /** + * Accessor for starting value. + * @return string Parsed value. + * @access public + */ + function getDefault() { + return $this->wrap(html_entity_decode($this->getContent(), ENT_QUOTES)); + } + + /** + * Applies word wrapping if needed. + * @param string $value New value. + * @return boolean True if allowed. + * @access public + */ + function setValue($value) { + return parent::setValue($this->wrap($value)); + } + + /** + * Test to see if text should be wrapped. + * @return boolean True if wrapping on. + * @access private + */ + function wrapIsEnabled() { + if ($this->getAttribute('cols')) { + $wrap = $this->getAttribute('wrap'); + if (($wrap == 'physical') || ($wrap == 'hard')) { + return true; + } + } + return false; + } + + /** + * Performs the formatting that is peculiar to + * this tag. There is strange behaviour in this + * one, including stripping a leading new line. + * Go figure. I am using Firefox as a guide. + * @param string $text Text to wrap. + * @return string Text wrapped with carriage + * returns and line feeds + * @access private + */ + protected function wrap($text) { + $text = str_replace("\r\r\n", "\r\n", str_replace("\n", "\r\n", $text)); + $text = str_replace("\r\n\n", "\r\n", str_replace("\r", "\r\n", $text)); + if (strncmp($text, "\r\n", strlen("\r\n")) == 0) { + $text = substr($text, strlen("\r\n")); + } + if ($this->wrapIsEnabled()) { + return wordwrap( + $text, + (integer)$this->getAttribute('cols'), + "\r\n"); + } + return $text; + } + + /** + * The content of textarea is not part of the page. + * @return boolean True. + * @access public + */ + function isPrivateContent() { + return true; + } +} + +/** + * File upload widget. + * @package SimpleTest + * @subpackage WebTester + */ +class SimpleUploadTag extends SimpleWidget { + + /** + * Starts with attributes only. + * @param hash $attributes Attribute names and + * string values. + */ + function __construct($attributes) { + parent::__construct('input', $attributes); + } + + /** + * Tag contains no content. + * @return boolean False. + * @access public + */ + function expectEndTag() { + return false; + } + + /** + * Dispatches the value into the form encoded packet. + * @param SimpleEncoding $encoding Form packet. + * @access public + */ + function write($encoding) { + if (! file_exists($this->getValue())) { + return; + } + $encoding->attach( + $this->getName(), + implode('', file($this->getValue())), + basename($this->getValue())); + } +} + +/** + * Drop down widget. + * @package SimpleTest + * @subpackage WebTester + */ +class SimpleSelectionTag extends SimpleWidget { + private $options; + private $choice; + + /** + * Starts with attributes only. + * @param hash $attributes Attribute names and + * string values. + */ + function __construct($attributes) { + parent::__construct('select', $attributes); + $this->options = array(); + $this->choice = false; + } + + /** + * Adds an option tag to a selection field. + * @param SimpleOptionTag $tag New option. + * @access public + */ + function addTag($tag) { + if ($tag->getTagName() == 'option') { + $this->options[] = $tag; + } + } + + /** + * Text within the selection element is ignored. + * @param string $content Ignored. + * @access public + */ + function addContent($content) { + return $this; + } + + /** + * Scans options for defaults. If none, then + * the first option is selected. + * @return string Selected field. + * @access public + */ + function getDefault() { + for ($i = 0, $count = count($this->options); $i < $count; $i++) { + if ($this->options[$i]->getAttribute('selected') !== false) { + return $this->options[$i]->getDefault(); + } + } + if ($count > 0) { + return $this->options[0]->getDefault(); + } + return ''; + } + + /** + * Can only set allowed values. + * @param string $value New choice. + * @return boolean True if allowed. + * @access public + */ + function setValue($value) { + for ($i = 0, $count = count($this->options); $i < $count; $i++) { + if ($this->options[$i]->isValue($value)) { + $this->choice = $i; + return true; + } + } + return false; + } + + /** + * Accessor for current selection value. + * @return string Value attribute or + * content of opton. + * @access public + */ + function getValue() { + if ($this->choice === false) { + return $this->getDefault(); + } + return $this->options[$this->choice]->getValue(); + } +} + +/** + * Drop down widget. + * @package SimpleTest + * @subpackage WebTester + */ +class MultipleSelectionTag extends SimpleWidget { + private $options; + private $values; + + /** + * Starts with attributes only. + * @param hash $attributes Attribute names and + * string values. + */ + function __construct($attributes) { + parent::__construct('select', $attributes); + $this->options = array(); + $this->values = false; + } + + /** + * Adds an option tag to a selection field. + * @param SimpleOptionTag $tag New option. + * @access public + */ + function addTag($tag) { + if ($tag->getTagName() == 'option') { + $this->options[] = &$tag; + } + } + + /** + * Text within the selection element is ignored. + * @param string $content Ignored. + * @access public + */ + function addContent($content) { + return $this; + } + + /** + * Scans options for defaults to populate the + * value array(). + * @return array Selected fields. + * @access public + */ + function getDefault() { + $default = array(); + for ($i = 0, $count = count($this->options); $i < $count; $i++) { + if ($this->options[$i]->getAttribute('selected') !== false) { + $default[] = $this->options[$i]->getDefault(); + } + } + return $default; + } + + /** + * Can only set allowed values. Any illegal value + * will result in a failure, but all correct values + * will be set. + * @param array $desired New choices. + * @return boolean True if all allowed. + * @access public + */ + function setValue($desired) { + $achieved = array(); + foreach ($desired as $value) { + $success = false; + for ($i = 0, $count = count($this->options); $i < $count; $i++) { + if ($this->options[$i]->isValue($value)) { + $achieved[] = $this->options[$i]->getValue(); + $success = true; + break; + } + } + if (! $success) { + return false; + } + } + $this->values = $achieved; + return true; + } + + /** + * Accessor for current selection value. + * @return array List of currently set options. + * @access public + */ + function getValue() { + if ($this->values === false) { + return $this->getDefault(); + } + return $this->values; + } +} + +/** + * Option for selection field. + * @package SimpleTest + * @subpackage WebTester + */ +class SimpleOptionTag extends SimpleWidget { + + /** + * Stashes the attributes. + */ + function __construct($attributes) { + parent::__construct('option', $attributes); + } + + /** + * Does nothing. + * @param string $value Ignored. + * @return boolean Not allowed. + * @access public + */ + function setValue($value) { + return false; + } + + /** + * Test to see if a value matches the option. + * @param string $compare Value to compare with. + * @return boolean True if possible match. + * @access public + */ + function isValue($compare) { + $compare = trim($compare); + if (trim($this->getValue()) == $compare) { + return true; + } + return trim(strip_tags($this->getContent())) == $compare; + } + + /** + * Accessor for starting value. Will be set to + * the option label if no value exists. + * @return string Parsed value. + * @access public + */ + function getDefault() { + if ($this->getAttribute('value') === false) { + return strip_tags($this->getContent()); + } + return $this->getAttribute('value'); + } + + /** + * The content of options is not part of the page. + * @return boolean True. + * @access public + */ + function isPrivateContent() { + return true; + } +} + +/** + * Radio button. + * @package SimpleTest + * @subpackage WebTester + */ +class SimpleRadioButtonTag extends SimpleWidget { + + /** + * Stashes the attributes. + * @param array $attributes Hash of attributes. + */ + function __construct($attributes) { + parent::__construct('input', $attributes); + if ($this->getAttribute('value') === false) { + $this->setAttribute('value', 'on'); + } + } + + /** + * Tag contains no content. + * @return boolean False. + * @access public + */ + function expectEndTag() { + return false; + } + + /** + * The only allowed value sn the one in the + * "value" attribute. + * @param string $value New value. + * @return boolean True if allowed. + * @access public + */ + function setValue($value) { + if ($value === false) { + return parent::setValue($value); + } + if ($value != $this->getAttribute('value')) { + return false; + } + return parent::setValue($value); + } + + /** + * Accessor for starting value. + * @return string Parsed value. + * @access public + */ + function getDefault() { + if ($this->getAttribute('checked') !== false) { + return $this->getAttribute('value'); + } + return false; + } +} + +/** + * Checkbox widget. + * @package SimpleTest + * @subpackage WebTester + */ +class SimpleCheckboxTag extends SimpleWidget { + + /** + * Starts with attributes only. + * @param hash $attributes Attribute names and + * string values. + */ + function __construct($attributes) { + parent::__construct('input', $attributes); + if ($this->getAttribute('value') === false) { + $this->setAttribute('value', 'on'); + } + } + + /** + * Tag contains no content. + * @return boolean False. + * @access public + */ + function expectEndTag() { + return false; + } + + /** + * The only allowed value in the one in the + * "value" attribute. The default for this + * attribute is "on". If this widget is set to + * true, then the usual value will be taken. + * @param string $value New value. + * @return boolean True if allowed. + * @access public + */ + function setValue($value) { + if ($value === false) { + return parent::setValue($value); + } + if ($value === true) { + return parent::setValue($this->getAttribute('value')); + } + if ($value != $this->getAttribute('value')) { + return false; + } + return parent::setValue($value); + } + + /** + * Accessor for starting value. The default + * value is "on". + * @return string Parsed value. + * @access public + */ + function getDefault() { + if ($this->getAttribute('checked') !== false) { + return $this->getAttribute('value'); + } + return false; + } +} + +/** + * A group of multiple widgets with some shared behaviour. + * @package SimpleTest + * @subpackage WebTester + */ +class SimpleTagGroup { + private $widgets = array(); + + /** + * Adds a tag to the group. + * @param SimpleWidget $widget + * @access public + */ + function addWidget($widget) { + $this->widgets[] = $widget; + } + + /** + * Accessor to widget set. + * @return array All widgets. + * @access protected + */ + protected function &getWidgets() { + return $this->widgets; + } + + /** + * Accessor for an attribute. + * @param string $label Attribute name. + * @return boolean Always false. + * @access public + */ + function getAttribute($label) { + return false; + } + + /** + * Fetches the name for the widget from the first + * member. + * @return string Name of widget. + * @access public + */ + function getName() { + if (count($this->widgets) > 0) { + return $this->widgets[0]->getName(); + } + } + + /** + * Scans the widgets for one with the appropriate + * ID field. + * @param string $id ID value to try. + * @return boolean True if matched. + * @access public + */ + function isId($id) { + for ($i = 0, $count = count($this->widgets); $i < $count; $i++) { + if ($this->widgets[$i]->isId($id)) { + return true; + } + } + return false; + } + + /** + * Scans the widgets for one with the appropriate + * attached label. + * @param string $label Attached label to try. + * @return boolean True if matched. + * @access public + */ + function isLabel($label) { + for ($i = 0, $count = count($this->widgets); $i < $count; $i++) { + if ($this->widgets[$i]->isLabel($label)) { + return true; + } + } + return false; + } + + /** + * Dispatches the value into the form encoded packet. + * @param SimpleEncoding $encoding Form packet. + * @access public + */ + function write($encoding) { + $encoding->add($this->getName(), $this->getValue()); + } +} + +/** + * A group of tags with the same name within a form. + * @package SimpleTest + * @subpackage WebTester + */ +class SimpleCheckboxGroup extends SimpleTagGroup { + + /** + * Accessor for current selected widget or false + * if none. + * @return string/array Widget values or false if none. + * @access public + */ + function getValue() { + $values = array(); + $widgets = $this->getWidgets(); + for ($i = 0, $count = count($widgets); $i < $count; $i++) { + if ($widgets[$i]->getValue() !== false) { + $values[] = $widgets[$i]->getValue(); + } + } + return $this->coerceValues($values); + } + + /** + * Accessor for starting value that is active. + * @return string/array Widget values or false if none. + * @access public + */ + function getDefault() { + $values = array(); + $widgets = $this->getWidgets(); + for ($i = 0, $count = count($widgets); $i < $count; $i++) { + if ($widgets[$i]->getDefault() !== false) { + $values[] = $widgets[$i]->getDefault(); + } + } + return $this->coerceValues($values); + } + + /** + * Accessor for current set values. + * @param string/array/boolean $values Either a single string, a + * hash or false for nothing set. + * @return boolean True if all values can be set. + * @access public + */ + function setValue($values) { + $values = $this->makeArray($values); + if (! $this->valuesArePossible($values)) { + return false; + } + $widgets = $this->getWidgets(); + for ($i = 0, $count = count($widgets); $i < $count; $i++) { + $possible = $widgets[$i]->getAttribute('value'); + if (in_array($widgets[$i]->getAttribute('value'), $values)) { + $widgets[$i]->setValue($possible); + } else { + $widgets[$i]->setValue(false); + } + } + return true; + } + + /** + * Tests to see if a possible value set is legal. + * @param string/array/boolean $values Either a single string, a + * hash or false for nothing set. + * @return boolean False if trying to set a + * missing value. + * @access private + */ + protected function valuesArePossible($values) { + $matches = array(); + $widgets = &$this->getWidgets(); + for ($i = 0, $count = count($widgets); $i < $count; $i++) { + $possible = $widgets[$i]->getAttribute('value'); + if (in_array($possible, $values)) { + $matches[] = $possible; + } + } + return ($values == $matches); + } + + /** + * Converts the output to an appropriate format. This means + * that no values is false, a single value is just that + * value and only two or more are contained in an array. + * @param array $values List of values of widgets. + * @return string/array/boolean Expected format for a tag. + * @access private + */ + protected function coerceValues($values) { + if (count($values) == 0) { + return false; + } elseif (count($values) == 1) { + return $values[0]; + } else { + return $values; + } + } + + /** + * Converts false or string into array. The opposite of + * the coercian method. + * @param string/array/boolean $value A single item is converted + * to a one item list. False + * gives an empty list. + * @return array List of values, possibly empty. + * @access private + */ + protected function makeArray($value) { + if ($value === false) { + return array(); + } + if (is_string($value)) { + return array($value); + } + return $value; + } +} + +/** + * A group of tags with the same name within a form. + * Used for radio buttons. + * @package SimpleTest + * @subpackage WebTester + */ +class SimpleRadioGroup extends SimpleTagGroup { + + /** + * Each tag is tried in turn until one is + * successfully set. The others will be + * unchecked if successful. + * @param string $value New value. + * @return boolean True if any allowed. + * @access public + */ + function setValue($value) { + if (! $this->valueIsPossible($value)) { + return false; + } + $index = false; + $widgets = $this->getWidgets(); + for ($i = 0, $count = count($widgets); $i < $count; $i++) { + if (! $widgets[$i]->setValue($value)) { + $widgets[$i]->setValue(false); + } + } + return true; + } + + /** + * Tests to see if a value is allowed. + * @param string Attempted value. + * @return boolean True if a valid value. + * @access private + */ + protected function valueIsPossible($value) { + $widgets = $this->getWidgets(); + for ($i = 0, $count = count($widgets); $i < $count; $i++) { + if ($widgets[$i]->getAttribute('value') == $value) { + return true; + } + } + return false; + } + + /** + * Accessor for current selected widget or false + * if none. + * @return string/boolean Value attribute or + * content of opton. + * @access public + */ + function getValue() { + $widgets = $this->getWidgets(); + for ($i = 0, $count = count($widgets); $i < $count; $i++) { + if ($widgets[$i]->getValue() !== false) { + return $widgets[$i]->getValue(); + } + } + return false; + } + + /** + * Accessor for starting value that is active. + * @return string/boolean Value of first checked + * widget or false if none. + * @access public + */ + function getDefault() { + $widgets = $this->getWidgets(); + for ($i = 0, $count = count($widgets); $i < $count; $i++) { + if ($widgets[$i]->getDefault() !== false) { + return $widgets[$i]->getDefault(); + } + } + return false; + } +} + +/** + * Tag to keep track of labels. + * @package SimpleTest + * @subpackage WebTester + */ +class SimpleLabelTag extends SimpleTag { + + /** + * Starts with a named tag with attributes only. + * @param hash $attributes Attribute names and + * string values. + */ + function __construct($attributes) { + parent::__construct('label', $attributes); + } + + /** + * Access for the ID to attach the label to. + * @return string For attribute. + * @access public + */ + function getFor() { + return $this->getAttribute('for'); + } +} + +/** + * Tag to aid parsing the form. + * @package SimpleTest + * @subpackage WebTester + */ +class SimpleFormTag extends SimpleTag { + + /** + * Starts with a named tag with attributes only. + * @param hash $attributes Attribute names and + * string values. + */ + function __construct($attributes) { + parent::__construct('form', $attributes); + } +} + +/** + * Tag to aid parsing the frames in a page. + * @package SimpleTest + * @subpackage WebTester + */ +class SimpleFrameTag extends SimpleTag { + + /** + * Starts with a named tag with attributes only. + * @param hash $attributes Attribute names and + * string values. + */ + function __construct($attributes) { + parent::__construct('frame', $attributes); + } + + /** + * Tag contains no content. + * @return boolean False. + * @access public + */ + function expectEndTag() { + return false; + } +} +?> \ No newline at end of file diff --git a/code/ryzom/tools/server/www/webtt/vendors/simpletest/test_case.php b/code/ryzom/tools/server/www/webtt/vendors/simpletest/test_case.php new file mode 100644 index 000000000..ba023c3b2 --- /dev/null +++ b/code/ryzom/tools/server/www/webtt/vendors/simpletest/test_case.php @@ -0,0 +1,658 @@ +label = $label; + } + } + + /** + * Accessor for the test name for subclasses. + * @return string Name of the test. + * @access public + */ + function getLabel() { + return $this->label ? $this->label : get_class($this); + } + + /** + * This is a placeholder for skipping tests. In this + * method you place skipIf() and skipUnless() calls to + * set the skipping state. + * @access public + */ + function skip() { + } + + /** + * Will issue a message to the reporter and tell the test + * case to skip if the incoming flag is true. + * @param string $should_skip Condition causing the tests to be skipped. + * @param string $message Text of skip condition. + * @access public + */ + function skipIf($should_skip, $message = '%s') { + if ($should_skip && ! $this->should_skip) { + $this->should_skip = true; + $message = sprintf($message, 'Skipping [' . get_class($this) . ']'); + $this->reporter->paintSkip($message . $this->getAssertionLine()); + } + } + + /** + * Accessor for the private variable $_shoud_skip + * @access public + */ + function shouldSkip() { + return $this->should_skip; + } + + /** + * Will issue a message to the reporter and tell the test + * case to skip if the incoming flag is false. + * @param string $shouldnt_skip Condition causing the tests to be run. + * @param string $message Text of skip condition. + * @access public + */ + function skipUnless($shouldnt_skip, $message = false) { + $this->skipIf(! $shouldnt_skip, $message); + } + + /** + * Used to invoke the single tests. + * @return SimpleInvoker Individual test runner. + * @access public + */ + function createInvoker() { + return new SimpleErrorTrappingInvoker( + new SimpleExceptionTrappingInvoker(new SimpleInvoker($this))); + } + + /** + * Uses reflection to run every method within itself + * starting with the string "test" unless a method + * is specified. + * @param SimpleReporter $reporter Current test reporter. + * @return boolean True if all tests passed. + * @access public + */ + function run($reporter) { + $context = SimpleTest::getContext(); + $context->setTest($this); + $context->setReporter($reporter); + $this->reporter = $reporter; + $started = false; + foreach ($this->getTests() as $method) { + if ($reporter->shouldInvoke($this->getLabel(), $method)) { + $this->skip(); + if ($this->should_skip) { + break; + } + if (! $started) { + $reporter->paintCaseStart($this->getLabel()); + $started = true; + } + $invoker = $this->reporter->createInvoker($this->createInvoker()); + $invoker->before($method); + $invoker->invoke($method); + $invoker->after($method); + } + } + if ($started) { + $reporter->paintCaseEnd($this->getLabel()); + } + unset($this->reporter); + $context->setTest(null); + return $reporter->getStatus(); + } + + /** + * Gets a list of test names. Normally that will + * be all internal methods that start with the + * name "test". This method should be overridden + * if you want a different rule. + * @return array List of test names. + * @access public + */ + function getTests() { + $methods = array(); + foreach (get_class_methods(get_class($this)) as $method) { + if ($this->isTest($method)) { + $methods[] = $method; + } + } + return $methods; + } + + /** + * Tests to see if the method is a test that should + * be run. Currently any method that starts with 'test' + * is a candidate unless it is the constructor. + * @param string $method Method name to try. + * @return boolean True if test method. + * @access protected + */ + protected function isTest($method) { + if (strtolower(substr($method, 0, 4)) == 'test') { + return ! SimpleTestCompatibility::isA($this, strtolower($method)); + } + return false; + } + + /** + * Announces the start of the test. + * @param string $method Test method just started. + * @access public + */ + function before($method) { + $this->reporter->paintMethodStart($method); + $this->observers = array(); + } + + /** + * Sets up unit test wide variables at the start + * of each test method. To be overridden in + * actual user test cases. + * @access public + */ + function setUp() { + } + + /** + * Clears the data set in the setUp() method call. + * To be overridden by the user in actual user test cases. + * @access public + */ + function tearDown() { + } + + /** + * Announces the end of the test. Includes private clean up. + * @param string $method Test method just finished. + * @access public + */ + function after($method) { + for ($i = 0; $i < count($this->observers); $i++) { + $this->observers[$i]->atTestEnd($method, $this); + } + $this->reporter->paintMethodEnd($method); + } + + /** + * Sets up an observer for the test end. + * @param object $observer Must have atTestEnd() + * method. + * @access public + */ + function tell($observer) { + $this->observers[] = &$observer; + } + + /** + * @deprecated + */ + function pass($message = "Pass") { + if (! isset($this->reporter)) { + trigger_error('Can only make assertions within test methods'); + } + $this->reporter->paintPass( + $message . $this->getAssertionLine()); + return true; + } + + /** + * Sends a fail event with a message. + * @param string $message Message to send. + * @access public + */ + function fail($message = "Fail") { + if (! isset($this->reporter)) { + trigger_error('Can only make assertions within test methods'); + } + $this->reporter->paintFail( + $message . $this->getAssertionLine()); + return false; + } + + /** + * Formats a PHP error and dispatches it to the + * reporter. + * @param integer $severity PHP error code. + * @param string $message Text of error. + * @param string $file File error occoured in. + * @param integer $line Line number of error. + * @access public + */ + function error($severity, $message, $file, $line) { + if (! isset($this->reporter)) { + trigger_error('Can only make assertions within test methods'); + } + $this->reporter->paintError( + "Unexpected PHP error [$message] severity [$severity] in [$file line $line]"); + } + + /** + * Formats an exception and dispatches it to the + * reporter. + * @param Exception $exception Object thrown. + * @access public + */ + function exception($exception) { + $this->reporter->paintException($exception); + } + + /** + * For user defined expansion of the available messages. + * @param string $type Tag for sorting the signals. + * @param mixed $payload Extra user specific information. + */ + function signal($type, $payload) { + if (! isset($this->reporter)) { + trigger_error('Can only make assertions within test methods'); + } + $this->reporter->paintSignal($type, $payload); + } + + /** + * Runs an expectation directly, for extending the + * tests with new expectation classes. + * @param SimpleExpectation $expectation Expectation subclass. + * @param mixed $compare Value to compare. + * @param string $message Message to display. + * @return boolean True on pass + * @access public + */ + function assert($expectation, $compare, $message = '%s') { + if ($expectation->test($compare)) { + return $this->pass(sprintf( + $message, + $expectation->overlayMessage($compare, $this->reporter->getDumper()))); + } else { + return $this->fail(sprintf( + $message, + $expectation->overlayMessage($compare, $this->reporter->getDumper()))); + } + } + + /** + * Uses a stack trace to find the line of an assertion. + * @return string Line number of first assert* + * method embedded in format string. + * @access public + */ + function getAssertionLine() { + $trace = new SimpleStackTrace(array('assert', 'expect', 'pass', 'fail', 'skip')); + return $trace->traceMethod(); + } + + /** + * Sends a formatted dump of a variable to the + * test suite for those emergency debugging + * situations. + * @param mixed $variable Variable to display. + * @param string $message Message to display. + * @return mixed The original variable. + * @access public + */ + function dump($variable, $message = false) { + $dumper = $this->reporter->getDumper(); + $formatted = $dumper->dump($variable); + if ($message) { + $formatted = $message . "\n" . $formatted; + } + $this->reporter->paintFormattedMessage($formatted); + return $variable; + } + + /** + * Accessor for the number of subtests including myelf. + * @return integer Number of test cases. + * @access public + */ + function getSize() { + return 1; + } +} + +/** + * Helps to extract test cases automatically from a file. + * @package SimpleTest + * @subpackage UnitTester + */ +class SimpleFileLoader { + + /** + * Builds a test suite from a library of test cases. + * The new suite is composed into this one. + * @param string $test_file File name of library with + * test case classes. + * @return TestSuite The new test suite. + * @access public + */ + function load($test_file) { + $existing_classes = get_declared_classes(); + $existing_globals = get_defined_vars(); + include_once($test_file); + $new_globals = get_defined_vars(); + $this->makeFileVariablesGlobal($existing_globals, $new_globals); + $new_classes = array_diff(get_declared_classes(), $existing_classes); + if (empty($new_classes)) { + $new_classes = $this->scrapeClassesFromFile($test_file); + } + $classes = $this->selectRunnableTests($new_classes); + return $this->createSuiteFromClasses($test_file, $classes); + } + + /** + * Imports new variables into the global namespace. + * @param hash $existing Variables before the file was loaded. + * @param hash $new Variables after the file was loaded. + * @access private + */ + protected function makeFileVariablesGlobal($existing, $new) { + $globals = array_diff(array_keys($new), array_keys($existing)); + foreach ($globals as $global) { + $GLOBALS[$global] = $new[$global]; + } + } + + /** + * Lookup classnames from file contents, in case the + * file may have been included before. + * Note: This is probably too clever by half. Figuring this + * out after a failed test case is going to be tricky for us, + * never mind the user. A test case should not be included + * twice anyway. + * @param string $test_file File name with classes. + * @access private + */ + protected function scrapeClassesFromFile($test_file) { + preg_match_all('~^\s*class\s+(\w+)(\s+(extends|implements)\s+\w+)*\s*\{~mi', + file_get_contents($test_file), + $matches ); + return $matches[1]; + } + + /** + * Calculates the incoming test cases. Skips abstract + * and ignored classes. + * @param array $candidates Candidate classes. + * @return array New classes which are test + * cases that shouldn't be ignored. + * @access public + */ + function selectRunnableTests($candidates) { + $classes = array(); + foreach ($candidates as $class) { + if (TestSuite::getBaseTestCase($class)) { + $reflection = new SimpleReflection($class); + if ($reflection->isAbstract()) { + SimpleTest::ignore($class); + } else { + $classes[] = $class; + } + } + } + return $classes; + } + + /** + * Builds a test suite from a class list. + * @param string $title Title of new group. + * @param array $classes Test classes. + * @return TestSuite Group loaded with the new + * test cases. + * @access public + */ + function createSuiteFromClasses($title, $classes) { + if (count($classes) == 0) { + $suite = new BadTestSuite($title, "No runnable test cases in [$title]"); + return $suite; + } + SimpleTest::ignoreParentsIfIgnored($classes); + $suite = new TestSuite($title); + foreach ($classes as $class) { + if (! SimpleTest::isIgnored($class)) { + $suite->add($class); + } + } + return $suite; + } +} + +/** + * This is a composite test class for combining + * test cases and other RunnableTest classes into + * a group test. + * @package SimpleTest + * @subpackage UnitTester + */ +class TestSuite { + private $label; + private $test_cases; + + /** + * Sets the name of the test suite. + * @param string $label Name sent at the start and end + * of the test. + * @access public + */ + function TestSuite($label = false) { + $this->label = $label; + $this->test_cases = array(); + } + + /** + * Accessor for the test name for subclasses. If the suite + * wraps a single test case the label defaults to the name of that test. + * @return string Name of the test. + * @access public + */ + function getLabel() { + if (! $this->label) { + return ($this->getSize() == 1) ? + get_class($this->test_cases[0]) : get_class($this); + } else { + return $this->label; + } + } + + /** + * Adds a test into the suite by instance or class. The class will + * be instantiated if it's a test suite. + * @param SimpleTestCase $test_case Suite or individual test + * case implementing the + * runnable test interface. + * @access public + */ + function add($test_case) { + if (! is_string($test_case)) { + $this->test_cases[] = $test_case; + } elseif (TestSuite::getBaseTestCase($test_case) == 'testsuite') { + $this->test_cases[] = new $test_case(); + } else { + $this->test_cases[] = $test_case; + } + } + + /** + * Builds a test suite from a library of test cases. + * The new suite is composed into this one. + * @param string $test_file File name of library with + * test case classes. + * @access public + */ + function addFile($test_file) { + $extractor = new SimpleFileLoader(); + $this->add($extractor->load($test_file)); + } + + /** + * Delegates to a visiting collector to add test + * files. + * @param string $path Path to scan from. + * @param SimpleCollector $collector Directory scanner. + * @access public + */ + function collect($path, $collector) { + $collector->collect($this, $path); + } + + /** + * Invokes run() on all of the held test cases, instantiating + * them if necessary. + * @param SimpleReporter $reporter Current test reporter. + * @access public + */ + function run($reporter) { + $reporter->paintGroupStart($this->getLabel(), $this->getSize()); + for ($i = 0, $count = count($this->test_cases); $i < $count; $i++) { + if (is_string($this->test_cases[$i])) { + $class = $this->test_cases[$i]; + $test = new $class(); + $test->run($reporter); + unset($test); + } else { + $this->test_cases[$i]->run($reporter); + } + } + $reporter->paintGroupEnd($this->getLabel()); + return $reporter->getStatus(); + } + + /** + * Number of contained test cases. + * @return integer Total count of cases in the group. + * @access public + */ + function getSize() { + $count = 0; + foreach ($this->test_cases as $case) { + if (is_string($case)) { + if (! SimpleTest::isIgnored($case)) { + $count++; + } + } else { + $count += $case->getSize(); + } + } + return $count; + } + + /** + * Test to see if a class is derived from the + * SimpleTestCase class. + * @param string $class Class name. + * @access public + */ + static function getBaseTestCase($class) { + while ($class = get_parent_class($class)) { + $class = strtolower($class); + if ($class == 'simpletestcase' || $class == 'testsuite') { + return $class; + } + } + return false; + } +} + +/** + * This is a failing group test for when a test suite hasn't + * loaded properly. + * @package SimpleTest + * @subpackage UnitTester + */ +class BadTestSuite { + private $label; + private $error; + + /** + * Sets the name of the test suite and error message. + * @param string $label Name sent at the start and end + * of the test. + * @access public + */ + function BadTestSuite($label, $error) { + $this->label = $label; + $this->error = $error; + } + + /** + * Accessor for the test name for subclasses. + * @return string Name of the test. + * @access public + */ + function getLabel() { + return $this->label; + } + + /** + * Sends a single error to the reporter. + * @param SimpleReporter $reporter Current test reporter. + * @access public + */ + function run($reporter) { + $reporter->paintGroupStart($this->getLabel(), $this->getSize()); + $reporter->paintFail('Bad TestSuite [' . $this->getLabel() . + '] with error [' . $this->error . ']'); + $reporter->paintGroupEnd($this->getLabel()); + return $reporter->getStatus(); + } + + /** + * Number of contained test cases. Always zero. + * @return integer Total count of cases in the group. + * @access public + */ + function getSize() { + return 0; + } +} +?> diff --git a/code/ryzom/tools/server/www/webtt/vendors/simpletest/tidy_parser.php b/code/ryzom/tools/server/www/webtt/vendors/simpletest/tidy_parser.php new file mode 100644 index 000000000..3d8b4b2ac --- /dev/null +++ b/code/ryzom/tools/server/www/webtt/vendors/simpletest/tidy_parser.php @@ -0,0 +1,382 @@ +free(); + } + + /** + * Frees up any references so as to allow the PHP garbage + * collection from unset() to work. + */ + private function free() { + unset($this->page); + $this->forms = array(); + $this->labels = array(); + } + + /** + * This builder is only available if the 'tidy' extension is loaded. + * @return boolean True if available. + */ + function can() { + return extension_loaded('tidy'); + } + + /** + * Reads the raw content the page using HTML Tidy. + * @param $response SimpleHttpResponse Fetched response. + * @return SimplePage Newly parsed page. + */ + function parse($response) { + $this->page = new SimplePage($response); + $tidied = tidy_parse_string($input = $this->insertGuards($response->getContent()), + array('output-xml' => false, 'wrap' => '0', 'indent' => 'no'), + 'latin1'); + $this->walkTree($tidied->html()); + $this->attachLabels($this->widgets_by_id, $this->labels); + $this->page->setForms($this->forms); + $page = $this->page; + $this->free(); + return $page; + } + + /** + * Stops HTMLTidy stripping content that we wish to preserve. + * @param string The raw html. + * @return string The html with guard tags inserted. + */ + private function insertGuards($html) { + return $this->insertEmptyTagGuards($this->insertTextareaSimpleWhitespaceGuards($html)); + } + + /** + * Removes the extra content added during the parse stage + * in order to preserve content we don't want stripped + * out by HTMLTidy. + * @param string The raw html. + * @return string The html with guard tags removed. + */ + private function stripGuards($html) { + return $this->stripTextareaWhitespaceGuards($this->stripEmptyTagGuards($html)); + } + + /** + * HTML tidy strips out empty tags such as