How to Make Dropdown Button

Task To implement a dropdown box with different citation source, description at [Issue #83](PR #521 PR #521 Steps Create dropdown in bootstrap way <div id="dataset-block-wrapper"> <div id="dropdown-div"> <div class="dropdown-box"> <button id="CiteDataset" class="drop-citation-btn dropdown-toggle" type="button" data-toggle="dropdown">Cite Dataset<span class="caret"></span></button> <?php $text = file_get_contents('https://data.datacite.org/text/x-bibliography/10.5524/' . $model->identifier); $clean_text = strip_tags(preg_replace("/&#?[a-z0-9]+;/i", "", $text)); ?> <script> function showText() { var textWindow = window.open(); textWindow.document.write(`<?php echo $clean_text; ?>`); } </script> <ul class="dropdown-menu" aria-labelledby="CiteDataset"> <li><a id="Text" onclick="showText()" target="_blank">Text</a></li> <li><a id="citeRis" href='https://data.datacite.org/application/x-research-info-systems/10.5524/<?php echo $model->identifier;?>' target="_self">RIS</a></li> <li><a id="citeBibTeX" href='https://data.datacite.org/application/x-bibtex/10.5524/<?php echo $model->identifier;?>' target="_self">BibTeX</a></li> </ul> </div> </div> </div> Create dropdown in javascript way <div id="dropdown-div"> <div> <a id="CiteDataset" onclick="showCitation()" class="drop-citation-btn" >Cite Dataset<span class="caret"></span></a> <div id="citationDropdown" class="citation-content"> <?php $text = file_get_contents('https://data.datacite.org/text/x-bibliography/10.5524/' . $model->identifier); $clean_text = strip_tags(preg_replace("/&#?[a-z0-9]+;/i", "", $text)); textWindow.document.write(`<?php echo $clean_text; ?>`); </script> <ul> <li><a id="Text" onclick="showText()" target="_blank">Text</a></li> <li><a id="citeRis" href='https://data.datacite.org/application/x-research-info-systems/10.5524/<?php echo $model->identifier;?>' target="_self">RIS</a></li> <li><a id="citeBibTeX" href='https://data.datacite.org/application/x-bibtex/10.5524/<?php echo $model->identifier;?>' target="_self">BibTeX</a></li> </ul> </div> </div> </div> <script> /* When the user clicks on the button, toggle between hiding and showing the dropdown content */ function showCitation() { document.getElementById("citationDropdown").classList.toggle("show"); } // Close the dropdown if the user clicks outside of it window.onclick = function(event) { if (!event.target.matches('.drop-citation-btn')) { var dropdowns = document.getElementsByClassName("citation-content"); var i; for (i = 0; i < dropdowns.length; i++) { var openDropdown = dropdowns[i]; if (openDropdown.classList.contains('show')) { openDropdown.classList.remove('show'); } } } } //Write the clean text to a new window function showText() { var text = `<?php echo $clean_text; ?>` console.log(text); var textWindow = window.open(); textWindow.document.write(text); } </script> Thoughts Since html comes with bootstrap with default dropdown features, it is better use it, as it is cleaner and less code. But good to know how to implement dropdown in javascript Pass the acceptance test /** * @Then I go to new tab and should see :arg1 */ public function iGoToNewTabAndShouldSee($arg1) { $session = $this->minkContext->getSession(); $numberOfTab = $session->getWindowNames(); if (sizeof($numberOfTab) < 2) { print ("Expected to see at least 2 windows opened."); exit; } $session->switchToWindow($numberOfTab[1]); PHPUnit_Framework_Assert::assertTrue($session->getPage()->hasContent($arg1)); } /** * @When I click :arg1 * To trigger onclick event */ public function iClick($arg1) { $element = $this->minkContext->getSession()->getPage()->find('css', "a[id='$arg1']" ); $element->click(); } @ok @javascript @citation-box Scenario: To see the citation box and and the citation source Given I am not logged in to Gigadb web site And I am on "/dataset/101001" When I press "Cite Dataset" Then I should see "Text" And I should see "RIS" And I should see "BibTeX" @ok @javascript @citation-box Scenario: To show the citation text from CrossCite after clicking the Formatted Text button in the citation box Given I am not logged in to Gigadb web site And I am on "/dataset/101001" And I press "Cite Dataset" When I click "Text" Then I go to new tab and should see "Huang, Y., Li, Y., Burt, D. W., Chen, H., Zhang, Y., Qian, W., Kim, H., Gan, S., Zhao, Y., Li, J., Yi, K., Feng, H., Zhu, P., Li, B., Liu, Q., Fairley, S., Magor, K. E., Du, Z., Hu, X., … Li, N. (2013). Genome sequence of the duck (Anas platyrhynchos) [Data set]. GigaScience Database. https://doi.org/10.5524/101001" @ok @javascript @citation-box Scenario: To get RIS file after clicking the RIS in the citation box Given I am not logged in to Gigadb web site And I am on "/dataset/101001" And I press "Cite Dataset" When I click on the "RIS" button Then the response should contain "101001" # 200: the request completed successfully And the response should contain "200" @ok @javascript @citation-box Scenario: To get BibTeX file after clicking the BibTeX in the citation box Given I am not logged in to Gigadb web site And I am on "/dataset/101001" And I press "Cite Dataset" When I click on the "BibTeX" button Then the response should contain "101001" # 200: the request completed successfully And the response should contain "200" Reference What is Tabnabbing? How to solve it? here ...

May 21, 2021 · 3 min · 626 words · Ken Cho

How to Review Fuw Cicd

PR546 details at here, gist Suggestion from Rija, google doc here’s a suggestion on how to review and merge Me: Rebase the latest change (the “Use CSV file to provide data for test” PR I saw you’ve just merged Peter) You: get the branch deployed and working (all tests passing and deployed to AWS) You: make a list of areas of the codebase that you think was changed or added Me: I’ll add additional/orthogonal areas to the list I think are missing/worth talking about if any ...

May 20, 2021 · 26 min · 5521 words · Ken Cho

Red Hat Enterprise Linux Technical Overview

Course Content What is Linux, Open Source Software, and a Distribution? Introduction to the Shell 2.1 Prompt $: normal user 2.2 Prompt #: root user 2.3 ls: list directory contents 2.4 ls -a 2.5 ls -all 2.6 ls --all 2.7 ls -l file1 dirA 2.8 crontab: maintains crontab files for individual users Kernel and User Spaces, kernel is the heart of Linux operation system 3.1 Process with unique ID User process associate with a particular user, fg and bg Daemon process eg, network services or other house keeping tasks to keep the system running Kernel threads part of the kernel that are running as if they were regular user processes or system daemon, but are not associated with the terminal, they are part of the kernel, but they are still scheduled as if there were regular processes ps: get process information ps -ef: show all process information with detail Orientation to the Graphical User Interface 4.1 GNOME3 ...

May 5, 2021 · 3 min · 561 words · Ken Cho

Why CSS works in Chrome but not Safari?

Observation for PR #521 Safari Chrome After manual add in styles in Safari browser Problem The dropdown button, dropdown box and dropdown list were not wrapped inside a <div></div> <div class="color-background color-background-block dataset-color-background-block"> <p><?= $mainSection->getReleaseDetails()['authors'] ?> (<?=$mainSection->getReleaseDetails()['release_year']?>): <?= $mainSection->getReleaseDetails()['dataset_title'].' '.($mainSection->getReleaseDetails()['publisher'] ?? '<span class="label label-danger">NO PUBLISHER SET</span>').'. '; ?><a href="https://doi.org/10.5524/<?php echo $model->identifier;?>">https://doi.org/10.5524/<?php echo $model->identifier;?></a></p> <p><a class="doi-badge" href="#"><span class="badge">DOI</span><span class="badge">10.5524/<?php echo $model->identifier;?></span></a><button onclick="showCitation()" class="drop-citation-btn" >Cite Dataset<span class="caret"></span></button></p> <div id="citationDropdown" class="citation-content"> <a id="citeText" href='http://data.datacite.org/text/x-bibliography/10.5524/<?php echo $model->identifier;?>' target="_blank">Text</a> <a id="citeRis" href='http://data.datacite.org/application/x-research-info-systems/10.5524/<?php echo $model->identifier;?>' target="_self">RIS</a> <a id="citeBibTeX" href='http://data.datacite.org/application/x-bibtex/10.5524/<?php echo $model->identifier;?>' target="_self">BibTeX</a> </div> </div> Solution Wrap all dropdown stuff inside dataset-block-wrapper <div class="color-background color-background-block dataset-color-background-block"> <p><?= $mainSection->getReleaseDetails()['authors'] ?> (<?=$mainSection->getReleaseDetails()['release_year']?>): <?= $mainSection->getReleaseDetails()['dataset_title'].' '.($mainSection->getReleaseDetails()['publisher'] ?? '<span class="label label-danger">NO PUBLISHER SET</span>').'. '; ?><a href="https://doi.org/10.5524/<?php echo $model->identifier;?>">https://doi.org/10.5524/<?php echo $model->identifier;?></a></p> <div id="dataset-block-wrapper"> <div id="dropdown-div"> <div class="dropdown-box"> <button id="CiteDataset" class="drop-citation-btn dropdown-toggle" type="button" data-toggle="dropdown">Cite Dataset<span class="caret"></span></button> <?php $text = file_get_contents('https://data.datacite.org/text/x-bibliography/10.5524/' . $model->identifier); $clean_text = strip_tags(preg_replace("/&#?[a-z0-9]+;/i", "", $text)); ?> <script> function showText() { var textWindow = window.open(); textWindow.document.write(`<?php echo $clean_text; ?>`); } </script> <ul class="dropdown-menu" aria-labelledby="CiteDataset"> <li><a id="Text" onclick="showText()" target="_blank">Text</a></li> <li><a id="citeRis" href='https://data.datacite.org/application/x-research-info-systems/10.5524/<?php echo $model->identifier;?>' target="_self">RIS</a></li> <li><a id="citeBibTeX" href='https://data.datacite.org/application/x-bibtex/10.5524/<?php echo $model->identifier;?>' target="_self">BibTeX</a></li> </ul> </div> </div> </div> </div> Update the CSS #dropdown-div { margin : 0; float : left ; } .dropdown-box { position: absolute; } .drop-citation-btn { width: 110px; color: white; font-size: 13px; font-weight: normal; border: none; cursor: pointer; background-color: #099242; padding: 5px 10px; border-radius: 4px 4px 4px 4px; display: inline-block; position: relative; text-decoration: none; } .drop-citation-btn:hover { color: white; text-decoration: none; } .drop-citation-btn:focus { outline: none; } #dropdown-div ul { list-style: none; position: relative; float: none; margin-top: 5px; min-width: 100px; border: 1px solid #099242; border-radius: 4px 4px 4px 4px; font-size: 13px; } #dropdown-div li a:hover {background-color: #F3FAF6;} Reference Cross browser testing Handling common HTML and CSS problem ...

March 11, 2021 · 2 min · 284 words · Ken Cho

Add Delete Button for file attribute page

Problem - Add-delete-button-#457 Create Delete button function in the admin file page DatasetLog and CurationLog to log the events. Pass the unit test and acceptance test. How Create Delete button in /view/adminFile/_form.php <td><a role="button" class="btn js-delete" name="delete_file_attr" data="<?= $fa->id ?>">Delete</a></td> </script> $('.js-delete').click(function (e) { e.preventDefault(); id = $(this).attr('data'); row = $('.row-edit-' + id); if (id) { $.post('/adminFile/deleteFileAttribute', { 'id': id }, function(result) { if (result) { // console.log(result); } }, 'json'); } window.location.reload(); }) </script> Create action deleteFileAttribute in AdminFileController.php public function accessRules() { return array( array('allow', // admin only 'actions'=>array('linkFolder','admin','delete','index','view','create','update','update1', 'editAttr', 'uploadAttr', 'deleteFileAttribute'), 'roles'=>array('admin'), ), array('allow', 'actions' => array('create1'), 'users' => array('@'), ), array('allow', // allow all users 'actions' => array('downloadCount'), 'users'=>array('*'), ), array('deny', // deny all users 'users'=>array('*'), ), ); } /** * Yii's method for routing urls to an action. Override to use custom actions */ public function actions() { return array( 'deleteFileAttribute'=>'application.controllers.adminFile.DeleteFileAttributeAction', ); } Create DeleteFileAttributeAction.php in /controllers/adminFile, because AdminFileController.php is very big, so better be implemented in separate class <?php /** * This action will delete file attributes in admin file update page */ class DeleteFileAttributeAction extends CAction { public function run() { if (!Yii::app()->request->isPostRequest) throw new CHttpException(404, "The requested page does not exist."); if (isset($_POST['id'])) { $attribute = FileAttributes::model()->findByPk($_POST['id']); if ($attribute) { $out = $attribute->file->dataset_id; $fileName = $attribute->file->name; $fileModel = get_class($attribute); $fileId = $attribute->file->id; $modelId = $attribute->id; $model = Dataset::model()->findByPk($out); if ($model->upload_status === "Published") { DatasetLog::createDatasetLogEntry($out, $fileName, $fileModel, $modelId, $fileId); } else { CurationLog::createCurationLogEntry($out, $fileName); //Pass in dataset_id returned from File object. } $attribute->delete(); Yii::app()->end(); } } } } Factory method in /protected/models/DatasetLog.php to log Published dataset /** * Factory method to call for common attributes * @param int $id * @param string $fileName * @param string $fileModel * @param int $modelId * @param int $fileId * @return DatasetLog */ public static function makeNewInstanceForDatasetLogBy (int $id, string $fileName, string $fileModel, int $modelId, int $fileId): DatasetLog { $datasetlog = new DatasetLog(); $datasetlog->created_at = date("Y-m-d H:i:s"); $datasetlog->dataset_id = $id; $datasetlog->message = $fileName; $datasetlog->model = $fileModel; $datasetlog->model_id = $modelId; $datasetlog->url = Yii::app()->createUrl('/adminFile/update', array('id'=>$fileId)); return $datasetlog; } /** * Retrieves attributes and store them in dataset_log table when triggered. * @param int $id * @param string $fileName * @param string $fileModel * @param int $modelId * @param int $fileId * @return bool */ public static function createDatasetLogEntry(int $id, string $fileName, string $fileModel, int $modelId, int $fileId): bool { $datasetlog = self::makeNewInstanceForDatasetLogBy($id, $fileName, $fileModel, $modelId, $fileId); $datasetlog->message = $fileName. ": file attribute deleted"; return $datasetlog->save(); } Pass the unit test for datasetLog <?php class DatasetLogTest extends CDbTestCase { public function testDataSetLogEntryFactory() { // With reference to the entry in dataset_log fixture $datasetId = 1; $fileName = "File Tinamus_guttatus.fa.gz"; $fileModel = "File"; $modelId = 16945; $fileId = 16945; //mockup ID $datasetlog = DatasetLog::makeNewInstanceForDatasetLogBy($datasetId, $fileName, $fileModel, $modelId, $fileId); $this->assertNotNull($datasetlog); $this->assertTrue(is_a($datasetlog, DatasetLog::class)); $this->assertEquals($datasetId, $datasetlog->dataset_id); $this->assertEquals($fileName, $datasetlog->message); $this->assertEquals($fileModel, $datasetlog->model); $this->assertEquals($modelId, $datasetlog->model_id); $this->assertEquals("./bin/adminFile/update/id/$fileId", $datasetlog->url); $this->assertTrue($datasetlog->isNewRecord); } // Includde Dataset fixture to avoid unique duplicate key value violation with dataset_log_pkey protected $fixtures=array( 'datasets'=>'Dataset', ); public function testCreateDatasetLogEntry() { $datasetId = 1; $fileName = "File Tinamus_guttatus.fa.gz"; $fileModel = "File"; $modelId = 16945; $fileId = 16945; //mockup ID $saveNewEntry = DatasetLog::createDatasetLogEntry($datasetId, $fileName, $fileModel, $modelId, $fileId); $this->assertTrue(is_bool($saveNewEntry) === true, "bool is returned"); $this->assertTrue(true===$saveNewEntry, "No new entry is saved to dataset log table"); // To assert the delete message will be generated as expected $datasetlog = DatasetLog::model()->findByPk($datasetId); $this->assertEquals("File Tinamus_guttatus.fa.gz: file attribute deleted", $datasetlog->message, "Delete message was generated in different format"); } } Factory method in /protected/models/CurationLog.php to log non Published dataset /** * Factory method to make a new instance and factor out the common code * * @param int $id * @param string $creator * @return CurationLog */ public static function makeNewInstanceForCurationLogBy(int $id, string $creator): CurationLog { $curationlog = new CurationLog(); $curationlog->creation_date = date("Y-m-d"); $curationlog->last_modified_date = null; $curationlog->dataset_id = $id; $curationlog->created_by = $creator; return $curationlog; } public static function createlog($status,$id) { $curationlog = self::makeNewInstanceForCurationLogBy($id, "System"); $curationlog->action = "Status changed to ".$status; return $curationlog->save(); } public static function createlog_assign_curator($id,$creator,$username) { $curationlog = self::makeNewInstanceForCurationLogBy($id, $creator); $curationlog->action = "Curator Assigned"." $username"; return $curationlog->save(); } /** * Retrieves attributes and store them in curation_log table when triggered * @param $id * @param string $fileName * @return bool */ public static function createCurationLogEntry(int $id, string $fileName): bool { $curationlog = self::makeNewInstanceForCurationLogBy($id, "System"); $curationlog->action = $fileName.": file attribute deleted"; return $curationlog->save(); } Pass the unit test for CurationLog <?php class CurationLogTest extends CDbTestCase { public function testMakeNewInstance() { $datasetId = 1; $creator = "System"; $curationLog = CurationLog::makeNewInstanceForCurationLogBy($datasetId, $creator); $this->assertNotNull($curationLog); $this->assertTrue(is_a($curationLog, CurationLog::class)); $this->assertEquals($datasetId, $curationLog->dataset_id); $this->assertEquals($creator, $curationLog->created_by); $this->assertTrue($curationLog->isNewRecord); } } Create I should see a file attribute table in DatasetViewContext.php /** * @Then I should see a file attribute table */ public function iShouldSeeATable(TableNode $table) { foreach ($table as $row) { PHPUnit_Framework_Assert::assertTrue( $this->minkContext->getSession()->getPage()->hasContent($row['Attribute Name']) ); PHPUnit_Framework_Assert::assertTrue( $this->minkContext->getSession()->getPage()->hasContent($row['Value']) ); PHPUnit_Framework_Assert::assertTrue( $this->minkContext->getSession()->getPage()->hasContent($row['Unit']) ); } } Pass the acceptance test @admin-file @issue-457 Feature: A curator can manage file attributes in admin file update page As a curator, I want to manage file attributes from the update form So that I can associate various attributes to files Background: Given Gigadb web site is loaded with production-like data And an admin user exists @ok Scenario: Guest user cannot visit admin file update page Given I am not logged in to Gigadb web site When I go to "/adminFile/update/" Then I should see "Login" @ok Scenario: Go to a published dataset found in production-like database Given I am not logged in to Gigadb web site When I go to "dataset/100056" And I should see "Termitomyces sp. J132 fungus genome assembly data." And I follow "History" Then I should see "History" tab with text "File Termitomyces_assembly_v1.0.fa.gz updated" And I should see "History" tab with text "File Termitomyces_gene_v1.0.cds.fa updated" And I should see "History" tab with text "File Termitomyces_gene_v1.0.cds.fa updated" And I should see "History" tab with text "File Termitomyces_gene_v1.0.gff updated" And I should see "History" tab with text "File Termitomyces_gene_v1.0.gff updated" And I should see "History" tab with text "File Termitomyces_gene_v1.0.pep.fa updated" And I should see "History" tab with text "File Termitomyces_gene_v1.0.pep.fa updated" @ok @Published Scenario: Sign in as admin and visit admin file update page and see New Attribute, Edit, Delete buttons Given I sign in as an admin When I am on "/adminFile/update/id/13973" Then I should see a button "New Attribute" And I should see a file attribute table | Attribute Name | Value | Unit | | last_modified | 2013-7-15 | | And I should see a button input "Edit" And I should see a button input "Delete" @ok @javascript @Published Scenario: Sign in as admin, delete an attribute of a published dataset and check history tab Given I sign in as an admin And I am on "/adminFile/update/id/13973" And I should see "last_modified" When I press "Delete" And I go to "dataset/100056" Then I should see "Termitomyces sp. J132 fungus genome assembly data." And I follow "History" And I should see "History" tab with text "Termitomyces_assembly_v1.0.fa.gz: file attribute deleted" @ok @javascript @Published Scenario: Sign in as admin, no delete button should be seen after delete action has been triggered Given I sign in as an admin And I am on "/adminFile/update/id/13973" And I should see a file attribute table | Attribute Name | Value | Unit | | last_modified | 2013-7-15 | | And I should see a button input "Delete" When I press "Delete" And I wait "3" seconds Then I should not see "last_modified" And I should not see "2013-7-15" And I should not see a button "Delete" @ok @javascript @NonPublished Scenario: Go to a non published dataset found in production-like database, create then delete a keyword attribute Given I sign in as an admin And I am on "/adminFile/update/id/95354" And I should see "test Bauhinia" And I press "Delete" And I should not see "test Bauhinia" #Go to the last page of dataset log When I go to "datasetLog/admin/DatasetLog_page/74" Then I should not see "100245" And I should not see "FCHCGJYBBXX-HKBAUpcgEAACRAAPEI-201_L2_2.fq.gz: file attribute added" And I should not see "FCHCGJYBBXX-HKBAUpcgEAACRAAPEI-201_L2_2.fq.gz: file attribute deleted" Learn Tables relationship dataset file file_attribute id id id identifier dataset_id file_id upload_status value 2.1 Update file_attribute table in data/dev/production_like ...

February 22, 2021 · 9 min · 1895 words · Ken Cho