diff --git a/src/ajax/check_hgvs_dialogue.php b/src/ajax/check_hgvs_dialogue.php new file mode 100644 index 00000000..f2687ae4 --- /dev/null +++ b/src/ajax/check_hgvs_dialogue.php @@ -0,0 +1,610 @@ + + * L. Werkman + * + * + * This file is part of LOVD. + * + * LOVD is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * LOVD is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with LOVD. If not, see . + * + *************/ + +define('ROOT_PATH', '../'); +require ROOT_PATH . 'inc-init.php'; +require ROOT_PATH . 'inc-lib-variants.php'; +header('Content-type: text/javascript; charset=UTF-8'); + + +// Retrieving the transcripts to map to. +// We are using REQUEST and not GET or POST, because the +// input of this script can be both GET and POST. +$aTranscripts = (empty($_REQUEST['transcripts'])? array() : explode('|', urldecode($_REQUEST['transcripts']))); + +// Retrieving the name of the input field. +$sFieldName = urldecode($_REQUEST['fieldName']); + + + +if (!($_REQUEST['var'])) { + // If the variant is empty, we can simply close the script. + exit; +} + + + +// Retrieve the reference sequence from the info given through the URL. +if (strpos($_REQUEST['refSeqInfo'], '-') === false) { + // The '-' serves as a communication tool; it tells us that + // the given input was a GB + chromosome. When no '-' is + // found, we know that the input was the reference sequence + // of a transcript. + $sType = 'VOT'; + $sReferenceSequence = urldecode($_REQUEST['refSeqInfo']); + global $_DB; + $bRefSeqIsSupportedByVV = ( + 'hg' == substr($_DB->query('SELECT id FROM ' . TABLE_GENOME_BUILDS . ' LIMIT 1')->fetchColumn(), 0, 2) + ); + +} else { + // We know we got information on a GB. This is given through + // JS in the format of -. + $sType = 'VOG'; + list($sGenomeBuildID, $sChromosome) = explode('-', urldecode($_REQUEST['refSeqInfo'])); + $sReferenceSequence = ( + !isset($_SETT['human_builds'][$sGenomeBuildID])? + '' : $_SETT['human_builds'][$sGenomeBuildID]['ncbi_sequences'][$sChromosome] + ); + + $bRefSeqIsSupportedByVV = ( + isset($_SETT['human_builds'][$sGenomeBuildID]) && $_SETT['human_builds'][$sGenomeBuildID]['supported_by_VV'] + ); +} + + + +if ($bRefSeqIsSupportedByVV) { + // We want to reset all values if a variant input was changed, + // because we want to keep all validated variants coherent. + // We only do this if the variants can be fully checked by + // VariantValidator, because we can only map those. For variants + // that we cannot map, we can also not automatically create a + // coherent set of variants, and must thus allow the user to + // create this set themselves. + print(' + // Resetting all values. + if ($(\'#variantForm input[name*="VariantOn"]\').hasClass("accept")) { + // If any input in the form is of the class accept(ed), this means + // that these input fields were filled in after full mapping and + // validation of VariantValidator. If then, the script is called + // again, we want to RESET these values, since we do not want to + // risk having incoherent variants in the form simultaneously, + // especially not those we have mapped and validated ourselves. + // Resetting the transcript fields. + var oTranscriptFields = $(\'#variantForm input[name$="VariantOnTranscript/DNA"]\'); + oTranscriptFields.val("").removeClass(); + oTranscriptFields.siblings("img").attr({src: "gfx/trans.png"}); + $(\'#variantForm input[name$="VariantOnTranscript/RNA"]\').val("").removeClass(); + $(\'#variantForm input[name$="VariantOnTranscript/Protein"]\').val("").removeClass(); + + // Resetting the genomic fields. + var oGenomicVariants = $(\'#variantForm input[name^="VariantOnGenome/DNA"]\'); + oGenomicVariants.val("").removeClass(); + oGenomicVariants.siblings("img").attr({src: "gfx/trans.png"}); + } + '); +} + + + +// Preparing the JS for the buttons. +print(' +// Preparing the buttons. +var oButtonYes = {"Yes":function () { + // The user accepts the given fixed variant. + // We will fill in this fixed variant, close the dialogue, + // and perform a new call to this script by activating + // the onChange. + var oInput = $(\'input[name="' . $sFieldName . '"]\'); + oInput.val(decodeURI("' . rawurlencode(lovd_fixHGVS($_REQUEST['var'])) . '")); + $(this).dialog("close"); + oInput.change(); +}}; +var oButtonNo = {"No, I will take a look myself":function () { + // The user does not accept the given fixed variant. + var oInput = $(\'input[name="' . $sFieldName . '"]\'); + oInput.val(decodeURI("' . rawurlencode($_REQUEST['var']) . '")).attr("class", "err"); + oInput.siblings("img:first").attr({src: "gfx/cross.png", title: "Please check the HGVS syntax of your variant description before sending it into the database."}); + $(this).dialog("close"); +}}; +var oButtonOKValid = {"OK":function () { + // The variant was mapped and looks just great! + // All steps have already been taken; the only + // thing left to do is to close the dialogue. + $(this).dialog("close"); +}}; +var oButtonOKInvalid = {"OK":function () { + // The user agrees to change their invalid input manually. + var oInput = $(\'input[name="' . $sFieldName . '"]\'); + oInput.val(decodeURI("' . rawurlencode(substr(strstr($_REQUEST['var'], ':'), 1)) . '")).attr("class", "err"); + oInput.siblings("img:first").attr({src: "gfx/cross.png", title: "Your variant is not validated..."}); + $(this).dialog("close"); +}}; +var oButtonOKCouldBeValid = {"OK":function () { + // We could not validate this variant, but the problem + // lies with us. We will accept this variant and the + // uncertainty that comes with it. + // Just to be sure, we remove the reference sequence here, + // because it might still be stuck to the variant + // description from the mapping process. + var oInput = $(\'input[name="' . $sFieldName . '"]\'); + oInput.val(decodeURI("' . rawurlencode(substr(strstr($_REQUEST['var'], ':'), 1)) . '")).attr("class", "warn"); + oInput.siblings("img:first").attr({src: "gfx/check_orange.png", title: "Your variant could not be (in)validated..."}); + $(this).dialog("close"); +}}; +'); // Fixme; Use lovd_removeRefSeq once the necessary code has been pulled in (from the branch feat/checkHGVSTool) + + +// Create a PHP function to easily update the dialogue. +function update_dialogue($sText, $sButtons = '', $bCleanSlate = false) +{ + // This function fills the variantCheckDialogue with the given + // text, adds the right buttons and sends it to the user. + // If $bCleanSlate, it will remove the old text and start over; + // if !$bCleanSlate, it will append. + print(($bCleanSlate ? ' + // Updating the contents. + $("#variantCheckDialogue").html("' . $sText . '
"); + ' : ' + // Appending to the contents. + $("#variantCheckDialogue").append("' . $sText . '
"); + ')); + + print(($sButtons ? ' + // Placing the buttons. + $("#variantCheckDialogue").dialog({buttons: $.extend({}, ' . $sButtons . ')}); + ' : ' + // Removing buttons. + $("#variantCheckDialogue").dialog({buttons: {}}); + ')); +} + + +// Create a PHP function to easily update the images to the left of each step. +function update_images_per_step($sStep, $sImage) +{ + // This function takes a step, and replaces the image that + // was put next to this step by the given $sImage. + print(' + // Updating one of the status images. + $("#' . $sStep . '").attr({src: "' . $sImage . '"}); + '); +} + + + + + +// Performing initial checks. +if ($_REQUEST['action'] == 'check') { + // Opening the dialogue. + print(' + // Setting up the dialogue. + $("body").append("
"); + $("#variantCheckDialogue").dialog({ + draggable:true,resizable:false,minWidth:600,show:"fade",closeOnEscape:false,hide:"fade",modal:true, + open: function(event, ui) { $(".ui-dialog-titlebar-close").hide(); } + }); + '); + + update_dialogue( + ' Performing initial checks.', + '', + true + ); + + + // Check whether this variant is supported by LOVD. + $aVariant = lovd_getVariantInfo($_REQUEST['var'], false); + $bIsSupportedByLOVD = !isset($aVariant['errors']['ENOTSUPPORTED']); + + if (!$bIsSupportedByLOVD) { + // If the variant is not supported by LOVD, we cannot perform an HGVS check nor the mapping. + // We will notify the user and end the script here. + + update_images_per_step('statusChecks', 'gfx/cross.png'); + update_dialogue( + '
Your variant contains syntax which our HGVS check cannot recognise. ' . + 'Therefore, we cannot validate your variant nor map it to other reference sequences. ' . + 'Please thoroughly validate your variant by hand.', + 'oButtonOKCouldBeValid' + ); + exit; + } + + + // Perform our HGVS check. + if (!lovd_isHGVS($_REQUEST['var'])) { + // If the variant is not HGVS, we cannot send the variant to + // VariantValidator yet. We will try to see if our fixHGVS + // function knows what to do, but if not, we need to exit + // this script and wait for the user to return with a variant + // which we can interpret. + + // Let the user know that the given variant did not pass our HGVS check. + $sResponse = '
Your variant (\"' . htmlspecialchars($_REQUEST['var']) . '\") did not pass our HGVS check.

'; + update_images_per_step('statusChecks', 'gfx/cross.png'); + + + // Show the user the warnings and errors we found through getVariantInfo. + $aVariantIssues = ($aVariant === false ? array() : array_merge(array_values($aVariant['errors']), array_values($aVariant['warnings']))); + + if (!empty($aVariantIssues)) { + $sResponse .= 'We found the following problems:
- '; + $sResponse .= implode('
-', array_map(function($sVariantIssue) { + return addslashes($sVariantIssue); + }, $aVariantIssues)) . '

'; + } + + + // Show the fixed variant if fixHGVS was successful. + $sFixedVariant = lovd_fixHGVS($_REQUEST['var']); + + if ($sFixedVariant !== $_REQUEST['var'] && lovd_isHGVS($sFixedVariant)) { + // Good, we can propose a fix. If the user agrees with the fix, + // we can continue to the mapping. + update_dialogue($sResponse . 'Did you mean \"' . htmlspecialchars($sFixedVariant) . '\"?
', + 'oButtonYes, oButtonNo'); + + // Our 'Yes' button sets the steps in motion which change the user's + // input into the fixed variant, and reactivates the dialogue. + // It is then started from the top. + + } else { + // We could not propose a fix. + update_dialogue($sResponse . 'Please check your variant for errors and try again.
', + 'oButtonOKInvalid'); + } + exit; + } + + + // Check whether VariantValidator supports the syntax of the variant. + $bIsSupportedByVV = + !(isset($aVariant['warnings']['WNOTSUPPORTED']) + || isset($aVariant['messages']['IUNCERTAINPOSITIONS']) + || isset($aVariant['messages']['IPOSTIONRANGE'])); + + if (!$bIsSupportedByVV) { + // If syntax was found which VariantValidator does not support, we + // cannot send the variant in for mapping. We will notify the + // user and exit this script. + update_images_per_step('statusChecks', 'gfx/cross.png'); + update_dialogue( + '
Your variant contains syntax which VariantValidator cannot recognise. ' . + 'Therefore, we cannot map your variant nor validate the positions.', + 'oButtonOKCouldBeValid' + ); + exit; + } + + + if (!$bRefSeqIsSupportedByVV) { + // If the given genome build is not supported by VV, we cannot fully validate + // the variant... We will have to accept these variants into the database + // anyway, since this issue lies with us. + die(' + $("#variantCheckDialogue").dialog("close"); + var oInput = $(\'input[name="' . htmlspecialchars(sFieldName) . '"]\'); + oInput.attr("class", "warn"); + oInput.siblings("img:first").attr({src: "gfx/check_orange.png", title: "We validated the syntax, but could not validate the positions."}); + '); + } + + + // Check if the description itself holds a reference sequence. + // if (lovd_holdsRefSeq($sVariant)) { Fixme; Update line below with this line once the necessary code has been pulled in -> Committed in feat/checkHGVSTool on January 14th 2022; ID 7abf9d70dc3094f5f9cfa0dfc43039c49b4217ff. + if (preg_match('/.*:[a-z]\./', $_REQUEST['var'])) { + // The given variant description holds a reference sequence. + $sRefSeqInDescription = substr($_REQUEST['var'], 0, strpos($_REQUEST['var'], ':')); + + if ($sRefSeqInDescription == $sReferenceSequence) { + // Perfect, no issues found; the user redundantly gave + // the reference sequence in the variant description, + // but that is no problem at all, since the given refSeq + // matches our expectations. The reference sequence will + // be cut from the description after the mapping. + $sFullVariant = $_REQUEST['var']; + + } else { + // The user gave a refSeq within the variant description + // input which does not match our expectations. The variant + // is then likely to be wrong. We cannot accept it. + update_images_per_step('statusChecks', 'gfx/cross.png'); + update_dialogue( + '
The reference sequence given in the input description, does not equal the' . + ' reference sequence matched to the variant by LOVD automatically. Please have' . + ' another look and perhaps try again from a different input field.', + 'oButtonOKInvalid' + ); + exit; + } + + } else { + // The variant in the input field does not hold a reference + // sequence. We will add it to make a full variant that we + // can then send to VariantValidator. + $sFullVariant = $sReferenceSequence . ':' . $_REQUEST['var']; + } + + + // All checks have passed; we are ready for the mapping. + update_images_per_step('statusChecks', 'gfx/check.png'); + update_dialogue(' Mapping your variant.'); + + print(' + $.get("ajax/check_hgvs_dialogue.php?" + + "action=map" + + "&var=' . urlencode($sFullVariant) . '" + + "&fieldName=' . urlencode($sFieldName) . '" + + "&type=' . $sType . '" + + "&refSeqInfo=' . urlencode($_REQUEST['refSeqInfo']) . '" + + "&transcripts=' . urlencode(implode('|', $aTranscripts)) . '" + ).fail(function(){alert("An error occurred while trying to map your variant, please try again later.");$("#variantCheckDialogue").dialog("close");}) + '); +} + + + + + +// Performing the mapping. +if ($_REQUEST['action'] == 'map') { + // Add the source of the variant that will be mapped. + print(' + // Add source. + $(\'#variantForm input[name="source"]\').val("' . ($sType == 'VOT'? $sType : $sGenomeBuildID) . '"); + '); + + // Call VariantValidator. + require ROOT_PATH . 'class/variant_validator.php'; + $_VV = new LOVD_VV(); + $aMappedVariant = ( + $sType == 'VOG' ? + $_VV->verifyGenomic($_REQUEST['var'], array( + 'map_to_transcripts' => !empty($aTranscript), // Should we map the variant to transcripts? + 'predict_protein' => !empty($aTranscript), // Should we get protein predictions? + 'lift_over' => (1 < (int) $_DB->query('SELECT COUNT(*) FROM ' . TABLE_GENOME_BUILDS)->fetchColumn()), // Should we get other genomic mappings of this variant? + 'select_transcripts' => $aTranscripts, + )) : + $_VV->verifyVariant($_REQUEST['var'], array('select_transcripts' => $aTranscripts)) + ); + + // Check for issues on our end. + if ($aMappedVariant === false + || in_array(array_keys($aMappedVariant['errors']), array(array('EBUILD'), array('ESYNTAX')))) { + // If our VV call returned false, or if we found an EBUILD or ESYNTAX + // error, this is an issue that lies with us, not the user. + // We will have to allow these variants into the database. + update_images_per_step('statusMapping', 'gfx/cross.png'); + update_dialogue('
' . + ($aMappedVariant === false? 'An unknown issue occurred while calling VariantValidator.' + : 'This variant type is not supported by VariantValidator.') . + ' Therefore, we could only check the syntax and not perform the mapping.', + 'oButtonOKCouldBeValid' + ); + exit; + } + + + // Check if VariantValidator bumped into any issues. + if (!empty($aMappedVariant['errors'])) { + // The variant holds a fatal issue. We will exit the script and not + // accept this variant into the database. + + update_images_per_step('statusMapping', 'gfx/cross.png'); + update_dialogue( + '
We could not validate nor map your variant because of the following problem(s):
- ' . + implode('
-', $aMappedVariant['errors']) . '

' . + 'Please take another look at your variant and try again.', + 'oButtonOKInvalid' + ); + exit; + } + + // Check for warnings. + if (!empty($aMappedVariant['warnings'])) { + // One or more warnings were found. Perhaps the variant was corrected? + + if (isset($aMappedVariant['warnings']['WROLLBACK']) + || isset($aMappedVariant['warnings']['WCORRECTED'])) { + // The variant was corrected. + update_dialogue('
Your variant was corrected to ' . $aMappedVariant['data']['DNA'] . + ' to fully match HGVS guidelines.'); + $bImprovedByVV = true; + } + + if (isset($aMappedVariant['warnings']['WFLAG'])) { + // This type of warning tells us that VariantValidator had a problem + // which is an issue with them, not us nor our user. We can only get + // the mapping on all genome builds, not on (other) transcripts. + // We will notify the user. + update_dialogue('
Your variant could not fully be validated due to unknown issues.'); + // Fixme; Either find a fix within VV, or Call Mutalyzer. + } + + // Check whether the mapping was successful. + } elseif (!isset($aMappedVariant['data']['DNA']) + || empty($aMappedVariant['data']['DNA'])) { + // Although we did not receive any warnings or errors, the DNA field + // is left empty. This means we have no information on the mapping + // and there is not much we can do... We will inform the user that + // an unknown error occurred and that they should try again later. + update_images_per_step('statusMapping', 'gfx/cross.png'); + update_dialogue( + '
An unknown error occurred while trying to validate and map your variant.' . + ' We are sorry for the inconvenience. Please try again later.', + 'oButtonOKInvalid' + ); + exit; + } + + + // When sending in a variant on transcript, VariantValidator only + // returns the variant as mapped on that one transcript. If we are + // on a VOT creation form, and there are multiple transcripts open, + // we want each transcript to get a mapping. To get this, we then + // need to call VariantValidator a second time using one of the + // genomic variants as were returned using our first call. + if ($sType == 'VOT' && count($aTranscripts) > 1) { + + $aMappedViaGB = ( + !isset($aMappedVariant['data']['genomic_mappings']['hg38']) ? // Yes=We have a genomic reference from our first call; No=We don't have a genomic reference. + array() : + $_VV->verifyGenomic($aMappedVariant['data']['genomic_mappings']['hg38'], array( + 'map_to_transcripts' => true, // Should we map the variant to transcripts? + 'predict_protein' => true, // Should we get protein predictions? + 'lift_over' => false, // Should we get other genomic mappings of this variant? + 'select_transcripts' => array_diff($aTranscripts, array($sReferenceSequence)), // Which transcripts do we want to map to? + )) + ); + + if (!isset($aMappedViaGB['data']['transcript_mappings'])) { + // If for any reason no new transcript mappings were given, + // we cannot perform this extra step, and will thus miss + // some information. We will inform the user. + update_dialogue('
Your variant could not be mapped to all transcripts due to unknown issues.'); + } + + $aMappedVariant['data']['transcript_mappings'] = $aMappedViaGB['data']['transcript_mappings']; + + unset($aMappedViaGB); // We don't need the rest of this information. + } + + // We have the mapping data and can now send it to the input fields. + + // Save the ['data']['DNA'] variant to the right type of mapping to + // easily add it into the right fields later. + if ($sType == 'VOT') { + // If the input type was a variant on transcript, the ['data']['DNA'] + // field holds information on a transcript mapping. + $aMappedVariant['data']['transcript_mappings'][$sReferenceSequence] = $aMappedVariant['data']; + } else { + // If the input was not a VOT, it was a genomic variant, meaning we + // should add the information into the genomic mappings. + $aMappedVariant['data']['genomic_mappings'][$sGenomeBuildID] = $aMappedVariant['data']['DNA']; + } + + // Returning the mapping for transcript, RNA and protein variants. + foreach ($aMappedVariant['data']['transcript_mappings'] as $sTranscript => $aTranscriptData) { + // Filling in the input fields. + print(' + // Adding transcript info to the fields. + var oTranscriptField = $("input").filter(function() { + return $(this).data("id_ncbi") == "' . $sTranscript . '" + }); + + if (!oTranscriptField.prop("disabled")) { + oTranscriptField.val("' . $aTranscriptData['DNA'] . '").attr("class", "accept");; + oTranscriptField.siblings("img:first").attr({src: "gfx/check.png", title: "Validated"}); + var sBaseOfFieldName = oTranscriptField.attr("name").substring(0, oTranscriptField.attr("name").indexOf("DNA")); + $(\'#variantForm input[name$="\' + sBaseOfFieldName + "RNA" + \'"]\').val("' . $aTranscriptData['RNA'] . '").attr("class", "accept"); + $(\'#variantForm input[name$="\' + sBaseOfFieldName + "Protein" + \'"]\').val("' . $aTranscriptData['protein'] . '").attr("class", "accept"); + }'); + } + + // Returning the mapping for genomic variants. + foreach ($aMappedVariant['data']['genomic_mappings'] as $sGBID => $aMappedGenomicVariant) { + if (is_string($aMappedGenomicVariant)) { + // The variant is a string. We don't need to make any edits. + $sMappedGenomicVariant = $aMappedGenomicVariant; + + } elseif (count($aMappedGenomicVariant) == 1) { + // The variant is formatted as an array, since multiple variants were + // possible. However, only one variant was found. We can simply take + // the first element. + $sMappedGenomicVariant = $aMappedGenomicVariant[0]; + + } else { + // Multiple possible variants were found. We will inform the user, + // and concatenate the variants similarly to the example below: + // NC_1233456.1:g.1del + NC_123456.1:g.2_3del + NC_123456.1:g.4del = + // NC_123456.1:g.1del^2_3del^4del. + update_dialogue('
There were multiple genomic variant predictions for build ' . $sGBID . '.'); + + $sMappedGenomicVariant = + preg_replace('/(.*:[a-z]\.).*/', '', $aMappedGenomicVariant[0]) . + implode('^', + array_map(function ($sFullVariant) { + return preg_replace('/.*:[a-z]\./', '', $sFullVariant); + }, $aMappedGenomicVariant) + ); + } + + // Removing the reference sequence. + $sMappedGenomicVariant = preg_replace('/.*:/', '', $sMappedGenomicVariant); // Fixme; Find a cleaner way of cutting off the reference sequence. + + // Filling in the input field. + print(' + // Adding genomic info the fields. + var oGenomicField = $("input").filter(function() { + return $(this).data("genomeBuild") == "' . $sGBID . '" + }); + oGenomicField.val("' . $sMappedGenomicVariant . '").attr("class", "accept"); + oGenomicField.siblings("img:first").attr({src: "gfx/check.png", title: "Validated"}); + '); + } + + + // Fill and deactivate all fields that remained empty. + // Some fields might not have been filled after the mapping. Some + // unknown issues have occurred here, most likely concerning the + // reference sequence. Because we want to allow users to fill in + // these fields without that resulting in a reset of all values, + // we will deactivate the onChanges for these fields and warn the + // user. + print(' + // Fill in all fields that remained empty. + $(\'#variantForm input[name*="VariantOn"]\').each(function(e){ + sName = $(this).attr("name"); + if ($(this).val() === "" + && (sName.includes("DNA") || sName.endsWith("RNA") || sName.endsWith("Protein"))) { + if (sName.includes("Genome")) { + $(this).val("g.?"); + } else { + $(this).val((sName.endsWith("DNA")? "c" : (sName.endsWith("RNA")? "r" : "p")) + ".?"); + } + $(this).off("change").attr("class", "warn"); + $(this).siblings("img:first").attr({src: "gfx/check_orange.png", title: "Variant mapping failed! The HGVS check of this field is turned off to allow changes to be made freely. To turn the checks back on, refresh the page."}); + } + }); + '); + + // Send final message to the user. + update_images_per_step('statusMapping', 'gfx/check.png'); + update_dialogue( + '
Your variant was successfully mapped' . (!isset($bImprovedByVV) ? '' : ', improved') . + ' and validated by VariantValidator. Thank you for your patience!', + 'oButtonOKValid' + ); +} +?> diff --git a/src/ajax/mobidetails.php b/src/ajax/mobidetails.php index 062692e8..a9a5f771 100644 --- a/src/ajax/mobidetails.php +++ b/src/ajax/mobidetails.php @@ -111,10 +111,14 @@ $_SESSION['csrf_tokens']['mobidetails_confirm'] = md5(uniqid()); $sFormConfirmation = str_replace('{{CSRF_TOKEN}}', $_SESSION['csrf_tokens']['mobidetails_confirm'], $sFormConfirmation); + // This print statement and flush do not work. + // It seems that flush successfully forces the output + // to the browser, but the browser does not seem to + // execute the JS until the page has finished loading. (Chrome) print(' $("#mobidetails_dialog").html("\'Please"); '); - ob_end_flush(); + @ob_end_flush(); flush(); // Now check with MobiDetails. diff --git a/src/class/object_custom.php b/src/class/object_custom.php index 23fc8e68..90afcc03 100644 --- a/src/class/object_custom.php +++ b/src/class/object_custom.php @@ -299,6 +299,12 @@ function buildForm ($sPrefix = '') $aFormData[$sPrefix . $sCol] = $aEntry; } + // The element data will be passed on, so that viewForm() can make sure it will be added to the HTML. + // NOTE: Element data is not stored in the database, but added by, for instance, getForm(). + if (!empty($aCol['element_data'])) { + $aFormData[$sPrefix . $sCol][] = $aCol['element_data']; + } + // Any custom links we want to mention? if (!empty($aCol['custom_links'])) { $sLinks = ''; diff --git a/src/class/object_genome_builds.php b/src/class/object_genome_builds.php index ef5e32f9..53f16d35 100644 --- a/src/class/object_genome_builds.php +++ b/src/class/object_genome_builds.php @@ -123,7 +123,7 @@ function prepareData ($zData = '', $sView = 'list') $sDNAColumn = 'VariantOnGenome/DNA' . (!$zData['column_suffix']? '' : '/') . $zData['column_suffix']; $nPercentComplete = (int) $_DB->query( 'SELECT ROUND( - (SELECT COUNT(*) FROM ' . TABLE_VARIANTS. ' + (SELECT COUNT(*) FROM ' . TABLE_VARIANTS . ' WHERE `' . $sDNAColumn . '` IS NOT NULL AND `' . $sDNAColumn . '` != "") / ( SELECT COUNT(*) FROM ' . TABLE_VARIANTS . ') * 100)')->fetchColumn(); diff --git a/src/class/object_genome_variants.php b/src/class/object_genome_variants.php index 200417ef..6bb2b4d0 100644 --- a/src/class/object_genome_variants.php +++ b/src/class/object_genome_variants.php @@ -222,20 +222,6 @@ function __construct () - function buildForm ($sPrefix = '') - { - $aForm = parent::buildForm($sPrefix); - // Link to HGVS for nomenclature. - if (isset($aForm[$sPrefix . 'VariantOnGenome/DNA'])) { - $aForm[$sPrefix . 'VariantOnGenome/DNA'][0] = str_replace('(HGVS format)', '(HGVS format)', $aForm[$sPrefix . 'VariantOnGenome/DNA'][0]); - } - return $aForm; - } - - - - - function checkFields ($aData, $zData = false, $aOptions = array()) { global $_AUTH, $_SETT; @@ -268,6 +254,26 @@ function checkFields ($aData, $zData = false, $aOptions = array()) } } + foreach ($aData as $sField => $sVariant) { + if (strpos($sField, 'DNA') !== false) { + // We want to check the input of all DNA fields: are these variant + // descriptions indeed cleanly formatted? And if our check seems + // to fail, is this perhaps because it holds syntax that we do + // not support? If we DO support the syntax but the variant does + // not seem to be HGVS, we will send an error. + if (lovd_isHGVS($sVariant)) { + // The variant looks good! + continue; + } + $aVariantInfo = lovd_getVariantInfo($sVariant, false); + if (array_diff(array_keys($aVariantInfo['errors']), array('ENOTSUPPORTED')) // Are there any errors other than ENOTSUPPORTED? + || array_diff(array_keys($aVariantInfo['warnings']), array('WNOTSUPPORTED'))) { // Are there any warnings other than WNOTSUPPORTED? + // There are problems that are not caused by lack of syntax support. + lovd_errorAdd($sField, 'The variant ' . $sVariant . ' did not pass our checks. Please take another look and try again.'); + } + } + } + // Do this before running checkFields so that we have time to predict the DBID and fill it in. if (!empty($aData['VariantOnGenome/DNA']) // DNA filled in. && isset($this->aColumns['VariantOnGenome/DBID']) // DBID column active. @@ -351,9 +357,15 @@ function getForm () } } - // Add genome build name to VOG/DNA field. - $this->aColumns['VariantOnGenome/DNA']['description_form'] = 'Relative to ' . $_CONF['refseq_build'] . ' / ' . $_SETT['human_builds'][$_CONF['refseq_build']]['ncbi_name'] . '.' . - (!$this->aColumns['VariantOnGenome/DNA']['description_form']? '' : '
' . $this->aColumns['VariantOnGenome/DNA']['description_form']); + // Add genome build name and element data to VOG/DNA fields, and add in the link to the HGVS website. + $aActiveBuilds = $_DB->query('SELECT id, name, column_suffix FROM ' . TABLE_GENOME_BUILDS)->fetchAllGroupAssoc(); + foreach ($aActiveBuilds as $sBuild => $aBuild) { + $sColumn = 'VariantOnGenome/DNA' . (!$aBuild['column_suffix']? '' : '/' . $aBuild['column_suffix']); + $this->aColumns[$sColumn]['description_form'] = 'Relative to ' . $aBuild['name'] . '.' . + (!$this->aColumns[$sColumn]['description_form']? '' : '
' . $this->aColumns[$sColumn]['description_form']); + $this->aColumns[$sColumn]['element_data'] = array('genome_build' => $sBuild); + $this->aColumns[$sColumn]['form_type'][0] = str_replace('(HGVS format)', '(HGVS format)', $this->aColumns[$sColumn]['form_type'][0]); + } // FIXME; right now two blocks in this array are put in, and optionally removed later. However, the if() above can build an entire block, such that one of the two big unset()s can be removed. // A similar if() to create the "authorization" block, or possibly an if() in the building of this form array, is easier to understand and more efficient. diff --git a/src/class/variant_validator.php b/src/class/variant_validator.php index 12f71173..2247ac8b 100644 --- a/src/class/variant_validator.php +++ b/src/class/variant_validator.php @@ -882,7 +882,7 @@ public function verifyVariant ($sVariant, $aOptions = array()) // NM, we end up with only one NM here. $aJSON = current($aJSON); - // Add a warning in case we submitted a intronic variant while not + // Add a warning in case we submitted an intronic variant while not // using an NC reference sequence. if (preg_match('/^N[MR]_.+[0-9]+[+-][0-9]+/', $sVariant)) { $aData['warnings']['WINTRONICWITHOUTNC'] = 'Without using a genomic reference sequence, intronic bases can not be verified.' . diff --git a/src/inc-init.php b/src/inc-init.php index 76118a91..141aef6b 100644 --- a/src/inc-init.php +++ b/src/inc-init.php @@ -360,6 +360,7 @@ 'hg18' => array( 'ncbi_name' => 'Build 36.1', + 'supported_by_VV' => false, // FIXME: This information is also stored in the chromosomes table. // Remove it from here? 'ncbi_sequences' => @@ -394,6 +395,7 @@ 'hg19' => array( 'ncbi_name' => 'GRCh37', + 'supported_by_VV' => true, // FIXME: This information is also stored in the chromosomes table. // Remove it from here? 'ncbi_sequences' => @@ -429,6 +431,7 @@ 'hg38' => array( 'ncbi_name' => 'GRCh38', + 'supported_by_VV' => true, // FIXME: This information is also stored in the chromosomes table. // Remove it from here? 'ncbi_sequences' => diff --git a/src/inc-js-variants.php b/src/inc-js-variants.php index 42625925..1fe67ba9 100644 --- a/src/inc-js-variants.php +++ b/src/inc-js-variants.php @@ -42,120 +42,52 @@ define('AJAX_NO_AUTH', '8'); define('AJAX_DATA_ERROR', '9'); -$_SETT = array('objectid_length' => array('transcripts' => 8)); +$_SETT = array( + 'objectid_length' => array('transcripts' => 8), + 'variant_validator' => array( + 'genome_builds' => array('hg19', 'hg38') + ), +); ?> -function lovd_checkHGVS (e) -{ - // Function that is being called everytime a change has been made to a DNA field, - // either from an onKeyUp or onChange, although the onKeyUp only uses this function partially. - // This will run the Mutalyzer checkHGVS module (if needed) and will return the response to the user. - - var oVariantDNA = $(this); - oVariantDNA.removeClass(); - - // If we're a "preliminary" trigger, actually run when a key has been pressed, we just want a quick check - // if the DNA field seems correct. If so, we show the mark and the buttons, just like a "real" onChange(). - // However, when it doesn't look good, we don't request Mutalyzer (to confirm, they should know best) - // unless we're a "real" onChange() request. - - var bHGVS; // True -> correct syntax; False -> We don't recognize it, but Mutalyzer might. - // First check: genomic field should start with g. or m., cDNA field should start with c. or n.. - if (oVariantDNA.attr('name') == 'VariantOnGenome/DNA' && !/^(g|m)\./.test(oVariantDNA.val().substring(0, 2))) { - bHGVS = false; - } else if (oVariantDNA.attr('name') != 'VariantOnGenome/DNA' && !/^(c|n)\./.test(oVariantDNA.val().substring(0, 2))) { - bHGVS = false; - } else { - // Try to match simple stuff: deletions, duplications, insertions, inversions and substitutions. - var oRegExp = /^[cgmn]\.\-?\d+([-+]\d+)?([ACGT]>[ACGT]|(_\-?\d+([-+]\d+)?)?d(el|up)([ACGT])*|_\-?\d+([-+]\d+)?(inv|ins([ACGT])+))$/; - // "false" doesn't necessarily mean false here! Just means this check doesn't recognize it. Mutalyzer may still. - bHGVS = (oRegExp.test(oVariantDNA.val())); - } - - // Grab the corresponding protein description field if it exists. - var oProtein = $(oVariantDNA).parent().parent().siblings().find('input[name="' + $(oVariantDNA).attr('name').substring(0, ) + '_VariantOnTranscript/Protein"]'); - // Add a transparent placeholder for the indicator at the protein field, so that the form will not shift when it is added. - oProtein.siblings('img:first').removeClass().attr('src', 'gfx/trans.png'); - if (e.type == 'change' && !bHGVS && oVariantDNA.val()) { - // This is a "real" onChange call(), we couldn't match the variant, but we do have something filled in. Check with Mutalyzer! - if (oVariantDNA.attr('name') == 'VariantOnGenome/DNA') { - var sVariantNotation = 'g:' + oVariantDNA.val(); // The actual chromosome is not important, it's just the variant syntax that matters here. - } else { - var sVariantNotation = 'c:' + oVariantDNA.val(); // The actual transcript is not important, it's just the variant syntax that matters here. - } - - // Now we have to check with Mutalyzer... - $(oVariantDNA).siblings('img:first').attr({ - src: 'gfx/lovd_loading.gif', - alt: 'Loading...', - title: 'Loading...', - className: '', - onmouseover: '', - onmouseout: '' - }).show(); - - // Make the call to Mutalyzer to see if the variant is correct HGVS. - $.get('ajax/check_hgvs.php', { variant: sVariantNotation }, - function(sData) { - if (sData != '') { - // Either Mutalyzer says No, our regexp didn't find a c. or g. at the beginning or user lost $_AUTH. - oVariantDNA.siblings('img:first').attr({ - src: 'gfx/cross.png', - alt: (sData == ? 'Unexpected response from Mutalyzer. Please try again later.' : 'Not a valid HGVS syntax!'), - title: (sData == ? 'Unexpected response from Mutalyzer. Please try again later.' : 'Not a valid HGVS syntax!'), - }).show(); - // Now hide the "Map variant" and "Predict" buttons. - if (!$.isEmptyObject(aTranscripts)) { - oVariantDNA.siblings('button:eq(0)').hide(); - oProtein.siblings('button:eq(0)').hide(); - } - } else { - oVariantDNA.siblings('img:first').attr({ - src: 'gfx/check.png', - alt: 'Valid HGVS syntax!', - title: 'Valid HGVS syntax!' - }).show(); - // Check if the variant description is a c.? or a g.?. If it is, then do not let the user map the variant. - if (oVariantDNA.val().substring(1,3) == '.?') { - oVariantDNA.siblings('button:eq(0)').hide(); - oProtein.siblings('button:eq(0)').hide(); - } else if (!$.isEmptyObject(aTranscripts)) { - // Only enable the mapping buttons when there are transcripts added to this variant. - oVariantDNA.siblings('button:eq(0)').show(); - oProtein.siblings('button:eq(0)').show(); - // Hide possible 'view prediction button' - $('#' + jq_escape(oProtein.attr('name')) + '_view_prediction').remove(); - } - } - }); - - } else if (bHGVS) { - // We didn't need Mutalyzer, and we know we've got a good-looking variant here. - oVariantDNA.siblings('img:first').attr({ - src: 'gfx/check.png', - alt: 'Valid HGVS syntax!', - title: 'Valid HGVS syntax!' - }).show(); - if (!$.isEmptyObject(aTranscripts)) { - // Only enable the mapping buttons when there are transcripts added to this variant. - oVariantDNA.siblings('button:eq(0)').show(); - oProtein.siblings('button:eq(0)').show(); - // Hide possible 'view prediction button' - $('#' + jq_escape(oProtein.attr('name')) + '_view_prediction').remove(); - } - } else { - // No HGVS syntax, but no "real" onChange trigger yet, either. - oVariantDNA.siblings('img:first').hide(); - if (!$.isEmptyObject(aTranscripts)) { - oVariantDNA.siblings('button:eq(0)').hide(); - oProtein.siblings('button:eq(0)').hide(); - } - } - return false; +function lovd_checkHGVS(e) +{ + // This function should be called from any DNA variant input field + // to check the HGVS of the given value. It sends the input (and + // all other relevant data on the form) to + // ajax/check_hgvs_dialogue.php. This script will then perform + // the actual checks and return mapping information if possible. + + var sVariant = $(this).val(); + var sFieldName = $(this).attr("name"); + var oChromosome = $('select[name="chromosome"]'); + var sChromosome = ( + oChromosome.length ? // Yes=VOG form; No=VOT form. + oChromosome.val() : + $("td:contains('Chromosome')").last().filter(function () { + return $(this).html() === "Chromosome"; + }).siblings().eq(1).html() + ); + var sRefSeqInfo = ( + sFieldName[0] !== 'V'? // Yes=RefSeq is a transcript; No=RefSeq is genomic. + $(this).data('id_ncbi') : + $(this).data('genomeBuild') + '-' + sChromosome + ); + var sTranscripts = $($('#variantForm input[name$="_VariantOnTranscript/DNA"]')).map(function(){ + return $(this).data('id_ncbi'); + }).get().join('|'); + + $.get("ajax/check_hgvs_dialogue.php?" + + "action=check" + + "&var=" + encodeURIComponent(sVariant) + + "&fieldName=" + encodeURIComponent(sFieldName) + + "&refSeqInfo=" + encodeURIComponent(sRefSeqInfo) + + "&transcripts=" + encodeURIComponent(sTranscripts) + ).fail(function(){alert("An error occurred while checking your variant, please try again later.");$("#variantCheckDialogue").dialog("close");}); } @@ -186,11 +118,11 @@ function lovd_convertPosition (oElement) if (oThisDNA.attr("name").indexOf("VariantOnTranscript") >= 0) { sSource = "VOT"; } else { - pos = oThisDNA.attr("name").lastIndexOf("/"); - sSource = oThisDNA.attr("name").substr(pos + 1); + sSource = oThisDNA.data('genomeBuild'); } oVariantSource.val(sSource); } + var oAllDNA = $('input[name$="_VariantOnTranscript/DNA"]'); $(oAllDNA).removeClass().siblings('img:first').attr({ src: 'gfx/trans.png', @@ -200,12 +132,14 @@ className: '', onmouseover: '', onmouseout: '' }).show(); + var oAllProteins = $('input[name$="_VariantOnTranscript/Protein"]'); $(oAllProteins).siblings('img:first').attr({ src: 'gfx/trans.png', alt: '', title: '' }).show(); + $(oThisDNA).siblings('img:first').attr({ src: 'gfx/lovd_loading.gif', alt: 'Loading...', @@ -215,9 +149,17 @@ className: '', onmouseout: '' }).show(); - if (oThisDNA.attr('name') == 'VariantOnGenome/DNA') { + if (oThisDNA.filter("[name^='VariantOnGenome/DNA']").size()) { // This function was called from the genomic variant, so build a list of genes and prepare the variant accordingly for mutalyzer. - var sVariantNotation = 'chr:' + oThisDNA.val(); + var oChromosome = $('select[name="chromosome"]'); + var sChromosome = ( + oChromosome.length ? // Yes=VOG form; No=VOT form. + oChromosome.val() : + $("td:contains('Chromosome')").last().filter(function () { + return $(this).html() === "Chromosome"; + }).siblings().eq(1).html() + ); + var sVariantNotation = 'chr' + sChromosome + ':' + oThisDNA.val(); var aGenes = []; for (nTranscriptID in aTranscripts) { if ($.inArray(aTranscripts[nTranscriptID][1], aGenes) == -1) { @@ -239,14 +181,16 @@ className: '', $.get('ajax/convert_position.php', { variant: sVariantNotation, gene: sGene }, function(sData) { if (sData != '' && sData != '' && sData != '') { - if (oThisDNA.attr('name') == 'VariantOnGenome/DNA') { + if (oThisDNA.filter("[name^='VariantOnGenome/DNA']").size()) { // This function was called from the genomic variant, so fill in the return values from mutalyzer in the transcript DNA fields. aVariants = sData.split(';'); var nVariants = aVariants.length; for (i = 0; i < nVariants; i++) { var aVariant = /^([A-Z]{2}_\d{6,9}\.\d{1,2}(?:\([A-Z0-9]+_v\d{3}\))?):([cn]\..+)$/.exec(aVariants[i]); if (aVariant != null) { - var oInput = $('#variantForm input[id_ncbi="' + aVariant[1] + '"]'); + var oInput = $("input").filter(function() { + return $(this).data("id_ncbi") === aVariant[1]; + }); if (oInput[0] != undefined) { // If the transcript returned by mutalyzer is present in the form, fill in the respons from mutalyzer. oInput.val(aVariant[2]); @@ -515,44 +459,47 @@ function lovd_highlightInput (oElement) $(function () { - var oGenomicVariant = $('#variantForm input[name="VariantOnGenome/DNA"]'); + var oGenomicVariants = $('#variantForm input[name^="VariantOnGenome/DNA"]'); var oTranscriptVariants = $('#variantForm input[name$="_VariantOnTranscript/DNA"]'); // Add the button and image at the end of the genomic DNA field. - oGenomicVariant.parent().append('   '); + oGenomicVariants.parent().append('   '); // Add an onChange event that runs lovd_checkHGVS. - oGenomicVariant.change(lovd_checkHGVS); - // Add same function to the onKeyUp event, but then it will check itself if the variant is likely to be complete. - oGenomicVariant.keyup(lovd_checkHGVS); - - if (oGenomicVariant.val() !== '') { - // Variant field already has content, check HGVS now because if we're on an edit form we - // want the buttons to be ready. - oGenomicVariant.change(); - } + oGenomicVariants.change(lovd_checkHGVS); + + $('#variantForm select[name="chromosome"]').change(function (e) { + // We want to make sure that anytime the chromosome is updated, + // the HGVS check and mapping is rerun using the new chromosome. + var sSource = $('#variantForm input[name="source"]').val(); + if (sSource != '') { + $("input").filter(function() { + return $(this).data("genomeBuild") == sSource; + }).change(); + } + }); + + // We disable the effect of the Enter key, since we do not want the user + // to be able to easily submit the form (which is the default effect of Enter), + // since this would mean the onchange would be bypassed and the HGVS check would + // not be run. + $(document).on("keydown", "input[name*='DNA']", function(event) { + return event.key != "Enter"; + }); if (oTranscriptVariants[0] != undefined) { // Add the buttons and images at the end of the transcripts DNA fields. - oTranscriptVariants.parent().append('   '); + oTranscriptVariants.parent().append('   '); var nTranscriptVariants = oTranscriptVariants.size(); for (i=0; i < nTranscriptVariants; i++) { - // Add an artificial attribute "id_ncbi" to the transcripts DNA input field. This is needed to link the response from Mutalyzer to this field, if needed. - $(oTranscriptVariants[i]).attr('id_ncbi', aTranscripts[$(oTranscriptVariants[i]).attr('name').substring(0, )][0]); + // Add an artificial attribute "id_ncbi" to the transcripts DNA input field. This is needed to link the response from VariantValidator to this field. + $(oTranscriptVariants[i]).data('id_ncbi', aTranscripts[$(oTranscriptVariants[i]).attr('name').substring(0, )][0]); } // Add an onChange event that runs lovd_checkHGVS. oTranscriptVariants.change(lovd_checkHGVS); - // Add same function to the onKeyUp event, but then it will check itself if the variant is likely to be complete. - oTranscriptVariants.keyup(lovd_checkHGVS); var oProteinVariants = $('#variantForm input[name$="_VariantOnTranscript/Protein"]'); if (oProteinVariants[0] != undefined) { // Add the buttons and images at the end of the protein description fields. - oProteinVariants.parent().append('   '); - } - - if (oTranscriptVariants.val() !== '') { - // Variant field already has content, check HGVS now because if we're on an edit form we - // want the buttons to be ready. - oTranscriptVariants.change(); + oProteinVariants.parent().append('   '); } } }); diff --git a/src/inc-lib-form.php b/src/inc-lib-form.php index 20475223..94978334 100644 --- a/src/inc-lib-form.php +++ b/src/inc-lib-form.php @@ -891,7 +891,7 @@ function lovd_viewForm ($a, * 'end_fieldset', * array('
', '', 'print', ''), * array('
', '', 'note', ''), - * array('
', '', 'text|password|file', '', ), + * array('
', '', 'text|password|file', '', , ''), * array('
', '', 'textarea', '', , ), * array('
', '', 'select', '', , (array, key => val|query, [0] => [1]), ' . $sDataSuffix); + // When $aElementData is given, it will be added into the HTML code in a 'data-...' format, + // so that jQuery can easily extract it and use it. + array_walk($aElementData, function (&$sVal, $sKey) { + $sVal = 'data-' . str_replace('_', '-', $sKey) . '="' . htmlspecialchars($sVal) . '"'; + }); + + print('' . $sDataSuffix); continue; diff --git a/src/inc-lib-init.php b/src/inc-lib-init.php index 0296e3dc..56412ca2 100644 --- a/src/inc-lib-init.php +++ b/src/inc-lib-init.php @@ -2369,6 +2369,18 @@ function lovd_isColleagueOfOwner ($sType, $Data, $bMustHaveEditPermission = true +function lovd_isHGVS($sVariant) +{ + // This wrapper calls the HGVS check functionality of lovd_getVariantInfo. + // To increase readability, please use this function rather than a direct + // call to getVariantInfo when checking the HGVS of a variant. + return lovd_getVariantInfo($sVariant, false, true); +} + + + + + function lovd_isOwner ($sType, $Data) { // Checks if the current user (specified by global $_AUTH) is owner of the diff --git a/src/inc-lib-variants.php b/src/inc-lib-variants.php index 68cc4c18..2b63e063 100644 --- a/src/inc-lib-variants.php +++ b/src/inc-lib-variants.php @@ -108,7 +108,7 @@ function lovd_fixHGVS ($sVariant, $sType = '') $sVariant = str_replace(array('‐', '−', '–', '—'), '-', $sVariant); // Do a quick HGVS check. - if (lovd_getVariantInfo($sReference . $sVariant, false, true)) { + if (lovd_isHGVS($sReference . $sVariant)) { // All good! return $sReference . $sVariant; } @@ -619,6 +619,7 @@ function lovd_fixHGVS ($sVariant, $sType = '') + /** * Predict a protein description of a variant and given transcript using the * Mutalyzer webservice. diff --git a/src/scripts/fix_variant_descriptions.php b/src/scripts/fix_variant_descriptions.php index f9bc1ea0..4523434f 100644 --- a/src/scripts/fix_variant_descriptions.php +++ b/src/scripts/fix_variant_descriptions.php @@ -549,7 +549,7 @@ function ($sVOT) } elseif ($aVOT['RNA'] == str_replace('?', '', $aVVVot['data']['RNA']) || (strpos($aVOT['RNA'], 'spl') !== false && preg_match('/[0-9]+[+-][0-9]+/', $aVVVot['data']['DNA']))) { // We ignore small differences, where maybe the RNA has been verified. - } elseif (lovd_getVariantInfo(lovd_fixHGVS('c' . strstr($aVOT['RNA'], '.'), 'c'), '', true) + } elseif (lovd_isHGVS(lovd_fixHGVS('c' . strstr($aVOT['RNA'], '.'), 'c')) || preg_match('/^r\.\[[0-9]+/', $aVOT['RNA'])) { // If the RNA variant looks like a full variant description, // the current value must be better (or at least more @@ -941,7 +941,7 @@ function ($sVOT) } elseif ($aVOT['RNA'] == str_replace('?', '', $aVVVot['data']['RNA']) || (strpos($aVOT['RNA'], 'spl') !== false && preg_match('/[0-9]+[+-][0-9]+/', $aVVVot['data']['DNA']))) { // We ignore small differences, where maybe the RNA has been verified. - } elseif (lovd_getVariantInfo(lovd_fixHGVS('c' . strstr($aVOT['RNA'], '.'), 'c'), '', true) + } elseif (lovd_isHGVS(lovd_fixHGVS('c' . strstr($aVOT['RNA'], '.'), 'c')) || preg_match('/^r\.\[[0-9]+/', $aVOT['RNA'])) { // If the RNA variant looks like a full variant description, // the current value must be better (or at least more diff --git a/src/styles.css b/src/styles.css index 30c73601..928407e7 100644 --- a/src/styles.css +++ b/src/styles.css @@ -108,7 +108,7 @@ table.error td {padding : 0px 4px;} -/* Error messages on forms, required by lovd_errorPrint() */ +/* Error, warning and accepted messages on forms, required by lovd_errorPrint() */ div.err {font-size : 11px; border : 1px solid #FF0000; background : #F3F3F3; padding : 5px;} input.err, textarea.err, button.err, select.err {border : 1px solid #EE0000;} @@ -118,6 +118,10 @@ input.warn, textarea.warn, button.warn, select.warn {border : 1px solid #CCAA00;} input.warn:hover, input.warn:focus, textarea.warn:hover, textarea.warn:focus, button.warn:hover, select.warn:hover, select.warn:focus {background : #FFFFE8; border : 1px solid #AA6600;} +input.accept, textarea.accept, button.accept, select.accept +{background : #e9fae1; border : 1px solid #60b932;} +input.accept:hover, input.accept:focus, textarea.accept:hover, textarea.accept:focus, button.accept:hover, select.accept:hover, select.accept:focus +{background : #d7ffc4; border : 1px solid #448a21;} diff --git a/src/variants.php b/src/variants.php index 3c7844fc..ea384da3 100644 --- a/src/variants.php +++ b/src/variants.php @@ -833,18 +833,8 @@ function(sData) { // If the source is a transcript, we describe it with an empty string. $_POST['source'] = ''; - } else { - // If the source of the variant is not a transcript, it is a genome build. - // We will then send the ID of this genome build to the database. - // We have received the last piece of the field used, which may - // be a genome build (from VOG/DNA/hg38) or "DNA" (from VOG/DNA). - $sColumnSuffix = ($_POST['source'] == 'DNA'? '' : $_POST['source']); - - // Get the ID by its column suffix and give this as the source. - $sID = $_DB->query( - 'SELECT id FROM ' . TABLE_GENOME_BUILDS . ' - WHERE column_suffix = ?', array($sColumnSuffix))->fetchColumn(); - $_POST['source'] = $sID; + } elseif (!$_DB->query('SELECT COUNT(*) FROM ' . TABLE_GENOME_BUILDS . ' WHERE ID = ?', array($_POST['source']))->fetchColumn()) { + unset($aFieldsGenome[array_search('source', $aFieldsGenome)]); } $_POST['owned_by'] = ($_AUTH['level'] >= LEVEL_CURATOR? $_POST['owned_by'] : $_AUTH['id']); @@ -970,7 +960,7 @@ function(sData) { print("\n" . ' ' . "\n\n"); - lovd_includeJS('inc-js-variants.php?chromosome=' . $_POST['chromosome']); + lovd_includeJS('inc-js-variants.php'); ?>