From c12b096e7e18ecda7bce62932dd8f09094bd47c1 Mon Sep 17 00:00:00 2001 From: kshefchek Date: Wed, 27 Jul 2016 16:53:19 -0700 Subject: [PATCH 01/17] first pass at case pages --- .../single-tab/individual-gene.yaml | 156 +++++++++++++++ .../single-tab/individual-phenotype.yaml | 156 +++++++++++++++ .../single-tab/individual-variant.yaml | 184 ++++++++++++++++++ lib/monarch/api.js | 2 + lib/monarch/web/webapp.js | 85 ++++++++ templates/case.mustache | 39 ++++ 6 files changed, 622 insertions(+) create mode 100644 conf/golr-views/single-tab/individual-gene.yaml create mode 100644 conf/golr-views/single-tab/individual-phenotype.yaml create mode 100644 conf/golr-views/single-tab/individual-variant.yaml create mode 100644 templates/case.mustache diff --git a/conf/golr-views/single-tab/individual-gene.yaml b/conf/golr-views/single-tab/individual-gene.yaml new file mode 100644 index 00000000..a0148e12 --- /dev/null +++ b/conf/golr-views/single-tab/individual-gene.yaml @@ -0,0 +1,156 @@ +id: individual_gene +schema_generating: true +document_category: generic_association +weight: 20 + +## Results table, horizontal +result_weights: object^5.0 + +## Ordering of facets, vertical +filter_weights: subject_taxon_closure_label^3.5 object_taxon_closure_label^3.0 + +## SOLR FIELD DEFINITIONS + +fields: + +## SUBJECT + + - id: subject + description: "The CURIE for oban:association_has_subject. May be disease, variant, gene, person, ...." + display_name: Model + type: string + property: [] + + - id: subject_label + description: "Label for association_subject. This will always be rdfs:label. Conventions may vary as to what goes in the label. For genes will be symbol, but we may choose to uniquify by prefixing with species" + display_name: Model + type: string + property: [] + searchable: true + + - id: subject_closure + description: "Reflexive closure of association_has_subject. A list of CURIEs. If an individual, first traverse rdf:tpye. The default closure is subclass, but other may optionally be added depending on what type of association this is and what the class is. E.g. for expression associations, the object is an anatomy class, and the closure will include part_of" + display_name: Model + type: string + cardinality: multi + property: [] + + - id: subject_closure_label + description: "Labels for subject_closure." + display_name: Model + type: string + cardinality: multi + property: [] + searchable: true + + - id: subject_taxon + description: "Taxonomic class of the subject. This is typically a CURIE of the form NCBITaxon:nnnn." + display_name: Species + type: string + property: [] + + - id: subject_taxon_label + description: "Label of taxon." + display_name: Species + type: string + property: [] + searchable: true + + - id: subject_taxon_closure + description: "Reflexive closure of taxon. ALWAYS up SubClassOf." + display_name: Species + type: string + cardinality: multi + property: [] + + - id: subject_taxon_closure_label + description: "Labels for taxon_closure." + display_name: Species + type: string + cardinality: multi + property: [] + searchable: true + + - id: object + description: "The CURIE for oban:association_has_object. This is often, but not always an ontology class. E.g. for a gene-gene interaction it is an (arbitrary) member of the pair." + display_name: Gene + type: string + property: [] + + - id: object_label + description: "Label for association_object." + display_name: Gene + type: string + property: [] + searchable: true + + - id: object_closure + description: "Reflexive closure of association_has_object. A list of CURIEs. If an individual, first traverse rdf:tpye. The default closure is subclass, but other may optionally be added depending on what type of association this is and what the class is. E.g. for expression associations, the object is an anatomy class, and the closure will include part_of" + display_name: Gene + type: string + cardinality: multi + property: [] + + - id: object_closure_label + description: "Labels for object_class_closure." + display_name: Gene + type: string + cardinality: multi + property: [] + searchable: true + + - id: object_taxon + description: "Taxonomic class of the object. This is typically a CURIE of the form NCBITaxon:nnnn. This field may be unfilled when used with certain categories" + display_name: Species + type: string + property: [] + + - id: object_taxon_label + description: "Label of taxon." + display_name: Species + type: string + property: [] + searchable: true + + - id: object_taxon_closure + description: "Reflexive closure of taxon. ALWAYS up SubClassOf." + display_name: Species + type: string + cardinality: multi + property: [] + + - id: object_taxon_closure_label + description: "Labels for taxon_closure." + display_name: Species + type: string + cardinality: multi + property: [] + searchable: true + + - id: evidence_object + description: "List of CURIES of all entities that form part of the evidence graph." + display_name: Evidence + type: string + cardinality: multi + property: [] + + - id: evidence_object_label + description: "evidence object label" + display_name: Evidence + type: string + cardinality: multi + property: [] + + - id: evidence_object_closure + description: "Closure for evidence object" + display_name: Evidence + type: string + cardinality: multi + property: [] + + - id: evidence_object_closure_label + description: "List of CURIES of all entities that form part of the evidence closure." + display_name: Evidence + type: string + cardinality: multi + property: [] diff --git a/conf/golr-views/single-tab/individual-phenotype.yaml b/conf/golr-views/single-tab/individual-phenotype.yaml new file mode 100644 index 00000000..f6e5f83f --- /dev/null +++ b/conf/golr-views/single-tab/individual-phenotype.yaml @@ -0,0 +1,156 @@ +id: individual_phenotype +schema_generating: true +document_category: generic_association +weight: 20 + +## Results table, horizontal +result_weights: object^5.0 + +## Ordering of facets, vertical +filter_weights: subject_taxon_label^3.5 + +## SOLR FIELD DEFINITIONS + +fields: + +## SUBJECT + + - id: subject + description: "The CURIE for oban:association_has_subject. May be disease, variant, gene, person, ...." + display_name: Model + type: string + property: [] + + - id: subject_label + description: "Label for association_subject. This will always be rdfs:label. Conventions may vary as to what goes in the label. For genes will be symbol, but we may choose to uniquify by prefixing with species" + display_name: Model + type: string + property: [] + searchable: true + + - id: subject_closure + description: "Reflexive closure of association_has_subject. A list of CURIEs. If an individual, first traverse rdf:tpye. The default closure is subclass, but other may optionally be added depending on what type of association this is and what the class is. E.g. for expression associations, the object is an anatomy class, and the closure will include part_of" + display_name: Model + type: string + cardinality: multi + property: [] + + - id: subject_closure_label + description: "Labels for subject_closure." + display_name: Model + type: string + cardinality: multi + property: [] + searchable: true + + - id: subject_taxon + description: "Taxonomic class of the subject. This is typically a CURIE of the form NCBITaxon:nnnn." + display_name: Species + type: string + property: [] + + - id: subject_taxon_label + description: "Label of taxon." + display_name: Species + type: string + property: [] + searchable: true + + - id: subject_taxon_closure + description: "Reflexive closure of taxon. ALWAYS up SubClassOf." + display_name: Species + type: string + cardinality: multi + property: [] + + - id: subject_taxon_closure_label + description: "Labels for taxon_closure." + display_name: Species + type: string + cardinality: multi + property: [] + searchable: true + + - id: object + description: "The CURIE for oban:association_has_object. This is often, but not always an ontology class. E.g. for a gene-gene interaction it is an (arbitrary) member of the pair." + display_name: Phenotype + type: string + property: [] + + - id: object_label + description: "Label for association_object." + display_name: Phenotype + type: string + property: [] + searchable: true + + - id: object_closure + description: "Reflexive closure of association_has_object. A list of CURIEs. If an individual, first traverse rdf:tpye. The default closure is subclass, but other may optionally be added depending on what type of association this is and what the class is. E.g. for expression associations, the object is an anatomy class, and the closure will include part_of" + display_name: Phenotype + type: string + cardinality: multi + property: [] + + - id: object_closure_label + description: "Labels for object_class_closure." + display_name: Phenotype + type: string + cardinality: multi + property: [] + searchable: true + + - id: object_taxon + description: "Taxonomic class of the object. This is typically a CURIE of the form NCBITaxon:nnnn. This field may be unfilled when used with certain categories" + display_name: Species + type: string + property: [] + + - id: object_taxon_label + description: "Label of taxon." + display_name: Species + type: string + property: [] + searchable: true + + - id: object_taxon_closure + description: "Reflexive closure of taxon. ALWAYS up SubClassOf." + display_name: Species + type: string + cardinality: multi + property: [] + + - id: object_taxon_closure_label + description: "Labels for taxon_closure." + display_name: Species + type: string + cardinality: multi + property: [] + searchable: true + + - id: evidence_object + description: "List of CURIES of all entities that form part of the evidence graph." + display_name: Evidence + type: string + cardinality: multi + property: [] + + - id: evidence_object_label + description: "evidence object label" + display_name: Evidence + type: string + cardinality: multi + property: [] + + - id: evidence_object_closure + description: "Closure for evidence object" + display_name: Evidence + type: string + cardinality: multi + property: [] + + - id: evidence_object_closure_label + description: "List of CURIES of all entities that form part of the evidence closure." + display_name: Evidence + type: string + cardinality: multi + property: [] diff --git a/conf/golr-views/single-tab/individual-variant.yaml b/conf/golr-views/single-tab/individual-variant.yaml new file mode 100644 index 00000000..d7013c84 --- /dev/null +++ b/conf/golr-views/single-tab/individual-variant.yaml @@ -0,0 +1,184 @@ +id: individual_variant +schema_generating: true +document_category: generic_association +weight: 20 + +## Results table, horizontal +result_weights: object^5.0 + +## Ordering of facets, vertical +filter_weights: subject_taxon_closure_label^3.5 object_taxon_closure_label^3.0 + +## SOLR FIELD DEFINITIONS + +fields: + +## SUBJECT + + - id: subject + description: "The CURIE for oban:association_has_subject. May be disease, variant, gene, person, ...." + display_name: Model + type: string + property: [] + + - id: subject_label + description: "Label for association_subject. This will always be rdfs:label. Conventions may vary as to what goes in the label. For genes will be symbol, but we may choose to uniquify by prefixing with species" + display_name: Model + type: string + property: [] + searchable: true + + - id: subject_closure + description: "Reflexive closure of association_has_subject. A list of CURIEs. If an individual, first traverse rdf:tpye. The default closure is subclass, but other may optionally be added depending on what type of association this is and what the class is. E.g. for expression associations, the object is an anatomy class, and the closure will include part_of" + display_name: Model + type: string + cardinality: multi + property: [] + + - id: subject_closure_label + description: "Labels for subject_closure." + display_name: Model + type: string + cardinality: multi + property: [] + searchable: true + + - id: subject_taxon + description: "Taxonomic class of the subject. This is typically a CURIE of the form NCBITaxon:nnnn." + display_name: Species + type: string + property: [] + + - id: subject_taxon_label + description: "Label of taxon." + display_name: Species + type: string + property: [] + searchable: true + + - id: subject_taxon_closure + description: "Reflexive closure of taxon. ALWAYS up SubClassOf." + display_name: Species + type: string + cardinality: multi + property: [] + + - id: subject_taxon_closure_label + description: "Labels for taxon_closure." + display_name: Species + type: string + cardinality: multi + property: [] + searchable: true + + - id: object + description: "The CURIE for oban:association_has_object. This is often, but not always an ontology class. E.g. for a gene-gene interaction it is an (arbitrary) member of the pair." + display_name: Variant + type: string + property: [] + + - id: object_label + description: "Label for association_object." + display_name: Variant + type: string + property: [] + searchable: true + + - id: object_closure + description: "Reflexive closure of association_has_object. A list of CURIEs. If an individual, first traverse rdf:tpye. The default closure is subclass, but other may optionally be added depending on what type of association this is and what the class is. E.g. for expression associations, the object is an anatomy class, and the closure will include part_of" + display_name: Variant + type: string + cardinality: multi + property: [] + + - id: object_closure_label + description: "Labels for object_class_closure." + display_name: Variant + type: string + cardinality: multi + property: [] + searchable: true + + - id: object_taxon + description: "Taxonomic class of the object. This is typically a CURIE of the form NCBITaxon:nnnn. This field may be unfilled when used with certain categories" + display_name: Species + type: string + property: [] + + - id: object_taxon_label + description: "Label of taxon." + display_name: Species + type: string + property: [] + searchable: true + + - id: object_taxon_closure + description: "Reflexive closure of taxon. ALWAYS up SubClassOf." + display_name: Species + type: string + cardinality: multi + property: [] + + - id: object_taxon_closure_label + description: "Labels for taxon_closure." + display_name: Species + type: string + cardinality: multi + property: [] + searchable: true + + - id: object_gene + description: "Gene related to the subject." + display_name: Gene + type: string + property: [] + + - id: object_gene_label + description: "Label of the gene." + display_name: Gene + type: string + property: [] + searchable: true + + - id: object_gene_closure + description: "Reflexive closure of gene." + display_name: Gene + type: string + cardinality: multi + property: [] + + - id: object_gene_closure_label + description: "Labels for gene_closure." + display_name: Gene + type: string + cardinality: multi + property: [] + searchable: true + + - id: evidence_object + description: "List of CURIES of all entities that form part of the evidence graph." + display_name: Evidence + type: string + cardinality: multi + property: [] + + - id: evidence_object_label + description: "evidence object label" + display_name: Evidence + type: string + cardinality: multi + property: [] + + - id: evidence_object_closure + description: "Closure for evidence object" + display_name: Evidence + type: string + cardinality: multi + property: [] + + - id: evidence_object_closure_label + description: "List of CURIES of all entities that form part of the evidence closure." + display_name: Evidence + type: string + cardinality: multi + property: [] diff --git a/lib/monarch/api.js b/lib/monarch/api.js index d90bc704..9e7a1ff0 100644 --- a/lib/monarch/api.js +++ b/lib/monarch/api.js @@ -4390,6 +4390,8 @@ bbop.monarch.Engine.prototype.resolveIdToType = function(id) { type = 'phenotype'; } else if (metadata['category'].indexOf('publication') > -1) { type = 'literature'; + } else if (metadata['category'].indexOf('person') > -1) { + type = 'case'; } else if (variant_categories.indexOf(category) > -1) { type = 'variant'; } else if (model_categories.indexOf(category) > -1) { diff --git a/lib/monarch/web/webapp.js b/lib/monarch/web/webapp.js index a2f1e392..63c59979 100644 --- a/lib/monarch/web/webapp.js +++ b/lib/monarch/web/webapp.js @@ -2128,6 +2128,90 @@ web.wrapRouteGet(app, '/genotype/:id.:fmt?', '/genotype/{id}.{fmt}', ['id', 'fmt web.wrapRouteGet(app, '/genotype/:id', '/genotype/{id}', ['id'], genotypeByIdHandler, errorResponse); +function caseByIdHandler(request, id, fmt) { + try { + + //Curify ID if needed + if (/_/.test(id) && !/\:/.test(id)){ + engine.log("ID contains underscore, replacing with : and redirecting"); + var newID = id.replace("_",":"); + return web.wrapRedirect(genURL('model',newID)); + } + + // Rendering. + var info = newInfo(); + info = engine.fetchDataInfo(id); + + if (fmt != null) { + return formattedResults(info, fmt,request); + } + + if (typeof info.id === 'undefined'){ + info.id = id; + } + if (typeof info.label === 'undefined'){ + info.label = id; + } + info.label = info.label.replace(/^:/, ''); + + + addCoreRenderers(info, 'model', id); + addGolrStaticFiles(info); + + info.hasPhenotypes = true; + + var phenotype_filter = [{ field: 'object_category', value: 'phenotype' }]; + addGolrTable(info, "subject_closure", id, 'phenotypes-table', phenotype_filter, 'individual_phenotype', '#phenotypes'); + info.phenotypeNum = engine.fetchAssociationCount(id, 'subject_closure', phenotype_filter, 'object'); + + var gene_filter = [{ field: 'object_category', value: 'gene' }]; + addGolrTable(info, "subject_closure", id, 'gene-table', gene_filter, 'individual_gene', '#genes'); + info.geneNum = engine.fetchAssociationCount(id, 'subject_closure', gene_filter, 'object'); + + var variant_filter = [{ field: 'object_category', value: 'variant' }]; + addGolrTable(info, "subject_closure", id, 'variant-table', variant_filter, 'individual_variant','#variants'); + info.variantNum = engine.fetchAssociationCount(id, 'subject_closure', variant_filter, 'object'); + + // Phenogrid + addPhenogridFiles(info); + + // Add templates + info.includes.phenotype_anchor = addPhenotypeAnchor(info); + info.includes.phenotype_table = addPhenotypeTable(info); + + // Add gene table + info.includes.gene_anchor = addGeneAnchor(info); + info.includes.gene_table = addGeneTable(); + + // Add variant table + info.includes.variant_anchor = addVariantAnchor(info); + info.includes.variant_table = addVariantTable(); + + info.title = 'Monarch Case: '+info.label+' ('+ info.id+')'; + + info.primary_xref = function() {return genExternalHref('source',{id : id})}; + + info.includes.phenogrid_anchor = expandTemplate('phenogrid-anchor', info); + info.pup_tent_js_libraries.push("/phenogridloader-no-species.js"); + info.monarch_launchable.push('loadPhenogrid()'); + + //Launch function for annotation score + info.pup_tent_js_variables.push({name:'globalID',value:id}); + info.monarch_launchable.push('getAnnotationScore(globalID)'); + + var output = pup_tent.render('case.mustache', info, + 'monarch_base.mustache'); + return web.wrapHTML(output); + } + catch(err) { + return errorResponseWithObject(err); + } +}; + +web.wrapRouteGet(app, '/case/:id.:fmt?', '/case/{id}.{fmt}', ['id', 'fmt'], caseByIdHandler, errorResponse); +web.wrapRouteGet(app, '/case/:id', '/case/{id}', ['id'], caseByIdHandler, errorResponse); + + function genMGIXRef(id) { return "" + id + ""; @@ -4440,6 +4524,7 @@ web.wrapRouteGet(app, '/gene/:id/:section.:fmt?', '/gene/{id}/{section}.{fmt?}', web.wrapRouteGet(app, '/variant/:id/:section.:fmt?', '/variant/{id}/{section}.{fmt?}', ['id', 'section', 'fmt'], fetchFeatureSection); web.wrapRouteGet(app, '/genotype/:id/:section.:fmt?', '/genotype/{id}/{section}.{fmt?}', ['id', 'section', 'fmt'], fetchFeatureSection); web.wrapRouteGet(app, '/model/:id/:section.:fmt?', '/model/{id}/{section}.{fmt?}', ['id', 'section', 'fmt'], fetchFeatureSection); +web.wrapRouteGet(app, '/case/:id/:section.:fmt?', '/case/{id}/{section}.{fmt?}', ['id', 'section', 'fmt'], fetchFeatureSection); if (false) { /* Disabling all /legacy/xxx and /labs/xxx endpoints that aren't dual-mode */ diff --git a/templates/case.mustache b/templates/case.mustache new file mode 100644 index 00000000..5a789736 --- /dev/null +++ b/templates/case.mustache @@ -0,0 +1,39 @@ +{{{includes.navbar}}} + +
+
+
+
+
+ {{#alerts}} +
+ {{{.}}} +
+ {{/alerts}} + +

Case: {{label}}

+ Your feedback welcome! +

+

+
+
+ {{{includes.phenogrid_anchor}}} + {{{includes.phenotype_anchor}}} + {{{includes.gene_anchor}}} + {{{includes.variant_anchor}}} +
+
+
+ {{{includes.phenotype_table}}} + {{{includes.gene_table}}} + {{{includes.variant_table}}} +
+ +
+
+
+
+
+
+{{{includes.footer}}} From 2d60d82cee7f9e8befc857b5de48f60c375cf4a2 Mon Sep 17 00:00:00 2001 From: kshefchek Date: Wed, 27 Jul 2016 17:00:45 -0700 Subject: [PATCH 02/17] add subject column to tables --- conf/golr-views/single-tab/individual-gene.yaml | 10 +++++----- conf/golr-views/single-tab/individual-phenotype.yaml | 10 +++++----- conf/golr-views/single-tab/individual-variant.yaml | 10 +++++----- 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/conf/golr-views/single-tab/individual-gene.yaml b/conf/golr-views/single-tab/individual-gene.yaml index a0148e12..7c939e12 100644 --- a/conf/golr-views/single-tab/individual-gene.yaml +++ b/conf/golr-views/single-tab/individual-gene.yaml @@ -4,7 +4,7 @@ document_category: generic_association weight: 20 ## Results table, horizontal -result_weights: object^5.0 +result_weights: subject^6.0 object^5.0 ## Ordering of facets, vertical filter_weights: subject_taxon_closure_label^3.5 object_taxon_closure_label^3.0 @@ -17,27 +17,27 @@ fields: - id: subject description: "The CURIE for oban:association_has_subject. May be disease, variant, gene, person, ...." - display_name: Model + display_name: Case type: string property: [] - id: subject_label description: "Label for association_subject. This will always be rdfs:label. Conventions may vary as to what goes in the label. For genes will be symbol, but we may choose to uniquify by prefixing with species" - display_name: Model + display_name: Case type: string property: [] searchable: true - id: subject_closure description: "Reflexive closure of association_has_subject. A list of CURIEs. If an individual, first traverse rdf:tpye. The default closure is subclass, but other may optionally be added depending on what type of association this is and what the class is. E.g. for expression associations, the object is an anatomy class, and the closure will include part_of" - display_name: Model + display_name: Case type: string cardinality: multi property: [] - id: subject_closure_label description: "Labels for subject_closure." - display_name: Model + display_name: Case type: string cardinality: multi property: [] diff --git a/conf/golr-views/single-tab/individual-phenotype.yaml b/conf/golr-views/single-tab/individual-phenotype.yaml index f6e5f83f..d5f0f417 100644 --- a/conf/golr-views/single-tab/individual-phenotype.yaml +++ b/conf/golr-views/single-tab/individual-phenotype.yaml @@ -4,7 +4,7 @@ document_category: generic_association weight: 20 ## Results table, horizontal -result_weights: object^5.0 +result_weights: subject^6.0 object^5.0 ## Ordering of facets, vertical filter_weights: subject_taxon_label^3.5 @@ -17,27 +17,27 @@ fields: - id: subject description: "The CURIE for oban:association_has_subject. May be disease, variant, gene, person, ...." - display_name: Model + display_name: Case type: string property: [] - id: subject_label description: "Label for association_subject. This will always be rdfs:label. Conventions may vary as to what goes in the label. For genes will be symbol, but we may choose to uniquify by prefixing with species" - display_name: Model + display_name: Case type: string property: [] searchable: true - id: subject_closure description: "Reflexive closure of association_has_subject. A list of CURIEs. If an individual, first traverse rdf:tpye. The default closure is subclass, but other may optionally be added depending on what type of association this is and what the class is. E.g. for expression associations, the object is an anatomy class, and the closure will include part_of" - display_name: Model + display_name: Case type: string cardinality: multi property: [] - id: subject_closure_label description: "Labels for subject_closure." - display_name: Model + display_name: Case type: string cardinality: multi property: [] diff --git a/conf/golr-views/single-tab/individual-variant.yaml b/conf/golr-views/single-tab/individual-variant.yaml index d7013c84..cfc08ea5 100644 --- a/conf/golr-views/single-tab/individual-variant.yaml +++ b/conf/golr-views/single-tab/individual-variant.yaml @@ -4,7 +4,7 @@ document_category: generic_association weight: 20 ## Results table, horizontal -result_weights: object^5.0 +result_weights: subject^6.0 object^5.0 ## Ordering of facets, vertical filter_weights: subject_taxon_closure_label^3.5 object_taxon_closure_label^3.0 @@ -17,27 +17,27 @@ fields: - id: subject description: "The CURIE for oban:association_has_subject. May be disease, variant, gene, person, ...." - display_name: Model + display_name: Case type: string property: [] - id: subject_label description: "Label for association_subject. This will always be rdfs:label. Conventions may vary as to what goes in the label. For genes will be symbol, but we may choose to uniquify by prefixing with species" - display_name: Model + display_name: Case type: string property: [] searchable: true - id: subject_closure description: "Reflexive closure of association_has_subject. A list of CURIEs. If an individual, first traverse rdf:tpye. The default closure is subclass, but other may optionally be added depending on what type of association this is and what the class is. E.g. for expression associations, the object is an anatomy class, and the closure will include part_of" - display_name: Model + display_name: Case type: string cardinality: multi property: [] - id: subject_closure_label description: "Labels for subject_closure." - display_name: Model + display_name: Case type: string cardinality: multi property: [] From 236b559ae15108bb2e31f34265b4cd6bf6ce479f Mon Sep 17 00:00:00 2001 From: kshefchek Date: Wed, 27 Jul 2016 17:35:39 -0700 Subject: [PATCH 03/17] fix UDP formatting --- lib/monarch/api.js | 1 + lib/monarch/web/webapp.js | 23 ++++++++++++++--------- 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/lib/monarch/api.js b/lib/monarch/api.js index 9e7a1ff0..9a8b0c78 100644 --- a/lib/monarch/api.js +++ b/lib/monarch/api.js @@ -4372,6 +4372,7 @@ bbop.monarch.Engine.prototype.getCategories = function(id) { bbop.monarch.Engine.prototype.resolveIdToType = function(id) { var engine = this; var type = false; //Return false if no type is found + id = id.replace(/^UDP/, ":UDP"); var nodeByID = engine.getGraphNodeByID(id, engine.config.scigraph_data_url); var graph = new bbop.model.graph(); graph.load_json(nodeByID); diff --git a/lib/monarch/web/webapp.js b/lib/monarch/web/webapp.js index 63c59979..f9fc7a49 100644 --- a/lib/monarch/web/webapp.js +++ b/lib/monarch/web/webapp.js @@ -2130,17 +2130,15 @@ web.wrapRouteGet(app, '/genotype/:id', '/genotype/{id}', ['id'], genotypeByIdHan function caseByIdHandler(request, id, fmt) { try { - - //Curify ID if needed - if (/_/.test(id) && !/\:/.test(id)){ - engine.log("ID contains underscore, replacing with : and redirecting"); - var newID = id.replace("_",":"); - return web.wrapRedirect(genURL('model',newID)); + + if (/^UDP/.test(id)) { + id = id.replace(/^UDP/, ":UDP"); } // Rendering. var info = newInfo(); info = engine.fetchDataInfo(id); + if (fmt != null) { return formattedResults(info, fmt,request); @@ -2155,7 +2153,7 @@ function caseByIdHandler(request, id, fmt) { info.label = info.label.replace(/^:/, ''); - addCoreRenderers(info, 'model', id); + addCoreRenderers(info, 'case', id); addGolrStaticFiles(info); info.hasPhenotypes = true; @@ -4128,6 +4126,11 @@ web.wrapRouteGet(app, '/disease/:id/:section', '/disease/{id}/{section}', ['id', function fetchFeatureSection(request, id, section, fmt) { + + if (/^UDP/.test(id)) { + id = id.replace(/^UDP/, ":UDP"); + } + var info = engine.fetchSectionInfo(id, section); var sectionInfo = @@ -5466,8 +5469,10 @@ if (false) { /* Disabling all /legacy/xxx and /labs/xxx endpoints that aren't du function resolveByIdHandler(request, id, fmt) { var returnFunc; - - id = engine.convertIdToCurie(id); + + if (!/^UDP/.test(id)) { + id = engine.convertIdToCurie(id); + } var type = engine.resolveIdToType(id); if (type) { From ae35b72bf4b899a33ef8e109ec855cc1566863a3 Mon Sep 17 00:00:00 2001 From: kshefchek Date: Wed, 27 Jul 2016 17:49:15 -0700 Subject: [PATCH 04/17] remove case links --- js/lib/monarch/linker.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/lib/monarch/linker.js b/js/lib/monarch/linker.js index 9b45a446..68dd2115 100644 --- a/js/lib/monarch/linker.js +++ b/js/lib/monarch/linker.js @@ -130,7 +130,7 @@ bbop.monarch.linker.prototype.url = function (id, xid, modifier, category){ } if (category == null){ throw new Error('category is missing!'); - } else if (category != 'pathway' && !(/^_/.test(id))){ + } else if (category != 'pathway' && category != 'individual' && !(/^_/.test(id))){ retval = this.app_base + '/' + category + '/' + id; } } From 0ff51e9218845a6e595ce5d308d9aac0a294db8d Mon Sep 17 00:00:00 2001 From: kshefchek Date: Wed, 31 Aug 2016 17:07:58 -0700 Subject: [PATCH 05/17] replace person with case --- .../{individual-gene.yaml => case-gene.yaml} | 4 ++-- ...ual-phenotype.yaml => case-phenotype.yaml} | 6 ++--- ...ividual-variant.yaml => case-variant.yaml} | 6 ++--- .../single-tab/disease-pathway.yaml | 2 +- .../single-tab/disease-phenotype.yaml | 2 +- conf/golr-views/single-tab/dovechart.yaml | 2 +- conf/golr-views/single-tab/gene-disease.yaml | 2 +- conf/golr-views/single-tab/gene-homolog.yaml | 2 +- conf/golr-views/single-tab/gene-pathway.yaml | 2 +- .../golr-views/single-tab/gene-phenotype.yaml | 2 +- .../golr-views/single-tab/geno-gene-page.yaml | 2 +- .../single-tab/genotype-disease.yaml | 2 +- conf/golr-views/single-tab/genotype-gene.yaml | 2 +- .../single-tab/genotype-phenotype.yaml | 2 +- .../single-tab/literature-disease.yaml | 2 +- .../single-tab/literature-gene.yaml | 2 +- .../single-tab/literature-genotype.yaml | 2 +- .../single-tab/literature-model.yaml | 2 +- .../single-tab/literature-phenotype.yaml | 2 +- .../single-tab/literature-variant.yaml | 2 +- conf/golr-views/single-tab/model-disease.yaml | 2 +- conf/golr-views/single-tab/model-gene.yaml | 2 +- .../golr-views/single-tab/model-genotype.yaml | 2 +- .../single-tab/model-phenotype.yaml | 2 +- conf/golr-views/single-tab/model-variant.yaml | 2 +- .../single-tab/variant-disease.yaml | 2 +- conf/golr-views/single-tab/variant-gene.yaml | 2 +- .../single-tab/variant-genotype.yaml | 2 +- .../single-tab/variant-phenotype.yaml | 2 +- lib/monarch/api.js | 6 ++--- lib/monarch/web/webapp.js | 23 +++++++++++-------- templates/case.mustache | 2 +- 32 files changed, 51 insertions(+), 48 deletions(-) rename conf/golr-views/single-tab/{individual-gene.yaml => case-gene.yaml} (98%) rename conf/golr-views/single-tab/{individual-phenotype.yaml => case-phenotype.yaml} (97%) rename conf/golr-views/single-tab/{individual-variant.yaml => case-variant.yaml} (97%) diff --git a/conf/golr-views/single-tab/individual-gene.yaml b/conf/golr-views/single-tab/case-gene.yaml similarity index 98% rename from conf/golr-views/single-tab/individual-gene.yaml rename to conf/golr-views/single-tab/case-gene.yaml index 7c939e12..f4dc0283 100644 --- a/conf/golr-views/single-tab/individual-gene.yaml +++ b/conf/golr-views/single-tab/case-gene.yaml @@ -1,4 +1,4 @@ -id: individual_gene +id: case_gene schema_generating: true document_category: generic_association weight: 20 @@ -16,7 +16,7 @@ fields: ## SUBJECT - id: subject - description: "The CURIE for oban:association_has_subject. May be disease, variant, gene, person, ...." + description: "The CURIE for oban:association_has_subject. May be disease, variant, gene, case, ...." display_name: Case type: string property: [] diff --git a/conf/golr-views/single-tab/individual-phenotype.yaml b/conf/golr-views/single-tab/case-phenotype.yaml similarity index 97% rename from conf/golr-views/single-tab/individual-phenotype.yaml rename to conf/golr-views/single-tab/case-phenotype.yaml index d5f0f417..acf1f7e3 100644 --- a/conf/golr-views/single-tab/individual-phenotype.yaml +++ b/conf/golr-views/single-tab/case-phenotype.yaml @@ -1,10 +1,10 @@ -id: individual_phenotype +id: case_phenotype schema_generating: true document_category: generic_association weight: 20 ## Results table, horizontal -result_weights: subject^6.0 object^5.0 +result_weights: subject^6.0 relation^5.5 object^5.0 ## Ordering of facets, vertical filter_weights: subject_taxon_label^3.5 @@ -16,7 +16,7 @@ fields: ## SUBJECT - id: subject - description: "The CURIE for oban:association_has_subject. May be disease, variant, gene, person, ...." + description: "The CURIE for oban:association_has_subject. May be disease, variant, gene, case, ...." display_name: Case type: string property: [] diff --git a/conf/golr-views/single-tab/individual-variant.yaml b/conf/golr-views/single-tab/case-variant.yaml similarity index 97% rename from conf/golr-views/single-tab/individual-variant.yaml rename to conf/golr-views/single-tab/case-variant.yaml index cfc08ea5..afe49a5c 100644 --- a/conf/golr-views/single-tab/individual-variant.yaml +++ b/conf/golr-views/single-tab/case-variant.yaml @@ -1,10 +1,10 @@ -id: individual_variant +id: case_variant schema_generating: true document_category: generic_association weight: 20 ## Results table, horizontal -result_weights: subject^6.0 object^5.0 +result_weights: subject^6.0 object_gene^5.0 object^4.0 ## Ordering of facets, vertical filter_weights: subject_taxon_closure_label^3.5 object_taxon_closure_label^3.0 @@ -16,7 +16,7 @@ fields: ## SUBJECT - id: subject - description: "The CURIE for oban:association_has_subject. May be disease, variant, gene, person, ...." + description: "The CURIE for oban:association_has_subject. May be disease, variant, gene, case, ...." display_name: Case type: string property: [] diff --git a/conf/golr-views/single-tab/disease-pathway.yaml b/conf/golr-views/single-tab/disease-pathway.yaml index 5e5c4c61..d060eb81 100644 --- a/conf/golr-views/single-tab/disease-pathway.yaml +++ b/conf/golr-views/single-tab/disease-pathway.yaml @@ -16,7 +16,7 @@ fields: ## SUBJECT - id: subject - description: "The CURIE for oban:association_has_subject. May be disease, variant, gene, person, ...." + description: "The CURIE for oban:association_has_subject. May be disease, variant, gene, case, ...." display_name: Disease type: string property: [] diff --git a/conf/golr-views/single-tab/disease-phenotype.yaml b/conf/golr-views/single-tab/disease-phenotype.yaml index d744a5cf..c4546b4b 100644 --- a/conf/golr-views/single-tab/disease-phenotype.yaml +++ b/conf/golr-views/single-tab/disease-phenotype.yaml @@ -16,7 +16,7 @@ fields: ## SUBJECT - id: subject - description: "The CURIE for oban:association_has_subject. May be disease, variant, gene, person, ...." + description: "The CURIE for oban:association_has_subject. May be disease, variant, gene, case, ...." display_name: Disease type: string property: [] diff --git a/conf/golr-views/single-tab/dovechart.yaml b/conf/golr-views/single-tab/dovechart.yaml index b5100834..974025b3 100644 --- a/conf/golr-views/single-tab/dovechart.yaml +++ b/conf/golr-views/single-tab/dovechart.yaml @@ -12,7 +12,7 @@ filter_weights: subject_taxon^7.5 object_taxon^4.7 fields: - id: subject - description: "The CURIE for oban:association_has_subject. May be disease, variant, gene, person, ...." + description: "The CURIE for oban:association_has_subject. May be disease, variant, gene, case, ...." display_name: Subject type: string property: [] diff --git a/conf/golr-views/single-tab/gene-disease.yaml b/conf/golr-views/single-tab/gene-disease.yaml index c96afa23..22a20464 100644 --- a/conf/golr-views/single-tab/gene-disease.yaml +++ b/conf/golr-views/single-tab/gene-disease.yaml @@ -16,7 +16,7 @@ fields: ## SUBJECT - id: subject - description: "The CURIE for oban:association_has_subject. May be disease, variant, gene, person, ...." + description: "The CURIE for oban:association_has_subject. May be disease, variant, gene, case, ...." display_name: Gene type: string property: [] diff --git a/conf/golr-views/single-tab/gene-homolog.yaml b/conf/golr-views/single-tab/gene-homolog.yaml index 168f0c6d..97e9dbec 100644 --- a/conf/golr-views/single-tab/gene-homolog.yaml +++ b/conf/golr-views/single-tab/gene-homolog.yaml @@ -16,7 +16,7 @@ fields: ## SUBJECT - id: subject - description: "The CURIE for oban:association_has_subject. May be disease, variant, gene, person, ...." + description: "The CURIE for oban:association_has_subject. May be disease, variant, gene, case, ...." display_name: Gene type: string property: [] diff --git a/conf/golr-views/single-tab/gene-pathway.yaml b/conf/golr-views/single-tab/gene-pathway.yaml index acf6b617..9945e017 100644 --- a/conf/golr-views/single-tab/gene-pathway.yaml +++ b/conf/golr-views/single-tab/gene-pathway.yaml @@ -16,7 +16,7 @@ fields: ## SUBJECT - id: subject - description: "The CURIE for oban:association_has_subject. May be disease, variant, gene, person, ...." + description: "The CURIE for oban:association_has_subject. May be disease, variant, gene, case, ...." display_name: Gene type: string property: [] diff --git a/conf/golr-views/single-tab/gene-phenotype.yaml b/conf/golr-views/single-tab/gene-phenotype.yaml index 2b285657..973e02d3 100644 --- a/conf/golr-views/single-tab/gene-phenotype.yaml +++ b/conf/golr-views/single-tab/gene-phenotype.yaml @@ -16,7 +16,7 @@ fields: ## SUBJECT - id: subject - description: "The CURIE for oban:association_has_subject. May be disease, variant, gene, person, ...." + description: "The CURIE for oban:association_has_subject. May be disease, variant, gene, case, ...." display_name: Gene type: string property: [] diff --git a/conf/golr-views/single-tab/geno-gene-page.yaml b/conf/golr-views/single-tab/geno-gene-page.yaml index f671fe33..9732172c 100644 --- a/conf/golr-views/single-tab/geno-gene-page.yaml +++ b/conf/golr-views/single-tab/geno-gene-page.yaml @@ -16,7 +16,7 @@ fields: ## SUBJECT - id: subject - description: "The CURIE for oban:association_has_subject. May be disease, variant, gene, person, ...." + description: "The CURIE for oban:association_has_subject. May be disease, variant, gene, case, ...." display_name: Genotype type: string property: [] diff --git a/conf/golr-views/single-tab/genotype-disease.yaml b/conf/golr-views/single-tab/genotype-disease.yaml index 5f82f7a6..28909e62 100644 --- a/conf/golr-views/single-tab/genotype-disease.yaml +++ b/conf/golr-views/single-tab/genotype-disease.yaml @@ -16,7 +16,7 @@ fields: ## SUBJECT - id: subject - description: "The CURIE for oban:association_has_subject. May be disease, variant, Disease, person, ...." + description: "The CURIE for oban:association_has_subject. May be disease, variant, gene, case, ...." display_name: Genotype type: string property: [] diff --git a/conf/golr-views/single-tab/genotype-gene.yaml b/conf/golr-views/single-tab/genotype-gene.yaml index 541afeab..baa1bafb 100644 --- a/conf/golr-views/single-tab/genotype-gene.yaml +++ b/conf/golr-views/single-tab/genotype-gene.yaml @@ -16,7 +16,7 @@ fields: ## SUBJECT - id: subject - description: "The CURIE for oban:association_has_subject. May be disease, variant, gene, person, ...." + description: "The CURIE for oban:association_has_subject. May be disease, variant, gene, case, ...." display_name: Genotype type: string property: [] diff --git a/conf/golr-views/single-tab/genotype-phenotype.yaml b/conf/golr-views/single-tab/genotype-phenotype.yaml index e018e101..a031c760 100644 --- a/conf/golr-views/single-tab/genotype-phenotype.yaml +++ b/conf/golr-views/single-tab/genotype-phenotype.yaml @@ -16,7 +16,7 @@ fields: ## SUBJECT - id: subject - description: "The CURIE for oban:association_has_subject. May be disease, variant, gene, person, ...." + description: "The CURIE for oban:association_has_subject. May be disease, variant, gene, case, ...." display_name: Genotype type: string property: [] diff --git a/conf/golr-views/single-tab/literature-disease.yaml b/conf/golr-views/single-tab/literature-disease.yaml index d455cbc7..f6643a19 100644 --- a/conf/golr-views/single-tab/literature-disease.yaml +++ b/conf/golr-views/single-tab/literature-disease.yaml @@ -16,7 +16,7 @@ fields: ## SUBJECT - id: subject - description: "The CURIE for oban:association_has_subject. May be disease, variant, gene, person, ...." + description: "The CURIE for oban:association_has_subject. May be disease, variant, gene, case, ...." display_name: Publication ID type: string property: [] diff --git a/conf/golr-views/single-tab/literature-gene.yaml b/conf/golr-views/single-tab/literature-gene.yaml index 097af984..6d79640b 100644 --- a/conf/golr-views/single-tab/literature-gene.yaml +++ b/conf/golr-views/single-tab/literature-gene.yaml @@ -16,7 +16,7 @@ fields: ## SUBJECT - id: subject - description: "The CURIE for oban:association_has_subject. May be disease, variant, gene, person, ...." + description: "The CURIE for oban:association_has_subject. May be disease, variant, gene, case, ...." display_name: Publication ID type: string property: [] diff --git a/conf/golr-views/single-tab/literature-genotype.yaml b/conf/golr-views/single-tab/literature-genotype.yaml index f516a7ad..f66fd082 100644 --- a/conf/golr-views/single-tab/literature-genotype.yaml +++ b/conf/golr-views/single-tab/literature-genotype.yaml @@ -16,7 +16,7 @@ fields: ## SUBJECT - id: subject - description: "The CURIE for oban:association_has_subject. May be disease, variant, gene, person, ...." + description: "The CURIE for oban:association_has_subject. May be disease, variant, gene, case, ...." display_name: Publication ID type: string property: [] diff --git a/conf/golr-views/single-tab/literature-model.yaml b/conf/golr-views/single-tab/literature-model.yaml index bd3c7c6e..da479a6f 100644 --- a/conf/golr-views/single-tab/literature-model.yaml +++ b/conf/golr-views/single-tab/literature-model.yaml @@ -16,7 +16,7 @@ fields: ## SUBJECT - id: subject - description: "The CURIE for oban:association_has_subject. May be disease, variant, gene, person, ...." + description: "The CURIE for oban:association_has_subject. May be disease, variant, gene, case, ...." display_name: Publication ID type: string property: [] diff --git a/conf/golr-views/single-tab/literature-phenotype.yaml b/conf/golr-views/single-tab/literature-phenotype.yaml index dc83cbb1..0b10989d 100644 --- a/conf/golr-views/single-tab/literature-phenotype.yaml +++ b/conf/golr-views/single-tab/literature-phenotype.yaml @@ -16,7 +16,7 @@ fields: ## SUBJECT - id: subject - description: "The CURIE for oban:association_has_subject. May be disease, variant, gene, person, ...." + description: "The CURIE for oban:association_has_subject. May be disease, variant, gene, case, ...." display_name: Publication ID type: string property: [] diff --git a/conf/golr-views/single-tab/literature-variant.yaml b/conf/golr-views/single-tab/literature-variant.yaml index eb0d864b..43fea11a 100644 --- a/conf/golr-views/single-tab/literature-variant.yaml +++ b/conf/golr-views/single-tab/literature-variant.yaml @@ -16,7 +16,7 @@ fields: ## SUBJECT - id: subject - description: "The CURIE for oban:association_has_subject. May be disease, variant, gene, person, ...." + description: "The CURIE for oban:association_has_subject. May be disease, variant, gene, case, ...." display_name: Publication ID type: string property: [] diff --git a/conf/golr-views/single-tab/model-disease.yaml b/conf/golr-views/single-tab/model-disease.yaml index c1de6595..d0c0403e 100644 --- a/conf/golr-views/single-tab/model-disease.yaml +++ b/conf/golr-views/single-tab/model-disease.yaml @@ -16,7 +16,7 @@ fields: ## SUBJECT - id: subject - description: "The CURIE for oban:association_has_subject. May be disease, variant, gene, person, ...." + description: "The CURIE for oban:association_has_subject. May be disease, variant, gene, case, ...." display_name: Model type: string property: [] diff --git a/conf/golr-views/single-tab/model-gene.yaml b/conf/golr-views/single-tab/model-gene.yaml index 79581b34..d10bd0ae 100644 --- a/conf/golr-views/single-tab/model-gene.yaml +++ b/conf/golr-views/single-tab/model-gene.yaml @@ -16,7 +16,7 @@ fields: ## SUBJECT - id: subject - description: "The CURIE for oban:association_has_subject. May be disease, variant, gene, person, ...." + description: "The CURIE for oban:association_has_subject. May be disease, variant, gene, case, ...." display_name: Model type: string property: [] diff --git a/conf/golr-views/single-tab/model-genotype.yaml b/conf/golr-views/single-tab/model-genotype.yaml index 2dc92c50..c984fdb2 100644 --- a/conf/golr-views/single-tab/model-genotype.yaml +++ b/conf/golr-views/single-tab/model-genotype.yaml @@ -16,7 +16,7 @@ fields: ## SUBJECT - id: subject - description: "The CURIE for oban:association_has_subject. May be disease, variant, gene, person, ...." + description: "The CURIE for oban:association_has_subject. May be disease, variant, gene, case, ...." display_name: Model type: string property: [] diff --git a/conf/golr-views/single-tab/model-phenotype.yaml b/conf/golr-views/single-tab/model-phenotype.yaml index c97b0427..2d6ca33d 100644 --- a/conf/golr-views/single-tab/model-phenotype.yaml +++ b/conf/golr-views/single-tab/model-phenotype.yaml @@ -16,7 +16,7 @@ fields: ## SUBJECT - id: subject - description: "The CURIE for oban:association_has_subject. May be disease, variant, gene, person, ...." + description: "The CURIE for oban:association_has_subject. May be disease, variant, gene, case, ...." display_name: Model type: string property: [] diff --git a/conf/golr-views/single-tab/model-variant.yaml b/conf/golr-views/single-tab/model-variant.yaml index b3b1c1bd..509e7fbb 100644 --- a/conf/golr-views/single-tab/model-variant.yaml +++ b/conf/golr-views/single-tab/model-variant.yaml @@ -16,7 +16,7 @@ fields: ## SUBJECT - id: subject - description: "The CURIE for oban:association_has_subject. May be disease, variant, gene, person, ...." + description: "The CURIE for oban:association_has_subject. May be disease, variant, gene, case, ...." display_name: Model type: string property: [] diff --git a/conf/golr-views/single-tab/variant-disease.yaml b/conf/golr-views/single-tab/variant-disease.yaml index 0747be5b..53545595 100644 --- a/conf/golr-views/single-tab/variant-disease.yaml +++ b/conf/golr-views/single-tab/variant-disease.yaml @@ -17,7 +17,7 @@ fields: ## SUBJECT - id: subject - description: "The CURIE for oban:association_has_subject. May be disease, variant, gene, person, ...." + description: "The CURIE for oban:association_has_subject. May be disease, variant, gene, case, ...." display_name: Variant type: string property: [] diff --git a/conf/golr-views/single-tab/variant-gene.yaml b/conf/golr-views/single-tab/variant-gene.yaml index aa711a09..2ec66d65 100644 --- a/conf/golr-views/single-tab/variant-gene.yaml +++ b/conf/golr-views/single-tab/variant-gene.yaml @@ -16,7 +16,7 @@ fields: ## SUBJECT - id: subject - description: "The CURIE for oban:association_has_subject. May be disease, variant, gene, person, ...." + description: "The CURIE for oban:association_has_subject. May be disease, variant, gene, case, ...." display_name: Variant type: string property: [] diff --git a/conf/golr-views/single-tab/variant-genotype.yaml b/conf/golr-views/single-tab/variant-genotype.yaml index fcef952b..4d4d3be8 100644 --- a/conf/golr-views/single-tab/variant-genotype.yaml +++ b/conf/golr-views/single-tab/variant-genotype.yaml @@ -16,7 +16,7 @@ fields: ## SUBJECT - id: subject - description: "The CURIE for oban:association_has_subject. May be disease, variant, gene, person, ...." + description: "The CURIE for oban:association_has_subject. May be disease, variant, gene, case, ...." display_name: Variant type: string property: [] diff --git a/conf/golr-views/single-tab/variant-phenotype.yaml b/conf/golr-views/single-tab/variant-phenotype.yaml index d2965e1c..08065886 100644 --- a/conf/golr-views/single-tab/variant-phenotype.yaml +++ b/conf/golr-views/single-tab/variant-phenotype.yaml @@ -17,7 +17,7 @@ fields: ## SUBJECT - id: subject - description: "The CURIE for oban:association_has_subject. May be disease, variant, gene, person, ...." + description: "The CURIE for oban:association_has_subject. May be disease, variant, gene, case, ...." display_name: Variant type: string property: [] diff --git a/lib/monarch/api.js b/lib/monarch/api.js index 9a8b0c78..0fbe1faa 100644 --- a/lib/monarch/api.js +++ b/lib/monarch/api.js @@ -4372,7 +4372,9 @@ bbop.monarch.Engine.prototype.getCategories = function(id) { bbop.monarch.Engine.prototype.resolveIdToType = function(id) { var engine = this; var type = false; //Return false if no type is found - id = id.replace(/^UDP/, ":UDP"); + if (!/.*[:].*/.test(id)) { + id = ':' + id; + } var nodeByID = engine.getGraphNodeByID(id, engine.config.scigraph_data_url); var graph = new bbop.model.graph(); graph.load_json(nodeByID); @@ -4391,8 +4393,6 @@ bbop.monarch.Engine.prototype.resolveIdToType = function(id) { type = 'phenotype'; } else if (metadata['category'].indexOf('publication') > -1) { type = 'literature'; - } else if (metadata['category'].indexOf('person') > -1) { - type = 'case'; } else if (variant_categories.indexOf(category) > -1) { type = 'variant'; } else if (model_categories.indexOf(category) > -1) { diff --git a/lib/monarch/web/webapp.js b/lib/monarch/web/webapp.js index f9fc7a49..b93281fd 100644 --- a/lib/monarch/web/webapp.js +++ b/lib/monarch/web/webapp.js @@ -2131,8 +2131,8 @@ web.wrapRouteGet(app, '/genotype/:id', '/genotype/{id}', ['id'], genotypeByIdHan function caseByIdHandler(request, id, fmt) { try { - if (/^UDP/.test(id)) { - id = id.replace(/^UDP/, ":UDP"); + if (!/.*[:].*/.test(id)) { + id = ':' + id; } // Rendering. @@ -2158,16 +2158,19 @@ function caseByIdHandler(request, id, fmt) { info.hasPhenotypes = true; - var phenotype_filter = [{ field: 'object_category', value: 'phenotype' }]; - addGolrTable(info, "subject_closure", id, 'phenotypes-table', phenotype_filter, 'individual_phenotype', '#phenotypes'); + var phenotype_filter = [{ field: 'object_category', value: 'phenotype' }, + { field: 'subject_category', value: 'case' }]; + addGolrTable(info, "subject_closure", id, 'phenotypes-table', phenotype_filter, 'case_phenotype', '#phenotypes'); info.phenotypeNum = engine.fetchAssociationCount(id, 'subject_closure', phenotype_filter, 'object'); - var gene_filter = [{ field: 'object_category', value: 'gene' }]; - addGolrTable(info, "subject_closure", id, 'gene-table', gene_filter, 'individual_gene', '#genes'); + var gene_filter = [{ field: 'object_category', value: 'gene' }, + { field: 'subject_category', value: 'case' }]; + addGolrTable(info, "subject_closure", id, 'gene-table', gene_filter, 'case_gene', '#genes'); info.geneNum = engine.fetchAssociationCount(id, 'subject_closure', gene_filter, 'object'); - var variant_filter = [{ field: 'object_category', value: 'variant' }]; - addGolrTable(info, "subject_closure", id, 'variant-table', variant_filter, 'individual_variant','#variants'); + var variant_filter = [{ field: 'object_category', value: 'variant' }, + { field: 'subject_category', value: 'case' }]; + addGolrTable(info, "subject_closure", id, 'variant-table', variant_filter, 'case_variant','#variants'); info.variantNum = engine.fetchAssociationCount(id, 'subject_closure', variant_filter, 'object'); // Phenogrid @@ -4127,8 +4130,8 @@ web.wrapRouteGet(app, '/disease/:id/:section', '/disease/{id}/{section}', ['id', function fetchFeatureSection(request, id, section, fmt) { - if (/^UDP/.test(id)) { - id = id.replace(/^UDP/, ":UDP"); + if (!/.*[:].*/.test(id)) { + id = ':' + id; } var info = engine.fetchSectionInfo(id, section); diff --git a/templates/case.mustache b/templates/case.mustache index 5a789736..dc6fe6e4 100644 --- a/templates/case.mustache +++ b/templates/case.mustache @@ -11,7 +11,7 @@
{{/alerts}} -

Case: {{label}}

+

Case: MONARCH:{{label}}

Your feedback welcome!

From f37a3fcfab5c04bee0ed7e1b33b7e90aaca0e7f1 Mon Sep 17 00:00:00 2001 From: kshefchek Date: Mon, 7 Nov 2016 12:35:13 -0800 Subject: [PATCH 06/17] manual copy of webapp.js --- lib/monarch/web/webapp.js | 1549 ++++++++++--------------------------- 1 file changed, 403 insertions(+), 1146 deletions(-) diff --git a/lib/monarch/web/webapp.js b/lib/monarch/web/webapp.js index b93281fd..529a72a1 100644 --- a/lib/monarch/web/webapp.js +++ b/lib/monarch/web/webapp.js @@ -77,6 +77,16 @@ else { useWebpack = false; } +var usePuptentNoCache = env.getEnv().USE_PUPTENT_NOCACHE; +if (usePuptentNoCache && usePuptentNoCache === '1') { + console.log('#USE_PUPTENT_NOCACHE enabled'); + usePuptentNoCache = true; +} +else { + usePuptentNoCache = false; +} + + // // newInfo() creates a new info object for use with pup-tent // newInfo(someInfo) will extend someInfo with any necessary defaults @@ -186,7 +196,6 @@ var pup_tent_dirs = [ 'node_modules/font-awesome/fonts', 'node_modules/phenogrid/dist', // dist contains phenogrid-bundle.js and phenogrid-bundle.css 'node_modules/phenogrid/config', // config contains phenogrid_config.js - 'node_modules/cytoscape/dist', // config contains phenogrid_config.js 'widgets/keggerator/js', 'widgets/class-enrichment', 'conf', // get access to conf/golr-conf.json @@ -399,7 +408,7 @@ function buildEngine(defaultConfig, golrConfig) { // When not in production, re-read files from disk--makes development // easier. - if( !engine.isProduction() ){ + if (!engine.isProduction() || usePuptentNoCache){ pup_tent.use_cache_p(false); } @@ -419,7 +428,7 @@ function buildEngine(defaultConfig, golrConfig) { }, store: function(tbl, key, val) { var path = "./cache/"+tbl+"/key-"+key+".json"; - console.log('###CACHE SAVE:', key); + // console.log('###CACHE SAVE:', key); env.fs_writeFileSync(path, JSON.stringify(val)); }, clear: function(match) { @@ -538,7 +547,7 @@ function expandTemplate(tmplName, tmplInfo) { function addCoreRenderers(info, type, id, defaults) { // Initialize info info = newInfo(info); - + // Standard context. info['@context'] = "/conf/monarch-context.json"; @@ -548,7 +557,7 @@ function addCoreRenderers(info, type, id, defaults) { info.pup_tent_js_variables = []; // info.pup_tent_js_libraries.push("/facet-filters.js"); - + //Adding some global app variables var golr_conf_json = env.readJSON('conf/golr-conf.json'); info.pup_tent_js_variables.push({name:'global_app_base', @@ -672,7 +681,7 @@ function addCoreRenderers(info, type, id, defaults) { info.monarch_launchable.push('navbar_search_init()'); info.includes.footer = expandTemplate('footer', info); - info.includes.classificationComponent = expandTemplate('classificationComponent', info); + // info.includes.classificationComponent = expandTemplate('classificationComponent', info); info.isProduction = engine.config.type == 'production'; @@ -827,7 +836,7 @@ function statusHandler(request) { function getStatus(request) { var status = {}; - + if (typeof request !== 'undefined') { status['location'] = request.url || request.pathInfo || '???'; } @@ -836,7 +845,7 @@ function getStatus(request) { status['okay'] = true; status['message'] = 'okay'; status['date'] = (new Date()).toString(); - + status['platform'] = env.isRingoJS() ? 'ringojs' : 'nodejs'; status['platform_version'] = env.isRingoJS() ? 'RingoJS Version Unavailable' : @@ -846,7 +855,7 @@ function getStatus(request) { {'name': 'config_type', 'value': engine.config.type}, {'name': 'good_robot_hits', 'value': reporter.report('robots.txt')} ]; - + return status; } @@ -868,9 +877,9 @@ function serviceStatusHandler(request) { var status = {}; var info = {}; info = engine.getHealthCheck(); - + var server_list = Object.keys(info); - + server_list.forEach(function (i) { if (info[i]['status'] === 'pass') { info[i]['status'] = ''; @@ -878,10 +887,10 @@ function serviceStatusHandler(request) { info[i]['status'] = ''; } }); - + addCoreRenderers(info); info.title = 'Monarch Services'; - + var output = pup_tent.render('status.mustache', info,'monarch_base.mustache'); return web.wrapHTML(output); @@ -889,19 +898,6 @@ function serviceStatusHandler(request) { web.wrapRouteGet(app, '/services/status', '/services/status', [], serviceStatusHandler, errorResponse); -if (false) { /* Disabling all /legacy/xxx and /labs/xxx endpoints that aren't dual-mode */ -app.get('/labs/old-home', function(request) { - var info = newInfo(); - addCoreRenderers(info); - - info.pup_tent_css_libraries = [ - '/main.css' - ]; - info.title = 'Monarch Diseases and Phenotypes'; - var output = pup_tent.render('main.mustache', info, 'monarch_base.mustache'); - return response.html(output); -}); -} function pageByPageHandler(request, page) { var info = newInfo(); @@ -914,6 +910,7 @@ function pageByPageHandler(request, page) { var pageTitles = { about: 'About Monarch', releases: 'Monarch Releases', + disclaimer: 'Monarch Disclaimer', team: 'Monarch Development Team', software: 'Monarch Software', services: 'Monarch Services', @@ -955,6 +952,14 @@ web.wrapRouteGet(app, '/robots.txt', '/robots.txt', [], }, errorResponse ); +function wrapContentOrError(path) { + var result = web.wrapContent(path); + if (!result) { + result = errorResponse(404, 'Path not found: ' + path); + } + + return result; +} // anything in the docs/ directory is passed through statically @@ -970,7 +975,8 @@ function docHandler(request, p1, p2, p3) { path += '/' + p3; } - return web.wrapContent(path); + var result = wrapContentOrError(path); + return result; } web.wrapRouteGet(app, '/docs/:p1/:p2/:p3', '/docs/{p1}/{p2}/{p3}', ['p1', 'p2', 'p3'], docHandler, errorResponse); @@ -987,21 +993,21 @@ web.wrapRouteGet(app, '/fonts/:f', '/fonts/{f}', ['f'], else if (/^glyphicons/.test(f)) { path = './node_modules/bootstrap/dist/fonts/'+f; } - return web.wrapContent(path); + return wrapContentOrError(path); }, errorResponse ); web.wrapRouteGet(app, '/image/:page', '/image/{page}', ['page'], function(request, page) { var path = './image/'+page; - return web.wrapContent(path); + return wrapContentOrError(path); }, errorResponse ); web.wrapRouteGet(app, '/image/team/:page', '/image/team/{page}', ['page'], function(request, page) { var path = './image/team/'+page; - return web.wrapContent(path); + return wrapContentOrError(path); }, errorResponse ); @@ -1009,7 +1015,7 @@ web.wrapRouteGet(app, '/images/:file.png', '/images/{file}.png', ['file'], function(request, file) { var path = './node_modules/jquery-ui/themes/base/images/'+file + '.png'; // console.log('resolving jqueryui base theme image:', path); - return web.wrapContent(path); + return wrapContentOrError(path); }, errorResponse ); @@ -1029,7 +1035,7 @@ web.wrapRouteGet(app, '/node_modules/phenogrid/:filename', '/node_modules/phenog // path = './node_modules/gfm.css/gfm.css'; } - return web.wrapContent(path); + return wrapContentOrError(path); }, errorResponse ); @@ -1049,30 +1055,46 @@ web.wrapRouteGet(app, '/node_modules/phenogrid/:filename', '/node_modules/phenog // Returns: // All classes with :term as a substring -function searchHandler(request, term, fmt) { - console.log('searchHandler:', term, fmt); +function searchHandler(request, term) { + console.log('searchHandler:', term); try { - if (/^\s*\S+:\S+\s*$/.test(term)) { - var url; - engine.log("Redirecting " + term); - var resultObj = engine.getVocabularyTermByID(term); - //Taking the first result - var type = engine.resolveIdToType(term); - url = genURL(type,term); - return web.wrapRedirect(url); + // if (/^\s*\S+:\S+\s*$/.test(term)) { + // var url; + // engine.log("Redirecting " + term); + // var resultObj = engine.getVocabularyTermByID(term); + // //Taking the first result + // var type = engine.resolveIdToType(term); + // url = genURL(type,term); + // return web.wrapRedirect(url); + // } + + // check if a format is specified + var match = /^.+(.json|.jsonp|.text|.rdf|.nt)$/i.exec(term); + var fmt = null; + if(match != null) { + fmt = match[1].replace(".", ""); + term = term.replace(match[1], ""); } + // TODO delete that? // temporary fix: need to properly figure out when to encode/decode // See: https://github.com/monarch-initiative/monarch-app/issues/287 - term = term.replace(/'/g, "'"); - var results = engine.searchOverOntologies(term); + //term = term.replace(/'/g, "'"); + + //var results = engine.searchOverOntologies(term); + var resultsCount = 50; + var results = engine.autocomplete(term, null, resultsCount); + + // TODO new implementation for Zhou + //var results = engine.search(term, {}, ["category", "leaf", "taxon_label"], resultsCount, 0); + var info = newInfo(); info.results = results; - info.results.forEach( function (i) { +/* info.results.forEach( function (i) { i.categories = i.categories.map( function (k) { return k.toLowerCase();}) - }); - + });*/ + if (fmt != null) { return formattedResults(info, fmt); } @@ -1082,7 +1104,7 @@ function searchHandler(request, term, fmt) { addCoreRenderers(info, 'search', term); // adorn object with rendering functions - if (info.results.length > 0){ + if (info.results.length > 0) { info.hasResults = true; info.resultsTable = function() {return genTableOfSearchResults(info.results); }; info.description = "Results for "+term+ " searching phenotypes, diseases, genes, and models"; @@ -1119,8 +1141,6 @@ function searchHandler(request, term, fmt) { } } -// Order matters here in the declaration of these routes. -web.wrapRouteGet(app, '/search/:term.:fmt?', '/search/{term}.{fmt}', ['term', 'fmt'], searchHandler, errorResponse); web.wrapRouteGet(app, '/search/:term', '/search/{term}', ['term'], searchHandler, errorResponse); @@ -1167,7 +1187,7 @@ if (useBundle && !useWebpack) { function(request, file, type) { var path = './dist/' + file + '.' + type; // console.log('resolving file.:type:', path); - return web.wrapContent(path); + return wrapContentOrError(path); }, errorResponse ); } @@ -1176,30 +1196,22 @@ if (useBundle && !useWebpack) { web.wrapRouteGet(app, '/app.bundle.js', '/app.bundle.js', [], function(request) { var path = './dist/app.bundle.js'; - return web.wrapContent(path); + return wrapContentOrError(path); }, errorResponse ); web.wrapRouteGet(app, '/app.bundle.css', '/app.bundle.css', [], function(request) { var path = './dist/app.bundle.css'; - return web.wrapContent(path); + return wrapContentOrError(path); }, errorResponse ); } -web.wrapRouteGet(app, '/favicon.ico', '/favicon.ico', [], - function(request) { - var path = './image/favicon.ico'; - // console.log('resolving favicon.ico'); - return web.wrapContent(path); - }, errorResponse -); - // Method: autocomplete // -// proxy for vocbaulary services autocomplete +// proxy for vocabulary services autocomplete // // Path: // - /autocomplete/:term @@ -1215,14 +1227,15 @@ web.wrapRouteGet(app, '/favicon.ico', '/favicon.ico', [], function autocompleteByCategoryTermHandler(request,category,term,fmt) { // todo - we would like to normalize possible categories; e.g. phenotype --> Phenotype - var info = engine.searchSubstring(term, category); + //var info = engine.searchSubstring(term, category); + var info = engine.autocomplete(term, category); // engine.log("got autocomplete results..."+info.length); // if (info.length > 0) { // console.log("first is: ", info[0]); // } if (fmt != null) { //engine.log("format is "+fmt); - var res= formattedResults(info,fmt,request); + var res = formattedResults(info,fmt,request); return res; } else { return { @@ -1325,7 +1338,7 @@ function diseaseLandingHandler(request) { addGolrStaticFiles(info); var diseaseDist = env.readJSON('./widgets/dove/stats/DO-cache.json'); - info.pup_tent_js_libraries.push("/dove.min.js"); + info.pup_tent_js_libraries.push('/dove.min.js'); info.pup_tent_css_libraries.push("/dovegraph.css"); if (!useBundle) { @@ -1345,154 +1358,6 @@ function diseaseLandingHandler(request) { web.wrapRouteGet(app, '/disease', '/disease', [], diseaseLandingHandler, errorResponse); web.wrapRouteGet(app, '/disease/', '/disease/', [], diseaseLandingHandler, errorResponse); -if (false) { /* Disabling all /legacy/xxx and /labs/xxx endpoints that aren't dual-mode */ -// DISEASE PAGE -// Status: working but needs work -app.get('/legacy/disease/:id.:fmt?', function(request, id, fmt) { - try { - engine.log("getting /disease/:id where id="+id); - var newId = engine.resolveClassId(id); - if (newId != id && typeof newId != 'undefined' ) { - engine.log("redirecting: "+id+" ==> "+newId); - return web.wrapRedirect(genURL('disease',newId)); - } - engine.log("Fetching id from engine, where cache="+engine.cache); - var info = engine.fetchDiseaseInfo(id); - - if (info == null || info.id == null) { - return notFoundResponse("Cannot find "+id); - } - - engine.log("Got info for disease"); - if (fmt != null) { - return formattedResults(info, fmt,request); - } - - // HTML - addCoreRenderers(info, 'disease', id); - - //Add pup_tent libs - // info.pup_tent_css_libraries.push("/monarch-specific.css"); - info.pup_tent_css_libraries.push("/imagehover.css"); - - addPhenogridFiles(info); - - info.pup_tent_js_libraries.push("/phenogridloader-no-species.js"); - info.monarch_launchable.push('loadPhenogrid()'); - // info.pup_tent_js_libraries.push("/stupidtable.min.js"); - // info.pup_tent_js_libraries.push("/tables.js"); - info.monarch_launchable.push('InitTables()'); - - info.title = 'Monarch Disease: '+info.label+' ('+ info.id+')'; - - //HACK because we are always redirected to the underscore, we need curi-style ids for proper link generation - //ONTOQUEST!!! - info.primary_xref = function() {return genExternalHref('source',{id : id.replace(/_/,':')})}; - - info.hasHeritability = function() {return checkExistence(info.heritability)}; - info.heritability = engine.unique(info.heritability.map(function(h) {return h.inheritance.label})).join(", "); - - if (typeof info.synonyms != 'undefined'){ - info.aka = info.synonyms.join(", "); - } - - info.xrefs = function() { - if (info.database_cross_reference != null) { - return info.database_cross_reference.map(function(r) { return genExternalHref('source',{id : r}) }).join(", "); - //return info.database_cross_reference.join(", "); - } - }; - info.altids = function() { - if (info.has_alternative_id != null) { - return info.has_alternative_id.join(", "); - } - } - - // variables checking existence of data in sections - info.hasDef = function() {return checkExistence(info.definitions)}; - info.hasComment = function() {return checkExistence(info.comment)}; - info.hasAka = function() {return checkExistence(info.synonyms)}; - info.hasXrefs = function() {return checkExistence(info.database_cross_reference)}; - - info.hasPhenotypes = function() {return checkExistence(info.phenotype_associations)}; - info.hasGenes = function() {return checkExistence(info.gene_associations)}; - info.hasAlleles = function() {return checkExistence(info.alleles)}; - info.hasModels = function() {return checkExistence(info.models)}; - info.hasSim = function() {return simcount() > 0}; - info.hasPathways = function() {return checkExistence(info.pathway_associations)}; - info.hasLiterature = function() {return checkExistence(info.literature)}; - - //the score is out of 1, so scale to 5 stars - info.annotationScore = function() { - if (info.annotation_sufficiency != null) { - return (5 * info.annotation_sufficiency); - } else { - return 0; - } - }; - //info.phenotypeNum = function() {return getNumLabel(info.phenotype_associations)}; - info.phenotypeNum = function() { - if (info.phenotype_associations != null) { - return getNumLabel(engine.unique(info.phenotype_associations.map(function(p) {return p.phenotype.id})))}; - return 0; - }; - info.geneNum = function() { - if (info.gene_associations != null) { - return getNumLabel(engine.unique(info.gene_associations.map(function(g) {return g.gene.id})))}; - return 0; - }; - info.alleleNum = function() {return getNumLabel(info.alleles)}; - info.modelNum = function() {return getNumLabel(info.models)}; - info.simNum = function() {return simcount()}; - info.literatureNum = function() {return getNumLabel(info.pmidinfo)}; - - var simcount = function() { - if (info.similar_diseases != null) { - var unnestedAssocs = []; - for (var i = 0; i < info.similar_diseases.length; i++) { - var iset = info.similar_diseases[i]; - for (var j = 0; j < iset.b.length; j++) { - unnestedAssocs = unnestedAssocs.concat({a:iset.a, b:iset.b[j]}); - } - } - return unnestedAssocs.length; - } - return 0; - }; - //need to count the num of unique pathways - info.pathwayNum = function() { - if (info.pathway_associations != null) { - var pathwayIds = []; - pathwayIds = info.pathway_associations.map(function(a) {return a.pathway.id}) - pathwayIds = engine.unique(pathwayIds); - return pathwayIds.length; - } - return 0; - }; - - // filter phenotype list for formatting for phenogrid. - // adorn object with rendering functions - info.phenotypeTable = function() {return genTableOfDiseasePhenotypeAssociations(info.phenotype_associations);}; - info.geneTable = function() {return genTableOfDiseaseGeneAssociations(info.gene_associations);}; - info.alleleTable = function() {return genTableOfDiseaseAlleleAssociations(info.alleles);}; - //engine.log("ALLELE TABLE-pre mustache:"+JSON.stringify(info)); - info.modelTable = function() {return genTableOfDiseaseModelAssociations(info.models);}; - //TODO: figure out how to best show this... one table per species? - //TODO: defaulting to showing mouse here - since it's the only one we have - info.simModelTable = function () {return genTableOfSimilarModels(info.similar_models['10090']);}; - info.simTable = function() {return genTableOfSimilarDiseases(info.similar_diseases);}; - info.pathwayTable = function() {return genTableOfDiseasePathwayAssociations(info.pathway_associations);}; - info.literatureTable = function() {return genTableOfLiterature(info.literature, info.pmidinfo);}; - - var output = pup_tent.render('disease-legacy.mustache',info,'monarch_base.mustache'); - return response.html(output); - } - catch(err) { - return errorResponseWithObject(err); - } - -}); -} // This function checks if a variable exists in the JSON blob (and is used to dynamically @@ -1627,7 +1492,7 @@ function phenotypeLandingHandler(request) { var phenoDist = env.readJSON('./widgets/dove/stats/hp-ontology-4.json'); info.pup_tent_css_libraries.push("/dovegraph.css"); - info.pup_tent_js_libraries.push("/dove.min.js"); + info.pup_tent_js_libraries.push('/dove.min.js'); info.pup_tent_js_libraries.push("/graph-config.js"); if (!useBundle) { // info.pup_tent_js_libraries.push("/barchart-launcher.js"); @@ -1645,215 +1510,47 @@ web.wrapRouteGet(app, '/phenotype', '/phenotype', [], phenotypeLandingHandler, e web.wrapRouteGet(app, '/phenotype/', '/phenotype/', [], phenotypeLandingHandler, errorResponse); -if (false) { /* Disabling all /legacy/xxx and /labs/xxx endpoints that aren't dual-mode */ -app.get('/legacy/phenotype/:id.:fmt?', function(request, id, fmt) { - - // TEMPORARY. Remove when this resolved: https://github.com/monarch-initiative/monarch-app/issues/246 - if (id.indexOf("ZP") == 0) { - - var info = { - message: "Zebrafish phenotypes are currently under construction" - }; - addCoreRenderers(info); - info.title = info.message; - var output = pup_tent.render('underconstruction.mustache',info,'monarch_base.mustache'); - var res = response.html(output); - res.status = 404; - return res; - +function addNonEmptyAnchors(info, inhibit_filters_kludge) { + if (info.phenotypeNum && info.phenotypeNum > 0) { + info.includes.phenotype_anchor = addPhenotypeAnchor(info); + info.includes.phenotype_table = addPhenotypeTable(info); } - - try { - var info = engine.fetchPhenotypeInfo(id); - - // TEMPORARY - see https://github.com/monarch-initiative/monarch-app/issues/246 - if (info.genotype_associations != null) { - info.genotype_associations = info.genotype_associations.filter(function(a){return a.has_genotype.id != null && a.has_genotype.id.indexOf("ZFIN") == -1}); - } - - if (fmt != null) { - return formattedResults(info, fmt,request); - } - - addCoreRenderers(info, 'phenotype', id); - - //Add pup_tent libs - // info.pup_tent_css_libraries.push("/monarch-specific.css"); - - // info.pup_tent_js_libraries.push("/stupidtable.min.js"); - // info.pup_tent_js_libraries.push("/tables.js"); - info.monarch_launchable.push('InitTables()'); - - info.title = 'Monarch Phenotype: '+info.label+' ('+ info.id+')'; - - if (typeof info.synonyms != 'undefined'){ - info.aka = info.synonyms.join(", "); - } - - info.xrefs = function() { - if (info.database_cross_reference != null) { - return info.database_cross_reference.map(function(r) { return genExternalHref('source',{id : r}) }).join(", "); - //return info.database_cross_reference.join(", "); - } - }; - - // variables checking existence of data in sections - info.hasDef = function() {return checkExistence(info.definitions)}; - info.hasAka = function() {return checkExistence(info.synonyms)}; - info.hasXrefs = function() {return checkExistence(info.database_cross_reference)}; - info.hasDiseases = function() {return checkExistence(info.disease_associations)}; - info.hasGenes = function() {return checkExistence(info.gene_associations)}; - info.hasGenotypes = function() {return checkExistence(info.genotype_associations)}; - info.hasLiterature = function() {return checkExistence(info.literature)}; - - info.diseaseNum = function() {return getNumLabel(info.disease_associations)}; - info.geneNum = function() { - if (info.gene_associations != null) { - return getNumLabel(engine.unique(info.gene_associations.map(function(g) {return g.gene.id})))}; - return 0; - }; - - info.genotypeNum = function() {return getNumLabel(info.genotype_associations)}; - info.literatureNum = function() {return getNumLabel(info.pmidinfo)}; - - // adorn object with rendering functions - info.diseaseTable = function() {return genTableOfDiseasePhenotypeAssociations(info.disease_associations)} ; - info.geneTable = function() {return genTableOfGenePhenotypeAssociations(info.gene_associations)}; - info.genotypeTable = function() {return genTableOfGenotypePhenotypeAssociations(info.genotype_associations)}; - info.literatureTable = function() {return genTableOfLiterature(info.literature, info.pmidinfo)}; - - var output = pup_tent.render('phenotype-legacy.mustache',info,'monarch_base.mustache'); - return response.html(output); + if (info.geneNum && info.geneNum > 0) { + info.includes.gene_anchor = addGeneAnchor(info); + info.includes.gene_table = addGeneTable(!inhibit_filters_kludge); } - catch(err) { - return errorResponseWithObject(err); + if (info.genotypeNum && info.genotypeNum > 0) { + info.includes.genotype_anchor = addGenotypeAnchor(info); + info.includes.genotype_table = addGenotypeTable(!inhibit_filters_kludge); } -}); -} - - -if (false) { /* Disabling all /legacy/xxx and /labs/xxx endpoints that aren't dual-mode */ -// Note: currently both /genotype/ and /model/ direct here; -// need to decide if we want these URLs to behave differently, or -// to collapse/redirect -var fetchLegacyGenotypePage = function(request, id, fmt) { - try { - var info = engine.fetchGenotypeInfo(id); - if (fmt != null) { - if (fmt == 'json') { - return response.json(info); - } - } - - console.log("INFO:"+JSON.stringify(info)); - - addCoreRenderers(info, 'genotype', id); - - //Add pup_tent libs - // info.pup_tent_css_libraries.push("/monarch-specific.css"); - info.pup_tent_css_libraries.push("/imagehover.css"); - - addPhenogridFiles(info); - - info.pup_tent_js_libraries.push("/genotypepage.js"); - // info.pup_tent_js_libraries.push("/stupidtable.min.js"); - // info.pup_tent_js_libraries.push("/tables.js"); - info.monarch_launchable.push('InitTables()'); - - info.title = 'Monarch Genotype: '+info.label+' ('+ info.id+')'; - - info.overview = function() {return genOverviewOfGenotype(info) }; - - // variables checking existence of data in sections - info.hasPhenotypes = function() {return checkExistence(info.phenotype_associations)}; - info.hasDiseases = function() {return checkExistence(info.disease_associations)}; - info.hasGenes = function() {return checkExistence(info.has_affected_genes)}; - info.hasVariants = function() { return checkExistence(info.has_sequence_alterations)}; - info.hasSim = function() {return checkExistence(info.sim)}; - info.hasLiterature = function() {return checkExistence(info.literature)}; - - info.phenotypeNum = function() { - if (info.phenotype_associations != null) { - return getNumLabel(engine.unique(info.phenotype_associations.map(function(p) { - if (typeof p.has_phenotype != 'undefined' && typeof p.has_phenotype.type != 'undefined') - return p.has_phenotype.type.id})))}; - return 0; - }; - - - info.diseaseNum = function() {return getNumLabel(info.disease_associations)}; - info.geneNum = function() {return getNumLabel(info.has_affected_genes)}; - info.variantNum = function() { - return getNumLabel(vassoc) - }; - info.simNum = function() {return getNumLabel(info.sim)}; - info.literatureNum = function() {return getNumLabel(info.pmidinfo)}; - - info.primary_xref = genMGIXRef(id); - info.taxon_xref; - if (info.taxon){ - info.taxon_xref = function() {return genExternalHref('source',info.taxon)}; - } - - - //info.xrefs = function() {return genExternalHref('source',{id : id})}; - - // adorn object with rendering functions - info.phenotypeTable = function() {return genTableOfGenotypePhenotypeAssociations(info.phenotype_associations);} ; - info.literatureTable = function() {return genTableOfLiterature(info.literature, info.pmidinfo);}; - info.variantTable = function() {return genTableOfGenoVariantAssociations(info);}; - - info.annotationScore = function() { - if (info.annotation_sufficiency != null) { - return (5 * info.annotation_sufficiency); - } else { - return 0; - } - }; - - var output = pup_tent.render('genotype-legacy.mustache',info,'monarch_base.mustache'); - return response.html(output); + if (info.variantNum && info.variantNum > 0) { + info.includes.variant_anchor = addVariantAnchor(info); + info.includes.variant_table = addVariantTable(!inhibit_filters_kludge); } - catch(err) { - return errorResponseWithObject(err); + if (info.diseaseNum && info.diseaseNum > 0) { + info.includes.disease_anchor = addDiseaseAnchor(info); + info.includes.disease_table = addDiseaseTable(); } -}; - - - - - -// GENOTYPE - Sub-pages -// Example: /genotype/MGI_4420313/genotype_associations.json -// Currently only works for json or rdf output -var fetchLegacyGenotypeSection = function(request, id, section, fmt) { - var newId = engine.resolveClassId(id); - if (newId != id) { - engine.log("redirecting: "+id+" ==> "+newId); - return web.wrapRedirect(genURL('genotype',newId)); + if (info.modelNum && info.modelNum > 0) { + info.includes.model_anchor = addModelAnchor(info); + info.includes.model_table = addModelTable(!inhibit_filters_kludge); } - - var info = engine.fetchGenotypeInfo(id); - - var sectionInfo = - { id: "obo:"+id }; // <-- TODO - unify ID/URI strategy - sectionInfo[section] = info[section]; - engine.addJsonLdContext(sectionInfo); - - if (fmt != null) { - return formattedResults(sectionInfo, fmt,request); + if (info.pathwayNum && info.pathwayNum > 0) { + info.includes.pathway_anchor = addPathwayAnchor(info); + info.includes.pathway_table = addPathwayTable(); } - else { - return response.error("plain HTML does not work for page sections. Please append .json or .rdf to URL"); + if (info.literatureNum && info.literatureNum > 0) { + info.includes.literature_anchor = addLiteratureAnchor(info); + info.includes.literature_table = addLiteratureTable(); + } + if (info.homologNum && info.homologNum > 0) { + info.includes.homolog_anchor = addHomologAnchor(info); + info.includes.homolog_table = addHomologTable(); + } + if (info.orthologNum && info.orthologNum > 0) { + info.includes.ortholog_phenotype_anchor = addOrthoPhenoAnchor(info); + info.includes.ortholog_phenotype_table = addOrthoPhenoTable(); } -}; - -// Status: STUB -// this just calls the genotype page - TODO -app.get('/legacy/genotype/:id.:fmt?', fetchLegacyGenotypePage); -app.get('/legacy/model/:id.:fmt?', fetchLegacyGenotypePage); -app.get('/legacy/genotype/:id./:section.:fmt?',fetchLegacyGenotypeSection); -app.get('/legacy/model/:id/:section.:fmt?', fetchLegacyGenotypeSection); } @@ -1898,7 +1595,7 @@ function modelByIdHandler(request, id, fmt) { var genotype_filter = [{ field: 'object_category', value: 'genotype' }]; addGolrTable(info, "subject_closure", id, 'genotype-table', genotype_filter, 'model_genotype', '#genotypes'); - info.geneNum = engine.fetchAssociationCount(id, 'subject_closure', genotype_filter, 'object'); + info.genotypeNum = engine.fetchAssociationCount(id, 'subject_closure', genotype_filter, 'object'); var gene_filter = [{ field: 'object_category', value: 'gene' }]; addGolrTable(info, "subject_closure", id, 'gene-table', gene_filter, 'model_gene', '#genes'); @@ -1911,30 +1608,15 @@ function modelByIdHandler(request, id, fmt) { // Phenogrid addPhenogridFiles(info); - // Add templates - info.includes.phenotype_anchor = addPhenotypeAnchor(info); - info.includes.phenotype_table = addPhenotypeTable(info); - - // Add gene table - info.includes.gene_anchor = addGeneAnchor(info); - info.includes.gene_table = addGeneTable(); - - // Add genotype table - info.includes.genotype_anchor = addGenotypeAnchor(info); - info.includes.genotype_table = addGenotypeTable(); - - // Add variant table - info.includes.variant_anchor = addVariantAnchor(info); - info.includes.variant_table = addVariantTable(); - - // Add disease table - info.includes.disease_anchor = addDiseaseAnchor(info); - info.includes.disease_table = addDiseaseTable(); - + addNonEmptyAnchors(info, true); info.title = 'Monarch Model: '+info.label+' ('+ info.id+')'; info.primary_xref = function() {return genExternalHref('source',{id : id})}; + info.xrefs = function() { + return buildXrefsList(id, info.database_cross_reference); + }; + info.hasXrefs = function() {return checkExistence(info.database_cross_reference) || !!info.primary_xref}; if (info.taxon){ info.taxon_xref = function() {return genExternalHref('source',info.taxon)}; @@ -1950,12 +1632,6 @@ function modelByIdHandler(request, id, fmt) { } } - info.xrefs = function() { - if (info.database_cross_reference != null) { - return info.database_cross_reference.map(function(r) { return genExternalHref('source',{id : r}) }).join(", "); - //return info.database_cross_reference.join(", "); - } - }; info.altids = function() { if (info.has_alternative_id != null) { return info.has_alternative_id.join(", "); @@ -1966,13 +1642,12 @@ function modelByIdHandler(request, id, fmt) { info.hasDef = function() {return checkExistence(info.definitions)}; info.hasComment = function() {return checkExistence(info.comment)}; info.hasAka = function() {return checkExistence(info.synonyms)}; - info.hasXrefs = function() {return checkExistence(info.database_cross_reference)}; info.hasEqual = function() {return checkExistence(info.equivalentClasses)}; info.hasPhenotypes = info.phenotypeNum; info.includes.phenogrid_anchor = expandTemplate('phenogrid-anchor', info); if (info.hasPhenotypes){ - info.pup_tent_js_libraries.push("/phenogridloader-no-species.js"); + info.pup_tent_js_libraries.push("/phenogridloader-onclick.js"); info.monarch_launchable.push('loadPhenogrid()'); } @@ -1980,8 +1655,9 @@ function modelByIdHandler(request, id, fmt) { info.pup_tent_js_variables.push({name:'globalID',value:id}); info.monarch_launchable.push('getAnnotationScore(globalID)'); - var output = pup_tent.render('model.mustache', info, - 'monarch_base.mustache'); + info.node_label = 'Model'; + info.node_logo = '/image/carousel-models.png'; + var output = pup_tent.render('node.mustache', info, 'monarch_base.mustache'); return web.wrapHTML(output); } catch(err) { @@ -2038,7 +1714,7 @@ function genotypeByIdHandler(request, id, fmt) { var model_filter = [{ field: 'subject_category', value: 'model' }]; addGolrTable(info, "object_closure", id, 'model-table', model_filter, 'model_genotype', '#models'); - info.geneNum = engine.fetchAssociationCount(id, 'object_closure', model_filter, 'subject'); + info.modelNum = engine.fetchAssociationCount(id, 'object_closure', model_filter, 'subject'); var variant_filter = [{ field: 'subject_category', value: 'variant' }]; addGolrTable(info, "object_closure", id, 'variant-table', variant_filter, 'variant_genotype','#variants'); @@ -2047,28 +1723,15 @@ function genotypeByIdHandler(request, id, fmt) { // Phenogrid addPhenogridFiles(info); - // Add templates - info.includes.phenotype_anchor = addPhenotypeAnchor(info); - info.includes.phenotype_table = addPhenotypeTable(info); - - // Add gene table - info.includes.gene_anchor = addGeneAnchor(info); - info.includes.gene_table = addGeneTable(); - - // Add variant table - info.includes.variant_anchor = addVariantAnchor(info); - info.includes.variant_table = addVariantTable(); - - info.includes.model_anchor = addModelAnchor(info); - info.includes.model_table = addModelTable(); - - // Add disease table - info.includes.disease_anchor = addDiseaseAnchor(info); - info.includes.disease_table = addDiseaseTable(); + addNonEmptyAnchors(info, true); info.title = 'Monarch Genotype: '+info.label+' ('+ info.id+')'; info.primary_xref = function() {return genExternalHref('source',{id : id})}; + info.xrefs = function() { + return buildXrefsList(id, info.database_cross_reference); + }; + info.hasXrefs = function() {return checkExistence(info.database_cross_reference) || !!info.primary_xref}; if (info.taxon){ info.taxon_xref = function() {return genExternalHref('source',info.taxon)}; @@ -2084,12 +1747,6 @@ function genotypeByIdHandler(request, id, fmt) { } } - info.xrefs = function() { - if (info.database_cross_reference != null) { - return info.database_cross_reference.map(function(r) { return genExternalHref('source',{id : r}) }).join(", "); - //return info.database_cross_reference.join(", "); - } - }; info.altids = function() { if (info.has_alternative_id != null) { return info.has_alternative_id.join(", "); @@ -2100,13 +1757,12 @@ function genotypeByIdHandler(request, id, fmt) { info.hasDef = function() {return checkExistence(info.definitions)}; info.hasComment = function() {return checkExistence(info.comment)}; info.hasAka = function() {return checkExistence(info.synonyms)}; - info.hasXrefs = function() {return checkExistence(info.database_cross_reference)}; info.hasEqual = function() {return checkExistence(info.equivalentClasses)}; info.hasPhenotypes = info.phenotypeNum; info.includes.phenogrid_anchor = expandTemplate('phenogrid-anchor', info); if (info.hasPhenotypes){ - info.pup_tent_js_libraries.push("/phenogridloader-no-species.js"); + info.pup_tent_js_libraries.push("/phenogridloader-onclick.js"); info.monarch_launchable.push('loadPhenogrid()'); } @@ -2114,8 +1770,9 @@ function genotypeByIdHandler(request, id, fmt) { info.pup_tent_js_variables.push({name:'globalID',value:id}); info.monarch_launchable.push('getAnnotationScore(globalID)'); - var output = pup_tent.render('genotype.mustache', info, - 'monarch_base.mustache'); + info.node_label = 'Genotype'; + info.node_logo = '/image/carousel-genes.png'; + var output = pup_tent.render('node.mustache', info, 'monarch_base.mustache'); return web.wrapHTML(output); } catch(err) { @@ -2128,98 +1785,13 @@ web.wrapRouteGet(app, '/genotype/:id.:fmt?', '/genotype/{id}.{fmt}', ['id', 'fmt web.wrapRouteGet(app, '/genotype/:id', '/genotype/{id}', ['id'], genotypeByIdHandler, errorResponse); -function caseByIdHandler(request, id, fmt) { - try { - - if (!/.*[:].*/.test(id)) { - id = ':' + id; - } - - // Rendering. - var info = newInfo(); - info = engine.fetchDataInfo(id); - - - if (fmt != null) { - return formattedResults(info, fmt,request); - } - - if (typeof info.id === 'undefined'){ - info.id = id; - } - if (typeof info.label === 'undefined'){ - info.label = id; - } - info.label = info.label.replace(/^:/, ''); - - - addCoreRenderers(info, 'case', id); - addGolrStaticFiles(info); - - info.hasPhenotypes = true; - - var phenotype_filter = [{ field: 'object_category', value: 'phenotype' }, - { field: 'subject_category', value: 'case' }]; - addGolrTable(info, "subject_closure", id, 'phenotypes-table', phenotype_filter, 'case_phenotype', '#phenotypes'); - info.phenotypeNum = engine.fetchAssociationCount(id, 'subject_closure', phenotype_filter, 'object'); - - var gene_filter = [{ field: 'object_category', value: 'gene' }, - { field: 'subject_category', value: 'case' }]; - addGolrTable(info, "subject_closure", id, 'gene-table', gene_filter, 'case_gene', '#genes'); - info.geneNum = engine.fetchAssociationCount(id, 'subject_closure', gene_filter, 'object'); - - var variant_filter = [{ field: 'object_category', value: 'variant' }, - { field: 'subject_category', value: 'case' }]; - addGolrTable(info, "subject_closure", id, 'variant-table', variant_filter, 'case_variant','#variants'); - info.variantNum = engine.fetchAssociationCount(id, 'subject_closure', variant_filter, 'object'); - - // Phenogrid - addPhenogridFiles(info); - - // Add templates - info.includes.phenotype_anchor = addPhenotypeAnchor(info); - info.includes.phenotype_table = addPhenotypeTable(info); - - // Add gene table - info.includes.gene_anchor = addGeneAnchor(info); - info.includes.gene_table = addGeneTable(); - - // Add variant table - info.includes.variant_anchor = addVariantAnchor(info); - info.includes.variant_table = addVariantTable(); - - info.title = 'Monarch Case: '+info.label+' ('+ info.id+')'; - - info.primary_xref = function() {return genExternalHref('source',{id : id})}; - - info.includes.phenogrid_anchor = expandTemplate('phenogrid-anchor', info); - info.pup_tent_js_libraries.push("/phenogridloader-no-species.js"); - info.monarch_launchable.push('loadPhenogrid()'); - - //Launch function for annotation score - info.pup_tent_js_variables.push({name:'globalID',value:id}); - info.monarch_launchable.push('getAnnotationScore(globalID)'); - - var output = pup_tent.render('case.mustache', info, - 'monarch_base.mustache'); - return web.wrapHTML(output); - } - catch(err) { - return errorResponseWithObject(err); - } -}; - -web.wrapRouteGet(app, '/case/:id.:fmt?', '/case/{id}.{fmt}', ['id', 'fmt'], caseByIdHandler, errorResponse); -web.wrapRouteGet(app, '/case/:id', '/case/{id}', ['id'], caseByIdHandler, errorResponse); - - function genMGIXRef(id) { return "" + id + ""; } -function geneLandingPageHandler(request) { +function geneLandingHandler(request) { var info = prepLandingPage(); //info.blog_results = loadBlogData('gene-news', 4); info.spotlight = engine.fetchSpotlight('gene'); @@ -2259,7 +1831,7 @@ function geneLandingPageHandler(request) { var phenoDist = env.readJSON('./widgets/dove/stats/hp-ontology-4.json'); var diseaseDist = env.readJSON('./widgets/dove/stats/DO-cache.json'); - info.pup_tent_js_libraries.push("/dove.min.js"); + info.pup_tent_js_libraries.push('/dove.min.js'); info.pup_tent_css_libraries.push("/dovegraph.css"); info.pup_tent_js_libraries.push("/graph-config.js"); if (!useBundle) { @@ -2277,115 +1849,12 @@ function geneLandingPageHandler(request) { return web.wrapHTML(output); } -web.wrapRouteGet(app, '/gene', '/gene', [], geneLandingPageHandler, errorResponse); -web.wrapRouteGet(app, '/gene/', '/gene/', [], geneLandingPageHandler, errorResponse); - - - -if (false) { /* Disabling all /legacy/xxx and /labs/xxx endpoints that aren't dual-mode */ -// Status: STUB -app.get('/legacy/gene/:id.:fmt?', function(request, id, fmt) { - - //Redirect to NCBI Gene ID - var mappedID = getGeneMapping(id); - if (typeof mappedID != 'undefined' && mappedID != id){ - engine.log("found updated ID, redirecting to: "+mappedID); - return web.wrapRedirect(genURL('gene',mappedID,fmt)); - } - - var info; - try { - info = engine.fetchGeneInfo(id); - } - catch(err) { - return errorResponseWithObject(err); - } - console.log("got gene info..phenotype list is "+JSON.stringify(info.phenotype_list)); - - if (fmt != null) { - return formattedResults(info,fmt,request); - } - - // HTML - addCoreRenderers(info, 'gene', id); - - //Add pup_tent libs - // info.pup_tent_css_libraries.push("/monarch-specific.css"); - info.pup_tent_css_libraries.push("/imagehover.css"); - - // info.pup_tent_js_libraries.push("/stupidtable.min.js"); - // info.pup_tent_js_libraries.push("/tables.js"); - info.monarch_launchable.push('InitTables()'); - - addPhenogridFiles(info); - - info.pup_tent_js_libraries.push("/phenogridloader-no-species.js"); - info.monarch_launchable.push('loadPhenogrid()'); - - info.title = 'Monarch Gene: '+info.label+' ('+ info.id+')'; - - // variables checking existence of data in sections - info.hasPhenotypes = function() {return checkExistence(info.phenotype_associations)}; - info.hasPathways = function() {return checkExistence(info.pathway_associations)}; - info.hasDiseases = function() {return checkExistence(info.disease_associations)}; - info.hasGenotypes = function() {return checkExistence(info.genotype_associations)}; - info.hasLocation = function() {return checkExistence(info.location)}; - info.hasAlleles = function() {return checkExistence(info.alleles)}; - info.hasOrthologs = function() {return checkExistence(info.orthologs)}; - info.hasInteractions = function() {return checkExistence(info.interactions)}; - info.hasSummary = function() {return checkExistence(info.summary)}; - info.hasLiterature = function() {return checkExistence(info.literature)}; - info.hasSynonym = function() {return checkExistence(info.synonyms)}; - - //info.phenotypeNum = function() {return getNumLabel(info.phenotype_associations)}; - info.phenotypeNum = function() { - if (info.phenotype_associations != null) { - return getNumLabel(engine.unique(info.phenotype_associations.map(function(p) {return p.phenotype.id})))}; - return 0; - }; - - info.genotypeNum = function() {return getNumLabel(info.genotype_associations)}; - info.pathwayNum = function() {return getNumLabel(info.pathway_associations)}; - info.diseaseNum = function() {return getNumLabel(info.disease_associations)}; - info.alleleNum = function() {return getNumLabel(info.alleles)}; - info.orthologNum = function() {return getNumLabel(info.orthologs)}; - info.interactionNum = function() {return getNumLabel(info.interactions)}; - info.literatureNum = function() {return getNumLabel(info.pmidinfo)}; - - // adorn object with rendering functions - info.phenotypeTable = function() {return genTableOfGenePhenotypeAssociations(info.phenotype_associations);}; - info.pathwayTable = function() {return genTableOfGenePathwayAssociations(info.pathway_associations);}; - info.diseaseTable = function() {return genTableOfGeneDiseaseAssociations(info.disease_associations);}; - info.genotypeTable = function() {return genTableOfGeneGenotypeAssociations(info.genotype_associations);}; - info.alleleTable = function() {return genTableOfGeneAlleleAssociations(info.alleles);}; - info.orthologTable = function() {return genTableOfGeneOrthologAssociations(info.orthologs);}; - info.interactionTable = function() {return genTableOfGeneInteractionAssociations(info.interactions);}; - info.literatureTable = function() {return genTableOfLiterature(info.literature, info.pmidinfo);}; - - info.primary_xref = function() {return genExternalHref('source',{id : info.id})}; - info.xrefTable = function() {return genTableOfGeneXRefs(info.xrefs);}; - - info.annotationScore = function() { - if (info.annotation_sufficiency != null) { - return (5 * info.annotation_sufficiency); - } else { - return 0; - } - }; +web.wrapRouteGet(app, '/gene', '/gene', [], geneLandingHandler, errorResponse); +web.wrapRouteGet(app, '/gene/', '/gene/', [], geneLandingHandler, errorResponse); - //Link out to NCBI - info.taxon_xref; - if (info.taxon){ - info.taxon_xref = function() {return genExternalHref('source',info.taxon)}; - } - var output = pup_tent.render('gene-legacy.mustache',info,'monarch_base.mustache'); - return response.html(output); -}); -} - -function genotypeLandingPageHandler(request){ +function genotypeLandingHandler(request){ var info = prepLandingPage(); //info.blog_results = loadBlogData('model-news', 4); @@ -2432,7 +1901,7 @@ function genotypeLandingPageHandler(request){ if (!useBundle) { // info.pup_tent_js_libraries.push("/barchart-launcher.js"); } - info.pup_tent_js_libraries.push("/dove.min.js"); + info.pup_tent_js_libraries.push('/dove.min.js'); info.pup_tent_js_libraries.push("/graph-config.js"); info.pup_tent_js_variables.push({name:'globalDataGraph',value:hpStub}); @@ -2444,7 +1913,7 @@ function genotypeLandingPageHandler(request){ return web.wrapHTML(output); } -function modelLandingPageHandler(request){ +function modelLandingHandler(request){ var info = prepLandingPage(); //info.blog_results = loadBlogData('model-news', 4); @@ -2491,7 +1960,7 @@ function modelLandingPageHandler(request){ if (!useBundle) { // info.pup_tent_js_libraries.push("/barchart-launcher.js"); } - info.pup_tent_js_libraries.push("/dove.min.js"); + info.pup_tent_js_libraries.push('/dove.min.js'); info.pup_tent_js_libraries.push("/graph-config.js"); info.pup_tent_js_variables.push({name:'globalDataGraph',value:diseaseDist}); @@ -2503,50 +1972,12 @@ function modelLandingPageHandler(request){ return web.wrapHTML(output); } -web.wrapRouteGet(app, '/model', '/model', [], modelLandingPageHandler, errorResponse); -web.wrapRouteGet(app, '/model/', '/model/', [], modelLandingPageHandler, errorResponse); -web.wrapRouteGet(app, '/genotype', '/genotype', [], genotypeLandingPageHandler, errorResponse); -web.wrapRouteGet(app, '/genotype/', '/genotype/', [], genotypeLandingPageHandler, errorResponse); +web.wrapRouteGet(app, '/model', '/model', [], modelLandingHandler, errorResponse); +web.wrapRouteGet(app, '/model/', '/model/', [], modelLandingHandler, errorResponse); +web.wrapRouteGet(app, '/genotype', '/genotype', [], genotypeLandingHandler, errorResponse); +web.wrapRouteGet(app, '/genotype/', '/genotype/', [], genotypeLandingHandler, errorResponse); -function getGeneMapping(id) { - var mappedID; - var mappings = engine.mapGeneToNCBIgene(id); - var ncbigene_ids = Object.keys(mappings); - if (ncbigene_ids.length > 0) { - mappedID = mappings[ncbigene_ids[0]]['id']; - } - return mappedID; -} - - -if (false) { /* Disabling all /legacy/xxx and /labs/xxx endpoints that aren't dual-mode */ -// GENE - Sub-pages -// Example: /gene/NCIBGene:12166/phenotype_associations.json -// Currently only works for json or rdf output -app.get('/legacy/gene/:id/:section.:fmt?', function(request, id, section, fmt) { - //Below breaks phenogrid loading due to endless redirect loops - - var mappedID = getGeneMapping(id); - if (typeof mappedID != 'undefined' && mappedID != id){ - engine.log("found updated ID, redirecting to: "+mappedID); - return web.wrapRedirect(genURL('gene',mappedID,fmt)); - } - var info = engine.fetchGeneInfo(id); - - var sectionInfo = - { id: "obo:"+id }; // <-- TODO - unify ID/URI strategy - sectionInfo[section] = info[section]; - engine.addJsonLdContext(sectionInfo); - - if (fmt != null) { - return formattedResults(sectionInfo, fmt,request); - } - else { - return response.error("plain HTML does not work for page sections. Please append .json or .rdf to URL"); - } -}); -} //For receiving of HPO relations for Phenogrid @@ -2568,25 +1999,6 @@ web.wrapRouteGet(app, '/neighborhood/:id/:depth/:direction/:relationship.:fmt?', web.wrapRouteGet(app, '/neighborhood/:id/:depth/:direction/:relationship', '/neighborhood/{id}/{depth}/{direction}/{relationship}', ['id', 'depth', 'direction', 'relationship'], neighborhoodByIdDepthDirectionRelationshipHandler, errorResponse); - - -if (false) { /* Disabling all /legacy/xxx and /labs/xxx endpoints that aren't dual-mode */ -// Status: STUB -// note we hardcode this for now -app.get('/phenome/Homo_sapiens.gff3', function(request, id, fmt) { - - var url = 'http://beta.neuinfo.org/services/v1/federation/data/nlx_152525-9.tsv?q=*&offset=0'; - - var gffStr = httpclient.get(url, {}).content; - return { - body: [gffStr], - headers: {'Content-Type': 'text/plain'}, - status: 200 - }; -}); -} - - // Method: compare // // phenotypic comparison between two entities @@ -2687,45 +2099,10 @@ app.get('/legacy/variant/:id.:fmt?', function(request, id, fmt) { engine.log("redirecting: "+id+" to source at "+url); return web.wrapRedirect(url); }); -} - - -web.wrapRouteGet(app, '/class', '/class', [], - function(request) { - return web.wrapHTML(staticTemplate('class_main')); - }, errorResponse); - -// generic ontology view - most often this will be overridden, e.g. a disease class -// Status: STUB -function classByIdHandler(request, id, fmt) { - var opts = - { - level : request.params.level - }; - - var info = newInfo(engine.fetchClassInfo(id, opts)); // Monarch API is currently a simpler wrapper to OntoQuest - if (fmt != null) { - if (fmt == 'json') { - return formattedResults(info,fmt,request); - } - else { - return response.error("Cannot return results in this format: "+fmt); - } - } - - // adorn object with rendering functions - //info.diseaseTable = function() {return genTableOfDiseaseGeneAssociations(info.disease_associations)} ; - //info.phenotypeTable = function() {return genTableOGenePhenotypeAssociations(info.phenotype_associations)} ; - //info.alleleTable = function() {return genTableOfDiseaseAlleleAssociations(info.alleles)} ; - - return web.wrapHTML(expandTemplate('class', info)); -} - -// Order matters here in the declaration of these routes. -web.wrapRouteGet(app, '/class/:id.:fmt?', '/class/{id}.{fmt}', ['id', 'fmt'], classByIdHandler, errorResponse); -web.wrapRouteGet(app, '/class/:id', '/class/{id}', ['id'], classByIdHandler, errorResponse); +} +if (false) { web.wrapRouteGet(app, '/anatomy', '/anatomy', [], function(request) { var info = prepLandingPage(); @@ -2770,20 +2147,28 @@ function anatomyByIdHandler(request, id, fmt) { //info.phenotypeTable = function() {return genTableOGenePhenotypeAssociations(info.phenotype_associations)} ; //info.alleleTable = function() {return genTableOfDiseaseAlleleAssociations(info.alleles)} ; - var output = pup_tent.render('anatomy.mustache',info,'monarch_base.mustache'); + info.node_label = 'anatomy'; + info.node_logo = '/image/logo.png'; + var output = pup_tent.render('node.mustache', info, 'monarch_base.mustache'); return web.wrapHTML(output); } // Order matters here in the declaration of these routes. web.wrapRouteGet(app, '/anatomy/:id.:fmt?', '/anatomy/{id}.{fmt}', ['id', 'fmt'], anatomyByIdHandler, errorResponse); web.wrapRouteGet(app, '/anatomy/:id', '/anatomy/{id}', ['id'], anatomyByIdHandler, errorResponse); +} +function literatureLandingHandler(request){ -/* Literature Pages */ -web.wrapRouteGet(app, '/literature', '/literature', [], - function(request) { - return web.wrapHTML(staticTemplate('literature_main')); - }, errorResponse); + var info = prepLandingPage(); + info.title = 'Monarch Literature'; + + var output = pup_tent.render('literature_main.mustache', info,'monarch_base.mustache'); + return web.wrapHTML(output); +} + +web.wrapRouteGet(app, '/literature', '/literature', [], literatureLandingHandler, errorResponse); +web.wrapRouteGet(app, '/literature/', '/literature/', [], literatureLandingHandler, errorResponse); function literatureByIdHandler(request, id, fmt) { var info; @@ -2799,15 +2184,15 @@ function literatureByIdHandler(request, id, fmt) { addCoreRenderers(info, 'literature', id); addGolrStaticFiles(info); - + var assoc_filter = [{ field: 'subject_category', value: 'publication', plist : ['-'] }]; - + addGolrTable(info, "source", id, 'association-table', assoc_filter, 'generic_association','#associations'); info.assocNum = engine.fetchAssociationCount(id, 'source', assoc_filter); // Add gene table info.includes.association_anchor = addAssociationAnchor(info); - info.includes.association_table = addAssociationTableWithFilter(); + info.includes.association_table = addAssociationTable(true); var literatureLauncher = 'fetchLiteratureOverview(' + regres[1] + ')'; info.monarch_launchable.push(literatureLauncher); @@ -2857,8 +2242,8 @@ function mapStyleToCategories(style) { } function scoreHandler(request) { - engine.log("Ready to score"); - engine.log("Params:"+JSON.stringify(request.params)); + // engine.log("Ready to score"); + // engine.log("Params:"+JSON.stringify(request.params)); var target = null; var categories = web.getParam(request, 'categories') || []; //default to phenotips categories. @@ -2969,11 +2354,11 @@ web.wrapRoutePost(app, '/simsearch/phenotype/', '/simsearch/phenotype/', [], sim /** * phenoPacketHandler * REST service for returning phenopackets - * + * * request params (in requent.query * @param q - query * @param fq - filters - * @param personality - golr personality + * @param personality - golr personality */ function phenoPacketHandler(request) { // Get params @@ -2984,13 +2369,13 @@ function phenoPacketHandler(request) { if (typeof query === 'undefined') { query = "*:*"; } - + if (typeof showEmptyFields === 'undefined') { showEmptyFields = false; } - + var personality = request.query.personality; - + // Try to determine personality from filters if (typeof personality === 'undefined') { var subject = ""; @@ -3017,26 +2402,26 @@ function phenoPacketHandler(request) { }); personality = subject + "_" + object; } - + var limit = 5000 var response = engine.fetchSolrDocuments(query, filters, personality, limit); var phenopacket = phenoPacketBuilder.buildPhenoPacket(response, personality, showEmptyFields); - + phenopacket.params = { 'q' : query, 'fq' : filters, 'personality' : personality, 'showEmptyFields' : showEmptyFields }; - + var status = getStatus(); - + phenopacket.name = status.name; phenopacket.date = status.date; - + // Comment out until we keep API versions up to date /*var version = status.offerings.filter( - offering => offering.name == 'api_version' + offering => offering.name == 'api_version' && 'value' in offering); if (version.length > 0) { @@ -3407,7 +2792,7 @@ web.wrapRouteGet(app, '/labs/cy-explore-demo', '/labs/cy-explore-demo', [], info.pup_tent_js_libraries.push("/cytoscape.min.js"); info.pup_tent_css_libraries.push("/monarch-labs.css"); info.pup_tent_css_libraries.push("/tour.css"); - + info.monarch_launchable.push('CyExploreDemoInit()'); info.title = 'cy-explore-demo'; @@ -3753,12 +3138,14 @@ function addGolrTable(info, query_field, id, div, filter, personality, anchor) { var replacer = new RegExp('-', 'g'); //There has to be a better way - var id_var = "query_id_" + bbop.core.uuid().replace(replacer, ''); - var field_var = "query_field_" + bbop.core.uuid().replace(replacer, ''); - var div_var = "query_div_" + bbop.core.uuid().replace(replacer, ''); - var filt_var = "filter_" + bbop.core.uuid().replace(replacer, ''); - var person_var = "person_" + bbop.core.uuid().replace(replacer, ''); - var anchor_var = "anchor_" + bbop.core.uuid().replace(replacer, ''); + var suffix = bbop.core.uuid().replace(replacer, ''); + var id_var = "query_id_" + suffix; + var field_var = "query_field_" + suffix; + var div_var = "query_div_" + suffix; + var filt_var = "filter_" + suffix; + var person_var = "person_" + suffix; + var anchor_var = "anchor_" + suffix; + var is_leaf_var = "is_leaf_" + suffix; var launch = ''; info.pup_tent_js_variables.push({name: id_var, value: id}); @@ -3766,12 +3153,13 @@ function addGolrTable(info, query_field, id, div, filter, personality, anchor) { info.pup_tent_js_variables.push({name: div_var, value: div}); info.pup_tent_js_variables.push({name: person_var, value: personality}); info.pup_tent_js_variables.push({name: anchor_var, value: anchor}); - info.pup_tent_js_variables.push({name: filt_var, value: filter}); + info.pup_tent_js_variables.push({name: is_leaf_var, value: info.isLeafNode}); + launch = 'getTableFromSolr(' + id_var + ', ' + field_var + ', ' + div_var + ', ' + filt_var + ', ' - + person_var + ', ' + anchor_var +')'; - + + person_var + ', ' + anchor_var + + ', ' + is_leaf_var + ')'; info.monarch_launchable.push(launch); } @@ -3806,101 +3194,83 @@ app.get('/labs/widget-scratch', function phenotypeByIdHandler(request, id, fmt){ - engine.log("PhenotypeID= "+id); - - //Curify ID if needed - if (/_/.test(id) && !/\:/.test(id)){ - engine.log("ID contains underscore, replacing with : and redirecting"); - var newID = id.replace("_",":"); - return web.wrapRedirect(genURL('phenotype',newID)); - } - - // Rendering. - var info = newInfo(engine.fetchClassInfo(id, {level:1})); - - if (fmt != null) { - // TODO - return formattedResults(info, fmt, request); - } - - addCoreRenderers(info, 'phenotype', id); - addGolrStaticFiles(info); - // info.pup_tent_css_libraries.push("/monarch-specific.css"); - - //Load variables for client side tables - var disease_filter = [{ field: 'subject_category', value: 'disease' }]; - addGolrTable(info, "object_closure", id, 'disease-table', disease_filter, 'disease_phenotype',"#diseases"); - info.diseaseNum = engine.fetchAssociationCount(id, 'object_closure', disease_filter, 'subject'); - - var gene_filter = [{ field: 'subject_category', value: 'gene' }]; - addGolrTable(info, "object_closure", id, 'gene-table', gene_filter, 'gene_phenotype', "#genes"); - info.geneNum = engine.fetchAssociationCount(id, 'object_closure', gene_filter, 'subject'); + //Curify ID if needed + if (/_/.test(id) && !/\:/.test(id)){ + engine.log("ID contains underscore, replacing with : and redirecting"); + var newID = id.replace("_",":"); + return web.wrapRedirect(genURL('phenotype',newID)); + } - var genotype_filter = [{ field: 'subject_category', value: 'genotype' }]; - addGolrTable(info, "object_closure", id, 'genotype-table', genotype_filter, 'genotype_phenotype',"#genotypes"); - info.genotypeNum = engine.fetchAssociationCount(id, 'object_closure', genotype_filter, 'subject'); + // Rendering. + var info = newInfo(engine.fetchClassInfo(id, {level:1})); - var model_filter = [{ field: 'subject_category', value: 'model' }]; - addGolrTable(info, "object_closure", id, 'model-table', model_filter, 'genotype_phenotype',"#models"); - info.modelNum = engine.fetchAssociationCount(id, 'object_closure', model_filter, 'subject'); + if (fmt != null) { + // TODO + return formattedResults(info, fmt, request); + } - var variant_filter = [{ field: 'subject_category', value: 'variant' }]; - addGolrTable(info, "object_closure", id, 'variant-table', variant_filter, 'variant_phenotype',"#variants"); - info.variantNum = engine.fetchAssociationCount(id, 'object_closure', variant_filter, 'subject'); + addCoreRenderers(info, 'phenotype', id); + addGolrStaticFiles(info); + // info.pup_tent_css_libraries.push("/monarch-specific.css"); - // Add templates - info.includes.disease_anchor = addDiseaseAnchor(info); - info.includes.disease_table = addDiseaseTable(); + //Load variables for client side tables + var disease_filter = [{ field: 'subject_category', value: 'disease' }]; + addGolrTable(info, "object_closure", id, 'disease-table', disease_filter, 'disease_phenotype',"#diseases"); + info.diseaseNum = engine.fetchAssociationCount(id, 'object_closure', disease_filter, 'subject'); - // Add gene table - info.includes.gene_anchor = addGeneAnchor(info); - info.includes.gene_table = addGeneTableWithFilter(); + var gene_filter = [{ field: 'subject_category', value: 'gene' }]; + addGolrTable(info, "object_closure", id, 'gene-table', gene_filter, 'gene_phenotype', "#genes"); + info.geneNum = engine.fetchAssociationCount(id, 'object_closure', gene_filter, 'subject'); - // Add genotype table - info.includes.genotype_anchor = addGenotypeAnchor(info); - info.includes.genotype_table = addGenotypeTableWithFilter(); + var genotype_filter = [{ field: 'subject_category', value: 'genotype' }]; + addGolrTable(info, "object_closure", id, 'genotype-table', genotype_filter, 'genotype_phenotype',"#genotypes"); + info.genotypeNum = engine.fetchAssociationCount(id, 'object_closure', genotype_filter, 'subject'); - // Add model table - info.includes.model_anchor = addModelAnchor(info); - info.includes.model_table = addModelTable(); + var model_filter = [{ field: 'subject_category', value: 'model' }]; + addGolrTable(info, "object_closure", id, 'model-table', model_filter, 'genotype_phenotype',"#models"); + info.modelNum = engine.fetchAssociationCount(id, 'object_closure', model_filter, 'subject'); - // Add variant table - info.includes.variant_anchor = addVariantAnchor(info); - info.includes.variant_table = addVariantTableWithFilter(); + var variant_filter = [{ field: 'subject_category', value: 'variant' }]; + addGolrTable(info, "object_closure", id, 'variant-table', variant_filter, 'variant_phenotype',"#variants"); + info.variantNum = engine.fetchAssociationCount(id, 'object_closure', variant_filter, 'subject'); - if (typeof info.synonyms != 'undefined'){ - info.aka = info.synonyms.join(", "); - } + addNonEmptyAnchors(info); - info.xrefs = function() { - if (info.database_cross_reference != null) { - return info.database_cross_reference.map(function(r) { return genExternalHref('source',{id : r}) }).join(", "); - //return info.database_cross_reference.join(", "); - } - }; + if (typeof info.synonyms != 'undefined'){ + info.aka = info.synonyms.join(", "); + } - if (info.equivalentClasses){ - info.equivalentClasses = info.equivalentClasses.join(", "); - } + if (info.equivalentClasses){ + info.equivalentClasses = info.equivalentClasses.join(", "); + } - info.title = 'Monarch Phenotype: '+info.label+' ('+ info.id+')'; + info.title = 'Monarch Phenotype: '+info.label+' ('+ info.id+')'; - // variables checking existence of data in sections - info.hasDef = function() {return checkExistence(info.definitions)}; - info.hasAka = function() {return checkExistence(info.synonyms)}; - info.hasXrefs = function() {return checkExistence(info.database_cross_reference)}; - info.hasEqual = function() {return checkExistence(info.equivalentClasses)}; - info.hasGenes = true; + info.primary_xref = function() {return genExternalHref('source', {id : id})}; + info.xrefs = function() { + return buildXrefsList(id, info.database_cross_reference); + }; + info.hasXrefs = function() {return checkExistence(info.database_cross_reference) || !!info.primary_xref}; - //Variables and launcher for ontology view - info.pup_tent_js_variables.push({name:'globalID',value:id}); - info.pup_tent_js_variables.push({name:'globalLabel',value:info.label}); - info.pup_tent_js_variables.push({name:'phenotype_root',value:'UPHENO:0001001'}); - info.monarch_launchable.push("getOntologyBrowser(globalID, globalLabel, phenotype_root)"); + // variables checking existence of data in sections + info.hasDef = function() {return checkExistence(info.definitions)}; + info.hasAka = function() {return checkExistence(info.synonyms)}; + info.hasEqual = function() {return checkExistence(info.equivalentClasses)}; + info.hasGenes = true; - var output = pup_tent.render('phenotype.mustache', info, - 'monarch_base.mustache'); - return web.wrapHTML(output); + //Variables and launcher for ontology view + info.pup_tent_js_variables.push({name:'globalID',value:id}); + info.pup_tent_js_variables.push({name:'globalLabel',value:info.label}); + info.pup_tent_js_variables.push({name:'phenotype_root',value:'UPHENO:0001001'}); + info.classificationBrowserURL = 'https://github.com/obophenotype/upheno'; + info.hasBrw = true; + info.monarch_launchable.push("getOntologyBrowser(globalID, globalLabel, phenotype_root)"); + + info.node_label = 'Phenotype'; + info.node_logo = '/image/carousel-phenotypes.png'; + var output = pup_tent.render('node.mustache', info, + 'monarch_base.mustache'); + return web.wrapHTML(output); } web.wrapRouteGet(app, '/phenotype/:id.:fmt?', '/phenotype/{id}.{fmt}', ['id', 'fmt'], phenotypeByIdHandler, errorResponse); @@ -3932,9 +3302,24 @@ web.wrapRouteGet(app, '/phenotype/:id/:section.:fmt', '/phenotype/{id}/{section} web.wrapRouteGet(app, '/phenotype/:id/:section', '/phenotype/{id}/{section}', ['id', 'section'], phenotypeByIdSectionHandler, errorResponse); +function buildXrefsList(id, database_cross_reference) { + var xrefs = []; + if (database_cross_reference != null) { + for (var xref_key in database_cross_reference) { + var xref = database_cross_reference[xref_key]; + if (xref !== id) { + xrefs.push(genExternalHref('source', {id: xref})); + } + } + } + xrefs.unshift(genExternalHref('source', {id: id})); + var result = xrefs.join(', '); + return result; +} + function diseaseByIdHandler(request, id, fmt) { - engine.log("getting /disease/:id where id="+id + " fmt=" + fmt); + // engine.log("getting /disease/:id where id="+id + " fmt=" + fmt); //Curify ID if needed if (/_/.test(id)){ @@ -3966,7 +3351,7 @@ function diseaseByIdHandler(request, id, fmt) { var phenotype_filter = [{ field: 'object_category', value: 'phenotype' }, { field: 'subject_category', value: 'disease' }]; addGolrTable(info, "subject_closure", id, 'phenotypes-table', phenotype_filter, 'disease_phenotype','#phenotypes'); - info.phenotypeNum = engine.fetchAssociationCount(id, 'subject_closure', phenotype_filter); + info.phenotypeNum = engine.fetchAssociationCount(id, 'subject_closure', phenotype_filter, 'object'); var gene_filter = [ { field: 'subject_category', value: 'gene' }, @@ -3995,66 +3380,35 @@ function diseaseByIdHandler(request, id, fmt) { addGolrTable(info, "subject_closure", id, 'pathway-table', pathway_filter, 'disease_pathway','#pathways'); info.pathwayNum = engine.fetchAssociationCount(id, 'subject_closure', pathway_filter, 'object'); - /*var literature_filter = [{ field: 'subject_category', value: 'publication' }, - { field: 'object_category', value: 'disease' }]; + var literature_filter = [{ field: 'subject_category', value: 'publication' }, + { field: 'object_category', value: 'disease' }]; addGolrTable(info, "object_closure", id, 'literature-table', literature_filter, 'lit_disease_disp','#literature'); - info.literatureNum = engine.fetchAssociationCount(id, 'object_closure', literature_filter, 'subject');*/ + info.literatureNum = engine.fetchAssociationCount(id, 'object_closure', literature_filter, 'subject'); // Phenogrid addPhenogridFiles(info); - // Add templates - info.includes.phenotype_anchor = addPhenotypeAnchor(info); - info.includes.phenotype_table = addPhenotypeTable(info); - - // Add gene table - info.includes.gene_anchor = addGeneAnchor(info); - info.includes.gene_table = addGeneTableWithFilter(); - - // Add genotype table - info.includes.genotype_anchor = addGenotypeAnchor(info); - info.includes.genotype_table = addGenotypeTableWithFilter(); - - // Add model table - info.includes.model_anchor = addModelAnchor(info); - info.includes.model_table = addModelTableWithFilter(); + addNonEmptyAnchors(info); - // Add variant table - info.includes.variant_anchor = addVariantAnchor(info); - info.includes.variant_table = addVariantTableWithFilter(); - - // Add pathway table - info.includes.pathway_anchor = addPathwayAnchor(info); - info.includes.pathway_table = addPathwayTable(); - - // Add publication table - info.includes.literature_anchor = addLiteratureAnchor(info); - info.includes.literature_table = addLiteratureTable(); info.title = 'Monarch Disease: '+info.label+' ('+ info.id+')'; info.primary_xref = function() {return genExternalHref('source',{id : id})}; + info.xrefs = function() { + return buildXrefsList(id, info.database_cross_reference); + }; + info.hasXrefs = function() {return checkExistence(info.database_cross_reference) || !!info.primary_xref}; if (typeof info.synonyms != 'undefined'){ info.aka = info.synonyms.join(", "); } - info.xrefs = function() { - if (info.database_cross_reference != null) { - return info.database_cross_reference.map(function(r) { return genExternalHref('source',{id : r}) }).join(", "); - //return info.database_cross_reference.join(", "); - } - }; info.altids = function() { if (info.has_alternative_id != null) { return info.has_alternative_id.join(", "); } } - if (info.equivalentClasses){ - info.equivalentClasses = info.equivalentClasses.join(", "); - } - //info.hasHeritability = function() {return checkExistence(info.heritability)}; //info.heritability = engine.unique(info.heritability.map(function(h) {return h.inheritance.label})).join(", "); @@ -4062,7 +3416,6 @@ function diseaseByIdHandler(request, id, fmt) { info.hasDef = function() {return checkExistence(info.definitions)}; info.hasComment = function() {return checkExistence(info.comment)}; info.hasAka = function() {return checkExistence(info.synonyms)}; - info.hasXrefs = function() {return checkExistence(info.database_cross_reference)}; info.hasEqual = function() {return checkExistence(info.equivalentClasses)}; info.hasPhenotypes = info.phenotypeNum; if (info.phenotypeNum > 10000){ @@ -4075,6 +3428,8 @@ function diseaseByIdHandler(request, id, fmt) { info.pup_tent_js_variables.push({name:'globalID',value:id}); info.pup_tent_js_variables.push({name:'globalLabel',value:info.label}); info.pup_tent_js_variables.push({name:'root',value:'DOID:4'}); + info.classificationBrowserURL = 'https://github.com/monarch-initiative/monarch-disease-ontology'; + info.hasBrw = true; info.monarch_launchable.push("getOntologyBrowser(globalID, globalLabel, root)"); var output; @@ -4082,21 +3437,26 @@ function diseaseByIdHandler(request, id, fmt) { if (info.isLeafNode){ info.pup_tent_js_variables.push({name:'globalID',value:id}); info.monarch_launchable.push('getAnnotationScore(globalID)'); - if (info.hasPhenotypes){ - info.pup_tent_js_libraries.push("/phenogridloader-no-species.js"); - info.monarch_launchable.push('loadPhenogrid()'); - } - output = pup_tent.render('disease.mustache', info, - 'monarch_base.mustache'); - } else { - if (info.hasPhenotypes){ - info.pup_tent_js_libraries.push("/phenogridloader-onclick.js"); - info.monarch_launchable.push('loadPhenogrid()'); - } - output = pup_tent.render('disease-non-leaf.mustache', info, - 'monarch_base.mustache'); } + if (info.hasPhenotypes){ + info.pup_tent_js_libraries.push("/phenogridloader-onclick.js"); + info.monarch_launchable.push('loadPhenogrid()'); + } + info.node_label = 'Disease'; + info.node_logo = '/image/carousel-diseases.png'; + output = pup_tent.render('node.mustache', info, 'monarch_base.mustache'); + // } else { + // if (info.hasPhenotypes){ + // info.pup_tent_js_libraries.push("/phenogridloader-onclick.js"); + // info.monarch_launchable.push('loadPhenogrid()'); + // } + // info.node_label = 'Disease Group'; + // info.node_logo = '/image/carousel-diseases.png'; + // output = pup_tent.render('node.mustache', info, + // 'monarch_base.mustache'); + // } + return web.wrapHTML(output); } @@ -4129,11 +3489,6 @@ web.wrapRouteGet(app, '/disease/:id/:section', '/disease/{id}/{section}', ['id', function fetchFeatureSection(request, id, section, fmt) { - - if (!/.*[:].*/.test(id)) { - id = ':' + id; - } - var info = engine.fetchSectionInfo(id, section); var sectionInfo = @@ -4208,11 +3563,11 @@ function geneByIdHandler(request, id, fmt) { var pathway_filter = [{ field: 'object_category', value: 'pathway' }]; addGolrTable(info, "subject_closure", id, 'pathway-table', pathway_filter, 'gene_pathway','#pathways'); info.pathwayNum = engine.fetchAssociationCount(id, 'subject_closure', pathway_filter, 'object'); - + var ortho_phenotype_filter = [{ field: 'object_category', value: 'phenotype' }]; addGolrTable(info, "subject_ortholog_closure", info.cliqueLeader, 'ortholog-phenotype-table', ortho_phenotype_filter, 'gene_phenotype','#ortholog-phenotypes'); - + info.orthoPhenoNum = engine.fetchAssociationCount(info.cliqueLeader, 'subject_ortholog_closure', ortho_phenotype_filter, 'object'); // Phenogrid @@ -4245,14 +3600,22 @@ function geneByIdHandler(request, id, fmt) { // Add pathway table info.includes.pathway_anchor = addPathwayAnchor(info); info.includes.pathway_table = addPathwayTable(); - + // Add ortholog phenotype table info.includes.ortholog_phenotype_anchor = addOrthoPhenoAnchor(info); info.includes.ortholog_phenotype_table = addOrthoPhenoTable(); + + // hack to inhibit species filters which isn't working on Gene page for some reason. + addNonEmptyAnchors(info, true); + info.title = 'Monarch Gene: '+info.label+' ('+ info.id+')'; - info.primary_xref = function() {return genExternalHref('source',{id : id})}; + info.primary_xref = function() {return genExternalHref('source', {id : id})}; + info.xrefs = function() { + return buildXrefsList(id, info.database_cross_reference); + }; + info.hasXrefs = function() {return checkExistence(info.database_cross_reference) || !!info.primary_xref}; if (info.taxon){ info.taxon_xref = function() {return genExternalHref('source',info.taxon)}; @@ -4268,12 +3631,6 @@ function geneByIdHandler(request, id, fmt) { } } - info.xrefs = function() { - if (info.database_cross_reference != null) { - return info.database_cross_reference.map(function(r) { return genExternalHref('source',{id : r}) }).join(", "); - //return info.database_cross_reference.join(", "); - } - }; info.altids = function() { if (info.has_alternative_id != null) { return info.has_alternative_id.join(", "); @@ -4284,7 +3641,6 @@ function geneByIdHandler(request, id, fmt) { info.hasDef = function() {return checkExistence(info.definitions)}; info.hasComment = function() {return checkExistence(info.comment)}; info.hasAka = function() {return checkExistence(info.synonyms)}; - info.hasXrefs = function() {return checkExistence(info.database_cross_reference)}; info.hasEqual = function() {return checkExistence(info.equivalentClasses)}; info.hasPhenotypes = info.phenotypeNum; @@ -4295,13 +3651,15 @@ function geneByIdHandler(request, id, fmt) { info.monarch_launchable.push(myGeneLauncher); if (info.hasPhenotypes){ - info.pup_tent_js_libraries.push("/phenogridloader-no-species.js"); + info.pup_tent_js_libraries.push("/phenogridloader-onclick.js"); info.monarch_launchable.push('loadPhenogrid()'); } info.includes.phenogrid_anchor = expandTemplate('phenogrid-anchor', info); - var output = pup_tent.render('gene.mustache', info, + info.node_label = 'Gene'; + info.node_logo = '/image/carousel-genes.png'; + var output = pup_tent.render('node.mustache', info, 'monarch_base.mustache'); return web.wrapHTML(output); @@ -4386,7 +3744,7 @@ function variantByIdHandler(request, id, fmt) { var newID = id.replace("_",":"); return web.wrapRedirect(genURL('variant',newID)); } - + // OMIM variants have a period in the ID, add back to id and // set format to null, TODO account for actual .json format if (id.match(/^OMIM/)){ @@ -4430,29 +3788,15 @@ function variantByIdHandler(request, id, fmt) { // Phenogrid addPhenogridFiles(info); - // Add templates - info.includes.phenotype_anchor = addPhenotypeAnchor(info); - info.includes.phenotype_table = addPhenotypeTable(info); - - // Add gene table - info.includes.disease_anchor = addDiseaseAnchor(info); - info.includes.disease_table = addDiseaseTable(); - - // Add gene table - info.includes.gene_anchor = addGeneAnchor(info); - info.includes.gene_table = addGeneTable(); - - // Add genotype table - info.includes.genotype_anchor = addGenotypeAnchor(info); - info.includes.genotype_table = addGenotypeTable(); - - // Add model table - info.includes.model_anchor = addModelAnchor(info); - info.includes.model_table = addModelTable(); + addNonEmptyAnchors(info, true); info.title = 'Monarch Variant: '+info.label+' ('+ info.id+')'; - info.primary_xref = function() {return genExternalHref('source',{id : id})}; + info.primary_xref = function() {return genExternalHref('source', {id : id})}; + info.xrefs = function() { + return buildXrefsList(id, info.database_cross_reference); + }; + info.hasXrefs = function() {return checkExistence(info.database_cross_reference) || !!info.primary_xref}; if (info.taxon){ info.taxon_xref = function() {return genExternalHref('source',info.taxon)}; @@ -4468,12 +3812,6 @@ function variantByIdHandler(request, id, fmt) { } } - info.xrefs = function() { - if (info.database_cross_reference != null) { - return info.database_cross_reference.map(function(r) { return genExternalHref('source',{id : r}) }).join(", "); - //return info.database_cross_reference.join(", "); - } - }; info.altids = function() { if (info.has_alternative_id != null) { return info.has_alternative_id.join(", "); @@ -4493,10 +3831,9 @@ function variantByIdHandler(request, id, fmt) { info.hasAka = function() {return checkExistence(info.synonyms)}; info.hasTypes= function() {return checkExistence(info.categories)}; info.hasEqual = function() {return checkExistence(info.equivalentClasses)}; - info.hasXrefs = function() {return checkExistence(info.database_cross_reference)}; if (info.hasPhenotypes){ - info.pup_tent_js_libraries.push("/phenogridloader-no-species.js"); + info.pup_tent_js_libraries.push("/phenogridloader-onclick.js"); info.monarch_launchable.push('loadPhenogrid()'); } @@ -4506,7 +3843,9 @@ function variantByIdHandler(request, id, fmt) { info.pup_tent_js_variables.push({name:'globalID',value:id}); info.monarch_launchable.push('getAnnotationScore(globalID)'); - var output = pup_tent.render('variant.mustache', info, + info.node_label = 'Variant'; + info.node_logo = '/image/logo.png'; + var output = pup_tent.render('node.mustache', info, 'monarch_base.mustache'); return web.wrapHTML(output); @@ -4520,17 +3859,15 @@ function variantByIdHandler(request, id, fmt) { web.wrapRouteGet(app, '/variant/:id.:fmt?', '/variant/{id}.{fmt}', ['id', 'fmt'], variantByIdHandler, errorResponse); web.wrapRouteGet(app, '/variant/:id', '/variant/{id}', ['id'], variantByIdHandler, errorResponse); - - //Sequence Feature - Sub-pages //Example: /gene/NCIBGene:12166/phenotype_associations.json //Currently only works for json or rdf output +// TODO: DELETE THIS: SEE: https://github.com/monarch-initiative/monarch-app/issues/975#issuecomment-238665637 web.wrapRouteGet(app, '/gene/:id/:section.:fmt?', '/gene/{id}/{section}.{fmt?}', ['id', 'section', 'fmt'], fetchFeatureSection); web.wrapRouteGet(app, '/variant/:id/:section.:fmt?', '/variant/{id}/{section}.{fmt?}', ['id', 'section', 'fmt'], fetchFeatureSection); web.wrapRouteGet(app, '/genotype/:id/:section.:fmt?', '/genotype/{id}/{section}.{fmt?}', ['id', 'section', 'fmt'], fetchFeatureSection); web.wrapRouteGet(app, '/model/:id/:section.:fmt?', '/model/{id}/{section}.{fmt?}', ['id', 'section', 'fmt'], fetchFeatureSection); -web.wrapRouteGet(app, '/case/:id/:section.:fmt?', '/case/{id}/{section}.{fmt?}', ['id', 'section', 'fmt'], fetchFeatureSection); if (false) { /* Disabling all /legacy/xxx and /labs/xxx endpoints that aren't dual-mode */ @@ -4553,7 +3890,7 @@ app.get('/labs/case/:id', function(request, id, fmt){ addCoreRenderers(info, 'patient', id); addPhenogridFiles(info); - info.pup_tent_js_libraries.push("/phenogridloader-no-species.js"); + info.pup_tent_js_libraries.push("/phenogridloader-onclick.js"); info.monarch_launchable.push('loadPhenogrid()'); info.hasPhenotypes = true; @@ -4623,18 +3960,16 @@ function associationByIdHandler(request, id, fmt){ info.title = 'Monarch Association: '+info.label+' ('+ info.id+')'; - info.primary_xref = function() {return genExternalHref('source',{id : id})}; + info.primary_xref = function() {return genExternalHref('source', {id : id})}; + info.xrefs = function() { + return buildXrefsList(id, info.database_cross_reference); + }; + info.hasXrefs = function() {return checkExistence(info.database_cross_reference) || !!info.primary_xref}; if (typeof info.synonyms != 'undefined'){ info.aka = info.synonyms.join(", "); } - info.xrefs = function() { - if (info.database_cross_reference != null) { - return info.database_cross_reference.map(function(r) { return genExternalHref('source',{id : r}) }).join(", "); - //return info.database_cross_reference.join(", "); - } - }; info.altids = function() { if (info.has_alternative_id != null) { return info.has_alternative_id.join(", "); @@ -4645,7 +3980,6 @@ function associationByIdHandler(request, id, fmt){ info.hasDef = function() {return checkExistence(info.definitions)}; info.hasComment = function() {return checkExistence(info.comment)}; info.hasAka = function() {return checkExistence(info.synonyms)}; - info.hasXrefs = function() {return checkExistence(info.database_cross_reference)}; var output = pup_tent.render('associations.mustache', info, 'monarch_base.mustache'); @@ -4686,17 +4020,11 @@ function addDiseaseAnchor(info) { return expandTemplate('anchor', disease_anchor); } -function addDiseaseTable() { - var disease_table = {href: "diseases", div: "disease-table"}; - return expandTemplate('golr-table', disease_table); -} - -function addDiseaseTableWithFilter() { - var disease_table = {href: "diseases", div: "disease-table", filter: true}; +function addDiseaseTable(with_filter) { + var disease_table = {href: "diseases", div: "disease-table", filter: with_filter}; return expandTemplate('golr-table', disease_table); } - function addGeneAnchor(info) { var gene_anchor = {id: info.id, resultNum: info.geneNum, @@ -4704,8 +4032,8 @@ function addGeneAnchor(info) { return expandTemplate('anchor', gene_anchor); } -function addGeneTableWithFilter() { - var gene_table = {href: "genes", div: "gene-table", filter: true} +function addGeneTable(with_filter) { + var gene_table = {href: "genes", div: "gene-table", filter: with_filter} return expandTemplate('golr-table', gene_table); } @@ -4716,13 +4044,8 @@ function addAssociationAnchor(info) { return expandTemplate('association-anchor', assoc_anchor); } -function addAssociationTableWithFilter() { - var gene_table = {href: "associations", div: "association-table", filter: true} - return expandTemplate('golr-table', gene_table); -} - -function addGeneTable() { - var gene_table = {href: "genes", div: "gene-table"} +function addAssociationTable(with_filter) { + var gene_table = {href: "associations", div: "association-table", filter: with_filter} return expandTemplate('golr-table', gene_table); } @@ -4733,15 +4056,11 @@ function addModelAnchor(info) { return expandTemplate('anchor', model_anchor); } -function addModelTable() { - var model_table = {href: "models", div: "model-table"}; +function addModelTable(with_filter) { + var model_table = {href: "models", div: "model-table", filter: with_filter}; return expandTemplate('golr-table', model_table); } -function addModelTableWithFilter() { - var model_table = {href: "models", div: "model-table", filter: true}; - return expandTemplate('golr-table', model_table); -} function addVariantAnchor(info) { var variant_anchor = {id: info.id, type: "Variants", @@ -4750,13 +4069,8 @@ function addVariantAnchor(info) { return expandTemplate('anchor', variant_anchor); } -function addVariantTable() { - var variant_table = {href: "variants", div: "variant-table"}; - return expandTemplate('golr-table', variant_table); -} - -function addVariantTableWithFilter() { - var variant_table = {href: "variants", div: "variant-table", filter: true}; +function addVariantTable(with_filter) { + var variant_table = {href: "variants", div: "variant-table", filter: with_filter}; return expandTemplate('golr-table', variant_table); } @@ -4791,13 +4105,8 @@ function addGenotypeAnchor(info) { return expandTemplate('anchor', genotype_anchor); } -function addGenotypeTable() { - var genotype_table = {href: "genotypes", div: "genotype-table"}; - return expandTemplate('golr-table', genotype_table); -} - -function addGenotypeTableWithFilter() { - var genotype_table = {href: "genotypes", div: "genotype-table", filter: true}; +function addGenotypeTable(with_filter) { + var genotype_table = {href: "genotypes", div: "genotype-table", filter: with_filter}; return expandTemplate('golr-table', genotype_table); } @@ -4816,7 +4125,7 @@ function addLiteratureTable() { function addOrthoPhenoAnchor(info) { var ortho_pheno_anchor = {id: info.id, resultNum: info.orthoPhenoNum, - type: "Homolog-Phenotypes", href: "ortholog-phenotypes"}; + type: "Ortholog-Phenotypes", href: "ortholog-phenotypes"}; return expandTemplate('anchor', ortho_pheno_anchor); } @@ -4937,107 +4246,6 @@ function notFoundHandler(request) { web.wrapRouteGet(app, '/*', '/{other*}', [], notFoundHandler, errorResponse); -if (false) { /* Disabling all /legacy/xxx and /labs/xxx endpoints that aren't dual-mode */ -//TODO Delete -app.get('/labs/gene/:id.:fmt?', function(request, id, fmt) { - - //Redirect to NCBI Gene ID - var mappedID = getGeneMapping(id); - if (typeof mappedID != 'undefined' && mappedID != id){ - engine.log("found updated ID, redirecting to: "+mappedID); - return web.wrapRedirect(genURL('gene',mappedID)); - } - - var info; - try { - info = engine.fetchGeneInfo(id); - } - catch(err) { - return errorResponseWithObject(err); - } - - if (fmt != null) { - return formattedResults(info,fmt,request); - } - - // HTML - addCoreRenderers(info, 'gene', id); - - //Add pup_tent libs - // info.pup_tent_css_libraries.push("/monarch-specific.css"); - info.pup_tent_css_libraries.push("/imagehover.css"); - - // info.pup_tent_js_libraries.push("/stupidtable.min.js"); - // info.pup_tent_js_libraries.push("/tables.js"); - info.monarch_launchable.push('InitTables()'); - - addPhenogridFiles(info); - - info.pup_tent_js_libraries.push("/phenogridloader-no-species.js"); - info.monarch_launchable.push('loadPhenogrid()'); - - info.title = 'Monarch Gene: '+info.label+' ('+ info.id+')'; - - // variables checking existence of data in sections - info.hasPhenotypes = function() {return checkExistence(info.phenotype_associations)}; - info.hasPathways = function() {return checkExistence(info.pathway_associations)}; - info.hasDiseases = function() {return checkExistence(info.disease_associations)}; - info.hasGenotypes = function() {return checkExistence(info.genotype_associations)}; - info.hasLocation = function() {return checkExistence(info.location)}; - info.hasAlleles = function() {return checkExistence(info.alleles)}; - info.hasOrthologs = function() {return checkExistence(info.orthologs)}; - info.hasInteractions = function() {return checkExistence(info.interactions)}; - info.hasSummary = function() {return checkExistence(info.summary)}; - info.hasLiterature = function() {return checkExistence(info.literature)}; - info.hasSynonym = function() {return checkExistence(info.synonyms)}; - - //info.phenotypeNum = function() {return getNumLabel(info.phenotype_associations)}; - info.phenotypeNum = function() { - if (info.phenotype_associations != null) { - return getNumLabel(engine.unique(info.phenotype_associations.map(function(p) {return p.phenotype.id})))}; - return 0; - }; - - info.genotypeNum = function() {return getNumLabel(info.genotype_associations)}; - info.pathwayNum = function() {return getNumLabel(info.pathway_associations)}; - info.diseaseNum = function() {return getNumLabel(info.disease_associations)}; - info.alleleNum = function() {return getNumLabel(info.alleles)}; - info.orthologNum = function() {return getNumLabel(info.orthologs)}; - info.interactionNum = function() {return getNumLabel(info.interactions)}; - info.literatureNum = function() {return getNumLabel(info.pmidinfo)}; - - // adorn object with rendering functions - info.phenotypeTable = function() {return genTableOfGenePhenotypeAssociations(info.phenotype_associations);}; - info.pathwayTable = function() {return genTableOfGenePathwayAssociations(info.pathway_associations);}; - info.diseaseTable = function() {return genTableOfGeneDiseaseAssociations(info.disease_associations);}; - info.genotypeTable = function() {return genTableOfGeneGenotypeAssociations(info.genotype_associations);}; - info.alleleTable = function() {return genTableOfGeneAlleleAssociations(info.alleles);}; - info.orthologTable = function() {return genTableOfGeneOrthologAssociations(info.orthologs);}; - info.interactionTable = function() {return genTableOfGeneInteractionAssociations(info.interactions);}; - info.literatureTable = function() {return genTableOfLiterature(info.literature, info.pmidinfo);}; - - info.primary_xref = function() {return genExternalHref('source',{id : info.id})}; - info.xrefTable = function() {return genTableOfGeneXRefs(info.xrefs);}; - - info.annotationScore = function() { - if (info.annotation_sufficiency != null) { - return (5 * info.annotation_sufficiency); - } else { - return 0; - } - }; - - //Link out to NCBI - info.taxon_xref; - - if (info.taxon){ - info.taxon_xref = function() {return genExternalHref('source',info.taxon)}; - } - - var output = pup_tent.render('gene-jbrowse.mustache',info,'monarch_base.mustache'); - return response.html(output); -}); -} function analyzeByDatatypePostHandler(request, datatype, fmt) { @@ -5470,30 +4678,79 @@ if (false) { /* Disabling all /legacy/xxx and /labs/xxx endpoints that aren't du } +function faviconHandler(request, fmt) { + var path = './image/favicon.ico'; + return wrapContentOrError(path); +} + +web.wrapRouteGet(app, '/favicon.ico', '/favicon.ico', [], faviconHandler, errorResponse); + function resolveByIdHandler(request, id, fmt) { - var returnFunc; - - if (!/^UDP/.test(id)) { - id = engine.convertIdToCurie(id); - } + var result; + + id = engine.convertIdToCurie(id); var type = engine.resolveIdToType(id); if (type) { - returnFunc = web.wrapRedirect(genURL(type, id)); + result = web.wrapRedirect(genURL(type, id)); } else { - engine.log(id); - returnFunc = notFoundResponse("Cannot find "+id); + // engine.log('Unable to resolve id: ' + id); + result = notFoundResponse('Unable to resolve id: ' + id); + } + + return result; +} + +// +// Same as the above resolveByIdHandler(), but only continues if the converted ID +// looks like a CURIE. This is to avoid pinging SciGraph unnecessarily when a scraper +// or client error tries to GET a path like /foo, which isn't intended to be an ID. +// +// This handler also deals with files like 'apple-touch-icon' by returning the favicon.ico +// when requested. This is to avoid useless log messages in our server. See: +// http://stackoverflow.com/questions/5110776/apple-touch-icon-for-websites/21144916#21144916 +// +// For the /resolve/ID endpoint handler (above), we can assume the user knows what they are doing and +// can pass the purported ID through to SciGraph without checking. This will eventually +// let us handle any cases where we want to have non-CURIE strings resolved via the /resolve +// endpoint (although one could argue that would be a different endpoint). +// + +function rootPathHandler(request, id, fmt) { + var result; + + if (id.indexOf('apple-touch-icon') === 0) { + result = faviconHandler(request, id); + } + else { + id = engine.convertIdToCurie(id); + + if (id.indexOf(':') === -1) { + result = notFoundResponse('No such path: ' + id); + } + else { + var type = engine.resolveIdToType(id); + if (type) { + result = web.wrapRedirect(genURL(type, id)); + } + else { + // engine.log('Unable to resolve id: ' + id); + result = notFoundResponse('Unable to resolve id: ' + id); + } + } } - return returnFunc; + + return result; } + // Order matters here in the declaration of these routes. web.wrapRouteGet(app, '/resolve/:id.:fmt?', '/resolve/{id}.{fmt}', ['id', 'fmt'], resolveByIdHandler, errorResponse); web.wrapRouteGet(app, '/resolve/:id', '/resolve/{id}', ['id'], resolveByIdHandler, errorResponse); // Duplicate the above for /{id} -web.wrapRouteGet(app, '/:id.:fmt?', '/{id}.{fmt}', ['id', 'fmt'], resolveByIdHandler, errorResponse); -web.wrapRouteGet(app, '/:id', '/{id}', ['id'], resolveByIdHandler, errorResponse); +web.wrapRouteGet(app, '/:id.:fmt?', '/{id}.{fmt}', ['id', 'fmt'], rootPathHandler, errorResponse); +web.wrapRouteGet(app, '/:id', '/{id}', ['id'], rootPathHandler, errorResponse); //Dowloads Section From e7a3a58472967e052a2e1d76cd87b3600bd32a62 Mon Sep 17 00:00:00 2001 From: kshefchek Date: Tue, 8 Nov 2016 12:18:12 -0800 Subject: [PATCH 07/17] break out phenogrid configuration into conf file --- conf/phenogrid_config.json | 58 ++++++++++ js/phenogridloader-onclick.js | 69 ++++++----- lib/monarch/api.js | 13 ++- lib/monarch/web/webapp.js | 180 +++++++++++++++++++++++++++-- templates/disclaimer-stub.mustache | 10 ++ templates/node.mustache | 10 +- 6 files changed, 293 insertions(+), 47 deletions(-) create mode 100644 conf/phenogrid_config.json create mode 100644 templates/disclaimer-stub.mustache diff --git a/conf/phenogrid_config.json b/conf/phenogrid_config.json new file mode 100644 index 00000000..b472e94f --- /dev/null +++ b/conf/phenogrid_config.json @@ -0,0 +1,58 @@ +{ + "all": { + "title": null, + "xAxis": [ + { + "groupId": "9606", + "groupName": "Homo sapiens" + }, + { + "groupId": "10090", + "groupName": "Mus musculus" + }, + { + "groupId": "7955", + "groupName": "Danio rerio" + }, + { + "groupId": "7227", + "groupName": "Drosophila melanogaster" + }, + { + "groupId": "6239", + "groupName": "Caenorhabditis elegans" + } + ], + "yAxis": null + }, + "cases": { + "title": null, + "xAxis": [ + { + "groupId": "9606", + "groupName": "Homo sapiens" + }, + { + "groupId": "case", + "groupName": "Cases" + }, + { + "groupId": "10090", + "groupName": "Mus musculus" + }, + { + "groupId": "7955", + "groupName": "Danio rerio" + }, + { + "groupId": "7227", + "groupName": "Drosophila melanogaster" + }, + { + "groupId": "6239", + "groupName": "Caenorhabditis elegans" + } + ], + "yAxis": null + } +} \ No newline at end of file diff --git a/js/phenogridloader-onclick.js b/js/phenogridloader-onclick.js index e5b15ef8..87d3a784 100644 --- a/js/phenogridloader-onclick.js +++ b/js/phenogridloader-onclick.js @@ -1,9 +1,9 @@ -function loadPhenogrid() { +function loadPhenogrid(phenogrid_conf, view) { var isGridLoading = false; jQuery('#categories a[href="#compare"]').click(function(event) { if (!(jQuery('#pg_svg_container').length) && isGridLoading === false){ isGridLoading = true; - initPhenogrid(); + initPhenogrid(phenogrid_conf, view); } }); // Trigger a click event if we're loading the page on an href @@ -12,7 +12,7 @@ function loadPhenogrid() { jQuery('#categories a[href="#compare"]').click(); } - function initPhenogrid () { + function initPhenogrid (phenogrid_conf, view) { // Add spinner var spinner_div = makeSpinnerDiv(); jQuery('#compare-panel').append(spinner_div.to_string()); @@ -22,34 +22,41 @@ function loadPhenogrid() { disease_id = disease_id.substring(slash_idx+1); var phenotype_list = []; var phenogridContainer = document.getElementById('phen_vis'); - - var gridSkeletonData = { - "title": null, - "xAxis": [ - { - "groupId": "9606", - "groupName": "Homo sapiens" - }, - { - "groupId": "10090", - "groupName": "Mus musculus" - }, - { - "groupId": "7955", - "groupName": "Danio rerio" - }, - { - "groupId": "7227", - "groupName": "Drosophila melanogaster" - } - , - { - "groupId": "6239", - "groupName": "Caenorhabditis elegans" - } - ], - "yAxis": phenotype_list - }; + var gridSkeletonData = {}; + + if (typeof(phenogrid_conf[view]) !== 'undefined') { + console.log("made it here"); + gridSkeletonData = phenogrid_conf[view]; + gridSkeletonData.yAxis = phenotype_list; + } else { + // Default configuration + gridSkeletonData = { + "title": null, + "xAxis": [ + { + "groupId": "9606", + "groupName": "Homo sapiens" + }, + { + "groupId": "10090", + "groupName": "Mus musculus" + }, + { + "groupId": "7955", + "groupName": "Danio rerio" + }, + { + "groupId": "7227", + "groupName": "Drosophila melanogaster" + }, + { + "groupId": "6239", + "groupName": "Caenorhabditis elegans" + } + ], + "yAxis": phenotype_list + }; + } jQuery.ajax({ url : '/' + disease_id + '/phenotype_list.json', diff --git a/lib/monarch/api.js b/lib/monarch/api.js index 7a87ef1d..fc175bf4 100644 --- a/lib/monarch/api.js +++ b/lib/monarch/api.js @@ -1097,7 +1097,7 @@ bbop.monarch.Engine.prototype.searchByPhenotypeProfile = function(query,target_s '7227' : { label : 'Drosophila melanogaster', target_idspace : 'FlyBase', b_type : 'gene',b_source : 'nif-0000-00558-2'}, '6239' : { label : 'C elegans', target_idspace : 'WormBase', b_type : 'gene',b_source : 'nif-0000-00558-2'}, '7955' : { label : 'Danio rerio', target_idspace : 'ZFIN', b_type : 'gene', b_source : 'nif-0000-21427-10'}, - 'UDP': { label :'UDP',target_idspace: 'UDP', b_type:'UDPICS patients',b_source: 'udpics'} + 'case': { label :'Case',target_idspace: 'MONARCH', b_type:'case',b_source: 'case_data'} }; var resource = {}; @@ -1445,9 +1445,18 @@ bbop.monarch.Engine.prototype.getCategories = function(id) { bbop.monarch.Engine.prototype.resolveIdToType = function(id) { var engine = this; var type = false; //Return false if no type is found - if (!/.*[:].*/.test(id)) { + + if (id.indexOf(":") === -1) { id = ':' + id; } + + /* This is a hack to accept both MONARCH:case1 and :case1 + * In the next release we will standardize all case curies to be + * MONARCH:c0001 + */ + if (/^MONARCH/.test(id)) { + id = id.replace(/^MONARCH/, ""); + } var nodeByID = engine.getGraphNodeByID(id, engine.config.scigraph_data_url); var graph = new bbop.model.graph(); graph.load_json(nodeByID); diff --git a/lib/monarch/web/webapp.js b/lib/monarch/web/webapp.js index 529a72a1..4bd7cf6c 100644 --- a/lib/monarch/web/webapp.js +++ b/lib/monarch/web/webapp.js @@ -678,6 +678,8 @@ function addCoreRenderers(info, type, id, defaults) { info.includes.analytics = expandTemplate('analytics', {'analytics_id': alys_id}); info.includes.navbar = expandTemplate('navbar', info); + info.includes.disclaimer = expandTemplate('disclaimer-stub', info); + info.monarch_launchable.push('navbar_search_init()'); info.includes.footer = expandTemplate('footer', info); @@ -698,11 +700,26 @@ function addCoreRenderers(info, type, id, defaults) { // adds js and other files required for phenogrid function addPhenogridFiles(info) { + var phenogrid_conf_json = env.readJSON('conf/phenogrid_config.json'); + info.pup_tent_js_variables.push({name:'global_phenogrid_conf', + value: phenogrid_conf_json}); info.pup_tent_js_libraries.push("/phenogrid_config.js"); info.pup_tent_js_libraries.push("/phenogrid-bundle.js"); // Minified - Zhou info.pup_tent_css_libraries.push("/phenogrid-bundle.css"); // Minified - Zhou } + +function addPhenogridView(info, view) { + var replacer = new RegExp('-', 'g'); + + var suffix = bbop.core.uuid().replace(replacer, ''); + var viewID = "view" + suffix; + + info.pup_tent_js_variables.push({name: viewID, value: view}); + info.monarch_launchable.push( + 'loadPhenogrid(global_phenogrid_conf, ' + viewID + ')'); +} + // Takes JSON and returns an HTTP response, possibly translating // the JSON into a requested format. // Note that HTML is handled separately. @@ -1607,6 +1624,8 @@ function modelByIdHandler(request, id, fmt) { // Phenogrid addPhenogridFiles(info); + var phenogridView = "all" + addPhenogridView(info, phenogridView); addNonEmptyAnchors(info, true); @@ -1722,6 +1741,8 @@ function genotypeByIdHandler(request, id, fmt) { // Phenogrid addPhenogridFiles(info); + var phenogridView = "all" + addPhenogridView(info, phenogridView); addNonEmptyAnchors(info, true); @@ -1784,6 +1805,98 @@ function genotypeByIdHandler(request, id, fmt) { web.wrapRouteGet(app, '/genotype/:id.:fmt?', '/genotype/{id}.{fmt}', ['id', 'fmt'], genotypeByIdHandler, errorResponse); web.wrapRouteGet(app, '/genotype/:id', '/genotype/{id}', ['id'], genotypeByIdHandler, errorResponse); +function caseByIdHandler(request, id, fmt) { + try { + + if (id.indexOf(':') === -1) { + id = ':' + id; + } + + /* This is a hack to accept both MONARCH:case1 and :case1 + * In the next release we will standardize all case curies to be + * MONARCH:c0001 + */ + if (/^MONARCH/.test(id)) { + id = id.replace(/^MONARCH/, ""); + } + + // Rendering. + var info = newInfo(); + info = engine.fetchDataInfo(id); + + + if (fmt != null) { + return formattedResults(info, fmt,request); + } + + if (typeof info.id === 'undefined'){ + info.id = id; + } + if (typeof info.label === 'undefined'){ + info.label = id; + } + info.label = info.label.replace(/^:/, ''); + + + addCoreRenderers(info, 'case', id); + addGolrStaticFiles(info); + + info.hasPhenotypes = true; + + var phenotype_filter = [{ field: 'object_category', value: 'phenotype' }, + { field: 'subject_category', value: 'case' }]; + addGolrTable(info, "subject_closure", id, 'phenotypes-table', phenotype_filter, 'case_phenotype', '#phenotypes'); + info.phenotypeNum = engine.fetchAssociationCount(id, 'subject_closure', phenotype_filter, 'object'); + + + var variant_filter = [{ field: 'object_category', value: 'variant' }, + { field: 'subject_category', value: 'case' }]; + addGolrTable(info, "subject_closure", id, 'variant-table', variant_filter, 'case_variant','#variants'); + info.variantNum = engine.fetchAssociationCount(id, 'subject_closure', variant_filter, 'object'); + + // Phenogrid + addPhenogridFiles(info); + var phenogridView = "cases" + addPhenogridView(info, phenogridView); + + addNonEmptyAnchors(info, true); + + // Add templates + info.includes.phenotype_anchor = addPhenotypeAnchor(info); + info.includes.phenotype_table = addPhenotypeTable(info); + + // Add variant table + info.includes.variant_anchor = addVariantAnchor(info); + info.includes.variant_table = addVariantTable(); + + info.title = 'Monarch Case: '+info.label+' ('+ info.id+')'; + + // Link to disclaimer + info.hasDisclaimer = true; + + info.primary_xref = function() {return genExternalHref('source',{id : id})}; + + info.includes.phenogrid_anchor = expandTemplate('phenogrid-anchor', info); + info.pup_tent_js_libraries.push("/phenogridloader-onclick.js"); + + + //Launch function for annotation score + info.pup_tent_js_variables.push({name:'globalID',value:id}); + info.monarch_launchable.push('getAnnotationScore(globalID)'); + + info.node_label = 'Case'; + info.node_logo = '/image/carousel-diseases.png'; + var output = pup_tent.render('node.mustache', info, 'monarch_base.mustache'); + return web.wrapHTML(output); + } + catch(err) { + return errorResponseWithObject(err); + } +}; + +web.wrapRouteGet(app, '/case/:id.:fmt?', '/case/{id}.{fmt}', ['id', 'fmt'], caseByIdHandler, errorResponse); +web.wrapRouteGet(app, '/case/:id', '/case/{id}', ['id'], caseByIdHandler, errorResponse); + function genMGIXRef(id) { return "MonarchInitiative.org is not intended for direct diagnostic use or medical decision-making. +If you have any health questions about the information contained on this website, +please contact a medical professional. + +The Monarch Initiative sources variant interpretations as provided by the original source + + +For more information see our disclaimer + + \ No newline at end of file diff --git a/templates/node.mustache b/templates/node.mustache index d672b5c0..2243879f 100644 --- a/templates/node.mustache +++ b/templates/node.mustache @@ -59,15 +59,21 @@ {{/hasDef}} + + {{#hasDisclaimer}} + -

+
-
+
+ {{{includes.disclaimer}}}
+ + {{/hasDisclaimer}} {{#hasAka}}
From 3779ff889569915b75ed0f7c177048df8db84350 Mon Sep 17 00:00:00 2001 From: kshefchek Date: Tue, 8 Nov 2016 13:03:37 -0800 Subject: [PATCH 08/17] fixed analyze page bug introduced by last commit --- js/Analyze.js | 63 ++++++++++++++++++++--------------- js/phenogridloader-onclick.js | 4 +-- lib/monarch/web/webapp.js | 29 +++++++++++----- 3 files changed, 58 insertions(+), 38 deletions(-) diff --git a/js/Analyze.js b/js/Analyze.js index 43e3bef2..c2044a23 100644 --- a/js/Analyze.js +++ b/js/Analyze.js @@ -1,5 +1,5 @@ -function AnalyzeInit(uploaded_data){ +function AnalyzeInit(phenogrid_conf, view){ // hide the limit field under search section // since the selected target species is 'all' by default - Zhou jQuery('#analyze-limit').hide(); @@ -807,32 +807,41 @@ function AnalyzeInit(uploaded_data){ } // New data schema since Phenogrid 1.3.0 input - Zhou - var gridSkeletonData = { - "title": null, - "xAxis": [ - { - "groupId": "9606", - "groupName": "Homo sapiens" - }, - { - "groupId": "10090", - "groupName": "Mus musculus" - }, - { - "groupId": "7955", - "groupName": "Danio rerio" - }, - { - "groupId": "7227", - "groupName": "Drosophila melanogaster" - }, - { - "groupId": "6239", - "groupName": "Caenorhabditis elegans" - } - ], - "yAxis": phenotype_list - }; + var gridSkeletonData = {}; + + if (typeof(view) !== 'undefined' + && typeof(phenogrid_conf[view]) !== 'undefined') { + gridSkeletonData = phenogrid_conf[view]; + gridSkeletonData.yAxis = phenotype_list; + } else { + // Default configuration + gridSkeletonData = { + "title": null, + "xAxis": [ + { + "groupId": "9606", + "groupName": "Homo sapiens" + }, + { + "groupId": "10090", + "groupName": "Mus musculus" + }, + { + "groupId": "7955", + "groupName": "Danio rerio" + }, + { + "groupId": "7227", + "groupName": "Drosophila melanogaster" + }, + { + "groupId": "6239", + "groupName": "Caenorhabditis elegans" + } + ], + "yAxis": phenotype_list + }; + } console.log('before Phenogrid.createPhenogridForElement in Analyze.js'); Phenogrid.createPhenogridForElement(document.getElementById('phen_vis'), { diff --git a/js/phenogridloader-onclick.js b/js/phenogridloader-onclick.js index 87d3a784..7be61617 100644 --- a/js/phenogridloader-onclick.js +++ b/js/phenogridloader-onclick.js @@ -24,8 +24,8 @@ function loadPhenogrid(phenogrid_conf, view) { var phenogridContainer = document.getElementById('phen_vis'); var gridSkeletonData = {}; - if (typeof(phenogrid_conf[view]) !== 'undefined') { - console.log("made it here"); + if (typeof(view) !== 'undefined' + && typeof(phenogrid_conf[view]) !== 'undefined') { gridSkeletonData = phenogrid_conf[view]; gridSkeletonData.yAxis = phenotype_list; } else { diff --git a/lib/monarch/web/webapp.js b/lib/monarch/web/webapp.js index 4bd7cf6c..9c120783 100644 --- a/lib/monarch/web/webapp.js +++ b/lib/monarch/web/webapp.js @@ -720,6 +720,17 @@ function addPhenogridView(info, view) { 'loadPhenogrid(global_phenogrid_conf, ' + viewID + ')'); } +function addPhenogridViewToAnalyze(info, view) { + var replacer = new RegExp('-', 'g'); + + var suffix = bbop.core.uuid().replace(replacer, ''); + var viewID = "view" + suffix; + + info.pup_tent_js_variables.push({name: viewID, value: view}); + info.monarch_launchable.push( + 'AnalyzeInit(global_phenogrid_conf, ' + viewID + ')'); +} + // Takes JSON and returns an HTTP response, possibly translating // the JSON into a requested format. // Note that HTML is handled separately. @@ -1624,7 +1635,7 @@ function modelByIdHandler(request, id, fmt) { // Phenogrid addPhenogridFiles(info); - var phenogridView = "all" + var phenogridView = "all"; addPhenogridView(info, phenogridView); addNonEmptyAnchors(info, true); @@ -1741,7 +1752,7 @@ function genotypeByIdHandler(request, id, fmt) { // Phenogrid addPhenogridFiles(info); - var phenogridView = "all" + var phenogridView = "all"; addPhenogridView(info, phenogridView); addNonEmptyAnchors(info, true); @@ -3500,7 +3511,7 @@ function diseaseByIdHandler(request, id, fmt) { // Phenogrid addPhenogridFiles(info); - var phenogridView = "all" + var phenogridView = "all"; addPhenogridView(info, phenogridView); addNonEmptyAnchors(info); @@ -3716,7 +3727,7 @@ function geneByIdHandler(request, id, fmt) { // Phenogrid addPhenogridFiles(info); - var phenogridView = "all" + var phenogridView = "all"; addPhenogridView(info, phenogridView); // Add templates @@ -3933,7 +3944,7 @@ function variantByIdHandler(request, id, fmt) { // Phenogrid addPhenogridFiles(info); - var phenogridView = "all" + var phenogridView = "all"; addPhenogridView(info, phenogridView); addNonEmptyAnchors(info, true); @@ -4038,7 +4049,7 @@ app.get('/labs/case/:id', function(request, id, fmt){ addCoreRenderers(info, 'patient', id); addPhenogridFiles(info); - var phenogridView = "all" + var phenogridView = "all"; addPhenogridView(info, phenogridView); info.pup_tent_js_libraries.push("/phenogridloader-onclick.js"); info.monarch_launchable.push('loadPhenogrid()'); @@ -4466,7 +4477,7 @@ function analyzeByDatatypePostHandler(request, datatype, fmt) { info.pup_tent_js_libraries.push("/Analyze.js"); addPhenogridFiles(info); - var phenogridView = "all" + var phenogridView = "all"; addPhenogridView(info, phenogridView); // info.pup_tent_js_libraries.push("/stupidtable.min.js"); // info.pup_tent_js_libraries.push("/tables.js"); @@ -4595,8 +4606,8 @@ function analyzeByDatatypeGetHandler(request, datatype, fmt) { info.pup_tent_js_libraries.push("/Analyze.js"); addPhenogridFiles(info); - var phenogridView = "all" - addPhenogridView(info, phenogridView); + var phenogridView = "all"; + addPhenogridViewToAnalyze(info, phenogridView); // info.pup_tent_js_libraries.push("/stupidtable.min.js"); // info.pup_tent_js_libraries.push("/tables.js"); From 75631f82ff33f32e94894b243af366731d9a8808 Mon Sep 17 00:00:00 2001 From: kshefchek Date: Thu, 10 Nov 2016 10:44:24 -0800 Subject: [PATCH 09/17] remove any hardcoding of configuration, raise error instead --- conf/phenogrid_config.json | 2 +- js/Analyze.js | 28 +--------------------------- js/phenogridloader-onclick.js | 28 +--------------------------- lib/monarch/web/webapp.js | 31 +++++++++---------------------- 4 files changed, 12 insertions(+), 77 deletions(-) diff --git a/conf/phenogrid_config.json b/conf/phenogrid_config.json index b472e94f..5e1a1e07 100644 --- a/conf/phenogrid_config.json +++ b/conf/phenogrid_config.json @@ -1,5 +1,5 @@ { - "all": { + "default": { "title": null, "xAxis": [ { diff --git a/js/Analyze.js b/js/Analyze.js index c2044a23..8ff6a56e 100644 --- a/js/Analyze.js +++ b/js/Analyze.js @@ -814,33 +814,7 @@ function AnalyzeInit(phenogrid_conf, view){ gridSkeletonData = phenogrid_conf[view]; gridSkeletonData.yAxis = phenotype_list; } else { - // Default configuration - gridSkeletonData = { - "title": null, - "xAxis": [ - { - "groupId": "9606", - "groupName": "Homo sapiens" - }, - { - "groupId": "10090", - "groupName": "Mus musculus" - }, - { - "groupId": "7955", - "groupName": "Danio rerio" - }, - { - "groupId": "7227", - "groupName": "Drosophila melanogaster" - }, - { - "groupId": "6239", - "groupName": "Caenorhabditis elegans" - } - ], - "yAxis": phenotype_list - }; + throw new Error("No configuration defined for gridSkeletonData"); } console.log('before Phenogrid.createPhenogridForElement in Analyze.js'); diff --git a/js/phenogridloader-onclick.js b/js/phenogridloader-onclick.js index 7be61617..a289e88c 100644 --- a/js/phenogridloader-onclick.js +++ b/js/phenogridloader-onclick.js @@ -29,33 +29,7 @@ function loadPhenogrid(phenogrid_conf, view) { gridSkeletonData = phenogrid_conf[view]; gridSkeletonData.yAxis = phenotype_list; } else { - // Default configuration - gridSkeletonData = { - "title": null, - "xAxis": [ - { - "groupId": "9606", - "groupName": "Homo sapiens" - }, - { - "groupId": "10090", - "groupName": "Mus musculus" - }, - { - "groupId": "7955", - "groupName": "Danio rerio" - }, - { - "groupId": "7227", - "groupName": "Drosophila melanogaster" - }, - { - "groupId": "6239", - "groupName": "Caenorhabditis elegans" - } - ], - "yAxis": phenotype_list - }; + throw new Error("No configuration defined for gridSkeletonData"); } jQuery.ajax({ diff --git a/lib/monarch/web/webapp.js b/lib/monarch/web/webapp.js index 9c120783..6233bb3c 100644 --- a/lib/monarch/web/webapp.js +++ b/lib/monarch/web/webapp.js @@ -1635,7 +1635,7 @@ function modelByIdHandler(request, id, fmt) { // Phenogrid addPhenogridFiles(info); - var phenogridView = "all"; + var phenogridView = "default"; addPhenogridView(info, phenogridView); addNonEmptyAnchors(info, true); @@ -1752,7 +1752,7 @@ function genotypeByIdHandler(request, id, fmt) { // Phenogrid addPhenogridFiles(info); - var phenogridView = "all"; + var phenogridView = "default"; addPhenogridView(info, phenogridView); addNonEmptyAnchors(info, true); @@ -3511,7 +3511,7 @@ function diseaseByIdHandler(request, id, fmt) { // Phenogrid addPhenogridFiles(info); - var phenogridView = "all"; + var phenogridView = "default"; addPhenogridView(info, phenogridView); addNonEmptyAnchors(info); @@ -3727,7 +3727,7 @@ function geneByIdHandler(request, id, fmt) { // Phenogrid addPhenogridFiles(info); - var phenogridView = "all"; + var phenogridView = "default"; addPhenogridView(info, phenogridView); // Add templates @@ -3944,7 +3944,7 @@ function variantByIdHandler(request, id, fmt) { // Phenogrid addPhenogridFiles(info); - var phenogridView = "all"; + var phenogridView = "default"; addPhenogridView(info, phenogridView); addNonEmptyAnchors(info, true); @@ -4049,7 +4049,7 @@ app.get('/labs/case/:id', function(request, id, fmt){ addCoreRenderers(info, 'patient', id); addPhenogridFiles(info); - var phenogridView = "all"; + var phenogridView = "default"; addPhenogridView(info, phenogridView); info.pup_tent_js_libraries.push("/phenogridloader-onclick.js"); info.monarch_launchable.push('loadPhenogrid()'); @@ -4477,21 +4477,12 @@ function analyzeByDatatypePostHandler(request, datatype, fmt) { info.pup_tent_js_libraries.push("/Analyze.js"); addPhenogridFiles(info); - var phenogridView = "all"; - addPhenogridView(info, phenogridView); + var phenogridView = "default"; + addPhenogridViewToAnalyze(info, phenogridView); // info.pup_tent_js_libraries.push("/stupidtable.min.js"); // info.pup_tent_js_libraries.push("/tables.js"); info.monarch_launchable.push('InitTables()'); - info.pup_tent_js_variables.push.apply(info.pup_tent_js_variables, - [ - {name:'user_input',value: user_request} - ]); - info.monarch_launchable.push.apply(info.monarch_launchable, - [ - 'AnalyzeInit(user_input)' - ]); - info.title = 'Monarch Analysis'; var output = pup_tent.render('analyze.mustache',info,'monarch_base.mustache'); @@ -4606,17 +4597,13 @@ function analyzeByDatatypeGetHandler(request, datatype, fmt) { info.pup_tent_js_libraries.push("/Analyze.js"); addPhenogridFiles(info); - var phenogridView = "all"; + var phenogridView = "default"; addPhenogridViewToAnalyze(info, phenogridView); // info.pup_tent_js_libraries.push("/stupidtable.min.js"); // info.pup_tent_js_libraries.push("/tables.js"); info.monarch_launchable.push('InitTables()'); - info.monarch_launchable.push.apply(info.monarch_launchable, - [ - 'AnalyzeInit()' - ]); info.title = 'Monarch Analysis'; From d79ec0cfcf8a201e9388c9691b5dac3932841c79 Mon Sep 17 00:00:00 2001 From: kshefchek Date: Thu, 10 Nov 2016 11:49:20 -0800 Subject: [PATCH 10/17] have table match filters on analyze page, fixes half of #1391 --- conf/phenogrid_config.json | 2 +- lib/monarch/web/webapp.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/conf/phenogrid_config.json b/conf/phenogrid_config.json index 5e1a1e07..575e8008 100644 --- a/conf/phenogrid_config.json +++ b/conf/phenogrid_config.json @@ -26,7 +26,7 @@ "yAxis": null }, "cases": { - "title": null, + "title": "Phenotype Similarity of Diseases, Cases, and Model Genes", "xAxis": [ { "groupId": "9606", diff --git a/lib/monarch/web/webapp.js b/lib/monarch/web/webapp.js index 6233bb3c..12f8b1d1 100644 --- a/lib/monarch/web/webapp.js +++ b/lib/monarch/web/webapp.js @@ -4491,7 +4491,7 @@ function analyzeByDatatypePostHandler(request, datatype, fmt) { function analyzeByDatatypeGetHandler(request, datatype, fmt) { var target = web.getParam(request, 'target'); - var species = web.getParam(request, 'species'); + var species = web.getParam(request, 'target_species'); var mode = web.getParam(request, 'mode'); var input_items = web.getParam(request, 'input_items'); var limit = web.getParam(request, 'limit'); From 459fafc5d3e29206a6d05d0a78ff6cbb4c870c1f Mon Sep 17 00:00:00 2001 From: kshefchek Date: Fri, 11 Nov 2016 08:44:44 -0800 Subject: [PATCH 11/17] fix broken id resolution test --- conf/phenogrid_config.json | 2 +- lib/monarch/web/webapp.js | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/conf/phenogrid_config.json b/conf/phenogrid_config.json index 575e8008..538a2f05 100644 --- a/conf/phenogrid_config.json +++ b/conf/phenogrid_config.json @@ -34,7 +34,7 @@ }, { "groupId": "case", - "groupName": "Cases" + "groupName": "Human Cases" }, { "groupId": "10090", diff --git a/lib/monarch/web/webapp.js b/lib/monarch/web/webapp.js index 12f8b1d1..55fdc8ff 100644 --- a/lib/monarch/web/webapp.js +++ b/lib/monarch/web/webapp.js @@ -4844,6 +4844,7 @@ function resolveByIdHandler(request, id, fmt) { if (id.indexOf(':') === -1) { id = ':' + id; } + id = engine.convertIdToCurie(id); var type = engine.resolveIdToType(id); if (type) { From 7059fadb3adc56c085b80bf05737bb78eadb95a0 Mon Sep 17 00:00:00 2001 From: kshefchek Date: Mon, 14 Nov 2016 14:09:29 -0800 Subject: [PATCH 12/17] fix bugs in phenopackets, id resolution, phenogrid conf --- js/golr-table.js | 11 ++++------- js/monarch-common.js | 3 +++ lib/monarch/api.js | 10 ++++++++++ lib/monarch/web/webapp.js | 37 +++++++++++++++++-------------------- 4 files changed, 34 insertions(+), 27 deletions(-) diff --git a/js/golr-table.js b/js/golr-table.js index fee8ba2e..cac3296c 100644 --- a/js/golr-table.js +++ b/js/golr-table.js @@ -204,7 +204,7 @@ function getTableFromSolr(id, golr_field, div, filter, personality, tab_anchor, //Hardcode for now if (personality === 'variant_phenotype') { - addPhenoPacketButton(pager, molr_manager, id); + addPhenoPacketButton(pager.button_span_id(), molr_manager); } // Details for spinner @@ -242,15 +242,12 @@ function getTableFromSolr(id, golr_field, div, filter, personality, tab_anchor, } } -function addPhenoPacketButton(pager, manager, id){ +function addPhenoPacketButton(pager_span, manager){ var fun_id = bbop.core.uuid(); manager.register('search', _drawPhenoPacketBtn, '-3', fun_id); function _drawPhenoPacketBtn() { - - // Make download button - var span = pager.button_span_id(); // / Add button to DOM. var button_props = { @@ -263,7 +260,7 @@ function addPhenoPacketButton(pager, manager, id){ var button = new bbop.html.button(label, button_props); var button_elt = '#' + button.get_id(); - jQuery('#' + span).append(button.to_string()); + jQuery('#' + pager_span).append(button.to_string()); jQuery(button_elt).append("BETA"); //var infoIcon = ""; //jQuery('#' + span).append(infoIcon); @@ -272,7 +269,7 @@ function addPhenoPacketButton(pager, manager, id){ jQuery('#' + button.get_id()).click( function() { var solrParams = manager.get_filter_query_string(); - solrParams = solrParams.replace('sfq=', 'fq=', 'g'); + solrParams = solrParams.replace(/sfq=/g, 'fq='); var personality = manager.get_personality(); var personalityParam = "&personality="+personality var qurl = global_app_base + '/phenopacket?' + solrParams diff --git a/js/monarch-common.js b/js/monarch-common.js index 58082a04..795a9535 100644 --- a/js/monarch-common.js +++ b/js/monarch-common.js @@ -187,6 +187,7 @@ function getAnnotationScore() { /* * Function: filter_equivalents + * Status: Deprecated * * Arguments: * : eq_graph - raw json in the structure of a bbop.model.graph @@ -278,6 +279,7 @@ function filter_equivalents(eq_graph, map) { return map; }; +// Deprecated function remove_equivalent_ids(map, id_list, response) { //TODO pass server in using puptent var var ids = id_list.join('&id='); @@ -299,6 +301,7 @@ function remove_equivalent_ids(map, id_list, response) { }); }; +// Deprecated function add_species_to_autocomplete(data, map, gene_ids) { var graph = new bbop.model.graph(); graph.load_json(data); diff --git a/lib/monarch/api.js b/lib/monarch/api.js index fc175bf4..0d2e5e2e 100644 --- a/lib/monarch/api.js +++ b/lib/monarch/api.js @@ -4180,6 +4180,11 @@ bbop.monarch.Engine.prototype.fetchAssociations = function(id, field, filter, li } }); } + + if (logFetchTimes) { + var timeDelta = Date.now(); + this.log("FETCHING: " + "GET" + " " + golrManager.get_state_url()); + } return golrManager.search(); }; @@ -4204,6 +4209,11 @@ bbop.monarch.Engine.prototype.fetchSolrDocuments = function (query, filters, per golrManager.set_results_count(limit); } + if (logFetchTimes) { + var timeDelta = Date.now(); + this.log("FETCHING: " + "GET" + " " + golrManager.get_state_url()); + } + return golrManager.search(); }; diff --git a/lib/monarch/web/webapp.js b/lib/monarch/web/webapp.js index 55fdc8ff..23e589f2 100644 --- a/lib/monarch/web/webapp.js +++ b/lib/monarch/web/webapp.js @@ -718,6 +718,7 @@ function addPhenogridView(info, view) { info.pup_tent_js_variables.push({name: viewID, value: view}); info.monarch_launchable.push( 'loadPhenogrid(global_phenogrid_conf, ' + viewID + ')'); + return info; } function addPhenogridViewToAnalyze(info, view) { @@ -729,6 +730,7 @@ function addPhenogridViewToAnalyze(info, view) { info.pup_tent_js_variables.push({name: viewID, value: view}); info.monarch_launchable.push( 'AnalyzeInit(global_phenogrid_conf, ' + viewID + ')'); + return info; } // Takes JSON and returns an HTTP response, possibly translating @@ -1635,8 +1637,6 @@ function modelByIdHandler(request, id, fmt) { // Phenogrid addPhenogridFiles(info); - var phenogridView = "default"; - addPhenogridView(info, phenogridView); addNonEmptyAnchors(info, true); @@ -1678,7 +1678,8 @@ function modelByIdHandler(request, id, fmt) { if (info.hasPhenotypes){ info.pup_tent_js_libraries.push("/phenogridloader-onclick.js"); - info.monarch_launchable.push('loadPhenogrid()'); + var phenogridView = "default"; + addPhenogridView(info, phenogridView); } //Launch function for annotation score @@ -1752,8 +1753,6 @@ function genotypeByIdHandler(request, id, fmt) { // Phenogrid addPhenogridFiles(info); - var phenogridView = "default"; - addPhenogridView(info, phenogridView); addNonEmptyAnchors(info, true); @@ -1795,7 +1794,8 @@ function genotypeByIdHandler(request, id, fmt) { if (info.hasPhenotypes){ info.pup_tent_js_libraries.push("/phenogridloader-onclick.js"); - info.monarch_launchable.push('loadPhenogrid()'); + var phenogridView = "default"; + addPhenogridView(info, phenogridView); } //Launch function for annotation score @@ -2526,8 +2526,8 @@ function phenoPacketHandler(request) { }); personality = subject + "_" + object; } - - var limit = 5000 + + var limit = 1000; var response = engine.fetchSolrDocuments(query, filters, personality, limit); var phenopacket = phenoPacketBuilder.buildPhenoPacket(response, personality, showEmptyFields); @@ -3511,12 +3511,9 @@ function diseaseByIdHandler(request, id, fmt) { // Phenogrid addPhenogridFiles(info); - var phenogridView = "default"; - addPhenogridView(info, phenogridView); addNonEmptyAnchors(info); - info.title = 'Monarch Disease: '+info.label+' ('+ info.id+')'; info.primary_xref = function() {return genExternalHref('source',{id : id})}; @@ -3567,7 +3564,8 @@ function diseaseByIdHandler(request, id, fmt) { if (info.hasPhenotypes){ info.pup_tent_js_libraries.push("/phenogridloader-onclick.js"); - info.monarch_launchable.push('loadPhenogrid()'); + var phenogridView = "default"; + addPhenogridView(info, phenogridView); } info.node_label = 'Disease'; info.node_logo = '/image/carousel-diseases.png'; @@ -3727,9 +3725,7 @@ function geneByIdHandler(request, id, fmt) { // Phenogrid addPhenogridFiles(info); - var phenogridView = "default"; - addPhenogridView(info, phenogridView); - + // Add templates info.includes.phenotype_anchor = addPhenotypeAnchor(info); info.includes.phenotype_table = addPhenotypeTable(info); @@ -3809,7 +3805,8 @@ function geneByIdHandler(request, id, fmt) { if (info.hasPhenotypes){ info.pup_tent_js_libraries.push("/phenogridloader-onclick.js"); - info.monarch_launchable.push('loadPhenogrid()'); + var phenogridView = "default"; + addPhenogridView(info, phenogridView); } info.includes.phenogrid_anchor = expandTemplate('phenogrid-anchor', info); @@ -3944,8 +3941,6 @@ function variantByIdHandler(request, id, fmt) { // Phenogrid addPhenogridFiles(info); - var phenogridView = "default"; - addPhenogridView(info, phenogridView); addNonEmptyAnchors(info, true); @@ -3993,7 +3988,8 @@ function variantByIdHandler(request, id, fmt) { if (info.hasPhenotypes){ info.pup_tent_js_libraries.push("/phenogridloader-onclick.js"); - info.monarch_launchable.push('loadPhenogrid()'); + var phenogridView = "default"; + addPhenogridView(info, phenogridView); } info.includes.phenogrid_anchor = expandTemplate('phenogrid-anchor', info); @@ -4841,10 +4837,11 @@ function resolveByIdHandler(request, id, fmt) { var result; + id = engine.convertIdToCurie(id); + if (id.indexOf(':') === -1) { id = ':' + id; } - id = engine.convertIdToCurie(id); var type = engine.resolveIdToType(id); if (type) { From bf976b0e4476b4300178c29ba05bac203e9caf01 Mon Sep 17 00:00:00 2001 From: kshefchek Date: Thu, 17 Nov 2016 12:20:25 -0800 Subject: [PATCH 13/17] add support for patient phenopackets --- lib/monarch/phenopacket-builder.js | 110 ++++++++++++++++++++++++----- lib/monarch/web/webapp.js | 6 +- 2 files changed, 99 insertions(+), 17 deletions(-) diff --git a/lib/monarch/phenopacket-builder.js b/lib/monarch/phenopacket-builder.js index 6d1b34ab..bb064df2 100644 --- a/lib/monarch/phenopacket-builder.js +++ b/lib/monarch/phenopacket-builder.js @@ -15,14 +15,18 @@ function buildPhenoPacket(response, personality, showEmptyFields) { switch(personality) { case "variant_phenotype": - var packet = buildVariantPhenotype(response) + var packet = buildVariantPhenotype(response); + phenopacket.phenopacket = packet; + break; + case "case": + var packet = buildCasePacket(response); phenopacket.phenopacket = packet; break; default: throw new Error("personality is not supported") } if (!showEmptyFields) { - clean_object(phenopacket); + cleanObject(phenopacket); } return phenopacket; } @@ -64,7 +68,7 @@ function buildVariantPhenotype(response) { label : doc.subject_label }); - variant.types = getVariantTypes(doc.subject_closure_map); + variant.type = getEntityType(doc.subject, doc.subject_closure, doc.subject_closure_map); var phenotype_association = new PhenoPacket.PhenotypeAssociation({ entity : variant.id, @@ -92,36 +96,110 @@ function buildVariantPhenotype(response) { return packet; } +/** + * Build phenopacket for cases + * + * @param {object} golrManager - bbop.golr.manager + * @returns {array} list of phenopackets + */ +function buildCasePacket(response) { + var packet = new PhenoPacket.PhenoPacket({}); + var entityList = []; + + response.documents().forEach(function(doc){ + //Things to ignore: DOID:4 + if (doc.object === 'DOID:4'){ + return; + } + if (doc.subject_category === 'case') { + if (entityList.map( + function(val){return val.id;}).indexOf(doc.subject) === -1) { + var entity_type = getEntityType(doc.subject, doc.subject_closure, doc.subject_closure_map); + var entity = new PhenoPacket.Entity({ + id : doc.subject, + label : doc.subject_label, + type : entity_type + }); + entityList.push(entity); + + } + } + if (doc.object_category === 'phenotype') { + var ontologyClass = new PhenoPacket.OntologyClass({ + id: doc.object, + label : doc.object_label + }); + + var phenotypeTypes = [ontologyClass]; + + var phenotype = new PhenoPacket.Phenotype({ + types: phenotypeTypes + }); + + var phenotype_association = new PhenoPacket.PhenotypeAssociation({ + entity : doc.subject, + phenotype : phenotype + }); + packet.phenotype_profile.push(phenotype_association); + } + + if (doc.object_category === 'variant') { + + var variant = new PhenoPacket.Variant({ + id : doc.object, + label : doc.object_label + }); + + variant.type = getEntityType(doc.object, doc.object_closure, doc.object_closure_map); + packet.variants.push(variant); + } + + }); + + if (entityList.length > 0) { + packet.entities = entityList; + } + packet.schema = "phenopacket-level-1"; + return packet; +} + // Remove anything that is null or undefined // Credit http://stackoverflow.com/a/24190282 -function clean_object(obj) { +function cleanObject(obj) { Object.keys(obj).forEach (function (key) { if (obj[key] === null || Object.keys(obj[key]).length === 0) { delete obj[key]; } else if (typeof obj[key] === 'object') { - clean_object(obj[key]); + cleanObject(obj[key]); } }); } -function getVariantTypes(closureMap) { +function getEntityType(curie, closureList, closureMap) { var typeMap = {}; - var typeList = []; + var type = {}; + if (typeof(closureList) === 'undefined'){ + closureList = []; + } + if (typeof(closureMap) === 'undefined'){ + closureMap = {}; + } try { typeMap = JSON.parse(closureMap); } catch (e) { console.log(e); } - Object.keys(typeMap).forEach( function(type) { - if (/SO:|GENO:/.test(type)) { - var map = {}; - map.id = type; - map.label = typeMap[type]; - typeList.push(map); - } - }); - return typeList; + + if (closureList.length > 0 && closureList[0] != curie) { + type.id = closureList[0]; + type.label = typeMap[closureList[0]]; + } else if (closureList.length > 1) { + type.id = closureList[1]; + type.label = typeMap[closureList[1]]; + } + + return type; } diff --git a/lib/monarch/web/webapp.js b/lib/monarch/web/webapp.js index 5c61917b..20eced10 100644 --- a/lib/monarch/web/webapp.js +++ b/lib/monarch/web/webapp.js @@ -2766,6 +2766,10 @@ function phenoPacketHandler(request) { } var personality = request.query.personality; + + if (filters.constructor !== Array) { + filters = [request.query.fq] + } // Try to determine personality from filters if (typeof personality === 'undefined') { @@ -2793,7 +2797,7 @@ function phenoPacketHandler(request) { }); personality = subject + "_" + object; } - + var limit = 1000; var response = engine.fetchSolrDocuments(query, filters, personality, limit); var phenopacket = phenoPacketBuilder.buildPhenoPacket(response, personality, showEmptyFields); From 8984b087025754223463d231334bdb43de01d410 Mon Sep 17 00:00:00 2001 From: kshefchek Date: Fri, 18 Nov 2016 12:56:49 -0800 Subject: [PATCH 14/17] add disclaimer text, some clean up --- css/monarch-common.css | 11 +++- js/golr-table.js | 10 +--- js/monarch-tabs.js | 48 ++++++++--------- lib/monarch/api.js | 83 ------------------------------ lib/monarch/web/webapp.js | 75 ++++++--------------------- templates/disclaimer-stub.mustache | 16 +++++- templates/node.mustache | 5 ++ 7 files changed, 69 insertions(+), 179 deletions(-) diff --git a/css/monarch-common.css b/css/monarch-common.css index 3948bd04..cb68a6c3 100644 --- a/css/monarch-common.css +++ b/css/monarch-common.css @@ -814,7 +814,16 @@ div.bs3table { font-size: 0.9em; } -#results-area .bs3table > table > thead > tr > th { +#results-area #case-variant-table > table > tbody > tr > td:nth-last-child(2) { + font-size: 14px !important; +} + +#results-area #case-variant-table > table > thead > tr > th:nth-last-child(2) { + min-width:60px !important; + width:60px !important; +} + +#results-area #case-variant-table > table > thead > tr > th { padding-left:5px; padding-right:5px; } diff --git a/js/golr-table.js b/js/golr-table.js index cac3296c..e4fc53a3 100644 --- a/js/golr-table.js +++ b/js/golr-table.js @@ -73,15 +73,7 @@ function getTableFromSolr(id, golr_field, div, filter, personality, tab_anchor, molr_manager.set_personality(personality); molr_manager.add_query_filter(golr_field, id, ['*']); molr_manager.query_variants['facet.method'] = 'enum'; - -// var golr_manager = new bbop.golr.manager.jquery(srv, gconf); -// golr_manager.default_rows = 25; -// golr_manager.reset_results_count(); -// golr_manager.set_personality(personality); -// //golr_manager.add_query_filter('document_category', 'annotation', ['*']); -// golr_manager.add_query_filter(golr_field, id, ['*']); -// golr_manager.query_variants['facet.method'] = 'enum'; - + molr_manager.set_results_count(25); if (filter != null && filter instanceof Array && filter.length > 0){ filter.forEach( function (val) { diff --git a/js/monarch-tabs.js b/js/monarch-tabs.js index a49ad7d1..7df36793 100644 --- a/js/monarch-tabs.js +++ b/js/monarch-tabs.js @@ -37,33 +37,33 @@ function InitTabs() { jQuery(panel_id + '-panel').show(); window.location.hash = panel_id; }); - //HACK TO GET THE ANALYZE PAGE TO WORK, REFACTOR OUT - jQuery('#internal-link').click(function(event) { - console.log('internal-link'); - var panel_id = jQuery(this).attr('href'); - event.preventDefault(); - jQuery('.category').hide(); - jQuery(panel_id).show(); - jQuery(".query-tab").css({'color': 'white', 'background-color': '#999', 'border-bottom': '1px solid darkgray'}); - jQuery(".results-tab").css({'color': 'white', 'background-color': '#999', 'border-bottom': '1px solid darkgray'}); - jQuery(".upload-tab").css({'color': 'black', 'background-color': 'white', 'border-bottom': '1px solid white'}); - }); - - // Since we're a tabby version, we're going to try and open - // any tabs defined by fragments. - if ( window && window.location && window.location.hash && - window.location.hash != "" && window.location.hash != "#" ){ - var fragname = window.location.hash; + + function adjustTabColor(panel_id) { + // Since we're a tabby version, we're going to try and open + // any tabs defined by fragments. + if ( window && window.location && window.location.hash && + window.location.hash != "" && window.location.hash != "#" ){ - if (fragname !== '#overview') { - jQuery('.first.category').hide(); - jQuery(fragname).show(); + if (panel_id !== '#overview') { + jQuery('.first.category').hide(); + jQuery(panel_id).show(); - jQuery('.contenttab').css({'color': 'white', 'background-color': '#999', 'border-bottom': '1px solid darkgray'}); - jQuery('.tabcontainer a[href="' + fragname + '"]').children('.contenttab').css({'color': 'black', 'background-color': 'white', 'border-bottom': '1px solid white'}); - } + jQuery('.contenttab').css({'color': 'white', 'background-color': '#999', 'border-bottom': '1px solid darkgray'}); + jQuery('.tabcontainer a[href="' + panel_id + '"]').children('.contenttab').css({'color': 'black', 'background-color': 'white', 'border-bottom': '1px solid white'}); + } + } } - + + //Hack to get links to internal html anchors to work + jQuery('#internal-link').click(function(event) { + var panel_id = jQuery(this).attr('href'); + jQuery('#categories a[href="'+panel_id+'"]').click(); + adjustTabColor(panel_id); + + }); + + adjustTabColor(window.location.hash); + /* Literature Tab */ /* This is used to display hidden authors on the literature tab (because only the diff --git a/lib/monarch/api.js b/lib/monarch/api.js index 0d2e5e2e..c02c7073 100644 --- a/lib/monarch/api.js +++ b/lib/monarch/api.js @@ -4506,89 +4506,6 @@ bbop.monarch.Engine.prototype.fetchDataInfo = function(id, opts) { return resultObj; } -//Hack to get patient pages, will eventually go away in favor of getting this info from a golr document -bbop.monarch.Engine.prototype.fetchPatientInfo = function(id) { - var info = {}; - var engine = this; - var neighbors = engine.getGraphNeighbors(id,1, undefined, undefined, true, engine.config.scigraph_data_url); - info.diseases = []; - info.genotypes = []; - info.phenotypes = []; - info.phenotype_list = []; - info.family = []; - info.related = []; - info.source = ''; - - var ontoGraph = new bbop.model.graph(); - ontoGraph.load_json(neighbors); - - var genotype_nodes = ontoGraph.get_parent_nodes(id, 'GENO_0000222'); - var phenotype_nodes = ontoGraph.get_parent_nodes(id, 'RO_0002200'); - var related_list = ontoGraph.get_child_nodes(id, 'RO_0001000'); - var family_list = ontoGraph.get_parent_nodes(id, 'RO_0002350'); - - - if (ontoGraph.get_node(id)){ - info.id = ontoGraph.get_node(id).id(); - info.label = ontoGraph.get_node(id).label(); - } - - if (genotype_nodes){ - genotype_nodes.forEach(function (node){ - info.genotypes.push(node.id()); - }); - } - - if (family_list){ - family_list.forEach(function (node){ - if (/Coriell/.test(node.id())){ - info.source = 'Coriell'; - } - info.family.push(node.id()); - }); - } - - if (related_list){ - related_list.forEach(function (node){ - if (/Coriell/.test(node.id())){ - info.source = 'Coriell'; - } - info.related.push(node.id()); - }); - } - - - if (phenotype_nodes){ - phenotype_nodes.forEach(function (node){ - if (node.metadata().category && node.metadata().category.indexOf('disease') != -1) { - info.diseases.push({ id : node.id(), - label : node.label()}); - } else { - info.phenotypes.push({ id : node.id(), - label : node.label()}) - } - }); - } - - if (info.diseases){ - info.diseases.forEach(function (i){ - var disease_info = engine.fetchCoreDiseaseInfo(i.id); - if (disease_info && disease_info.phenotype_list) - info.phenotype_list.push.apply(info.phenotype_list, disease_info.phenotype_list); - }); - } - if (info.phenotypes){ - var temp = info.phenotypes.map(function(i){ - return {"id" : i.object, "label": i.object_label, "observed": "positive", "isPresent" : "true"} - }); - info.phenotype_list.push.apply(info.phenotype_list, temp); - } - - return info; - -} - - // Generate json blob bbop.monarch.Engine.prototype.getHealthCheck = function () { var engine = this; diff --git a/lib/monarch/web/webapp.js b/lib/monarch/web/webapp.js index 20eced10..fc580d85 100644 --- a/lib/monarch/web/webapp.js +++ b/lib/monarch/web/webapp.js @@ -2129,7 +2129,7 @@ function caseByIdHandler(request, id, fmt) { var variant_filter = [{ field: 'object_category', value: 'variant' }, { field: 'subject_category', value: 'case' }]; - addGolrTable(info, "subject_closure", id, 'variant-table', variant_filter, 'case_variant','#variants'); + addGolrTable(info, "subject_closure", id, 'case-variant-table', variant_filter, 'case_variant','#variants'); info.variantNum = engine.fetchAssociationCount(id, 'subject_closure', variant_filter, 'object'); // Phenogrid @@ -2145,12 +2145,20 @@ function caseByIdHandler(request, id, fmt) { // Add variant table info.includes.variant_anchor = addVariantAnchor(info); - info.includes.variant_table = addVariantTable(); + info.includes.variant_table = addCaseVariantTable(); info.title = 'Monarch Case: '+info.label+' ('+ info.id+')'; // Link to disclaimer info.hasDisclaimer = true; + + if (/^:c\d+$/.test(id)) { + info.hasSource = true; + info.source = + 'Undiagnosed ' + + 'Diseases Program'; + } info.primary_xref = function() {return genExternalHref('source',{id : id})}; @@ -4296,64 +4304,6 @@ web.wrapRouteGet(app, '/model/:id/:section.:fmt?', '/model/{id}/{section}.{fmt?} web.wrapRouteGet(app, '/case/:id/:section.:fmt?', '/case/{id}/{section}.{fmt?}', ['id', 'section', 'fmt'], fetchCaseSection); -if (false) { /* Disabling all /legacy/xxx and /labs/xxx endpoints that aren't dual-mode */ -app.get('/labs/case/:id/phenotype_list.:fmt?', function(request, id, fmt){ - var info = newInfo(); - info = engine.fetchPatientInfo(id); - - if (fmt != null) { - return formattedResults(info, fmt,request); - } else { - return response.error("plain HTML does not work for page sections. Please append .json or .rdf to URL"); - } -}); -} - -if (false) { /* Disabling all /legacy/xxx and /labs/xxx endpoints that aren't dual-mode */ -app.get('/labs/case/:id', function(request, id, fmt){ - var info = newInfo(); - info = engine.fetchPatientInfo(id); - - addCoreRenderers(info, 'patient', id); - addPhenogridFiles(info); - var phenogridView = "default"; - addPhenogridView(info, phenogridView); - info.pup_tent_js_libraries.push("/phenogridloader-onclick.js"); - info.monarch_launchable.push('loadPhenogrid()'); - - info.hasPhenotypes = true; - info.includes.phenogrid_anchor = expandTemplate('phenogrid-anchor', info); - - // info.pup_tent_css_libraries.push("/monarch-specific.css"); - - info.hasRelated = function() {return checkExistence(info.related)}; - info.hasFam = function() {return checkExistence(info.family)}; - info.hasGeno = function() {return checkExistence(info.genotypes)}; - - info.fam = function() { - if (info.family != null) { - return info.family.map(function(r) { return genExternalHref('source',{id : r}) }).join(", "); - } - }; - - info.rel = function() { - if (info.related != null) { - return info.related.map(function(r) { return genExternalHref('source',{id : r}) }).join(", "); - } - }; - - info.geno = function() { - if (info.genotypes != null) { - return info.genotypes.map(function(r) { return genExternalHref('source',{id : r}) }).join(", "); - } - }; - - var output = pup_tent.render('patient.mustache', info, - 'monarch_base.mustache'); - return response.html(output); -}); -} - function associationByIdHandler(request, id, fmt){ try { @@ -4502,6 +4452,11 @@ function addVariantTable(with_filter) { return expandTemplate('golr-table', variant_table); } +function addCaseVariantTable(with_filter) { + var variant_table = {href: "variants", div: "case-variant-table", filter: with_filter}; + return expandTemplate('golr-table', variant_table); +} + function addHomologAnchor(info) { var homolog_anchor = {id: info.id, type: "Homologs", resultNum: info.homologNum, diff --git a/templates/disclaimer-stub.mustache b/templates/disclaimer-stub.mustache index 87a16dc9..584b4a11 100644 --- a/templates/disclaimer-stub.mustache +++ b/templates/disclaimer-stub.mustache @@ -1,10 +1,22 @@ +
Disclaimer
+
MonarchInitiative.org is not intended for direct diagnostic use or medical decision-making. If you have any health questions about the information contained on this website, please contact a medical professional. +
+ +
+The Monarch Initiative sources variant interpretations as provided by the original source +and provides mappings to third party databases such as dbSNP when possible. +
-The Monarch Initiative sources variant interpretations as provided by the original source +
Case pages provide a subset of the information included in the original source, such as +phenotypes and variants of interest. In addition, we provide similarity scores to diseases, other cases, and non-human models +based on phenotype profile comparisons computed by OwlSim. +This analysis is not intended to supersede the analysis performed by the original source. +
-For more information see our disclaimer +
For more information see our full disclaimer.
\ No newline at end of file diff --git a/templates/node.mustache b/templates/node.mustache index 2243879f..993af251 100644 --- a/templates/node.mustache +++ b/templates/node.mustache @@ -111,6 +111,11 @@
URI:  {{{iri}}}
+ {{#hasSource}} +
+ Source:  {{{source}}} +
+ {{/hasSource}} {{#hasBrw}}

From 1a77396719fa3c75c6a30f77fe0e8f4aff7963c6 Mon Sep 17 00:00:00 2001 From: kshefchek Date: Fri, 18 Nov 2016 15:02:51 -0800 Subject: [PATCH 15/17] add download buttons --- conf/golr-views/single-tab/case-variant.yaml | 2 +- css/monarch-common.css | 7 ++++++ js/golr-table.js | 3 ++- lib/monarch/api.js | 3 ++- lib/monarch/web/webapp.js | 23 ++++++++++++++++++++ templates/button.mustache | 3 +++ templates/node.mustache | 13 +++++++++++ 7 files changed, 51 insertions(+), 3 deletions(-) create mode 100644 templates/button.mustache diff --git a/conf/golr-views/single-tab/case-variant.yaml b/conf/golr-views/single-tab/case-variant.yaml index afe49a5c..13174b33 100644 --- a/conf/golr-views/single-tab/case-variant.yaml +++ b/conf/golr-views/single-tab/case-variant.yaml @@ -4,7 +4,7 @@ document_category: generic_association weight: 20 ## Results table, horizontal -result_weights: subject^6.0 object_gene^5.0 object^4.0 +result_weights: subject^6.0 object_gene^5.0 object^5.5 ## Ordering of facets, vertical filter_weights: subject_taxon_closure_label^3.5 object_taxon_closure_label^3.0 diff --git a/css/monarch-common.css b/css/monarch-common.css index cb68a6c3..d5a277ba 100644 --- a/css/monarch-common.css +++ b/css/monarch-common.css @@ -401,6 +401,13 @@ div.content-bottom > div.text-center > h2 { border:1px solid black; } +.download-btn { + margin-bottom: 7px; +} +.button-container{ + width: 150px; +} + /* Buttons */ /* These styles override some bootstrap button styles to make the buttons slimmer * and less skeuomorphic. */ diff --git a/js/golr-table.js b/js/golr-table.js index e4fc53a3..2adfe6b2 100644 --- a/js/golr-table.js +++ b/js/golr-table.js @@ -323,7 +323,8 @@ function addDownloadButton(pager, manager){ var field_list = fields; var args_hash = { rows : '100000', - header : "true" + header : 'true', + encapsulator: '0' }; var url = manager.get_download_url(field_list, args_hash); diff --git a/lib/monarch/api.js b/lib/monarch/api.js index c02c7073..b2e3398b 100644 --- a/lib/monarch/api.js +++ b/lib/monarch/api.js @@ -4630,6 +4630,7 @@ bbop.monarch.Engine.prototype.getGolrDownloadUrl = function (id, format, associa } var golrManager = new bbop.golr.manager.nodejs(golrServer, golrConf); + args_hash['encapsulator'] = '0'; if (typeof format === 'undefined') { format = 'tsv'; //default to tsv @@ -4645,7 +4646,7 @@ bbop.monarch.Engine.prototype.getGolrDownloadUrl = function (id, format, associa golrManager.add_query_filter_as_string(filter); field_list = ['subject', 'subject_label', 'subject_category', 'subject_taxon', 'subject_taxon_label', - 'relation', + 'subject_gene', 'subject_gene_label','relation', 'object', 'object_label', 'object_category', 'object_taxon', 'object_taxon_label', 'evidence','source']; diff --git a/lib/monarch/web/webapp.js b/lib/monarch/web/webapp.js index fc580d85..2a6269db 100644 --- a/lib/monarch/web/webapp.js +++ b/lib/monarch/web/webapp.js @@ -2151,6 +2151,29 @@ function caseByIdHandler(request, id, fmt) { // Link to disclaimer info.hasDisclaimer = true; + info.hasDownloads = true; + + downloadList = [ + { + 'button_class': 'btn-primary', + 'href': 'phenopacket?q=*:*&fq=subject_closure:"' + id + '"&personality=case', + 'text': "Phenopacket" + }, + { + 'button_class': 'btn-primary', + 'href': '/downloads/' + id + '/association/phenotype.tsv', + 'text': "Phenotypes" + }, + { + 'button_class': 'btn-primary', + 'href': '/downloads/' + id + '/association/variant.tsv', + 'text': "Variants" + } + ]; + + info.includes.downloads = downloadList.map(function (val) { + return expandTemplate('button', val); + }).join(' '); if (/^:c\d+$/.test(id)) { info.hasSource = true; diff --git a/templates/button.mustache b/templates/button.mustache new file mode 100644 index 00000000..42e3b66d --- /dev/null +++ b/templates/button.mustache @@ -0,0 +1,3 @@ + \ No newline at end of file diff --git a/templates/node.mustache b/templates/node.mustache index 993af251..849166f9 100644 --- a/templates/node.mustache +++ b/templates/node.mustache @@ -116,6 +116,19 @@ Source:  {{{source}}}
{{/hasSource}} + {{#hasDownloads}} +
+
+
+
+

Downloads

+
+ {{{includes.downloads}}} +
+
+
+
+ {{/hasDownloads}} {{#hasBrw}}

From 2b10378f0fc425bcb6476dae4a2ea9fd0f109eee Mon Sep 17 00:00:00 2001 From: kshefchek Date: Fri, 18 Nov 2016 16:21:43 -0800 Subject: [PATCH 16/17] add icons to download buttons --- css/monarch-common.css | 4 ++++ js/golr-table.js | 2 +- lib/monarch/api.js | 5 +++-- lib/monarch/web/webapp.js | 13 ++++++++----- templates/button.mustache | 8 +++++++- 5 files changed, 23 insertions(+), 9 deletions(-) diff --git a/css/monarch-common.css b/css/monarch-common.css index d5a277ba..c91a9455 100644 --- a/css/monarch-common.css +++ b/css/monarch-common.css @@ -403,10 +403,14 @@ div.content-bottom > div.text-center > h2 { .download-btn { margin-bottom: 7px; + text-align: left; } .button-container{ width: 150px; } +.btn-variant{ + width: 150px; +} /* Buttons */ /* These styles override some bootstrap button styles to make the buttons slimmer diff --git a/js/golr-table.js b/js/golr-table.js index 2adfe6b2..fd46ff20 100644 --- a/js/golr-table.js +++ b/js/golr-table.js @@ -324,7 +324,7 @@ function addDownloadButton(pager, manager){ var args_hash = { rows : '100000', header : 'true', - encapsulator: '0' + encapsulator: '"' }; var url = manager.get_download_url(field_list, args_hash); diff --git a/lib/monarch/api.js b/lib/monarch/api.js index b2e3398b..e47580cc 100644 --- a/lib/monarch/api.js +++ b/lib/monarch/api.js @@ -4630,7 +4630,7 @@ bbop.monarch.Engine.prototype.getGolrDownloadUrl = function (id, format, associa } var golrManager = new bbop.golr.manager.nodejs(golrServer, golrConf); - args_hash['encapsulator'] = '0'; + args_hash['encapsulator'] = '"'; if (typeof format === 'undefined') { format = 'tsv'; //default to tsv @@ -4647,7 +4647,8 @@ bbop.monarch.Engine.prototype.getGolrDownloadUrl = function (id, format, associa field_list = ['subject', 'subject_label', 'subject_category', 'subject_taxon', 'subject_taxon_label', 'subject_gene', 'subject_gene_label','relation', - 'object', 'object_label', 'object_category', + 'object', 'object_gene', 'object_gene_label', + 'object_label', 'object_category', 'object_taxon', 'object_taxon_label', 'evidence','source']; diff --git a/lib/monarch/web/webapp.js b/lib/monarch/web/webapp.js index 2a6269db..fb36804d 100644 --- a/lib/monarch/web/webapp.js +++ b/lib/monarch/web/webapp.js @@ -2155,19 +2155,22 @@ function caseByIdHandler(request, id, fmt) { downloadList = [ { - 'button_class': 'btn-primary', + 'button_class': 'btn-warning', 'href': 'phenopacket?q=*:*&fq=subject_closure:"' + id + '"&personality=case', - 'text': "Phenopacket" + 'icon': '/image/phenopackets_logo.png', + 'text': "PhenoPacket" }, { - 'button_class': 'btn-primary', + 'button_class': 'btn-success', 'href': '/downloads/' + id + '/association/phenotype.tsv', - 'text': "Phenotypes" + 'icon': '/image/carousel-phenotypes.png', + 'text': "Phenotypes" }, { 'button_class': 'btn-primary', 'href': '/downloads/' + id + '/association/variant.tsv', - 'text': "Variants" + 'icon': '/image/carousel-genes.png', + 'text': "Variants" } ]; diff --git a/templates/button.mustache b/templates/button.mustache index 42e3b66d..1d03ef9f 100644 --- a/templates/button.mustache +++ b/templates/button.mustache @@ -1,3 +1,9 @@
- {{text}} + + {{#icon}} + {{text}} + {{/icon}} + {{^icon}} + {{text}} + {{/icon}}
\ No newline at end of file From f35546f7d7473e26e3a79cb5c66b2641689a6906 Mon Sep 17 00:00:00 2001 From: kshefchek Date: Fri, 18 Nov 2016 16:41:13 -0800 Subject: [PATCH 17/17] forgot to add phenopacket img and slash --- image/phenopackets_logo.png | Bin 0 -> 5357 bytes lib/monarch/web/webapp.js | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) create mode 100644 image/phenopackets_logo.png diff --git a/image/phenopackets_logo.png b/image/phenopackets_logo.png new file mode 100644 index 0000000000000000000000000000000000000000..98c95e244879718021a3007bb1eeff22e4472f1a GIT binary patch literal 5357 zcmbVwcQhPK)b|p*VY5V8b@jSJRuCJ#ujqCOf{5Ot_ZGc`RiaA>mMGDp_bxU|o@h_B z=tK)5x*&M>`M$s3f8KNM%)K*nXXbZ*Gw04Z6OYz?ObKQI0{{R@4Ruw0qQ?JM$U($< zO%l0JR3zT|kCg!*M_7Ln8(co9r#=Sm_CEerUUq=TUREBCPBtp;Zhm%NK6YN5a1A#f zI~PI!R~O6x05nKLRq08J`0>FuLYRl1uL$2goQ{D8)WjE>?(QK~wWg11|p zQwc2^uBr-N*U>6$#3N8-O*CAQIAB^me!sSP?92P6=*P2Iyu4$_f_&=20O272`$GNw z4j;dbk#~XbM9%v;+Pxk2t~Tb6^1L^bWtbqKPr6LaotCZjot6>Hc6~Ku7DeoIQA!}L z@XW}R@M$sv=Jo5oS~BZ8Jz8O?i#m54(+$J%9RvfbhMXHnMS7q=R5^+|?ZBdsZQ`ug zQaxgjd5_^vP^@K(uF}8}!kU_*%wO)MIHJ# zV^xZ9wC!I#5BU>0ai$i|5u@s6bx73r^4h$AYVTyMHQ%G(p>OtPhQ_(2>&_^W#WVE} zqOKB|*cIoIgQUz zv|Y?b=~=bp2#HW!!2d_&7u)~;CN{yK&4#~Jo4v~mRhu<}6hOTXU!x|RKN+C8E%3dr zX+l+#6jJgt`tN|oh>y{|nLdBoZRNBNLqPr?aU8iy)<-K+ecvaXKR0>gR!e&gGr*KoE>~+58eY=Q4@0P8Io!fPE2~R@VDbUmO|dpfky$K9^p7egEVS zU&^m%Jm_ckm56&^zwt)SiP{(=&O_9B=h{qZlBi;kZypN1OD(v&zRnyAq~W<{xaL0z z(clh^Su@#|aL^hELEXhK{~-%{5cK(F0ZYLB?aR#GBh9rRZhz@% zqgT1j=;?kW=CxHM*k&<-=xQ=g*X<93v(?>a+cXD^O8y4CdAQh60Vs7@fONdJf1#T{ z%=sKfSmu`TZ&{6L_HFrIK{s{z#6M1xT;nL&U}vHZqrjn|D&sGGGAjXG{rueMS&GO& ztCJqp`6>r?D*&S)5U*;scy7UoaWg77i28Ihv)sqB+9+~pSuj&%dGa=>&zVoH-u-o) z>m-Bm8k@Oh@rbDVn{Q;RNHcmf(d*V)?8^uk-)x(neOrIE^6b)xFOg>C+->ID$Pbg7 zJHuK-jE%y6&&@%6CCqO1-lO;Y8olx1{6dI2!@4}{rIn<$glTY5UIK%dwBy96Ijz&L zXLwZec9$~w@6h!3dtJFZS?MB1l_mmSyop%H&2~l3Eh7`>O|=#c6tXo?aG*asoz|ft zK3;0BO;FMEZFPGOZ^BEO*-V#Bs{65>TX$t-W(%7rFlCh7}ce9An2wii_gEH1;m8&B=df}@8fl(i);wKNFVg9F`ap;&nNDR# zj2!rqdQTp-vU7rY9_f+I(I4^h;=qYljk4?=pMMv8Opkzc+C~-XQCD)#8?Xq(nlaN_ zQ%DJWasGOlHJ@438;g9&BPAB-rt`|979CgkO!#7U4r~p;utvCUFQqR6J zN-#F+P`Hf;7190ZVkv`zZ`C;n^ys_>>=}k)?fW!ko;r%El*Y-MRlN*-Q3SU{x~Gvk`||D zxhqH6maAZk8E9zo0-uxd@tIcIcTS?L;5~9*AVmDhC9d=Uz@CtyE~`($*Re=(@k+~z6FYN zLxN*o%i|=GmKa_dl&q&2iVtM4IOAAYdhr=4q->QJwfw!gAasX;s}`Q#kkFs54BzA*G1R@Ax zh+)SJcqQA=sdm??FRsP6w5-^7MY~(k?Ev8qWHWdTdrxQ*+RR5xlJ_dL3Wshw?L}+h zkT}x7U;9yGK`&W-raCDLv+(Ww_gQBc?srZOB|(ggvgYc!Q&mnwj{nlS8ta))uuX~= zmIuf_47ovnA+o?kjgo~W5EM6KpxE$MovloBpURToN@9YmP7<#H+YSliEg zX-ieFB%+rQmnY081y@-vES61d&O+k`;ZL2(-{nAt738^55Mgk-D$QutVR@;<&Ubz> z$2eAd-nA~@xe{;$$|@But*4tM6now9FERmQ%A_^OXVNB@E$@H{Fojad!SW=%2CAOf zm}xM?WTULC@YANAL?09Ab2=bHtw-gGnka-i_B#3P=I5mF zaBD|+#vsqmBStWAJZPnhi_sRxe+M3}41;RsVEND5vOmS`Q_7ppAAq2Wg?GTZkLwzd zJsFx29Ty>H^ls0!3eA45AvDJuIU`8nK1wvX7yUoiy1JeiP!CJIjmj4X0MT#QV`%jP zM^%bD=vX;cyg}}hFBcvV`O5Z+~dw5^C9NppOo+(WT7{)X*4j1oPRwK+KET+8=cvQFm zF%%fM!Y7!+aDwm?t%%B>IfeU1!rv&#MEU{*`N3r9H`G9a#X)oD-xcerdS_LRE9JhO z1X|_3Jg%pkV?dROU%X)_L4oNbxxT5K;r+$%jQ#po*$SpL(;WVix8GH=Ku}wIO6KjP zw|;!&VIe_3C6A$%@7gff6QO^>)xVdGA%ffpl*F*=y%T<^XV(#k9YxMB8Y$ zFe?E46pC`+^xz-LQ~73Rm_eA#Tf5vbWJb-MmqVTIjg^S+?;P$VAcAnUG}swCddB)G z)K0lV+89$y4q3$`3K2hCttdACqp0cZLy=-f?|cNRO2=U^+nv2$*&hIg;o>MoLXNjs z<73OLszD_1{EZNTnioBv2|IDu6y$Jf7?or9COUUN>RBLSC{sZ#!0HyBTFgreNnfDe zAd8jHdoPU2j}RkM`NIx$lM-HF4z~_ZoN0Wmd)+yMglG6He6JEBAOFFmXr-v;dY#|Q zW~!Xjqf-wAmpDgn8x84Ej8};7L$O>?3gCOD@p~rMBFFlnO9V= z>X(+&UB|sOf=c;CGM_JXt4z1oKLn3dEtqXR-E)~EUK0Xd!)tR{3NFF3)2X`pRv&TIJ+Kmz9-JThx9%IC~pv%4>ItxIj2WR2)$X;Zm$J64Szrr<2$Y zIdNM>lRU#^X&=@GwP$O8)3NlpX4hWS@qzhXcBh6|;=Mhe0%K^!Wi3r=UbZy0XDmg^BE9w|ys${N+u*#khOpHAQ4>jQ*@Ne)X*_(K7u=K4 zXRu_8Gql5}aS{$?0Q3OAW#CBp@BQ`Lf+Ab7tIV8%{H>0YQWmwPODdz`%5t$y$u-eo zv7Q_LDx462&ALHS(Ng#gZW+C{Bu6*-`_;0&muW=dAyw|z#_>+mvr+uRHv zL#2O|sfDS@%+;Hm$BS@|*=5YHYv3;zFBdz0kGu=sytQ=Ibrf|*{0op$;#Z^CM!wJq zSCU1Ys9jFTH5}{}o*%5x1S_j+gINeT#PNCrOqhq+WSg!cNrKsrl%oRJB-pFi{V?t8 z?O-c77jpoksNOuvYTdYU!~^4D4i5q*xqI%Bd`yw=w(ot|9o6BwUS$>fgM2ebaaVB zuOw<#lYjR1W;+4RAfB)(gNY^F!jpss0(UlaBBuLtIc+O7k?okpFkzO!MhGOas3K)` zx=wX0y;mSp(XR>CjGf&>_yya;vFYHwH1F&4di5fCWZYgLEfQ%fITKSV8K*m(BIKB8 z@9|+{tDtk=;fcAXesOZ>)Nxb&99$)J$*j!=Eo|BGV_x^Ln$su@lnSLvwnW5M=~#+Q{(SMa{4gC_{=VQb9mT2tKj?9{P7M;)7l414?$t~dJl7aknD4!2H&IX6 zswL@ovQi1yywo3^nM_RYA4fEPKh+ZSPaI%)cpW$qT$_j9vz#%USo*->B&Ov}@01=% z^+#4OAL$#VV}HX|whgMkfozleYs2So;#f2XknB~N{$m>hal`Ur@*nxJvQ9~JH<~PC zQo-nx4=9p|)$;m*tLn*uJKr3%ecfd)k8I)60^$_Saf_dR1>QyE=SSXPV)BJW{~*B zVF{{n6|sM&xh^7gjVh9XHO3hg-I`&4jHFa_?Gzjb?fz8g8Sb&$+ceBT@3$@{s!cmZ zcV%5l(Z>M)oCS%qm`qQKVwEk$GQ1U3=Fchr%QCkBZen?wTbLkPV$uO