o&&(n.val=o);var p;p=c.geo.origin.fixedLineage?c.geo.origin.windowOffset:{left:c.geo.origin.windowOffset.left+c.geo.window.scroll.left,top:c.geo.origin.windowOffset.top+c.geo.window.scroll.top},d.coord={left:p.left+(d.coord.left-c.geo.origin.windowOffset.left),top:p.top+(d.coord.top-c.geo.origin.windowOffset.top)},e.__sideChange(e.__instance._$tooltip,d.side),c.geo.origin.fixedLineage?e.__instance._$tooltip.css("position","fixed"):e.__instance._$tooltip.css("position",""),e.__instance._$tooltip.css({left:d.coord.left,top:d.coord.top,height:d.size.height,width:d.size.width}).find(".tooltipster-arrow").css({left:"",top:""}).css(n.prop,n.val),e.__instance._$tooltip.appendTo(e.__instance.option("parent")),e.__instance._trigger({type:"repositioned",event:b,position:d})},__sideChange:function(a,b){a.removeClass("tooltipster-bottom").removeClass("tooltipster-left").removeClass("tooltipster-right").removeClass("tooltipster-top").addClass("tooltipster-"+b)},__targetFind:function(a){var b={},c=this.__instance._$origin[0].getClientRects();if(c.length>1){var d=this.__instance._$origin.css("opacity");1==d&&(this.__instance._$origin.css("opacity",.99),c=this.__instance._$origin[0].getClientRects(),this.__instance._$origin.css("opacity",1))}if(c.length<2)b.top=Math.floor(a.geo.origin.windowOffset.left+a.geo.origin.size.width/2),b.bottom=b.top,b.left=Math.floor(a.geo.origin.windowOffset.top+a.geo.origin.size.height/2),b.right=b.left;else{var e=c[0];b.top=Math.floor(e.left+(e.right-e.left)/2),e=c.length>2?c[Math.ceil(c.length/2)-1]:c[0],b.right=Math.floor(e.top+(e.bottom-e.top)/2),e=c[c.length-1],b.bottom=Math.floor(e.left+(e.right-e.left)/2),e=c.length>2?c[Math.ceil((c.length+1)/2)-1]:c[c.length-1],b.left=Math.floor(e.top+(e.bottom-e.top)/2)}return b}}}),a});
\ No newline at end of file
diff --git a/app/assets/javascripts/vendor.js b/app/assets/javascripts/vendor.js
index 68827662c..76dfe4056 100644
--- a/app/assets/javascripts/vendor.js
+++ b/app/assets/javascripts/vendor.js
@@ -6,35 +6,22 @@
//
// WARNING: THE FIRST BLANK LINE MARKS THE END OF WHAT'S TO BE PROCESSED, ANY BLANK LINE SHOULD
// GO AFTER THE REQUIRES BELOW.
-//
+// Jquery 2 dependencies
//= require jquery2
//= require jquery-migrate-1.3.0.min
//= require jquery_ujs
//= require jquery-ui
+// popper is required by bootstrap 4
//= require popper
//= require bootstrap-sprockets
-//
-//= require jquery.blockUI
-//= require facebox
-//= require thickbox
-//= require fg.menu
-//= require jquery.tools.min
+// Other
//= require jquery.dataTables
-//= require dataTables.fixedHeader
//= require chosen.jquery
-//= require ajax-chosen
-//= require jquery.cookie
//= require autocomplete
-//= require jquery.hoverIntent
-//= require jquery.simple.tree
-//= require jquery.scrollTo-1.4.0-min
-//= require jquery.rating.pack
-//= require history/jquery.history
+// Alertify is used the admin page
//= require alertify
-//= require jquery.tooltip
-//= require Chart.min
-//= require select2
//= require jquery.readyselector
+// can be removed used only in the ontology bridge form
//= require trumbowyg
//= require sharer.min
diff --git a/app/assets/stylesheets/account.scss b/app/assets/stylesheets/account.scss
index 3112a95d4..c96f1b072 100644
--- a/app/assets/stylesheets/account.scss
+++ b/app/assets/stylesheets/account.scss
@@ -1,223 +1,255 @@
-.account-page-center{
- display: flex;
- justify-content: center;
- margin: 30px 0;
+.account-page-center {
+ display: flex;
+ justify-content: center;
+ margin: 30px 0;
+}
+.account-page-center svg path {
+ fill: var(--primary-color)
}
-.account-page-title{
- font-size: 18px;
- font-weight: 700;
+
+.clipboard .copy svg path {
+ fill: none;
}
-.account-page-sub-container{
- display: flex;
+.account-page-title {
+ font-size: 18px;
+ font-weight: 700;
}
-.account-page-first-row{
- width: 566px;
- margin-right: 20px;
+
+.account-page-sub-container {
+ display: flex;
+}
+
+.account-page-first-row {
+ width: 566px;
+ margin-right: 20px;
+}
+
+.account-page-second-row {
+ width: 566px;
+}
+
+#account-page-title-line {
+ width: 93px;
+ margin-top: 3px;
+ border: 0.5px solid var(--primary-color);
+ border-radius: 5px;
+ margin-bottom: 0px !important;
+}
+
+.account-page-card {
+ border: 1px solid #DFDFDF;
+ border-radius: 5px;
+ padding: 20px 20px;
+ margin-top: 20px;
+}
+
+.account-page-card-title {
+ font-size: 16px;
+ font-weight: 600;
+}
+
+.account-page-personal-informations-title-bar {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+}
+
+.account-page-rounded-button {
+ display: flex;
+ justify-content: center;
+ border: 0.5px solid var(--primary-color);
+ padding: 10px;
+ border-radius: 50px;
+ width: 40px;
+}
+
+.account-page-info-column {
+ display: flex;
+}
+
+.account-page-info-column .title {
+ margin-right: 9px;
+ font-size: 15px;
+ color: #666666;
+}
+
+.account-page-info-column .info {
+ font-size: 15px;
+ font-weight: 600;
+}
+
+.account-page-card-desc {
+ font-size: 13px;
+ color: #666666;
+ margin: 8px 0;
+}
+
+.apikey {
+ font-size: 17px;
+ font-weight: 600;
+}
+
+.account-page-card-container {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+}
+
+.account-page-no-ontology {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ flex-direction: column;
+ padding: 37px;
+}
+
+.account-page-no-ontology p {
+ color: #bbbbbb;
+ font-size: 16px;
+ margin: 26px 0;
+}
+
+.account-page-upload-ontology-button {
+ width: 220px;
+ font-size: 16px;
+ font-weight: 500;
+ color: var(--primary-color);
+ background-color: white;
+ padding: 16px;
+ border: 1px solid var(--primary-color);
+ border-radius: 5px;
+ text-align: center;
}
-.account-page-second-row{
- width: 566px;
-}
-
-#account-page-title-line{
- width: 93px;
- margin-top: 3px;
- border: 0.5px solid var(--primary-color);
- border-radius: 5px;
- margin-bottom: 0px !important ;
-}
-.account-page-card{
- border: 1px solid #DFDFDF;
- border-radius: 5px;
- padding: 20px 20px;
- margin-top: 20px;
-}
-.account-page-card-title{
- font-size: 16px;
- font-weight: 600;
-}
-.account-page-personal-informations-title-bar{
- display: flex;
- align-items: center;
- justify-content:space-between;
-}
-.account-page-rounded-button{
- display: flex;
- justify-content: center;
- border: 0.5px solid var(--primary-color);
- padding: 10px;
- border-radius: 50px;
- width: 40px;
-}
-.account-page-info-column{
- display: flex;
-}
-.account-page-info-column .title{
- margin-right: 9px;
- font-size: 15px;
- color: #666666;
-}
-
-.account-page-info-column .info{
- font-size: 15px;
- font-weight: 600;
-}
-.account-page-card-desc{
- font-size: 13px;
- color: #666666;
- margin: 8px 0;
-}
-.apikey{
- font-size: 17px;
- font-weight: 600;
-}
-.account-page-card-container{
- display: flex;
- justify-content: space-between;
- align-items: center;
-}
-.account-page-no-ontology{
- display: flex;
- align-items: center;
- justify-content: center;
- flex-direction: column;
- padding: 37px;
-}
-.account-page-no-ontology p{
- color: #bbbbbb;
- font-size: 16px;
- margin: 26px 0;
-}
-.account-page-upload-ontology-button{
- width: 220px;
- font-size: 16px;
- font-weight: 500;
- color: var(--primary-color);
- background-color: white;
- padding: 16px;
- border: 1px solid var(--primary-color);
- border-radius: 5px;
- text-align: center;
-}
-.account-page-select-ontology-set-button{
- display: flex;
- justify-content: space-between;
- align-items: center;
- width: 200px;
- border: 1px solid var(--primary-color);
- padding: 16px;
- border-radius: 5px;
- font-size: 16px;
- font-weight: 500;
- color: var(--primary-color);
-}
-.account-page-select-ontology-set-button p{
- margin-bottom: 0 !important;
-}
-.account-page-api-documentation-link{
- display: flex;
- margin-top: 10px;
-}
-.account-page-api-documentation-link a{
- font-size: 15px;
- font-weight: 500;
- color: var(--primary-color);
- text-decoration: none;
-}
-.account-page-api-documentation-link a svg{
- margin-left: 10px;
- margin-bottom: 5px;
-}
-svg path{
- fill: var(--primary-color);
-}
-
-.account-page-subscribe-button{
- border: 1px solid var(--primary-color);
- text-decoration: none;
- color: var(--primary-color);
- border-radius: 5px;
- padding: 12px 20px;
- font-size: 14px;
- font-weight: 500;
-}
-
-.account-page-subscription{
- margin-top: 10px;
- display: flex;
- justify-content: space-between;
-}
-.account-page-subscription a{
- font-size: 15px;
- font-weight: 400;
- color: var(--primary-color);
-}
-.account-page-subscription div{
- display: flex;
-}
-.account-page-subscription div .notes{
- margin-right: 23px;
- color: #666666 !important;
- font-weight: 400;
-}
-.account-page-subscription div .subscribe_to_notes{
- color: #EB4335 !important;
- font-weight: 400 !important;
- border: unset !important;
- background-color: unset !important;
- vertical-align: top;
- padding: unset !important;
- box-shadow: unset !important;
-}
-.account-page-small-cards-container{
- display: flex;
- flex-wrap: wrap;
-}
-.account-page-submitted-ontology{
- background-color: #F6F6F6;
- padding: 10px;
- border-radius: 5px;
- margin-right: 10px;
- margin-top: 10px;
-}
-
-.account-page-submitted-ontology a{
- color: #777777 !important;
- font-weight: 500;
- font-size: 15px;
-}
-.no-margin{
- margin: 0 !important;
-}
-.change-password{
- margin-top: 14px;
- display: flex;
- justify-content: center;
+.account-page-select-ontology-set-button {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ width: 200px;
+ border: 1px solid var(--primary-color);
+ padding: 16px;
+ border-radius: 5px;
+ font-size: 16px;
+ font-weight: 500;
+ color: var(--primary-color);
}
+
+.account-page-select-ontology-set-button p {
+ margin-bottom: 0 !important;
+}
+
+.account-page-api-documentation-link {
+ display: flex;
+ margin-top: 10px;
+}
+
+.account-page-api-documentation-link a {
+ font-size: 15px;
+ font-weight: 500;
+ color: var(--primary-color);
+ text-decoration: none;
+}
+
+.account-page-api-documentation-link a svg {
+ margin-left: 10px;
+ margin-bottom: 5px;
+}
+
+.account-page-subscribe-button {
+ border: 1px solid var(--primary-color);
+ text-decoration: none;
+ color: var(--primary-color);
+ border-radius: 5px;
+ padding: 12px 20px;
+ font-size: 14px;
+ font-weight: 500;
+}
+
+.account-page-subscription {
+ margin-top: 10px;
+ display: flex;
+ justify-content: space-between;
+}
+
+.account-page-subscription a {
+ font-size: 15px;
+ font-weight: 400;
+ color: var(--primary-color);
+}
+
+.account-page-subscription > div {
+ display: flex;
+}
+
+.account-page-subscription div .notes {
+ margin-right: 23px;
+ color: #666666 !important;
+ font-weight: 400;
+}
+
+.account-page-subscription div .subscribe_to_notes {
+ color: var(--error-color) !important;
+ font-weight: 400 !important;
+ border: unset !important;
+ background-color: unset !important;
+ vertical-align: top;
+ padding: unset !important;
+ box-shadow: unset !important;
+}
+
+.account-page-small-cards-container {
+ display: flex;
+ flex-wrap: wrap;
+}
+
+.account-page-submitted-ontology {
+ background-color: #F6F6F6;
+ padding: 10px;
+ border-radius: 5px;
+ margin-right: 10px;
+ margin-top: 10px;
+}
+
+.account-page-submitted-ontology a {
+ color: #777777 !important;
+ font-weight: 500;
+ font-size: 15px;
+}
+
+.no-margin {
+ margin: 0 !important;
+}
+
+.change-password {
+ margin-top: 14px;
+ display: flex;
+ justify-content: center;
+}
+
@media only screen and (max-width: 1200px) {
- .account-page-first-row{
- width: 47vw;
- margin-right: 20px;
- }
-
- .account-page-second-row{
- width: 47vw;
- }
+ .account-page-first-row {
+ width: 47vw;
+ margin-right: 20px;
+ }
+
+ .account-page-second-row {
+ width: 47vw;
+ }
}
@media only screen and (max-width: 950px) {
- .account-page-first-row{
- width: 80vw;
- margin-right: 20px;
- }
-
- .account-page-second-row{
- width: 80vw;
- }
- .account-page-sub-container{
- display:block;
- }
+ .account-page-first-row {
+ width: 80vw;
+ margin-right: 20px;
+ }
+
+ .account-page-second-row {
+ width: 80vw;
+ }
+ .account-page-sub-container {
+ display: block;
+ }
}
\ No newline at end of file
diff --git a/app/assets/stylesheets/admin.scss b/app/assets/stylesheets/admin.scss
index 440605d04..c52a938c8 100644
--- a/app/assets/stylesheets/admin.scss
+++ b/app/assets/stylesheets/admin.scss
@@ -8,6 +8,27 @@
margin-bottom: 30px;
}
+.analytics {
+ .card-header-1{
+ color: white; font-size: 60px; font-weight: 600; word-wrap: break-word
+ }
+
+ .card-header-2{
+ color: white; font-size: 14px; font-weight: 400; word-wrap: break-word
+ }
+
+ .card-header-3{
+ color: white; opacity: 0.6; font-size: 14px; font-weight: 400; word-wrap: break-word
+ }
+}
+
+.yasgui .autocompleteWrapper, .yasgui .tabContextButton{
+ display: none !important;
+}
+.yasqe .yasqe_buttons .yasqe_share{
+ display: none !important;
+}
+
.alert-box span {
font-weight: bold;
text-transform: uppercase;
@@ -50,6 +71,7 @@ table.dataTable tbody tr.selected {
.ontologies_list_container {
padding: 1em;
+ position: relative;
}
/* Datatables */
@@ -106,10 +128,7 @@ table.dataTable tbody tr.selected {
display: none;
}
-/* to fix facebox default sizing in chrome */
-#facebox .body {
- width: 375px !important;
-}
+
.zebra td {
padding: 8px 12px 8px 12px !important;
@@ -133,9 +152,7 @@ table.dataTable tbody tr.selected {
}
.site-admin-page-section {
- display: flex;
margin-top: 15px;
-
.admin-action-item {
margin-right: 8px;
}
@@ -166,3 +183,8 @@ div.groupFormError {
padding-top: 3px;
}
+
+div.groupFormError {
+ color: red;
+ padding-top: 3px;
+}
\ No newline at end of file
diff --git a/app/assets/stylesheets/agent_tooltip.scss b/app/assets/stylesheets/agent_tooltip.scss
new file mode 100644
index 000000000..7460f746e
--- /dev/null
+++ b/app/assets/stylesheets/agent_tooltip.scss
@@ -0,0 +1,43 @@
+.agent-container{
+ display: flex;
+ align-items: center;
+ margin: 10px;
+}
+.agent-circle{
+ width: 70px;
+ height: 70px;
+ background-color: var(--light-color);
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ border-radius: 35px;
+ margin-right: 12px;
+}
+.agent-name{
+ font-size: 18px;
+ font-weight: 600;
+ margin-bottom: 3px;
+}
+.agent-dependency{
+ font-size: 16px;
+ font-weight: 400;
+ color: #767676;
+ margin-bottom: 5px;
+ display: flex;
+ align-items: center;
+}
+.agent-type-icon path{
+ fill: var(--primary-color)
+}
+.agent-dependency-icon{
+ width: 20px;
+ height: 20px;
+ margin-right: 5px;
+}
+.agent-dependency-icon.ror{
+ width: 30px;
+ height: 30px;
+}
+.agent-dependency-icon path{
+ fill: #C0C0C0
+}
\ No newline at end of file
diff --git a/app/assets/stylesheets/agents.scss b/app/assets/stylesheets/agents.scss
index c469fae57..08e47fb87 100644
--- a/app/assets/stylesheets/agents.scss
+++ b/app/assets/stylesheets/agents.scss
@@ -1,3 +1,32 @@
+.agents-inputs input {
+ @extend .form-control !optional;
+ height: 100% !important;
+}
+.agent-chip{
+ display: flex;
+ justify-content: center;
+ align-items: center;
+}
+
+.agent-chip-circle svg{
+ height: 15px;
+}
+
+.agent-chip-circle{
+ height: 30px;
+ width: 30px;
+ background-color: rgba(128, 128, 128, 0.08);
+ border-radius: 15px;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ margin-right:10px;
+}
+
+.agent-chip-name{
+ color: #8C8E8D;
+ font-size: 15px;
+}
.agents-inputs input {
@extend .form-control !optional;
}
\ No newline at end of file
diff --git a/app/assets/stylesheets/annotator.scss b/app/assets/stylesheets/annotator.scss
index d07f55d7c..8cb42cc98 100644
--- a/app/assets/stylesheets/annotator.scss
+++ b/app/assets/stylesheets/annotator.scss
@@ -1,78 +1,236 @@
-div#semanticTypes_chzn.chzn-container input.default {
- font-style: oblique !important;
+.annotator-page-container{
+ display:flex;
+ justify-content:center;
}
-
-div#semanticTypes_chzn.chzn-container-active input.default {
- font-style: normal !important;
+.annotator-page-container a{
+ color: var(--primary-color) !important;
}
-
-div#annotations_filter, div#annotations_info {
- display: none;
+.annotator-page-subcontainer{
+ width: 1248px;
+ padding: 20px 50px;
}
-
-.result_count {
- font-weight: bold;
+.annotator-page-title{
+ font-size: 25px;
+ font-weight: 700;
+}
+.annotator-page-title .line{
+ height: 2px;
+ width: 57px;
+ background-color: var(--primary-color);
+ border-radius: 10px;
+}
+.annotator-page-decription{
+ color: #888888;
+ margin-top: 20px;
+}
+.annotator-page-inputs{
+ margin-top: 20px;
+}
+.annotator-page-inputs .inputs{
+ display: flex;
+}
+.annotator-page-text-area{
+ box-shadow: 2px 30px 60px rgba(0, 0, 0, 0.1);
+ border-radius: 8px;
+ width: 630px;
+ margin-right: 30px;
+}
+.annotator-page-text-area textarea{
+ font-size: 16px;
+ outline: none;
+ padding: 20px;
+ width: 630px;
+ border: none;
+ margin-right: 30px;
+}
+.annotator-page-text-area .insert-sample-text-button{
+ display: flex;
+ justify-content: flex-end;
+ padding: 10px 20px 20px 20px;
+}
+.annotator-page-text-area .insert-sample-text-button .button{
+ display: flex;
+ align-items: center;
+}
+.annotator-page-text-area .insert-sample-text-button .button:hover{
+ cursor: pointer;
+}
+.annotator-page-text-area .insert-sample-text-button .button .text{
+ font-size: 14px;
+ font-weight: 500;
+ color: var(--primary-color);
+ margin-right: 10px;
+}
+.annotator-page-text-area .insert-sample-text-button .button svg{
+ width: 16px;
+ height: 16px;
+}
+.annotator-page-text-area .insert-sample-text-button .button svg path{
+ fill: var(--primary-color);
+}
+.annotator-page-options{
+ width: 100%;
}
-#annotations th {
- padding-right: 6px;
+.annotator-page-options .section-text{
+ font-weight: 600;
+
+}
+.annotator-page-options .title{
+ margin-top: 10px;
+ color: #888888;
+ font-size: 14px;
+ font-weight: 500;
+ margin-bottom: 5px;
}
-#annotations span[class="popup_container"] {
- padding-left: 1.7em;
+.annotator-page-options .chips{
+ display: flex;
+}
+.annotator-page-options input{
+ accent-color: var(--primary-color) revert;
+}
+.annotator-page-options .radios{
+ display: flex;
}
-#annotator_parameters {
- color: gray;
- font-weight: bold;
+.annotator-page-options .advanced-options-button{
+ display: flex;
+ align-items: center;
+ margin-top: 15px;
+}
+.annotator-page-options .advanced-options-button:hover{
+ cursor: pointer;
+}
+.annotator-page-options .advanced-options-button .text{
+ margin-left: 10px;
+ color: var(--primary-color);
+ font-size: 14px;
}
-#annotations_container {
- display: none;
- margin-top: 10px;
- margin-bottom: 25px;
+.annotator-page-options .advanced-options-button svg path{
+ fill: var(--primary-color);
+}
+.annotator-page-button{
+ margin-top: 27px;
+ width: 630px;
}
-#annotations_container #result_counts {
- float: right;
- font-style: oblique;
+.annotator-page-options .chips{
+ display: flex;
+ flex-wrap: wrap;
+}
+.annotator-page-options .select-ontologies{
+ margin: 10px 0;
+}
+.annotator-page-options .preftitle{
+ font-size: 14px;
+ color: #666666;
+ margin-bottom: 5px;
+}
+.annotator-page-container .advanced-options-button{
+ color: var(--primary-color);
+ font-size: 14px;
+ margin-top: 5px !important;
+}
+.annotator-page-container .advanced-options-button:hover{
+ cursor: pointer;
+}
+.annotator-page-container .advanced-options-button svg{
+ margin-left: 5px;
+}
+.annotator-page-container .advanced-options-button svg path{
+ fill: var(--primary-color);
+}
+.annotator-page-container .advanced-options-button.hide-button svg{
+ transform: scaleY(-1);
+}
+.annotation-context{
color: gray;
+ font-weight: 400;
}
-
-#annotator-help i {
- margin-left: .25em;
+.annotator-page-container .highlighted-annotation{
+ color: black;
+ font-weight: 600;
+}
+.annotator-page-results .cont{
+ margin-top: 40px;
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+}
+.annotator-page-results .title{
+ font-size: 18px;
+ font-weight: 600;
+}
+.annotator-page-results .details{
+ color: #888888;
+}
+.annotator-page-container .more-advanced-options{
+ margin-top: 20px;
+}
+.annotator-page-container .more-advanced-options .filters_line{
+ display: flex;
+ margin-top: 20px;
+}
+.annotator-page-container .more-advanced-options .filters_line div{
+ width: 100%;
}
-/* AnnotatorPlus */
-
-.annotatorplus {
-
- #annotator-help > i.fa.fa-question-circle {
- margin-left: .25em;
- vertical-align: middle;
- }
-
- #download_links {
- margin-top: 1.5em;
- }
-
- #annotator_parameters {
- font-weight: normal;
- }
+.annotator-page-container .more-advanced-options .filters_line > :not(:first-child) {
+ margin-left: 20px;
+}
+.annotator-page-container .more-advanced-options .chips{
+ display: flex;
+ margin-top: 20px;
+}
+.annotation-parent{
+ display: flex;
+ white-space: nowrap;
+}
+.annotation-parent div, .annotation-parent a{
+ margin-right: 11px;
+}
+.annotation-parent .text{
+ margin-right: 8px;
+}
- .annotator_spinner {
- display: none;
-
- img {
- margin-left: 3px;
- vertical-align: middle;
- }
- }
+.annotation-parent a{
+ text-decoration: underline !important;
+}
+.annotator-page-options .prefrences{
+ margin-top: 10px;
+}
- .annotator_error {
- color: red;
- font-style: italic;
- margin-left: 3px;
- vertical-align: middle;
- }
-}
\ No newline at end of file
+.annotation-parent .level{
+ font-weight: 600;
+ color: var(--primary-color);
+}
+.annotation-parent .gray{
+ color: #888888;
+}
+.annotator-table-container{
+ margin-top: 20px;
+}
+.annotator-table-container .class{
+ width: 250px;
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+}
+.annotation-parent + div{
+ margin-top: 5px;
+}
+.annotator-bottom-actions{
+ margin-top: 20px;
+ display: flex;
+}
+.annotator-bottom-actions div{
+ display: inline-block;
+}
+.annotator-bottom-actions div + div{
+ margin-left: 20px;
+}
+.annotator-bottom-actions .rdf-button svg, .annotator-doc svg{
+ width: 21px;
+}
diff --git a/app/assets/stylesheets/application.css.scss.erb b/app/assets/stylesheets/application.css.scss.erb
old mode 100644
new mode 100755
index 28f3f1469..65c233fbd
--- a/app/assets/stylesheets/application.css.scss.erb
+++ b/app/assets/stylesheets/application.css.scss.erb
@@ -11,16 +11,12 @@
*= require jquery-ui
*= require alertify
*= require chosen
- *= require facebox
- *= require fg.menu
*= require jquery-ui-1.8.1.custom
*= require jquery.autocomplete
- *= require jquery.rating
- *= require jquery.tooltip
- *= require thickbox
- *= require select2
*= require trumbowyg
+ *= require flag-icon
*= require theme-variables
+ *= require summary
*/
/* BioPortal */
@@ -37,19 +33,32 @@
@import "recommender";
@import "search";
@import "submissions";
-@import "tree";
@import "ontolobridge";
@import "fair_assement";
@import "instances_table";
-@import "file_uploader";
@import "register";
@import "lostpassword";
@import "flatpickr/dist/themes/light";
+@import "tom-select/dist/scss/tom-select";
+@import "tippy.js/dist/tippy";
+@import 'tippy.js/themes/light-border';
+@import '@triply/yasgui/build/yasgui.min';
+//@import 'highlight.js/styles/default.min';
+@import 'highlight.js/styles/intellij-light';
@import "feedback";
@import "login";
@import "components/index";
@import "account";
@import "agents";
+@import "upload_ontology";
+@import "edit-ontology";
+@import "nav_bar";
+@import "ontology_details_header";
+@import "ontology_viewer";
+@import "browse";
+@import "agent_tooltip";
+@import "content_finder";
+@import "tools";
/* Bootstrap and Font Awesome */
diff --git a/app/assets/stylesheets/bioportal.scss b/app/assets/stylesheets/bioportal.scss
index f3b3a6e25..a13fd8843 100644
--- a/app/assets/stylesheets/bioportal.scss
+++ b/app/assets/stylesheets/bioportal.scss
@@ -1,3 +1,18 @@
+.turbo-progress-bar {
+ height: 5px;
+ background-color: var(--admin-color);
+}
+
+a{
+ text-decoration: none !important;
+}
+p {
+ margin-bottom: 0;
+}
+
+body{
+ position: relative;
+}
.alignright {
float:right;
@@ -6,6 +21,73 @@
float:left;
}
+.admin-border{
+ border: 1px solid;
+ border-radius: 5px;
+ border-color: var(--admin-color) !important;
+}
+
+.admin-background{
+ background-color: var(--bg-info-light-color) !important;
+ border-color: var(--admin-color) !important;
+ color: var(--admin-color) !important;
+ border-radius: 5px;
+}
+
+.container-gradient {
+ background: linear-gradient(-45deg, var(--admin-color), var(--primary-color), var(--admin-color));
+ background-size: 400% 400%;
+ animation: gradient 15s ease infinite;
+ .header-component{
+ color: white;
+ }
+
+ .field-description_text{
+ color: white !important;
+ opacity: 0.7;
+ }
+
+}
+
+.disabled-link{
+ pointer-events: none;
+ color: #888888 !important;
+ span{
+ opacity: 0.6;
+ }
+ a {
+ color: #888888 !important;
+ }
+ svg path{
+ fill: #888888 !important;
+ }
+}
+.text-truncate-scroll{
+ overflow: scroll;
+ white-space: nowrap;
+}
+
+
+.bg-warning-light{
+ background-color: var(--bg-warning-light-color) !important;
+}
+
+.bg-danger-light{
+ background-color: var(--bg-danger-light-color) !important;
+}
+
+@keyframes gradient {
+ 0% {
+ background-position: 0% 50%;
+ }
+ 50% {
+ background-position: 100% 50%;
+ }
+ 100% {
+ background-position: 0% 50%;
+ }
+}
+
#hd {
background: image-url('layout/header_bg.png') repeat-x;
width: 100%;
@@ -474,11 +556,15 @@ tr.mainresource td {
margin-bottom: 1em;
}
-.feedback ul li, .enable-lists ul li {
+.enable-lists ul li {
list-style-position: outside;
list-style-type: square;
margin-left: 1.5em;
}
+.feedback ul li{
+ list-style-position: outside;
+ margin-left: 1.5em;
+}
.enable-lists ul {
margin-bottom: 15px;
@@ -498,7 +584,7 @@ tr.mainresource td {
}
.obsolete_class {
- color: rgb(100,100,100);
+ color: rgb(100,100,100)!important;
cursor: help;
font-style: oblique;
}
@@ -568,7 +654,8 @@ div.tree_error {
}
#bd ul.simpleTree li{
- margin-left:-10px;
+ margin-left: 0px;
+ padding: 5px 0 0 10px;
}
#bd ul.simpleTree{
@@ -586,6 +673,26 @@ div.tree_error {
overflow:auto;
border: 1px solid #444444;
*/
+ a.tree-link {
+ display: inline-block;
+ padding: 5px;
+ word-break: break-all;
+ text-wrap: wrap;
+ color: var(--primary-color) !important;
+ }
+
+ a.tree-link.active {
+ cursor: default;
+ background-color: var(--light-color);
+ font-weight: bold;
+ border-radius: 3px;
+ padding: 7px 5px;
+ }
+
+ .tree-border-left{
+ border-left: 2px dotted #eee;
+ margin-left: 2px;
+ }
}
.simpleTree li {
list-style: none;
@@ -958,27 +1065,6 @@ button.fg-button-menu, button.fg-button {
border: none;
}
-#ontology_picker_container div.chzn-container {
- width: 432px !important;
-}
-
-#ontology_picker_container div.chzn-container-active ul.chzn-choices li.search-field input {
- font-style: normal !important;
-}
-
-#ontology_picker_container div.chzn-container ul.chzn-choices {
- max-height: 110px;
- overflow: auto !important;
-}
-
-#ontology_picker_container div.chzn-container li.search-field input {
- font-style: oblique;
-}
-
-#ontology_picker_container div.chzn-drop {
- display: none;
-}
-
.no_right_border {
border-right: none !important;
}
@@ -1137,6 +1223,9 @@ a.truncated_less, a.truncated_more {
.highlighted .search_ontology_acronym {
color: white;
}
+.hide {
+ display: none !important;
+}
.empty-state {
display: none;
@@ -1158,3 +1247,7 @@ turbo-frame[busy] .hide-if-loading, .show-if-loading {
turbo-frame[busy] ~ .show-if-loading {
display: inline-block;
}
+
+.hide{
+ display:none;
+}
\ No newline at end of file
diff --git a/app/assets/stylesheets/browse.scss b/app/assets/stylesheets/browse.scss
new file mode 100644
index 000000000..2dc96db26
--- /dev/null
+++ b/app/assets/stylesheets/browse.scss
@@ -0,0 +1,656 @@
+
+.browse-container p {
+ margin: unset;
+}
+
+.browse-container h2 {
+ margin: unset;
+ line-height: unset;
+}
+
+.browse-container hr {
+ margin: unset;
+}
+
+.browse-center {
+ display: flex;
+ justify-content: center;
+ margin: 20px 50px 50px;
+}
+
+.browse-title {
+ font-size: 22px;
+ font-weight: 700;
+}
+
+.browse-submit-new-ontology-and-you-are-admin-container {
+ display: flex;
+ justify-content: center;
+ margin-bottom: 20px;
+ padding: 20px;
+ & > div {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ border-radius: 5px;
+ border: 1px solid #DFDFDF;
+ }
+
+}
+
+.browse-desc-text {
+ font-size: 16px;
+ color: #666666;
+ font-weight: 400;
+ margin: 5px 0 !important;
+ overflow: hidden;
+ display: -webkit-box;
+ -webkit-box-orient: vertical;
+ -webkit-line-clamp: var(--read-more-line-clamp, 2);
+}
+
+
+.browse-you-are-admin {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ padding: 20px;
+ div {
+ display: flex;
+ align-items: center;
+ }
+}
+
+.browse-you-are-admin h3 {
+ font-size: 20px;
+ font-weight: 600;
+
+}
+
+.browse-you-are-admin div p {
+ margin-left: 20px;
+}
+
+.browse-upload-ontology-button {
+ margin: 20px 0;
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ font-size: 15px;
+ font-weight: 500;
+ color: var(--primary-color);
+ width: 226px;
+ padding: 15px 25px;
+ border: 1px solid var(--primary-color);
+ border-radius: 40px;
+}
+
+.browse-show-more-button {
+ cursor: pointer;
+ font-size: 14px;
+ color: gray;
+ margin-bottom: 10px;
+}
+
+.browse-ontology-container {
+ border: 1px solid #DFDFDF;
+ border-radius: 5px;
+ padding: 15px 20px;
+ margin-bottom: 20px;
+ position: relative;
+ box-shadow: rgba(100, 100, 111, 0.08) 0 7px 29px 0;
+}
+
+.browse-ontology-description {
+ width: 540px;
+}
+
+.browse-ontology-title {
+ color: var(--primary-color) !important;
+ font-weight: 600;
+ font-size: 18px;
+}
+
+.browse-fair {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ width: 400px;
+}
+
+.browse-sub-container {
+ display: flex;
+}
+
+.browse-first-row {
+ width: 300px;
+ margin-right: 35px;
+
+ .pill-button {
+ width: 100%;
+ justify-content: center;
+ }
+}
+
+.browse-second-row {
+ width: 828px;
+
+ .browse-ontologies {
+ margin-top: 90px;
+ }
+
+}
+
+#browse-title-line {
+ width: 55px;
+ margin-top: 3px;
+ border: 0.5px solid var(--primary-color);
+ border-radius: 5px;
+}
+
+.browse-fair-title {
+ font-size: 16px;
+ color: #666666;
+ font-weight: 400;
+}
+
+.browse-progress-bar {
+ width: 154px;
+ height: 10px;
+ border-radius: 20px;
+ background-color: #E7E7E7;
+
+}
+
+.browse-faire-progress {
+ width: 100%;
+ height: 10px;
+ background-color: var(--primary-color);
+ border-radius: 20px 0px 0px 20px;
+}
+
+.browse-fair-score {
+ font-size: 14px;
+ font-weight: 500;
+ color: #666666;
+}
+
+.browse-fair-details {
+ font-size: 14px;
+ font-weight: 400;
+ color: var(--primary-color) !important;
+}
+
+.browse-uploaded {
+ font-size: 13px;
+ height: 37px;
+ max-width: 400px;
+ background-color: var(--light-color);
+ border-radius: 5px;
+ display: flex;
+ padding: 2px 15px;
+ justify-content: space-between;
+ align-items: center;
+ color: var(--primary-color);
+ margin-top: 15px;
+}
+
+.browse-uploaded-date {
+ white-space: nowrap;
+}
+
+.browse-ontology-cards {
+ display: grid;
+ grid-template-columns: 113px 113px;
+ grid-template-rows: min-content;
+ grid-column-gap: 15px;
+ grid-row-gap: 15px;
+ direction: rtl;
+}
+
+.browse-onology-card {
+ border: 0.5px solid var(--primary-color);
+ border-radius: 5px;
+ height: 70px;
+ width: 100px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+ color: var(--primary-color) !important;
+}
+
+.browse-card-number {
+ font: 17px;
+ font-weight: 700;
+}
+
+.browse-card-text {
+ font-size: 15px;
+ font-weight: 500;
+}
+
+#browse-sub-title-line {
+ width: 20px;
+ margin-top: 3px;
+ border: 0.5px solid var(--primary-color);
+ border-radius: 5px;
+ margin-bottom: 15px;
+}
+
+.browse-filters-title {
+ font-weight: 600;
+ font-size: 16px;
+ text-decoration: underline;
+ text-underline-offset: 12px;
+ text-decoration-color: var(--primary-color);
+ text-decoration-thickness: 2px;
+ margin-bottom: 13px !important;
+}
+
+.browse-search-bar {
+ display: flex;
+
+}
+
+.browse-search-bar input {
+ border-radius: 14px;
+ box-shadow: rgba(100, 100, 111, 0.08) 0 7px 29px 0;
+ border: none;
+ // border: 1px solid #dee2e6;
+ padding: 20px 20px;
+ margin-bottom: 20px;
+ font-size: 16px;
+ position: absolute;
+ width: 828px;
+ z-index: 1;
+
+}
+
+.browse-search-bar input:focus {
+ box-shadow: rgba(100, 100, 111, 0.2) 0px 7px 29px 0px;
+ outline: none;
+}
+
+.browse-search-bar select {
+ border: none;
+ background-color: white;
+ padding: 20px 20px;
+ margin: 1px;
+ font-size: 16px;
+ background-image: url("data:image/svg+xml;utf8, ");
+ -webkit-appearance: none;
+ -moz-appearance: none;
+ background-repeat: no-repeat;
+ background-position-x: 90%;
+ background-position-y: 50%;
+
+}
+
+.browse-search-bar select:focus {
+ outline: none;
+ box-shadow: rgba(100, 100, 111, 0.1) 0px 7px 29px 0px;
+}
+
+.browse-search-bar .browse-format-filter {
+ position: absolute;
+ margin-left: 500px;
+ z-index: 2;
+ width: 150px;
+}
+
+.browse-search-bar .browse-sort-by-filter {
+ position: absolute;
+ margin-left: 632px;
+ z-index: 2;
+ width: 200px;
+ border-radius: 0 14px 14px 0;
+}
+
+.browse-search-button {
+ margin-left: 85%;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+
+ border-radius: 14px;
+ padding: 20px;
+ background-color: var(--primary-color);
+ width: 160px;
+ height: 62px;
+ cursor: pointer;
+}
+
+.browse-search-button p {
+ font-size: 16px;
+ color: white;
+ margin-left: 15px;
+}
+
+.browse-filter {
+ border: 1px solid #DFDFDF;
+ border-radius: 5px;
+ padding: 14px 20px;
+ margin-bottom: 12px;
+ box-shadow: rgba(100, 100, 111, 0.08) 0 7px 29px 0;
+ .switch-filter{
+ justify-content: space-between;
+ margin-bottom: 23px;
+ }
+}
+
+
+.align-alert{
+ justify-content: center;
+ display: flex;
+}
+
+.browse-filter-checks-container {
+ display: flex;
+ flex-wrap: wrap;
+ margin-top: 10px;
+
+ div {
+ display: grid;
+ flex-grow: 1;
+ }
+
+ .spinner-border-sm{
+ width: 0.75rem;
+ height: 0.75rem;
+ }
+}
+
+.browse-filter-title-bar {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ font-size: 14px;
+ font-weight: 400;
+ color: #666666;
+ cursor: pointer;
+}
+
+.browse-ontology-title-bar {
+ display: flex;
+ align-items: center;
+}
+
+.browse-ontology-deprecated {
+ background-color: #EB433521;
+ color: var(--error-color);
+ padding: 10px;
+ font-size: 14px;
+ border-radius: 8px;
+ margin-left: 15px;
+ margin-right: 15px;
+ font-weight: 500;
+}
+
+.browse-ontology-view {
+ background-color: var(--light-color);
+ color: var(--primary-color);
+ padding: 10px;
+ font-size: 14px;
+ border-radius: 8px;
+ margin-left: 15px;
+ font-weight: 500;
+}
+
+.browse-switch-filter {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ margin-bottom: 20px;
+}
+
+.browse-switch-filter p {
+ font-size: 16px;
+ color: #666666;
+}
+
+
+.browse-ontology-title-bar {
+ display: flex;
+ align-items: center;
+}
+
+.browse-ontology-deprecated {
+ background-color: #EB433521;
+ color: var(--error-color);
+ padding: 10px;
+ font-size: 14px;
+ border-radius: 8px;
+ margin-left: 15px;
+ font-weight: 500;
+}
+
+.browse-ontology-view {
+ background-color: var(--light-color);
+ color: var(--primary-color);
+ padding: 10px;
+ font-size: 14px;
+ border-radius: 8px;
+ margin-left: 15px;
+ font-weight: 500;
+}
+
+
+.browse-empty-illustration {
+ margin-top: 100px;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ flex-direction: column;
+}
+
+.browse-empty-illustration p {
+ font-size: 16px;
+ color: #B8B8B8;
+ font-weight: 500;
+ margin-top: 10px;
+}
+
+
+@media only screen and (max-width: 1250px) {
+ .browse-first-row {
+ width: 24vw;
+ margin-right: 20px;
+ }
+
+ .browse-second-row {
+ width: 68vw;
+ }
+ .browse-search-bar input {
+ width: 94vw;
+ }
+ .browse-search-bar .browse-format-filter {
+ margin-left: 50%
+ }
+ .browse-search-bar .browse-sort-by-filter {
+ margin-left: 65%
+ }
+
+}
+
+@media only screen and (max-width: 1005px) {
+ .browse-sub-container {
+ display: block;
+ }
+ .browse-second-row {
+ width: 94vw;
+ }
+ .browse-first-row {
+ width: 94vw;
+ }
+ .browse-search-bar input {
+ position: static;
+ margin-bottom: 1vw;
+ }
+ .browse-search-bar .browse-format-filter {
+ margin-left: 0;
+ position: static;
+ border-radius: 14px;
+ width: 46.5vw;
+ box-shadow: rgba(100, 100, 111, 0.1) 0px 7px 29px 0px;
+ margin-right: 1vw;
+ }
+ .browse-search-bar .browse-sort-by-filter {
+ margin-left: 0;
+ position: static;
+ border-radius: 14px;
+ width: 46vw;
+ box-shadow: rgba(100, 100, 111, 0.1) 0px 7px 29px 0px;
+ }
+
+ .browse-sub-container {
+ margin-top: 20px;
+ }
+ .browse-center {
+ margin-left: 20px;
+ }
+}
+
+@media only screen and (max-width: 893px) {
+ .browse-ontology-container {
+ display: block;
+ }
+ .browse-ontology-description {
+ width: 100%;
+ }
+ .browse-ontology-cards {
+ direction: ltr;
+ margin-top: 20px;
+ }
+ .browse-ontology-deprecated {
+ margin-right: 0;
+ }
+ .browse-ontology-view {
+ margin-right: 0;
+ }
+
+}
+
+
+// Browser loader skeleton
+
+.browse-sket {
+ display: flex;
+}
+
+.browse-sket-column-one {
+ margin-right: 37px;
+}
+
+.browse-sket-column-one .one {
+ width: 525px;
+ height: 50px;
+ background: linear-gradient(-90deg, #EEE, #F5F5F5, #EEE);
+ border-radius: 5px;
+ margin-bottom: 15px;
+ background-size: 400% 400%;
+ animation: skeleton 3s ease-in-out infinite;
+}
+
+.browse-sket-column-one .two {
+ width: 525px;
+ height: 44px;
+ background: linear-gradient(-90deg, #EEE, #F5F5F5, #EEE);
+ border-radius: 5px;
+ margin-bottom: 15px;
+ background-size: 400% 400%;
+ animation: skeleton 3s ease-in-out infinite;
+}
+
+.browse-sket-column-one .three {
+ width: 525px;
+ height: 18px;
+ background: linear-gradient(-90deg, #EEE, #F5F5F5, #EEE);
+ border-radius: 5px;
+ margin-bottom: 15px;
+ background-size: 400% 400%;
+ animation: skeleton 3s ease-in-out infinite;
+}
+
+.browse-sket-column-one .four {
+ width: 160px;
+ height: 36px;
+ background: linear-gradient(-90deg, #EEE, #F5F5F5, #EEE);
+ border-radius: 5px;
+ background-size: 400% 400%;
+ animation: skeleton 3s ease-in-out infinite;
+}
+
+.browse-sket-column-two {
+ margin-right: 15px;
+}
+
+.browse-sket-column-two .one {
+ width: 113px;
+ height: 78px;
+ background: linear-gradient(-90deg, #EEE, #F5F5F5, #EEE);
+ border-radius: 5px;
+ margin-bottom: 15px;
+ background-size: 400% 400%;
+ animation: skeleton 3s ease-in-out infinite;
+}
+
+.browse-sket-column-two .two {
+ width: 113px;
+ height: 78px;
+ background: linear-gradient(-90deg, #EEE, #F5F5F5, #EEE);
+ border-radius: 5px;
+ margin-bottom: 15px;
+ background-size: 400% 400%;
+ animation: skeleton 3s ease-in-out infinite;
+}
+
+.browse-sket-column-three .one {
+ width: 113px;
+ height: 78px;
+ background: linear-gradient(-90deg, #EEE, #F5F5F5, #EEE);
+ border-radius: 5px;
+ margin-bottom: 15px;
+ background-size: 400% 400%;
+ animation: skeleton 3s ease-in-out infinite;
+}
+
+.browse-sket-column-three .two {
+ width: 113px;
+ height: 78px;
+ background: linear-gradient(-90deg, #EEE, #F5F5F5, #EEE);
+ border-radius: 5px;
+ margin-bottom: 15px;
+ background-size: 400% 400%;
+ animation: skeleton 3s ease-in-out infinite;
+}
+
+@keyframes skeleton {
+ 0% {
+ background-position: 0 0;
+ }
+ 100% {
+ background-position: 400% 0;
+
+ }
+
+
+}
+
+
+#back_top_btn {
+ position: fixed;
+ bottom: 30px;
+ right: 30px;
+ transition: background-color .3s,
+ opacity .5s, visibility .5s;
+ opacity: 0;
+ visibility: hidden;
+ z-index: 1000;
+}
+
+
+#back_top_btn.show {
+ opacity: 1;
+ visibility: visible;
+}
\ No newline at end of file
diff --git a/app/assets/stylesheets/components/alert.scss b/app/assets/stylesheets/components/alert.scss
new file mode 100644
index 000000000..21403b307
--- /dev/null
+++ b/app/assets/stylesheets/components/alert.scss
@@ -0,0 +1,102 @@
+.alert-container {
+ display: flex;
+ align-items: center;
+ padding: 20px;
+ border-radius: 5px;
+
+
+}
+
+.alert-container.alert-info-type {
+ background-color: var(--bg-info-light-color);
+}
+
+.alert-container.alert-warning-type {
+ background-color: var(--bg-warning-light-color);
+}
+
+.alert-container.alert-danger-type {
+ background-color: var(--bg-danger-light-color);
+}
+
+.alert-container.alert-success-type {
+ background-color: var(--bg-success-light-color);
+}
+
+
+.alert-message {
+ font-size: 16px;
+ margin: 0 10px;
+ width: 100%;
+}
+
+
+.alert-message.alert-info-type {
+ color: rgb(59, 130, 246);
+}
+
+.alert-message.alert-warning-type {
+ color: rgb(234, 179, 8);
+}
+
+.alert-message.alert-danger-type {
+ color: rgb(239, 68, 68);
+}
+
+.alert-message.alert-success-type {
+ color: rgb(34, 197, 94);
+}
+
+.alert-icon {
+ align-self: flex-start;
+}
+
+.alert-icon svg {
+ width: 25px;
+ margin: 0 !important;
+}
+
+.alert-icon.alert-info-type svg path {
+ fill: rgb(59, 130, 246);
+}
+
+.alert-icon.alert-warning-type svg path {
+ fill: rgb(234, 179, 8);
+}
+
+.alert-icon.alert-danger-type svg path {
+ fill: rgb(239, 68, 68);
+}
+
+.alert-icon.alert-success-type svg path {
+ fill: rgb(34, 197, 94);
+}
+
+
+.alert-close svg {
+ width: 25px;
+ cursor: pointer;
+}
+
+.alert-close.alert-info-type svg path {
+ fill: rgb(59, 130, 246);
+}
+
+.alert-close.alert-warning-type svg path {
+ fill: rgb(234, 179, 8);
+}
+
+.alert-close.alert-danger-type svg path {
+ fill: rgb(239, 68, 68);
+}
+
+.alert-close.alert-success-type svg path {
+ fill: rgb(34, 197, 94);
+}
+
+
+.alert-button {
+ white-space: nowrap;
+ margin-right: 20px;
+}
+
diff --git a/app/assets/stylesheets/components/card.scss b/app/assets/stylesheets/components/card.scss
new file mode 100644
index 000000000..825f227cf
--- /dev/null
+++ b/app/assets/stylesheets/components/card.scss
@@ -0,0 +1,5 @@
+.summary-card {
+ border: 1px solid #dfdfdf;
+ border-radius: 5px;
+ margin-top: 20px;
+}
\ No newline at end of file
diff --git a/app/assets/stylesheets/components/card_message.scss b/app/assets/stylesheets/components/card_message.scss
index 0201775d3..9d3332a1c 100644
--- a/app/assets/stylesheets/components/card_message.scss
+++ b/app/assets/stylesheets/components/card_message.scss
@@ -34,6 +34,10 @@
color: #EE404C !important;
border: 1px solid #EE404C;
}
+.card-message-button-warning {
+ color: #ff6700 !important;
+ border: 1px solid #ff6700;
+}
.card-message-has-title{
color: #666666;
font-weight: 400;
diff --git a/app/assets/stylesheets/components/chip_button.scss b/app/assets/stylesheets/components/chip_button.scss
new file mode 100644
index 000000000..1b19a2981
--- /dev/null
+++ b/app/assets/stylesheets/components/chip_button.scss
@@ -0,0 +1,36 @@
+.chip_button_container {
+ background-color: #f6f6f6;
+ padding: 10px;
+ border-radius: 5px;
+ color: #777777 !important;
+ font-weight: 500;
+ font-size: 15px;
+ line-height: 44px;
+ display: inline;
+}
+.chip-button-component-container {
+ display: inline-block;
+}
+.chip-button-component-container svg path{
+ fill: var(--primary-color);
+}
+
+.chip_button_small {
+ font-size: 12px !important;
+ padding: 5px !important;
+ line-height: unset !important;
+}
+
+.chip_button_container_clickable {
+ background-color: var(--light-color);
+ line-height: 44px;
+ padding: 10px;
+ border-radius: 5px;
+ color: var(--primary-color);
+ font-weight: 500;
+ font-size: 15px;
+ display: inline;
+}
+.chip_button_container_clickable a{
+ color: var(--primary-color);
+}
diff --git a/app/assets/stylesheets/components/chips.scss b/app/assets/stylesheets/components/chips.scss
index 63811c9d1..ac1a2a939 100644
--- a/app/assets/stylesheets/components/chips.scss
+++ b/app/assets/stylesheets/components/chips.scss
@@ -1,4 +1,4 @@
-.chips-container div{
+.chips-container > div{
margin-right: 10px;
}
@@ -11,15 +11,17 @@
display: none;
}
+
.chips-container div label{
cursor: pointer;
}
.chips-container div label input[type="checkbox"]{
display: none;
}
-.chips-container div label span{
+.chips-container div label > span{
position: relative;
- display: inline-block;
+ display: flex;
+ align-items: center;
background:white;
border: 0.5px solid #BDBDBD;
color: #a7a7a7;
@@ -29,6 +31,10 @@
user-select: none;
}
+.chips-container.disabled div label > span, .chips-container div label span:has(span.disabled){
+ background-color: #f8f9fa !important;
+}
+
.chips-container div label input[type="checkbox"]:checked ~ span{
border: 1px solid var(--primary-color);
color: var(--primary-color);
diff --git a/app/assets/stylesheets/components/circle_progress_bar.scss b/app/assets/stylesheets/components/circle_progress_bar.scss
new file mode 100644
index 000000000..7c5095a64
--- /dev/null
+++ b/app/assets/stylesheets/components/circle_progress_bar.scss
@@ -0,0 +1,26 @@
+:root {
+ --circle-progress-bar-width: 50px;
+ --circle-progress-bar-height: 50px;
+}
+
+.circular-progress {
+ width: var(--circle-progress-bar-width);
+ height: var(--circle-progress-bar-height);
+ border-radius: 50%;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ position: relative;
+}
+.inner-circle {
+ position: absolute;
+ width: 85%;
+ height: 85%;
+ border-radius: 50%;
+}
+
+.percentage {
+ position: relative;
+ color: rgba(0, 0, 0, 0.8);
+ margin-bottom: 0;
+}
\ No newline at end of file
diff --git a/app/assets/stylesheets/components/concept_details.scss b/app/assets/stylesheets/components/concept_details.scss
new file mode 100644
index 000000000..47b0eb326
--- /dev/null
+++ b/app/assets/stylesheets/components/concept_details.scss
@@ -0,0 +1,9 @@
+.concept_details_component .raw-table .dropdown-title-bar p {
+ color: var(--primary-color);
+ font-weight: 500;
+}
+
+
+.concept_details_component table th {
+ width: 220px;
+}
\ No newline at end of file
diff --git a/app/assets/stylesheets/components/dropdown.scss b/app/assets/stylesheets/components/dropdown.scss
new file mode 100644
index 000000000..9d325c5c7
--- /dev/null
+++ b/app/assets/stylesheets/components/dropdown.scss
@@ -0,0 +1,21 @@
+.dropdown-title-bar {
+ display: flex;
+ align-items: center;
+ font-weight: 550;
+ justify-content: space-between;
+ font-size: 16px;
+ color: #000000;
+ cursor: pointer;
+ padding: 0 14px 0 0;
+}
+
+.dropdown-container {
+ border: 1px solid #dfdfdf;
+ border-radius: 5px;
+ margin-bottom: 20px;
+ margin-top: 20px;
+}
+
+.dropdown-item-selected {
+ background-color: var(--light-color) !important;
+}
\ No newline at end of file
diff --git a/app/assets/stylesheets/components/field_container.scss b/app/assets/stylesheets/components/field_container.scss
new file mode 100644
index 000000000..cd2b46ea7
--- /dev/null
+++ b/app/assets/stylesheets/components/field_container.scss
@@ -0,0 +1,23 @@
+.field-container {
+ margin-bottom: 0.5rem;
+}
+
+
+.field-description_text,
+.field-description_text a {
+ color: #888888 !important;
+ font-size: 15px;
+ margin-bottom: 0;
+}
+
+.field-description_text {
+ overflow: hidden;
+ display: -webkit-box;
+ -webkit-box-orient: vertical;
+ -webkit-line-clamp: var(--read-more-line-clamp, 5);
+}
+
+.field-normal_text {
+ font-size: 15px;
+ color: black;
+}
\ No newline at end of file
diff --git a/app/assets/stylesheets/components/file_input_loader.scss b/app/assets/stylesheets/components/file_input_loader.scss
new file mode 100644
index 000000000..029ab9f71
--- /dev/null
+++ b/app/assets/stylesheets/components/file_input_loader.scss
@@ -0,0 +1,54 @@
+.file_uploader {
+ color: #D7D7EF;
+ font-family: 'Lato', sans-serif;
+ border: 1px dashed #CFCFCF;
+ border-radius: 5px;
+}
+
+.file-message {
+ display: flex;
+ margin-top: 10px;
+ font-size: 12px;
+ color: #888888;
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+}
+
+.file_uploader>h2 {
+ margin: 50px 0;
+}
+
+.file-drop-area {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+ width: 100%;
+ padding: 25px;
+ transition: 0.2s;
+ position: relative;
+}
+
+.choose-file-button {
+ flex-shrink: 0;
+ background-color: rgba(255, 255, 255, 0.04);
+ border: 1px solid rgba(255, 255, 255, 0.1);
+ border-radius: 3px;
+ padding: 8px 15px;
+ margin-right: 10px;
+ font-size: 12px;
+ text-transform: uppercase;
+}
+
+.file-input {
+ height: 100%;
+ width: 100%;
+ cursor: pointer;
+ opacity: 0;
+ position: absolute;
+}
+
+.file-drop-area svg path {
+ fill: #CECECE;
+}
\ No newline at end of file
diff --git a/app/assets/stylesheets/components/header.scss b/app/assets/stylesheets/components/header.scss
new file mode 100644
index 000000000..ed8152788
--- /dev/null
+++ b/app/assets/stylesheets/components/header.scss
@@ -0,0 +1,16 @@
+.header-component {
+ display: flex;
+ align-items: center;
+ margin-bottom: 5px;
+ font-weight: 550;
+ justify-content: space-between;
+ font-size: 16px;
+ color: #000000;
+ cursor: pointer;
+ width: 100%;
+ padding: 14px 20px;
+ position: relative;
+ p {
+ margin-bottom: 0;
+ }
+}
\ No newline at end of file
diff --git a/app/assets/stylesheets/components/image.scss b/app/assets/stylesheets/components/image.scss
new file mode 100644
index 000000000..97414ab03
--- /dev/null
+++ b/app/assets/stylesheets/components/image.scss
@@ -0,0 +1,22 @@
+.image-container {
+ position: relative;
+ .image-content{
+ width: 100%;
+ object-fit: scale-down;
+ margin-bottom: 30px;
+ }
+ .loop_icon {
+ position: absolute;
+ width: 50px;
+ background-color: white;
+ box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1), 0 1px 3px rgba(0, 0, 0, 0.08);
+ border-radius: 50%;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ height: 50px;
+ padding: 10px;
+ bottom: 0;
+ right: 0;
+ }
+}
\ No newline at end of file
diff --git a/app/assets/stylesheets/components/index.scss b/app/assets/stylesheets/components/index.scss
index 39ee43892..3c7abb541 100644
--- a/app/assets/stylesheets/components/index.scss
+++ b/app/assets/stylesheets/components/index.scss
@@ -1,3 +1,37 @@
@import 'chips';
@import 'card_message';
+@import "notification";
+@import 'chip_button';
+@import 'rounded_button';
+@import 'summary_section';
+@import 'dropdown';
+@import 'field_container';
+@import 'modal';
+@import 'search_input';
+@import 'nested_form';
+@import 'circle_progress_bar';
+@import 'input_field';
+@import 'file_input_loader';
+@import 'text_area_field';
+@import 'regular_button';
+@import 'tabs_container';
+@import 'pill_tabs_container';
+@import 'outline_tabs_container';
+@import 'pill_button';
+@import "switch";
+@import "table";
+@import "concept_details";
+@import "card";
+@import "header";
+@import "image";
+@import "alert";
+@import "progress_pages";
+@import "select";
+@import "radio";
+@import "progress_bar";
+@import "search_result";
+@import "range_slider";
+@import "ontologies_selector";
+@import "loader";
+@import "vertical_tabs";
@import 'search_input';
\ No newline at end of file
diff --git a/app/assets/stylesheets/components/input_field.scss b/app/assets/stylesheets/components/input_field.scss
new file mode 100644
index 000000000..fff132fc5
--- /dev/null
+++ b/app/assets/stylesheets/components/input_field.scss
@@ -0,0 +1,36 @@
+.input-field-component {
+ width: 100%;
+ font-size: 13px;
+ padding: 10px;
+ border: 1px solid #BDBDBD;
+ border-radius: 5px;
+ outline: none;
+ resize: none;
+}
+
+.input-field-component:focus {
+ border: 1px solid var(--primary-color);
+}
+
+.text-input-label {
+ font-size: 14px;
+ color: #666666;
+ margin-bottom: 5px;
+ img {
+ width: 15px;
+ height: 15px;
+ vertical-align: text-bottom;
+ }
+}
+
+.text-input-error-text {
+ font-size: 12px;
+ color: var(--error-color)
+}
+
+.text-input-helper-text {
+ font-size: 12px;
+ color: #666666;
+ margin-top: 5px;
+}
+
diff --git a/app/assets/stylesheets/components/loader.scss b/app/assets/stylesheets/components/loader.scss
new file mode 100644
index 000000000..2392bba20
--- /dev/null
+++ b/app/assets/stylesheets/components/loader.scss
@@ -0,0 +1,12 @@
+.loader-component{
+ display: flex;
+ justify-content: center;
+}
+
+.lds-ellipsis.loader-component{
+ transform: scale(1);
+}
+
+.lds-ellipsis.loader-component div{
+ background: var(--primary-color);
+}
\ No newline at end of file
diff --git a/app/assets/stylesheets/components/modal.scss b/app/assets/stylesheets/components/modal.scss
new file mode 100644
index 000000000..2997e12e7
--- /dev/null
+++ b/app/assets/stylesheets/components/modal.scss
@@ -0,0 +1,20 @@
+.modal-content{
+ border-radius: 20px !important;
+}
+
+.modal-title {
+ text-align: center;
+ flex: 1px;
+}
+
+.close {
+ margin-left: 0px;
+ &:focus{
+ outline: none;
+ }
+}
+
+.shape {
+ border-radius: 50% !important;
+ width: 35px;
+}
\ No newline at end of file
diff --git a/app/assets/stylesheets/components/nested_form.scss b/app/assets/stylesheets/components/nested_form.scss
new file mode 100644
index 000000000..4bb85ba8d
--- /dev/null
+++ b/app/assets/stylesheets/components/nested_form.scss
@@ -0,0 +1,55 @@
+.nested-form-input-container .titles{
+ display: flex;
+ font-size: 14px;
+ color: #666666;
+ margin-bottom: 5px;
+ width: 90%;
+ img {
+ width: 15px;
+ height: 15px;
+ vertical-align: text-bottom;
+ }
+}
+
+
+.nested-form-input-container input:focus{
+ border: 1px solid var(--primary-color) !important;
+}
+
+.nested-form-input-container .delete{
+ display: flex;
+ border: 1px dashed #BDBDBD;
+ justify-content: center;
+ align-items: center;
+ height: 43px;
+ width: 43px;
+ border-radius: 5px;
+ cursor: pointer;
+}
+
+.nested-form-input-container .add-another-object{
+ border: 1px dashed #BDBDBD;
+ border-radius: 5px;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ padding: 10px;
+ cursor: pointer;
+ margin-top: 10px;
+}
+.nested-form-input-container .add-another-object svg path{
+ fill: #DADADA;
+}
+.nested-form-input-container .add-another-object div{
+ color: #DADADA;
+ margin-left: 10px;
+}
+
+
+
+
+
+
+
+
+
diff --git a/app/assets/stylesheets/components/notification.scss b/app/assets/stylesheets/components/notification.scss
new file mode 100644
index 000000000..fafecc190
--- /dev/null
+++ b/app/assets/stylesheets/components/notification.scss
@@ -0,0 +1,146 @@
+.notification {
+ display: flex;
+ position: fixed;
+ top: 0;
+ right: 0;
+ bottom: 0;
+ left: 0;
+ z-index: 50;
+ padding: 1.5rem 1rem;
+ justify-content: center;
+ align-items: flex-end;
+ pointer-events: none;
+ transition-property: background-color, border-color, color, fill, stroke, opacity, box-shadow, transform;
+ transition-duration: 1000ms;
+ transform: translateX(1rem);
+ opacity: 0;
+ @media (min-width: 640px) {
+ padding: 4rem 1.5rem 1.5rem;
+ justify-content: flex-end;
+ align-items: flex-start;
+ }
+}
+
+
+.notification-inner {
+ overflow: hidden;
+ padding: 1rem;
+ background-color: #ffffff;
+ width: 100%;
+ max-width: 24rem;
+ border-radius: 0.5rem;
+ pointer-events: auto;
+ box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05);
+}
+
+.notification-content {
+ display: flex;
+ align-items: flex-start;
+}
+
+.notification-content svg {
+ width: 1.5rem;
+ height: 1.5rem;
+}
+
+.notification-text {
+ padding-top: 0.125rem;
+ margin-left: 0.75rem;
+ flex: 1 1 0;
+ width: 0;
+}
+
+.notification-text p:first-of-type {
+ color: #111827;
+ font-size: 0.875rem;
+ line-height: 1.25rem;
+ font-weight: 500;
+}
+
+.notification-text p:last-of-type {
+ margin-top: 0.25rem;
+ color: #6B7280;
+ font-size: 0.875rem;
+ line-height: 1.25rem;
+}
+
+.notification-close {
+ display: inline-flex;
+ background-color: #ffffff;
+ color: #9CA3AF;
+ border: none;
+ cursor: pointer;
+}
+
+.notification-close svg {
+ height: 1rem;
+ outline: none;
+}
+
+.type-success path {
+ fill: #14a38c;
+}
+
+.type-error {
+ path:first-of-type {
+ fill: #f44336;
+ }
+
+ path {
+ fill: white;
+ }
+}
+
+.type-alert path {
+ fill: #edb464;
+}
+
+
+.slide-in-right {
+ animation-name: slide-in-right;
+ animation-duration: 0.5s;
+ animation-delay: 0.5s;
+ animation-timing-function: cubic-bezier(0.250, 0.460, 0.450, 0.940);
+ animation-fill-mode: forwards;
+}
+
+
+.slide-in-out-right {
+ animation-name: slide-in-right, slide-out-right;
+ animation-duration: 0.5s, 0.5s;
+ animation-delay: 0.5s, 5s;
+ animation-timing-function: cubic-bezier(0.250, 0.460, 0.450, 0.940), cubic-bezier(0.550, 0.085, 0.680, 0.530);
+ animation-fill-mode: forwards, forwards;
+}
+
+
+@keyframes slide-in-right {
+ 0% {
+ transform: translateX(1rem);
+ opacity: 0;
+ }
+ 50% {
+ opacity: 0.4;
+ }
+ 100% {
+ transform: translateX(0);
+ opacity: 1;
+ }
+}
+
+@keyframes slide-out-right {
+ 0% {
+ transform: translateX(0);
+ opacity: 1;
+ }
+ 50% {
+ opacity: 0.4;
+ }
+ 100% {
+ transform: translateX(1rem);
+ opacity: 0;
+ }
+}
+
+
+
diff --git a/app/assets/stylesheets/components/ontologies_selector.scss b/app/assets/stylesheets/components/ontologies_selector.scss
new file mode 100644
index 000000000..3b431afa5
--- /dev/null
+++ b/app/assets/stylesheets/components/ontologies_selector.scss
@@ -0,0 +1,137 @@
+.ontologies-selector-container{
+ width: 800px;
+ padding: 0 10px;
+
+}
+.ontologies-selector-input{
+ position: relative;
+ padding-bottom: 70px;
+}
+.ontologies-selector-input input{
+ width: 100%;
+ font-size: 15px;
+ padding: 15px 20px;
+ border-radius: 8px;
+ border: 1px solid #DCDCDC;
+ outline: none;
+ position: absolute;
+}
+.ontologies-selector-input input:focus{
+ border: 1px solid #a6a6a6;
+}
+.ontologies-selector-input svg{
+ position: absolute;
+ top: 17px;
+ right: 20px;
+}
+.ontologies-selector-input svg path{
+ fill: #a6a6a6;
+}
+
+.ontologies-selector-options .nav-item{
+ margin-right: 0px !important;
+}
+.ontologies-selector-options .tab-items{
+ width: 100%;
+ justify-content: space-between;
+}
+.ontologies-selector-options .tab-link{
+ padding: 0 10px;
+}
+.ontologies-selector-options .chips{
+ margin-top: 10px;
+ display: flex;
+ flex-wrap: wrap;
+}
+.horizontal-line{
+ margin: 10px 0;
+ width: 100%;
+ height: 1px;
+ background-color: #d7d7d7;
+ border-radius: 100%;
+}
+
+.ontologies-selector-results .chips-container div label > span{
+ font-size: 16px;
+ padding: 10px 15px;
+}
+.ontologies-selector-results label{
+ width: 100%
+}
+.ontologies-selector-results .chips-container > div{
+ margin-right: 0;
+}
+.ontologies-selector-results .ontologies svg{
+ display: none !important;
+}
+.ontologies-selector-results .ontologies{
+ max-height: 300px;
+ overflow-y: scroll;
+}
+.save-cancel-buttons{
+ display: flex;
+ justify-content: center;
+ margin-top: 20px;
+}
+.ontologies-selector-results .button{
+ width: 200px;
+}
+.ontologies-selector-results .button + .button{
+ margin-left: 20px
+}
+.switch-filters {
+ display: flex;
+}
+.switch-filters > div{
+ display: flex;
+ padding: 15px 20px;
+ border: 1px solid #d7d7d7;
+ border-radius: 8px;
+ margin-bottom: 20px;
+ color: #666666;
+}
+.switch-filters > div + div{
+ margin-left: 20px;
+}
+
+.switch-filters .text{
+ margin-right: 20px
+}
+
+.ontologies-selector-results .results-number{
+ color: #A1A1A1;
+ margin: 10px 0;
+}
+.ontologies-selector-results .results-number span{
+ color: var(--primary-color);
+}
+.ontologies-selector-button{
+ display: flex;
+ justify-content: end;
+ align-items: center;
+}
+.ontologies-selector-button .clear-selection{
+ margin-top: 5px;
+ font-size: 15px;
+ color: var(--primary-color);
+ margin-right: 20px;
+ cursor: pointer;
+}
+.ontologies-selector-button a{
+ color: var(--primary-color) !important;
+ margin-top: 5px;
+ font-size: 15px;
+}
+.ontologies-selector-button a svg{
+ display: none;
+}
+.ontologies-selector-button a span{
+ display: none;
+}
+
+.ontologies-selector-results .select-all{
+ cursor: pointer;
+}
+.ontologies-selector-button a{
+ margin-right: 0;
+}
\ No newline at end of file
diff --git a/app/assets/stylesheets/components/outline_tabs_container.scss b/app/assets/stylesheets/components/outline_tabs_container.scss
new file mode 100644
index 000000000..76c390d92
--- /dev/null
+++ b/app/assets/stylesheets/components/outline_tabs_container.scss
@@ -0,0 +1,27 @@
+
+.outline-tabs{
+ border: 1px solid rgba(0, 0, 0, 0.125);
+ border-radius: 0.25rem 0.25rem 0 0;
+ padding-top: 1rem;
+}
+.outline-tabs .tab-items .nav-item{
+ margin-right: 0;
+
+}
+
+.outline-tabs .tab-items .nav-item.active a{
+ color: var(--primary-color) !important;
+}
+
+.outline-tabs .nav-item .tab-link{
+ display: block;
+ padding: 0 1rem 0.2rem 1rem;
+}
+
+.outline-tabs + .tab-content {
+ .tab-pane{
+ border: 1px solid rgba(0, 0, 0, 0.125);
+ border-top: none ;
+ border-radius: 0 0 0.25rem 0.25rem;
+ }
+}
\ No newline at end of file
diff --git a/app/assets/stylesheets/components/pill_button.scss b/app/assets/stylesheets/components/pill_button.scss
new file mode 100644
index 000000000..13a88c1fb
--- /dev/null
+++ b/app/assets/stylesheets/components/pill_button.scss
@@ -0,0 +1,34 @@
+.pill-button {
+ font-size: 15px;
+ display: flex;
+ align-items: center;
+ border: 1px solid var(--primary-color);
+ border-radius: 32px;
+ padding: 10px 20px;
+ cursor: pointer;
+ transition: background-color ease 0.3s;
+ white-space: nowrap;
+ background-color: transparent;
+ &:focus{
+ outline: none;
+ }
+ a{
+ color: var(--primary-color) !important;
+ }
+}
+
+.pill-button:hover {
+ background-color: var(--primary-color);
+ color: white !important;
+ a {
+ color: white !important;
+ }
+}
+
+.pill-button:hover svg path {
+ fill: white;
+}
+
+.pill-button svg {
+ margin-right: 10px;
+}
\ No newline at end of file
diff --git a/app/assets/stylesheets/components/pill_tabs_container.scss b/app/assets/stylesheets/components/pill_tabs_container.scss
new file mode 100644
index 000000000..e03697544
--- /dev/null
+++ b/app/assets/stylesheets/components/pill_tabs_container.scss
@@ -0,0 +1,22 @@
+.pill-tabs-container {
+ display: flex;
+ justify-content: space-between;
+}
+
+.pill-tabs-container .tab-items{
+ margin-bottom: 10px;
+}
+
+.pill-tabs-container .nav-item {
+ display: block;
+ padding: 0.2rem 1rem;
+}
+
+.pill-tabs-container .nav-item.active {
+ border-radius: 5px;
+ background-color: var(--primary-color);
+ color: white !important;
+ a {
+ color: white !important;
+ }
+}
\ No newline at end of file
diff --git a/app/assets/stylesheets/components/primary_button.scss b/app/assets/stylesheets/components/primary_button.scss
new file mode 100644
index 000000000..5e534fecd
--- /dev/null
+++ b/app/assets/stylesheets/components/primary_button.scss
@@ -0,0 +1,101 @@
+.button-container{
+ width: 100%;
+}
+.primary-button {
+ width: 100%;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ font-size: 16px;
+ color: white;
+ height: 60px;
+ background-color: var(--primary-color);
+ border: none;
+ border-radius: 9px;
+ transition: background-color ease 0.3s;
+}
+.primary-button:hover {
+ background-color: var(--hover-color);
+ cursor: pointer;
+}
+
+
+.animation-container{
+ width: 100%;
+ height: 60px;
+ font-size: 16px;
+ background-color: var(--hover-color);
+ border: none;
+ border-radius: 9px;
+ justify-content: center;
+ align-items: center;
+ display: none;
+
+}
+.lds-ellipsis {
+ display: inline-block;
+ position: relative;
+ margin-top: 50px;
+ width: 80px;
+ height: 80px;
+ transform: scale(0.7);
+}
+
+.lds-ellipsis div {
+ position: absolute;
+ width: 13px;
+ height: 13px;
+ border-radius: 50%;
+ background: white;
+ animation-timing-function: cubic-bezier(0, 1, 1, 0);
+}
+
+.lds-ellipsis div:nth-child(1) {
+ left: 8px;
+ animation: lds-ellipsis1 0.6s infinite;
+}
+
+.lds-ellipsis div:nth-child(2) {
+ left: 8px;
+ animation: lds-ellipsis2 0.6s infinite;
+}
+
+.lds-ellipsis div:nth-child(3) {
+ left: 32px;
+ animation: lds-ellipsis2 0.6s infinite;
+}
+
+.lds-ellipsis div:nth-child(4) {
+ left: 56px;
+ animation: lds-ellipsis3 0.6s infinite;
+}
+
+@keyframes lds-ellipsis1 {
+ 0% {
+ transform: scale(0);
+ }
+
+ 100% {
+ transform: scale(1);
+ }
+}
+
+@keyframes lds-ellipsis3 {
+ 0% {
+ transform: scale(1);
+ }
+
+ 100% {
+ transform: scale(0);
+ }
+}
+
+@keyframes lds-ellipsis2 {
+ 0% {
+ transform: translate(0, 0);
+ }
+
+ 100% {
+ transform: translate(24px, 0);
+ }
+}
diff --git a/app/assets/stylesheets/components/progress_bar.scss b/app/assets/stylesheets/components/progress_bar.scss
new file mode 100644
index 000000000..7f60e1539
--- /dev/null
+++ b/app/assets/stylesheets/components/progress_bar.scss
@@ -0,0 +1,22 @@
+.progress-bar-component{
+ width: 100%;
+ height: 30px;
+ background-color: #E7E7E7;
+ border-radius: 3px;
+ margin-right: 5px;
+ position: relative;
+}
+.progress-bar-component-text{
+ position: absolute;
+ top: 4px;
+ left: 14px;
+ color: white;
+ z-index: 1;
+}
+.progress-bar-component-progress{
+ position: absolute;
+ height: 30px;
+ background-color: var(--primary-color);
+ border-radius: 3px;
+ z-index: 0;
+}
\ No newline at end of file
diff --git a/app/assets/stylesheets/components/progress_pages.scss b/app/assets/stylesheets/components/progress_pages.scss
new file mode 100644
index 000000000..42b055fa4
--- /dev/null
+++ b/app/assets/stylesheets/components/progress_pages.scss
@@ -0,0 +1,118 @@
+.progress-pages-container {
+ display: flex;
+ align-items: center;
+ margin-top: 20px;
+ margin-bottom: 50px;
+ width: 100%;
+}
+
+.progress-pages-container hr {
+ flex-grow: 1;
+ border: 1px solid #D9D9D9;
+ margin: 0;
+}
+
+.progress-pages-container hr.active {
+ border: 1px solid var(--primary-color);
+}
+
+.progress-pages-container .progress-item {
+ position: relative;
+ & > div {
+ position: absolute;
+ top: -13px;
+ left: -13px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ }
+}
+
+.progress-pages-container .progress-item:first-of-type {
+ & > div {
+ align-items: start;
+ left: 0;
+ }
+}
+
+.progress-pages-container .progress-item:last-of-type {
+ & > div {
+ align-items: flex-end;
+ left: -23px;
+ }
+}
+
+.progress-pages-container .progress-item div .active:nth-child(2) {
+ color: var(--primary-color);
+ font-weight: 600;
+}
+
+.progress-pages-container .progress-item div span:nth-child(2) {
+ position: absolute;
+ font-size: 12px;
+ top: 33px;
+ white-space: nowrap;
+ color: #A9A9A9;
+}
+
+.progress-pages-container .progress-content .active:nth-child(2) {
+ color: var(--primary-color);
+ font-weight: 600;
+}
+
+.progress-pages-container .progress-content div:nth-child(2) {
+ position: absolute;
+ right: -38px;
+ top: 33px;
+
+}
+
+
+
+.outlined-checked-circle {
+ border: 2px solid var(--primary-color) !important;
+ background-color: var(--primary-color) !important;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+}
+
+.outlined-active-circle {
+ border: 2px solid var(--primary-color) !important;
+}
+
+.outlined-circle {
+ border: 1px solid #D9D9D9;
+ border-radius: 13px;
+ height: 26px;
+ width: 26px;
+ background-color: white;
+
+}
+
+.outlined-checked-circle img {
+ display: block !important;
+}
+
+.outlined-active-circle img {
+ display: none;
+}
+
+.outlined-circle img {
+ display: none;
+}
+
+
+
+.progress-pages-actions {
+ display: flex;
+ justify-content: flex-end;
+ margin-top: 20px;
+}
+
+.progress-pages-next-button {
+ margin-left: 25px;
+}
+
+
+
diff --git a/app/assets/stylesheets/components/radio.scss b/app/assets/stylesheets/components/radio.scss
new file mode 100644
index 000000000..b59eaae28
--- /dev/null
+++ b/app/assets/stylesheets/components/radio.scss
@@ -0,0 +1,58 @@
+.radio{
+ position: relative;
+ border: 1px solid #BDBDBD;
+ padding: 4px 15px;
+ border-radius: 5px;
+ margin-right: 10px;
+}
+.radio.selected{
+ border-color: var(--primary-color);
+}
+.radio:hover{
+ cursor: pointer;
+}
+.radio input[type="radio"]{
+ display: none;
+}
+.radio span{
+ height: 12px;
+ width: 12px;
+ border-radius: 50%;
+ border: 1px solid #BDBDBD;
+ display: block;
+ position: absolute;
+ left: 15px;
+ top: 8px;
+}
+.radio span:after{
+ content: "";
+ height: 7px;
+ width: 7px;
+ background: var(--primary-color);
+ display: block;
+ position: absolute;
+ left: 50%;
+ right: 50%;
+ transform: translate(-46%, 21%) scale(0);
+ border-radius: 50%;
+ transition: transform 0.1s ease-in-out;
+}
+
+.radio input[type="radio"]:checked ~ span:after{
+ transform: translate(-46%, 21%) scale(1);
+}
+
+.radio input[type="radio"]:checked ~ span{
+ border: 1px solid var(--primary-color);
+}
+
+.radio .text{
+ padding-left: 20px;
+ font-size: 13px;
+ font-weight: 400;
+ color: #BDBDBD;
+}
+.radio input[type="radio"]:checked ~ .text{
+ color: var(--primary-color);
+ font-weight: 500;
+}
\ No newline at end of file
diff --git a/app/assets/stylesheets/components/range_slider.scss b/app/assets/stylesheets/components/range_slider.scss
new file mode 100644
index 000000000..4b54c3ba5
--- /dev/null
+++ b/app/assets/stylesheets/components/range_slider.scss
@@ -0,0 +1,59 @@
+.range-slider{
+ position: relative;
+ width: 100%;
+
+}
+.range-slider input{
+ -webkit-appearance: none;
+ -moz-appearance: none;
+ appearance: none;
+ background-color: #dbdbdb;
+ width: 100%;
+ position: absolute;
+ cursor: pointer;
+ height: 7px;
+ top: 4px;
+ border-radius: 5px;
+}
+.range-slider input::-webkit-slider-thumb{
+ -webkit-appearance: none;
+ width: 40px;
+ height: 40px;
+ cursor: pointer;
+ position: relative;
+ z-index: 3;
+}
+
+.range-slider .selector{
+ position: absolute;
+ z-index: 2;
+ left: 52%;
+}
+.range-slider .selector .select-button{
+ height: 15px;
+ width: 15px;
+ border-radius: 50%;
+ position: absolute;
+ background-color: var(--primary-color);
+}
+.range-slider .select-range{
+ width: 53%;
+ position: absolute;
+ z-index: 1;
+ background-color: gray;
+ border-radius: 3px 0 0 3px;
+ height: 7px;
+ top: 4px;
+ background-color: var(--primary-color);
+}
+
+.range-slider-container .selection{
+ background: var(--primary-color);
+ border-radius: 3px;
+ display: inline-block;
+ margin-bottom: 5px;
+ color: white;
+ padding: 1px 8px;
+}
+
+
diff --git a/app/assets/stylesheets/components/regular_button.scss b/app/assets/stylesheets/components/regular_button.scss
new file mode 100644
index 000000000..d92453991
--- /dev/null
+++ b/app/assets/stylesheets/components/regular_button.scss
@@ -0,0 +1,213 @@
+.regular-button {
+ width: 100%;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ font-size: 16px;
+ height: 60px;
+ border-radius: 9px;
+ padding: 0 30px;
+}
+.regular-button.slim{
+ border-radius: 5px;
+ height: 42px;
+ padding: 0 15px;
+}
+
+.primary-button {
+ color: white !important;
+ background-color: var(--primary-color);
+ border: none;
+ transition: background-color ease 0.3s;
+}
+.primary-button:focus {
+ outline: none;
+}
+
+.primary-button:hover {
+ background-color: var(--hover-color);
+ cursor: pointer;
+}
+
+.primary-button.disabled-button{
+ background-color: #a3a3a3;
+}
+.primary-button.disabled-button:hover {
+ background-color: #a3a3a3;
+ cursor:default;
+}
+
+.danger-button.primary-button {
+ background-color: #F24C3D !important;
+}
+
+.danger-button.primary-button:hover {
+ background-color: #d74639 !important;
+}
+
+.warning-button.primary-button {
+ background-color: #F2BE22 !important;
+}
+
+.warning-button.primary-button:hover {
+ background-color: #dcac1d !important;
+}
+
+.secondary-button {
+ color: var(--primary-color) !important;
+ border: 1px solid var(--primary-color);
+ transition: background-color ease 0.3s;
+ background-color: rgba(0, 0, 0, 0) !important;
+}
+
+.secondary-button:focus {
+ outline: none;
+}
+
+.secondary-button:hover {
+ background-color: var(--primary-color) !important;
+ cursor: pointer;
+ color: white !important;
+
+ .secondary-button-icon path {
+ fill: white;
+ }
+}
+
+.secondary-button.disabled-button {
+ border: 1px solid #a3a3a3;
+ color: #a3a3a3 !important;
+}
+
+.secondary-button.disabled-button:hover {
+ background-color: rgba(0, 0, 0, 0) !important;
+ cursor: default;
+ color: #a3a3a3 !important;
+}
+
+.secondary-button.danger-button {
+ color: #F24C3D !important;
+ border: 1px solid #F24C3D;
+}
+.secondary-button.danger-button:hover {
+ background-color: #F24C3D !important;
+ color: white !important;
+}
+.secondary-button.warning-button {
+ color: #F2BE22 !important;
+ border: 1px solid #F2BE22;
+}
+
+.secondary-button.warning-button:hover {
+ background-color: #dcac1d !important;
+ color: white !important;
+}
+
+.left-button-icon{
+ margin-right: 10px;
+ margin-bottom: 3px;
+}
+
+.right-button-icon {
+ margin-left: 10px;
+ margin-bottom: 3px;
+}
+
+.secondary-button-icon path {
+ fill: var(--primary-color);
+}
+
+.primary-button-icon path {
+ fill: white !important;
+}
+
+
+.animation-container {
+ width: 100%;
+ height: 60px;
+ font-size: 16px;
+ background-color: var(--hover-color);
+ border: none;
+ border-radius: 9px;
+ justify-content: center;
+ align-items: center;
+ display: none;
+}
+.animation-container.slim {
+ border-radius: 5px;
+ height: 42px;
+}
+.animation-container.danger-button{
+ background-color: #d74639 !important;
+}
+.animation-container.warning-button{
+ background-color: #dcac1d !important;
+}
+
+.lds-ellipsis {
+ display: inline-block;
+ position: relative;
+ margin-top: 50px;
+ width: 80px;
+ height: 80px;
+ transform: scale(0.7);
+}
+
+.lds-ellipsis div {
+ position: absolute;
+ width: 13px;
+ height: 13px;
+ border-radius: 50%;
+ background: white;
+ animation-timing-function: cubic-bezier(0, 1, 1, 0);
+}
+
+.lds-ellipsis div:nth-child(1) {
+ left: 8px;
+ animation: lds-ellipsis1 0.6s infinite;
+}
+
+.lds-ellipsis div:nth-child(2) {
+ left: 8px;
+ animation: lds-ellipsis2 0.6s infinite;
+}
+
+.lds-ellipsis div:nth-child(3) {
+ left: 32px;
+ animation: lds-ellipsis2 0.6s infinite;
+}
+
+.lds-ellipsis div:nth-child(4) {
+ left: 56px;
+ animation: lds-ellipsis3 0.6s infinite;
+}
+
+@keyframes lds-ellipsis1 {
+ 0% {
+ transform: scale(0);
+ }
+
+ 100% {
+ transform: scale(1);
+ }
+}
+
+@keyframes lds-ellipsis3 {
+ 0% {
+ transform: scale(1);
+ }
+
+ 100% {
+ transform: scale(0);
+ }
+}
+
+@keyframes lds-ellipsis2 {
+ 0% {
+ transform: translate(0, 0);
+ }
+
+ 100% {
+ transform: translate(24px, 0);
+ }
+}
\ No newline at end of file
diff --git a/app/assets/stylesheets/components/rounded_button.scss b/app/assets/stylesheets/components/rounded_button.scss
new file mode 100644
index 000000000..41e2b7695
--- /dev/null
+++ b/app/assets/stylesheets/components/rounded_button.scss
@@ -0,0 +1,17 @@
+.rounded-button {
+ border: 1px solid var(--primary-color);
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ right: 40px;
+ transition: background-color ease 0.3s;
+}
+
+.rounded-button:hover {
+ background-color: var(--primary-color);
+
+}
+
+.rounded-button:hover svg path {
+ fill: white;
+}
\ No newline at end of file
diff --git a/app/assets/stylesheets/components/search_input.scss b/app/assets/stylesheets/components/search_input.scss
index 8f2d88ef1..dd721562a 100644
--- a/app/assets/stylesheets/components/search_input.scss
+++ b/app/assets/stylesheets/components/search_input.scss
@@ -1,4 +1,4 @@
-#home-search-drop-down{
+.search-container{
display: none;
font-size: 16px;
background: white;
@@ -6,41 +6,96 @@
border-radius: 0 0 14px 14px;
border: none;
box-shadow: 2px 30px 60px rgba(0, 0, 0, 0.1);
+ position: absolute;
}
-.home-search-ontology-content{
+.search-content{
display: flex;
+ flex-wrap: wrap;
color: #777777 !important;
justify-content: space-between;
padding: 20px 20px;
cursor: pointer;
border-top: 1px solid #f7f7f7
}
-.home-search-ontology-content:hover{
+.search-content:hover{
background-color: rgba(0, 0, 0, 0.01);
}
-.home-search-ontology-content div{
+.search-content div{
display: flex;
}
-.home-search-ontology-content div img{
+.search-content div img{
width: 12px;
}
-.home-search-ontology-content div p{
+
+.search-content div p{
font-weight: 300;
- margin-left: 10px;
margin-bottom: 0;
+ word-break: break-word;
+}
+.search-content div small {
+ word-break: break-word;
}
-.home-dropdown-active{
+.search-dropdown-active{
box-shadow: none !important;
}
-#seached-ontology{
+
+.search-element{
margin-bottom: 0;
+ max-width: 280px;
}
-#seached-ontologies{
+
+.searched-elements{
margin-bottom: 0;
}
-.search-inputs input {
- @extend .form-control !optional;
-}
\ No newline at end of file
+.search-inputs{
+ position: relative;
+}
+
+.concepts-search-button{
+ top: 15px !important;
+ right: 10px !important;
+}
+
+
+.home-search-button{
+ position: absolute;
+ top: 38px;
+ right: 12px;
+}
+
+.home-search-button svg{
+ width: 15px;
+ height: 15px;
+ cursor: pointer;
+}
+.home-search-button svg path{
+ fill: var(--primary-color);
+}
+.home-search-button.search-input-nav-icon{
+ position: absolute;
+ top: 4px;
+ right: 6px;
+ z-index: 99;
+}
+.home-search-button.search-input-nav-icon svg{
+ width: 11px;
+ height: 11px;
+ cursor: pointer;
+}
+
+.home-search-button.search-input-nav-icon svg path{
+ fill: white;
+}
+.search-component-loader{
+ padding-top: 4px;
+ padding-right: 2px;
+ color: var(--primary-color);
+}
+.home-search-button.search-input-nav-icon .search-component-loader{
+ margin-top: 0;
+ padding-right: 0;
+ color: white;
+}
diff --git a/app/assets/stylesheets/components/search_result.scss b/app/assets/stylesheets/components/search_result.scss
new file mode 100644
index 000000000..fc9928861
--- /dev/null
+++ b/app/assets/stylesheets/components/search_result.scss
@@ -0,0 +1,118 @@
+.search-result-component.sub-component{
+ margin-bottom: 10px;
+}
+
+
+.search-result-component .title{
+ color: var(--primary-color) !important;
+ font-size: 20px;
+ font-weight: 500;
+}
+
+.search-result-component.sub-component .title{
+ color: var(--primary-color) !important;
+ font-size: 18px;
+ font-weight: 500;
+}
+
+.search-result-component .uri{
+ color: #888888;
+ font-size: 14px;
+ margin: 3px 0;
+}
+
+.search-result-component.sub-component .uri{
+ color: #888888;
+ font-size: 12px;
+ margin: 3px 0;
+}
+
+.search-result-component .actions{
+ display: flex;
+ margin-top: 10px;
+}
+
+.search-result-component.sub-component .actions{
+ display: flex;
+ margin-top: 7px;
+}
+
+.search-result-component .actions .button{
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ border-radius: 4px;
+ background-color: var(--light-color);
+ padding: 5px 13px;
+ margin-right: 10px;
+}
+
+.search-result-component .actions .button:hover{
+ cursor: pointer;
+}
+.search-result-component .actions .button svg{
+ width: 16px;
+}
+
+.search-result-component .actions .button svg path{
+ fill: var(--primary-color);
+}
+
+.search-result-component .actions .button .text{
+ color: var(--primary-color);
+ margin-left: 8px;
+}
+
+.search-result-component.sub-component .actions .button .text{
+ font-size: 12px;
+}
+
+.search-result-component.sub-component .actions .button svg{
+ width: 12px;
+}
+
+.search-result-component .actions .button.icon-right .text{
+ margin:0 8px;
+}
+
+.more-from-ontology{
+ display: flex;
+ margin-top: 10px;
+}
+
+.more-from-ontology .vertical-line{
+ width: 1px;
+ background-color: var(--primary-color);
+ border-radius: 100px;
+ margin-right: 30px;
+}
+
+.search-result-sub-components{
+ margin: 20px 0;
+}
+
+.search-result-sub-components .reuses-title{
+ display: flex;
+ align-items: center;
+ margin-bottom: 5px;
+}
+
+.search-result-sub-components .reuses-title div{
+ margin-left: 10px;
+ font-size: 16px;
+ font-weight: 600;
+ color: #888888;
+}
+
+.more-from-ontology.reuses{
+ background-color: #F8F8F8;
+}
+.more-from-ontology.reuses .vertical-line{
+ background-color: #888888;
+}
+.search-result-component .definition + .definition{
+ margin-top: 10px;
+}
+
+
+
diff --git a/app/assets/stylesheets/components/select.scss b/app/assets/stylesheets/components/select.scss
new file mode 100644
index 000000000..c53c1453b
--- /dev/null
+++ b/app/assets/stylesheets/components/select.scss
@@ -0,0 +1,61 @@
+.ts-wrapper{
+ display: flex;
+}
+
+.ts-control {
+ padding: 12px;
+ border-radius: 5px;
+}
+
+.ts-dropdown-content .option {
+ padding: 12px;
+}
+
+.ts-dropdown .active {
+ background-color: #f8f8f8;
+}
+
+.ts-dropdown {
+ flex: 1 1 auto;
+ min-width: 9rem;
+ margin: 0;
+ color: #666666;
+}
+
+
+.ts-wrapper.single .ts-control:after {
+ border-color: #343a40 transparent transparent;
+ border-style: solid;
+ border-width: 5px 5px 0;
+ content: " ";
+ display: block;
+ height: 0;
+ margin-top: -3px;
+ position: absolute;
+ right: calc(0.5rem);
+ top: 50%;
+ width: 0;
+}
+
+.ts-wrapper.multi .ts-control>div{
+ border-radius: 5px;
+ font-size: 11px;
+ padding: 2px 0 4px 6px;
+ color: #888888;
+}
+
+.ts-wrapper.plugin-remove_button:not(.rtl) .item .remove{
+ border-left: none;
+ color: #888888 !important;
+ margin-left: 0;
+ margin-right: 1px;
+}
+
+.ts-wrapper.plugin-remove_button .item .remove:hover {
+ background: unset;
+}
+
+.has-items .ts-control > input {
+ width: unset !important;
+}
+
diff --git a/app/assets/stylesheets/components/summary_section.scss b/app/assets/stylesheets/components/summary_section.scss
new file mode 100644
index 000000000..057208665
--- /dev/null
+++ b/app/assets/stylesheets/components/summary_section.scss
@@ -0,0 +1,12 @@
+.card_title {
+ display: flex;
+ font-size: 18px;
+ margin-bottom: 20px;
+
+ span:nth-child(1){
+ text-decoration: underline;
+ text-underline-offset: 12px;
+ text-decoration-color: var(--primary-color);
+ text-decoration-thickness: 2px;
+ }
+}
diff --git a/app/assets/stylesheets/components/switch.scss b/app/assets/stylesheets/components/switch.scss
new file mode 100644
index 000000000..003474383
--- /dev/null
+++ b/app/assets/stylesheets/components/switch.scss
@@ -0,0 +1,63 @@
+
+.switch-filter{
+ display:flex;
+ align-items: center;
+
+}
+.switch-filter > p, .switch-filter > div{
+ font-size: 16px;
+ color: #666666;
+ margin-bottom: 0;
+ margin-right: 10px;
+}
+
+
+
+/* Toggle switch css */
+.switch {
+ position: relative;
+ display: inline-block;
+ width: 40px;
+ height: 20px;
+ margin-bottom: 0;
+}
+.switch input {
+ opacity: 0;
+ width: 0;
+ height: 0;
+}
+.slider {
+ position: absolute;
+ cursor: pointer;
+ top: 0;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ background-color: #ccc;
+ -webkit-transition: .4s;
+ transition: .4s;
+ border-radius: 34px;
+}
+.slider:before {
+ position: absolute;
+ content: "";
+ height: 13px;
+ width: 13px;
+ left: 4px;
+ bottom: 4px;
+ background-color: white;
+ -webkit-transition: .4s;
+ transition: .4s;
+ border-radius: 50%;
+}
+input:checked + .slider {
+ background-color: var(--primary-color);
+}
+input:focus + .slider {
+ box-shadow: 0 0 1px var(--primary-color);
+}
+input:checked + .slider:before {
+ -webkit-transform: translateX(19px);
+ -ms-transform: translateX(19px);
+ transform: translateX(19px);
+}
\ No newline at end of file
diff --git a/app/assets/stylesheets/components/table.scss b/app/assets/stylesheets/components/table.scss
new file mode 100644
index 000000000..6c03be874
--- /dev/null
+++ b/app/assets/stylesheets/components/table.scss
@@ -0,0 +1,55 @@
+.table-content{
+ border-collapse: collapse;
+ width: 100%;
+ border-spacing: 0;
+ box-sizing: border-box !important;
+}
+.table-auto-layout{
+ table-layout: auto !important;
+}
+
+.table-layout-fixed{
+ table-layout: fixed;
+}
+
+.table-content thead th{
+ background-color: hsl(0, 0%, 100%);
+ border-bottom: 1px solid hsl(240, 4%, 85%);
+ font-weight: 700;
+ color: hsl(230, 13%, 9%);
+}
+
+.table-content-borderless thead th {
+ border-bottom: none !important;
+}
+
+.table-content td, .table-content th{
+ padding: 0.75rem;
+ vertical-align: top;
+}
+
+
+.table-content-stripped tbody tr:nth-child(odd) {
+ background-color: #FAFAFA;
+}
+
+.table-content tbody th:first-child {
+ color: #888888;
+ font-weight: 400;
+}
+
+table.dataTable thead td, table.dataTable thead th{
+ padding: 20px 10px;
+}
+
+
+.table-mini{
+ font-size: 14px;
+}
+
+.table-outline{
+ border: 1px solid #C7C7C7 !important;
+ border-radius: 8px;
+ padding: 10px;
+}
+
diff --git a/app/assets/stylesheets/components/tabs_container.scss b/app/assets/stylesheets/components/tabs_container.scss
new file mode 100644
index 000000000..bb670a95c
--- /dev/null
+++ b/app/assets/stylesheets/components/tabs_container.scss
@@ -0,0 +1,60 @@
+.tabs-container {
+ border-bottom: 1px solid #DFDFDF;
+ display: flex;
+ justify-content: space-between;
+ & > div {
+ display: flex;
+ justify-content: space-between;
+ width: 100%;
+ }
+}
+
+.tabs-container hr {
+ border: 1px solid #f3f3f3;
+ width: 100%;
+ margin: 0;
+}
+
+.tabs-container .tab-items {
+ display: flex;
+ margin: 0;
+ position: relative;
+}
+
+.tabs-container .tab-items > div {
+ font-size: 16px;
+ font-weight: 400;
+ color: #5e5e5e;
+ margin-right: 30px;
+ cursor: pointer;
+ opacity: 60%;
+ transition: opacity 0.3s ease;
+
+ a {
+ color: #5e5e5e !important;
+ }
+}
+
+.tabs-container .tab-items div:hover {
+
+ opacity: 100%;
+}
+
+.tabs-container .tab-items div hr {
+ display: none;
+ margin-top: 10px;
+}
+
+.tabs-container .tab-items .active {
+ font-weight: 500;
+ opacity: 100%;
+}
+
+.tabs-container .tab-items .active hr {
+ display: block;
+ border: 1px solid var(--primary-color);
+ opacity: 100%;
+}
+.container{
+ overflow-x: auto;
+}
diff --git a/app/assets/stylesheets/components/text_area_field.scss b/app/assets/stylesheets/components/text_area_field.scss
new file mode 100644
index 000000000..6f50aa4bc
--- /dev/null
+++ b/app/assets/stylesheets/components/text_area_field.scss
@@ -0,0 +1,14 @@
+.text-content {
+ overflow: hidden;
+ display: -webkit-box;
+ -webkit-box-orient: vertical;
+ -webkit-line-clamp: var(--read-more-line-clamp, 5);
+}
+
+
+.see_more_text {
+ color: var(--primary-color);
+ font-size: 15px;
+ margin-top: 10px;
+ text-align: end;
+}
\ No newline at end of file
diff --git a/app/assets/stylesheets/components/vertical_tabs.scss b/app/assets/stylesheets/components/vertical_tabs.scss
new file mode 100644
index 000000000..aa47a1923
--- /dev/null
+++ b/app/assets/stylesheets/components/vertical_tabs.scss
@@ -0,0 +1,83 @@
+.center {
+ display: flex;
+ justify-content: center;
+ margin-top: 50px;
+}
+
+.edit-ontology-container {
+ padding: 0 50px;
+ width: 1248px
+}
+
+.edit-ontology-title {
+ font-size: 18px;
+ font-weight: bold;
+}
+
+.edit-ontology-title hr {
+ width: 93px;
+ border: 1px solid var(--primary-color);
+ margin: 0;
+ opacity: 100%;
+}
+
+
+.tabs-left-column {
+ border-radius: 5px;
+ min-width: 250px;
+ .nav-pills.disabled a {
+ color: #888888 !important;
+ cursor: not-allowed;
+ }
+
+ .nav-pills:not(.disabled){
+ .vertical-tab-item.active {
+ color: var(--primary-color);
+ background-color: var(--light-color) !important;
+ border-left: 3px solid var(--primary-color);
+ font-weight: 700;
+ }
+
+
+
+ .vertical-tab-item:hover {
+ background-color: #F6F6F6;
+ }
+
+ }
+}
+
+.vertical-tab-item {
+ font-size: 14px;
+ width: 100%;
+ padding: 10px 15px;
+ font-weight: 500;
+ margin: 3px 0;
+ cursor: pointer;
+ border-radius: 5px;
+ transition: background-color ease 0.3s;
+}
+
+.tabs-right-column {
+ border-radius: 5px;
+ width: 100%;
+}
+
+
+
+.tabs-left-column input {
+ border: 1px solid #BDBDBD;
+ outline: none;
+ font-size: 14px;
+ border-radius: 5px;
+ padding: 10px 15px;
+ width: 100%;
+ margin-top: 20px;
+}
+
+
+
+
+
+
+
diff --git a/app/assets/stylesheets/concepts.scss b/app/assets/stylesheets/concepts.scss
index 7f3bc860d..e466177ed 100644
--- a/app/assets/stylesheets/concepts.scss
+++ b/app/assets/stylesheets/concepts.scss
@@ -14,11 +14,11 @@
}
a.btn.btn-link {
- padding: 0;
+ padding: 0;
}
}
-.concept_details td:nth-child(1) {
+.concept_details td:nth-child(2) {
white-space: nowrap;
}
@@ -31,3 +31,133 @@ div.synonym-change-request {
div.synonym-change-request button {
padding: 0px;
}
+.nav-link.active{
+ border-radius: 5px;
+}
+.concepts-general-details{
+ width: 870px;
+ border-radius: 5px;
+ border: 1px solid #DFDFDF;
+}
+.concepts-nav-item{
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+}
+
+.concepts-nav-item a{
+ margin: 12px 24px;
+ color: #888888 !important;
+ cursor: pointer;
+}
+.concepts-tabs-container{
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+}
+.concepts-tabs{
+ display: flex;
+ justify-content: space-between;
+ width: 589px;
+}
+.concepts-active-tab a{
+ font-weight: 600;
+ color: var(--primary-color) !important;
+}
+.concepts-active-tab hr{
+ margin: 0;
+ border: 1px solid var(--primary-color);
+ border-radius: 5px;
+ display: block !important;
+ width: 100%;
+}
+.concepts-nav-item hr{
+ margin: 0;
+ display: none;
+}
+#concepts-header-line{
+ margin: 0;
+}
+.concepts-json{
+ width: 32px;
+ height: 32px;
+ border: 1px solid var(--primary-color);
+ border-radius: 16px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ position: absolute;
+ right: 40px;
+ transition: background-color ease 0.3s;
+}
+.concepts-json:hover{
+ background-color: var(--primary-color);
+
+}
+.concepts-json:hover svg path{
+ fill: white;
+}
+
+.concepts-content div{
+ margin-bottom: 5px;
+}
+.concepts-raw-data{
+ margin-top: 20px;
+ border-radius: 5px;
+ border: 1px solid #DFDFDF;
+
+}
+.concepts-raw-title{
+ display: flex;
+ justify-content: space-between;
+ padding: 12px 24px;
+ color: #888888;
+ cursor: pointer;
+ font-size: 16px;
+ font-weight: 400;
+}
+.concepts-raw-title div{
+ padding: 10px 0px;
+}
+
+#details_content{
+ border: none !important;
+}
+
+#details_content .card{
+ border-top: none !important;
+ border-top-left-radius: 0;
+ border-top-right-radius: 0;
+}
+
+#concept_browser{
+ .outline-tabs div, .outline-tabs .tab-items{
+ width: 100%;
+ }
+ .outline-tabs .tab-items .nav-item {
+ flex: 1;
+ }
+ .outline-tabs .tab-items .nav-item a {
+ display: flex;
+ justify-content: center;
+ svg path {
+ fill: #5e5e5e !important;
+ }
+ }
+ .outline-tabs .tab-items .nav-item.active a {
+ svg path {
+ fill: var(--primary-color) !important;
+ }
+ }
+}
+
+.select-collection-placeholder{
+ display: flex;
+ justify-content: center;
+ color: var(--gray-color);
+ margin-top: 10px;
+}
+
+.concepts-mapping-count .d-flex{
+ display: inline !important;
+}
\ No newline at end of file
diff --git a/app/assets/stylesheets/content_finder.scss b/app/assets/stylesheets/content_finder.scss
new file mode 100644
index 000000000..4259b5720
--- /dev/null
+++ b/app/assets/stylesheets/content_finder.scss
@@ -0,0 +1,42 @@
+.content-finder-container{
+ display: flex;
+ justify-content: center;
+ margin-bottom: 6px;
+}
+
+.content-finder-container .inputs > div{
+ margin:10px 0;
+ text-align: center;
+}
+
+.content-finder-result{
+ text-align: left;
+ width: 95%;
+ margin-left: auto;
+ margin-right: auto;
+ background-color: #fff;
+}
+
+.content-finder-html-result{
+ max-width: 95%;
+ margin-left: auto;
+ margin-right: auto;
+}
+.hljs-custom-prefixes{
+ color: grey;
+}
+.hljs-custom-symbol{
+ color: red;
+}
+
+.hljs-custom-concepts{
+ color: #770088;
+}
+
+.hljs-subject{
+ color: green;
+}
+
+.hljs-predicate{
+ color: #770088;
+}
\ No newline at end of file
diff --git a/app/assets/stylesheets/edit-ontology.scss b/app/assets/stylesheets/edit-ontology.scss
new file mode 100644
index 000000000..5b47432c7
--- /dev/null
+++ b/app/assets/stylesheets/edit-ontology.scss
@@ -0,0 +1,146 @@
+.center {
+ display: flex;
+ justify-content: center;
+ margin-top: 50px;
+}
+
+.edit-ontology-container {
+ padding: 0 50px;
+ width: 1248px
+}
+.edit-ontology-container a{
+ color: var(--primary-color) !important;
+}
+
+.edit-ontology-title {
+ font-size: 18px;
+ font-weight: bold;
+}
+
+.edit-ontology-title hr {
+ width: 93px;
+ border: 1px solid var(--primary-color);
+ margin: 0;
+ opacity: 100%;
+}
+
+.edit-ontology-sub-container {
+
+ display: flex;
+}
+
+.edit-ontology-left-column {
+ border-radius: 5px;
+ width: 400px;
+ margin-right: 58px;
+
+}
+
+.edit-ontology-left-column {
+ .nav-pills.disabled a {
+ color: #888888 !important;
+ cursor: not-allowed;
+ }
+
+ .nav-pills:not(.disabled){
+ .edit-ontology-tab-item.active {
+ color: var(--primary-color);
+ background-color: var(--light-color) !important;
+ border-left: 3px solid var(--primary-color);
+ font-weight: 700;
+ }
+
+
+
+ .edit-ontology-tab-item:hover {
+ background-color: #F6F6F6;
+ }
+
+ }
+}
+
+.edit-ontology-tab-item {
+ font-size: 14px;
+ width: 100%;
+ padding: 10px 15px;
+ font-weight: 500;
+ margin: 3px 0;
+ cursor: pointer;
+ border-radius: 5px;
+ transition: background-color ease 0.3s;
+}
+
+.edit-ontology-right-column {
+ border-radius: 5px;
+ width: 100%;
+}
+
+.edit-ontology-desc {
+ font-size: 12px;
+ color: #777777;
+ margin: 10px 0;
+}
+
+.edit-ontology-desc a {
+ text-decoration: none;
+ color: var(--primary-color);
+}
+
+.edit-ontology-desc a svg {
+ transform: scale(1.2);
+}
+
+.edit-ontology-left-column input {
+ border: 1px solid #BDBDBD;
+ outline: none;
+ font-size: 14px;
+ border-radius: 5px;
+ padding: 10px 15px;
+ width: 100%;
+ margin-top: 20px;
+}
+
+.edit-ontology-field div {
+ font-size: 11px;
+ color: #666;
+
+}
+
+.edit-ontology-field input {
+ border: 1px solid #BDBDBD;
+ border-radius: 5px;
+ font-size: 14px;
+ padding: 10px 15px;
+ outline: none;
+ width: 100%;
+ margin-top: 5px;
+ margin-bottom: 20px;
+}
+
+.edit-ontology-field input:focus {
+ border-color: var(--primary-color);
+}
+
+#edit-ontology-actions-devider {
+ width: 100%;
+ border: 1px solid #E9E9E9;
+ border-radius: 210px;
+ margin: 20px 0;
+ opacity: 100%;
+
+}
+
+.edit-ontology-actions {
+ display: flex;
+ justify-content: flex-end;
+}
+
+.reset-all-button {
+ margin-right: 25px;
+ width: 186px;
+}
+
+.save-button {
+ width: 90px;
+}
+
diff --git a/app/assets/stylesheets/file_uploader.scss b/app/assets/stylesheets/file_uploader.scss
deleted file mode 100644
index 96c03f823..000000000
--- a/app/assets/stylesheets/file_uploader.scss
+++ /dev/null
@@ -1,53 +0,0 @@
-.file_uploader {
- color: #D7D7EF;
- font-family: 'Lato', sans-serif;
-}
-
-.file_uploader > h2 {
- margin: 50px 0;
-}
-
-
-.file-drop-area {
- position: relative;
- display: flex;
- align-items: center;
- width: 450px;
- max-width: 100%;
- padding: 25px;
- border: 1px dashed rgba(255, 255, 255, 0.4);
- border-radius: 3px;
- transition: 0.2s;
-
-}
-
-.choose-file-button {
- flex-shrink: 0;
- background-color: rgba(255, 255, 255, 0.04);
- border: 1px solid rgba(255, 255, 255, 0.1);
- border-radius: 3px;
- padding: 8px 15px;
- margin-right: 10px;
- font-size: 12px;
- text-transform: uppercase;
-}
-
-.file-message {
- font-size: small;
- font-weight: 300;
- line-height: 1.4;
- white-space: nowrap;
- overflow: hidden;
- text-overflow: ellipsis;
-}
-
-.file-input {
- position: absolute;
- left: 0;
- top: 0;
- height: 100%;
- width: 100%;
- cursor: pointer;
- opacity: 0;
-
-}
\ No newline at end of file
diff --git a/app/assets/stylesheets/footer.scss b/app/assets/stylesheets/footer.scss
index cddf69cfe..6cdd05791 100644
--- a/app/assets/stylesheets/footer.scss
+++ b/app/assets/stylesheets/footer.scss
@@ -1,10 +1,58 @@
-.legal-text {
- font-size: 0.9rem;
+.footer-container{
+ display: flex;
+ justify-content: center;
+ background-color: var(--primary-color);
+}
+footer{
+ width: 1248px;
+ background-color: var(--primary-color);
+ padding: 40px 50px;
}
-footer {
- img.logo {
- display: inline-block;
- max-width: 90%;
- }
-}
\ No newline at end of file
+.footer-header{
+ display: flex;
+ justify-content: space-between;
+ margin-bottom: 40px;
+}
+.footer-logo{
+ color: white;
+ display: flex;
+ align-items: center;
+}
+.footer-logo p{
+ margin-bottom: 0;
+ font-weight: 700;
+ font-size: 18px;
+ margin-left: 20px;
+}
+.footer-social-media-links a{
+ margin-left: 20px;
+ svg path {
+ fill: white;
+ }
+}
+.footer-nav-links{
+ display: flex;
+ flex-wrap: wrap;
+ justify-content: space-between;
+}
+.footer-nav-links div h2{
+ font-size: 21px;
+ font-weight: 700;
+ color: white;
+ margin-bottom: 10px;
+}
+.footer-nav-links div div{
+ display:flex;
+ flex-direction: column;
+}
+.footer-nav-links div a{
+ font-size: 16px;
+ font-weight: 400;
+ color: white !important;
+ margin-bottom: 10px;
+ opacity: 60%;
+}
+.footer-nav-links div a:hover{
+ opacity: 100%;
+}
diff --git a/app/assets/stylesheets/home.scss b/app/assets/stylesheets/home.scss
index f26409b71..327e0ed07 100644
--- a/app/assets/stylesheets/home.scss
+++ b/app/assets/stylesheets/home.scss
@@ -2,3 +2,536 @@ i.fa.fa-caret-square-o-down {
vertical-align: middle;
margin-left: 2px;
}
+
+
+
+.home-header-container{
+ height: 310px;
+}
+
+.home-header-background{
+ background-color: var(--primary-color);;
+ width: 100%;
+ height: 309px;
+ position: absolute;
+ z-index: 0;
+}
+
+.home-bubbles{
+ display: flex;
+ justify-content: center;
+}
+.home-bubble{
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ flex-direction: column;
+ background-color: rgba(255, 255, 255, 0.4);
+ position: absolute;
+ box-shadow: 2px 30px 60px rgba(0, 0, 0, 0.05);
+ transform: scale(0.1);
+ animation: scale-up 1s ease forwards;
+}
+.home-bubble-one{
+ width: 232px;
+ height: 232px;
+ border-radius: 116px;
+ z-index: 1;
+ margin-left: 622px;
+}
+.home-bubble-two{
+ width: 194px;
+ height: 194px;
+ border-radius: 97px;
+ z-index: 2;
+ margin-left: 387px;
+ margin-top: 161px;
+}
+.home-bubble-three{
+ width: 130px;
+ height: 130px;
+ border-radius: 65px;
+ z-index: 3;
+ margin-left: 656px;
+ margin-top: 192px;
+}
+.home-bubble-four{
+ width: 70px;
+ height: 70px;
+ border-radius: 35px;
+ z-index: 4;
+ margin-left: 815px;
+ margin-top: 189px;
+ transform: scale(1);
+
+}
+
+.home-bubble .h5{
+ color: white;
+ font-size: 18px;
+ margin: 0;
+ font-weight: 600;
+}
+.home-bubble p{
+ color: white;
+ font-size: 15px;
+ margin: 0;
+}
+.home-random-bubbles{
+ position: absolute;
+ transform: scale(0.1);
+ animation: scale-up-random 1s ease forwards;
+}
+.home-header-title-container{
+ display: flex;
+ justify-content: center;
+}
+.home-header-title{
+ position: absolute;
+ z-index: 4;
+ width: 500px;
+ margin-right: 664px;
+ margin-top: 123px;
+ opacity: 0;
+ transform: translateY(-100%);
+ animation: slide-and-fade 1s ease forwards;
+}
+.home-header-title h4{
+ font-size: 38px;
+ font-weight: 800;
+ color: white;
+}
+
+.home-header-title > p{
+ font-size: 20px;
+ font-weight: 400;
+ color: white;
+}
+
+.home-header-title .search-inputs input{
+ font-size: 16px;
+ outline: none;
+ padding: 20px;
+ width: 100%;
+ height: 100%;
+ margin-top: 20px;
+ border-radius: 14px;
+ border: none;
+ box-shadow: 2px 30px 60px rgba(0, 0, 0, 0.1);
+}
+.home-header-title .search-inputs input:focus{
+ box-shadow: 2px 30px 60px rgba(0, 0, 0, 0.15);
+}
+.home-twitter-loader{
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ height: 100%;
+}
+.home-statistics-link a{
+ color: var(--primary-color) !important;
+}
+
+.home-body-container{
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+}
+.home-body-container svg path{
+ fill: var(--primary-color);
+}
+.home-section{
+ padding: 0 50px;
+ margin-top: 70px;
+ width: 1248px;
+}
+.home-section > h4{
+ font-size: 20px;
+ margin-bottom: 5px;
+ font-weight: 700;
+}
+
+.home-section-line{
+ width: 60px;
+ margin-top: 3px;
+ border: 0.5px solid var(--primary-color);;
+ border-radius: 5px;
+ margin-bottom: 20px;
+}
+.home-statistics{
+ display: flex;
+}
+.home-statistics-container{
+ border-radius: 8px;
+ box-shadow: 2px 0px 60px rgba(0, 0, 0, 0.10);
+ padding: 30px 40px 10px 40px;
+
+}
+.home-statistics-container > div {
+ display: flex;
+ align-items: center;
+ flex-wrap: wrap;
+}
+.home-agroportal-figures{
+ margin-bottom: 20px;
+}
+
+.home-statistics-container > div > p {
+ font-size: 20px;
+ font-weight: 600;
+ margin-left: 18px;
+ margin-bottom: 0;
+}
+.home-statistics-item{
+ display: flex;
+ align-items: center;
+
+}
+.home-statistics> :not(:last-child){
+ margin-right: 49px;
+}
+.home-statistics-item hr{
+ height: 83px;
+ width: 0px;
+ border: 2px solid var(--primary-color);;
+ border-radius: 5px;
+ margin-right: 15px;
+ margin-top: 0;
+ margin-bottom: 0;
+}
+.home-statistics-item h4{
+ font-size: 30px;
+ font-weight: 600;
+ line-height: 1.2;
+ margin: 0;
+}
+.home-statistics-item p{
+ font-size: 18px;
+ font-weight: 400;
+ margin: 0;
+ color: #888;
+}
+.home-section > p {
+ font-size: 16px;
+ color: #888888;
+ margin-bottom: 9px;
+}
+.home-upload-benifits{
+ display: flex;
+ flex-wrap: wrap;
+}
+.home-upload-benifits div{
+ display: flex;
+ width: 455px;
+ align-items: flex-start;
+ margin-right: 57px;
+ margin-top: 15px
+}
+
+.home-upload-benifits div p{
+ margin-left: 17px;
+ font-size: 16px;
+ color: #888888;
+ margin-bottom: 0;
+}
+.home-upload-benifits div img{
+ margin-top: 3px
+}
+.home-ontologies-actions{
+ display: flex;
+ align-items: center;
+ margin-top: 30px;
+
+}
+.home-upload-ontology-button{
+
+ width: fit-content;
+ margin-right: 20px;
+}
+
+.home-upload-icon {
+ margin-right: 10px;
+}
+
+
+.home-recommendations-and-annotations{
+ font-size: 20px;
+ outline: none;
+ padding: 20px;
+ width: 100%;
+ resize: none;
+ border-radius: 14px;
+ border: none;
+
+}
+.home-services-buttons{
+ background-color: white;
+ border-radius: 8px;
+ padding: 0;
+ display: flex;
+ justify-content: flex-end;
+ align-items: center;
+}
+.home-services-buttons.container{
+ padding: 0 30px 30px 0;
+}
+.home-services-buttons .insert-sample-text-button{
+ display: flex;
+ align-items: center;
+ margin-right: 20px;
+}
+.home-services-buttons .insert-sample-text-button:hover{
+ cursor: pointer;
+}
+.home-services-buttons .insert-sample-text-button div{
+ color: var(--primary-color);
+ margin-right: 5px;
+ font-weight: 500;
+}
+.home-services-buttons .insert-sample-text-button svg{
+ width: 18px;
+ height: 18px;
+}
+.home-services-buttons .insert-sample-text-button svg path{
+ fill: var(--primary-color);
+
+}
+.home-card{
+ border-radius: 8px;
+ box-shadow: 2px 30px 60px rgba(0, 0, 0, 0.1);
+}
+.home-get-annotations{
+ cursor: pointer;
+ color: white;
+ background-color: var(--primary-color);
+ display: flex;
+ width: fit-content;
+ align-items: center;
+ padding: 15px 20px;
+ border-radius: 8px;
+ margin-left: 10px;
+ transition: background-color 0.3s ease;
+}
+.home-get-annotations:hover{
+ background-color: var(--hover-color);
+}
+.home-get-annotations p{
+ margin-right: 20px;
+ margin-bottom: 0;
+}
+.home-get-recommendations{
+ cursor: pointer;
+ color: var(--primary-color);
+ display: flex;
+ width: fit-content;
+ height: fit-content;
+ align-items: center;
+ padding: 15px 20px;
+ border-radius: 8px;
+ border: 1px solid var(--primary-color);
+ transition: background-color 0.3s ease;
+}
+.home-get-recommendations:hover{
+ color: white !important;
+ background-color: var(--primary-color);
+}
+.home-get-recommendations svg path{
+ fill: var(--primary-color)
+}
+.home-get-recommendations:hover .home-play-icon path{
+ fill: white;
+}
+.home-get-recommendations p{
+ margin-right: 20px;
+ margin-bottom: 0;
+}
+.home-section-sub-sections-container{
+ display: flex;
+ justify-content: space-between;
+}
+.home-sub-section-left{
+ width: 550px;
+}
+
+.home-sub-section-right{
+ width: 550px;
+}
+.home-sub-section-left h4, .home-sub-section-right h4{
+ font-size: 20px;
+ margin-bottom: 5px;
+ font-weight: 700;
+}
+.home-fair-scores{
+ height: 360px;
+ padding-top: 35px;
+}
+.home-twitter-news{
+ height: 360px;
+}
+.home-fair-scores a{
+ text-decoration: none;
+
+}
+.home-fair-details{
+ margin-right: 25px !important;
+}
+.home-fair-scores div{
+ display: flex;
+ justify-content: flex-end;
+ align-items: center;
+ margin-right: 20px;
+ margin-left: 27px;
+ margin-bottom: 14px;
+ color: var(--primary-color);
+}
+.home-fair-scores div p{
+ margin-right: 10px;
+ margin-bottom: 0;
+}
+.home-logos{
+ height: 138px;
+ display: flex;
+ align-items: center;
+ overflow: auto;
+
+}
+.home-logos img{
+ margin-left: 60px;
+}
+.home-upload-benifits svg{
+ width: 33px;
+ margin-top: 3px;
+}
+.home-upload-benifits svg path{
+ fill: var(--gray-color);
+}
+
+.home-support-title{
+ display: flex;
+ justify-content: center;
+ flex-direction: column;
+
+}
+.home-support-items{
+ display: flex;
+ justify-content: center;
+ flex-wrap: wrap;
+ img{
+ object-fit: scale-down;
+ width: 100px;
+ height: 100px;
+ }
+
+}
+.home-logo-instances{
+ padding: 23px;
+ margin: 7px 12px !important;
+ border-radius: 50%;
+ display: block;
+}
+.home-support-items > *:not(:first-child){
+ margin-left: 40px;
+}
+.home-support-items a{
+ margin-bottom: 40px;
+ opacity: 85%;
+ transition: opacity 0.3s ease;
+}
+.home-support-items a:hover{
+ opacity: 100%;
+}
+.home-result-type{
+ font-weight: 300;
+ margin-bottom: 0;
+}
+
+.home-upload-ontology-button path:hover {
+ fill: white;
+}
+
+.home-searched-ontology{
+ margin-bottom: 0;
+ word-wrap: break-word;
+ max-width: 400px;
+ margin-right: 20px;
+
+}
+.align-items{
+ display: flex;
+ align-items: center;
+}
+.margin-items{
+ margin-right: 10px;
+}
+
+.custom-logo-class{
+ width: 96px;
+ height: 96px;
+ object-fit: scale-down;
+}
+.fair-scores-badge-section{
+ height: 5px !important;
+}
+.fair-scores-badge-margin{
+ margin-right: 10px;
+ margin-bottom: 20px;
+ background-color: var(--primary-color) !important;
+}
+.home-support-items svg path{
+ fill: white;
+}
+@keyframes scale-up {
+ from { transform: scale(0.1); }
+ to { transform: scale(1); }
+}
+
+@keyframes scale-up-random {
+ from { transform: scale(0.1); }
+ to { transform: scale(1.06); }
+}
+
+@keyframes slide-and-fade {
+ from { opacity: 0; transform: translateY(-100%); }
+ to { opacity: 1; transform: translateY(0); }
+}
+
+@media (max-width: 1300px) {
+ .home-section{
+ width: 100%;
+ }
+ .home-section-sub-sections-container{
+ flex-direction: column;
+ }
+ .home-random-bubbles{
+ display: none;
+ }
+ .home-header-title{
+
+ margin:128px 50px;
+ width: 500px;
+
+ opacity: 0;
+ transform: translateY(-100%);
+ animation: slide-and-fade 1s ease forwards;
+ }
+ .home-header-title-container{
+ justify-content: start;
+ }
+ .home-sub-section-left {
+ width: 100%;
+ }
+
+ .home-sub-section-right {
+ width: 100%;
+ margin-top: 50px;
+ }
+ .home-fair-scores div{
+ padding: 0 10%;
+ }
+ .home-fair-scores{
+ height: unset;
+ }
+}
+
+
+
diff --git a/app/assets/stylesheets/login.scss b/app/assets/stylesheets/login.scss
index f2d68c91d..f832c6ed0 100644
--- a/app/assets/stylesheets/login.scss
+++ b/app/assets/stylesheets/login.scss
@@ -1,10 +1,13 @@
.login-form{
- margin-top: 30px;
- padding: 37px 41px;
- box-shadow: rgba(0, 0, 0, 0.08) 0px 20px 50px;
- border-radius: 14px;
+ margin-top: 30px;
+ padding: 37px 41px;
+ box-shadow: rgba(0, 0, 0, 0.08) 0px 20px 50px;
+ border-radius: 14px;
+ max-width: 439px;
+}
+.login-form a{
+ color: var(--primary-color) !important;
}
-
.login-input{
box-sizing: border-box;
outline: none;
@@ -41,24 +44,20 @@
text-decoration:none;
font-size: 13px;
}
-.login-button{
- margin-top: 10px;
- width: 357px;
- font-size: 16px;
- color: white;
- padding: 17px;
- background-color: var(--primary-color);
- border: none;
- border-radius: 9px;
- margin-bottom: 20px;
-}
-.login-button:hover{
- background-color: var(--hover-color);
- cursor: pointer;
-}
-
.dont-have-account{
font-size: 15px;
font-weight: 600;
text-align: center;
}
+.login-button-container{
+ margin-top: 10px;
+ margin-bottom: 20px;
+ width: 357px;
+}
+.disabled-login-sso{
+ width: 40px;
+ margin: 7px 10px;
+}
+.login-active-sso path{
+ fill: var(--primary-color)
+}
\ No newline at end of file
diff --git a/app/assets/stylesheets/mappings.scss b/app/assets/stylesheets/mappings.scss
index c4dbece77..c0a494fb0 100644
--- a/app/assets/stylesheets/mappings.scss
+++ b/app/assets/stylesheets/mappings.scss
@@ -1,4 +1,266 @@
+.mappigs-page-container{
+ display: flex;
+ justify-content: center;
+ .file_uploader{
+ width: 700px;
+ }
+}
+.mappings-page-subcontainer{
+ width: 1248px;
+ padding: 20px 50px;
+}
+
+.mappings-page-title{
+ font-size: 25px;
+ font-weight: 700;
+}
+.mappings-page-title .line{
+ height: 2px;
+ width: 57px;
+ background-color: var(--primary-color);
+ border-radius: 10px;
+}
+.mappings-page-decription{
+ color: #888888;
+ margin: 20px 0;
+}
+
+.mappings-bubble{
+ cursor: pointer;
+}
+.mappings-bubble-view-frame{
+ width: 600px;
+ height: 600px;
+ overflow: auto;
+}
+
+.mappings-zoom-buttons{
+ display: flex;
+ margin-top: 20px;
+ justify-content: center;
+}
+.mappings-zoom-buttons svg{
+ width: 40px;
+ cursor: pointer;
+ path{
+ fill: var(--primary-color)
+ }
+ &:hover path{
+ fill: var(--hover-color)
+ }
+}
+.mappings-zoom-buttons div + div{
+ margin-left: 40px;
+}
+.mappings-bubble-view-container{
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+}
+.mappings-table-view-container{
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ margin: 20px 0;
+}
+.mappings-ontologies-select{
+ width: 700px;
+}
+
+.mappings-table-container{
+ width: 678px;
+ margin: 20px 0;
+}
+.mappings-table-ontology-name{
+ font-weight: 600;
+}
+
+.bubble-tooltip {
+ position: absolute;
+ text-align: center;
+ padding: 6px;
+ font-size: 12px;
+ background: rgba(0, 0, 0, 0.7);
+ color: white;
+ border-radius: 4px;
+ pointer-events: none;
+ z-index: 9999;
+}
+
+.upload-mappings{
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ margin-top: 20px;
+}
+
+.upload-mappings-example{
+ width: 700px;
+ margin-bottom: 20px;
+}
+.upload-mappings-example.ontologies{
+ width: 600px;
+}
+
+.mappings-page-ontologies-selector{
+ width: 100%;
+ padding: 0 30px 30px 30px;
+}
+
+.mappings-page-ontologies-selector .selector-button{
+ margin-top: 20px;
+}
+
+.upload-mappings-example .title-bar{
+ display: flex;
+ justify-content: center;
+ width: 100%;
+ cursor: pointer;
+ padding: 15px;
+ color: var(--primary-color);
+ align-items: center;
+}
+.upload-mappings-example .title-bar svg{
+ margin-right: 10px;
+}
+
+.summary-mappigs-page-container{
+ margin-left: 90px;
+}
+.mapping-bubbles-loader{
+ height: 100%;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+}
+
+.summary-mappings-tab {
+ margin-top: 10px;
+}
+
+#ontology_viewermappings_content {
+ .summary-mappings-tab {
+ display: flex;
+ }
+
+ .summary-mappings-tab-table {
+ width: 400px;
+ }
+}
+
+.mappings-table-pagination a, .mappings-table-pagination em{
+ margin-left: 10px;
+}
+
+.mappings-bubble-view-legend{
+ width: 600px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ font-weight: 500;
+ padding: 20px;
+}
+.mappings-bubble-view-legend > .title {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+}
+
+.mappings-bubble-view-legend > .title .text{
+ font-size: 18px;
+ color: var(--primary-color);
+}
+.mappings-bubble-view-legend > .title .line{
+ background-color: var(--primary-color);
+ border-radius: 100%;
+ width: 40px;
+ height: 2px;
+}
+
+.content-container{
+ width: 100%;
+ margin-top: -35px;
+}
+.bubble-view-legend-item{
+ margin-top: 50px;
+}
+.bubble-view-legend-item .title{
+ font-weight: 500;
+}
+.bubble-view-legend-item .title span{
+ font-weight: 400;
+}
+
+.mappings-bubble-size-legend, .mappings-bubble-color-legend{
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ margin: 20px 0;
+}
+.mappings-bubble-size-legend .bubble{
+ border-radius: 100%;
+ border: 2px solid var(--primary-color);
+}
+.mappings-bubble-size-legend .bubble.bubble1{
+ width: 10px;
+ height: 10px;
+}
+.mappings-bubble-size-legend .bubble.bubble2{
+ width: 20px;
+ height: 20px;
+}
+.mappings-bubble-size-legend .bubble.bubble3{
+ width: 30px;
+ height: 30px;
+}
+.mappings-bubble-size-legend .bubble.bubble4{
+ width: 40px;
+ height: 40px;
+}
+.mappings-bubble-size-legend .bubble.bubble5{
+ width: 50px;
+ height: 50px;
+}
+.mappings-bubble-size-legend .bubble.bubble6{
+ width: 60px;
+ height: 60px;
+}
+.mappings-bubble-color-legend .bubble{
+ border-radius: 100%;
+ background-color: var(--primary-color);
+ width: 35px;
+ height: 35px;
+}
+.mappings-bubble-color-legend .bubble.bubble1{
+ opacity: 30%;
+}
+.mappings-bubble-color-legend .bubble.bubble2{
+ opacity: 50%;
+}
+.mappings-bubble-color-legend .bubble.bubble3{
+ opacity: 70%;
+}
+.mappings-bubble-color-legend .bubble.bubble4{
+ opacity: 80%;
+}
+.mappings-bubble-color-legend .bubble.bubble5{
+ opacity: 90%;
+}
+.mappings-bubble-color-legend .bubble.bubble6{
+ opacity: 100%;
+}
+.mappings-bubble-size-legend .bubble.yellow{
+ width: 35px;
+ height: 35px;
+ background-color: var(--secondary-color);
+ border: none;
+}
+.mappings-legend-text{
+ color: var(--primary-color);
+ font-size: 15px;
+ font-weight: 500;
+}
@media (min-width: 1000px) {
#mappings_container{
@@ -58,7 +320,7 @@ div#map_from_concept_details_table, div#map_to_concept_details_table {
overflow: auto;
}
-#map_to_picker, .select2-container {
+#map_to_picker {
width: 100% !important;
}
@@ -76,3 +338,23 @@ div#map_from_concept_details_table, div#map_to_concept_details_table {
width: 100%;
}
+.summary-mappings-tab-table {
+ .dataTables_wrapper .dataTables_filter {
+ float: none;
+ text-align: unset;
+ }
+}
+
+.summary-mappings-tab-table label {
+ display: block;
+ font-size: 0;
+}
+
+.summary-mappings-tab-table label input[type="search"] {
+ font-size: 16px;
+ width: 100%;
+ border-radius: 8px;
+ padding: 10px;
+ outline: none;
+ margin-left: 0 !important;
+}
\ No newline at end of file
diff --git a/app/assets/stylesheets/nav_bar.scss b/app/assets/stylesheets/nav_bar.scss
new file mode 100644
index 000000000..ddf561962
--- /dev/null
+++ b/app/assets/stylesheets/nav_bar.scss
@@ -0,0 +1,201 @@
+.nav-container{
+ display: flex;
+ justify-content: center;
+ background-color: var(--primary-color);
+}
+.top-nav{
+ display: flex !important;
+ background-color: var(--primary-color);
+ align-items: center;
+ justify-content: space-between;
+ height: 62px;
+ padding: 8px 42px;
+ width: 1248px;
+}
+.nav-responsiveness-container{
+ display: flex;
+ justify-content: space-between;
+}
+.nav-logo{
+ display: flex;
+ align-items: center;
+}
+.nav-logo p{
+ margin-left: 10px;
+ color: white;
+ font-size: 16px;
+ font-weight: 700;
+ margin-bottom: 0;
+}
+.nav-items{
+ display: flex;
+ justify-content: space-between;
+ align-items:center;
+ width: 1020px;
+}
+.nav-items > ul {
+ display: flex;
+ list-style: none;
+ margin-bottom: 0;
+ padding: 0;
+}
+
+.nav-items > ul > li {
+ margin-left: 17px;
+}
+
+.nav-items > ul > li > a {
+ color: white !important;
+ font-size: 15px;
+ opacity: 60%;
+ font-weight: 300;
+ transition: opacity 0.2s ease-in-out;
+}
+.nav-items > ul > li > a:hover{
+ opacity: 100%;
+}
+.nav-items > ul > li > a.active{
+ opacity: 100%;
+ font-weight: 500;
+}
+
+.nav-search-container {
+ width: 50% ;
+ position: relative;
+}
+.nav-search-container div > input {
+ height: 33px;
+ width: 100%;
+ outline: none;
+ opacity: 60%;
+ border: 1px solid white;
+ background-color: var(--primary-color) !important;
+ color: white;
+ border-radius: 5px;
+ font-size: 14px;
+ padding: 0 10px;
+}
+.nav-search-container div > input:focus{
+ opacity: 100%;
+ border-radius: 5px 5px 0 0;
+ border: 1px solid white;
+}
+.nav-search-container div > input::placeholder{
+ color: white;
+ opacity: 60%;
+}
+.nav-search-container div > input::-ms-input-placeholder{
+ color: white;
+ opacity: 60%;
+}
+
+.nav-search-container .search-container{
+ position: absolute;
+ z-index: 9999;
+ font-size: 12px !important;
+
+}
+
+.nav-language {
+ width: 47px !important;
+ .ts-control{
+ background-color: transparent;
+ color: white;
+ border: none;
+ outline: none;
+ cursor: pointer;
+ }
+
+ &.single.input-active .ts-control{
+ background: transparent !important;
+ }
+}
+
+.nav-language option{
+ background-color: white;
+ color: black;
+}
+.nav-items .nav-a{
+ padding: 3px 34px;
+ border: 1px solid white;
+ border-radius: 5px;
+ color: white !important;
+ transition: background-color 0.2s ease-in-out;
+}
+.nav-items .nav-a:hover{
+ background-color: rgba(255, 255, 255, 0.1);
+}
+
+.top-nav .menu-btn i{
+ color: #fff;
+ font-size: 22px;
+ cursor: pointer;
+ display: none;
+}
+.top-nav input[type="checkbox"]{
+ display: none;
+}
+
+.top-nav-nav-link{
+ color: white !important;
+ padding: 0 !important;
+}
+
+
+@media (max-width: 1300px){
+ .top-nav .menu-btn i{
+ display: block;
+ }
+ #nav-menu:checked ~ .menu-btn i:before{
+ content: "\f00d";
+ }
+ .nav-items{
+ display: none;
+ }
+ .menu-btn{
+ position: absolute;
+ right: 40px;
+ }
+ .right-nav-items{
+ flex-direction: column;
+ align-items: baseline !important;
+ }
+ .nav-search-container .nav-input{
+ margin-bottom: 0 !important;
+
+ }
+
+}
+.top-nav.show-responsive {
+ display: block !important;
+ background-color: var(--primary-color);
+ height: unset;
+}
+
+.top-nav-ul.show-responsive {
+ display: block;
+ text-decoration-style: none !important;
+}
+
+.nav-items.show-responsive {
+ flex-direction: column;
+ width: unset;
+ display: flex;
+ align-items: flex-start;
+}
+
+.show-responsive {
+ margin: 15px 0 !important;
+}
+
+.supportMenuDropdownLink.show-responsive {
+ margin-bottom: 15px;
+}
+
+.right-nav-items{
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ width: 50%;
+ gap: 20px;
+}
diff --git a/app/assets/stylesheets/notes.scss b/app/assets/stylesheets/notes.scss
index 43003ae26..0e957b2d2 100644
--- a/app/assets/stylesheets/notes.scss
+++ b/app/assets/stylesheets/notes.scss
@@ -136,11 +136,6 @@ textarea.create_note_inputs {
font-size: 12pt;
}
-.ontologies.show div#facebox div.discussion {
- padding-top: 1em;
- padding-left: 1.5em;
-}
-
.reply_author {
color: #234979;
}
diff --git a/app/assets/stylesheets/ontologies.scss b/app/assets/stylesheets/ontologies.scss
index 4de56daa7..afa87ae7c 100644
--- a/app/assets/stylesheets/ontologies.scss
+++ b/app/assets/stylesheets/ontologies.scss
@@ -1,17 +1,32 @@
$ont-metadata-bg-color: #e2ebf0;
$widget-table-border-color: #EFEFEF;
-$ont-show-bg-color: #e9ecef;
-.ontologies.show {
- background-color: $ont-show-bg-color;
- #bd {
- background-color: $ont-show-bg-color;
+.admin-background{
+ a.chip_button_container_clickable{
+ color: var(--admin-color) !important;
}
}
+.admin-border {
+ .dropdown-container{
+ margin-top: 0 !important;
+ margin-bottom: 0 !important;
+ }
+}
+
+.custom-container {
+ padding: 1rem;
+ background-color: #2c3e50; /* Dark gray */
+ border-radius: 0.25rem;
+}
+/* Code block styles */
+.custom-code {
+ font-family: 'Courier New', monospace;
+ font-size: 0.875rem; /* 14px */
+ color: #fff;
+}
.ontologies.show .gutter {
- background-color: rgba(0, 0, 0, 0.03);
background-repeat: no-repeat;
background-position: center;
@@ -26,7 +41,7 @@ $ont-show-bg-color: #e9ecef;
flex-wrap: wrap;
align-items: center;
justify-content: space-between;
-
+
background-color: white;
padding: 0.75rem 1.25rem;
@@ -41,7 +56,7 @@ $ont-show-bg-color: #e9ecef;
a {
color: #6c757d;
-
+
&:hover {
color: #0056b3;
text-decoration: none;
@@ -159,14 +174,18 @@ $ont-show-bg-color: #e9ecef;
}
}
-#ontology_versions td.show_more_subs {
- text-align: right;
- background-color: white;
-}
+
/************************************
/* Classes pane
************************************/
+.tree-container {
+ overflow-x: auto;
+ min-width: 35%;
+ min-height: 70vh;
+ max-height: 90vh;
+ font: small/1.231 arial,helvetica,clean,sans-serif;
+}
#bd_content {
display: flex;
@@ -176,6 +195,7 @@ $ont-show-bg-color: #e9ecef;
#bd_content .sidebar {
overflow-x: auto;
white-space: nowrap;
+ min-width: 35%;
}
#search_box:focus {
@@ -200,21 +220,11 @@ $ont-show-bg-color: #e9ecef;
/* Properties pane
************************************/
-#propTree a {
- font-family: "Myriad Pro","Myriad Web Pro","Myriad Web","Myriad","Trebuchet MS","Tahoma","Helvetica","Arial",sans-serif;
- font: small/1.231 arial,helvetica,clean,sans-serif;
-}
-
.ont-properties {
display: flex;
flex-direction: row;
}
-#propTree {
- overflow-x: auto;
- white-space: nowrap;
-}
-
/************************************
/* Widgets pane
************************************/
@@ -248,9 +258,6 @@ $ont-show-bg-color: #e9ecef;
margin-right: 15px;
}
-#ontology-browse-help i {
- margin-left: .25em;
-}
/************************************
/* Schemes pane
@@ -272,3 +279,37 @@ $ont-show-bg-color: #e9ecef;
}
+#select_content_language{
+ & ~ .ts-wrapper .ts-control{
+ padding: 6px 8px !important;
+ .item{
+ margin-right: 15px;
+ }
+ }
+}
+
+.metadata-exporter {
+ position: relative;
+}
+.metadata-exporter .download-btn {
+ position: absolute;
+ right: 20px;
+ z-index: 2;
+ .chip_button_container_clickable {
+ opacity: 0.6;
+ &:hover {
+ opacity: 1;
+ }
+ }
+}
+
+.htacess-code-container{
+ margin-top: 20px;
+ margin-bottom: 30px;
+ text-align: left;
+ padding: 20px;
+ background-color: #1d1d1d;
+ color: white;
+ border-radius: 10px;
+ position: relative;
+}
\ No newline at end of file
diff --git a/app/assets/stylesheets/ontology_details_header.scss b/app/assets/stylesheets/ontology_details_header.scss
new file mode 100644
index 000000000..812c2dab7
--- /dev/null
+++ b/app/assets/stylesheets/ontology_details_header.scss
@@ -0,0 +1,112 @@
+.ontology-details-header-container{
+ padding: 0 50px;
+ margin: 20px 0;
+ width: 1248px;
+}
+
+.ontology-details-path{
+ display: flex;
+ align-items: center;
+ color: #888888;
+ margin-bottom: 20px;
+}
+.ontology-details-path svg{
+ margin: 0 12px;
+}
+.ontology-details-path a{
+ text-decoration: underline !important;
+ color: #888888 !important;
+}
+.ontology-details-header-sub-container{
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ position: relative;
+}
+
+.ontology-details-name-bar{
+ display: flex;
+ align-items: center;
+}
+.ontology-details-name-bar > div{
+ font-size: 25px;
+ font-weight: 700;
+ margin-right: 10px;
+}
+
+.ontology-details-name-bar > div > span{
+ font-size: 17px;
+ font-weight: 500;
+}
+
+.ontology-details-name-bar .ontology-details-licence{
+ display: flex;
+ align-items: center;
+ background-color: #F6F6F6;
+ border-radius: 5px;
+ padding: 10px 20px;
+ cursor: pointer;
+ font-size: 12px;
+ color: #777777;
+ font-weight: 600;
+}
+.ontology-details-name-bar .ontology-details-licence svg{
+ margin-left: 10px;
+ transform: scale(1.2);
+}
+.ontology-details-last-update{
+ display: flex;
+ align-items: center;
+ font-size: 14px;
+ color: #888888;
+ margin-top: 12px;
+}
+.ontology-details-last-update img{
+ margin-right: 10px;
+}
+.ontology-details-header-right-container{
+ display: flex;
+}
+.ontology-details-watch-button {
+ color: var(--primary-color);
+ font-size: 15px;
+ display: flex;
+ align-items: center;
+ border: 1px solid var(--primary-color);
+ border-radius: 32px;
+ padding: 10px 20px;
+ cursor: pointer;
+ margin-left: 10px;
+ transition: background-color ease 0.3s;
+ white-space: nowrap;
+}
+
+
+.ontology-details-watch-button:hover,.ontology-details-edit-button:hover {
+ background-color: var(--primary-color);
+ color: white !important;
+
+}
+
+.ontology-details-watch-button:hover svg path,.ontology-details-edit-button:hover svg path {
+ fill: white;
+}
+
+.ontology-details-watch-button svg {
+ margin-right: 10px;
+}
+
+.ontology-details-edit-button {
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ border: 1px solid var(--primary-color);
+ border-radius: 22.5px;
+ padding: 10px;
+ height: 45px;
+ width: 45px;
+ cursor: pointer;
+ transition: background-color ease 0.3s;
+}
+
+
diff --git a/app/assets/stylesheets/ontology_viewer.scss b/app/assets/stylesheets/ontology_viewer.scss
new file mode 100644
index 000000000..1bf78e866
--- /dev/null
+++ b/app/assets/stylesheets/ontology_viewer.scss
@@ -0,0 +1,21 @@
+
+.ontologies-tabs-container {
+ & > .tabs-container {
+ justify-content: center;
+ }
+
+ & > .tabs-container > div {
+ width: 1248px;
+ padding: 0 50px;
+ }
+
+ & > .tab-content {
+ display: flex;
+ justify-content: center;
+
+ & > .tab-pane {
+ width: 1248px;
+ padding: 0 50px;
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/assets/stylesheets/recommender.scss b/app/assets/stylesheets/recommender.scss
index 9c49a7aca..07ba6952f 100644
--- a/app/assets/stylesheets/recommender.scss
+++ b/app/assets/stylesheets/recommender.scss
@@ -1,37 +1,195 @@
-.optionsBox {
- margin-top: 15px;
-}
-
-#inputTextHighlighted {
- display:none;
- background-color: #e2ebf0;
-}
-
-.generalError, .invalidMaxOntError, .invalidWeightsError, .notTextError, .sumWeightsError, .rangeWeightsError, .maxOntologiesError, .inputSizeError {
- display: none;
- color: red;
-}
-
-#resultsDisplay {
- background-color: white !important;
- margin-bottom: 35px;
-}
-
-.result-scores {
- background-color: #8cabd6;
- border: 1px solid #3e76b6;
-}
-
-.final-score {
- color: #ccc;
- background-color: #234979;
- border: 1px solid #234979;
-}
-
-.score-number {
- margin-left: 3px;
-}
-
-#recommender-help i {
- margin-left: .25em;
-}
+.recommender-page-container{
+ display:flex;
+ justify-content:center;
+}
+.recommender-page-subcontainer{
+ width: 1248px;
+ padding: 20px 50px;
+}
+
+.recommender-page-title .text{
+ font-size: 25px;
+ font-weight: 700;
+}
+
+.recommender-page-title .line{
+ height: 2px;
+ width: 57px;
+ background-color: var(--primary-color);
+ border-radius: 10px;
+}
+.recommender-page-decription{
+ color: #888888;
+ margin-top: 20px;
+}
+.recommender-page-inputs{
+ margin-top: 20px;
+}
+.recommender-page-inputs .inputs{
+ display: flex;
+}
+.recommender-page-text-area, .recommender-page-text-area-results {
+ box-shadow: 2px 30px 60px rgba(0, 0, 0, 0.1);
+ border-radius: 8px;
+ width: 630px;
+ margin-right: 30px;
+}
+.recommender-page-text-area-results{
+ padding: 20px;
+ min-height:205px;
+}
+
+.recommender-page-text-area textarea{
+ font-size: 16px;
+ outline: none;
+ padding: 20px;
+ width: 630px;
+ border: none;
+ margin-right: 30px;
+}
+.recommender-page-options{
+ width: 100%;
+}
+.recommender-page-text-area .insert-sample-text-button{
+ display: flex;
+ justify-content: flex-end;
+ padding: 20px;
+}
+.recommender-page-text-area .insert-sample-text-button .button{
+ display: flex;
+ align-items: center;
+}
+.recommender-page-text-area .insert-sample-text-button .button:hover{
+ cursor: pointer;
+}
+.recommender-page-text-area .insert-sample-text-button .button .text{
+ font-size: 14px;
+ font-weight: 500;
+ color: var(--primary-color);
+ margin-right: 10px;
+}
+.recommender-page-text-area .insert-sample-text-button .button svg{
+ width: 16px;
+ height: 16px;
+}
+.recommender-page-text-area .insert-sample-text-button .button svg path{
+ fill: var(--primary-color);
+}
+.recommender-page-options .section-text{
+ font-weight: 600;
+
+}
+.recommender-page-options .title{
+ margin-top: 10px;
+ color: #888888;
+ font-size: 14px;
+ font-weight: 500;
+ margin-bottom: 5px;
+}
+
+.recommender-page-options .chips{
+ display: flex;
+}
+.recommender-page-options input{
+ accent-color: var(--primary-color) revert;
+}
+.recommender-page-options .radios{
+ display: flex;
+}
+
+.recommender-page-options .advanced-options-button{
+ display: flex;
+ align-items: center;
+ margin-top: 15px;
+}
+.recommender-page-options .advanced-options-button:hover{
+ cursor: pointer;
+}
+.recommender-page-options .advanced-options-button .text{
+ margin-left: 10px;
+ color: var(--primary-color);
+ font-size: 14px;
+}
+
+.recommender-page-options .advanced-options-button svg path{
+ fill: var(--primary-color);
+}
+.recommender-page-button{
+ margin-top: 27px;
+ width: 630px;
+}
+
+.recommender-advanced-options .title {
+ font-weight: 600;
+ margin-top: 30px;
+}
+.recommender-advanced-options .inputs-container{
+ display: flex;
+ margin-top: 11px;
+ margin-bottom: 17px;
+}
+.recommender-advanced-options .input, .recommender-advanced-options .ninput{
+ width: 100%;
+}
+
+.recommender-advanced-options .ninput + .ninput{
+ margin-left: 20px;
+}
+
+.recommender-advanced-options .ontologies{
+ margin-right: 20px;
+}
+.recommender-advanced-options .hidebutton{
+ color: var(--primary-color);
+ display: flex;
+ align-items: center;
+}
+
+.recommender-advanced-options .hidebutton:hover{
+ cursor: pointer;
+}
+
+.recommender-advanced-options .hidebutton .text{
+ font-size: 14px;
+ font-weight: 500;
+ margin-left: 10px;
+
+}
+.recommender-advanced-options .hidebutton svg path{
+ fill: var(--primary-color);
+}
+.recommender-table-container{
+ margin-top: 20px;
+}
+.recommender-page-results .title{
+ margin-top: 63px;
+ font-size: 18px;
+ font-weight: 600;
+}
+.recommender-result-ontology{
+ font-size: 16px;
+ display: block;
+ color: var(--primary-color);
+}
+.highlighted_recommendation{
+ width: 135px;
+}
+.recommender-result-highlighted{
+ display: flex;
+ justify-content: flex-end;
+}
+.recommender-page-text-area-results a{
+ font-weight: 600;
+ text-decoration: underline !important;
+}
+
+.recommender-bottom-actions{
+ margin-top: 20px;
+ display: flex;
+}
+.recommender-bottom-actions div{
+ display: inline-block;
+}
+.recommender-bottom-actions div + div{
+ margin-left: 20px;
+}
\ No newline at end of file
diff --git a/app/assets/stylesheets/register.scss b/app/assets/stylesheets/register.scss
index 6db658b3a..9dda813db 100644
--- a/app/assets/stylesheets/register.scss
+++ b/app/assets/stylesheets/register.scss
@@ -83,23 +83,11 @@
margin-top: 14px;
}
-.register-button{
+.register-button-container{
margin-top: 20px;
- width: 363px;
- font-size: 16px;
- color: white;
- padding: 17px;
- background-color: var(--primary-color);
- border: none;
- border-radius: 9px;
-
}
-.register-button:hover{
- background-color: var(--hover-color);
- cursor: pointer;
-}
-#user_register_mail_list{
+.user_register_checkbox{
margin-top: 14px;
accent-color: #8E8E8E;
}
diff --git a/app/assets/stylesheets/search.scss b/app/assets/stylesheets/search.scss
index ab621fb36..e66312f7e 100644
--- a/app/assets/stylesheets/search.scss
+++ b/app/assets/stylesheets/search.scss
@@ -1,185 +1,83 @@
-form.button-to {
- float: left;
-}
-
-#ontology_picker_head {
- font-size: 10pt !important;
-}
-
-.not_visible {
- position: fixed !important;
- top: -999999px !important;
-}
-
-#search_results_container #search_results_info {
- display: none !important;
-}
-
-#search_results_filter {
- display: none;
-}
-
-#search_spinner {
- display: inline-block;
- padding: 8px 4px;
-}
-
-#search_options #ontology_ontologyId {
- display: none;
-}
-
-.class_details_pop {
- overflow: auto;
- width: 750px !important;
- display: block !important;
-}
-
-table#search_results td {
- vertical-align: top;
- padding: 12px 8px 12px 12px;
-}
-
-div.search_result {
- margin-bottom: 1.5em;
-}
-
-div.class_link a {
+.search-page-container {
+ display: flex;
+ justify-content: center;
+}
+.search-page-subcontainer {
+ width: 1248px;
+ padding: 20px 50px;
+}
+.search-page-input-container{
+ width: 100%;
+}
+
+.search-page-input{
+ position: relative;
+ padding-bottom: 30px;
+ display: flex;
+ .search-container{
+ top:65px;
+ }
+}
+.search-page-input input{
+ border-radius: 8px;
+ box-shadow: rgba(100, 100, 111, 0.1) 0 7px 29px 0;
+ border: none;
+ outline: none;
font-size: 18px;
+ padding: 15px 25px;
+ width: 100%;
}
-
-span.class_def {
- display: block;
- margin: 3px 0 2px;
- font-size: 12px;
+.search-page-input input:focus{
+ box-shadow: rgba(100, 100, 111, 0.2) 0 7px 29px 0;
}
-
-.additional_ont_results {
- padding: 2em;
- margin: 2em;
- background-color: rgb(230,230,230);
+.search-page-advanced{
+ display: flex;
+ margin-bottom: 15px;
}
-
-.additional_cls_results {
- padding: 2em;
- margin: 2em;
- background-color: rgb(230,230,230);
+.search-page-advanced .left{
+ width: 600px;
+ margin-right: 40px;
}
-
-.subordinate_ont_results {
- padding: 1em;
- padding-left: 2em;
- padding-top: 2em;
- margin: 1em;
- margin-left: 2em;
- margin-top: 2em;
- background-color: rgb(240,240,240);
+.search-page-advanced .filter-container{
+ margin-bottom: 15px;
}
-
-.subordinate_ont_results_title {
- color: rgb(100,100,100);
- background: rgb(200,200,200);
- padding: 0.5em;
+.search-page-advanced .filter-container .title{
+ margin-bottom: 5px;
+ color: #888888;
+ font-size: 14px;
}
-
-div.search_result_additional {
- padding-left: 30px;
- margin: 1em 0 1.2em;
+.search-page-button{
+ width: 120px;
+ margin-left: 20px;
}
-div.search_result_additional .class_link a {
- font-size: 15px !important;
+.search-page-button svg{
+ width: 14px;
}
-div.additional_results_link {
- margin-top: 5px;
+.search-page-options{
+ display: flex;
+ justify-content: space-between;
}
-
-.search_result_links a {
- font-size: 11px !important;
- color: green;
+.search-page-advanced-button{
+ display: flex;
+ align-items: center;
}
-
-.hide_link {
- text-decoration: underline;
- padding-left: 7px;
+.search-page-advanced-button :hover{
+ cursor: pointer;
}
-
-.not_underlined {
- text-decoration: none;
-}
-
-#search_results {
- display: none;
-}
-
-#search_results_container {
- margin-top: .5em;
- clear: both;
-}
-
-div#search_categories_chzn {
- width: 432px !important;
+.search-page-advanced-button .text{
+ margin-left: 10px;
+ color: var(--primary-color);
}
-div#search_categories_chzn .chzn-choices input {
- font-style: oblique;
+.search-page-advanced-button .icon svg path{
+ fill: var(--primary-color);
}
-
-div#search_categories_chzn.chzn-container-active input {
- font-style: normal !important;
-}
-
-div#search_categories_chzn .chzn-drop {
- width: 432px !important;
-}
-
-#search_messages {
- font-style: oblique;
- color: gray;
- padding-bottom: 7px;
-}
-
-#result_stats a {
- color: gray;
+.search-page-number-of-results{
+ color: #888888;
}
-#ontology_counts {
- display: none;
+.search-page-result-element{
+ margin-top: 40px;
}
-
-.popup_counts {
- float: right;
- display: none;
-}
-
-.ontology_counts_tooltip {
- background-color: #EEEEEE;
- border: 1px solid black;
- color: black;
- font-size: 12px;
- padding: 10px 15px;
- text-align: left;
- z-index: 999;
- box-shadow: 3px 3px 7px gray;
-}
-
-.definition {
- cursor: help;
-}
-
-.concept_uri {
- font-size: 9pt;
- color: gray;
-}
-
-#search_categories_chosen .chosen-container .chosen-container-multi {
- width: 432px;
-}
-
-/* Prevents placeholder text in search input from being truncated.
-/* https://github.com/harvesthq/chosen/issues/2029#issuecomment-187442769 */
-#search_options #ontology_ontologyId_chosen .search-field:only-child,
-#search_options #ontology_ontologyId_chosen .search-field:only-child input {
- width: 100% !important;
-}
-
diff --git a/app/assets/stylesheets/submissions.scss b/app/assets/stylesheets/submissions.scss
index 41e12ec32..47dc99d2c 100644
--- a/app/assets/stylesheets/submissions.scss
+++ b/app/assets/stylesheets/submissions.scss
@@ -8,4 +8,11 @@ div#contacts div.contact.col-sm-10.offset-sm-2 {
#submissionLocation small.form-text {
margin-bottom: 0.5em;
+}
+.tab-content{
+ position: relative;
+}
+.spacer {
+ margin-left: 10px;
+ margin-top: -13px;
}
\ No newline at end of file
diff --git a/app/assets/stylesheets/summary.scss.erb b/app/assets/stylesheets/summary.scss.erb
new file mode 100644
index 000000000..dc05fe2a5
--- /dev/null
+++ b/app/assets/stylesheets/summary.scss.erb
@@ -0,0 +1,253 @@
+.summary-page-center {
+ display: flex;
+ justify-content: center;
+ flex-wrap: wrap;
+ .flag-icon{
+ width: 30px;
+ height: 30px;
+ }
+}
+.summary-page-center a{
+ color: var(--primary-color) !important;
+}
+
+.summary-page-center .card_title{
+ margin-top: 40px;
+}
+.add-views-plus-icon path{
+ fill: var(--primary-color)
+}
+.summary-link-truncate{
+ max-width: 330px;
+ display: inline-flex;
+ overflow: hidden;
+ white-space: nowrap;
+ text-overflow: ellipsis;
+}
+
+.summary-page-first-row {
+ width: 670px;
+ margin-right: 20px;
+}
+
+.summary-page-second-row {
+ width: 450px;
+}
+
+@media (max-width: 1288px) {
+ .summary-page-first-row {
+ width: 100%;
+ margin: 0;
+ padding: 0 20px;
+ }
+ .summary-page-second-row {
+ width: 100%;
+ margin: 0;
+ padding: 0 20px;
+ }
+}
+
+.show > .btn-outline-primary.dropdown-toggle {
+ background-color: var(--primary-color) !important;
+ color: white !important;
+}
+
+
+.description_text,
+.description_text a {
+ color: #888888 !important;
+ font-size: 15px;
+ overflow: hidden;
+ margin-bottom: 0;
+ flex: 1;
+ min-width: 500px;
+}
+
+
+.creation_info {
+ display: flex;
+ flex-wrap: wrap;
+ align-items: center;
+}
+
+
+
+.date_creation_text {
+ font-size: 14px;
+ font-weight: 700;
+}
+
+.creator_text {
+ color: #888888;
+ font-size: 14px;
+ margin-left: 5px;
+ font-weight: 550;
+ margin-top: 15px;
+ width: 300px;
+}
+
+.creation_text {
+ font-size: 16px;
+}
+
+
+.icons_container {
+ margin-top: 10px;
+ justify-content: space-evenly;
+ display: flex;
+ padding: 0 20px;
+ svg path {
+ fill: var(--primary-color);
+ }
+}
+
+
+
+.disabled-icon {
+ pointer-events: none;
+ svg path {
+ fill: rgba(0, 0, 0, 0.1) !important;
+ }
+}
+
+.normal_text {
+ font-size: 15px;
+ color: black;
+ word-wrap: break-word;
+}
+
+
+
+.metrics {
+ display: flex;
+ justify-content: space-between;
+}
+
+.metrics-container {
+ border-radius: 8px;
+ height: 90px;
+ box-shadow: 2px 0px 60px rgba(0, 0, 0, 0.1);
+ padding: 71px 40px;
+ margin-top: 10px;
+}
+
+.metrics-container > div {
+ display: flex;
+ align-items: center;
+ margin-bottom: 20px;
+}
+
+.metrics-container > div > p {
+ font-size: 20px;
+ font-weight: 600;
+ margin-left: 18px;
+}
+
+.metrics-item {
+ display: flex;
+ align-items: center;
+}
+
+.metrics-item hr {
+ height: 73px;
+ width: 0px;
+ border: 2px solid var(--primary-color);
+ border-radius: 5px;
+ margin-right: 15px;
+}
+
+.metrics-item h4 {
+ font-size: 30px;
+ font-weight: 600;
+ line-height: 1.2;
+ color: #000000;
+}
+
+.metrics-item p,
+.metrics-item a {
+ font-size: 18px;
+ font-weight: 400;
+}
+
+
+#ontology_versions .show_more_subs td {
+ text-align: right;
+}
+
+#networkContainer{
+ transition: transform 0.3s;
+ }
+
+.active-fullscreen {
+ width: 100%;
+ height: 100vh;
+ position: fixed;
+ left: 0;
+ top: 0;
+ background-color: #ffffff;
+ z-index: 9999;
+}
+#fullscreen-button {
+ background-color: var(--primary-color);
+ -webkit-mask-image: url(asset-path('icons/full-screen.svg'));
+ mask-image: url(asset-path('icons/full-screen.svg'));
+ float: right;
+ position: relative;
+ bottom: 79px;
+ width: 32px;
+ height: 31px;
+ background-repeat: no-repeat!important;
+ background-position: 2px 2px;
+ right: 58px;
+ cursor: pointer;
+ }
+
+div.vis-network div.vis-navigation {
+ div.vis-button.vis-up{
+ background-color: var(--primary-color);
+ -webkit-mask-image: url(asset-path('icons/circle-up.svg'));
+ mask-image: url(asset-path('icons/circle-up.svg'));
+ background-image: none !important;
+ }
+ div.vis-button.vis-down{
+ background-color: var(--primary-color);
+ -webkit-mask-image: url(asset-path('icons/circle-down.svg'));
+ mask-image: url(asset-path('icons/circle-down.svg'));
+ background-image: none !important;
+ }
+
+ div.vis-button.vis-left{
+ background-color: var(--primary-color);
+ -webkit-mask-image: url(asset-path('icons/circle-left.svg'));
+ mask-image: url(asset-path('icons/circle-left.svg'));
+ background-image: none !important;
+ }
+
+ div.vis-button.vis-right{
+ background-color: var(--primary-color);
+ -webkit-mask-image: url(asset-path('icons/circle-right.svg'));
+ mask-image: url(asset-path('icons/circle-right.svg'));
+ background-image: none !important;
+ }
+
+ div.vis-button.vis-zoomIn{
+ background-color: var(--primary-color);
+ -webkit-mask-image: url(asset-path('icons/zoom-in.svg'));
+ mask-image: url(asset-path('icons/zoom-in.svg'));
+ background-image: none !important;
+ }
+
+ div.vis-button.vis-zoomOut{
+ background-color: var(--primary-color);
+ -webkit-mask-image: url(asset-path('icons/zoom-out.svg'));
+ mask-image: url(asset-path('icons/zoom-out.svg'));
+ background-image: none !important;
+ }
+
+ div.vis-button.vis-zoomExtends{
+ background-color: var(--primary-color);
+ -webkit-mask-image: url(asset-path('icons/zoom-center.svg'));
+ mask-image: url(asset-path('icons/zoom-center.svg'));
+ background-image: none !important;
+ }
+}
diff --git a/app/assets/stylesheets/theme-variables.scss.erb b/app/assets/stylesheets/theme-variables.scss.erb
index 35f088524..a0ee3a94c 100644
--- a/app/assets/stylesheets/theme-variables.scss.erb
+++ b/app/assets/stylesheets/theme-variables.scss.erb
@@ -1,29 +1,34 @@
<%# This file contains all the color themes of ontoportal alliance%>
-<% if $UI_THEME
- case $UI_THEME.to_s
+<% if (ui_theme = $UI_THEME.to_s.parameterize)
+ case ui_theme
when "agroportal" %>
:root{
- --primary-color: #31B404;
- --hover-color: #40C811;
+ --primary-color: #3CB371;
+ --hover-color: #41C67C;
--secondary-color: #ffc107;
+ --light-color: #F1F6FA;
}
<% when "stageportal" %>
:root{
- --primary-color: #76A7CC;
- --hover-color: #6B96B7;
+ --primary-color: #37AEA0;
+ --hover-color: #3BBDAE;
--secondary-color: #ffc107;
+ --light-color: #ECF7F6;
}
<% when "bioportal" %>
:root{
--primary-color: #76A7CC;
--hover-color: #6B96B7;
--secondary-color: #ffc107;
+ --light-color: #F0F5F6;
}
- <% when "ontoportal" %>
+
+ <% when "ontoportal" , "testportal" %>
:root{
- --primary-color: #6E98A2;
- --hover-color: #7BABB6;
+ --primary-color: #5499a4;
+ --hover-color: #6B96B7;
--secondary-color: #ffc107;
+ --light-color: #F1F6FA;
}
<% when "ecoportal" %>
:root{
@@ -34,3 +39,24 @@
<%# Here to add a new theme ... %>
<% end %>
<% end %>
+
+
+
+// common variables
+:root{
+ --error-color: #EB4335;
+ --warning-color: #e48c11;
+ --gray-color: #888888;
+ --success-color: #2DC54E;
+ --admin-color: #145FF4;
+ --container-max-width: 1248px;
+ --bg-info-light-color: rgba(59, 130, 246, 0.1);
+ --bg-danger-light-color: rgba(239, 68, 68, 0.1);
+ --bg-warning-light-color: rgba(234, 179, 8, 0.1);
+ --bg-success-light-color: rgba(34, 197, 94, 0.1);
+}
+
+
+
+
+
diff --git a/app/assets/stylesheets/themes/agroportal/main.scss b/app/assets/stylesheets/themes/agroportal/main.scss
index 4ada63be6..61f21efe3 100644
--- a/app/assets/stylesheets/themes/agroportal/main.scss
+++ b/app/assets/stylesheets/themes/agroportal/main.scss
@@ -1,6 +1,6 @@
-$color-primary: #31B404;
+$color-primary: var(--primary-color);
$color-secondary: #EFFFEF;
-$color-links: #215B04;
+$color-links: var(--primary-color);
$color-warning: #ffc107;
@import "../lirmm/main";
@import "search";
\ No newline at end of file
diff --git a/app/assets/stylesheets/themes/lirmm/bootstrap_overrides.scss b/app/assets/stylesheets/themes/lirmm/bootstrap_overrides.scss
index 969dcfec8..defc1f2be 100644
--- a/app/assets/stylesheets/themes/lirmm/bootstrap_overrides.scss
+++ b/app/assets/stylesheets/themes/lirmm/bootstrap_overrides.scss
@@ -6,17 +6,21 @@ a {
color: $color-links;
}
a i {
- color: $color-primary;
+ color: var(--primary-color);
}
+.text-primary {
+ color: var(--primary-color) !important;
+}
+
.btn-info, .btn-outline-primary:hover, .btn-primary , .nav-pills .nav-link.active{
- background-color: $color-primary !important;
- border-color: $color-primary !important;
+ background-color: var(--primary-color) !important;
+ border-color: var(--primary-color) !important;
color: #fff !important;
}
.btn-outline-primary{
- border-color: $color-primary !important;
- color: $color-primary !important;
+ border-color: var(--primary-color) !important;
+ color: var(--primary-color) !important;
}
.btn-danger {
color: #fff !important;
@@ -27,7 +31,7 @@ a i {
}
.btn-link {
- color: $color-primary !important;
+ color: var(--primary-color) !important;
}
.card-header.bg-success {
font-weight: bold;
diff --git a/app/assets/stylesheets/themes/lirmm/flags32.scss b/app/assets/stylesheets/themes/lirmm/flags32.scss
deleted file mode 100644
index 2a7323d7c..000000000
--- a/app/assets/stylesheets/themes/lirmm/flags32.scss
+++ /dev/null
@@ -1,245 +0,0 @@
-.f32 .flag{display:inline-block;height:32px;width:32px;vertical-align:text-top;line-height:32px;background-image: image-url('flags32.png');background-repeat:no-repeat;}
-.f32 ._African_Union{background-position:0 -32px;}
-.f32 ._Arab_League{background-position:0 -64px;}
-.f32 ._ASEAN{background-position:0 -96px;}
-.f32 ._CARICOM{background-position:0 -128px;}
-.f32 ._CIS{background-position:0 -160px;}
-.f32 ._Commonwealth{background-position:0 -192px;}
-.f32 ._England{background-position:0 -224px;}
-.f32 ._European_Union{background-position:0 -256px;}
-.f32 ._Islamic_Conference{background-position:0 -288px;}
-.f32 ._Kosovo{background-position:0 -320px;}
-.f32 ._NATO{background-position:0 -352px;}
-.f32 ._Northern_Cyprus{background-position:0 -384px;}
-.f32 ._Northern_Ireland{background-position:0 -416px;}
-.f32 ._Olimpic_Movement{background-position:0 -448px;}
-.f32 ._OPEC{background-position:0 -480px;}
-.f32 ._Red_Cross{background-position:0 -512px;}
-.f32 ._Scotland{background-position:0 -544px;}
-.f32 ._Somaliland{background-position:0 -576px;}
-.f32 ._Tibet{background-position:0 -608px;}
-.f32 ._United_Nations{background-position:0 -640px;}
-.f32 ._Wales{background-position:0 -672px;}
-.f32 .ad{background-position:0 -704px;}
-.f32 .ae{background-position:0 -736px;}
-.f32 .af{background-position:0 -768px;}
-.f32 .ag{background-position:0 -800px;}
-.f32 .ai{background-position:0 -832px;}
-.f32 .al{background-position:0 -864px;}
-.f32 .am{background-position:0 -896px;}
-.f32 .an{background-position:0 -928px;}
-.f32 .ao{background-position:0 -960px;}
-.f32 .aq{background-position:0 -992px;}
-.f32 .ar{background-position:0 -1024px;}
-.f32 .as{background-position:0 -1056px;}
-.f32 .at{background-position:0 -1088px;}
-.f32 .au{background-position:0 -1120px;}
-.f32 .aw{background-position:0 -1152px;}
-.f32 .az{background-position:0 -1184px;}
-.f32 .ba{background-position:0 -1216px;}
-.f32 .bb{background-position:0 -1248px;}
-.f32 .bd{background-position:0 -1280px;}
-.f32 .be{background-position:0 -1312px;}
-.f32 .bf{background-position:0 -1344px;}
-.f32 .bg{background-position:0 -1376px;}
-.f32 .bh{background-position:0 -1408px;}
-.f32 .bi{background-position:0 -1440px;}
-.f32 .bj{background-position:0 -1472px;}
-.f32 .bm{background-position:0 -1504px;}
-.f32 .bn{background-position:0 -1536px;}
-.f32 .bo{background-position:0 -1568px;}
-.f32 .br{background-position:0 -1600px;}
-.f32 .bs{background-position:0 -1632px;}
-.f32 .bt{background-position:0 -1664px;}
-.f32 .bw{background-position:0 -1696px;}
-.f32 .by{background-position:0 -1728px;}
-.f32 .bz{background-position:0 -1760px;}
-.f32 .ca{background-position:0 -1792px;}
-.f32 .cd{background-position:0 -1824px;}
-.f32 .cf{background-position:0 -1856px;}
-.f32 .cg{background-position:0 -1888px;}
-.f32 .ch{background-position:0 -1920px;}
-.f32 .ci{background-position:0 -1952px;}
-.f32 .ck{background-position:0 -1984px;}
-.f32 .cl{background-position:0 -2016px;}
-.f32 .cm{background-position:0 -2048px;}
-.f32 .cn{background-position:0 -2080px;}
-.f32 .co{background-position:0 -2112px;}
-.f32 .cr{background-position:0 -2144px;}
-.f32 .cu{background-position:0 -2176px;}
-.f32 .cv{background-position:0 -2208px;}
-.f32 .cy{background-position:0 -2240px;}
-.f32 .cz{background-position:0 -2272px;}
-.f32 .de{background-position:0 -2304px;}
-.f32 .dj{background-position:0 -2336px;}
-.f32 .dk{background-position:0 -2368px;}
-.f32 .dm{background-position:0 -2400px;}
-.f32 .do{background-position:0 -2432px;}
-.f32 .dz{background-position:0 -2464px;}
-.f32 .ec{background-position:0 -2496px;}
-.f32 .ee{background-position:0 -2528px;}
-.f32 .eg{background-position:0 -2560px;}
-.f32 .eh{background-position:0 -2592px;}
-.f32 .er{background-position:0 -2624px;}
-.f32 .es{background-position:0 -2656px;}
-.f32 .et{background-position:0 -2688px;}
-.f32 .fi{background-position:0 -2720px;}
-.f32 .fj{background-position:0 -2752px;}
-.f32 .fm{background-position:0 -2784px;}
-.f32 .fo{background-position:0 -2816px;}
-.f32 .fr{background-position:0 -2848px;}
-.f32 .ga{background-position:0 -2880px;}
-.f32 .gb{background-position:0 -2912px;}
-.f32 .gd{background-position:0 -2944px;}
-.f32 .ge{background-position:0 -2976px;}
-.f32 .gg{background-position:0 -3008px;}
-.f32 .gh{background-position:0 -3040px;}
-.f32 .gi{background-position:0 -3072px;}
-.f32 .gl{background-position:0 -3104px;}
-.f32 .gm{background-position:0 -3136px;}
-.f32 .gn{background-position:0 -3168px;}
-.f32 .gp{background-position:0 -3200px;}
-.f32 .gq{background-position:0 -3232px;}
-.f32 .gr{background-position:0 -3264px;}
-.f32 .gt{background-position:0 -3296px;}
-.f32 .gu{background-position:0 -3328px;}
-.f32 .gw{background-position:0 -3360px;}
-.f32 .gy{background-position:0 -3392px;}
-.f32 .hk{background-position:0 -3424px;}
-.f32 .hn{background-position:0 -3456px;}
-.f32 .hr{background-position:0 -3488px;}
-.f32 .ht{background-position:0 -3520px;}
-.f32 .hu{background-position:0 -3552px;}
-.f32 .id{background-position:0 -3584px;}
-.f32 .mc{background-position:0 -3584px;}
-.f32 .ie{background-position:0 -3616px;}
-.f32 .il{background-position:0 -3648px;}
-.f32 .im{background-position:0 -3680px;}
-.f32 .in{background-position:0 -3712px;}
-.f32 .iq{background-position:0 -3744px;}
-.f32 .ir{background-position:0 -3776px;}
-.f32 .is{background-position:0 -3808px;}
-.f32 .it{background-position:0 -3840px;}
-.f32 .je{background-position:0 -3872px;}
-.f32 .jm{background-position:0 -3904px;}
-.f32 .jo{background-position:0 -3936px;}
-.f32 .jp{background-position:0 -3968px;}
-.f32 .ke{background-position:0 -4000px;}
-.f32 .kg{background-position:0 -4032px;}
-.f32 .kh{background-position:0 -4064px;}
-.f32 .ki{background-position:0 -4096px;}
-.f32 .km{background-position:0 -4128px;}
-.f32 .kn{background-position:0 -4160px;}
-.f32 .kp{background-position:0 -4192px;}
-.f32 .kr{background-position:0 -4224px;}
-.f32 .kw{background-position:0 -4256px;}
-.f32 .ky{background-position:0 -4288px;}
-.f32 .kz{background-position:0 -4320px;}
-.f32 .la{background-position:0 -4352px;}
-.f32 .lb{background-position:0 -4384px;}
-.f32 .lc{background-position:0 -4416px;}
-.f32 .li{background-position:0 -4448px;}
-.f32 .lk{background-position:0 -4480px;}
-.f32 .lr{background-position:0 -4512px;}
-.f32 .ls{background-position:0 -4544px;}
-.f32 .lt{background-position:0 -4576px;}
-.f32 .lu{background-position:0 -4608px;}
-.f32 .lv{background-position:0 -4640px;}
-.f32 .ly{background-position:0 -4672px;}
-.f32 .ma{background-position:0 -4704px;}
-.f32 .md{background-position:0 -4736px;}
-.f32 .me{background-position:0 -4768px;}
-.f32 .mg{background-position:0 -4800px;}
-.f32 .mh{background-position:0 -4832px;}
-.f32 .mk{background-position:0 -4864px;}
-.f32 .ml{background-position:0 -4896px;}
-.f32 .mm{background-position:0 -4928px;}
-.f32 .mn{background-position:0 -4960px;}
-.f32 .mo{background-position:0 -4992px;}
-.f32 .mq{background-position:0 -5024px;}
-.f32 .mr{background-position:0 -5056px;}
-.f32 .ms{background-position:0 -5088px;}
-.f32 .mt{background-position:0 -5120px;}
-.f32 .mu{background-position:0 -5152px;}
-.f32 .mv{background-position:0 -5184px;}
-.f32 .mw{background-position:0 -5216px;}
-.f32 .mx{background-position:0 -5248px;}
-.f32 .my{background-position:0 -5280px;}
-.f32 .mz{background-position:0 -5312px;}
-.f32 .na{background-position:0 -5344px;}
-.f32 .nc{background-position:0 -5376px;}
-.f32 .ne{background-position:0 -5408px;}
-.f32 .ng{background-position:0 -5440px;}
-.f32 .ni{background-position:0 -5472px;}
-.f32 .nl{background-position:0 -5504px;}
-.f32 .no{background-position:0 -5536px;}
-.f32 .np{background-position:0 -5568px;}
-.f32 .nr{background-position:0 -5600px;}
-.f32 .nz{background-position:0 -5632px;}
-.f32 .om{background-position:0 -5664px;}
-.f32 .pa{background-position:0 -5696px;}
-.f32 .pe{background-position:0 -5728px;}
-.f32 .pf{background-position:0 -5760px;}
-.f32 .pg{background-position:0 -5792px;}
-.f32 .ph{background-position:0 -5824px;}
-.f32 .pk{background-position:0 -5856px;}
-.f32 .pl{background-position:0 -5888px;}
-.f32 .pr{background-position:0 -5920px;}
-.f32 .ps{background-position:0 -5952px;}
-.f32 .pt{background-position:0 -5984px;}
-.f32 .pw{background-position:0 -6016px;}
-.f32 .py{background-position:0 -6048px;}
-.f32 .qa{background-position:0 -6080px;}
-.f32 .re{background-position:0 -6112px;}
-.f32 .ro{background-position:0 -6144px;}
-.f32 .rs{background-position:0 -6176px;}
-.f32 .ru{background-position:0 -6208px;}
-.f32 .rw{background-position:0 -6240px;}
-.f32 .sa{background-position:0 -6272px;}
-.f32 .sb{background-position:0 -6304px;}
-.f32 .sc{background-position:0 -6336px;}
-.f32 .sd{background-position:0 -6368px;}
-.f32 .se{background-position:0 -6400px;}
-.f32 .sg{background-position:0 -6432px;}
-.f32 .si{background-position:0 -6464px;}
-.f32 .sk{background-position:0 -6496px;}
-.f32 .sl{background-position:0 -6528px;}
-.f32 .sm{background-position:0 -6560px;}
-.f32 .sn{background-position:0 -6592px;}
-.f32 .so{background-position:0 -6624px;}
-.f32 .sr{background-position:0 -6656px;}
-.f32 .st{background-position:0 -6688px;}
-.f32 .sv{background-position:0 -6720px;}
-.f32 .sy{background-position:0 -6752px;}
-.f32 .sz{background-position:0 -6784px;}
-.f32 .tc{background-position:0 -6816px;}
-.f32 .td{background-position:0 -6848px;}
-.f32 .tg{background-position:0 -6880px;}
-.f32 .th{background-position:0 -6912px;}
-.f32 .tj{background-position:0 -6944px;}
-.f32 .tl{background-position:0 -6976px;}
-.f32 .tm{background-position:0 -7008px;}
-.f32 .tn{background-position:0 -7040px;}
-.f32 .to{background-position:0 -7072px;}
-.f32 .tr{background-position:0 -7104px;}
-.f32 .tt{background-position:0 -7136px;}
-.f32 .tv{background-position:0 -7168px;}
-.f32 .tw{background-position:0 -7200px;}
-.f32 .tz{background-position:0 -7232px;}
-.f32 .ua{background-position:0 -7264px;}
-.f32 .ug{background-position:0 -7296px;}
-.f32 .us{background-position:0 -7328px;}
-.f32 .uy{background-position:0 -7360px;}
-.f32 .uz{background-position:0 -7392px;}
-.f32 .va{background-position:0 -7424px;}
-.f32 .vc{background-position:0 -7456px;}
-.f32 .ve{background-position:0 -7488px;}
-.f32 .vg{background-position:0 -7520px;}
-.f32 .vi{background-position:0 -7552px;}
-.f32 .vn{background-position:0 -7584px;}
-.f32 .vu{background-position:0 -7616px;}
-.f32 .ws{background-position:0 -7648px;}
-.f32 .ye{background-position:0 -7680px;}
-.f32 .za{background-position:0 -7712px;}
-.f32 .zm{background-position:0 -7744px;}
-.f32 .zw{background-position:0 -7744px;}
\ No newline at end of file
diff --git a/app/assets/stylesheets/themes/lirmm/landscape.scss b/app/assets/stylesheets/themes/lirmm/landscape.scss
index 13f2a5c32..4d927b256 100644
--- a/app/assets/stylesheets/themes/lirmm/landscape.scss
+++ b/app/assets/stylesheets/themes/lirmm/landscape.scss
@@ -1,6 +1,9 @@
// Place all the styles related to the landscape controller here.
// They will automatically be included in application.css.
// You can use Sass (SCSS) here: http://sass-lang.com/
+.landscape_ontologies_selector{
+ width: 100%;
+}
#pieChartDiv h2 {
margin-bottom: -2em;
diff --git a/app/assets/stylesheets/themes/lirmm/main.scss b/app/assets/stylesheets/themes/lirmm/main.scss
index 0c6431d76..ebb78dbf0 100644
--- a/app/assets/stylesheets/themes/lirmm/main.scss
+++ b/app/assets/stylesheets/themes/lirmm/main.scss
@@ -2,18 +2,11 @@
@import "annotator";
@import "app";
@import "bootstrap_overrides";
-@import "flags32";
@import "jqcloud";
@import "landscape";
@import "ontologies";
@import "recommender";
@import "search";
-@import "tooltipster.bundle.min";
-@import "plugins/tooltipster/sideTip/themes/tooltipster-sideTip-borderless.min";
-@import "plugins/tooltipster/sideTip/themes/tooltipster-sideTip-light.min";
-@import "plugins/tooltipster/sideTip/themes/tooltipster-sideTip-noir.min";
-@import "plugins/tooltipster/sideTip/themes/tooltipster-sideTip-punk.min";
-@import "plugins/tooltipster/sideTip/themes/tooltipster-sideTip-shadow.min";
/************************************
@@ -234,21 +227,3 @@ div.logos a {
}
}
-/************************************
- * FOOTER
-************************************/
-footer, .footer {
- background-color: $color-secondary !important;
- position: relative !important;
- padding: 30px 0;
-}
-
-
-
-footer a.logo.connect img {
- margin-right: 10px;
-}
-
-.legal-text {
- font-size: 0.9rem;
-}
diff --git a/app/assets/stylesheets/themes/lirmm/plugins/tooltipster/sideTip/themes/tooltipster-sideTip-borderless.min.scss b/app/assets/stylesheets/themes/lirmm/plugins/tooltipster/sideTip/themes/tooltipster-sideTip-borderless.min.scss
deleted file mode 100644
index 19408cb1e..000000000
--- a/app/assets/stylesheets/themes/lirmm/plugins/tooltipster/sideTip/themes/tooltipster-sideTip-borderless.min.scss
+++ /dev/null
@@ -1 +0,0 @@
-.tooltipster-sidetip.tooltipster-borderless .tooltipster-box{border:none;background:#1b1b1b;background:rgba(10,10,10,.9)}.tooltipster-sidetip.tooltipster-borderless.tooltipster-bottom .tooltipster-box{margin-top:8px}.tooltipster-sidetip.tooltipster-borderless.tooltipster-left .tooltipster-box{margin-right:8px}.tooltipster-sidetip.tooltipster-borderless.tooltipster-right .tooltipster-box{margin-left:8px}.tooltipster-sidetip.tooltipster-borderless.tooltipster-top .tooltipster-box{margin-bottom:8px}.tooltipster-sidetip.tooltipster-borderless .tooltipster-arrow{height:8px;margin-left:-8px;width:16px}.tooltipster-sidetip.tooltipster-borderless.tooltipster-left .tooltipster-arrow,.tooltipster-sidetip.tooltipster-borderless.tooltipster-right .tooltipster-arrow{height:16px;margin-left:0;margin-top:-8px;width:8px}.tooltipster-sidetip.tooltipster-borderless .tooltipster-arrow-background{display:none}.tooltipster-sidetip.tooltipster-borderless .tooltipster-arrow-border{border:8px solid transparent}.tooltipster-sidetip.tooltipster-borderless.tooltipster-bottom .tooltipster-arrow-border{border-bottom-color:#1b1b1b;border-bottom-color:rgba(10,10,10,.9)}.tooltipster-sidetip.tooltipster-borderless.tooltipster-left .tooltipster-arrow-border{border-left-color:#1b1b1b;border-left-color:rgba(10,10,10,.9)}.tooltipster-sidetip.tooltipster-borderless.tooltipster-right .tooltipster-arrow-border{border-right-color:#1b1b1b;border-right-color:rgba(10,10,10,.9)}.tooltipster-sidetip.tooltipster-borderless.tooltipster-top .tooltipster-arrow-border{border-top-color:#1b1b1b;border-top-color:rgba(10,10,10,.9)}.tooltipster-sidetip.tooltipster-borderless.tooltipster-bottom .tooltipster-arrow-uncropped{top:-8px}.tooltipster-sidetip.tooltipster-borderless.tooltipster-right .tooltipster-arrow-uncropped{left:-8px}
\ No newline at end of file
diff --git a/app/assets/stylesheets/themes/lirmm/plugins/tooltipster/sideTip/themes/tooltipster-sideTip-light.min.scss b/app/assets/stylesheets/themes/lirmm/plugins/tooltipster/sideTip/themes/tooltipster-sideTip-light.min.scss
deleted file mode 100644
index 298c9d4a5..000000000
--- a/app/assets/stylesheets/themes/lirmm/plugins/tooltipster/sideTip/themes/tooltipster-sideTip-light.min.scss
+++ /dev/null
@@ -1 +0,0 @@
-.tooltipster-sidetip.tooltipster-light .tooltipster-box{border-radius:3px;border:1px solid #ccc;background:#ededed}.tooltipster-sidetip.tooltipster-light .tooltipster-content{color:#666}.tooltipster-sidetip.tooltipster-light .tooltipster-arrow{height:9px;margin-left:-9px;width:18px}.tooltipster-sidetip.tooltipster-light.tooltipster-left .tooltipster-arrow,.tooltipster-sidetip.tooltipster-light.tooltipster-right .tooltipster-arrow{height:18px;margin-left:0;margin-top:-9px;width:9px}.tooltipster-sidetip.tooltipster-light .tooltipster-arrow-background{border:9px solid transparent}.tooltipster-sidetip.tooltipster-light.tooltipster-bottom .tooltipster-arrow-background{border-bottom-color:#ededed;top:1px}.tooltipster-sidetip.tooltipster-light.tooltipster-left .tooltipster-arrow-background{border-left-color:#ededed;left:-1px}.tooltipster-sidetip.tooltipster-light.tooltipster-right .tooltipster-arrow-background{border-right-color:#ededed;left:1px}.tooltipster-sidetip.tooltipster-light.tooltipster-top .tooltipster-arrow-background{border-top-color:#ededed;top:-1px}.tooltipster-sidetip.tooltipster-light .tooltipster-arrow-border{border:9px solid transparent}.tooltipster-sidetip.tooltipster-light.tooltipster-bottom .tooltipster-arrow-border{border-bottom-color:#ccc}.tooltipster-sidetip.tooltipster-light.tooltipster-left .tooltipster-arrow-border{border-left-color:#ccc}.tooltipster-sidetip.tooltipster-light.tooltipster-right .tooltipster-arrow-border{border-right-color:#ccc}.tooltipster-sidetip.tooltipster-light.tooltipster-top .tooltipster-arrow-border{border-top-color:#ccc}.tooltipster-sidetip.tooltipster-light.tooltipster-bottom .tooltipster-arrow-uncropped{top:-9px}.tooltipster-sidetip.tooltipster-light.tooltipster-right .tooltipster-arrow-uncropped{left:-9px}
\ No newline at end of file
diff --git a/app/assets/stylesheets/themes/lirmm/plugins/tooltipster/sideTip/themes/tooltipster-sideTip-noir.min.scss b/app/assets/stylesheets/themes/lirmm/plugins/tooltipster/sideTip/themes/tooltipster-sideTip-noir.min.scss
deleted file mode 100644
index 39f4ca388..000000000
--- a/app/assets/stylesheets/themes/lirmm/plugins/tooltipster/sideTip/themes/tooltipster-sideTip-noir.min.scss
+++ /dev/null
@@ -1 +0,0 @@
-.tooltipster-sidetip.tooltipster-noir .tooltipster-box{border-radius:0;border:3px solid #000;background:#fff}.tooltipster-sidetip.tooltipster-noir .tooltipster-content{color:#000}.tooltipster-sidetip.tooltipster-noir .tooltipster-arrow{height:11px;margin-left:-11px;width:22px}.tooltipster-sidetip.tooltipster-noir.tooltipster-left .tooltipster-arrow,.tooltipster-sidetip.tooltipster-noir.tooltipster-right .tooltipster-arrow{height:22px;margin-left:0;margin-top:-11px;width:11px}.tooltipster-sidetip.tooltipster-noir .tooltipster-arrow-background{border:11px solid transparent}.tooltipster-sidetip.tooltipster-noir.tooltipster-bottom .tooltipster-arrow-background{border-bottom-color:#fff;top:4px}.tooltipster-sidetip.tooltipster-noir.tooltipster-left .tooltipster-arrow-background{border-left-color:#fff;left:-4px}.tooltipster-sidetip.tooltipster-noir.tooltipster-right .tooltipster-arrow-background{border-right-color:#fff;left:4px}.tooltipster-sidetip.tooltipster-noir.tooltipster-top .tooltipster-arrow-background{border-top-color:#fff;top:-4px}.tooltipster-sidetip.tooltipster-noir .tooltipster-arrow-border{border-width:11px}.tooltipster-sidetip.tooltipster-noir.tooltipster-bottom .tooltipster-arrow-uncropped{top:-11px}.tooltipster-sidetip.tooltipster-noir.tooltipster-right .tooltipster-arrow-uncropped{left:-11px}
\ No newline at end of file
diff --git a/app/assets/stylesheets/themes/lirmm/plugins/tooltipster/sideTip/themes/tooltipster-sideTip-punk.min.scss b/app/assets/stylesheets/themes/lirmm/plugins/tooltipster/sideTip/themes/tooltipster-sideTip-punk.min.scss
deleted file mode 100644
index 6702cf557..000000000
--- a/app/assets/stylesheets/themes/lirmm/plugins/tooltipster/sideTip/themes/tooltipster-sideTip-punk.min.scss
+++ /dev/null
@@ -1 +0,0 @@
-.tooltipster-sidetip.tooltipster-punk .tooltipster-box{border-radius:5px;border:none;border-bottom:3px solid #f71169;background:#2a2a2a}.tooltipster-sidetip.tooltipster-punk.tooltipster-top .tooltipster-box{margin-bottom:7px}.tooltipster-sidetip.tooltipster-punk .tooltipster-content{color:#fff;padding:8px 16px}.tooltipster-sidetip.tooltipster-punk .tooltipster-arrow-background{display:none}.tooltipster-sidetip.tooltipster-punk.tooltipster-bottom .tooltipster-arrow-border{border-bottom-color:#2a2a2a}.tooltipster-sidetip.tooltipster-punk.tooltipster-left .tooltipster-arrow-border{border-left-color:#2a2a2a}.tooltipster-sidetip.tooltipster-punk.tooltipster-right .tooltipster-arrow-border{border-right-color:#2a2a2a}.tooltipster-sidetip.tooltipster-punk.tooltipster-top .tooltipster-arrow-border{border-top-color:#f71169}
\ No newline at end of file
diff --git a/app/assets/stylesheets/themes/lirmm/plugins/tooltipster/sideTip/themes/tooltipster-sideTip-shadow.min.scss b/app/assets/stylesheets/themes/lirmm/plugins/tooltipster/sideTip/themes/tooltipster-sideTip-shadow.min.scss
deleted file mode 100644
index 7d92926de..000000000
--- a/app/assets/stylesheets/themes/lirmm/plugins/tooltipster/sideTip/themes/tooltipster-sideTip-shadow.min.scss
+++ /dev/null
@@ -1 +0,0 @@
-.tooltipster-sidetip.tooltipster-shadow .tooltipster-box{border:none;border-radius:5px;background:#fff;box-shadow:0 0 10px 6px rgba(0,0,0,.1)}.tooltipster-sidetip.tooltipster-shadow.tooltipster-bottom .tooltipster-box{margin-top:6px}.tooltipster-sidetip.tooltipster-shadow.tooltipster-left .tooltipster-box{margin-right:6px}.tooltipster-sidetip.tooltipster-shadow.tooltipster-right .tooltipster-box{margin-left:6px}.tooltipster-sidetip.tooltipster-shadow.tooltipster-top .tooltipster-box{margin-bottom:6px}.tooltipster-sidetip.tooltipster-shadow .tooltipster-content{color:#8d8d8d}.tooltipster-sidetip.tooltipster-shadow .tooltipster-arrow{height:6px;margin-left:-6px;width:12px}.tooltipster-sidetip.tooltipster-shadow.tooltipster-left .tooltipster-arrow,.tooltipster-sidetip.tooltipster-shadow.tooltipster-right .tooltipster-arrow{height:12px;margin-left:0;margin-top:-6px;width:6px}.tooltipster-sidetip.tooltipster-shadow .tooltipster-arrow-background{display:none}.tooltipster-sidetip.tooltipster-shadow .tooltipster-arrow-border{border:6px solid transparent}.tooltipster-sidetip.tooltipster-shadow.tooltipster-bottom .tooltipster-arrow-border{border-bottom-color:#fff}.tooltipster-sidetip.tooltipster-shadow.tooltipster-left .tooltipster-arrow-border{border-left-color:#fff}.tooltipster-sidetip.tooltipster-shadow.tooltipster-right .tooltipster-arrow-border{border-right-color:#fff}.tooltipster-sidetip.tooltipster-shadow.tooltipster-top .tooltipster-arrow-border{border-top-color:#fff}.tooltipster-sidetip.tooltipster-shadow.tooltipster-bottom .tooltipster-arrow-uncropped{top:-6px}.tooltipster-sidetip.tooltipster-shadow.tooltipster-right .tooltipster-arrow-uncropped{left:-6px}
\ No newline at end of file
diff --git a/app/assets/stylesheets/themes/lirmm/tooltipster.bundle.min.scss b/app/assets/stylesheets/themes/lirmm/tooltipster.bundle.min.scss
deleted file mode 100644
index d8f30feec..000000000
--- a/app/assets/stylesheets/themes/lirmm/tooltipster.bundle.min.scss
+++ /dev/null
@@ -1 +0,0 @@
-.tooltipster-fall,.tooltipster-grow.tooltipster-show{-webkit-transition-timing-function:cubic-bezier(.175,.885,.32,1);-moz-transition-timing-function:cubic-bezier(.175,.885,.32,1.15);-ms-transition-timing-function:cubic-bezier(.175,.885,.32,1.15);-o-transition-timing-function:cubic-bezier(.175,.885,.32,1.15)}.tooltipster-base{display:flex;pointer-events:none;position:absolute}.tooltipster-box{flex:1 1 auto}.tooltipster-content{box-sizing:border-box;max-height:100%;max-width:100%;overflow:auto}.tooltipster-ruler{bottom:0;left:0;overflow:hidden;position:fixed;right:0;top:0;visibility:hidden}.tooltipster-fade{opacity:0;-webkit-transition-property:opacity;-moz-transition-property:opacity;-o-transition-property:opacity;-ms-transition-property:opacity;transition-property:opacity}.tooltipster-fade.tooltipster-show{opacity:1}.tooltipster-grow{-webkit-transform:scale(0,0);-moz-transform:scale(0,0);-o-transform:scale(0,0);-ms-transform:scale(0,0);transform:scale(0,0);-webkit-transition-property:-webkit-transform;-moz-transition-property:-moz-transform;-o-transition-property:-o-transform;-ms-transition-property:-ms-transform;transition-property:transform;-webkit-backface-visibility:hidden}.tooltipster-grow.tooltipster-show{-webkit-transform:scale(1,1);-moz-transform:scale(1,1);-o-transform:scale(1,1);-ms-transform:scale(1,1);transform:scale(1,1);-webkit-transition-timing-function:cubic-bezier(.175,.885,.32,1.15);transition-timing-function:cubic-bezier(.175,.885,.32,1.15)}.tooltipster-swing{opacity:0;-webkit-transform:rotateZ(4deg);-moz-transform:rotateZ(4deg);-o-transform:rotateZ(4deg);-ms-transform:rotateZ(4deg);transform:rotateZ(4deg);-webkit-transition-property:-webkit-transform,opacity;-moz-transition-property:-moz-transform;-o-transition-property:-o-transform;-ms-transition-property:-ms-transform;transition-property:transform}.tooltipster-swing.tooltipster-show{opacity:1;-webkit-transform:rotateZ(0);-moz-transform:rotateZ(0);-o-transform:rotateZ(0);-ms-transform:rotateZ(0);transform:rotateZ(0);-webkit-transition-timing-function:cubic-bezier(.23,.635,.495,1);-webkit-transition-timing-function:cubic-bezier(.23,.635,.495,2.4);-moz-transition-timing-function:cubic-bezier(.23,.635,.495,2.4);-ms-transition-timing-function:cubic-bezier(.23,.635,.495,2.4);-o-transition-timing-function:cubic-bezier(.23,.635,.495,2.4);transition-timing-function:cubic-bezier(.23,.635,.495,2.4)}.tooltipster-fall{-webkit-transition-property:top;-moz-transition-property:top;-o-transition-property:top;-ms-transition-property:top;transition-property:top;-webkit-transition-timing-function:cubic-bezier(.175,.885,.32,1.15);transition-timing-function:cubic-bezier(.175,.885,.32,1.15)}.tooltipster-fall.tooltipster-initial{top:0!important}.tooltipster-fall.tooltipster-dying{-webkit-transition-property:all;-moz-transition-property:all;-o-transition-property:all;-ms-transition-property:all;transition-property:all;top:0!important;opacity:0}.tooltipster-slide{-webkit-transition-property:left;-moz-transition-property:left;-o-transition-property:left;-ms-transition-property:left;transition-property:left;-webkit-transition-timing-function:cubic-bezier(.175,.885,.32,1);-webkit-transition-timing-function:cubic-bezier(.175,.885,.32,1.15);-moz-transition-timing-function:cubic-bezier(.175,.885,.32,1.15);-ms-transition-timing-function:cubic-bezier(.175,.885,.32,1.15);-o-transition-timing-function:cubic-bezier(.175,.885,.32,1.15);transition-timing-function:cubic-bezier(.175,.885,.32,1.15)}.tooltipster-slide.tooltipster-initial{left:-40px!important}.tooltipster-slide.tooltipster-dying{-webkit-transition-property:all;-moz-transition-property:all;-o-transition-property:all;-ms-transition-property:all;transition-property:all;left:0!important;opacity:0}@keyframes tooltipster-fading{0%{opacity:0}100%{opacity:1}}.tooltipster-update-fade{animation:tooltipster-fading .4s}@keyframes tooltipster-rotating{25%{transform:rotate(-2deg)}75%{transform:rotate(2deg)}100%{transform:rotate(0)}}.tooltipster-update-rotate{animation:tooltipster-rotating .6s}@keyframes tooltipster-scaling{50%{transform:scale(1.1)}100%{transform:scale(1)}}.tooltipster-update-scale{animation:tooltipster-scaling .6s}.tooltipster-sidetip .tooltipster-box{background:#565656;border:2px solid #000;border-radius:4px}.tooltipster-sidetip.tooltipster-bottom .tooltipster-box{margin-top:8px}.tooltipster-sidetip.tooltipster-left .tooltipster-box{margin-right:8px}.tooltipster-sidetip.tooltipster-right .tooltipster-box{margin-left:8px}.tooltipster-sidetip.tooltipster-top .tooltipster-box{margin-bottom:8px}.tooltipster-sidetip .tooltipster-content{color:#fff;line-height:18px;padding:6px 14px}.tooltipster-sidetip .tooltipster-arrow{overflow:hidden;position:absolute}.tooltipster-sidetip.tooltipster-bottom .tooltipster-arrow{height:10px;margin-left:-10px;top:0;width:20px}.tooltipster-sidetip.tooltipster-left .tooltipster-arrow{height:20px;margin-top:-10px;right:0;top:0;width:10px}.tooltipster-sidetip.tooltipster-right .tooltipster-arrow{height:20px;margin-top:-10px;left:0;top:0;width:10px}.tooltipster-sidetip.tooltipster-top .tooltipster-arrow{bottom:0;height:10px;margin-left:-10px;width:20px}.tooltipster-sidetip .tooltipster-arrow-background,.tooltipster-sidetip .tooltipster-arrow-border{height:0;position:absolute;width:0}.tooltipster-sidetip .tooltipster-arrow-background{border:10px solid transparent}.tooltipster-sidetip.tooltipster-bottom .tooltipster-arrow-background{border-bottom-color:#565656;left:0;top:3px}.tooltipster-sidetip.tooltipster-left .tooltipster-arrow-background{border-left-color:#565656;left:-3px;top:0}.tooltipster-sidetip.tooltipster-right .tooltipster-arrow-background{border-right-color:#565656;left:3px;top:0}.tooltipster-sidetip.tooltipster-top .tooltipster-arrow-background{border-top-color:#565656;left:0;top:-3px}.tooltipster-sidetip .tooltipster-arrow-border{border:10px solid transparent;left:0;top:0}.tooltipster-sidetip.tooltipster-bottom .tooltipster-arrow-border{border-bottom-color:#000}.tooltipster-sidetip.tooltipster-left .tooltipster-arrow-border{border-left-color:#000}.tooltipster-sidetip.tooltipster-right .tooltipster-arrow-border{border-right-color:#000}.tooltipster-sidetip.tooltipster-top .tooltipster-arrow-border{border-top-color:#000}.tooltipster-sidetip .tooltipster-arrow-uncropped{position:relative}.tooltipster-sidetip.tooltipster-bottom .tooltipster-arrow-uncropped{top:-10px}.tooltipster-sidetip.tooltipster-right .tooltipster-arrow-uncropped{left:-10px}
\ No newline at end of file
diff --git a/app/assets/stylesheets/themes/ontoportal/main.scss b/app/assets/stylesheets/themes/ontoportal/main.scss
index 2130fbeb5..b314af78e 100644
--- a/app/assets/stylesheets/themes/ontoportal/main.scss
+++ b/app/assets/stylesheets/themes/ontoportal/main.scss
@@ -1,6 +1,6 @@
-$color-primary: rgb(110, 152, 162);
-$color-secondary: #F7FDFC;
-$color-links: rgb(144, 188, 185);
+$color-primary: var(--primary-color);
+$color-secondary: #E4F1FB;
+$color-links: var(--primary-color);
$color-warning: #ffc107;
@import "../lirmm/main";
@import "search";
\ No newline at end of file
diff --git a/app/assets/stylesheets/themes/stageportal/main.scss b/app/assets/stylesheets/themes/stageportal/main.scss
index a56992679..b314af78e 100644
--- a/app/assets/stylesheets/themes/stageportal/main.scss
+++ b/app/assets/stylesheets/themes/stageportal/main.scss
@@ -1,6 +1,6 @@
-$color-primary: #76A7CC;
+$color-primary: var(--primary-color);
$color-secondary: #E4F1FB;
-$color-links: #76A7CC;
+$color-links: var(--primary-color);
$color-warning: #ffc107;
@import "../lirmm/main";
@import "search";
\ No newline at end of file
diff --git a/app/assets/stylesheets/tools.scss b/app/assets/stylesheets/tools.scss
new file mode 100644
index 000000000..3ed34770a
--- /dev/null
+++ b/app/assets/stylesheets/tools.scss
@@ -0,0 +1,13 @@
+.tools-container{
+ svg path {
+ fill: var(--primary-color);
+ }
+ .summary-card{
+ height: 100%;
+ background-color: white;
+ }
+
+ .tool-description{
+ color: var(--gray-color) !important;
+ }
+}
\ No newline at end of file
diff --git a/app/assets/stylesheets/tree.scss b/app/assets/stylesheets/tree.scss
deleted file mode 100644
index ed2d3a7c7..000000000
--- a/app/assets/stylesheets/tree.scss
+++ /dev/null
@@ -1,323 +0,0 @@
-/********************
-## TREE VIEW
-*********************/
-div.tree_error {
- background: none repeat scroll 0 0 lightYellow;
- font-weight: 600;
- padding: 5px 10px;
-}
-.expansion_error {
- color: red;
- font-size: x-small;
- font-style: oblique;
- padding: 0 3px;
-}
-.ncboTree {
- margin:0;
- padding:0;
- font-family: sans-serif;
-}
-.ncboTree li {
- list-style: none;
- margin:0;
- padding:0 0 0 22px;
- line-height: 14px;
-}
-.ncboTree li span {
- display:inline;
- clear: left;
- white-space: nowrap;
-}
-.ncboTree ul {
- margin:0;
- padding:0;
-}
-.ncboTree .root ul {
- margin:0;
-}
-.ncboTree .root {
- margin-left:-16px !important;
-}
-.ncboTree .line {
- padding:0;
- line-height: 3px;
- height:3px;
- font-size:3px;
- background: 0 0 no-repeat transparent url(data:image/gif;base64,R0lGODlhUAAUAIABAICAgP///yH5BAEAAAEALAAAAABQABQAAAI0jI+py+0PG4i02ouz3mryD4bi+HjkiabqYq7uC2NtTNd2MN/6Tub8D5QFh8SKr4hEHpOQAgA7);
-}
-.ncboTree .line-last {
- padding:0;
- line-height: 3px;
- height:3px;
- font-size:3px;
- background: 0 0 no-repeat transparent url(data:image/gif;base64,R0lGODlhAQABAID/AMDAwAAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==);
-}
-.ncboTree .line-over {
- padding:0;
- line-height: 3px;
- height:3px;
- font-size:3px;
- background: 0 0 no-repeat transparent url(data:image/gif;base64,R0lGODlhUAAUAMQfAICAgEVFRUZHRoKBgUlISKKionl6enJycmRkY2tra/Ly81JSUpGRkaqqq8rLyrOzstnZ2cLDwk1NTfv8+/f39+zt7Lq7u+fn5lhYV////15eXuDg4NLS0omKipqamf///yH5BAEAAB8ALAAAAABQABQAAAV44CeOH0CSQXCubOu+cAwHAvFJ3/Jhn/Yhn8Tn8DF8Bp/Oh/HxfAqfxufxsXwiH8eH84F8Np/Lp/JRfCifyScjM7FSsrh8Tq/b73Q3fs/v+/9zeoCDhIWGMIKHiouMeImNkJGSJI+TlpeFlZibnHeanaChL5+ipZshADs=);
-}
-.ncboTree .line-over-last {
- padding:0;
- line-height: 3px;
- height:3px;
- font-size:3px;
- background: 0 0 no-repeat transparent url(data:image/gif;base64,R0lGODlhUAAUAMQeAEVFRWtra+fn5k1NTWRkY3l6enJycklISMrLyvLy8////5qamV5eXvf397q7u1hYV8LDwkZHRoKBgbOzspGRkVJSUtnZ2eDg4Ozt7Pv8+6qqq9LS0omKiqKiov///wAAACH5BAEAAB4ALAAAAABQABQAAAVooCeOZOkBgKmubOu+8AhEhzd4lfd4jEd4AY/BU/BIPBwPxbPwdDwaz8Tj8EA8CM/GY/FcPAIPxpPwNDwZjyK2QrHf8Lh8Tq/b7/i8fs/v+/+AgYKDhIWGh4iJiouMjY6PkJGSk5SViSEAOw==);
-}
-.ncboTree .folder-open {
- background: 0 -2px no-repeat #fff url(data:image/gif;base64,R0lGODlhEQC6BOYAAICAgP//nHueu8aaGfn7+f/4k8TExP/////bdf/vif/kf///mQQCBMS+uaVzDcyZNM/PvNrYyuzs6OTe1s3Nzevz+7fG18mWMfr7/MuYM///paBuCJpoAsXFxZ5sBpxqBNDc58+iJqRyDPfwiZlnAf/XhMzLx6NxC7q6tNe4QLqHIsiVMJKvx523zad1D9q/bLB+GL/M2/r7+n2fvLOBG36gvb2KJfDkesKPKuKzQ7WCHf/rhMmgIbeEH6JwCsaaGv3VcOLBUKx6FNHR0fH097e3t////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAEYALAAAAAARALoEAAf/gEaCg4SFhoMAh4qLi4mMRkQgLTMClQIWiiwyBJydAooCnaKfh6GiFROkhqEMra0Rn4mOggIVFRK4E7CguhEQvyaqhQIQDcYNKA3ChDE1lpaYj7OP1IfT1diC19nV29zS39ze4Yrj5Ibm54Tp6trt4O+N8fLz1vX294Xs7fvq/ef/yAUMN/BbQXH59CVctxBRQ3cPD2aTiI1it4dGLFLTCK8hR0Yf6XnEGLIcyZMRUY5MyXKly4Ul8b1MGBOdSpg3aebMV1NhS5w/dQblufNeT4ZDjRatd9RhUqZL5zWFOJPoU6lR403NmPXd1q9d+YX1NxZgWYFnCaY1uBbhVa1t/yfGrTj34luvdTfm7Qi0qtK7YgGTFWyWMFrDahGzVezWL1TGciHTlWzXMVbKejHzFWoZrmaQe0F/Ftm3NGfTVjvjHW2StUzUf1UHlj2YdmHbh3En1r2Yd2PYj31HFj6ZeGXgl41nVr45NXLPzEVHJ326unPrsZ+vnt6a+2vswbXPFl+b/G3zudHvVt+b/W/wyd0Pl1+c/nH40O0v1988O/7t/EkXIHXXFeifgeH9N56C5TF4noPpQbiehO1R+B6C8Vk4n4b1cXgfhvl5uJ+I/SUIIoAkCpgigQe2aKKLGZ64oIwN0vigjRHiOKGOFfJ4IYwh+rihkB0S+SGQKBo5ov+SJcaI5IxP1hjljVPmWOWOV/aY5Y8vdumkl0FuOaSYRZJ5JJhJmrmkmk2GiSaUb0oZJ5VzWlknlndqmSeXX/bppp9p7jmmoGUSeiagcCIqp6J0Mmqno3hCqqekfP5paaCUDpppoZseemminy4aaqOjPlpqpKdOmmqlmK6qqaucwuppq7SCWquot5Kaq6m7otqrqr+yauuwuBKrq7G8IuurssAyK2yx0B4bbbLTLltts9c+K+221HJrrbfYgqttt+R+W264545r7rrosqtuu/C+K++rwdLrrL3Z4iuuvuny666/8QI8b6z1EnyvwfkivK/C/TL8r8MBQzzwrAdTnLBYxQtj3LDGD3McsccTr2moyJ2SLKvJBYMs8MoSs6xyyzC/LDPKFdN8sc0Z47yxzh3z/LHPIbeZMtAuEx2z0TMLXbPSNzOds9M7Q92z1D9THTRGWGetdTiBAAA7);
-}
-.ncboTree .folder-open-last {
- background: 0 -2px no-repeat #fff url(data:image/gif;base64,R0lGODlhEQAWAOYAAP/bdf/vif/kf///mQQCBMS+uaVzDc/PvICAgNrYysyZNM3Nzevz++zs6OTe1smWMcXFxbfG15poAp5sBv//pZxqBPr7/MuYM6BuCLWCHX6gvdHR0cKPKuLBULB+GJlnAdq/bPfwiaRyDLe3t7eEH7q6tOKzQ7/M28mgIciVMNDc58+iJvr7+qx6FPDkeszLx7OBG5Kvx/3VcLqHIp23zb2KJcaaGqNxC6JwCv/rhH2fvNe4QP/XhPH096d1D8TExP/4k/n7+caaGXueu///nP///////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAEYALAAAAAARABYAAAdcgEaCg4SFhoMIh4qLi4mMj4c9KjQ6Q5ZDEYoxLEGdnkOKQ56joIeiowwOpYaiBK6uCaCJjoJDDAwNuQ6xobsJB8Avq4VDBwXHBSUFw4QnGpeXmZDT1NXW19jZ1oEAOw==);
-}
-.ncboTree .folder-close-last {
- background: 0 -2px no-repeat #fff url(data:image/gif;base64,R0lGODlhEgAWAOYAAOvr6//bdf//nP/vif/kf//4k//UbwQCBO/v78S+ufv7+9u3UoCAgNrYysyZNMHBwevz++Tk5M/PvOTe1smWMcKPKpxqBLB+GLOBG72KJaBuCP//uuzs6LfG17e3t5lnAbWCHdu3caNxC55sBsuYM7qHIsCNKLq6tMiVMKx6FMbGxp23zceUL/r7+q58Fr/M26VzDbeEH6d1D32fvKt5E/H0936gvZKvx6h2EJpoAqampszLx8WSLdDc57a2tvn7+Xueu///////mf///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAEMALAAAAAASABYAAAdfgEOCg4SFhoQMh4qLjEOJjZCHNT0rM0CXQB2LNy0/np9Ai0CfB6CipD8QE6GKowevrw2hiY+DQBAQHAccE7KivQ0HEhI7rIdAEgnKCScJxoYvNpiYmpHW19jZ2tvc2YEAOw==);
-}
-.ncboTree .folder-close {
- background: 0 -2px no-repeat #fff url(data:image/gif;base64,R0lGODlhEgC+BOYAAICAgP//mXueu/n7+f///7a2tuvr6//Ub//4k///nP/vif/bdf/kfwQCBPv7++/v78S+udu3UtrYysyZNOTe1sHBwc/PvOTk5Ovz++zs6Nu3cbB+GLqHIrfG16BuCJlnAf//usmWMcKPKrWCHcuYM5xqBL2KJbOBG55sBqNxC7e3t8iVMJ23zcCNKKt5E6h2ELq6tL/M26ampreEH/H098bGxn6gvczLx8WSLceUL658Fn2fvPr7+qVzDad1D6x6FJKvx5poAtDc5////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAEMALAAAAAASAL4EAAf/gEOCg4SFhoQAh4qLjEOJjUM0Qiw7ApYCHYtAPAOdngKLAp4Nn6GjAxgUoIqiDa6uEqCJj4MCGBgZDRkUsaG8Eg0WFjerhwIWEMkQMBDFhjE2l5eZkLSQ14fW2NuC2tzY3t/V4t/h5Ivm59nq4OzX6e6D8PGO9Izz8fju+uz86v7nAJITKI5gOXvoECoyyI3hNoftFBqC+E7iRIuFKI7DKI9jR4/1QGpsNPIeyJAeSyYUeVLlwpYwWcpMGZPmTI4u193EmPPiTos9M9bEOZRnUaBHJQZFlFTh0o82oxL9qbQpwqfdrNrDinKqVKNUnWqlx7Xs2Hxn96Xtt/Zf24Bv/wfGLTj3YNirdRvmfbg34lekd7f2rRiY7OCNf6sWRrtYbWO2j91GhjtZbmW6l+0mFptZb2e+n/16HQ12M97QhE0LRo2YNGDVhlmTPDxbtknbK2Ez1u2YN2TfkoFTFm6ZOGbjml0rRu6ZOWjnoksr5ww99fTT1VtL3/76+urstcHfFp/be2zyL3GnR6+TvU/3QtW3N7+bfm/7v/EH1z+cf3H/xwGYHHfLCdicgc8hGF13BFKnoHUNYvegdgxWWGCE300YnobjcVgehud5uJ6I84FYn4n3oZifivux2J+L/8EYoIwDWuggjQfimKCOC15oo4Q8QvhjhkFS6OORNw4ZYv+RGzLZoZMfKnmilClSuaKVLWL5opYxcjmjlzUiCSSYOZK5o5k9JikmkWgKueaSbRqp5pxjvjmlnVXieaWeWfK5pZ9dAvqloGHSySahZSJ6pqJp1mkonIy6+eidk+ZZ6Z6X9pnpn5sG2umgnxbq6KiHhpqoqYui2mippEKqqqStUhqrpbNiWqumt3Kaq6e7gtqrqKwG6+qvpxKbqrGrDiusrMvS2qytz+Iara7T8lqtr9cCq+y2zHLrrLfQgiutuNSSa6252KKrbbfsfttuuO+OG2+5855bb7r3ruvuvvDyK6+/9AJsr8D4Eqxvvwj/m3DACw/ccMEPH6zwxAxT7LBixRBjLHHFHF/cccYfb+zxyCCTLHLJKJ+scrHZsqyuy/nCbLDMEdOssc0h42yyzinzvPKxLQP9stAxEz2z0TUjfbPSOTO9s9M9Q/1zskVTfbTVSWO9tNZNn+T112CHLTY3gQAAOw==);
-}
-.ncboTree .doc {
- background: 0 -1px no-repeat #fff url(data:image/gif;base64,R0lGODlhEgC4BOYAAICAgNvt/3V4o+Hw/+n1/+vr67e3t7a2tv///8nk/4ep3NHp/3SAsvj7/+32//v7++/v78HBwf39/djr//P5/8Df/8Ph//7//+Tk5Gdtnvz9/213qIGVw2lwotvn98bGxoyu33J8rpOq0n2Jto+z5fT09X+OvMDA//n5+W96rOTx/4SbyvX6/2t0pf7+/nN+sIqo2fb6/9jl9s7T/2Vqml5hkPf399nh7ZK877rd/83m/3qDsJS/8lWn7ZCjy87n/5G46oeh0v///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAEIALAAAAAASALgEAAf/gEKCg4SFhoQAh4qLjEKJjZCNj5GUhpOVmI6aiZyZjJeekaChkqSVo6aKqKmWrJCrroOwsZq0qra3uK26hbOxvq7ArMKpxKbGpMihyp7Mmc6Y0Ke8vdSI1rLYgtKU3KLatdjer+Djpdrmn+Xr6Ozi7tbpi/K57+339vnx8NT0h/679PXjxwtgNXz7EA5UWJCgLoPXGD50iAtiNokVKdqyuE0jLY7hEgpsiHGjx18ng6UctrJYy2Mvk8VcNrNZzWc3o+WcVvLjzm4/v/VEOVRlUZZHXSaFuVRmU5pPbUbFOVVnVZ4jJ14FulVo1oxdyYU999XkWHVn5wUVW9Zn2noi/+MubEuUrlG7SPEq1cuUr1O/UAFLFUyVsFXDWOWSRMyVsVfFWh2zhQxWMlnKZi2j1az27b+1l+didssZrujTi0fXVX2XdV7Xe2H3lf2XdmDbg3EX1n2Yd2LUkX03Fv4YeGXik41nRh46tXLSzDdH71z6s+eA00073x78+WrvrcG/Fh+b/GzztdHfVp+b/W73veH/5n5c/nD7xekvx59cP3T+zXXn33cDhlfgeAeWl+B5C6bX4HoPthfhexPGV+F8AmZY34X3cZifhvt52B+I/4kY4IYkEpiigSsi2KKCLzIYo4MzQlijhDdSmKOFO2KI4o8h9tihkB8CWSKRIxqpov+SLDLpopMwQimjlDRSaaOVOGKpo5Y8culjkF4OGWaRYJZ55JhJmrmkmk2y+aSbUcI5pZxV0nmlnVniuaWeXfL55Zl+ihkomYAWuqahbSL6pqJxMjqno3VCeqekeVK6p6V9YvrnoZwm2uminzYa6qOjRlrqpKdWmuqlq2ba6qaexgqqrKLSSqqtpuKKqq6q8sqqr64CC+usxNZa7K3H5prsrsv22uyvzwYb7bDGVoustcpiy6y2znILrbfSgkvtteRmW+6253ab7rfrhtvuuObGi6686tLLrr3u4gvvvPzW2++9/+Yb8L7+FgywwQIjTPDBDCfc8MIORwzxxIJqWvETqxcLm/G0G4vb8bsfgyPyyNQEAgA7);
-}
-.ncboTree .doc-last {
- background: 0 -1px no-repeat #fff url(data:image/gif;base64,R0lGODlhEgAWAOYAANvt/3V4o+Hw/+n1/4CAgOvr67e3t7a2ttHp/8nk/4ep3HSAsu32//v7++/v7/j7/8HBweTk5Njr/8Df/8Ph//39/fP5//7//5S/8pCjy4GVw1Wn7brd/2lwooqo2dvn98bGxn2Jtv7+/n+OvISbynJ8rvT09fn5+c7T//f39+Tx/8DA/5G46mdtnm13qM7n/296rHN+sJK872Vqmtjl9s3m/2t0pfX6/3qDsIeh0oyu3/z9/15hkI+z5fb6/9nh7ZOq0v///////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAEIALAAAAAASABYAAAcpgEKCg4SFhoQEh4qLjEKJjZCNj5GUhpOVmI6aiZyZnp+goaKjpKWmg4EAOw==);
-}
-.ncboTree .doc a.active {
- padding-left: 4px;
- margin-left: -4px;
-}
-.ncboTree .ajax {
- background: no-repeat 0 0 #ffffff url(data:image/gif;base64,R0lGODlhEAAQAMQAAP///+7u7t3d3bu7u6qqqpmZmYiIiHd3d2ZmZlVVVURERDMzMyIiIhEREQARAAAAAP///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH/C05FVFNDQVBFMi4wAwEAAAAh+QQFBwAQACwAAAAAEAAQAAAFdyAkQgGJJOWoQgIjBM8jkKsoPEzgyMGsCjPDw7ADpkQBxRDmSCRetpRA6Rj4kFBkgLC4IlUGhbNQIwXOYYWCXDufzYPDMaoKGBoKb886OjAKdgZAAgQkfCwzAgsDBAUCgl8jAQkHEAVkAoA1AgczlyIDczUDA2UhACH5BAUHABAALAAAAAAPABAAAAVjICSO0IGIATkqIiMKDaGKC8Q49jPMYsE0hQdrlABCGgvT45FKiRKQhWA0mPKGPAgBcTjsspBCAoH4gl+FmXNEUEBVAYHToJAVZK/XWoQQDAgBZioHaX8igigFKYYQVlkCjiMhACH5BAUHABAALAAAAAAQAA8AAAVgICSOUGGQqIiIChMESyo6CdQGdRqUENESI8FAdFgAFwqDISYwPB4CVSMnEhSej+FogNhtHyfRQFmIol5owmEta/fcKITB6y4choMBmk7yGgSAEAJ8JAVDgQFmKUCCZnwhACH5BAUHABAALAAAAAAQABAAAAViICSOYkGe4hFAiSImAwotB+si6Co2QxvjAYHIgBAqDoWCK2Bq6A40iA4yYMggNZKwGFgVCAQZotFwwJIF4QnxaC9IsZNgLtAJDKbraJCGzPVSIgEDXVNXA0JdgH6ChoCKKCEAIfkEBQcAEAAsAAAAABAADgAABUkgJI7QcZComIjPw6bs2kINLB5uW9Bo0gyQx8LkKgVHiccKVdyRlqjFSAApOKOtR810StVeU9RAmLqOxi0qRG3LptikAVQEh4UAACH5BAUHABAALAAAAAAQABAAAAVxICSO0DCQKBQQonGIh5AGB2sYkMHIqYAIN0EDRxoQZIaC6bAoMRSiwMAwCIwCggRkwRMJWKSAomBVCc5lUiGRUBjO6FSBwWggwijBooDCdiFfIlBRAlYBZQ0PWRANaSkED1oQYHgjDA8nM3kPfCmejiEAIfkEBQcAEAAsAAAAABAAEAAABWAgJI6QIJCoOIhFwabsSbiFAotGMEMKgZoB3cBUQIgURpFgmEI0EqjACYXwiYJBGAGBgGIDWsVicbiNEgSsGbKCIMCwA4IBCRgXt8bDACkvYQF6U1OADg8mDlaACQtwJCEAIfkEBQcAEAAsAAABABAADwAABV4gJEKCOAwiMa4Q2qIDwq4wiriBmItCCREHUsIwCgh2q8MiyEKODK7ZbHCoqqSjWGKI1d2kRp+RAWGyHg+DQUEmKliGx4HBKECIMwG61AgssAQPKA19EAxRKz4QCVIhACH5BAUHABAALAAAAAAQABAAAAVjICSOUBCQqHhCgiAOKyqcLVvEZOC2geGiK5NpQBAZCilgAYFMogo/J0lgqEpHgoO2+GIMUL6p4vFojhQNg8rxWLgYBQJCASkwEKLC17hYFJtRIwwBfRAJDk4ObwsidEkrWkkhACH5BAUHABAALAAAAQAQAA8AAAVcICSOUGAGAqmKpjis6vmuqSrUxQyPhDEEtpUOgmgYETCCcrB4OBWwQsGHEhQatVFhB/mNAojFVsQgBhgKpSHRTRxEhGwhoRg0CCXYAkKHHPZCZRAKUERZMAYGMCEAIfkEBQcAEAAsAAABABAADwAABV0gJI4kFJToGAilwKLCST6PUcrB8A70844CXenwILRkIoYyBRk4BQlHo3FIOQmvAEGBMpYSop/IgPBCFpCqIuEsIESHgkgoJxwQAjSzwb1DClwwgQhgAVVMIgVyKCEAIfkECQcAEAAsAAAAABAAEAAABWQgJI5kSQ6NYK7Dw6xr8hCw+ELC85hCIAq3Am0U6JUKjkHJNzIsFAqDqShQHRhY6bKqgvgGCZOSFDhAUiWCYQwJSxGHKqGAE/5EqIHBjOgyRQELCBB7EAQHfySDhGYQdDWGQyUhADs=);
- height: 16px;
- display:none;
-}
-.ncboTree .ajax li {
- display:none;
- margin:0;
- padding:0;
-}
-.ncboTree .trigger {
- display:inline;
- margin-left:-28px;
- width: 28px;
- height: 11px;
- cursor:pointer;
-}
-.ncboTree .text {
- cursor: default;
-}
-.ncboTree .active {
- cursor: default;
- background-color: #B9D5E4;
- font-weight: bold;
- padding-top: 1px;
- padding-right: 4px;
- padding-bottom: 1px;
- padding-left: 0px;
- line-height: 16px;
-}
-.ncboTree a, .ncboTree a:hover {
- text-decoration: none;
- color: black;
- font-size: 11pt;
-}
-.ncboTree a:hover {
- cursor: pointer;
-}
-
-/*
- * jQuery UI CSS Framework 1.8.7
- *
- * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT or GPL Version 2 licenses.
- * http://jquery.org/license
- *
- * http://docs.jquery.com/UI/Theming/API
- */
-
-/* Layout helpers
-----------------------------------*/
-.ncboAutocomplete .ui-front { z-index: 100; }
-.ncboAutocomplete .ui-helper-hidden { display: none; }
-.ncboAutocomplete .ui-helper-hidden-accessible { position: absolute !important; clip: rect(1px 1px 1px 1px); clip: rect(1px,1px,1px,1px); }
-.ncboAutocomplete .ui-helper-reset { margin: 0; padding: 0; border: 0; outline: 0; line-height: 1.3; text-decoration: none; font-size: 100%; list-style: none; }
-.ncboAutocomplete .ui-helper-clearfix:after { content: "."; display: block; height: 0; clear: both; visibility: hidden; }
-.ncboAutocomplete .ui-helper-clearfix { display: inline-block; }
-/* required comment for clearfix to work in Opera \*/
-* html .ncboAutocomplete .ui-helper-clearfix { height:1%; }
-.ncboAutocomplete .ui-helper-clearfix { display:block; }
-/* end clearfix */
-.ncboAutocomplete .ui-helper-zfix { width: 100%; height: 100%; top: 0; left: 0; position: absolute; opacity: 0; filter:Alpha(Opacity=0); }
-
-
-/* Interaction Cues
-----------------------------------*/
-.ncboAutocomplete .ui-state-disabled { cursor: default !important; }
-
-
-/* Icons
-----------------------------------*/
-
-/* states and images */
-.ncboAutocomplete .ui-icon { display: block; text-indent: -99999px; overflow: hidden; background-repeat: no-repeat; }
-
-
-/* Misc visuals
-----------------------------------*/
-
-/* Overlays */
-.ncboAutocomplete .ui-widget-overlay { position: fixed; top: 0; left: 0; width: 100%; height: 100%; }
-
-.jsonSuggest a {
- font-size: .8em;
-}
-
-.jsonSuggest a:hover {
- cursor: pointer;
- font-size: .8em;
-}
-
-/*
- * jQuery UI CSS Framework 1.8.7
- *
- * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT or GPL Version 2 licenses.
- * http://jquery.org/license
- *
- * http://docs.jquery.com/UI/Theming/API
- *
- * To view and modify this theme, visit http://jqueryui.com/themeroller/?ctl=themeroller
- */
-
-
-/* Component containers
-----------------------------------*/
-.ncboAutocomplete .ui-widget { font-family: Arial,sans-serif; font-size: 1em; }
-.ncboAutocomplete .ui-widget .ui-widget { font-size: 1em; }
-.ncboAutocomplete .ui-widget input, .ui-widget select, .ui-widget textarea, .ui-widget button { font-family: Arial,sans-serif; font-size: 1em; }
-.ncboAutocomplete .ui-widget-content { border: 1px solid #B6B6B6; background: #ffffff; color: #4F4F4F; }
-.ncboAutocomplete .ui-widget-content a { color: #4F4F4F; }
-.ncboAutocomplete .ui-widget-header { border: 1px solid #B6B6B6; color: #4F4F4F; font-weight: bold; }
-.ncboAutocomplete .ui-widget-header {
- background: #ededed 0 0 repeat-x; /* Old browsers */
- background: -moz-linear-gradient(to bottom, #ededed 0%, #c4c4c4 100%); /* FF3.6+ */
- background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#ededed), color-stop(100%,#c4c4c4)); /* Chrome,Safari4+ */
- background: -webkit-linear-gradient(to bottom, #ededed 0%,#c4c4c4 100%); /* Chrome10+,Safari5.1+ */
- background: -o-linear-gradient(to bottom, #ededed 0%,#c4c4c4 100%); /* Opera11.10+ */
- background: -ms-linear-gradient(to bottom, #ededed 0%,#c4c4c4 100%); /* IE10+ */
- background: linear-gradient(to bottom, #ededed 0%,#c4c4c4 100%); /* W3C */
-}
-.ncboAutocomplete .ui-widget-header a { color: #4F4F4F; }
-
-/* Interaction states
-----------------------------------*/
-.ncboAutocomplete .ui-state-default, .ui-widget-content .ui-state-default, .ui-widget-header .ui-state-default { border: 1px solid #B6B6B6; font-weight: normal; color: #4F4F4F; }
-.ncboAutocomplete .ui-state-default, .ui-widget-content .ui-state-default, .ui-widget-header .ui-state-default {
- background: #ededed 0 0 repeat-x; /* Old browsers */
- background: -moz-linear-gradient(to bottom, #ededed 0%, #c4c4c4 100%); /* FF3.6+ */
- background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#ededed), color-stop(100%,#c4c4c4)); /* Chrome,Safari4+ */
- background: -webkit-linear-gradient(to bottom, #ededed 0%,#c4c4c4 100%); /* Chrome10+,Safari5.1+ */
- background: -o-linear-gradient(to bottom, #ededed 0%,#c4c4c4 100%); /* Opera11.10+ */
- background: -ms-linear-gradient(to bottom, #ededed 0%,#c4c4c4 100%); /* IE10+ */
- background: linear-gradient(to bottom, #ededed 0%,#c4c4c4 100%); /* W3C */
- -webkit-box-shadow: 0 1px 0 rgba(255,255,255,0.6) inset;
- -moz-box-shadow: 0 1px 0 rgba(255,255,255,0.6) inset;
- box-shadow: 0 1px 0 rgba(255,255,255,0.6) inset;
-}
-.ncboAutocomplete .ui-state-default a, .ui-state-default a:link, .ui-state-default a:visited { color: #4F4F4F; text-decoration: none; }
-.ncboAutocomplete .ui-state-hover, .ui-widget-content .ui-state-hover, .ui-widget-header .ui-state-hover, .ui-state-focus, .ui-widget-content .ui-state-focus, .ui-widget-header .ui-state-focus { border: 1px solid #9D9D9D; font-weight: normal; color: #313131; }
-.ncboAutocomplete .ui-state-hover a, .ui-state-hover a:hover { color: #313131; text-decoration: none; }
-.ncboAutocomplete .ui-state-active, .ui-widget-content .ui-state-active, .ui-widget-header .ui-state-active {
- outline: none;
- color: #1c4257; border: 1px solid #7096ab;
- background: #ededed 0 -50px repeat-x; /* Old browsers */
- background: -moz-linear-gradient(to bottom, #b9e0f5 0%, #92bdd6 100%); /* FF3.6+ */
- background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#b9e0f5), color-stop(100%,#92bdd6)); /* Chrome,Safari4+ */
- background: -webkit-linear-gradient(to bottom, #b9e0f5 0%,#92bdd6 100%); /* Chrome10+,Safari5.1+ */
- background: -o-linear-gradient(to bottom, #b9e0f5 0%,#92bdd6 100%); /* Opera11.10+ */
- background: -ms-linear-gradient(to bottom, #b9e0f5 0%,#92bdd6 100%); /* IE10+ */
- background: linear-gradient(to bottom, #b9e0f5 0%,#92bdd6 100%); /* W3C */
- -webkit-box-shadow: none;
- -moz-box-shadow: none;
- box-shadow: none;
-}
-.ncboAutocomplete .ui-state-active a, .ui-state-active a:link, .ui-state-active a:visited { color: #313131; text-decoration: none; }
-.ncboAutocomplete .ui-widget :active { outline: none; }
-
-/* Icons
-----------------------------------*/
-
-/* Misc visuals
-----------------------------------*/
-
-/*
- * jQuery UI Autocomplete 1.8.7
- *
- * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT or GPL Version 2 licenses.
- * http://jquery.org/license
- *
- * http://docs.jquery.com/UI/Autocomplete#theming
- */
-.ncboAutocomplete .ui-autocomplete {
- position: absolute; cursor: default; z-index: 3;
- -moz-border-radius: 0;
- -webkit-border-radius: 0;
- border-radius: 0;
- -moz-box-shadow: 0 1px 5px rgba(0,0,0,0.3);
- -webkit-box-shadow: 0 1px 5px rgba(0,0,0,0.3);
- box-shadow: 0 1px 5px rgba(0,0,0,0.3);
-}
-
-/* workarounds */
-* html .ncboAutocomplete .ui-autocomplete { width:1px; } /* without this, the menu expands to 100% in IE6 */
-
-/*
- * jQuery UI Menu 1.8.7
- *
- * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT or GPL Version 2 licenses.
- * http://jquery.org/license
- *
- * http://docs.jquery.com/UI/Menu#theming
- */
-.ncboAutocomplete .ui-menu {
- list-style:none;
- padding: 2px;
- margin: 0;
- display:block;
- float: left;
-}
-.ncboAutocomplete .ui-menu .ui-menu {
- margin-top: -3px;
-}
-.ncboAutocomplete .ui-menu .ui-menu-item {
- margin:0;
- padding: 0;
- zoom: 1;
- float: left;
- clear: left;
- width: 100%;
-}
-.ncboAutocomplete .ui-menu .ui-menu-item a {
- text-decoration:none;
- display:block;
- padding:.2em .4em;
- line-height:1.5;
- zoom:1;
-}
-.ncboAutocomplete .ui-menu .ui-menu-item a.ui-state-focus,
-.ncboAutocomplete .ui-menu .ui-menu-item a.ui-state-hover,
-.ncboAutocomplete .ui-menu .ui-menu-item a.ui-state-active {
- font-weight: normal;
- margin: -1px;
- background: #5f83b9;
- color: #FFFFFF;
- text-shadow: 0px 1px 1px #234386;
- border-color: #466086;
- -moz-border-radius: 0;
- -webkit-border-radius: 0;
- border-radius: 0;
-}
diff --git a/app/assets/stylesheets/upload_ontology.scss b/app/assets/stylesheets/upload_ontology.scss
new file mode 100644
index 000000000..aecdcd960
--- /dev/null
+++ b/app/assets/stylesheets/upload_ontology.scss
@@ -0,0 +1,98 @@
+.upload-ontology-container {
+ display: flex;
+ justify-content: center;
+ padding: 40px 0;
+ .show {
+ display: block;
+ }
+}
+
+.upload-ontology-card {
+ width: 589px;
+ border-radius: 14px;
+ box-shadow: rgba(0, 0, 0, 0.05) 0px 20px 50px;
+ padding: 20px 40px;
+
+}
+
+.upload-ontology-center {
+ display: flex;
+ justify-content: center;
+ flex-direction: column;
+}
+
+.upload-ontology-progress {
+ display: flex;
+ align-items: center;
+ margin-top: 20px;
+ margin-bottom: 50px;
+}
+
+
+.upload-ontology-chips-container{
+ display: flex;
+ flex-wrap: wrap;
+}
+
+
+.hide {
+ display: none;
+}
+
+
+
+.upload-ontology-desc {
+ font-size: 12px;
+ color: #777777;
+ margin-bottom: 23px;
+}
+
+.upload-ontology-desc a {
+ text-decoration: none;
+ color: var(--primary-color);
+}
+.upload-ontology-desc a svg{
+ transform: scale(1.2);
+}
+
+
+.upload-ontology-contact .add-another-contact div {
+ font-size: 11px;
+ color: #DADADA;
+ margin-left: 10px;
+
+}
+
+.upload-ontology-field-container .location-choice{
+ display: flex;
+ align-items: center;
+ margin-bottom: 3px;
+}
+
+.upload-ontology-field-container .location-choice .title{
+ font-size: 13px;
+ color: black;
+ margin-left: 13px;
+ margin-bottom: 0;
+ cursor: pointer;
+}
+
+.upload-ontology-field-container > div{
+ font-size: 12px;
+ color: #666666;
+}
+
+
+.upload-ontology-input-field-container{
+ margin-bottom: 10px;
+}
+
+.upload-ontology-input-field-container .switch-filter p{
+ font-size: 12px !important;
+}
+.edit-ontology-tab .switch-filter {
+ img{
+ width: 15px;
+ height: 15px;
+ }
+}
\ No newline at end of file
diff --git a/app/controllers/admin/categories_controller.rb b/app/controllers/admin/categories_controller.rb
index 2af3f9143..ffe23c076 100644
--- a/app/controllers/admin/categories_controller.rb
+++ b/app/controllers/admin/categories_controller.rb
@@ -1,14 +1,16 @@
class Admin::CategoriesController < ApplicationController
+ include SubmissionUpdater, TurboHelper
+
layout :determine_layout
before_action :unescape_id, only: [:edit, :show, :update, :destroy]
before_action :authorize_admin
CATEGORIES_URL = "#{LinkedData::Client.settings.rest_url}/categories"
+ ATTRIBUTE_TO_INCLUDE = 'name,acronym,created,description,parentCategory,ontologies'
def index
- response = _categories
- render :json => response
+ @categories = _categories
end
def new
@@ -20,15 +22,16 @@ def new
end
def edit
- @category = LinkedData::Client::Models::Category.find_by_acronym(params[:id]).first
-
+ @category = _category
+ @acronyms = @category.ontologies.map { |url| url.match(/\/([^\/]+)$/)[1] }
+ @ontologies_category = LinkedData::Client::Models::Ontology.all(include: 'acronym').map {|o|[o.acronym, o.id] }
respond_to do |format|
format.html { render "edit", :layout => false }
end
end
def create
- response = { errors: '', success: '' }
+ response = { errors: nil, success: '' }
start = Time.now
begin
category = LinkedData::Client::Models::Category.new(values: category_params)
@@ -36,52 +39,83 @@ def create
if response_error?(category_saved)
response[:errors] = response_errors(category_saved)
else
- response[:success] = "category successfully created in #{Time.now - start}s"
+ response[:success] = t('admin.categories.category_created', time: Time.now - start)
end
rescue Exception => e
- response[:errors] = "Problem creating the category - #{e.message}"
+ response[:errors] = t('admin.categories.category_error_creation', message: e.message)
+ end
+
+ if response[:errors]
+ render_turbo_stream alert_error(id: 'category') { response[:errors] }
+ else
+ success_message = t('admin.categories.category_added_successfully')
+ streams = [alert_success(id: 'category') { success_message }]
+
+ streams << prepend('admin_categories_table_body', partial: 'admin/categories/category', locals: { category: category_saved })
+
+ render_turbo_stream(*streams)
end
- render json: response, status: (response[:errors] == '' ? :created : :internal_server_error)
end
def update
- response = { errors: '', success: ''}
+ response = { errors: nil, success: ''}
start = Time.now
begin
- category = LinkedData::Client::Models::Category.find_by_acronym(params[:id]).first
+ category = _category
+ add_ontologies_to_object(category_params[:ontologies],category) if (category_params[:ontologies].present? && category_params[:ontologies].size > 0 && category_params[:ontologies].first != '')
+ delete_ontologies_from_object(category_params[:ontologies], category.ontologies,category)
category.update_from_params(category_params)
- category_update = category.update
-
- if response_error?(category_update)
- response[:errors] = response_errors(category_update)
+ category.ontologies = Array(category_params[:ontologies])
+ category_updated = category.update
+ if response_error?(category_updated)
+ response[:errors] = response_errors(category_updated)
else
- response[:success] = "category successfully updated in #{Time.now - start}s"
+ response[:success] = t('admin.categories.category_updated_successfully', time: Time.now - start)
end
rescue Exception => e
- response[:errors] = "Problem updating the category - #{e.message}"
+ response[:errors] = t('admin.categories.problem_of_updating', message: e.message)
end
- render json: response, status: (response[:errors] == '' ? :ok : :internal_server_error)
+
+ if response[:errors]
+ render_turbo_stream(alert_error(id: 'category') { response[:errors] })
+ else
+ streams = [alert_success(id: 'category') { response[:success] },
+ replace(category.id.split('/').last, partial: 'admin/categories/category', locals: { category: category })
+ ]
+ render_turbo_stream(*streams)
+ end
+
end
def destroy
- response = { errors: '', success: ''}
+ response = { errors: nil, success: ''}
start = Time.now
begin
- category = LinkedData::Client::Models::Category.find_by_acronym(params[:id]).first
+ category = _category
error_response = category.delete
if response_error?(error_response)
response[:errors] = response_errors(error_response)
else
- response[:success] = "category successfully deleted in #{Time.now - start}s"
+ response[:success] = t('admin.categories.category_deleted_successfully', time: Time.now - start)
end
rescue Exception => e
- response[:errors] = "Problem deleting the category - #{e.message}"
+ response[:errors] = t('admin.categories.problem_of_deleting', message: e.message)
+ end
+ respond_to do |format|
+ format.turbo_stream do
+ if response[:errors]
+ render_turbo_stream alert(type: 'danger') { response[:errors].to_s }
+ else
+ render turbo_stream: [
+ alert(type: 'success') { response[:success] },
+ turbo_stream.remove(params[:id])
+ ]
+ end
+ end
end
- render json: response, status: (response[:errors] == '' ? :ok : :internal_server_error)
end
-
private
def unescape_id
@@ -89,20 +123,14 @@ def unescape_id
end
def category_params
- params.require(:category).permit(:acronym, :name, :description, :parentCategory).to_h
+ params.require(:category).permit(:acronym, :name, :description, :parentCategory, {ontologies:[]}).to_h
end
def _categories
- response = { categories: Hash.new, errors: '', success: '' }
- start = Time.now
- begin
- response[:categories] = JSON.parse(LinkedData::Client::HTTP.get(CATEGORIES_URL, { include: 'all' }, raw: true))
+ LinkedData::Client::HTTP.get(CATEGORIES_URL, { include: ATTRIBUTE_TO_INCLUDE })
+ end
- response[:success] = "categories successfully retrieved in #{Time.now - start}s"
- LOG.add :debug, "Categories - retrieved #{response[:categories].length} groups in #{Time.now - start}s"
- rescue Exception => e
- response[:errors] = "Problem retrieving categories - #{e.message}"
- end
- response
+ def _category(id = params[:id])
+ LinkedData::Client::HTTP.get(CATEGORIES_URL+ "/#{id.split('/').last}", { include: ATTRIBUTE_TO_INCLUDE })
end
end
diff --git a/app/controllers/admin/groups_controller.rb b/app/controllers/admin/groups_controller.rb
index 842982957..3fdbd5ef3 100644
--- a/app/controllers/admin/groups_controller.rb
+++ b/app/controllers/admin/groups_controller.rb
@@ -1,14 +1,16 @@
class Admin::GroupsController < ApplicationController
+ include SubmissionUpdater, TurboHelper, AdminHelper
layout :determine_layout
before_action :unescape_id, only: [:edit, :show, :update, :destroy]
before_action :authorize_admin
GROUPS_URL = "#{LinkedData::Client.settings.rest_url}/groups"
+ GROUPS_SYNCHRONIZE_URL = "#{LinkedData::Client.settings.rest_url}/slices/synchronize_groups"
+
def index
- response = _groups
- render :json => response
+ @groups = _groups
end
def new
@@ -21,14 +23,15 @@ def new
def edit
@group = LinkedData::Client::Models::Group.find_by_acronym(params[:id]).first
-
+ @acronyms = @group&.ontologies&.map { |url| url.match(/\/([^\/]+)$/)[1] }
+ @ontologies_group = LinkedData::Client::Models::Ontology.all(include: 'acronym').map {|o|[o.acronym, o.id] }
respond_to do |format|
format.html { render "edit", :layout => false }
end
end
def create
- response = { errors: '', success: '' }
+ response = { errors: nil, success: '' }
start = Time.now
begin
group = LinkedData::Client::Models::Group.new(values: group_params)
@@ -36,35 +39,58 @@ def create
if response_error?(group_saved)
response[:errors] = response_errors(group_saved)
else
- response[:success] = "group successfully created in #{Time.now - start}s"
+ response[:success] = t('admin.groups.group_created', time: Time.now - start)
end
rescue Exception => e
- response[:errors] = "Problem creating the group - #{e.message}"
+ response[:errors] = t('admin.groups.group_error_creation', message: e.message)
+ end
+
+ if response[:errors]
+ render_turbo_stream alert_error(id: 'group') { response[:errors] }
+ else
+ success_message = t('admin.groups.group_added_successfully')
+ streams = [alert_success(id: 'group') { success_message }]
+
+ streams << prepend('admin_groups_table_body', partial: 'admin/groups/group', locals: { group: group_saved })
+
+ render_turbo_stream(*streams)
end
- render json: response, status: (response[:errors] == '' ? :created : :internal_server_error)
end
def update
- response = { errors: '', success: ''}
+ response = { errors: nil, success: ''}
start = Time.now
begin
group = LinkedData::Client::Models::Group.find_by_acronym(params[:id]).first
+ add_ontologies_to_object(group_params[:ontologies],group) if (group_params[:ontologies].present? && group_params[:ontologies].size > 0 && group_params[:ontologies].first != '')
+ delete_ontologies_from_object(group_params[:ontologies],group.ontologies,group)
group.update_from_params(group_params)
+ group.ontologies = Array(group_params[:ontologies])
group_updated = group.update
if response_error?(group_updated)
response[:errors] = response_errors(group_updated)
else
- response[:success] = "group successfully updated in #{Time.now - start}s"
+ response[:success] = t('admin.groups.group_updated_successfully', time: Time.now - start)
end
rescue Exception => e
- response[:errors] = "Problem updating the group - #{e.message}"
+ response[:errors] = t('admin.groups.problem_of_updating', message: e.message)
+ end
+
+ if response[:errors]
+ render_turbo_stream(alert_error(id: 'group') { response[:errors] })
+ else
+
+ streams = [alert_success(id: 'group') { response[:success] },
+ replace(group.id.split('/').last, partial: 'admin/groups/group', locals: { group: group })
+ ]
+ render_turbo_stream(*streams)
end
- render json: response, status: (response[:errors] == '' ? :ok : :internal_server_error)
+
end
def destroy
- response = { errors: '', success: ''}
+ response = { errors: nil, success: ''}
start = Time.now
begin
group = LinkedData::Client::Models::Group.find_by_acronym(params[:id]).first
@@ -73,14 +99,56 @@ def destroy
if response_error?(error_response)
response[:errors] = response_errors(error_response)
else
- response[:success] = "group successfully deleted in #{Time.now - start}s"
+ response[:success] = t('admin.groups.group_deleted_successfully', time: Time.now - start)
end
rescue Exception => e
- response[:errors] = "Problem deleting the group - #{e.message}"
+ response[:errors] = t('admin.groups.problem_of_deleting', message: e.message)
+ end
+ respond_to do |format|
+ format.turbo_stream do
+ if response[:errors]
+ render_turbo_stream alert(type: 'danger') { response[:errors].to_s }
+ else
+ render turbo_stream: [
+ alert(type: 'success') { response[:success] },
+ turbo_stream.remove(params[:id])
+ ]
+ end
+ end
end
- render json: response, status: (response[:errors] == '' ? :ok : :internal_server_error)
end
+ def synchronize_groups
+ response = {}
+
+ begin
+ response_raw = LinkedData::Client::HTTP.get(GROUPS_SYNCHRONIZE_URL, params, raw: true)
+
+ response_json = JSON.parse(response_raw, symbolize_names: true)
+
+ if !response_json.is_a?(Array) && response_json[:errors]
+ _process_errors(response_json[:errors], response, true)
+ else
+ response[:success] = t('admin.groups.synchronization_of_groups')
+ end
+ rescue JSON::ParserError => e
+ response[:errors] = t('admin.groups.error_parsing', class: e.class, message: e.message)
+ rescue Exception => e
+ response[:errors] = t('admin.groups.problem_synchronizing_groups', class: e.class, message: e.message)
+ end
+
+ respond_to do |format|
+ format.turbo_stream do
+ if response[:errors]
+ render_turbo_stream alert(type: 'danger') { response[:errors].to_s }
+ else
+ render_turbo_stream alert(type: 'success') { response[:success] }
+ end
+ end
+ end
+ end
+
+
private
def unescape_id
@@ -88,20 +156,10 @@ def unescape_id
end
def group_params
- params.require(:group).permit(:acronym, :name, :description).to_h()
+ params.require(:group).permit(:acronym, :name, :description, {ontologies:[]}).to_h()
end
def _groups
- response = { groups: Hash.new, errors: '', success: '' }
- start = Time.now
- begin
- response[:groups] = JSON.parse(LinkedData::Client::HTTP.get(GROUPS_URL, { include: 'all' }, raw: true))
-
- response[:success] = "groups successfully retrieved in #{Time.now - start}s"
- LOG.add :debug, "Groups - retrieved #{response[:groups].length} groups in #{Time.now - start}s"
- rescue Exception => e
- response[:errors] = "Problem retrieving groups - #{e.message}"
- end
- response
+ LinkedData::Client::HTTP.get(GROUPS_URL, { include: 'all' })
end
end
diff --git a/app/controllers/admin/search_controller.rb b/app/controllers/admin/search_controller.rb
new file mode 100644
index 000000000..7f87d9263
--- /dev/null
+++ b/app/controllers/admin/search_controller.rb
@@ -0,0 +1,89 @@
+class Admin::SearchController < ApplicationController
+ include TurboHelper
+ layout :determine_layout
+ before_action :authorize_admin
+
+ SEARCH_URL = "#{LinkedData::Client.settings.rest_url}/admin/search"
+
+ def index
+ json = LinkedData::Client::HTTP.get("#{SEARCH_URL}/collections")
+ @collections = json.collections
+ end
+
+ def index_batch
+ response = {}
+ model = params[:model_name]
+
+ if model.blank?
+ render_turbo_stream(alert(type: 'danger') { 'No model selected' })
+ return
+ end
+
+ begin
+ response[:success] = LinkedData::Client::HTTP.post("#{SEARCH_URL}/index_batch/#{model}", {})
+ rescue StandardError => e
+ response[:errors] = e
+ end
+
+ respond_to do |format|
+ format.turbo_stream do
+ if response[:errors]
+ render_turbo_stream alert(type: 'danger') { response[:errors].to_s }
+ else
+ render_turbo_stream alert(type: 'success') { response[:success] }
+ end
+ end
+ end
+ end
+
+ def init_schema
+ response = {}
+ collection = params[:collection]
+
+ if collection.blank?
+ render_turbo_stream(alert(type: 'danger') { 'No collection selected' })
+ return
+ end
+
+ begin
+ response[:success] = LinkedData::Client::HTTP.post("#{SEARCH_URL}/collections/#{collection}/schema/init", {})
+ rescue StandardError => e
+ response[:errors] = e
+ end
+
+ respond_to do |format|
+ format.turbo_stream do
+ if response[:errors]
+ render_turbo_stream alert(type: 'danger') { response[:errors].to_s }
+ else
+ render_turbo_stream alert(type: 'success') { "Collection #{collection} schema initialized" }
+ end
+ end
+ end
+ end
+
+ def show
+ json = LinkedData::Client::HTTP.get("#{SEARCH_URL}/collections/#{params[:collection]}/schema", {}, raw: true)
+ @collection = JSON.parse(json.to_s)
+
+ @fields = @collection["fields"] + @collection["dynamicFields"] + @collection["copyFields"]
+ render 'show', layout: false
+ end
+
+ def search
+ query = params[:query] || '*'
+ page = (params[:page] || 1).to_i
+ page_size = (params[:page_size] || 10).to_i
+ start = (page - 1) * page_size
+
+ json = LinkedData::Client::HTTP.post("#{SEARCH_URL}/collections/#{params[:collection]}/search",
+ { q: query, start: start, rows: page_size },
+ raw: true)
+ response = JSON.parse(json.to_s)
+ @count = response["response"]["numFound"]
+ @docs = response["response"]["docs"]
+
+ render 'search', layout: false
+ end
+
+end
diff --git a/app/controllers/admin_controller.rb b/app/controllers/admin_controller.rb
index fbd34766a..550fcc752 100644
--- a/app/controllers/admin_controller.rb
+++ b/app/controllers/admin_controller.rb
@@ -1,9 +1,8 @@
class AdminController < ApplicationController
- include TurboHelper
+ include TurboHelper, HomeHelper, SparqlHelper
layout :determine_layout
before_action :cache_setup
-
ADMIN_URL = "#{LinkedData::Client.settings.rest_url}/admin/"
ONTOLOGIES_URL = "#{ADMIN_URL}ontologies_report"
USERS_URL = "#{LinkedData::Client.settings.rest_url}/users"
@@ -13,9 +12,35 @@ class AdminController < ApplicationController
ONTOLOGIES_LIST_URL = "#{LinkedData::Client.settings.rest_url}/ontologies/"
include DoiRequestAdministration
+ def sparql_endpoint
+ graph = params["named-graph-uri"]
+ apikey = params["apikey"]
+ user_name = params["username"]
+
+ unless user_name.blank?
+ user = LinkedData::Client::Models::User.find(user_name, {include: 'all', apikey: apikey})
+ render(inline: 'Query not permitted') && return if user.nil?
+ end
+
+ render(inline: 'Query not permitted') && return if graph.blank? && !user&.admin?
+
+ unless graph.blank?
+ acronym = graph.split('/')[-3]
+ @ontology = LinkedData::Client::Models::Ontology.find_by_acronym(acronym, {apikey: apikey}).first
+ render(inline: t('admin.query_not_permitted')) && return if @ontology.nil? || @ontology.errors
+ end
+
+ response = helpers.ontology_sparql_query(params[:query], graph)
+
+ render inline: response
+ end
def index
@users = LinkedData::Client::Models::User.all
+ @ontology_visits = ontology_visits_data
+ @users_visits = user_visits_data
+ @page_visits = page_visits_data
+ @ontologies_problems_count = _ontologies_report[:ontologies]&.select{|a,v| v[:problem]}&.size || 0
if session[:user].nil? || !session[:user].admin?
redirect_to :controller => 'login', :action => 'index', :redirect => '/admin'
@@ -26,44 +51,49 @@ def index
end
end
- def update_info
- response = {update_info: Hash.new, errors: '', success: '', notices: ''}
- json = LinkedData::Client::HTTP.get("#{ADMIN_URL}update_info", params, raw: true)
- begin
- update_info = JSON.parse(json)
+ def update_check_enabled
+ enabled = LinkedData::Client::HTTP.get("#{ADMIN_URL}update_check_enabled", {}, raw: false)
- if update_info["error"]
- response[:errors] = update_info["error"]
- else
- response[:update_info] = update_info
- response[:notices] = update_info["notes"] if update_info["notes"]
- response[:success] = "Update info successfully retrieved"
+ if enabled
+ response = {update_info: Hash.new, errors: nil, success: '', notices: ''}
+ json = LinkedData::Client::HTTP.get("#{ADMIN_URL}update_info", params, raw: true)
+
+ begin
+ update_info = JSON.parse(json)
+
+ if update_info["error"]
+ response[:errors] = update_info["error"]
+ else
+ response[:update_info] = update_info
+ response[:notices] = update_info["notes"] if update_info["notes"]
+ response[:success] = t('admin.update_info_successfully')
+ end
+ rescue Exception => e
+ response[:errors] = t('admin.error_update_info', message: e.message)
end
- rescue Exception => e
- response[:errors] = "Problem retrieving update info - #{e.message}"
- end
- render :json => response
- end
- def update_check_enabled
- enabled = LinkedData::Client::HTTP.get("#{ADMIN_URL}update_check_enabled", {}, raw: false)
- render :json => enabled
- end
+ if response[:errors]
+ render_turbo_stream alert(id: 'update_check_frame', type: 'danger') { response[:errors] }
+ else
+ output = []
- def submissions
- @submissions = nil
- @acronym = params["acronym"]
- @ontology = LinkedData::Client::Models::Ontology.find_by_acronym(params["acronym"]).first
- begin
- @submissions = @ontology.explore.submissions({include: "submissionId,creationDate,released,modificationDate,submissionStatus,hasOntologyLanguage,version,diffFilePath,ontology"})
- .sort {|a,b| b.submissionId.to_i <=> a.submissionId.to_i } || []
- rescue
- @submissions = []
+ output << response[:update_info]["notes"] if response[:update_info]["update_available"]
+
+ output << t('admin.current_version', version: response[:update_info]['current_version'])
+ output << t('admin.appliance_id', id: response[:update_info]['appliance_id'])
+
+
+ render_turbo_stream *output.map{|message| alert(id: 'update_check_frame', type: 'info') {message} }
+
+
+ end
+ else
+ render_turbo_stream alert(id: 'update_check_frame', type: 'info') { 'not enabled' }
end
- render :partial => "layouts/ontology_report_submissions"
end
+
def parse_log
@acronym = params["acronym"]
@parse_log = LinkedData::Client::HTTP.get(PARSE_LOG_URL.call(params["acronym"]), {}, raw: false)
@@ -75,66 +105,104 @@ def parse_log
full_log_file_path = ontology[:logFilePath]
@log_file_path = /#{params["acronym"]}\/\d+\/[-a-zA-Z0-9_]+\.log$/.match(full_log_file_path)
else
- @parse_log = "No record exists for ontology #{params["acronym"]}"
+ @parse_log = t('admin.no_record_exists', acronym: params["acronym"])
@log_file_path = "None"
end
render action: "parse_log"
end
def clearcache
- response = {errors: '', success: ''}
+ response = {errors: nil, success: ''}
if @cache.respond_to?(:flush_all)
begin
@cache.flush_all
- response[:success] = "UI cache successfully flushed"
+ response[:success] = t('admin.cache_flush_success')
rescue Exception => e
- response[:errors] = "Problem flushing the UI cache - #{e.class}: #{e.message}"
+ response[:errors] = t('admin.cache_flush_error', class: e.class, message: e.message)
end
else
- response[:errors] = "The UI cache does not respond to the 'flush_all' command"
+ response[:errors] = t('admin.no_flush_command')
end
- render :json => response
+
+ respond_to do |format|
+ format.turbo_stream do
+ if response[:errors]
+ render_turbo_stream alert(type: 'danger') { response[:errors].to_s }
+ else
+ render_turbo_stream alert(type: 'success') { response[:success] }
+ end
+ end
+ end
+
end
def resetcache
- response = {errors: '', success: ''}
+ response = {errors: nil, success: ''}
if @cache.respond_to?(:reset)
begin
@cache.reset
- response[:success] = "UI cache connection successfully reset"
+ response[:success] = t('admin.cache_reset_success')
rescue Exception => e
- response[:errors] = "Problem resetting the UI cache connection - #{e.message}"
+ response[:errors] = t('admin.cache_reset_error', message: e.message)
end
else
- response[:errors] = "The UI cache does not respond to the 'reset' command"
+ response[:errors] = t('admin.no_reset_command')
+ end
+
+ respond_to do |format|
+ format.turbo_stream do
+ if response[:errors]
+ render_turbo_stream alert(type: 'danger') { response[:errors].to_s }
+ else
+ render_turbo_stream alert(type: 'success') { response[:success] }
+ end
+ end
end
- render :json => response
end
def clear_goo_cache
- response = {errors: '', success: ''}
+ response = {errors: nil, success: ''}
begin
response_raw = LinkedData::Client::HTTP.post("#{ADMIN_URL}clear_goo_cache", params, raw: true)
- response[:success] = "Goo cache successfully flushed"
+ response[:success] = t('admin.clear_goo_cache_success')
rescue Exception => e
- response[:errors] = "Problem flushing the Goo cache - #{e.class}: #{e.message}"
+ response[:errors] = t('admin.clear_goo_cache_error', class: e.class, message: e.message)
end
- render :json => response
+
+ respond_to do |format|
+ format.turbo_stream do
+ if response[:errors]
+ render_turbo_stream alert(type: 'danger') { response[:errors].to_s }
+ else
+ render_turbo_stream alert(type: 'success') { response[:success] }
+ end
+ end
+ end
+
end
def clear_http_cache
- response = {errors: '', success: ''}
+ response = {errors: nil, success: ''}
begin
response_raw = LinkedData::Client::HTTP.post("#{ADMIN_URL}clear_http_cache", params, raw: true)
- response[:success] = "HTTP cache successfully flushed"
+ response[:success] = t('admin.clear_http_cache_success')
rescue Exception => e
- response[:errors] = "Problem flushing the HTTP cache - #{e.class}: #{e.message}"
+ response[:errors] = t('admin.clear_http_cache_error', class: e.class, message: e.message)
+ end
+
+ respond_to do |format|
+ format.turbo_stream do
+ if response[:errors]
+ render_turbo_stream alert(type: 'danger') { response[:errors].to_s }
+ else
+ render_turbo_stream alert(type: 'success') { response[:success] }
+ end
+ end
end
- render :json => response
end
def ontologies_report
@@ -155,19 +223,20 @@ def refresh_ontologies_report
response = response_json
if params["ontologies"].nil? || params["ontologies"].empty?
- response[:success] = "Refresh of ontologies report started successfully";
+ response[:success] = t('admin.refresh_report_without_ontologies')
else
ontologies = params["ontologies"].split(",").map {|o| o.strip}
- response[:success] = "Refresh of report for ontologies: #{ontologies.join(", ")} started successfully";
+ response[:success] = t('admin.refresh_report_with_ontologies', ontologies: ontologies.join(", "))
end
end
rescue Exception => e
- response[:errors] = "Problem refreshing report - #{e.class}: #{e.message}"
+ response[:errors] = t('admin.problem_refreshing_report', class: e.class, message: e.message)
# puts "#{e.class}: #{e.message}\n#{e.backtrace.join("\n\t")}"
end
render :json => response
end
+
def process_ontologies
_process_ontologies('enqued for processing', 'processing', :_process_ontology)
end
@@ -192,16 +261,16 @@ def delete_submission
errors = response_errors(error_response)
_process_errors(errors, response, true)
else
- response[:success] << "Submission #{params["id"]} for ontology #{ont} was deleted successfully"
+ response[:success] << t('admin.submission_deleted_successfully', id: params["id"], ont: ont)
end
else
- response[:errors] << "Submission #{params["id"]} for ontology #{ont} was not found in the system"
+ response[:errors] << t('admin.submission_not_found', id: params["id"], ont: ont)
end
else
- response[:errors] << "Ontology #{ont} was not found in the system"
+ response[:errors] << t('admin.ontology_not_found', ont: ont)
end
rescue Exception => e
- response[:errors] << "Problem deleting submission #{params["id"]} for ontology #{ont} - #{e.class}: #{e.message}"
+ response[:errors] << t('admin.problem_deleting_submission', id: params["id"], ont: ont, class: e.class, message: e.message )
end
if params[:turbo_stream]
@@ -217,10 +286,6 @@ def delete_submission
end
- def users
- response = _users
- render :json => response
- end
def doi_requests_list
render json: doi_requests
@@ -254,11 +319,11 @@ def _ontologies_report
_process_errors(ontologies_data_parsed[:errors], response, true)
else
response.merge!(ontologies_data_parsed)
- response[:success] = "Report successfully regenerated on #{ontologies_data_parsed[:report_date_generated]}"
- LOG.add :debug, "Ontologies Report - retrieved #{response[:ontologies].length} ontologies in #{Time.now - start}s"
+ response[:success] = t('admin.report_successfully_regenerated', report_date_generated: ontologies_data_parsed[:report_date_generated])
+ LOG.add :debug, t('admin.ontologies_report_retrieved', ontologies: response[:ontologies].length, time: Time.now - start)
end
rescue Exception => e
- response[:errors] = "Problem retrieving ontologies report - #{e.message}"
+ response[:errors] = t('admin.problem_retrieving_ontologies', message: e.message)
end
response
end
@@ -292,7 +357,7 @@ def _process_ontologies(success_keyword, error_keyword, process_proc)
response = {errors: '', success: ''}
if params["ontologies"].nil? || params["ontologies"].empty?
- response[:errors] = "No ontologies parameter passed. Syntax: ?ontologies=ONT1,ONT2,...,ONTN"
+ response[:errors] = t('admin.no_ontologies_parameter_passed')
else
ontologies = params["ontologies"].split(",").map {|o| o.strip}
@@ -306,13 +371,13 @@ def _process_ontologies(success_keyword, error_keyword, process_proc)
errors = response_errors(error_response) # see application_controller::response_errors
_process_errors(errors, response, false)
else
- response[:success] << "Ontology #{ont} #{success_keyword} successfully, "
+ response[:success] << t('admin.ontology_process_success', ont: ont, success_keyword: success_keyword)
end
else
- response[:errors] << "Ontology #{ont} was not found in the system, "
+ response[:errors] << t('admin.ontology_not_found_system', ont: ont)
end
rescue Exception => e
- response[:errors] << "Problem #{error_keyword} ontology #{ont} - #{e.class}: #{e.message}, "
+ response[:errors] << t('admin.ontology_process_error', error_keyword: error_keyword, ont: ont, class: e.class, message: e.message)
end
end
response[:success] = response[:success][0...-2] unless response[:success].empty?
@@ -321,18 +386,85 @@ def _process_ontologies(success_keyword, error_keyword, process_proc)
render :json => response
end
- def _users
- response = {users: Hash.new , errors: '', success: ''}
- start = Time.now
+
+ def user_visits_data
begin
- response[:users] = JSON.parse(LinkedData::Client::HTTP.get(USERS_URL, {include: 'all'}, raw: true))
+ analytics = JSON.parse(LinkedData::Client::HTTP.get("#{rest_url}/data/analytics/users", {}, raw: true))
+ rescue
+ analytics = {}
+ end
+ visits_data = { visits: [], labels: [] }
- response[:success] = "users successfully retrieved in #{Time.now - start}s"
- LOG.add :debug, "Users - retrieved #{response[:users].length} users in #{Time.now - start}s"
- rescue Exception => e
- response[:errors] = "Problem retrieving users - #{e.message}"
+ return visits_data if analytics.empty?
+
+ analytics.sort.each do |year, year_data|
+ year_data.each do |month, value|
+ visits_data[:visits] << value
+ visits_data[:labels] << DateTime.parse("#{year}/#{month}").strftime("%b %Y")
+ end
end
- response
+ visits_data
end
+ def ontology_visits_data
+ begin
+ analytics = JSON.parse(LinkedData::Client::HTTP.get("#{rest_url}/data/analytics/ontologies", {}, raw: true))
+ rescue
+ analytics = {}
+ end
+ visits_data = { visits: [], labels: [] }
+ @new_ontologies_count = []
+ @ontologies_count = 0
+
+ return visits_data if analytics.empty?
+
+ aggregated_data = {}
+ analytics.each do |acronym, years_data|
+ current_year_count = 0
+ previous_year_count = 0
+ years_data.each do |year, months_data|
+ previous_year_count += current_year_count
+ current_year_count = 0
+ aggregated_data[year] ||= {}
+ months_data.each do |month, value|
+ if aggregated_data[year][month]
+ aggregated_data[year][month] += value
+ else
+ aggregated_data[year][month] = value
+ end
+ current_year_count += value
+ end
+ end
+ @ontologies_count += 1
+ if previous_year_count.zero? && current_year_count.positive?
+ @new_ontologies_count << [acronym]
+ end
+ end
+
+
+ aggregated_data.sort.each do |year, year_data|
+ year_data.each do |month, value|
+ visits_data[:visits] << value
+ visits_data[:labels] << DateTime.parse("#{year}/#{month}").strftime("%b %Y")
+ end
+ end
+ visits_data
+ end
+
+ def page_visits_data
+ begin
+ analytics = JSON.parse(LinkedData::Client::HTTP.get("#{rest_url}/data/analytics/page_visits", {}, raw: true))
+ rescue
+ analytics = {}
+ end
+ visits_data = { visits: [], labels: [] }
+
+ return visits_data if analytics.empty?
+
+ analytics.each do |path, count|
+ visits_data[:labels] << path
+ visits_data[:visits] << count
+ end
+ visits_data
+ end
end
diff --git a/app/controllers/agents_controller.rb b/app/controllers/agents_controller.rb
index 9029a989f..651c02b10 100644
--- a/app/controllers/agents_controller.rb
+++ b/app/controllers/agents_controller.rb
@@ -3,16 +3,18 @@ class AgentsController < ApplicationController
before_action :authorize_and_redirect, :only => [:edit, :update, :create, :new]
def index
- @agents = LinkedData::Client::Models::Agent.all
+ @agents = LinkedData::Client::Models::Agent.all(include: 'all')
end
def show
- @agent = LinkedData::Client::Models::Agent.find(params[:agent_id])
- not_found("Agent with id #{@agent.id}") if @agent.nil?
+ # we use :agent_id not :id
+ @agent = LinkedData::Client::Models::Agent.find(params[:agent_id].split('/').last)
+ not_found(t('agents.not_found_agent', id: params[:agent_id])) if @agent.nil?
@agent_id = params[:id] || agent_id(@agent)
- @name_prefix = params[:name_prefix] ? "#{params[:name_prefix]}[#{params[:id]}]" : ''
+ @name_prefix = params[:name_prefix]
@edit_on_modal = params[:edit_on_modal]&.eql?('true')
+ @deletable = params[:deletable]&.eql?('true')
end
def ajax_agents
@@ -37,9 +39,9 @@ def new
@agent.creator = session[:user].id
@agent.agentType = params[:type] || 'person'
@agent.name = params[:name]
- @new_agent = params[:new_agent].nil? || params[:new_agent].eql?('true')
@name_prefix = params[:name_prefix] || ''
- @show_affiliations = params[:show_affiliations]&.eql?('true')
+ @show_affiliations = params[:show_affiliations].nil? || params[:show_affiliations]&.eql?('true')
+ @deletable = params[:deletable]&.eql?('true')
end
def create
@@ -47,62 +49,116 @@ def create
parent_id = params[:parent_id]
name_prefix = params[:name_prefix]
alert_id = agent_id_alert_container_id(params[:id], parent_id)
-
+ deletable = params[:deletable]&.eql?('true')
if new_agent.errors
render_turbo_stream alert_error(id: alert_id) { JSON.pretty_generate(response_errors(new_agent)) }
else
- success_message = 'New Agent added successfully'
+ success_message = t('agents.add_agent')
streams = [alert_success(id: alert_id) { success_message }]
- streams << prepend('agents_table_content', partial: 'agents/show_line', locals: { agent: new_agent })
-
- streams << replace_agent_form(new_agent, frame_id: params[:id], parent_id: parent_id, name_prefix: name_prefix) if params[:parent_id]
+ streams << prepend('admin_agents_table_body', partial: 'agents/agent', locals: { agent: new_agent })
+ streams << replace_agent_form(new_agent, agent_id: nil, frame_id: params[:id],
+ parent_id: parent_id, name_prefix: name_prefix,
+ deletable: deletable
+ ) if params[:parent_id]
render_turbo_stream(*streams)
end
end
def edit
- @agent = LinkedData::Client::Models::Agent.find("#{REST_URI}/Agents/#{params[:id]}")
- @name_prefix = params[:parent_id] || ''
+ @agent = LinkedData::Client::Models::Agent.find(params[:id].split('/').last)
+ @name_prefix = params[:name_prefix] || ''
@show_affiliations = params[:show_affiliations].nil? || params[:show_affiliations].eql?('true')
+ @deletable = params[:deletable].to_s.eql?('true')
+ end
+
+ def show_search
+ id = params[:id]
+ parent_id = params[:parent_id]
+ name_prefix = params[:name_prefix]
+ agent_type = params[:agent_type]
+ agent_deletable = params[:deletable].to_s.eql?('true')
+
+ attribute_template_output = helpers.agent_search_input(id, agent_type,
+ parent_id: parent_id,
+ name_prefix: name_prefix,
+ deletable: agent_deletable)
+ render_turbo_stream(replace(helpers.agent_id_frame_id(id, parent_id)) { render_to_string(inline: attribute_template_output) } )
+
end
def update
agent_update, agent = update_agent(params[:id].split('/').last, agent_params)
+
parent_id = params[:parent_id]
alert_id = agent_alert_container_id(agent, parent_id)
-
+ deletable = params[:deletable]&.eql?('true')
if response_error?(agent_update)
render_turbo_stream(alert_error(id: alert_id) { JSON.pretty_generate(response_errors(agent_update)) })
else
- success_message = 'Agent successfully updated'
+ success_message = t('agents.update_agent')
table_line_id = agent_table_line_id(agent_id(agent))
-
+ agent = find_agent_display_all(agent.id.split('/').last)
streams = [alert_success(id: alert_id) { success_message },
- replace(table_line_id, partial: 'agents/show_line', locals: { agent: agent })
+ replace(table_line_id, partial: 'agents/agent', locals: { agent: agent })
]
- streams << replace_agent_form(agent, parent_id: parent_id) if params[:parent_id]
+ streams << replace_agent_form(agent, agent_id: agent_id(agent.id), name_prefix: params[:name_prefix] , parent_id: parent_id, deletable: deletable) if params[:parent_id]
+
+ render_turbo_stream(*streams)
+ end
+ end
+
+ def agent_usages
+ @agent = find_agent_display_all
+ @ontology_acronyms = LinkedData::Client::Models::Ontology.all(include: 'acronym', display_links: false, display_context: false, include_views: true).map(&:acronym)
+ not_found(t('agents.not_found_agent', id: @agent.id)) if @agent.nil?
+ render partial: 'agents/agent_usage'
+ end
+
+ def update_agent_usages
+ agent = find_agent_display_all
+ responses, new_usages = update_agent_usages_action(agent, agent_usages_params)
+ parent_id = params[:parent_id]
+ alert_id = agent_alert_container_id(agent, parent_id)
+
+
+ if responses.values.any? { |x| response_error?(x) }
+ errors = {}
+ responses.each do |ont, response|
+ errors[ont.acronym] = response_errors(response) if response_error?(response)
+ end
+
+ render_turbo_stream(alert_error(id: alert_id) { helpers.agent_usage_errors_display(errors) })
+ else
+
+ success_message = t('agents.agent_usages_updated')
+ table_line_id = agent_table_line_id(agent_id(agent))
+ agent.usages = new_usages
+ streams = [alert_success(id: alert_id) { success_message },
+ replace(table_line_id, partial: 'agents/agent', locals: { agent: agent })
+ ]
render_turbo_stream(*streams)
end
+
end
def destroy
error = nil
- @agent = LinkedData::Client::Models::Agent.find("#{REST_URI}/Agents/#{params[:id]}")
+ @agent = LinkedData::Client::Models::Agent.find(params[:id].split('/').last)
success_text = ''
if @agent.nil?
- success_text = "Agent #{params[:id]} already deleted"
+ success_text = t('agents.agent_already_deleted', id: params[:id])
else
error_response = @agent.delete
if response_error?(error_response)
error = response_errors(error_response)
else
- success_text = "Agent #{params[:id]} deleted successfully"
+ success_text = t('agents.agent_deleted_successfully', id: params[:id])
end
end
@@ -115,7 +171,7 @@ def destroy
]
else
- render alert(type: 'danger') { error }
+ render_turbo_stream alert(type: 'danger') { error }
end
end
format.html { render json: { success: success_text, error: error } }
@@ -125,12 +181,14 @@ def destroy
private
- def replace_agent_form(agent, frame_id: nil, parent_id:, partial: 'agents/agent_show', name_prefix: '')
+ def replace_agent_form(agent, agent_id: nil, frame_id: nil, parent_id:, partial: 'agents/agent_show', name_prefix: '', deletable: true)
frame_id = frame_id ? agent_id_frame_id(frame_id, parent_id) : agent_frame_id(agent, parent_id)
- replace(frame_id, partial: partial,
- locals: { agent: agent, name_prefix: name_prefix, parent_id: parent_id, edit_on_modal: false })
+ replace(frame_id, partial: partial, layout: false ,
+ locals: { agent_id: agent_id, agent: agent, name_prefix: name_prefix, parent_id: parent_id,
+ edit_on_modal: false,
+ deletable: deletable})
end
def save_agent(params)
@@ -140,7 +198,7 @@ def save_agent(params)
end
def update_agent(id = params[:id], params)
- agent = LinkedData::Client::Models::Agent.find("#{REST_URI}/Agents/#{id}")
+ agent = LinkedData::Client::Models::Agent.find(id)
params[:creator] = session[:user].id if (agent.creator.nil? || agent.creator.empty?) && (params[:creator] || '').empty?
@@ -148,6 +206,58 @@ def update_agent(id = params[:id], params)
[res, agent.update_from_params(params)]
end
+ def update_agent_usages_action(agent, params)
+ current_usages = helpers.agents_used_properties(agent)
+ new_usages = params
+
+ diffs = current_usages.keys.each_with_object({}) do |key, result|
+ removed_values = current_usages[key] - Array(new_usages[key])
+ added_values = Array(new_usages[key]) - current_usages[key]
+ result[key] = removed_values + added_values
+ end
+
+ # changed_usages = new_usages.empty? ? current_usages : new_usages.select { |x, v| !((current_usages[x] - v) + (v - current_usages[x])).empty? }
+
+
+ changed_usages = diffs.reduce({}) do |h, attr_acronyms|
+ attr, acronyms = attr_acronyms
+ acronyms.each do |acronym|
+ h[acronym] ||= []
+ h[acronym] << attr
+ end
+ h
+ end
+ responses = {}
+ changed_usages.each do |ontology, attrs|
+ ontology = LinkedData::Client::Models::Ontology.find_by_acronym(ontology).first
+ sub = ontology.explore.latest_submission({ include: attrs.join(',') })
+ values = {}
+ attrs.each do |attr|
+ current_val = sub.send(attr)
+ if current_val.is_a?(Array)
+ existent_agent = current_val.find_index { |x| x.id.eql?(agent.id) }
+ if existent_agent
+ current_val.delete_at(existent_agent)
+ else
+ current_val << agent
+ end
+ values[attr.to_sym] = current_val.map { |x| x.id }
+ else
+ values[attr.to_sym] = agent
+ end
+ end
+
+ responses[ontology] = sub.update(values: values, cache_refresh_all: false)
+ end
+
+ [responses, new_usages]
+ end
+
+ def agent_usages_params
+ p = params.permit(hasCreator: [], hasContributor: [], curatedBy: [], publisher: [], fundedBy: [], endorsedBy: [], translator: [])
+ p.to_h
+ end
+
def agent_params
p = params.permit(:agentType, :name, :email, :acronym, :homepage, :creator,
{ identifiers: [:notation, :schemaAgency, :creator] },
@@ -170,4 +280,11 @@ def agent_params
end
p
end
+
+ def find_agent_display_all(id = params[:id])
+ # TODO fix in the api client, the find with params
+ LinkedData::Client::Models::Agent.where({ display: 'all' }) do |obj|
+ obj.id.to_s.eql?("#{rest_url}/Agents/#{id}")
+ end.first
+ end
end
diff --git a/app/controllers/ajax_proxy_controller.rb b/app/controllers/ajax_proxy_controller.rb
index d608b2c02..6e89b0d08 100644
--- a/app/controllers/ajax_proxy_controller.rb
+++ b/app/controllers/ajax_proxy_controller.rb
@@ -76,9 +76,6 @@ def json_ontology
render_json simple_ontology.to_json
end
- def loading_spinner
- render :partial => "loading_spinner"
- end
private
diff --git a/app/controllers/analytics_controller.rb b/app/controllers/analytics_controller.rb
deleted file mode 100644
index ccb9af6ca..000000000
--- a/app/controllers/analytics_controller.rb
+++ /dev/null
@@ -1,66 +0,0 @@
-require 'csv'
-
-class AnalyticsController < ApplicationController
-
- def track
- entry = Analytics.new
- entry.segment = params[:segment]
- entry.action = params[:analytics_action]
- entry.bp_slice = @subdomain_filter[:active] ? @subdomain_filter[:acronym] : nil
- entry.ip = request.remote_ip
- entry.user = session[:user].nil? ? nil : session[:user].id
- entry.params = params.except(:segment, :analytics_action, :action, :controller)
- entry.save
- head :ok
- end
-
- def search_result_clicked
- clicks = Analytics.where(:segment => "search", :action => "result_clicked").all
- rows = [["query", "position_clicked", "ontology_clicked", "higher_rated_ontologies", "additional_result", "exact_match", "concept_id", "time", "user", "bp_slice", "ip_address"]]
- clicks.each do |click|
- next if click.params.empty?
- rows << [
- click.params["query"].delete("\t"),
- click.params["position"],
- click.params["ontology_clicked"],
- click.params["higher_ontologies"].nil? ? "" : click.params["higher_ontologies"].join(";"),
- click.params["additional_result"],
- click.params["exact_match"],
- click.params["concept_id"],
- click.created_at,
- click.user,
- click.bp_slice,
- click.ip
- ]
- end
- respond_with_csv_file(rows, "search_result_clicked")
- end
-
- def user_intention_surveys
- surveys = Analytics.where(:segment => "users", :action => "intention_survey").all
- rows = [["page", "response", "email", "time", "user", "bp_slice", "ip_address"]]
- surveys.each do |survey|
- rows << [
- survey.params["page"],
- survey.params["intention_response"],
- survey.params["contest_email"],
- survey.created_at,
- survey.user,
- survey.bp_slice,
- survey.ip
- ]
- end
- respond_with_csv_file(rows, "user_intention_survey")
- end
-
- private
-
- def respond_with_csv_file(rows, filename = "output")
- output = ''
- rows.each do |row|
- output << row.to_csv.force_encoding('UTF-8')
- end
- send_data output, :type => 'text/csv', :disposition => "attachment; filename=#{filename}.csv"
- end
-
-end
diff --git a/app/controllers/annotator_controller.rb b/app/controllers/annotator_controller.rb
index 0e4e53fdd..6f1ec810b 100644
--- a/app/controllers/annotator_controller.rb
+++ b/app/controllers/annotator_controller.rb
@@ -3,212 +3,211 @@
class AnnotatorController < ApplicationController
layout :determine_layout
+ include ApplicationHelper
- # REST_URI is defined in application_controller.rb
- #ANNOTATOR_URI = REST_URI + "/annotator"
ANNOTATOR_URI = $ANNOTATOR_URL
+ ANNOTATOR_PLUS_URI = $ANNOTATOR_URL+"/annotatorplus"
+ NCBO_ANNOTATOR_PLUS_URI = $NCBO_ANNOTATOR_URL
+ before_action :initialize_options, only: [:index, :annotator_plus, :ncbo_annotator_plus]
def index
- @semantic_types_for_select = []
- @semantic_groups_for_select = []
- @semantic_types ||= get_semantic_types
- @sem_type_ont = LinkedData::Client::Models::Ontology.find_by_acronym('STY').first
- @semantic_groups ||= {"ACTI" => "Activities & Behaviors", "ANAT" => "Anatomy", "CHEM" => "Chemicals & Drugs","CONC" => "Concepts & Ideas","DEVI" => "Devices", "DISO" => "Disorders", "GENE" => "Genes & Molecular Sequences", "GEOG" => "Geographic Areas", "LIVB" => "Living Beings","OBJC" => "Objects", "OCCU" => "Occupations", "ORGA" => "Organizations", "PHEN" => "Phenomena", "PHYS" => "Physiology","PROC" => "Procedures"}
- @semantic_types.each_pair do |code, label|
- @semantic_types_for_select << ["#{label} (#{code})", code]
- end
- @semantic_groups.each_pair do |group, label|
- @semantic_groups_for_select << ["#{label} (#{group})", group]
- end
- @semantic_types_for_select.sort! {|a,b| a[0] <=> b[0]}
- @semantic_groups_for_select.sort! {|a,b| a[0] <=> b[0]}
- if !$MULTIPLE_RECOGNIZERS.nil? && $MULTIPLE_RECOGNIZERS == true
- # Get recognizers from ontologies_api only if asked
- @recognizers = parse_json(REST_URI + "/annotator/recognizers")
- else
- @recognizers = []
- end
- @annotator_ontologies = LinkedData::Client::Models::Ontology.all
+ set_annotator_info('/annotator', 'Annotator', ANNOTATOR_URI)
end
+ def annotator_plus
+ set_annotator_info('/annotatorplus', 'Annotator +', ANNOTATOR_PLUS_URI)
+ render 'index'
+ end
- def create
- params[:mappings] ||= []
- params[:max_level] ||= 0
- params[:ontologies] ||= []
- params[:semantic_types] ||= []
- params[:semantic_groups] ||= []
- text_to_annotate = params[:text].strip.gsub("\r\n", " ").gsub("\n", " ")
-
- options = { :ontologies => params[:ontologies],
- :class_hierarchy_max_level => params[:class_hierarchy_max_level].to_i,
- :expand_class_hierarchy => params[:class_hierarchy_max_level].to_i > 0,
- :semantic_types => params[:semantic_types],
- :semantic_groups => params[:semantic_groups],
- :expand_mappings => params[:expand_mappings],
- :longest_only => params[:longest_only],
- :exclude_numbers => params[:exclude_numbers] ||= "false", # service default is false
- :whole_word_only => params[:whole_word_only] ||= "true", # service default is true
- :exclude_synonyms => params[:exclude_synonyms] ||= "false", # service default is false
- :fast_context => params[:fast_context] ||= "false", # service default is false
- :score => params[:score],
- :score_threshold => params[:score_threshold] ||=-1,
- :confidence_threshold => params[:confidence_threshold] ||=-1,
- :lemmatize => params[:lemmatize] ||= "false",
- :ncbo_slice => params[:ncbo_slice] || ''
- }
+ def ncbo_annotator_plus
+ params[:apikey] = $NCBO_API_KEY
+ set_annotator_info('/ncbo_annotatorplus', 'NCBO Annotator +', NCBO_ANNOTATOR_PLUS_URI)
+ render 'index'
+ end
- start = Time.now
- query = ANNOTATOR_URI
- query += "?text=" + CGI.escape(text_to_annotate)
- #query += "&apikey=" + annotator_apikey
- #query += "&include=prefLabel"
- # Include= prefLabel causes an internal error when retrieving mappings
- query += "&expand_class_hierarchy=true" if options[:class_hierarchy_max_level] > 0
- query += "&class_hierarchy_max_level=" + options[:class_hierarchy_max_level].to_s if options[:class_hierarchy_max_level] > 0
- query += "&score=" + options[:score] unless options[:score] == ""
- query += "&score_threshold=" + options[:score_threshold] unless options[:score] == "" or options[:score_threshold]==-1
- query += "&confidence_threshold=" + options[:confidence_threshold] unless options[:score] == "" or options[:confidence_threshold]==-1
- query += "&fast_context=" + options[:fast_context] unless options[:fast_context].empty?
- query += "&ontologies=" + CGI.escape(options[:ontologies].join(',')) unless options[:ontologies].empty?
- query += "&semantic_types=" + options[:semantic_types].join(',') unless options[:semantic_types].empty?
- query += "&semantic_groups=" + options[:semantic_groups].join(',') unless options[:semantic_groups].empty?
- query += "&expand_mappings=" + options[:expand_mappings].to_s unless options[:expand_mappings].empty?
- query += "&longest_only=#{options[:longest_only]}"
- query += "&recognizer=#{params[:recognizer]}"
- query += "&exclude_numbers=" + options[:exclude_numbers].to_s unless options[:exclude_numbers].empty?
- query += "&lemmatize=" + options[:lemmatize].to_s unless options[:lemmatize].empty?
- query += "&whole_word_only=" + options[:whole_word_only].to_s unless options[:whole_word_only].empty?
- query += "&exclude_synonyms=" + options[:exclude_synonyms].to_s unless options[:exclude_synonyms].empty?
- query += "&ncbo_slice=" + options[:ncbo_slice].to_s unless options[:ncbo_slice].empty?
-
- annotations = parse_json(query) # See application_controller.rb
- #annotations = LinkedData::Client::HTTP.get(query)
- LOG.add :debug, "Query: #{query}"
- LOG.add :debug, "Retrieved #{annotations.length} annotations: #{Time.now - start}s"
- if annotations.empty? || params[:raw] == "true"
- # TODO: if params contains select ontologies and/or semantic types, only return those selected.
- response = {
- annotations: annotations,
- ontologies: get_simplified_ontologies_hash, # application_controller
- semantic_types: get_semantic_types # application_controller
- }
- else
- massage_annotated_classes(annotations, options)
- response = {
- annotations: annotations,
- ontologies: {}, # ontology data are in annotations already.
- semantic_types: {} # semantic types are in annotations already.
+ private
+ def set_annotator_info(url, page_name, uri)
+ @form_url = url
+ @page_name = page_name
+ annotator_results(uri)
+ end
+ def annotator_results(uri)
+ @advanced_options_open = false
+ @annotator_ontologies = LinkedData::Client::Models::Ontology.all
+ if params[:text] && !params[:text].empty?
+ @init_whole_word_only = true
+ api_params = {
+ text: remove_special_chars(params[:text]),
+ ontologies: params[:ontologies],
+ semantic_types: params[:semantic_types],
+ semantic_groups: params[:semantic_groups],
+ whole_word_only: params[:whole_word_only],
+ longest_only: params[:longest_only],
+ expand_mappings: params[:expand_mappings],
+ exclude_numbers: params[:exclude_numbers],
+ exclude_synonyms: params[:exclude_synonyms],
+ semantic_types: params[:semantic_types],
+ semantic_groups: params[:semantic_groups],
+ class_hierarchy_max_level: params[:class_hierarchy_max_level],
+ score_threshold: params[:score_threshold],
+ confidence_threshold: params[:confidence_threshold],
+ fast_context: params[:fast_context],
+ lemmatize: params[:lemmatize]
}
+ unless params[:score].eql?('none')
+ api_params[:score] = params[:score]
+ end
+ @json_link = json_link(uri, api_params)
+ @rdf_link = "#{@json_link}&format=rdf"
+ @results_table_header = [
+ t('annotator.class'), t('annotator.ontology'), t('annotator.context')
+ ]
+ if params[:fast_context]
+ @results_table_header += [t('annotator.negation'), t('annotator.experiencer'), t('annotator.temporality'), t('annotator.certainty')]
+ end
+ @direct_results = 0
+ @parents_results = 0
+ if params[:score].nil? || params[:score].eql?('none')
+ params[:score] = nil
+ else
+ @results_table_header.push(t('annotator.score'))
+ end
+ annotations = LinkedData::Client::HTTP.get(uri, api_params)
+ @ontologies = get_simplified_ontologies_hash
+ @semantic_types = get_semantic_types
+ @results = []
+ annotations.each do |annotation|
+ if annotation.annotations.empty?
+ row = {
+ class: annotation_class_info(annotation.annotatedClass),
+ ontology: annotation_ontology_info(annotation.annotatedClass.links),
+ context: "",
+ type: 'direct'
+ }
+ unless params[:score].eql?('none')
+ row[:score] = annotation.score.nil? ? '' : sprintf("%.2f", annotation.score)
+ end
+ @direct_results = @direct_results + 1
+ @results.push(row)
+ else
+ row = {
+ class: annotation_class_info(annotation.annotatedClass),
+ ontology: annotation_ontology_info(annotation.annotatedClass.links["ontology"]),
+ context: [],
+ type: 'direct'
+ }
+ unless params[:score].eql?('none')
+ row[:score] = annotation.score.nil? ? '' : sprintf("%.2f", annotation.score)
+ end
+ annotation.annotations.each do |a|
+ row[:context].push(a)
+ if params[:fast_context]
+ row[:negation] = a.negationContext
+ row[:experiencer] = a.experiencerContext
+ row[:temporality] = a.temporalityContext
+ row[:certainty] = a.certaintyContext
+ end
+ end
+ index = @results.find_index { |result| result[:class] == row[:class] }
+ if index
+ @results[index][:context].unshift(*row[:context])
+ @results[index][:score] = @results[index][:score].to_i + row[:score].to_i
+ else
+ @results.push(row)
+ end
+ @direct_results = @direct_results + 1
+ end
+ annotation.hierarchy.each do |parent|
+ row = {
+ class: annotation_class_info(parent.annotatedClass),
+ ontology: annotation_ontology_info(parent.annotatedClass.links["ontology"]),
+ context: [{child: annotation_class_info(annotation.annotatedClass), level: parent.distance}],
+ type: 'parent'
+ }
+ unless params[:score].eql?('none')
+ row[:score] = parent.score.nil? ? '' : sprintf("%.2f", parent.score)
+ end
+ index = @results.find_index { |result| result[:class] == row[:class] }
+ if index
+ @results[index][:context] += row[:context]
+ @results[index][:score] = @results[index][:score].to_i + row[:score].to_i
+ else
+ if params[:fast_context]
+ row[:negation] = annotation.annotations[0].negationContext
+ row[:experiencer] = annotation.annotations[0].experiencerContext
+ row[:temporality] = annotation.annotations[0].temporalityContext
+ row[:certainty] = annotation.annotations[0].certaintyContext
+ end
+ @results.push(row)
+ end
+ @parents_results = @parents_results + 1
+ end
+ end
+ @advanced_options_open = !empty_advanced_options
end
-
- render :json => response
end
- private
-
def get_semantic_types
semantic_types = {}
sty_ont = LinkedData::Client::Models::Ontology.find_by_acronym('STY').first
return semantic_types if sty_ont.nil?
# The first 500 items should be more than sufficient to get all semantic types.
sty_classes = sty_ont.explore.classes({'pagesize'=>500, include: 'prefLabel'})
- sty_classes.collection.each do |cls|
+ Array(sty_classes.collection).each do |cls|
code = cls.id.split("/").last
semantic_types[ code ] = cls.prefLabel
end
semantic_types
end
-
- def massage_annotated_classes(annotations, options)
- # Get the class details required for display, assume this is necessary
- # for every element of the annotations array because the API returns a set.
- # Use the batch REST API to get all the annotated class prefLabels.
- start = Time.now
- semantic_types = options[:semantic_types] || []
- class_details = get_annotated_classes(annotations, semantic_types)
- simplify_annotated_classes(annotations, class_details)
- # repeat the simplification for any annotation hierarchy or mappings.
- hierarchy = annotations.map {|a| a if a.keys.include? 'hierarchy' }.compact
- hierarchy.each do |a|
- simplify_annotated_classes(a['hierarchy'], class_details) if not a['hierarchy'].empty?
- end
- mappings = annotations.map {|a| a if a.keys.include? 'mappings' }.compact
- mappings.each do |a|
- simplify_annotated_classes(a['mappings'], class_details) if not a['mappings'].empty?
- end
- LOG.add :debug, "Completed massage for annotated classes: #{Time.now - start}s"
+ def annotation_class_info(cls)
+ return {
+ text: cls.prefLabel,
+ link: url_to_endpoint(cls.links["self"])
+ }
+ end
+ def annotation_ontology_info(ontology_url)
+ return {
+ text: @ontologies[ontology_url][:name],
+ link: url_to_endpoint(ontology_url)
+ }
end
- def simplify_annotated_classes(annotations, class_details)
- annotations2delete = []
- annotations.each do |a|
- cls_id = a['annotatedClass']['@id']
- details = class_details[cls_id]
- if details.nil?
- LOG.add :debug, "Failed to get class details for: #{a['annotatedClass']['links']['self']}"
- annotations2delete.push(cls_id)
- else
- # Replace the annotated class with simplified details.
- a['annotatedClass'] = details
- end
+ def initialize_options
+ @semantic_types_for_select = []
+ @semantic_groups_for_select = []
+ @semantic_types ||= get_semantic_types
+ @sem_type_ont = LinkedData::Client::Models::Ontology.find_by_acronym('STY').first
+ @semantic_groups ||= {"ACTI" => "Activities & Behaviors", "ANAT" => "Anatomy", "CHEM" => "Chemicals & Drugs","CONC" => "Concepts & Ideas","DEVI" => "Devices", "DISO" => "Disorders", "GENE" => "Genes & Molecular Sequences", "GEOG" => "Geographic Areas", "LIVB" => "Living Beings","OBJC" => "Objects", "OCCU" => "Occupations", "ORGA" => "Organizations", "PHEN" => "Phenomena", "PHYS" => "Physiology","PROC" => "Procedures"}
+ @semantic_types.each_pair do |code, label|
+ @semantic_types_for_select << ["#{label} (#{code})", code]
end
- # Remove any annotations that fail to resolve details.
- annotations.delete_if { |a| annotations2delete.include? a['annotatedClass']['@id'] }
+ @semantic_groups.each_pair do |group, label|
+ @semantic_groups_for_select << ["#{label} (#{group})", group]
+ end
+ @semantic_types_for_select.sort! {|a,b| a[0] <=> b[0]}
+ @semantic_groups_for_select.sort! {|a,b| a[0] <=> b[0]}
+ @ancestors_levels = ['None', '1', '2', '3', '4', '5', '6', '7', '8', '9', '10', 'All']
+ @include_score = ['none', 'old', 'cvalue', 'cvalueh']
end
- def get_annotated_class_hash(a)
- return {
- :class => a['annotatedClass']['@id'],
- :ontology => a['annotatedClass']['links']['ontology']
- }
+ def empty_advanced_options
+ params[:semantic_types].nil? &&
+ params[:semantic_groups].nil? &&
+ params[:class_hierarchy_max_level] == 'None' &&
+ (params[:score].nil? || params[:score] == 'none') &&
+ params[:score_threshold] == '0' &&
+ params[:confidence_threshold] == '0' &&
+ params[:fast_context].nil? &&
+ params[:lemmatize].nil?
end
- def get_annotated_classes(annotations, semantic_types=[])
- # Use batch service to get class prefLabels
- class_list = []
- annotations.each {|a| class_list << get_annotated_class_hash(a) }
- hierarchy = annotations.map {|a| a if a.keys.include? 'hierarchy' }.compact
- hierarchy.each do |a|
- a['hierarchy'].each {|h| class_list << get_annotated_class_hash(h) }
- end
- mappings = annotations.map {|a| a if a.keys.include? 'mappings' }.compact
- mappings.each do |a|
- a['mappings'].each {|m| class_list << get_annotated_class_hash(m) }
- end
- classes_simple = {}
- return classes_simple if class_list.empty?
- # remove duplicates
- class_set = class_list.to_set # get unique class:ontology set
- class_list = class_set.to_a # collection requires a list in batch call
- # make the batch call
- properties = 'prefLabel'
- properties = 'prefLabel,semanticType' if not semantic_types.empty?
- call_params = {'http://www.w3.org/2002/07/owl#Class'=>{'collection'=>class_list, 'include'=>properties}}
- classes_json = get_batch_results(call_params)
- # Simplify the response data for the UI
- @ontologies_hash ||= get_simplified_ontologies_hash # application_controller
- classes_data = JSON.parse(classes_json)
- classes_data["http://www.w3.org/2002/07/owl#Class"].each do |cls|
- c = simplify_class_model(cls)
- ont_details = @ontologies_hash[ c[:ontology] ]
- next if ont_details.nil? # NO DISPLAY FOR ANNOTATIONS ON ANY CLASS OUTSIDE THE BIOPORTAL ONTOLOGY SET.
- c[:ontology] = ont_details
- unless semantic_types.empty? || cls['semanticType'].nil?
- @semantic_types ||= get_semantic_types # application_controller
- # Extract the semantic type descriptions that are requested.
- semanticTypeURI = 'http://bioportal.bioontology.org/ontologies/umls/sty/'
- semanticCodes = cls['semanticType'].map {|t| t.sub( semanticTypeURI, '') }
- requestedCodes = semanticCodes.map {|code| (semantic_types.include? code and code) || nil }.compact
- requestedDescriptions = requestedCodes.map {|code| @semantic_types[code] }.compact
- c[:semantic_types] = requestedDescriptions
- else
- c[:semantic_types] = []
- end
- classes_simple[c[:id]] = c
+ def remove_special_chars(input)
+ regex = /^[a-zA-Z0-9\s]*$/
+ unless input.match?(regex)
+ input.gsub!(/[^\w\s]/, '')
end
- return classes_simple
+ input
end
end
diff --git a/app/controllers/annotatorplus_controller.rb b/app/controllers/annotatorplus_controller.rb
deleted file mode 100644
index abf8f02fd..000000000
--- a/app/controllers/annotatorplus_controller.rb
+++ /dev/null
@@ -1,210 +0,0 @@
-require 'json'
-require 'cgi'
-
-class AnnotatorplusController < ApplicationController
- layout :determine_layout
-
- # REST_URI is defined in application_controller.rb
- ANNOTATOR_URI = PROXY_URI + "/annotatorplus/"
-
- def index
- @semantic_types_for_select = []
- @semantic_types ||= get_semantic_types
- @sem_type_ont = LinkedData::Client::Models::Ontology.find_by_acronym('STY').first
- @semantic_groups ||= {"ACTI" => "Activities & Behaviors", "ANAT" => "Anatomy", "CHEM" => "Chemicals & Drugs","CONC" => "Concepts & Ideas",
- "DEVI" => "Devices", "DISO" => "Disorders", "GENE" => "Genes & Molecular Sequences", "GEOG" => "Geographic Areas", "LIVB" => "Living Beings",
- "OBJC" => "Objects", "OCCU" => "Occupations", "ORGA" => "Organizations", "PHEN" => "Phenomena", "PHYS" => "Physiology","PROC" => "Procedures"}
- @semantic_groups_for_select = []
- @semantic_types.each_pair do |code, label|
- @semantic_types_for_select << ["#{label} (#{code})", code]
- end
- @semantic_groups.each_pair do |group, label|
- @semantic_groups_for_select << ["#{label} (#{group})", group]
- end
-
- @semantic_types_for_select.sort! {|a,b| a[0] <=> b[0]}
- @semantic_groups_for_select.sort! {|a,b| a[0] <=> b[0]}
- @recognizers = parse_json(REST_URI + "/annotator/recognizers")
- @annotator_ontologies = LinkedData::Client::Models::Ontology.all
- @annotator_ontologies.sort_by! { |ont| ont.name.strip.downcase }
- end
-
-
- def create
- params[:mappings] ||= []
- params[:max_level] ||= 0
- params[:ontologies] ||= []
- params[:semantic_types] ||= []
- params[:semantic_groups] ||= []
- text_to_annotate = params[:text].strip.gsub("\r\n", " ").gsub("\n", " ")
-
- options = { :ontologies => params[:ontologies],
- :class_hierarchy_max_level => params[:class_hierarchy_max_level].to_i,
- :expand_class_hierarchy => params[:class_hierarchy_max_level].to_i > 0,
- :semantic_types => params[:semantic_types],
- :semantic_groups => params[:semantic_groups],
- :mappings => params[:mappings],
- :longest_only => params[:longest_only],
- :exclude_numbers => params[:exclude_numbers] ||= "false", # service default is false
- :whole_word_only => (params[:whole_word_only] == "true") ? "false" : "true", # service default is true
- :exclude_synonyms => params[:exclude_synonyms] ||= "false", # service default is false
- :negation => params[:negation] ||= "false", # service default is false
- :experiencer => params[:experiencer] ||= "false", # service default is false
- :temporality => params[:temporality] ||= "false", # service default is false
- :score => params[:score],
- :score_threshold => params[:score_threshold] ||=-1,
- :confidence_threshold => params[:confidence_threshold] ||=-1,
- :ncbo_slice => params[:ncbo_slice] || ''
- }
-
- start = Time.now
- query = ANNOTATOR_URI
- query += "?text=" + CGI.escape(text_to_annotate)
- query += "&include=prefLabel"
- query += "&expand_class_hierarchy=true" if options[:class_hierarchy_max_level] > 0
- query += "&class_hierarchy_max_level=" + options[:class_hierarchy_max_level].to_s if options[:class_hierarchy_max_level] > 0
- query += "&score=" + options[:score] unless options[:score] == ""
- query += "&score_threshold=" + options[:score_threshold] unless options[:score] == "" or options[:score_threshold]==-1
- query += "&confidence_threshold=" + options[:confidence_threshold] unless options[:score] == "" or options[:confidence_threshold]==-1
- query += "&negation=" + options[:negation] unless options[:negation].empty?
- query += "&experiencer=" + options[:experiencer] unless options[:experiencer].empty?
- query += "&temporality=" + options[:temporality] unless options[:temporality].empty?
- query += "&ontologies=" + CGI.escape(options[:ontologies].join(',')) unless options[:ontologies].empty?
- query += "&semantic_types=" + options[:semantic_types].join(',') unless options[:semantic_types].empty?
- query += "&semantic_groups=" + options[:semantic_groups].join(',') unless options[:semantic_groups].empty?
- query += "&mappings=" + options[:mappings].join(',') unless options[:mappings].empty?
- query += "&longest_only=#{options[:longest_only]}"
- query += "&recognizer=#{params[:recognizer]}"
- query += "&exclude_numbers=" + options[:exclude_numbers].to_s unless options[:exclude_numbers].empty?
- query += "&whole_word_only=" + options[:whole_word_only].to_s unless options[:whole_word_only].empty?
- query += "&exclude_synonyms=" + options[:exclude_synonyms].to_s unless options[:exclude_synonyms].empty?
- query += "&ncbo_slice=" + options[:ncbo_slice].to_s unless options[:ncbo_slice].empty?
-
- annotations = parse_json(query) # See application_controller.rb
- #annotations = LinkedData::Client::HTTP.get(query)
- LOG.add :debug, "Retrieved #{annotations.length} annotations: #{Time.now - start}s"
- if annotations.empty? || params[:raw] == "true"
- # TODO: if params contains select ontologies and/or semantic types, only return those selected.
- response = {
- annotations: annotations,
- ontologies: get_simplified_ontologies_hash, # application_controller
- semantic_types: get_semantic_types # application_controller
- }
- else
- massage_annotated_classes(annotations, options)
- response = {
- annotations: annotations,
- ontologies: {}, # ontology data are in annotations already.
- semantic_types: {} # semantic types are in annotations already.
- }
- end
-
- render :json => response
- end
-
- private
-
- def get_semantic_types
- semantic_types = {}
- sty_ont = LinkedData::Client::Models::Ontology.find_by_acronym('STY').first
- return semantic_types if sty_ont.nil?
- # The first 500 items should be more than sufficient to get all semantic types.
- sty_classes = sty_ont.explore.classes({'pagesize'=>500, include: 'prefLabel'})
- sty_classes.collection.each do |cls|
- code = cls.id.split("/").last
- semantic_types[ code ] = cls.prefLabel
- end
- semantic_types
- end
-
- def massage_annotated_classes(annotations, options)
- # Get the class details required for display, assume this is necessary
- # for every element of the annotations array because the API returns a set.
- # Use the batch REST API to get all the annotated class prefLabels.
- start = Time.now
- semantic_types = options[:semantic_types] || []
- class_details = get_annotated_classes(annotations, semantic_types)
- simplify_annotated_classes(annotations, class_details)
- # repeat the simplification for any annotation hierarchy or mappings.
- hierarchy = annotations.map {|a| a if a.keys.include? 'hierarchy' }.compact
- hierarchy.each do |a|
- simplify_annotated_classes(a['hierarchy'], class_details) if not a['hierarchy'].empty?
- end
- mappings = annotations.map {|a| a if a.keys.include? 'mappings' }.compact
- mappings.each do |a|
- simplify_annotated_classes(a['mappings'], class_details) if not a['mappings'].empty?
- end
- LOG.add :debug, "Completed massage for annotated classes: #{Time.now - start}s"
- end
-
- def simplify_annotated_classes(annotations, class_details)
- annotations2delete = []
- annotations.each do |a|
- cls_id = a['annotatedClass']['@id']
- details = class_details[cls_id]
- if details.nil?
- LOG.add :debug, "Failed to get class details for: #{a['annotatedClass']['links']['self']}"
- annotations2delete.push(cls_id)
- else
- # Replace the annotated class with simplified details.
- a['annotatedClass'] = details
- end
- end
- # Remove any annotations that fail to resolve details.
- annotations.delete_if { |a| annotations2delete.include? a['annotatedClass']['@id'] }
- end
-
- def get_annotated_class_hash(a)
- return {
- :class => a['annotatedClass']['@id'],
- :ontology => a['annotatedClass']['links']['ontology']
- }
- end
-
- def get_annotated_classes(annotations, semantic_types=[])
- # Use batch service to get class prefLabels
- class_list = []
- annotations.each {|a| class_list << get_annotated_class_hash(a) }
- hierarchy = annotations.map {|a| a if a.keys.include? 'hierarchy' }.compact
- hierarchy.each do |a|
- a['hierarchy'].each {|h| class_list << get_annotated_class_hash(h) }
- end
- mappings = annotations.map {|a| a if a.keys.include? 'mappings' }.compact
- mappings.each do |a|
- a['mappings'].each {|m| class_list << get_annotated_class_hash(m) }
- end
- classes_simple = {}
- return classes_simple if class_list.empty?
- # remove duplicates
- class_set = class_list.to_set # get unique class:ontology set
- class_list = class_set.to_a # collection requires a list in batch call
- # make the batch call
- properties = 'prefLabel'
- properties = 'prefLabel,semanticType' if not semantic_types.empty?
- call_params = {'http://www.w3.org/2002/07/owl#Class'=>{'collection'=>class_list, 'include'=>properties}}
- classes_json = get_batch_results(call_params)
- # Simplify the response data for the UI
- @ontologies_hash ||= get_simplified_ontologies_hash # application_controller
- classes_data = JSON.parse(classes_json)
- classes_data["http://www.w3.org/2002/07/owl#Class"].each do |cls|
- c = simplify_class_model(cls)
- ont_details = @ontologies_hash[ c[:ontology] ]
- next if ont_details.nil? # NO DISPLAY FOR ANNOTATIONS ON ANY CLASS OUTSIDE THE BIOPORTAL ONTOLOGY SET.
- c[:ontology] = ont_details
- unless semantic_types.empty? || cls['semanticType'].nil?
- @semantic_types ||= get_semantic_types # application_controller
- # Extract the semantic type descriptions that are requested.
- semanticTypeURI = 'http://bioportal.bioontology.org/ontologies/umls/sty/'
- semanticCodes = cls['semanticType'].map {|t| t.sub( semanticTypeURI, '') }
- requestedCodes = semanticCodes.map {|code| (semantic_types.include? code and code) || nil }.compact
- requestedDescriptions = requestedCodes.map {|code| @semantic_types[code] }.compact
- c[:semantic_types] = requestedDescriptions
- else
- c[:semantic_types] = []
- end
- classes_simple[c[:id]] = c
- end
- return classes_simple
- end
-
-end
diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb
index fcc9e9845..04215413c 100644
--- a/app/controllers/application_controller.rb
+++ b/app/controllers/application_controller.rb
@@ -13,9 +13,43 @@
# Likewise, all the methods added will be available for all controllers.
class ApplicationController < ActionController::Base
+ include InternationalisationHelper
+
+ before_action :set_locale
+
+ def self.t(*args)
+ InternationalisationHelper.t(*args)
+ end
+
+ # Sets the locale based on the locale cookie or the value returned by detect_locale.
+ def set_locale
+ I18n.locale = cookies[:locale] || detect_locale
+ cookies.permanent[:locale] = I18n.locale if cookies[:locale].nil?
+ logger.debug "* Locale set to '#{I18n.locale}'"
+ session[:locale] = I18n.locale
+ end
+
+ # Returns detedted locale based on the Accept-Language header of the request or the default locale if none is found.
+ def detect_locale
+ languages = request.headers['Accept-Language']&.split(',')
+ supported_languages = I18n.available_locales
+
+ Array(languages).each do |language|
+ language_code = language.split(/[-;]/).first.downcase.to_sym
+ return language_code if supported_languages.include?(language_code)
+ end
+
+ return I18n.default_locale
+ end
+
+
helper :all # include all helpers, all the time
helper_method :bp_config_json, :current_license, :using_captcha?
- rescue_from ActiveRecord::RecordNotFound, with: :not_found_record
+
+ if !Rails.env.development? && !Rails.env.test?
+ rescue_from ActiveRecord::RecordNotFound, with: :not_found_record
+ end
+
# Pull configuration parameters for REST connection.
REST_URI = $REST_URL
API_KEY = $API_KEY
@@ -52,9 +86,6 @@ class ApplicationController < ActionController::Base
$trial_license_initialized = false
- if !$EMAIL_EXCEPTIONS.nil? && $EMAIL_EXCEPTIONS == true
- include ExceptionNotifiable
- end
# See ActionController::RequestForgeryProtection for details
protect_from_forgery
@@ -62,6 +93,14 @@ class ApplicationController < ActionController::Base
before_action :set_global_thread_values, :domain_ontology_set, :authorize_miniprofiler, :clean_empty_strings_from_params_arrays, :init_trial_license
+ def invalidate_cache?
+ params[:invalidate_cache] && params[:invalidate_cache].to_s.eql?('true')
+ end
+
+ def show_image_modal
+ url = params[:url]
+ render turbo_stream: helpers.prepend('application_modal_content') { helpers.image_tag(url, style:'width: 100%') }
+ end
def set_global_thread_values
Thread.current[:session] = session
@@ -100,26 +139,23 @@ def domain_ontology_set
Thread.current[:slice] = @subdomain_filter
end
- def anonymous_user
- user = DataAccess.getUser($ANONYMOUS_USER)
- user ||= User.new({"id" => 0})
- end
+
def ontology_not_found(ontology_acronym)
- not_found("Ontology #{ontology_acronym} not found")
+ not_found(t('application.ontology_not_found',acronym: ontology_acronym))
end
def concept_not_found(concept_id)
- not_found("Concept #{concept_id} not found")
+ not_found(t('application.concept_not_found',concept: concept_id))
end
def not_found(message = '')
if request.xhr?
- render plain: message || "Error: load failed"
+ render plain: message || t('application.error_load')
return
end
- raise ActiveRecord::RecordNotFound.new(message || 'Not Found')
+ raise ActiveRecord::RecordNotFound.new(message || t('application.not_found_message'))
end
NOTIFICATION_TYPES = { :notes => "CREATE_NOTE_NOTIFICATION", :all => "ALL_NOTIFICATION" }
@@ -130,12 +166,6 @@ def to_param(name) # Paramaterizes URLs without encoding
end
end
- def undo_param(name) #Undo Paramaterization
- unless name.nil?
- name.to_s.gsub('_'," ")
- end
- end
-
def bp_config_json
# For config settings, see
# config/bioportal_config.rb
@@ -161,23 +191,11 @@ def bp_config_json
config.to_json
end
- def remote_file_exists?(url)
- begin
- url = URI.parse(url)
-
- if url.kind_of?(URI::FTP)
- check = check_ftp_file(url)
- else
- check = check_http_file(url)
- end
- rescue
- return false
- end
-
- check
+ def rest_url
+ helpers.rest_url
end
-
+
def check_http_file(url)
session = Net::HTTP.new(url.host, url.port)
session.use_ssl = true if url.port == 443
@@ -218,7 +236,7 @@ def parse_response_body(response)
def response_errors(error_response)
error_struct = parse_response_body(error_response)
- errors = {error: "There was an error, please try again"}
+ errors = {error: t('application.try_again')}
return errors unless error_struct
return errors unless error_struct.respond_to?(:errors)
errors = {}
@@ -267,22 +285,13 @@ def redirect_to_home # Redirect to Home Page
redirect_to "/"
end
- def redirect_to_history # Redirects to the correct tab through the history system
- if session[:redirect].nil?
- redirect_to_home
- else
- tab = find_tab(session[:redirect][:ontology])
- session[:redirect]=nil
- redirect_to uri_url(:ontology=>tab.ontology_id,:conceptid=>tab.concept)
- end
- end
def redirect_new_api(class_view = false)
# Hack to make ontologyid and conceptid work in addition to id and ontology params
params[:ontology] = params[:ontology].nil? ? params[:ontologyid] : params[:ontology]
# Error checking
if params[:ontology].nil? || params[:id] && params[:ontology].nil?
- @error = "Please provide an ontology id or concept id with an ontology id."
+ @error = t('application.provide_ontology_or_concept')
return
end
acronym = BpidResolver.id_to_acronym(params[:ontology])
@@ -332,24 +341,6 @@ def authorize_and_redirect
end
end
- # Verifies that a user owns an object
- def authorize_owner(id=nil)
- if id.nil?
- id = params[:id].to_i
- end
-
- id.map! {|i| i.to_i} if id.kind_of?(Array)
-
- if session[:user].nil?
- redirect_to_home
- else
- if id.kind_of?(Array)
- redirect_to_home if !session[:user].admin? && !id.include?(session[:user].id.to_i)
- else
- redirect_to_home if !session[:user].admin? && !session[:user].id.to_i.eql?(id)
- end
- end
- end
def authorize_admin
admin = session[:user] && session[:user].admin?
@@ -364,41 +355,7 @@ def ontology_restricted?(acronym)
restrict_downloads = $NOT_DOWNLOADABLE
restrict_downloads.include? acronym
end
- # updates the 'history' tab with the current selected concept
- def update_tab(ontology, concept)
- array = session[:ontologies] || []
- found = false
- for item in array
- if item.ontology_id.eql?(ontology.id)
- item.concept=concept
- found=true
- end
- end
-
- unless found
- array << History.new(ontology.id, ontology.name, ontology.acronym, concept)
- end
-
- session[:ontologies]=array
- end
- # Removes a 'history' tab
- def remove_tab(ontology_id)
- array = session[:ontologies]
- array.delete(find_tab(ontology_id))
- session[:ontologies]=array
- end
-
- # Returns a specific 'history' tab
- def find_tab(ontology_id)
- array = session[:ontologies]
- for item in array
- if item.ontology_id.eql?(ontology_id)
- return item
- end
- end
- return nil
- end
def check_delete_mapping_permission(mappings)
# ensure mappings is an Array of mappings (some calls may provide only a single mapping instance)
@@ -421,23 +378,25 @@ def using_captcha?
def get_class(params)
+ lang = request_lang
+
if @ontology.flat?
ignore_concept_param = params[:conceptid].nil? ||
- params[:conceptid].empty? ||
- params[:conceptid].eql?("root") ||
- params[:conceptid].eql?("bp_fake_root")
+ params[:conceptid].empty? ||
+ params[:conceptid].eql?("root") ||
+ params[:conceptid].eql?("bp_fake_root")
if ignore_concept_param
# Don't display any classes in the tree
@concept = LinkedData::Client::Models::Class.new
- @concept.prefLabel = "Please search for a class using the Jump To field above"
+ @concept.prefLabel = t('application.search_for_class')
@concept.obsolete = false
@concept.id = "bp_fake_root"
@concept.properties = {}
@concept.children = []
else
# Display only the requested class in the tree
- @concept = @ontology.explore.single_class({full: true}, params[:conceptid])
+ @concept = @ontology.explore.single_class({full: true, lang: lang }, params[:conceptid])
@concept.children = []
end
@root = LinkedData::Client::Models::Class.new
@@ -446,47 +405,54 @@ def get_class(params)
else
# not ignoring 'bp_fake_root' here
+ include = 'prefLabel,hasChildren,obsolete'
ignore_concept_param = params[:conceptid].nil? ||
- params[:conceptid].empty? ||
- params[:conceptid].eql?("root")
+ params[:conceptid].empty? ||
+ params[:conceptid].eql?("root")
if ignore_concept_param
# get the top level nodes for the root
# TODO_REV: Support views? Replace old view call: @ontology.top_level_classes(view)
- roots = @ontology.explore.roots(concept_schemes: params[:concept_schemes])
- if roots.nil? || roots.empty?
- LOG.add :debug, "Missing roots for #{@ontology.acronym}"
- not_found("Missing roots for #{@ontology.acronym}")
+ @roots = @ontology.explore.roots(concept_schemes: params[:concept_schemes]) rescue nil
+
+ if @roots.nil? || response_error?(@roots) || @roots.compact&.empty?
+ LOG.add :debug, t('application.missing_roots_for_ontology', acronym: @ontology.acronym)
+ classes = @ontology.explore.classes.collection
+ @concept = classes.first.explore.self(full: true) if classes&.first
+ return
end
+
@root = LinkedData::Client::Models::Class.new(read_only: true)
- @root.children = roots.sort{|x,y| (x.prefLabel || "").downcase <=> (y.prefLabel || "").downcase}
+ @root.children = @roots.sort{|x,y| (x&.prefLabel || "").downcase <=> (y&.prefLabel || "").downcase}
# get the initial concept to display
- root_child = @root.children.first
+ root_child = @root.children&.first
+ not_found(t('application.missing_roots')) if root_child.nil?
- @concept = root_child.explore.self(full: true)
+ @concept = root_child.explore.self(full: true, lang: lang)
# Some ontologies have "too many children" at their root. These will not process and are handled here.
if @concept.nil?
- LOG.add :debug, "Missing class #{root_child.links.self}"
- not_found("Missing class #{root_child.links.self}")
+ LOG.add :debug, t('application.missing_class', root_child: root_child.links.self)
+ not_found(t('application.missing_class', root_child: root_child.links.self))
end
else
# if the id is coming from a param, use that to get concept
- @concept = @ontology.explore.single_class({full: true}, params[:conceptid])
+ @concept = @ontology.explore.single_class({full: true, lang: lang}, params[:conceptid])
if @concept.nil? || @concept.errors
- LOG.add :debug, "Missing class #{@ontology.acronym} / #{params[:conceptid]}"
- not_found("Missing class #{@ontology.acronym} / #{params[:conceptid]}")
+ LOG.add :debug, t('application.missing_class_ontology', acronym: @ontology.acronym, concept_id: params[:conceptid])
+ not_found(t('application.missing_class_ontology', acronym: @ontology.acronym, concept_id: params[:conceptid]))
end
# Create the tree
- rootNode = @concept.explore.tree(include: "prefLabel,hasChildren,obsolete", concept_schemes: params[:concept_schemes])
+ rootNode = @concept.explore.tree(include: include, concept_schemes: params[:concept_schemes], lang: lang)
if rootNode.nil? || rootNode.empty?
- roots = @ontology.explore.roots(concept_schemes: params[:concept_schemes])
- if roots.nil? || roots.empty?
- LOG.add :debug, "Missing roots for #{@ontology.acronym}"
- not_found("Missing roots for #{@ontology.acronym}")
+ @roots = @ontology.explore.roots(concept_schemes: params[:concept_schemes])
+ if @roots.nil? || response_error?(@roots) || @roots.compact&.empty?
+ LOG.add :debug, t('application.missing_roots_for_ontology', acronym: @ontology.acronym)
+ @concept = @ontology.explore.classes.collection.first.explore.self(full: true)
+ return
end
- if roots.any? {|c| c.id == @concept.id}
- rootNode = roots
+ if @roots.any? {|c| c.id == @concept.id}
+ rootNode = @roots
else
rootNode = [@concept]
end
@@ -499,13 +465,6 @@ def get_class(params)
@concept
end
- def get_metrics_hash
- metrics_hash = {}
- # TODO: Metrics do not return for views on the backend, need to enable include_views param there
- @metrics = LinkedData::Client::Models::Metrics.all(include_views: true)
- @metrics.each {|m| metrics_hash[m.links['ontology']] = m }
- return metrics_hash
- end
def get_ontology_submission_ready(ontology)
# Get the latest 'ready' submission
@@ -528,17 +487,7 @@ def get_simplified_ontologies_hash()
return simple_ontologies
end
- def get_ontology_details(ont_uri)
- # Note the simplify_ontology_model will cache individual ontology data.
- begin
- ont_model = LinkedData::Client::Models::Ontology.find(ont_uri)
- ont = simplify_ontology_model(ont_model)
- rescue Exception => e
- LOG.add :error, e.message
- return nil
- end
- return ont
- end
+
def simplify_classes(classes)
# Simplify the classes batch service data for the UI
@@ -601,7 +550,7 @@ def simplify_class_model(cls_model)
end
rescue Exception => e
LOG.add :error, e.message
- LOG.add :error, "Failure to simplify class: #{cls}"
+ LOG.add :error, t('application.error_simplify_class', cls: cls)
end
return cls
end
@@ -616,7 +565,7 @@ def simplify_ontology_model(ont_model)
ont = Rails.cache.read(id)
return ont unless ont.nil?
# No cache or it has expired
- LOG.add :debug, "No cache or expired cache for ontology: #{id}"
+ LOG.add :debug, t('application.no_cache', id: id)
ont = {}
ont[:id] = id
ont[:uri] = id
@@ -633,7 +582,7 @@ def simplify_ontology_model(ont_model)
end
# Only cache a complete representation of a simplified ontology
if ont[:id].nil? || ont[:uri].nil? || ont[:acronym].nil? || ont[:name].nil? || ont[:ui].nil?
- raise "Incomplete simple ontology: #{id}, #{ont}"
+ raise t('application.incomplete_simple_ontology', id: id, ont: ont)
else
Rails.cache.write(ont[:id], ont, expires_in: EXPIRY_ONTOLOGY_SIMPLIFIED)
end
@@ -752,13 +701,24 @@ def init_trial_license
# Get the submission metadata from the REST API.
def submission_metadata
- @metadata ||= JSON.parse(Net::HTTP.get(URI.parse("#{REST_URI}/submission_metadata?apikey=#{API_KEY}")))
+ @metadata ||= helpers.submission_metadata
+ end
+
+ def request_lang
+ helpers.request_lang
+ end
+
+ def json_link(url, optional_params)
+ base_url = "#{url}?"
+ filtered_params = optional_params.reject { |_, value| value.nil? }
+ optional_params_str = filtered_params.map { |param, value| "#{param}=#{value}" }.join("&")
+ return base_url + optional_params_str + "&apikey=#{$API_KEY}"
end
- helper_method :submission_metadata
private
def not_found_record(exception)
@error_message = exception.message
+
render 'errors/not_found', status: 404
end
end
diff --git a/app/controllers/check_resolvability_controller.rb b/app/controllers/check_resolvability_controller.rb
new file mode 100644
index 000000000..4ad28747a
--- /dev/null
+++ b/app/controllers/check_resolvability_controller.rb
@@ -0,0 +1,23 @@
+class CheckResolvabilityController < ApplicationController
+ layout "tool"
+ include TurboHelper
+
+ def index
+ if params[:url]
+ @url = params[:url]
+ @results = helpers.check_resolvability_helper(@url)
+ end
+ end
+
+ def check_resolvability
+ url = params[:url]
+ container = "#{helpers.escape(params[:url])}_container"
+ result = helpers.check_resolvability_helper(url)
+ render_turbo_stream(replace(container) {
+ render_to_string UrlResolvabilityComponent.new(url: params[:url], resolvable: result[:result].eql?(1) || result[:result].eql?(2),
+ status: result[:status],
+ supported_formats: result[:allowed_format]), layout: false
+ })
+ end
+
+end
diff --git a/app/controllers/collections_controller.rb b/app/controllers/collections_controller.rb
index 773b7361f..14f697902 100644
--- a/app/controllers/collections_controller.rb
+++ b/app/controllers/collections_controller.rb
@@ -1,6 +1,44 @@
class CollectionsController < ApplicationController
- include CollectionsHelper
+ include CollectionsHelper,SearchContent
+
+
+ def index
+ acronym = params[:ontology]
+ @ontology = LinkedData::Client::Models::Ontology.find_by_acronym(acronym).first
+ ontology_not_found(acronym) if @ontology.nil?
+
+
+ collection_id = params[:collectionid]
+ @collection = get_collection(@ontology, collection_id) if collection_id
+
+
+ if params[:search].blank?
+ @collections = get_collections(@ontology)
+
+ render partial: 'collections/list_view'
+ else
+
+ query, page, page_size = helpers.search_content_params
+
+ results, _, next_page, total_count = search_ontologies_content(query: query,
+ page: page,
+ page_size: page_size,
+ filter_by_ontologies: [acronym],
+ filter_by_types: ['Collection'])
+
+
+ render inline: helpers.render_search_paginated_list(container_id: 'collections_sorted_list',
+ next_page_url: "/ontologies/#{@ontology.acronym}/collections",
+ child_url: "/ontologies/#{@ontology.acronym}/collections/show", child_turbo_frame: 'collection',
+ child_param: :collectionid,
+ results: results, next_page: next_page, total_count: total_count
+ )
+ end
+ end
+
def show
+ redirect_to(ontology_path(id: params[:ontology_id], p: 'collections', collectionid: params[:id], lang: request_lang)) and return unless turbo_frame_request?
+
@collection = get_request_collection
end
@@ -10,15 +48,15 @@ def show_label
collection_label = collection['prefLabel'] if collection
collection_label = params[:id] if collection_label.nil? || collection_label.empty?
- render LabelLinkComponent.inline(params[:id], collection_label)
+ render LabelLinkComponent.inline(params[:id], helpers.main_language_label(collection_label))
end
def show_members
- @ontology = LinkedData::Client::Models::Ontology.find_by_acronym(params[:ontology]).first
+ @ontology = LinkedData::Client::Models::Ontology.find_by_acronym(params[:ontology_id] || params[:ontology]).first
@collection = get_request_collection
page = params[:page] || '1'
@auto_click = page.to_s.eql?('1')
- @page = @collection.explore.members({page: page})
+ @page = @collection.explore.members({page: page, language: request_lang})
@concepts = @page.collection
if @ontology.nil?
ontology_not_found params[:ontology]
@@ -33,7 +71,7 @@ def get_request_collection
params[:id] = request_collection_id
if params[:id].nil? || params[:id].empty?
- render plain: 'Error: You must provide a valid collection id'
+ render plain: t('collections.error_valid_collection')
return
end
@ontology = LinkedData::Client::Models::Ontology.find_by_acronym(params[:ontology_id] || params[:ontology]).first
diff --git a/app/controllers/concepts_controller.rb b/app/controllers/concepts_controller.rb
index 2a6fcda63..96a5fd0b7 100644
--- a/app/controllers/concepts_controller.rb
+++ b/app/controllers/concepts_controller.rb
@@ -3,36 +3,40 @@
class ConceptsController < ApplicationController
include MappingsHelper
include ConceptsHelper
+ include TurboHelper
+
layout 'ontology'
- def show_concept
+ def show
params[:id] = params[:id] ? params[:id] : params[:conceptid]
if params[:id].nil? || params[:id].empty?
- render :text => "Error: You must provide a valid concept id"
+ render :text => t('concepts.error_valid_concept')
return
end
# Note that find_by_acronym includes views by default
- @ontology = LinkedData::Client::Models::Ontology.find_by_acronym(params[:ontology_id]).first
- ontology_not_found(params[:ontology_id]) if @ontology.nil?
+ @ontology = LinkedData::Client::Models::Ontology.find_by_acronym(params[:ontology]).first
+ ontology_not_found(params[:ontology]) if @ontology.nil?
+
+ redirect_to(ontology_path(id: params[:ontology], p: 'classes', conceptid: params[:id], lang: request_lang)) and return unless turbo_frame_request?
@submission = get_ontology_submission_ready(@ontology)
@ob_instructions = helpers.ontolobridge_instructions_template(@ontology)
- @concept = @ontology.explore.single_class({full: true}, params[:id])
+ @concept = @ontology.explore.single_class({full: true, language: request_lang}, params[:id])
@instances_concept_id = @concept.id
concept_not_found(params[:id]) if @concept.nil?
- gather_details
- render :partial => 'show'
+ @notes = @concept.explore.notes
+ render partial: 'show'
end
- def show
+ def index
# Handle multiple methods of passing concept ids
params[:id] = params[:id] ? params[:id] : params[:conceptid]
if params[:id].nil? || params[:id].empty?
- render :text => "Error: You must provide a valid concept id"
+ render :text => t('concepts.error_valid_concept')
return
end
@@ -40,23 +44,22 @@ def show
@ontology = LinkedData::Client::Models::Ontology.find_by_acronym(params[:ontology]).first
@ob_instructions = helpers.ontolobridge_instructions_template(@ontology)
- if request.xhr?
- display = params[:callback].eql?('load') ? {full: true} : {display: "prefLabel"}
- @concept = @ontology.explore.single_class(display, params[:id])
- concept_not_found(params[:id]) if @concept.nil?
- @schemes = params[:concept_schemes].split(',')
- show_ajax_request # process an ajax call
- else
- # Get the latest 'ready' submission, or fallback to any latest submission
- # TODO: change the logic here if the fallback will crash the visualization
- @submission = get_ontology_submission_ready(@ontology) # application_controller
-
- @concept = @ontology.explore.single_class({full: true}, params[:id])
- concept_not_found(params[:id]) if @concept.nil?
+ # Get the latest 'ready' submission, or fallback to any latest submission
+ # TODO: change the logic here if the fallback will crash the visualization
+ @submission = get_ontology_submission_ready(@ontology) # application_controller
- show_uri_request # process a full call
- render :file => '/ontologies/visualize', :use_full_path => true, :layout => 'ontology'
- end
+ @concept = @ontology.explore.single_class({full: true}, params[:id])
+ concept_not_found(params[:id]) if @concept.nil?
+ @schemes = params[:concept_schemes].split(',')
+
+ @concept.children = @concept.explore.children(pagesize: 750, concept_schemes: Array(@schemes).join(','), language: request_lang, display: 'prefLabel,obsolete,hasChildren').collection || []
+ @concept.children.sort! { |x, y| (x.prefLabel || "").downcase <=> (y.prefLabel || "").downcase } unless @concept.children.empty?
+ render turbo_stream: [
+ replace(helpers.child_id(@concept) + '_open_link') { TreeLinkComponent.tree_close_icon },
+ replace(helpers.child_id(@concept) + '_childs') do
+ helpers.concepts_tree_component(@concept, @concept, @ontology.acronym, Array(@schemes), request_lang, sub_tree: true)
+ end
+ ]
end
def show_label
@@ -70,7 +73,7 @@ def show_label
return
end
- render LabelLinkComponent.inline(cls_id, concept_label(ont_id, cls_id))
+ render LabelLinkComponent.inline(cls_id, helpers.main_language_label(concept_label(ont_id, cls_id)))
end
def show_definition
@@ -93,11 +96,16 @@ def show_tree
return
end
@ontology = LinkedData::Client::Models::Ontology.find_by_acronym(params[:ontology]).first
- if @ontology.nil?
+ if @ontology.nil? || @ontology.errors
ontology_not_found(params[:ontology])
- else
+ else
get_class(params) #application_controller
- render partial: 'ontologies/treeview', locals: { autoCLick: params[:auto_click] || true }
+
+ not_found(t('concepts.missing_roots')) if @root.nil?
+
+ render inline: helpers.concepts_tree_component(@root, @concept,
+ @ontology.acronym, Array(params[:concept_schemes]&.split(',')), request_lang,
+ id: 'concepts_tree_view', auto_click: params[:auto_click] || true)
end
end
@@ -113,7 +121,8 @@ def show_date_sorted_list
page: page,
sortby:'modified,created',
order:'desc,desc',
- display: 'prefLabel,modified,created'
+ display: 'prefLabel,modified,created',
+ language: request_lang
}
if @last_date
params.merge!(last_date: @last_date)
@@ -158,8 +167,9 @@ def details
ontology_not_found(params[:ontology]) if @ontology.nil?
@concept = @ontology.explore.single_class({full: true}, CGI.unescape(params[:conceptid]))
- concept_not_found(CGI.unescape(params[:conceptid])) if @concept.nil?
-
+ concept_not_found(CGI.unescape(params[:conceptid])) if @concept.nil? || @concept.errors
+ @container_id = params[:modal] ? 'application_modal_content' : 'concept_details'
+
if params[:styled].eql?("true")
render :partial => "details", :layout => "partial"
else
@@ -175,43 +185,14 @@ def biomixer
@concept = @ontology.explore.single_class({full: true}, params[:conceptid])
concept_not_found(params[:conceptid]) if @concept.nil?
- @immediate_load = true
-
render partial: "biomixer", layout: false
end
-# PRIVATE -----------------------------------------
-private
-
- def show_ajax_request
- case params[:callback]
- when 'load' # Load pulls in all the details of a node
- gather_details
- render :partial => 'load'
- when 'children' # Children is called only for drawing the tree
- @children = @concept.explore.children(pagesize: 750, concept_schemes: @schemes.join(',')).collection || []
- @children.sort! { |x, y| (x.prefLabel || "").downcase <=> (y.prefLabel || "").downcase } unless @children.empty?
- render :partial => 'child_nodes'
- end
- end
- # gathers the full set of data for a node
- def show_uri_request
- gather_details
- build_tree
- end
+ private
+
- def gather_details
- @notes = @concept.explore.notes
- update_tab(@ontology, @concept.id) #updates the 'history' tab with the current node
- end
- def build_tree
- # find path to root
- rootNode = @concept.explore.tree(include: "prefLabel,hasChildren,obsolete,subClassOf")
- @root = LinkedData::Client::Models::Class.new(read_only: true)
- @root.children = rootNode unless rootNode.nil?
- end
def filter_concept_with_no_date(concepts)
concepts.filter { |c| !concept_date(c).nil?}
diff --git a/app/controllers/concerns/ontology_content_serializer.rb b/app/controllers/concerns/ontology_content_serializer.rb
new file mode 100644
index 000000000..2d7dc1904
--- /dev/null
+++ b/app/controllers/concerns/ontology_content_serializer.rb
@@ -0,0 +1,46 @@
+# frozen_string_literal: true
+
+module OntologyContentSerializer
+ extend ActiveSupport::Concern
+
+ def serialize_content(ontology_acronym:, concept_id:, format:)
+ if ontology_acronym && concept_id
+ @format = format
+ @result = ""
+ @acronym = ontology_acronym
+
+ @format = 'ntriples' if format.eql?('html')
+
+ url = content_finder_url(ontology_acronym, concept_id)
+ accept_header = content_finder_accept_header(@format)
+ conn = Faraday.new(url: url) do |faraday|
+ faraday.headers['Accept'] = accept_header
+ faraday.adapter Faraday.default_adapter
+ faraday.headers['Authorization'] = "apikey token=#{get_apikey}"
+ end
+ response = conn.get
+ @result = response.body.force_encoding(Encoding::UTF_8)
+ end
+ [@result, accept_header]
+ end
+
+ def content_finder_url(acronym, uri)
+ URI.parse("#{rest_url}/ontologies/#{acronym.strip}/resolve/#{helpers.escape(uri.strip)}")
+ end
+
+ def content_finder_accept_header(output_format)
+ case output_format
+ when 'json', 'application/json', 'application/ld+json', 'application/*'
+ 'application/ld+json'
+ when 'xml', 'text/xml', 'text/rdf+xml', 'application/rdf+xml', 'application/xml'
+ 'application/rdf+xml'
+ when 'ntriples', 'application/n-triples', '*/*', 'text/*', 'text/n3'
+ 'application/n-triples'
+ when 'turtle', 'text/turtle'
+ 'text/turtle'
+ else
+ output_format
+ end
+ end
+
+end
diff --git a/app/controllers/concerns/ontology_updater.rb b/app/controllers/concerns/ontology_updater.rb
new file mode 100644
index 000000000..71672178c
--- /dev/null
+++ b/app/controllers/concerns/ontology_updater.rb
@@ -0,0 +1,106 @@
+module OntologyUpdater
+ extend ActiveSupport::Concern
+ include SubmissionUpdater
+ include TurboHelper
+
+ def update_existent_ontology(acronym)
+ @ontology = LinkedData::Client::Models::Ontology.find_by_acronym(acronym).first
+ return nil if @ontology.nil?
+
+ new_values = ontology_params
+ new_values.each do |key, values|
+ @ontology.send("#{key}=", values)
+ rescue StandardError
+ next
+ end
+ [@ontology, @ontology.update(values: new_values, cache_refresh_all: false)]
+ end
+
+ def ontology_from_params
+ ontology = LinkedData::Client::Models::Ontology.new(values: ontology_params)
+ ontology.viewOf = nil unless ontology.isView
+ ontology
+ end
+
+ def ontology_params
+ return {} unless params[:ontology]
+
+ p = params.require(:ontology).permit(:name, :acronym, { administeredBy: [] }, :viewingRestriction, { acl: [] },
+ { hasDomain: [] }, :viewOf, :isView, :subscribe_notifications, { group: [] })
+
+ p[:administeredBy].reject!(&:blank?) if p[:administeredBy]
+ # p[:acl].reject!(&:blank?)
+ p[:hasDomain].reject!(&:blank?) if p[:hasDomain]
+ p[:group].reject!(&:blank?) if p[:group]
+ p[:viewOf] = '' if p.key?(:viewOf) && !p.key?(:isView)
+ p.to_h
+ end
+
+ def show_new_errors(object, redirection = 'ontologies/new')
+ # TODO optimize
+ @ontologies = LinkedData::Client::Models::Ontology.all(include: 'acronym', include_views: true, display_links: false, display_context: false)
+ @categories = LinkedData::Client::Models::Category.all
+ @groups = LinkedData::Client::Models::Group.all(display_links: false, display_context: false)
+ @user_select_list = LinkedData::Client::Models::User.all.map { |u| [u.username, u.id] }
+ @user_select_list.sort! { |a, b| a[1].downcase <=> b[1].downcase }
+ @errors = response_errors(object)
+ @selected_attributes = (Array(errors_attributes) + Array(params[:submission]&.keys)).uniq
+ @ontology = ontology_from_params if @ontology.nil?
+
+ @submission = submission_from_params(params[:submission]) if params[:submission] && @submission.nil?
+ reset_agent_attributes
+ if redirection.is_a?(Hash) && redirection[:id]
+ render_turbo_stream replace(redirection[:id], partial: redirection[:partial])
+ else
+ render redirection, status: 422
+ end
+ end
+
+ def errors_attributes
+ @errors = @errors[:error] if @errors && @errors[:error]
+ @errors.keys.map(&:to_s) if @errors.is_a?(Hash)
+ end
+
+ def new_submission_hash(ontology, submission = nil)
+ @submission = submission
+ new_submission_params = submission_params(params[:submission])
+
+ if @submission
+ old_submission_values = @submission.to_hash.delete_if { |k, v| !copyable_submission_params?(k, v)}
+ new_submission_params = ActionController::Parameters.new(old_submission_values.merge(new_submission_params))
+ new_submission_params = submission_params(new_submission_params)
+ end
+
+ new_submission_params.delete 'submissionId'
+ new_submission_params[:ontology] = ontology.acronym
+ ActionController::Parameters.new(new_submission_params)
+ end
+
+ def update_submission_hash(acronym)
+ submission_params = submission_params(params[:submission])
+ submission_params[:ontology] = acronym
+ submission_params
+ end
+
+ private
+ def reset_agent_attributes
+ helpers.agent_attributes.each do |attr|
+ current_val = @submission[attr]
+ new_values = Array(current_val).map { |x| LinkedData::Client::Models::Agent.find(x.split('/').last) }
+
+ new_values = new_values.first unless current_val.is_a?(Array)
+
+ @submission[attr] = new_values
+ end
+ end
+
+ def copyable_submission_params?(key, value)
+ return false if value.nil? || (value.respond_to?(:empty?) && value.empty?)
+
+ attr_to_not_copy = [:versionIRI, :version, :deprecated, :valid, :curatedOn,
+ :pullLocation, :metadataVoc, :hasPriorVersion, :creationDate,
+ :submissionStatus]
+
+ !attr_to_not_copy.include?(key.to_sym)
+ end
+end
diff --git a/app/controllers/concerns/search_aggregator.rb b/app/controllers/concerns/search_aggregator.rb
new file mode 100644
index 000000000..c18e70ce4
--- /dev/null
+++ b/app/controllers/concerns/search_aggregator.rb
@@ -0,0 +1,230 @@
+module SearchAggregator
+ include UrlsHelper
+ extend ActiveSupport::Concern
+ BLACKLIST_FIX_STR = [
+ "https://",
+ "http://",
+ "bioportal.bioontology.org/ontologies/",
+ "purl.bioontology.org/ontology/",
+ "purl.obolibrary.org/obo/",
+ "swrl.stanford.edu/ontologies/",
+ "mesh.owl" # Avoids RH-MESH subordinate to MESH
+ ]
+
+ BLACKLIST_REGEX = [
+ /abnormalities/i,
+ /biological/i,
+ /biology/i,
+ /bioontology/i,
+ /clinical/i,
+ /extension/i,
+ /\.gov/i,
+ /ontology/i,
+ /ontologies/i,
+ /semanticweb/i
+ ]
+
+ def aggregate_results(query, results)
+ ontologies = aggregate_by_ontology(results)
+ grouped_results = add_subordinate_ontologies(query, ontologies)
+ all_ontologies = LinkedData::Client::Models::Ontology.all(include: 'acronym,name', include_views: true, display_links: false, display_context: false)
+
+ grouped_results.map do |group|
+ format_search_result(group, all_ontologies)
+ end
+ end
+
+ def format_search_result(result, ontologies)
+ same_ont = result[:same_ont]
+ same_cls = result[:sub_ont]
+ result = same_ont.shift
+ ontology = result.links['ontology'].split('/').last
+ {
+ root: search_result_elem(result, ontology, ontology_name_acronym(ontologies, ontology)),
+ descendants: same_ont.map { |x| search_result_elem(x, ontology, '') },
+ reuses: same_cls.map do |x|
+ format_search_result(x, ontologies)
+ end
+ }
+ end
+
+ private
+
+ def search_result_elem(class_object, ontology_acronym, title)
+ label = concept_label(class_object.prefLabel)
+ {
+ uri: class_object.id.to_s,
+ title: title.empty? ? label : "#{label} - #{title}",
+ ontology_acronym: ontology_acronym,
+ link: "/ontologies/#{ontology_acronym}?p=classes&conceptid=#{escape(class_object.id)}#{helpers.request_lang&.eql?("ALL") ? '' : "&language="+helpers.request_lang.to_s}",
+ definition: Array(class_object.definition)
+ }
+ end
+
+ def concept_label(pref_labels_list, obsolete = false, max_length = 60)
+ # select closest to query
+ selected = pref_labels_list.select do |pref_lab|
+ pref_lab.downcase.include?(@search_query.downcase) || @search_query.downcase.include?(pref_lab.downcase)
+ end.first
+
+ selected ||= (pref_labels_list&.first || '')
+
+ selected = selected[0..max_length] if selected.size > max_length
+ selected = "#{selected} ".html_safe if obsolete
+ selected
+ end
+
+ def ontology_name_acronym(ontologies, selected_acronym)
+ ontology = ontologies.select { |x| x.acronym.eql?(selected_acronym.split('/').last) }.first
+ "#{ontology.name} (#{ontology.acronym})"
+ end
+
+ def aggregate_by_ontology(results)
+ ontologies = {}
+
+ results.each do |res|
+ ont = res.links['ontology']
+ unless ontologies[ont]
+ ontologies[ont] = {
+ # classes with same URI
+ same_cls: [],
+ # other classes from the same ontology
+ same_ont: [],
+ # subordinate ontologies
+ sub_ont: []
+ }
+ end
+ ontologies[ont][:same_ont] << res
+ end
+ ontologies.values
+ end
+
+ def add_subordinate_ontologies(query, ontologies)
+ # get for each concept his main ontology parent
+ concepts_ontology_owner = extract_concepts_owners(ontologies, query)
+
+ # aggregate the subordinate results below the owner ontology results
+ subordinate_ontologies = []
+ ontologies.each_with_index do |ont, i|
+ cls_id = ont[:same_ont].first["@id"]
+
+ if concepts_ontology_owner.has_key?(cls_id)
+ # get the ontology that owns this class (if any)
+ ont_owner = concepts_ontology_owner[cls_id]
+ if ont_owner[:index].eql?(i)
+ # the current ontology is the owner of this primary result
+ subordinate_ontologies.push(ont)
+ else
+ # There is an owner, so put this ont result set into the sub_ont array of the owner
+ real_owner = ontologies[ont_owner[:index]]
+ real_owner[:sub_ont].push(ont)
+ end
+ else
+ # There is no ontology that owns this primary class result, just
+ # display this at the top level (it's not a subordinate)
+ subordinate_ontologies.push(ont)
+ end
+ end
+ subordinate_ontologies
+ end
+
+ def extract_concepts_owners(ontologies, query)
+ cls_ont_owner_tracker = {}
+ ontologies.each do |ont|
+ ont[:sub_ont] = [] # array for any subordinate ontology results regrouping the concept reuses
+
+ cls_id = ont[:same_ont].first["@id"]
+ next if cls_ont_owner_tracker.has_key?(cls_id)
+
+ # find the best match for the ontology owner (must iterate over all acronyms)
+ ont_owner = ontology_owner_of_class(cls_id, ontologies, query)
+
+ # This primary class result is owned by an ontology
+ cls_ont_owner_tracker[cls_id] = ont_owner if ont_owner[:index]
+ end
+ cls_ont_owner_tracker
+ end
+
+ def extract_back_list_words(acronyms, query)
+ blacklist_words = []
+ query.split(/\s+/).each_with_index do |search_word, i|
+ # Convert blacklist_search_words_arr to regex constructs so they are removed
+ # with case-insensitive matches in blacklist_cls_id_components
+ blacklist_words.push(Regexp.new(search_word, Regexp::IGNORECASE))
+
+ # Check for any substring matches against ontology acronyms, where the
+ # acronyms are assumed to be upper case strings.
+ # Note: We cannot use the ont_acronyms array .index method because it doesn't search for substring matches.
+ search_token = search_word
+ match = false
+
+ acronyms.each do |acronym|
+ match = acronym.include?(search_token)
+ break if match
+ end
+
+ # Remove this blacklisted search token because it matches or partially matches an ontology acronym.
+ blacklist_words.delete_at(i) if match
+ end
+ blacklist_words
+ end
+
+ def ontology_owner_of_class(cls_id, ontologies, query)
+ acronyms = ontologies.map { |ont| ont[:same_ont].first.links['ontology'].split('/').last }
+
+ # Remove any items in blacklistSearchWordsArr that match ontology acronyms.
+ # TODO make sure this is really useful
+ blacklist_words = extract_back_list_words(acronyms, query)
+
+ ont_owner = {
+ acronym: "",
+ index: nil,
+ weight: 0
+ }
+
+ acronyms.each_with_index do |acronym, i|
+ if ontology_own_class?(cls_id, acronym, blacklist_words)
+ weight = acronym.size * (cls_id.upcase.rindex(acronym) + 1)
+ if weight > ont_owner[:weight]
+ ont_owner = {
+ acronym: acronym,
+ index: i,
+ weight: weight
+ }
+ # Cannot break here, in case another acronym has greater weight.
+ end
+ end
+ end
+
+ ont_owner
+ end
+
+ def ontology_own_class?(cls_id, acronym, blacklist_words)
+ cls_id = blacklist_cls_id_components(cls_id.dup, blacklist_words)
+
+ cls_id.upcase.include?(acronym)
+ end
+
+ def blacklist_cls_id_components(cls_id, blacklist_words)
+
+ stripped_id = cls_id
+
+ # Remove fixed strings first
+ BLACKLIST_FIX_STR.each do |fixed_str|
+ stripped_id.gsub!(fixed_str, "")
+ end
+
+ # Cleanup with regex replacements
+ BLACKLIST_REGEX.each do |regex|
+ stripped_id.gsub!(regex, "")
+ end
+
+ # Remove search keywords (see perform_search and aggregate_results_with_subordinate_ontologies)
+ blacklist_words.each do |search_word_regex|
+ stripped_id.gsub!(search_word_regex, "")
+ end
+
+ stripped_id
+ end
+end
+
diff --git a/app/controllers/concerns/search_content.rb b/app/controllers/concerns/search_content.rb
new file mode 100644
index 000000000..e8fd48a59
--- /dev/null
+++ b/app/controllers/concerns/search_content.rb
@@ -0,0 +1,181 @@
+module SearchContent
+ extend ActiveSupport::Concern
+
+ def search_ontologies(query: '*', groups: [], categories: [], languages: [], private_only: false, formats: [],
+ is_of_type: [], formality_level: [],
+ show_views: false, status: 'alpha,beta,production',
+ page: 1, page_size: 10)
+
+ visibility = private_only ? "private" : 'public'
+ qf = [
+ "ontology_acronymSuggestEdge^25 ontology_nameSuggestEdge^15 descriptionSuggestEdge^10 ", # start of the word first
+ "ontology_acronym_text^15 ontology_name_text^10 description_text^5 "
+ ]
+ submissions = LinkedData::Client::HTTP.get('search/ontologies',
+ { query: query.blank? ? "*" : query,
+ groups: groups,
+ hasDomain: categories,
+ hasOntologyLanguage: formats,
+ status: status,
+ page: page, pagesize: page_size,
+ visibility: visibility,
+ isOfType: is_of_type,
+ hasFormat: formality_level,
+ show_views: show_views,
+ qf: qf, # custom ranking
+ languages: languages }
+ .reject { |k, v| v.blank? })
+
+ submissions = submissions.collection
+
+ submissions.map do |os|
+ transformed_os = OpenStruct.new
+ ontology = OpenStruct.new
+ metrics = OpenStruct.new
+ os.each_pair do |key, value|
+ if key.to_s.start_with?("ontology_")
+ ontology[key.to_s.sub("ontology_", "").gsub(/_.*\z/, "")] = value
+ elsif key.to_s.start_with?("metrics_")
+ metrics[key.to_s.sub("metrics_", "").gsub(/_.*\z/, "")] = value
+ elsif key != :links && key != :context
+ new_key = key.to_s.gsub(/_.*\z/, "")
+ transformed_os[new_key] = value
+ end
+ end
+ transformed_os[:ontology] = ontology unless ontology.to_h.empty?
+ transformed_os[:metrics] = metrics unless metrics.to_h.empty?
+ transformed_os
+ end
+ end
+
+ def search_ontologies_content(query:, page: 1, page_size: 10, filter_by_ontologies: [], filter_by_types: [])
+ acronyms = filter_by_ontologies
+ original_query = query
+ types = filter_by_types
+ query = query.gsub(':', '\:').gsub('/', '\/') if page.eql?(1)
+
+ qf = [
+ "ontology_t^100 resource_id^10",
+ "http___www.w3.org_2004_02_skos_core_prefLabel_txt^30",
+ "http___www.w3.org_2004_02_skos_core_prefLabel_t^30",
+ "http___www.w3.org_2000_01_rdf-schema_label_txt^30",
+ "http___www.w3.org_2000_01_rdf-schema_label_t^30",
+ ]
+ ontologies = LinkedData::Client::Models::Ontology.all(include: 'acronym,name,viewOf', also_include_views: true)
+ selected_onto = []
+
+ q = query.split(' ').first || ''
+ selected_onto += ontologies.select { |x| (acronyms.empty? && x.acronym.downcase.eql?(q.downcase)) || acronyms.include?(x.acronym) }
+
+ selected_onto.uniq!
+ [selected_onto.first].compact.each do |o|
+ acr = o.acronym
+ acronyms << acr
+ query.gsub!(/\b#{acr}\b/, "")
+ query.gsub!(/\b#{acr.downcase}\b/, "")
+ query.gsub!('-', " ")
+ end
+
+ query = query
+ if query.blank?
+ query = "*"
+ elsif query.split(' ').size > 1
+ query = "^#{query}*"
+ else
+ query = "*#{query}*"
+ end
+
+ results = search_content( q: query, qf: qf.join(' '), page: page, pagesize: page_size, ontologies: acronyms.first, types: types.join(','))
+ [search_content_result_to_json(original_query, query, results, ontologies, selected_onto), results.page,results.nextPage, results.totalCount]
+ end
+
+
+
+ def search_content(params)
+ LinkedData::Client::HTTP.get('search/ontologies/content', params)
+ end
+
+ private
+
+ def search_content_result_to_json(query, changed_query, results, ontologies, selected_onto = [])
+ json = []
+ selected_onto = selected_onto.empty? ? ontologies.select { |x| x.name.downcase.include?(query.downcase) || x.acronym.downcase.include?(query.downcase) } : selected_onto
+
+ json += selected_onto.map do |x|
+ {
+ id: ontology_path(id: x.acronym, p: 'summary'),
+ name: x.name,
+ acronym: x.acronym,
+ type: x.viewOf.blank? ? 'Ontology' : 'Ontology View',
+ label: nil
+ }
+ end
+
+ changed_query.gsub!('*', '')
+
+ json += results.collection.map do |x|
+ acronym = x.ontology_t || x.submission_id_t.split('/')[-3]
+ next nil unless acronym
+
+ label = nil
+ [
+ "http___www.w3.org_2000_01_rdf-schema_label_t",
+ "http___www.w3.org_2000_01_rdf-schema_label_txt",
+ "http___www.w3.org_2004_02_skos_core_prefLabel_t",
+ "http___www.w3.org_2004_02_skos_core_prefLabel_txt",
+ ].each do |v|
+ v = Array(x[v])
+ selected_label = v&.select { |p| p.downcase[changed_query.strip.downcase] || changed_query.downcase[p.strip.downcase] }&.first
+ label = selected_label if selected_label
+ label ||= v&.first
+ end
+
+
+ type = id_type(x.type_t, x.type_txt)
+ {
+ id: link_by_type(x.resource_id, acronym, type),
+ name: x.resource_id,
+ acronym: acronym,
+ type: type || '',
+ label: label
+ }
+ end.compact
+
+ json
+ end
+
+ def supported_types
+ %w[Concept Class Ontology ConceptScheme Collection NamedIndividual AnnotationProperty ObjectProperty DatatypeProperty]
+ end
+
+ def id_type(type_t, type_txt)
+
+ type = (Array(type_t) + Array(type_txt)).map { |x| helpers.link_last_part(x) }
+ .select{|x| supported_types.include?(x)}
+
+ type = Array(type).reject { |x| x.eql?("NamedIndividual") } if (Array(type).size > 1)
+
+ type.first
+ end
+
+ def link_by_type(id, ontology, type)
+ case type
+ when 'Concept', 'Class'
+ ontology_path(id: ontology, p: 'classes', conceptid: id)
+ when 'Ontology'
+ ontology_path(id: ontology, p: 'summary')
+ when 'ConceptScheme'
+ ontology_path(id: ontology, p: 'schemes', schemeid: id)
+ when 'Collection'
+ ontology_path(id: ontology, p: 'collections', collectionid: id)
+ when 'NamedIndividual'
+ ontology_path(id: ontology, p: 'instances', instanceid: id)
+ when 'AnnotationProperty', 'ObjectProperty', 'DatatypeProperty'
+ ontology_path(id: ontology, p: 'properties', propertyid: id)
+ else
+ "/content_finder?acronym=#{ontology}&uri=#{helpers.escape(id)}&output_format=html"
+ end
+ end
+
+end
+
diff --git a/app/controllers/concerns/submission_filter.rb b/app/controllers/concerns/submission_filter.rb
new file mode 100644
index 000000000..44d4f6e52
--- /dev/null
+++ b/app/controllers/concerns/submission_filter.rb
@@ -0,0 +1,383 @@
+module SubmissionFilter
+ extend ActiveSupport::Concern
+
+ include SearchContent
+
+ BROWSE_ATTRIBUTES = ['ontology', 'submissionStatus', 'description', 'pullLocation', 'creationDate',
+ 'contact', 'released', 'naturalLanguage', 'hasOntologyLanguage',
+ 'hasFormalityLevel', 'isOfType', 'deprecated', 'status', 'metrics']
+
+ def init_filters(params)
+ @show_views = params[:show_views]&.eql?('true')
+ @show_private_only = params[:private_only]&.eql?('true')
+ @show_retired = params[:show_retired]&.eql?('true')
+ @selected_format = params[:format]
+ @sort_by = params[:sort_by].blank? ? 'visits' : params[:sort_by]
+ @search = params[:search]
+ end
+
+ def submissions_paginate_filter(params)
+ request_params = filters_params(params, page: params[:page], pagesize: 10)
+ filter_params = params.permit(@filters.keys).to_h
+ init_filters(params)
+
+ @analytics = Rails.cache.fetch("ontologies_analytics-#{Time.now.year}-#{Time.now.month}") do
+ helpers.ontologies_analytics
+ end
+
+ @ontologies = LinkedData::Client::Models::Ontology.all(include: 'all', also_include_views: true, display_links: false, display_context: false)
+
+ # get fair scores of all ontologies
+ @fair_scores = fairness_service_enabled? ? get_fair_score('all') : nil
+
+ @total_ontologies = @ontologies.size
+ search_backend = params[:search_backend]
+ params = { query: @search,
+ status: request_params[:status],
+ show_views: @show_views,
+ private_only: @show_private_only,
+ languages: request_params[:naturalLanguage],
+ page_size: @total_ontologies,
+ formality_level: request_params[:hasFormalityLevel],
+ is_of_type: request_params[:isOfType],
+ groups: request_params[:group], categories: request_params[:hasDomain],
+ formats: request_params[:hasOntologyLanguage] }
+
+
+ if search_backend.eql?('index')
+ submissions = filter_using_index(**params)
+ submissions = @ontologies.map{ |ont| ontology_hash(ont, submissions) }
+ else
+ submissions = filter_using_data(@ontologies, **params)
+ end
+
+ submissions = sort_submission_by(submissions, @sort_by, @search)
+
+
+ @page = paginate_submissions(submissions, request_params[:page].to_i, request_params[:pagesize].to_i)
+
+ count = @page.page.eql?(1) ? count_objects(submissions) : {}
+
+ [@page.collection, @page.totalCount, count, filter_params]
+ end
+
+ def ontologies_filter_url(filters, page: 1, count: false)
+ helpers.ontologies_filter_url(filters, page: page, count: count)
+ end
+
+ private
+
+ def filter_using_index(query:, status:, show_views:, private_only:, languages:, page_size:, formality_level:, is_of_type:, groups:, categories:, formats:)
+ search_ontologies(
+ query: query,
+ status: status,
+ show_views: show_views,
+ private_only: private_only,
+ languages: languages,
+ page_size: page_size,
+ formality_level: formality_level,
+ is_of_type: is_of_type,
+ groups: groups, categories: categories,
+ formats: formats
+ )
+
+ end
+
+ def filter_using_data(ontologies, query:, status:, show_views:, private_only:, languages:, page_size:, formality_level:, is_of_type:, groups:, categories:, formats:)
+ submissions = LinkedData::Client::Models::OntologySubmission.all(include: BROWSE_ATTRIBUTES.join(','), also_include_views: true, display_links: false, display_context: false)
+ submissions = ontologies.map { |ont| ontology_hash(ont, submissions) }
+
+ submissions.map do |s|
+ out = ((s.ontology.viewingRestriction.eql?('public') && !private_only) || private_only && s.ontology.viewingRestriction.eql?('private'))
+ out = out && (groups.blank? || (s.ontology.group.map { |x| helpers.link_last_part(x) } & groups.split(',')).any?)
+ out = out && (categories.blank? || (s.ontology.hasDomain.map { |x| helpers.link_last_part(x) } & categories.split(',')).any?)
+ out = out && (status.blank? || status.eql?('alpha,beta,production,retired') || status.split(',').include?(s.status))
+ out = out && (formats.blank? || formats.split(',').any? { |f| s.hasOntologyLanguage.eql?(f) })
+ out = out && (is_of_type.blank? || is_of_type.split(',').any? { |f| helpers.link_last_part(s.isOfType).eql?(f) })
+ out = out && (formality_level.blank? || formality_level.split(',').any? { |f| helpers.link_last_part(s.hasFormalityLevel).eql?(f) })
+ out = out && (languages.blank? || languages.split(',').any? { |f| s.naturalLanguage.any? { |n| helpers.link_last_part(n).eql?(f) } })
+ out = out && (s.ontology.viewOf.blank? || (show_views && !s.ontology.viewOf.blank?))
+
+ out = out && (query.blank? || [s.description, s.ontology.name, s.ontology.acronym].any? { |x| (x|| '').downcase.include?(query.downcase) })
+
+ if out
+ s[:rank] = 0
+
+ next s if query.blank?
+
+ s[:rank] += 3 if s.ontology.acronym && s.ontology.acronym.downcase.include?(query.downcase)
+
+ s[:rank] += 2 if s.ontology.name && s.ontology.name.downcase.include?(query.downcase)
+
+ s[:rank] += 1 if s.description && s.description.downcase.include?(query.downcase)
+
+ s
+ else
+ nil
+ end
+
+ end.compact
+ end
+
+ def paginate_submissions(all_submissions, page, size)
+ current_page = page
+ page_size = size
+
+ start_index = (current_page - 1) * page_size
+ end_index = start_index + page_size - 1
+ next_page = current_page * page_size < all_submissions.size ? current_page + 1 : nil
+ OpenStruct.new(page: current_page, nextPage: next_page, totalCount: all_submissions.size,
+ collection: all_submissions[start_index..end_index])
+ end
+
+ def sort_submission_by(submissions, sort_by, query = nil)
+ return submissions.sort_by { |x| x[:rank] ? -x[:rank] : 0} unless query.blank?
+
+ if sort_by.eql?('visits')
+ submissions = submissions.sort_by { |x| -(x[:popularity] || 0) }
+ elsif sort_by.eql?('fair')
+ submissions = submissions.sort_by { |x| -x[:fairScore] }
+ elsif sort_by.eql?('notes')
+ submissions = submissions.sort_by { |x| -x[:note_count] }
+ elsif sort_by.eql?('projects')
+ submissions = submissions.sort_by { |x| -x[:project_count] }
+ elsif sort_by.eql?('metrics_classes')
+ submissions = submissions.sort_by { |x| -x[:class_count] }
+ elsif sort_by.eql?('metrics_individuals')
+ submissions = submissions.sort_by { |x| -x[:individual_count] }
+ elsif sort_by.eql?('creationDate')
+ submissions = submissions.sort_by { |x| x[:creationDate] || '' }.reverse
+ elsif sort_by.eql?('released')
+ submissions = submissions.sort_by { |x| x[:released] || '' }.reverse
+ elsif sort_by.eql?('ontology_name')
+ submissions = submissions.sort_by { |x| -x[:name] }
+ end
+ submissions
+ end
+
+ def filters_params(params, includes: BROWSE_ATTRIBUTES.join(','), page: 1, pagesize: 5)
+ request_params = { display_links: false, display_context: false,
+ include: includes, include_status: 'RDF' }
+ request_params.merge!(page: page.to_i, pagesize: pagesize.to_i) if page
+ filters_values_map = {
+ categories: :hasDomain,
+ groups: :group,
+ naturalLanguage: :naturalLanguage,
+ isOfType: :isOfType,
+ format: :hasOntologyLanguage,
+ hasFormalityLevel: :hasFormalityLevel,
+ search: %i[name acronym description],
+ sort_by: :order_by
+ }
+
+ filters_boolean_map = {
+ show_views: { api_key: :also_include_views, default: 'true' },
+ private_only: { api_key: :viewingRestriction, default: 'private' },
+ show_retired: { api_key: :status, default: 'retired' }
+ }
+ @filters = {}
+
+ filters_boolean_map.each do |k, v|
+ next unless params[k].eql?('true') || params[k].eql?(v[:default])
+
+ @filters.merge!(k => v[:default])
+ request_params.merge!(v[:api_key] => v[:default])
+ end
+
+ if params[:show_retired].blank?
+ @filters[:show_retired] = ''
+ request_params[:status] = 'alpha,beta,production'
+ else
+ request_params[:status] = 'alpha,beta,production,retired'
+ @filters[:show_retired] = 'true'
+ end
+
+ filters_values_map.each do |filter, api_key|
+ next if params[filter].nil? || params[filter].empty?
+
+ @filters.merge!(filter => params[filter])
+ Array(api_key).each do |key|
+ request_params.merge!(key => params[filter])
+ end
+ end
+
+ unless params[:sort_by].blank?
+ @filters[:sort_by] = params[:sort_by]
+ end
+
+ unless params[:search].blank?
+ @filters[:search] = params[:search]
+ end
+
+ request_params.delete(:order_by) if %w[visits fair].include?(request_params[:sort_by].to_s)
+ request_params
+ end
+
+ def ontology_hash(ont, submissions)
+ o = {}
+ sub = submissions.select{|x| x.ontology&.id.eql?(ont.id)}.first
+
+ o[:ontology] = ont
+
+ add_ontology_attributes(o, ont)
+ add_submission_attributes(o, sub)
+ add_fair_score_metrics(o, ont)
+
+ o[:hasOntologyLanguage] = sub&.hasOntologyLanguage
+
+ if sub&.metrics
+ o[:class_count] = sub.metrics.classes
+ o[:individual_count] = sub.metrics.individuals
+ else
+ o[:class_count] = 0
+ o[:individual_count] = 0
+ end
+ o[:class_count_formatted] = number_with_delimiter(o[:class_count], delimiter: ',')
+ o[:individual_count_formatted] = number_with_delimiter(o[:individual_count], delimiter: ',')
+
+ o[:note_count] = ont.notes&.length || 0
+ o[:project_count] = ont.projects&.length || 0
+ o[:popularity] = @analytics[ont.acronym] || 0
+ o[:rank] = sub&[:rank] || 0
+
+ OpenStruct.new(o)
+ end
+
+ def add_submission_attributes(ont_hash, sub)
+ return if sub.nil?
+
+ ont_hash[:submissionStatus] = sub.submissionStatus
+ ont_hash[:deprecated] = sub.deprecated
+ ont_hash[:status] = sub.status
+ ont_hash[:submission] = true
+ ont_hash[:pullLocation] = sub.pullLocation
+ ont_hash[:description] = sub.description
+ ont_hash[:creationDate] = sub.creationDate
+ ont_hash[:released] = sub.released
+ ont_hash[:naturalLanguage] = sub.naturalLanguage
+ ont_hash[:hasFormalityLevel] = sub.hasFormalityLevel
+ ont_hash[:isOfType] = sub.isOfType
+ ont_hash[:submissionStatusFormatted] = submission_status2string(sub).gsub(/\(|\)/, '')
+ ont_hash[:format] = sub.hasOntologyLanguage&.split('/').last
+ ont_hash[:contact] = sub.contact.map { |c| c.is_a?(String) ? c.split('|').first : c.name }.first unless sub.contact.nil?
+ end
+
+ def add_ontology_attributes(ont_hash, ont)
+ return if ont.nil?
+
+ ont_hash[:id] = ont.id
+ ont_hash[:type] = ont.viewOf.nil? ? 'ontology' : 'ontology_view'
+ ont_hash[:show] = ont.viewOf.nil? ? true : false # show ontologies only by default
+ ont_hash[:groups] = ont.group || []
+ ont_hash[:categories] = ont.hasDomain || []
+ ont_hash[:private] = ont.private?
+ ont_hash[:submissionStatus] = []
+ ont_hash[:administeredBy] = ont.administeredBy
+ ont_hash[:name] = ont.name
+ ont_hash[:acronym] = ont.acronym
+ ont_hash[:projects] = ont.projects
+ ont_hash[:notes] = ont.notes
+ ont_hash[:viewOfOnt] = ont.viewOf
+ end
+
+ def add_fair_score_metrics(ont_hash, ont)
+ if !@fair_scores.nil? && !@fair_scores[ont.acronym].nil?
+ ont_hash[:fairScore] = @fair_scores[ont.acronym]['score']
+ ont_hash[:normalizedFairScore] = @fair_scores[ont.acronym]['normalizedScore']
+ else
+ ont_hash[:fairScore] = 0
+ ont_hash[:normalizedFairScore] = 0
+ end
+ end
+
+ def ontology_filters_init(categories, groups)
+ @languages = submission_metadata.select { |x| x['@id']['naturalLanguage'] }.first['enforcedValues'].map do |id, name|
+ { 'id' => id, 'name' => name, 'value' => id.split('/').last, 'acronym' => name }
+ end
+
+ @formalityLevel = submission_metadata.select { |x| x['@id']['hasFormalityLevel'] }.first['enforcedValues'].map do |id, name|
+ { 'id' => id, 'name' => helpers.link_last_part(id), 'acronym' => name, 'value' => helpers.link_last_part(id) }
+ end
+
+ @isOfType = submission_metadata.select { |x| x['@id']['isOfType'] }.first['enforcedValues'].map do |id, name|
+ { 'id' => id, 'name' => helpers.link_last_part(id), 'acronym' => name, 'value' => helpers.link_last_part(id) }
+ end
+
+ @formats = [[t("submissions.filter.all_formats"), ''], 'OBO', 'OWL', 'SKOS', 'UMLS']
+ @sorts_options = [
+ [t("submissions.filter.sort_by_name"), 'ontology_name'],
+ [t("submissions.filter.sort_by_classes"), 'metrics_classes'],
+ [t("submissions.filter.sort_by_instances_concepts"), 'metrics_individuals'],
+ [t("submissions.filter.sort_by_submitted_date"), 'creationDate'],
+ [t("submissions.filter.sort_by_creation_date"), 'released'],
+ [t("submissions.filter.sort_by_fair_score"), 'fair'],
+ [t("submissions.filter.sort_by_popularity"), 'visits'],
+ [t("submissions.filter.sort_by_notes"), 'notes'],
+ [t("submissions.filter.sort_by_projects"), 'projects'],
+ ]
+
+ init_filters(params)
+ # @missingStatus = [
+ # {'id' => 'RDF', 'name' => 'RDF', 'acronym' => 'RDF'},
+ # {'id' => 'ABSOLETE', 'name' => 'ABSOLETE', 'acronym' => 'ABSOLETE'},
+ # {'id' => 'METRICS', 'name' => 'METRICS', 'acronym' => 'METRICS'},
+ # {'id' => 'RDF_LABELS', 'name' => 'RDF LABELS', 'acronym' => 'RDFLABELS'},
+ # {'id' => 'UPLOADED', 'name' => 'UPLOADED', 'acronym' => 'UPLOADED'},
+ # {'id' => 'INDEXED_PROPERTIES', 'name' => 'INDEXED PROPERTIES', 'acronym' => 'INDEXED_PROPERTIES'},
+ # {'id' => 'ANNOTATOR', 'name' => 'ANNOTATOR', 'acronym' => 'ANNOTATOR'},
+ # {'id' => 'DIFF', 'name' => 'DIFF', 'acronym' => 'DIFF'}
+ # ]
+
+ {
+ categories: object_filter(categories, :categories),
+ groups: object_filter(groups, :groups),
+ naturalLanguage: object_filter(@languages, :naturalLanguage, "value"),
+ hasFormalityLevel: object_filter(@formalityLevel, :hasFormalityLevel),
+ isOfType: object_filter(@isOfType, :isOfType, "value"),
+ # missingStatus: object_filter(@missingStatus, :missingStatus)
+ }
+ end
+
+ def check_id(name_value, objects, name_key)
+ selected_category = objects.select { |x| x[name_key].parameterize.underscore.eql?(name_value.parameterize.underscore) }
+ selected_category.first && selected_category.first['id']
+ end
+
+
+ def object_filter(objects, object_name, name_key = 'acronym')
+ checks = params[object_name]&.split(',') || []
+ checks = checks.map { |x| check_id(x, objects, name_key) }.compact
+
+ ids = objects.map { |x| x['id'] }
+ count = ids.count { |x| checks.include?(x) }
+ [objects, checks, count]
+ end
+
+ def count_objects(ontologies)
+ objects_count = {}
+ @categories = LinkedData::Client::Models::Category.all(display_links: false, display_context: false)
+ @groups = LinkedData::Client::Models::Group.all(display_links: false, display_context: false)
+
+ @filters = ontology_filters_init(@categories, @groups)
+ object_names = @filters.keys
+
+ @filters.each do |filter, values|
+ objects = values.first
+ objects_count[filter] = objects.map { |v| [v['id'], 0] }.to_h
+ end
+
+ ontologies.each do |ontology|
+ object_names.each do |name|
+ values = Array(ontology[name])
+ values.each do |v|
+ v.gsub!('http://data.bioontology.org', rest_url)
+
+ objects_count[name] = {} unless objects_count[name]
+ objects_count[name][v] = (objects_count[name][v] || 0) + 1
+ end
+ end
+ end
+ objects_count
+ end
+
+end
diff --git a/app/controllers/concerns/submission_updater.rb b/app/controllers/concerns/submission_updater.rb
index 4f330ad95..0120ef33e 100644
--- a/app/controllers/concerns/submission_updater.rb
+++ b/app/controllers/concerns/submission_updater.rb
@@ -1,24 +1,27 @@
module SubmissionUpdater
extend ActiveSupport::Concern
- def save_submission(new_submission_hash)
+ def submission_from_params(new_submission_hash)
convert_values_to_types(new_submission_hash)
-
- @ontology = LinkedData::Client::Models::Ontology.find_by_acronym(new_submission_hash[:ontology]).first
- @submission = LinkedData::Client::Models::OntologySubmission.new(values: submission_params(new_submission_hash))
+ LinkedData::Client::Models::OntologySubmission.new(values: submission_params(new_submission_hash))
+ end
+ def save_submission(new_submission_hash)
+ @submission = submission_from_params(new_submission_hash)
update_ontology_summary_only
@submission.save(cache_refresh_all: false)
end
- def update_submission(new_submission_hash)
+ def update_submission(new_submission_hash, submission_id , ontology = nil)
convert_values_to_types(new_submission_hash)
- @ontology = LinkedData::Client::Models::Ontology.find_by_acronym(new_submission_hash[:ontology]).first
- @submission = @ontology.explore.submissions({ display: 'all' }, new_submission_hash[:id])
+ @ontology = ontology || LinkedData::Client::Models::Ontology.find_by_acronym(new_submission_hash[:ontology]).first
+ new_submission_hash.delete(:ontology)
+
+ @submission = @ontology.explore.submissions({ include: 'all' }, submission_id)
- new_values = submission_params(new_submission_hash)
+ new_values = new_submission_hash
new_values.each do |key, values|
@submission.send("#{key}=", values)
rescue StandardError
@@ -26,25 +29,53 @@ def update_submission(new_submission_hash)
end
update_ontology_summary_only
- @submission.update(values: new_values, cache_refresh_all: false)
+ [@submission, @submission.update(values: new_values, cache_refresh_all: false)]
+ end
+
+ def add_ontologies_to_object(ontologies,object)
+ ontologies.each do |ont|
+ next if object.ontologies.include?(ont)
+ ontology = LinkedData::Client::Models::Ontology.find(ont)
+ if object.type.match(/\/([^\/]+)$/)[1] == 'Group'
+ ontology.group.push(object.id)
+ else
+ ontology.hasDomain.push(object.id)
+ end
+ ontology.update
+ end
+ end
+
+ def delete_ontologies_from_object(new_ontologies,old_ontologies,object)
+ new_ontologies = [] if new_ontologies.nil?
+ ontologies = old_ontologies - new_ontologies
+ ontologies.each do |ont|
+ ontology = LinkedData::Client::Models::Ontology.find(ont)
+ if object.type.match(/\/([^\/]+)$/)[1] == 'Group'
+ ontology.group.delete(object.id)
+ else
+ ontology.hasDomain.delete(object.id)
+ end
+ ontology.update
+ end
end
private
def update_ontology_summary_only(is_remote = @submission.isRemote)
- @ontology.summaryOnly = is_remote&.eql?('3')
- @ontology.update
+ if is_remote && @ontology.summaryOnly != is_remote.eql?('3')
+ @ontology.update(values: {summaryOnly: is_remote.eql?('3')}, cache_refresh_all: false)
+ end
end
def convert_values_to_types(new_submission_hash)
unless new_submission_hash[:contact].nil?
- new_submission_hash[:contact] = new_submission_hash[:contact].values
+ new_submission_hash[:contact] = new_submission_hash[:contact].values unless new_submission_hash[:contact].is_a?(Array)
new_submission_hash[:contact].delete_if { |c| c[:name].empty? || c[:email].empty? }
end
# Convert metadata that needs to be integer to int
- @metadata.map do |hash|
+ submission_metadata.map do |hash|
if hash["enforce"].include?("integer")
if !new_submission_hash[hash["attribute"]].nil? && !new_submission_hash[hash["attribute"]].eql?("")
new_submission_hash[hash["attribute"].to_s.to_sym] = Integer(new_submission_hash[hash["attribute"].to_s.to_sym])
@@ -83,22 +114,19 @@ def submission_params(params)
{ contact: %i[name email] },
:homepage,
:documentation,
- :publication,
+ {copyrightHolder: {}} # TODO add automatically no list Agents
:identifier,
:is_doi_requested,
]
- @metadata.each do |m|
-
+ submission_metadata.each do |m|
m_attr = m["attribute"].to_sym
-
- attributes << if m["enforce"].include?("list")
- [{ m_attr => {} }, { m_attr => []}]
- else
- m_attr
- end
+ m_attr = Array(m["enforce"]).include?("list") ? [{ m_attr => {} }, { m_attr => []}] : m_attr
+ attributes << m_attr
end
p = params.permit(attributes.uniq)
+ p['pullLocation'] = '' if p['isRemote']&.eql?('3')
+
p = p.to_h.transform_values do |v|
if v.is_a? Hash
v.values.reject(&:empty?)
@@ -109,7 +137,14 @@ def submission_params(params)
end
end
- @metadata.each do |m|
+ if p["copyrightHolder"]&.first&.include?("id") # TODO automatize
+ p["copyrightHolder"] = p["copyrightHolder"].first["id"]
+ elsif p["copyrightHolder"]
+ p["copyrightHolder"] = ''
+ end
+
+
+ submission_metadata.each do |m|
m_attr = m['attribute'].to_sym
if p[m_attr] && m['enforce'].include?('list')
p[m_attr] = Array(p[m_attr]) unless p[m_attr].is_a?(Array)
diff --git a/app/controllers/concerns/uri_redirection.rb b/app/controllers/concerns/uri_redirection.rb
new file mode 100644
index 000000000..9ef86fcd4
--- /dev/null
+++ b/app/controllers/concerns/uri_redirection.rb
@@ -0,0 +1,96 @@
+# frozen_string_literal: true
+
+module UriRedirection
+ extend ActiveSupport::Concern
+
+ include SearchContent
+
+ def find_type_by_id(id, acronym)
+ type, resource_id = find_type_by_search(id, acronym)
+ return type, resource_id if type
+
+ type, resource_id = find_type_by_metadata(id, acronym)
+ return type, resource_id if type
+
+ return nil, nil
+ end
+
+
+ def redirect_to_file?
+ accept_header.nil? || (accept_header != "text/html" && params[:p].nil?)
+ end
+
+ def redirect_to_file
+ # when dont have the specified format in the accept header
+ return not_acceptable("Invalid requested format, valid format are: JSON, XML, HTML and CSV\nto download the original file you can get it from: #{rest_url}/ontologies/#{params[:id]}/download\n") if accept_header.nil?
+
+ # when the format is different than text/html
+ redirect_to_download_file if (accept_header != "text/html" && params[:p].nil?)
+ end
+
+ private
+
+ def find_type_by_search(id, acronym)
+ # search for URIs that ends with "/id" or "#id"
+ result = search_content(q: "*##{id} || *\/#{id}", qf: "resource_id", page: 1, pagesize: 10, ontologies: acronym)
+
+ find_exact_resource = result[:collection].select { |x| helpers.link_last_part(x[:resource_id]).eql?(id) }.first
+
+ if !find_exact_resource
+ type = nil
+ resource_id = nil
+ else
+ type = id_type(find_exact_resource[:type_t], find_exact_resource[:type_txt])
+ resource_id = find_exact_resource[:resource_id]
+ end
+
+ [type, resource_id]
+ end
+
+ def find_type_by_metadata(id, acronym)
+ return nil, nil # TODO maybe implemented if needed
+ end
+
+
+ def not_acceptable(message = nil)
+ render plain: message, status: 406
+ end
+
+ def redirect_to_download_file
+ redirect_to("/ontologies/#{params[:id]}/download?format=#{helpers.escape(accept_header)}", allow_other_host: true)
+ end
+
+
+ def accept_header
+ header = request.env["HTTP_ACCEPT"]
+ entries = header.to_s.split(',')
+ parsed_entries = entries.map { |e| accept_entry(e) }
+ sorted_entries = parsed_entries.sort_by(&:last)
+ content_types = sorted_entries.map(&:first)
+ filtered_content_types = content_types.map { |e| find_content_type_for_media_range(e) }
+ filtered_content_types.flatten.compact.first
+ end
+
+ def accept_entry(entry)
+ type, *options = entry.split(';').map(&:strip)
+ quality = 0
+ options.delete_if { |e| quality = 1 - e[2..-1].to_f if e.start_with? 'q=' }
+ [options.unshift(type).join(';'), [quality, type.count('*'), 1 - options.size]]
+ end
+
+ def find_content_type_for_media_range(media_range)
+ case media_range.to_s
+ when '*/*', 'text/html', 'text/*'
+ 'text/html'
+ when 'application/json', 'application/ld+json', 'application/*'
+ 'application/ld+json'
+ when 'text/xml', 'text/rdf+xml', 'application/rdf+xml', 'application/xml'
+ 'application/rdf+xml'
+ when 'text/csv'
+ 'text/csv'
+ else
+ nil
+ end
+ end
+
+end
\ No newline at end of file
diff --git a/app/controllers/content_finder_controller.rb b/app/controllers/content_finder_controller.rb
new file mode 100644
index 000000000..c387efcf7
--- /dev/null
+++ b/app/controllers/content_finder_controller.rb
@@ -0,0 +1,12 @@
+require 'faraday'
+
+class ContentFinderController < ApplicationController
+ include OntologyContentSerializer
+
+ def index
+ @result, _ = serialize_content(ontology_acronym: params[:acronym],
+ concept_id: params[:uri],
+ format: params[:output_format])
+ render 'content_finder/index', layout: 'tool'
+ end
+end
\ No newline at end of file
diff --git a/app/controllers/errors_controller.rb b/app/controllers/errors_controller.rb
index b5ffb1eec..8b55c7903 100644
--- a/app/controllers/errors_controller.rb
+++ b/app/controllers/errors_controller.rb
@@ -3,10 +3,12 @@ class ErrorsController < ApplicationController
layout :determine_layout
def not_found
+ @referer_url = request.referer
render status: 404
end
def internal_server_error
+ @referer_url = request.referer
render status: 500
end
diff --git a/app/controllers/fair_score_controller.rb b/app/controllers/fair_score_controller.rb
index 9564a5875..8f62995b3 100644
--- a/app/controllers/fair_score_controller.rb
+++ b/app/controllers/fair_score_controller.rb
@@ -28,7 +28,7 @@ def get_fair
@fair_scores_data = create_fair_scores_data(get_fair_score(@ontologies).values.first, 1)
end
rescue NameError
- raise StandardError, 'Error: load failed'
+ #raise StandardError, 'Error: load failed'
end
end
end
\ No newline at end of file
diff --git a/app/controllers/history_controller.rb b/app/controllers/history_controller.rb
deleted file mode 100644
index 687839df5..000000000
--- a/app/controllers/history_controller.rb
+++ /dev/null
@@ -1,15 +0,0 @@
-class HistoryController < ApplicationController
-
- def remove # removes a 'history' tab
- remove_tab(undo_param(params[:ontology]))
- render :text =>"success"
- end
-
- def update # updates the 'history' tab to point to the new node
- ontology = DataAccess.getOntology(params[:ontology])
- update_tab(ontology,params[:concept])
- render :text =>"success"
- end
-
-
-end
diff --git a/app/controllers/home_controller.rb b/app/controllers/home_controller.rb
index 3e6952386..87f9e6e2c 100644
--- a/app/controllers/home_controller.rb
+++ b/app/controllers/home_controller.rb
@@ -7,71 +7,62 @@ class HomeController < ApplicationController
include FairScoreHelper
def index
- @ontologies_views = LinkedData::Client::Models::Ontology.all(include_views: true)
- @ontologies = @ontologies_views.select {|o| !o.viewOf}
- @ontologies_hash = Hash[@ontologies_views.map {|o| [o.acronym, o]}]
- @groups = LinkedData::Client::Models::Group.all
- @notes = LinkedData::Client::Models::Note.all
- @last_notes = []
- unless @notes.empty?
- @notes.sort! {|a,b| b.created <=> a.created }
- @notes[0..20].each do |n|
- ont_uri = n.relatedOntology.first
- ont = LinkedData::Client::Models::Ontology.find(ont_uri)
- next if ont.nil?
- username = n.creator.split("/").last
- note = {
- :uri => n.links['ui'],
- :id => n.id,
- :subject => n.subject,
- :body => n.body,
- :created => n.created,
- :author => username,
- :ont_name => ont.name
- }
- @last_notes.push note
- break if @last_notes.length >= [$HOME_LATEST_NOTES_COUNT.to_i, 5].max
- end
- end
- # Get the latest manual mappings
- # All mapping classes are bidirectional.
- # Each class in the list maps to all other classes in the list.
- if $DISPLAY_RECENT.nil? || $DISPLAY_RECENT == true
- @recent_mappings = get_recent_mappings # application_controller
+ @analytics = helpers.ontologies_analytics
+ # Calculate BioPortal summary statistics
+ @ont_count = @analytics.keys.size
+ metrics = LinkedData::Client::Models::Metrics.all
+ metrics = metrics.each_with_object(Hash.new(0)) do |h, sum|
+ h.to_hash.slice(:classes, :properties, :individuals).each { |k, v| sum[k] += v }
end
-
- organize_groups
- # Calculate BioPortal summary statistics
- @ont_count = @ontologies.length
- @cls_count = LinkedData::Client::Models::Metrics.all.map { |m| m.classes.to_i }.sum
- @individuals_count = LinkedData::Client::Models::Metrics.all.map {|m| m.individuals.to_i}.sum
- @prop_count = 36286
+ @cls_count = metrics[:classes]
+ @individuals_count = metrics[:individuals]
+ @prop_count = metrics[:properties]
@map_count = total_mapping_count
- #@analytics = LinkedData::Client::Analytics.last_month
-
- @ontology_names = @ontologies.map { |ont| ["#{ont.name} (#{ont.acronym})", ont.acronym] }
-
- @anal_ont_names = {}
+ @projects_count = LinkedData::Client::Models::Project.all.length
+ @users_count = LinkedData::Client::Models::User.all.length
+
+ @upload_benefits = [
+ t('home.benefit1'),
+ t('home.benefit2'),
+ t('home.benefit3'),
+ t('home.benefit4'),
+ t('home.benefit5')
+ ]
+
+ @anal_ont_names = []
@anal_ont_numbers = []
- # @analytics.onts[0..4].each do |visits|
- # ont = @ontologies_hash[visits[:ont].to_s]
- # @anal_ont_names[ont.acronym] = ont.name
- # @anal_ont_numbers << visits[:views]
- # end
-
-
- end
+ @analytics.sort_by{|ont, count| -count}[0..4].each do |ont, count|
+ @anal_ont_names << ont
+ @anal_ont_numbers << count
+ end
- def render_layout_partial
- partial = params[:partial]
- render partial: "layouts/#{partial}"
end
- def help
- # Show the header/footer or not
- layout = params[:pop].eql?('true') ? 'popup' : 'ontology'
- render layout: layout
+ def tools
+ @tools = {
+ search: {
+ link: "search/ontologies/content",
+ icon: "icons/search.svg",
+ title: t('tools.search.title'),
+ description: t('tools.search.description'),
+ },
+ converter: {
+ link: "/content_finder",
+ icon: "icons/settings.svg",
+ title: t('tools.converter.title'),
+ description: t('tools.converter.description'),
+ },
+ url_checker: {
+ link: check_resolvability_path,
+ icon: "check.svg",
+ title: t('tools.url_checker.title'),
+ description: t('tools.url_checker.description')
+ }
+ }
+
+ @title = "#{helpers.portal_name} #{t('layout.footer.tools')}"
+ render 'tools', layout: 'tool'
end
def all_resources
@@ -95,37 +86,37 @@ def feedback
@tags = []
unless params[:bug].nil? || params[:bug].empty?
- @tags << "Bug"
+ @tags << t('home.bug')
end
unless params[:proposition].nil? || params[:proposition].empty?
- @tags << "Proposition"
+ @tags << t('home.proposition')
end
unless params[:question].nil? || params[:question].empty?
- @tags << "Question"
+ @tags << t('home.question')
end
- unless params[:ontology_submissions_request].nil? || params[:bug].empty?
- @tags << "Ontology submissions request"
+ unless params[:ontology_submissions_request].nil? || params[:ontology_submissions_request].empty?
+ @tags << t('home.ontology_submissions_request')
end
@errors = []
if params[:name].nil? || params[:name].empty?
- @errors << 'Please include your name'
+ @errors << t('home.include_name')
end
if params[:email].nil? || params[:email].length < 1 || !params[:email].match(/^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}$/i)
- @errors << 'Please include your email'
+ @errors << t('home.include_email')
end
if params[:comment].nil? || params[:comment].empty?
- @errors << 'Please include your comment'
+ @errors << t('home.include_comment')
end
if using_captcha? && !session[:user]
unless verify_recaptcha
- @errors << 'Please fill in the proper text from the supplied image'
+ @errors << t('home.fill_text')
end
end
unless @errors.empty?
- render 'home/feedback/feedback', layout: feedback_layout
+ render 'home/feedback/feedback', layout: feedback_layout
return
end
@@ -134,21 +125,18 @@ def feedback
if params[:pop].eql?('true')
render 'home/feedback/feedback_complete', layout: 'popup'
else
- flash[:notice] = 'Feedback has been sent'
+ flash[:notice] = t('home.notice_feedback')
redirect_to_home
end
end
- def user_intention_survey
- render partial: 'user_intention_survey', layout: false
- end
def site_config
render json: bp_config_json
end
def account
- @title = 'Account Information'
+ @title = t('home.account_title')
if session[:user].nil?
redirect_to controller: 'login', action: 'index', redirect: '/account'
return
@@ -159,7 +147,7 @@ def account
@user_ontologies = @user.customOntology
@user_ontologies ||= []
- onts = LinkedData::Client::Models::Ontology.all
+ onts = LinkedData::Client::Models::Ontology.all(include_views: true);
@admin_ontologies = onts.select { |o| o.administeredBy.include? @user.id }
projects = LinkedData::Client::Models::Project.all
@@ -170,11 +158,12 @@ def account
def feedback_complete; end
- def validate_ontology_file_show; end
-
- def validate_ontology_file
- response = LinkedData::Client::HTTP.post('/validate_ontology_file', ontology_file: params[:ontology_file])
- @process_id = response.process_id
+ def annotator_recommender_form
+ if params[:submit_button] == "annotator"
+ redirect_to "/annotator?text=#{helpers.escape(params[:text])}"
+ elsif params[:submit_button] == "recommender"
+ redirect_to "/recommender?input=#{helpers.escape(params[:input])}"
+ end
end
private
diff --git a/app/controllers/instances_controller.rb b/app/controllers/instances_controller.rb
index 5d346ef3b..a980ccc61 100644
--- a/app/controllers/instances_controller.rb
+++ b/app/controllers/instances_controller.rb
@@ -1,53 +1,53 @@
class InstancesController < ApplicationController
- include InstancesHelper
- def index_by_ontology
- get_ontology(params)
- custom_render get_instances_by_ontology_json(@ontology, get_query_parameters)
- end
+ include InstancesHelper, SearchContent
+
+ def index
+ if params[:type].blank?
+ concept_type = 'NamedIndividual'
+ else
+ is_concept_instance = true
+ concept_type = params[:type]
+ end
- def index_by_class
get_ontology(params)
- get_class(params)
- custom_render get_instances_by_class_json(@concept, get_query_parameters)
+
+ query, page, page_size = helpers.search_content_params
+
+ results, _, next_page, total_count = search_ontologies_content(query: query,
+ page: page,
+ page_size: page_size,
+ filter_by_ontologies: [@ontology.acronym],
+ filter_by_types: Array(concept_type))
+
+ view = helpers.render_search_paginated_list(container_id: (is_concept_instance ? 'concept_' : '') + 'instances_sorted_list',
+ next_page_url: "/ontologies/#{@ontology.acronym}/instances?type=#{helpers.escape(params[:type])}",
+ child_url: "/ontologies/#{@ontology.acronym}/instances/show?modal=#{is_concept_instance.to_s}",
+ child_turbo_frame: 'instance_show',
+ child_param: :instanceid,
+ show_count: is_concept_instance,
+ auto_click: params[:instanceid].blank? && page.eql?(1),
+ results: results, next_page: next_page, total_count: total_count)
+
+ if is_concept_instance && page.eql?(1)
+ render turbo_stream: view
+ else
+ render inline: view
+ end
end
def show
- @instance = get_instance_details_json(params[:ontology_id], params[:instance_id], {include: 'all'})
- render partial: 'instances/instance_details'
+ get_ontology(params)
+ @instance = get_instance_details_json(params[:ontology], params[:id] || params[:instanceid], {include: 'all'})
+
+ redirect_to(ontology_path(id: params[:ontology], p: 'instances', instanceid: params[:id] || params[:instanceid], lang: request_lang)) and return unless turbo_frame_request?
+
+ render partial: 'instances/details', layout: nil
end
private
def get_ontology(params)
- @ontology = LinkedData::Client::Models::Ontology.find_by_acronym(params[:ontology]).first
+ @ontology = LinkedData::Client::Models::Ontology.find_by_acronym(params[:ontology] || params[:acronym] || params[:ontology_id]).first
ontology_not_found(params[:ontology]) if @ontology.nil?
end
- # json render + adding next and prev pages links
- def custom_render(instances)
- instances[:collection].map! { |i| add_labels_to_print(i, @ontology.acronym)}
- if (instances.respond_to? :links) && (!instances.respond_to? :errors)
- instances.links = {
- nextPage: get_page_link(instances.nextPage),
- prevPage: get_page_link(instances.prevPage)
- }
- end
-
- render json: instances
- end
-
- def get_page_link(page_number)
- return nil if page_number.nil?
-
- if request.query_parameters.has_key?(:page)
- request.original_url.gsub(/page=\d+/, "page=#{page_number}")
- elsif request.query_parameters.empty?
- request.original_url + "?" + "page=#{page_number}"
- else
- request.original_url + "&" + "page=#{page_number}"
- end
- end
-
- def get_query_parameters
- request.query_parameters.slice(:include, :display, :page, :pagesize, :search , :sortby , :order) || {}
- end
end
\ No newline at end of file
diff --git a/app/controllers/label_xl_controller.rb b/app/controllers/label_xl_controller.rb
index e5543aa6d..521d35fb7 100644
--- a/app/controllers/label_xl_controller.rb
+++ b/app/controllers/label_xl_controller.rb
@@ -10,7 +10,7 @@ def show_label
label_xl_label = label_xl ? label_xl['literalForm'] : nil
label_xl_label = params[:id] if label_xl_label.nil? || label_xl_label.empty?
- render LabelLinkComponent.inline(params[:id], label_xl_label)
+ render LabelLinkComponent.inline(params[:id], helpers.main_language_label(label_xl_label))
end
private
@@ -19,7 +19,7 @@ def get_request_label_xl
params[:id] = params[:id] ? params[:id] : params[:label_xl_id]
params[:ontology_id] = params[:ontology_id] ? params[:ontology_id] : params[:ontology]
if params[:id].nil? || params[:id].empty?
- render text: 'Error: You must provide a valid label_xl id'
+ render text: t('label_xl.error_valid_label_xl')
return
end
@ontology = LinkedData::Client::Models::Ontology.find_by_acronym(params[:ontology_id]).first
diff --git a/app/controllers/landscape_controller.rb b/app/controllers/landscape_controller.rb
index 2ddc5b1eb..6909b2cf3 100644
--- a/app/controllers/landscape_controller.rb
+++ b/app/controllers/landscape_controller.rb
@@ -43,16 +43,16 @@ def index
ontologyFormatsCount = {"OWL" => 0, "SKOS" => 0, "UMLS" => 0, "OBO" => 0}
- @metrics_average = [{attr: "numberOfClasses", label: "Number of classes", array: []},
- {attr: "numberOfIndividuals", label: "Number of individuals", array: []},
- {attr: "numberOfProperties", label: "Number of properties", array: []},
- {attr: "maxDepth", label: "Max depth", array: []},
- {attr: "maxChildCount", label: "Max child count", array: []},
- {attr: "averageChildCount", label: "Average child count", array: []},
- {attr: "classesWithOneChild", label: "Classes with one child", array: []},
- {attr: "classesWithMoreThan25Children", label: "Classes with more than 25 children", array: []},
- {attr: "classesWithNoDefinition", label: "Classes with no definition ", array: []},
- {attr: "numberOfAxioms", label: "Number of axioms (triples)", array: []}]
+ @metrics_average = [{attr: "classes", label: t('landscape.classes'), array: []},
+ {attr: "individuals", label: t('landscape.individuals'), array: []},
+ {attr: "properties", label: t('landscape.properties'), array: []},
+ {attr: "maxDepth", label: t('landscape.max_depth'), array: []},
+ {attr: "maxChildCount", label: t('landscape.max_child_count'), array: []},
+ {attr: "averageChildCount", label: t('landscape.average_child_count'), array: []},
+ {attr: "classesWithOneChild", label: t('landscape.classes_with_one_child'), array: []},
+ {attr: "classesWithMoreThan25Children", label: t('landscape.classes_with_more_than_25_children'), array: []},
+ {attr: "classesWithNoDefinition", label: t('landscape.classes_with_no_definition'), array: []},
+ {attr: "numberOfAxioms", label: t('landscape.number_of_xioms_triples'), array: []}]
# Attributes to include. To avoid to get everything and make it faster
# They are also used to get the value of each property later in the controller
@@ -73,16 +73,18 @@ def index
# We need prefixes to display them, we remove them to call them in the include
relations_attributes = @relations_array.map {|r| r.to_s.split(":")[1]}
+
metrics_attributes = @metrics_average.map {|m| m[:attr]}
# Concat all attributes array and generate a string separated with comma for include param
all_attributes = sub_attributes.concat(contributors_attr_list).concat(org_attr_list)
- .concat(relations_attributes).concat(metrics_attributes).concat(pref_properties_attributes).join(",")
+ .concat(relations_attributes).concat([:metrics]).concat(pref_properties_attributes).join(",")
# Special treatment for includedInDataCatalog: arrays with a lot of different values, so it trigger the SPARQL default
# when we retrieve multiple attr with multiple values in the array, and make the request slower
- data_catalog_submissions = LinkedData::Client::Models::OntologySubmission.all(include_status: "any", include_views: true, display_links: false, display_context: false, include: "includedInDataCatalog")
+ @submissions = LinkedData::Client::Models::OntologySubmission.all(include_status: "any", include_views: true, display_links: false, display_context: false, include: 'all')
+ data_catalog_submissions = @submissions
dataCatalog_count_hash = {}
# Add our Portal to the dataCatalog list
@@ -99,9 +101,6 @@ def index
end
end
- # Get all latest submissions with the needed attributes (this request can be slow)
- @submissions = LinkedData::Client::Models::OntologySubmission.all(include_status: "any", include_views: true, display_links: false, display_context: false, include: all_attributes)
-
# Iterate ontologies to get the submissions with all metadata
@submissions.each do |sub|
ont = sub.ontology
@@ -147,9 +146,9 @@ def index
# Count the number of classes (individuals for skos by ontologies) to get number of ontologies by slice of size
if sub.hasOntologyLanguage.eql?("SKOS")
- ontology_size = sub.numberOfIndividuals
+ ontology_size = sub.metrics&.individuals || 0
else
- ontology_size = sub.numberOfClasses
+ ontology_size = sub.metrics&.classes || 0
end
if (!ontology_size.nil?)
if (ontology_size >= 100000)
@@ -188,36 +187,36 @@ def index
end
# Get the count for usedOntologyEngineeringTool (to create a tag cloud)
- if (engineering_tool_count.has_key?(sub.usedOntologyEngineeringTool))
- engineering_tool_count[sub.usedOntologyEngineeringTool] += 1
- else
- engineering_tool_count[sub.usedOntologyEngineeringTool] = 1
+ Array(sub.usedOntologyEngineeringTool).each do |tool|
+ if engineering_tool_count.key?(tool)
+ engineering_tool_count[tool] += 1
+ else
+ engineering_tool_count[tool] = 1
+ end
end
# Get people that are mentioned as ontology actors (contact, contributors, creators, curator) to create a tag cloud
# hasContributor hasCreator contact(explore,name) curatedBy
contributors_attr_list.each do |contributor_attr|
- contributor_label = sub.send(contributor_attr.to_s).to_s
- if !contributor_label.nil?
- contributors_split = contributor_label.split(",")
- contributors_split.each do |contrib|
- if people_count_hash.has_key?(contrib)
- people_count_hash[contrib][contributor_attr] += 1
- else
- # Create the contributor entry in the Hash and create the attr entries that will be incremented
- people_count_hash[contrib] = {}
- people_count_hash[contrib][:contact] = 0
- contributors_attr_list.each do |create_contributor_attr|
- people_count_hash[contrib][create_contributor_attr] = 0
- end
- people_count_hash[contrib][contributor_attr] += 1
+ contributors = sub.send(contributor_attr.to_s)
+ Array(contributors).each do |contributor|
+ contrib = contributor.name || contributor.to_s
+ if people_count_hash.has_key?(contrib)
+ people_count_hash[contrib][contributor_attr] += 1
+ else
+ # Create the contributor entry in the Hash and create the attr entries that will be incremented
+ people_count_hash[contrib] = {}
+ people_count_hash[contrib][:contact] = 0
+ contributors_attr_list.each do |create_contributor_attr|
+ people_count_hash[contrib][create_contributor_attr] = 0
end
+ people_count_hash[contrib][contributor_attr] += 1
end
end
end
sub.contact.each do |contact|
contributor_label = contact.name
- if !contributor_label.nil?
+ unless contributor_label.nil?
if people_count_hash.has_key?(contributor_label)
people_count_hash[contributor_label][:contact] += 1
else
@@ -229,44 +228,35 @@ def index
end
people_count_hash[contributor_label][:contact] += 1
end
- people_count_emails[contributor_label] = contact.email if !contact.email.nil?
+ people_count_emails[contributor_label] = contact.email unless contact.email.nil?
end
end
org_attr_list.each do |org_attr|
# If the attribute object is not a list we make it a list of the single object we get
- orgs_list = sub.send(org_attr.to_s)
- if !orgs_list.kind_of?(Array)
- orgs_list = [orgs_list]
- end
+ organizations_list = Array(sub.send(org_attr.to_s))
+
+ organizations_list.each do |org|
+ org_str = org.name || org.to_s rescue org.to_s
+ org_uri = nil
+ # Check if the organization is actually an URL
+ if org_str =~ /\A#{URI::regexp}\z/
+ org_uri = org_str
+ # Remove http, www and last / from URI
+ org_str = org_str.sub("http://", "").sub("https://", "").sub("www.", "")
+ org_str = org_str[0..-2] if org_str.last.eql?("/")
+ end
- orgs_list.each do |orgs_comma_list|
- if !orgs_comma_list.nil? &&
- orgs_comma_split = orgs_comma_list.split(",")
- orgs_comma_split.each do |org_str|
- # TODO: handle badly formatted strings and URI
- org_uri = nil
- # Check if the organization is actually an URL
- if org_str =~ /\A#{URI::regexp}\z/
- org_uri = org_str
- # Remove http, www and last / from URI
- org_str = org_str.sub("http://", "").sub("https://", "").sub("www.", "")
- org_str = org_str[0..-2] if org_str.last.eql?("/")
-
- end
-
- if org_count_hash.has_key?(org_str)
- org_count_hash[org_str][org_attr] += 1
- else
- # Create the contrinutor entry in the Hash and create the attr entries that will be incremented
- org_count_hash[org_str] = {}
- org_attr_list.each do |create_org_attr|
- org_count_hash[org_str][create_org_attr] = 0
- end
- org_count_hash[org_str][:uri] = org_uri if !org_uri.nil?
- org_count_hash[org_str][org_attr] += 1
- end
+ if org_count_hash.has_key?(org_str)
+ org_count_hash[org_str][org_attr] += 1
+ else
+ # Create the contrinutor entry in the Hash and create the attr entries that will be incremented
+ org_count_hash[org_str] = {}
+ org_attr_list.each do |create_org_attr|
+ org_count_hash[org_str][create_org_attr] = 0
end
+ org_count_hash[org_str][:uri] = org_uri unless org_uri.nil?
+ org_count_hash[org_str][org_attr] += 1
end
end
end
@@ -281,17 +271,19 @@ def index
relation_values.each do |relation_value|
target_id = relation_value
target_in_portal = false
+ target_ont = nil
# if we find our portal URL in the ontology URL, then we just keep the ACRONYM to try to get the ontology.
- if relation_value.include?($UI_URL)
+ if relation_value.include?(helpers.portal_name)
relation_value = relation_value.split('/').last
+ target_ont = LinkedData::Client::Models::Ontology.find_by_acronym(relation_value).first
end
+
# Use acronym to get ontology from the portal
- target_ont = LinkedData::Client::Models::Ontology.find_by_acronym(relation_value).first
if target_ont
target_id = target_ont.acronym
target_in_portal = true
end
- ontology_relations_array.push({source: ont.acronym, target: target_id, relation: relation_attr.to_s, targetInPortal: target_in_portal})
+ ontology_relations_array.push({ source: ont.acronym, target: target_id, relation: relation_attr.to_s, targetInPortal: target_in_portal })
end
end
end
@@ -342,15 +334,15 @@ def index
title_array = []
total_count = 0
if hash_counts.has_key?(:projects)
- title_array.push("#{hash_counts[:projects]} projects")
+ title_array.push(t('landscape.projects_count', count: hash_counts[:projects]))
total_count += hash_counts[:projects]
end
if hash_counts.has_key?(:notes)
- title_array.push("#{hash_counts[:notes]} notes")
+ title_array.push(t('landscape.notes_count', count: hash_counts[:notes]))
total_count += hash_counts[:notes]
end
if hash_counts.has_key?(:reviews)
- title_array.push("#{hash_counts[:reviews]} reviews")
+ title_array.push(t('landscape.reviews_count', count: hash_counts[:reviews]))
total_count += hash_counts[:reviews]
end
if total_count > 0
@@ -364,15 +356,15 @@ def index
title_array = []
total_count = 0
if hash_counts.has_key?(:projects)
- title_array.push("#{hash_counts[:projects]} projects")
+ title_array.push(t('landscape.projects_count', count: hash_counts[:projects]))
total_count += hash_counts[:projects]
end
if hash_counts.has_key?(:notes)
- title_array.push("#{hash_counts[:notes]} notes")
+ title_array.push(t('landscape.notes_count', count: hash_counts[:notes]))
total_count += hash_counts[:notes]
end
if hash_counts.has_key?(:reviews)
- title_array.push("#{hash_counts[:reviews]} reviews")
+ title_array.push(t('landscape.reviews_count', count: hash_counts[:reviews]))
total_count += hash_counts[:reviews]
end
if total_count > 0
@@ -397,22 +389,22 @@ def index
title_array = []
total_count = 0
if hash_count[:contact] > 0
- title_array.push("#{hash_count[:contact]} as contact")
+ title_array.push(t('landscape.as_contact_count', count: hash_count[:contact]))
total_count += hash_count[:contact]
end
if hash_count[:hasContributor] > 0
- title_array.push("#{hash_count[:hasContributor]} as contributor")
+ title_array.push(t('landscape.as_contributor_count', count: hash_count[:hasContributor]))
total_count += hash_count[:hasContributor]
end
if hash_count[:hasCreator] > 0
- title_array.push("#{hash_count[:hasCreator]} as creator")
+ title_array.push(t('landscape.as_creator_count', count: hash_count[:hasCreator]))
total_count += hash_count[:hasCreator]
end
if hash_count[:curatedBy] > 0
- title_array.push("#{hash_count[:curatedBy]} as curator")
+ title_array.push(t('landscape.as_curator_count', count: hash_count[:curatedBy]))
total_count += hash_count[:curatedBy]
end
- title_str = "Contributions: #{title_array.join(", ")}"
+ title_str = t('landscape.contributions', title: title_array.join(", "))
if total_count > 1
if people_count_emails[people.to_s].nil?
@@ -430,18 +422,18 @@ def index
title_array = []
total_count = 0
if hash_count[:publisher] > 0
- title_array.push("published #{hash_count[:publisher]} ontologies")
+ title_array.push(t('landscape.published_ontologies', count: hash_count[:publisher]))
total_count += hash_count[:publisher]
end
if hash_count[:fundedBy] > 0
- title_array.push("funded #{hash_count[:fundedBy]} ontologies")
+ title_array.push( t('landscape.funded_ontologies', count: hash_count[:fundedBy]))
total_count += hash_count[:fundedBy]
end
if hash_count[:endorsedBy] > 0
- title_array.push("endorsed #{hash_count[:endorsedBy]} ontologies")
+ title_array.push( t('landscape.endorsed_ontologies', count: hash_count[:endorsedBy]))
total_count += hash_count[:endorsedBy]
end
- title_str = "Contributions: #{title_array.join(", ")}"
+ title_str = t('landscape.contributions', title: title_array.join(", "))
if total_count > 1
if hash_count.has_key?(:uri)
@@ -506,36 +498,36 @@ def index
# Format the ontologyFormatsCount hash as the JSON needed to generate the chart
ontologyFormatsChartJson = { labels: ontologyFormatsCount.keys,
- datasets: [{ label: "Number of ontologies using this format",
+ datasets: [{ label: t('landscape.number_of_ontologies_using_format'),
data: ontologyFormatsCount.values,
backgroundColor: pie_colors_array[3]}] }
isOfTypeChartJson = { labels: isOfTypeCount.keys,
- datasets: [{ label: "Number of ontologies of this ontology type",
+ datasets: [{ label: t('landscape.number_of_ontologies_of_type'),
data: isOfTypeCount.values,
backgroundColor: pie_colors_array[0]}] }
formalityLevelChartJson = { labels: formalityLevelCount.keys,
- datasets: [{ label: "Number of ontologies of this formality level",
+ datasets: [{ label: t('landscape.number_of_ontologies_of_formality_level'),
data: formalityLevelCount.values,
backgroundColor: pie_colors_array[2]}] }
dataCatalogChartJson = { labels: dataCatalog_count_hash.keys,
- datasets: [{ label: "Number of ontologies in this catalog", data: dataCatalog_count_hash.values,
+ datasets: [{ label: t('landscape.number_of_ontologies_in_catalog'), data: dataCatalog_count_hash.values,
backgroundColor: pie_colors_array[5]}] }
# Format the groupOntologiesCount hash as the JSON needed to generate the chart
groupCountChartJson = { labels: groups_count_hash.keys,
- datasets: [{ label: "Number of ontologies", data: groups_count_hash.values,
+ datasets: [{ label: t('landscape.number_of_ontologies'), data: groups_count_hash.values,
backgroundColor: pie_colors_array[3]}] }
domainCountChartJson = { labels: domains_count_hash.keys,
- datasets: [{ label: "Number of ontologies", data: domains_count_hash.values,
+ datasets: [{ label: t('landscape.number_of_ontologies'), data: domains_count_hash.values,
backgroundColor: pie_colors_array[4]}] }
# Format the groupOntologiesCount hash as the JSON needed to generate the chart
sizeSlicesChartJson = { labels: size_slices_hash.keys,
- datasets: [{ label: "Number of ontologies with a class count in this range",
+ datasets: [{ label: t('landscape.number_of_ontologies_with_class_count_in_range'),
data: size_slices_hash.values,
backgroundColor: pie_colors_array[2]}] }
@@ -550,7 +542,7 @@ def index
groups_info_hash[group.acronym][:name] = group.name
groups_info_hash[group.acronym][:description] = []
# Slice the description in 6 words string to avoid too long sentence in the bar chart tooltip in js
- group.description.split(" ").each_slice(6) {|slice| groups_info_hash[group.acronym][:description].push(slice.join(" ")) }
+ group.description.split(" ").each_slice(6) {|slice| groups_info_hash[group.acronym][:description].push(slice.join(" ")) } if group.description
end
domains_info_hash = {}
@@ -560,31 +552,31 @@ def index
domains_info_hash[domain.acronym][:name] = domain.name
domains_info_hash[domain.acronym][:description] = []
# Slice the description in 6 words string to avoid too long sentence in the bar chart tooltip in js
- domain.description.split(" ").each_slice(6) {|slice| domains_info_hash[domain.acronym][:description].push(slice.join(" ")) }
+ domain.description.split(" ").each_slice(6) {|slice| domains_info_hash[domain.acronym][:description].push(slice.join(" ")) } if domain.description
end
@landscape_data = {
- people_count_json_cloud: people_count_json_cloud,
- org_count_json_cloud: org_count_json_cloud,
- engineering_tool_cloud_json: engineering_tool_cloud_json,
- notes_ontologies_json_cloud: notes_ontologies_json_cloud,
- notes_people_json_cloud: notes_people_json_cloud,
- natural_language_json_pie: natural_language_json_pie,
- licenseProperty_json_pie: licenseProperty_json_pie,
- ontology_relations_array: ontology_relations_array,
- prefLabelProperty_json_pie: prefLabelProperty_json_pie,
- synonymProperty_json_pie: synonymProperty_json_pie,
- definitionProperty_json_pie: definitionProperty_json_pie,
- authorProperty_json_pie: authorProperty_json_pie,
- ontologyFormatsChartJson: ontologyFormatsChartJson,
- isOfTypeChartJson: isOfTypeChartJson,
- formalityLevelChartJson: formalityLevelChartJson,
- dataCatalogChartJson: dataCatalogChartJson,
- groupCountChartJson: groupCountChartJson,
- groupsInfoHash: groups_info_hash,
- domainCountChartJson: domainCountChartJson,
- domainsInfoHash: domains_info_hash,
- sizeSlicesChartJson: sizeSlicesChartJson
+ people_count_json_cloud: people_count_json_cloud,
+ org_count_json_cloud: org_count_json_cloud,
+ engineering_tool_cloud_json: engineering_tool_cloud_json,
+ notes_ontologies_json_cloud: notes_ontologies_json_cloud,
+ notes_people_json_cloud: notes_people_json_cloud,
+ natural_language_json_pie: natural_language_json_pie,
+ licenseProperty_json_pie: licenseProperty_json_pie,
+ ontology_relations_array: ontology_relations_array,
+ prefLabelProperty_json_pie: prefLabelProperty_json_pie,
+ synonymProperty_json_pie: synonymProperty_json_pie,
+ definitionProperty_json_pie: definitionProperty_json_pie,
+ authorProperty_json_pie: authorProperty_json_pie,
+ ontologyFormatsChartJson: ontologyFormatsChartJson,
+ isOfTypeChartJson: isOfTypeChartJson,
+ formalityLevelChartJson: formalityLevelChartJson,
+ dataCatalogChartJson: dataCatalogChartJson,
+ groupCountChartJson: groupCountChartJson,
+ groupsInfoHash: groups_info_hash,
+ domainCountChartJson: domainCountChartJson,
+ domainsInfoHash: domains_info_hash,
+ sizeSlicesChartJson: sizeSlicesChartJson
}.to_json.html_safe
end
@@ -610,11 +602,14 @@ def notes_create_hash_entry(uri_id, notes_type, hash)
# Add metrics metadata from the param sub to the @metrics_average var to get the average for each metrics
def get_metrics_for_average(sub)
# Adding metrics to their arrays
-
- @metrics_average.each do |metrics|
- if !sub.send(metrics[:attr]).nil?
- metrics[:array].push(sub.metrics.send(metrics[:attr]))
+ metrics = sub.send(:metrics)
+ @metrics_average.each do |m|
+ if metrics.nil? || metrics.send(m[:attr]).nil?
+ m[:array].push(0)
+ else
+ m[:array].push(metrics.send(m[:attr]))
end
+
end
end
diff --git a/app/controllers/language_controller.rb b/app/controllers/language_controller.rb
new file mode 100644
index 000000000..0ccf6b59c
--- /dev/null
+++ b/app/controllers/language_controller.rb
@@ -0,0 +1,21 @@
+class LanguageController < ApplicationController
+
+ # set locale to the language selected by the user
+ def set_locale_language
+ language = params[:language].strip.downcase.to_sym
+ supported_languages = I18n.available_locales
+
+ if language
+ if supported_languages.include?(language)
+ cookies.permanent[:locale] = language
+ else
+ # in case we want to show a message if the language is not available
+ flash.now[:notice] = t('language.translation_not_available', language: language)
+ logger.error flash.now[:notice]
+ end
+ end
+
+ redirect_to request.referer || root_path
+ end
+
+end
diff --git a/app/controllers/login_controller.rb b/app/controllers/login_controller.rb
index bae176851..11b113b17 100755
--- a/app/controllers/login_controller.rb
+++ b/app/controllers/login_controller.rb
@@ -16,9 +16,14 @@ def index
# logs in a user
def create
+ if is_email(params[:user][:username])
+ username = LinkedData::Client::Models::User.find_by_email(params[:user][:username]).first.username
+ else
+ username = params[:user][:username]
+ end
@errors = validate(params[:user])
if @errors.size < 1
- logged_in_user = LinkedData::Client::Models::User.authenticate(params[:user][:username], params[:user][:password])
+ logged_in_user = LinkedData::Client::Models::User.authenticate(username, params[:user][:password])
if logged_in_user && !logged_in_user.errors
login(logged_in_user)
redirect = "/"
@@ -27,10 +32,9 @@ def create
redirect = CGI.unescape(session[:redirect])
end
-
- redirect_to redirect
+ redirect_to redirect, allow_other_host: true
else
- @errors << "Invalid account name/password combination"
+ @errors << t('login.invalid_account_combination')
render :action => 'index'
end
else
@@ -38,6 +42,28 @@ def create
end
end
+
+ def create_omniauth
+ auth_data = request.env['omniauth.auth']
+ auth_code = auth_data.credentials.token
+ token_provider = helpers.omniauth_token_provider(params[:provider])
+
+ logged_in_user = LinkedData::Client::HTTP.post("#{LinkedData::Client.settings.rest_url}/users/authenticate", { access_token: auth_code , token_provider: token_provider})
+ if logged_in_user && !logged_in_user.errors
+ login(logged_in_user)
+ redirect = "/"
+
+ if session[:redirect]
+ redirect = CGI.unescape(session[:redirect])
+ end
+
+ redirect_to redirect
+ else
+ @errors = [t('login.authentication_failed', provider: params[:provider])]
+ render :action => 'index'
+ end
+ end
+
# Login as the provided username (only for admin users)
def login_as
unless session[:user] && session[:user].admin?
@@ -64,10 +90,10 @@ def destroy
old_user = session[:user]
session[:user] = session[:admin_user]
session.delete(:admin_user)
- flash[:success] = "Logged out #{old_user.username} , returned to #{session[:user].username} ".html_safe
+ flash[:success] = t('login.admin_logged_out', old_user: old_user.username, user: session[:user].username).html_safe
else
session[:user] = nil
- flash[:success] = "You have successfully logged out"
+ flash[:success] = t('login.user_logged_out')
end
redirect_to request.referer || "/"
end
@@ -88,7 +114,7 @@ def send_pass
if resp.nil?
redirect_to "/lost_pass_success"
else
- flash[:notice] = resp.errors.first + ". Please try again."
+ flash[:notice] = resp.errors.first + t('login.try_again_notice')
redirect_to "/lost_pass"
end
end
@@ -99,11 +125,12 @@ def reset_password
token = params[:tk]
@user = LinkedData::Client::HTTP.post("/users/reset_password", {username: username, email: email, token: token})
if @user.is_a?(LinkedData::Client::Models::User)
- @user.validate_password = true
login(@user)
+ @user = LinkedData::Client::Models::User.find(@user.id, include: 'all')
+ @user.validate_password = true
render "users/edit"
else
- flash[:notice] = @user.errors.first + ". Please reset your password again."
+ flash[:notice] = @user.errors.first + t('login.reset_password_again')
redirect_to "/lost_pass"
end
end
@@ -113,8 +140,8 @@ def reset_password
def login(user)
return unless user
session[:user] = user
- custom_ontologies_text = session[:user].customOntology && !session[:user].customOntology.empty? ? "The display is now based on your Custom Ontology Set ." : ""
- notice = "Welcome " + user.username.to_s + " ! " + custom_ontologies_text
+ custom_ontologies_text = session[:user].customOntology && !session[:user].customOntology.empty? ? t('login.custom_ontology_set') : ""
+ notice = t('login.welcome') + user.username.to_s + "! " + custom_ontologies_text
flash[:success] = notice.html_safe
end
@@ -122,14 +149,18 @@ def validate(params)
errors=[]
if params[:username].nil? || params[:username].length <1
- errors << "Please enter an account name"
+ errors << t('login.error_account_name')
end
if params[:password].nil? || params[:password].length <1
- errors << "Please enter a password"
+ errors << t('login.error_password')
end
return errors
end
+ def is_email(email)
+ email =~ /\A[^@\s]+@[^@\s]+\z/
+ end
+
end
diff --git a/app/controllers/mappings_controller.rb b/app/controllers/mappings_controller.rb
index e35ef3a15..e6c9fabd4 100644
--- a/app/controllers/mappings_controller.rb
+++ b/app/controllers/mappings_controller.rb
@@ -15,32 +15,26 @@ class MappingsController < ApplicationController
INTERPORTAL_HASH = $INTERPORTAL_HASH ||= {}
def index
+ @ontologies_mapping_count = LinkedData::Client::HTTP.get("#{MAPPINGS_URL}/statistics/ontologies")
ontology_list = LinkedData::Client::Models::Ontology.all.select { |o| !o.summaryOnly }
- ontologies_mapping_count = LinkedData::Client::HTTP.get("#{MAPPINGS_URL}/statistics/ontologies")
ontologies_hash = {}
ontology_list.each do |ontology|
ontologies_hash[ontology.acronym] = ontology
end
- # TODO_REV: Views support for mappings
- # views_list.each do |view|
- # ontologies_hash[view.ontologyId] = view
- # end
-
@options = {}
- ontologies_mapping_count&.members&.each do |ontology_acronym|
- # Adding external and interportal mappings to the dropdown list
+ @ontologies_mapping_count&.members&.each do |ontology_acronym|
if ontology_acronym.to_s == EXTERNAL_MAPPINGS_GRAPH
- mapping_count = ontologies_mapping_count[ontology_acronym.to_s] || 0
- select_text = "External Mappings (#{number_with_delimiter(mapping_count, delimiter: ',')})" if mapping_count >= 0
+ mapping_count = @ontologies_mapping_count[ontology_acronym.to_s] || 0
+ select_text = t('mappings.external_mappings', number_with_delimiter: number_with_delimiter(mapping_count, delimiter: ',')) if mapping_count >= 0
ontology_acronym = EXTERNAL_URL_PARAM_STR
elsif ontology_acronym.to_s.start_with?(INTERPORTAL_MAPPINGS_GRAPH)
- mapping_count = ontologies_mapping_count[ontology_acronym.to_s] || 0
- select_text = "Interportal Mappings - #{ontology_acronym.to_s.split("/")[-1].upcase} (#{number_with_delimiter(mapping_count, delimiter: ',')})" if mapping_count >= 0
+ mapping_count = @ontologies_mapping_count[ontology_acronym.to_s] || 0
+ select_text = t('mappings.interportal_mappings', acronym: ontology_acronym.to_s.split("/")[-1].upcase, number_with_delimiter: number_with_delimiter(mapping_count, delimiter: ',')) if mapping_count >= 0
ontology_acronym = INTERPORTAL_URL_PARAM_STR + ontology_acronym.to_s.split("/")[-1]
else
ontology = ontologies_hash[ontology_acronym.to_s]
- mapping_count = ontologies_mapping_count[ontology_acronym] || 0
+ mapping_count = @ontologies_mapping_count[ontology_acronym] || 0
next unless ontology && mapping_count > 0
select_text = "#{ontology.name} - #{ontology.acronym} (#{number_with_delimiter(mapping_count, delimiter: ',')})"
end
@@ -48,21 +42,13 @@ def index
end
@options = @options.sort
- end
-
- def count
- @ontology = LinkedData::Client::Models::Ontology.find_by_acronym(params[:id]).first
- @ontology_acronym = @ontology&.acronym || params[:id]
- @mapping_counts = mapping_counts(@ontology_acronym)
- render partial: 'count'
- end
+ @options.unshift([])
- def loader
@example_code = [{
"classes": ["http://bioontology.org/ontologies/BiomedicalResourceOntology.owl#Image_Algorithm",
"http://purl.org/incf/ontology/Computational_Neurosciences/cno_alpha.owl#cno_0000202"],
- "name": 'This is the mappings produced to test the bulk load',
+ "name": t('mappings.test_bulk_load'),
"source": 'https://w3id.org/semapv/LexicalMatching',
"comment": 'mock data',
"relation": [
@@ -74,9 +60,20 @@ def loader
"source_contact_info": 'orcid:1234,orcid:5678',
"date": '2020-05-30'
}]
- render partial: 'mappings/bulk_loader/loader'
end
+
+ def count
+ @ontology_acronym = params[:ontology] || params[:id]
+ @mapping_counts = mapping_counts(@ontology_acronym)
+
+ respond_to do |format|
+ format.html { render partial: 'mappings/count' }
+ format.json { render json: @mapping_counts }
+ end
+ end
+
+
def loader_process
response = LinkedData::Client::HTTP.post('/mappings/load', file: params[:file])
errors = response.errors
@@ -85,6 +82,7 @@ def loader_process
created = response.created
respond_to do |format|
format.turbo_stream do
+ # TO test
render turbo_stream: turbo_stream.replace('file_loader_result',
partial: 'mappings/bulk_loader/loaded_mappings',
locals: { errors: errors, created: created })
@@ -105,36 +103,37 @@ def show
def show_mappings
page = params[:page] || 1
@ontology = LinkedData::Client::Models::Ontology.find_by_acronym(params[:id]).first
- @target_ontology = LinkedData::Client::Models::Ontology.find(params[:target])
+ @target_ontology = LinkedData::Client::Models::Ontology.find(params[:target].split('/').last)
# Cases if ontology or target are interportal or external
if @ontology.nil?
ontology_acronym = params[:id]
if params[:id] == EXTERNAL_URL_PARAM_STR
- @ontology_name = "External Mappings"
+ @ontology_name = t('mappings.external_mappings')
elsif params[:id].start_with?(INTERPORTAL_URL_PARAM_STR)
@ontology_name = params[:id].sub(":", " - ")
end
else
ontology_acronym = @ontology.acronym
- @ontology_name = @ontology.name
+ @ontology_name = ontology_acronym
end
if @target_ontology.nil?
if params[:target] == EXTERNAL_MAPPINGS_GRAPH
target_acronym = EXTERNAL_URL_PARAM_STR
- @target_ontology_name = "External Mappings"
+ @target_ontology_name = t('mappings.external_mappings')
elsif params[:target].start_with?(INTERPORTAL_MAPPINGS_GRAPH)
target_acronym = "#{INTERPORTAL_URL_PARAM_STR}:#{params[:target].split("/")[-1]}"
- @target_ontology_name = "Interportal - #{params[:target].split("/")[-1].upcase}"
+ @target_ontology_name = t('mappings.interportal_mappings', params: params[:target].split("/")[-1].upcase)
end
else
target_acronym = @target_ontology.acronym
- @target_ontology_name = @target_ontology.name
+ @target_ontology_name = target_acronym
end
ontologies = [ontology_acronym, target_acronym]
@mapping_pages = LinkedData::Client::HTTP.get("#{MAPPINGS_URL}", { page: page, ontologies: ontologies.join(',') })
+ not_found(@mapping_pages.errors) if @mapping_pages.respond_to?(:errors)
@mappings = @mapping_pages.collection
@delete_mapping_permission = check_delete_mapping_permission(@mappings)
@@ -160,13 +159,9 @@ def get_concept_table
@concept = @ontology.explore.single_class({ full: true }, params[:conceptid])
@mappings = @concept.explore.mappings
-
+ @type = params[:type]
@delete_mapping_permission = check_delete_mapping_permission(@mappings)
- render turbo_stream: [
- replace('mapping_count') { "#{@mappings.size}" },
- replace('concept_mappings', partial: 'mappings/concept_mappings')
- ]
-
+ render partial: 'mappings/concept_mappings', layout: false
end
def new
@@ -195,7 +190,7 @@ def create
@delete_mapping_permission = check_delete_mapping_permission(@mapping_saved)
mapping = LinkedData::Client::Models::Mapping.find(@mapping_saved.id)
render turbo_stream: [
- alert(type: 'success') { 'Mapping created' },
+ alert(type: 'success') {t('mappings.mapping_created')},
prepend('concept_mappings_table_content', partial: 'show_line', locals: { map: mapping, concept: @concept })
]
end
@@ -219,7 +214,7 @@ def update
render_turbo_stream(alert_error { JSON.pretty_generate errors })
else
render_turbo_stream(
- alert_success { 'Mapping updated' },
+ alert_success { t('mappings.mapping_updated') },
replace(@mapping.id.split('/').last, partial: 'show_line', locals: { map: request_mapping, concept: @concept })
)
end
@@ -235,7 +230,7 @@ def destroy
map_uri = "#{MAPPINGS_URL}/#{CGI.escape(map_id)}"
result = LinkedData::Client::HTTP.delete(map_uri)
if result.status == 204
- success_text = "#{map_id} deleted successfully"
+ success_text = t('mappings.mapping_deleted', map_id: map_id)
else
error = result.body
end
@@ -248,7 +243,7 @@ def destroy
]
else
- render alert(type: 'danger') { error }
+ render_turbo_stream alert(type: 'danger') { error }
end
end
format.html { render json: { success: success_text, error: error } }
@@ -279,8 +274,8 @@ def mapping_form(mapping: nil)
end
else
mapping = LinkedData::Client::Models::Mapping.new
- @ontology_from = LinkedData::Client::Models::Ontology.find(params[:ontology_from])
- @ontology_to = LinkedData::Client::Models::Ontology.find(params[:ontology_to])
+ @ontology_from = LinkedData::Client::Models::Ontology.find_by_acronym(params[:ontology_from].split('/').last).first
+ @ontology_to = params[:ontology_to].present? ? LinkedData::Client::Models::Ontology.find_by_acronym(params[:ontology_to].split('/').last).first : nil
@concept_from = @ontology_from.explore.single_class({ full: true }, params[:conceptid_from]) if @ontology_from
if @ontology_to
@concept_to = @ontology_to.explore.single_class({ full: true }, params[:conceptid_to])
@@ -335,15 +330,15 @@ def mapping_form_values
def request_mapping
mapping = LinkedData::Client::Models::Mapping.find(params[:id])
- not_found("Mapping #{params[:id]} not found") if mapping.nil? || mapping.errors
+ not_found( t('mappings.mapping_not_found', id: params[:id]) ) if mapping.nil? || mapping.errors
mapping
end
def valid_values?(values)
errors = []
if values[:classes].reject(&:blank?).size != 2
- errors << 'Source and target concepts need to be specified'
+ errors << t('mappings.error_of_source_and_target')
end
errors
end
-end
+end
\ No newline at end of file
diff --git a/app/controllers/metadata_export_controller.rb b/app/controllers/metadata_export_controller.rb
new file mode 100644
index 000000000..46a56cc2c
--- /dev/null
+++ b/app/controllers/metadata_export_controller.rb
@@ -0,0 +1,32 @@
+class MetadataExportController < ApplicationController
+ include MetadataHelper
+
+ def index
+ @ontology = LinkedData::Client::Models::Ontology.find_by_acronym(params[:ontology]).first
+ ontology_not_found(params[:ontology]) if @ontology.nil?
+
+ @submission_latest = @ontology.explore.latest_submission(include: 'all')
+ @ontology_metadata = {}
+ @ontology.to_hash.each do |k, v|
+ @ontology_metadata[k] = v
+ end
+
+ content_metadata_attributes.each do |attr, label|
+ value = @submission_latest.send(attr)
+
+ if attr.to_s.eql?('contact') || agent?(attr)
+ new_values = Array(value).map do |x|
+ next x if x.is_a?(String)
+
+ x = x.to_h || x.to_hash
+ x.delete(:context)
+ x.delete(:links)
+ x.delete(:id)
+ x[:email] || x[:name]
+ end
+ value = value.is_a?(Array) ? new_values : new_values.first
+ end
+ @ontology_metadata[attr] = value
+ end
+ end
+end
diff --git a/app/controllers/ncbo_annotatorplus_controller.rb b/app/controllers/ncbo_annotatorplus_controller.rb
deleted file mode 100644
index d6a418a30..000000000
--- a/app/controllers/ncbo_annotatorplus_controller.rb
+++ /dev/null
@@ -1,224 +0,0 @@
-class NcboAnnotatorplusController < ApplicationController
- layout :determine_layout
-
- before_action :check_ncbo_annotatorplus_enabled
-
- NCBO_ANNOTATOR_URI = $NCBO_ANNOTATOR_URL
- NCBO_API_KEY = $NCBO_API_KEY
-
- def index
- @semantic_types_for_select = []
- @semantic_groups_for_select = []
- @semantic_types ||= get_semantic_types
- @sem_type_ont = LinkedData::Client::Models::Ontology.find_by_acronym('STY').first
- @semantic_groups ||= {"ACTI" => "Activities & Behaviors", "ANAT" => "Anatomy", "CHEM" => "Chemicals & Drugs","CONC" => "Concepts & Ideas",
- "DEVI" => "Devices", "DISO" => "Disorders", "GENE" => "Genes & Molecular Sequences", "GEOG" => "Geographic Areas", "LIVB" => "Living Beings",
- "OBJC" => "Objects", "OCCU" => "Occupations", "ORGA" => "Organizations", "PHEN" => "Phenomena", "PHYS" => "Physiology","PROC" => "Procedures"}
- @semantic_types.each_pair do |code, label|
- @semantic_types_for_select << ["#{label} (#{code})", code]
- end
- @semantic_groups.each_pair do |group, label|
- @semantic_groups_for_select << ["#{label} (#{group})", group]
- end
- @semantic_types_for_select.sort! {|a,b| a[0] <=> b[0]}
- @semantic_groups_for_select.sort! {|a,b| a[0] <=> b[0]}
- @recognizers = parse_json(REST_URI + "/annotator/recognizers")
- @annotator_ontologies = LinkedData::Client::Models::Ontology.all
- @ontologies_for_select = get_ontologies_for_select
- end
-
-
- def create
- params[:mappings] ||= []
- params[:max_level] ||= 0
- params[:ontologies] ||= []
- params[:semantic_types] ||= []
- params[:semantic_groups] ||= []
- text_to_annotate = params[:text].strip.gsub("\r\n", " ").gsub("\n", " ")
-
- options = { :ontologies => params[:ontologies],
- :class_hierarchy_max_level => params[:class_hierarchy_max_level].to_i,
- :expand_class_hierarchy => params[:class_hierarchy_max_level].to_i > 0,
- :semantic_types => params[:semantic_types],
- :semantic_groups => params[:semantic_groups],
- :mappings => params[:mappings],
- :longest_only => params[:longest_only],
- :exclude_numbers => params[:exclude_numbers] ||= "false", # service default is false
- :whole_word_only => params[:whole_word_only] ||= "true", # service default is true
- :exclude_synonyms => params[:exclude_synonyms] ||= "false", # service default is false
- :fast_context => params[:fast_context] ||= "false", # service default is false
- :score => params[:score],
- :score_threshold => params[:score_threshold] ||=-1,
- :confidence_threshold => params[:confidence_threshold] ||=-1,
- :ncbo_slice => params[:ncbo_slice] || ''
- }
-
- start = Time.now
- query = NCBO_ANNOTATOR_URI
- query += "?text=" + CGI.escape(text_to_annotate)
- query += "&apikey=" + NCBO_API_KEY
- query += "&include=prefLabel"
- query += "&expand_class_hierarchy=true" if options[:class_hierarchy_max_level] > 0
- query += "&class_hierarchy_max_level=" + options[:class_hierarchy_max_level].to_s if options[:class_hierarchy_max_level] > 0
- query += "&score=" + options[:score] unless options[:score] == ""
- query += "&score_threshold=" + options[:score_threshold] unless options[:score] == "" or options[:score_threshold]==-1
- query += "&confidence_threshold=" + options[:confidence_threshold] unless options[:score] == "" or options[:confidence_threshold]==-1
- query += "&fast_context=" + options[:fast_context] unless options[:fast_context].empty?
- query += "&ontologies=" + CGI.escape(options[:ontologies].join(',')) unless options[:ontologies].empty?
- query += "&semantic_types=" + options[:semantic_types].join(',') unless options[:semantic_types].empty?
- query += "&semantic_groups=" + options[:semantic_groups].join(',') unless options[:semantic_groups].empty?
- query += "&mappings=" + options[:mappings].join(',') unless options[:mappings].empty?
- query += "&longest_only=#{options[:longest_only]}"
- query += "&recognizer=#{params[:recognizer]}"
- query += "&exclude_numbers=" + options[:exclude_numbers].to_s unless options[:exclude_numbers].empty?
- query += "&whole_word_only=" + options[:whole_word_only].to_s unless options[:whole_word_only].empty?
- query += "&exclude_synonyms=" + options[:exclude_synonyms].to_s unless options[:exclude_synonyms].empty?
- query += "&ncbo_slice=" + options[:ncbo_slice].to_s unless options[:ncbo_slice].empty?
-
- annotations = parse_json(query) # See application_controller.rb
- #annotations = LinkedData::Client::HTTP.get(query)
- LOG.add :debug, "Query: #{query}"
- LOG.add :debug, "Retrieved #{annotations.length} annotations: #{Time.now - start}s"
- if annotations.empty? || params[:raw] == "true"
- # TODO: if params contains select ontologies and/or semantic types, only return those selected.
- response = {
- annotations: annotations,
- ontologies: get_simplified_ontologies_hash, # application_controller
- semantic_types: get_semantic_types # application_controller
- }
- else
- massage_annotated_classes(annotations, options)
- response = {
- annotations: annotations,
- ontologies: {}, # ontology data are in annotations already.
- semantic_types: {} # semantic types are in annotations already.
- }
- end
-
- render :json => response
- end
-
- private
-
- def get_semantic_types
- semantic_types = {}
- sty_ont = LinkedData::Client::Models::Ontology.find_by_acronym('STY').first
- return semantic_types if sty_ont.nil?
- # The first 500 items should be more than sufficient to get all semantic types.
- sty_classes = sty_ont.explore.classes({'pagesize'=>500, include: 'prefLabel'})
- sty_classes.collection.each do |cls|
- code = cls.id.split("/").last
- semantic_types[ code ] = cls.prefLabel
- end
- semantic_types
- end
-
- def massage_annotated_classes(annotations, options)
- # Get the class details required for display, assume this is necessary
- # for every element of the annotations array because the API returns a set.
- # Use the batch REST API to get all the annotated class prefLabels.
- start = Time.now
- semantic_types = options[:semantic_types] || []
- class_details = get_annotated_classes(annotations, semantic_types)
- simplify_annotated_classes(annotations, class_details)
- # repeat the simplification for any annotation hierarchy or mappings.
- hierarchy = annotations.map {|a| a if a.keys.include? 'hierarchy' }.compact
- hierarchy.each do |a|
- simplify_annotated_classes(a['hierarchy'], class_details) if not a['hierarchy'].empty?
- end
- mappings = annotations.map {|a| a if a.keys.include? 'mappings' }.compact
- mappings.each do |a|
- simplify_annotated_classes(a['mappings'], class_details) if not a['mappings'].empty?
- end
- LOG.add :debug, "Completed massage for annotated classes: #{Time.now - start}s"
- end
-
- def simplify_annotated_classes(annotations, class_details)
- annotations2delete = []
- annotations.each do |a|
- cls_id = a['annotatedClass']['@id']
- details = class_details[cls_id]
- if details.nil?
- LOG.add :debug, "Failed to get class details for: #{a['annotatedClass']['links']['self']}"
- annotations2delete.push(cls_id)
- else
- # Replace the annotated class with simplified details.
- a['annotatedClass'] = details
- end
- end
- # Remove any annotations that fail to resolve details.
- annotations.delete_if { |a| annotations2delete.include? a['annotatedClass']['@id'] }
- end
-
- def get_annotated_class_hash(a)
- return {
- :class => a['annotatedClass']['@id'],
- :ontology => a['annotatedClass']['links']['ontology']
- }
- end
-
- def get_annotated_classes(annotations, semantic_types=[])
- # Use batch service to get class prefLabels
- class_list = []
- annotations.each {|a| class_list << get_annotated_class_hash(a) }
- hierarchy = annotations.map {|a| a if a.keys.include? 'hierarchy' }.compact
- hierarchy.each do |a|
- a['hierarchy'].each {|h| class_list << get_annotated_class_hash(h) }
- end
- mappings = annotations.map {|a| a if a.keys.include? 'mappings' }.compact
- mappings.each do |a|
- a['mappings'].each {|m| class_list << get_annotated_class_hash(m) }
- end
- classes_simple = {}
- return classes_simple if class_list.empty?
- # remove duplicates
- class_set = class_list.to_set # get unique class:ontology set
- class_list = class_set.to_a # collection requires a list in batch call
- # make the batch call
- properties = 'prefLabel'
- properties = 'prefLabel,semanticType' if not semantic_types.empty?
- call_params = {'http://www.w3.org/2002/07/owl#Class'=>{'collection'=>class_list, 'include'=>properties}}
- classes_json = get_batch_results(call_params)
- # Simplify the response data for the UI
- @ontologies_hash ||= get_simplified_ontologies_hash # application_controller
- classes_data = JSON.parse(classes_json)
- classes_data["http://www.w3.org/2002/07/owl#Class"].each do |cls|
- c = simplify_class_model(cls)
- ont_details = @ontologies_hash[ c[:ontology] ]
- next if ont_details.nil? # NO DISPLAY FOR ANNOTATIONS ON ANY CLASS OUTSIDE THE BIOPORTAL ONTOLOGY SET.
- c[:ontology] = ont_details
- unless semantic_types.empty? || cls['semanticType'].nil?
- @semantic_types ||= get_semantic_types # application_controller
- # Extract the semantic type descriptions that are requested.
- semanticTypeURI = 'http://bioportal.bioontology.org/ontologies/umls/sty/'
- semanticCodes = cls['semanticType'].map {|t| t.sub( semanticTypeURI, '') }
- requestedCodes = semanticCodes.map {|code| (semantic_types.include? code and code) || nil }.compact
- requestedDescriptions = requestedCodes.map {|code| @semantic_types[code] }.compact
- c[:semantic_types] = requestedDescriptions
- else
- c[:semantic_types] = []
- end
- classes_simple[c[:id]] = c
- end
- return classes_simple
- end
-
- # Get the ontologies from NCBO to populate select onto for the Annotator plus
- def get_ontologies_for_select
- ontologies_json = JSON.parse(Net::HTTP.get(URI.parse("http://data.bioontology.org/ontologies?apikey=#{NCBO_API_KEY}")))
- ontologies_array = []
-
- ontologies_json.each do |onto|
- ontologies_array.push(["#{onto['name']} (#{onto['acronym']})", onto['acronym']])
- end
-
- return ontologies_array
- end
-
- protected
-
- def check_ncbo_annotatorplus_enabled
- raise ActionController::RoutingError.new('Not Found') unless $NCBO_ANNOTATORPLUS_ENABLED == true
- end
-
-end
diff --git a/app/controllers/notes_controller.rb b/app/controllers/notes_controller.rb
index 83051c4e1..e08836392 100644
--- a/app/controllers/notes_controller.rb
+++ b/app/controllers/notes_controller.rb
@@ -1,17 +1,19 @@
class NotesController < ApplicationController
include TurboHelper
layout 'ontology'
+
NOTES_PROPOSAL_TYPES = {
- ProposalNewClass: "New Class Proposal",
- ProposalChangeHierarchy: "New Relationship Proposal",
- ProposalChangeProperty: "Change Property Value Proposal"
+ ProposalNewClass: t('notes.new_class_proposal'),
+ ProposalChangeHierarchy: t('notes.new_relationship_proposal'),
+ ProposalChangeProperty: t('notes.change_property_value_proposal')
}
def show
id = clean_note_id(params[:id])
@note = LinkedData::Client::Models::Note.get(id, include_threads: true)
- @ontology = (@notes.explore.relatedOntology || []).first
+ @note_decorator = NoteDecorator.new(@note, view_context)
+ @ontology = (@note.explore.relatedOntology || []).first
if request.xhr?
render :partial => 'thread'
@@ -100,10 +102,10 @@ def create
new_note = note.save
parent_type = params[:type].eql?("ontology") ? 'ontology' : 'class'
ontology_acronym = new_note.relatedOntology.first.split('/').last
- success_message = 'New comment added successfully'
+ success_message = t('notes.new_comment_added')
locals = { note: new_note, ontology_acronym: ontology_acronym, parent_type: parent_type }
partial = 'notes/note_line'
- container_id = "#{parent_type}_notes_table_content"
+ container_id = "#{parent_type}_notes_table_body"
alerts_container_id = nil
end
@@ -128,10 +130,10 @@ def destroy
if note.errors
response[:errors] = note.errors
else
- response[:success] = "Note #{note_id} was deleted successfully"
+ response[:success] = t('notes.note_deleted_successfully', note_id: note_id)
end
else
- response[:errors] = "Note #{note_id} was not found in the system"
+ response[:errors] = t('notes.note_not_found', note_id: note_id)
end
parent_type = params[:parent_type]
alerts_container_id = "notes_#{parent_type}_list_table_alerts"
diff --git a/app/controllers/ontolobridge_controller.rb b/app/controllers/ontolobridge_controller.rb
index 476f3efa5..89d3d62b6 100644
--- a/app/controllers/ontolobridge_controller.rb
+++ b/app/controllers/ontolobridge_controller.rb
@@ -36,7 +36,7 @@ def request_term
response["error"] = e.message
rescue Exception => e
code = 500
- response["error"] = "Problem creating a new term #{endpoint}: #{e.class} - #{e.message}"
+ response["error"] = t('ontolobridge.problem_of_creating_new_term', endpoint: endpoint, class: e.class, message: e.message)
end
render json: [response, code], status: code
@@ -45,7 +45,7 @@ def request_term
def save_new_term_instructions
code = 200
response = {error: '', success: ''}
- response[:success] = "New term request instructions for #{params['acronym']} saved"
+ response[:success] = t('ontolobridge.new_term_instructions_saved', acronym: params['acronym'])
ont_data = Ontology.find_by(acronym: params['acronym'])
ont_data ||= Ontology.new
ont_data.acronym = params['acronym']
@@ -55,7 +55,7 @@ def save_new_term_instructions
ont_data.save
rescue Exception => e
code = 500
- response[:error] = "Unable to save new term instructions for #{params['acronym']} due to a server error"
+ response[:error] = t('ontolobridge.error_saving_new_term_instructions', acronym: params['acronym'])
end
sleep(1)
render json: [response, code], status: code
diff --git a/app/controllers/ontologies_controller.rb b/app/controllers/ontologies_controller.rb
index f84c34a09..caec35f99 100644
--- a/app/controllers/ontologies_controller.rb
+++ b/app/controllers/ontologies_controller.rb
@@ -4,9 +4,16 @@ class OntologiesController < ApplicationController
include InstancesHelper
include ActionView::Helpers::NumberHelper
include OntologiesHelper
+ include ConceptsHelper
include SchemesHelper
include CollectionsHelper
include MappingStatistics
+ include OntologyUpdater
+ include TurboHelper
+ include SparqlHelper
+ include SubmissionFilter
+ include OntologyContentSerializer
+ include UriRedirection
require 'multi_json'
require 'cgi'
@@ -14,143 +21,45 @@ class OntologiesController < ApplicationController
helper :concepts
helper :fair_score
- layout :determine_layout
+ layout 'ontology'
- before_action :authorize_and_redirect, :only=>[:edit,:update,:create,:new]
+ before_action :authorize_and_redirect, :only => [:edit, :update, :create, :new]
before_action :submission_metadata, only: [:show]
- KNOWN_PAGES = Set.new(["terms", "classes", "mappings", "notes", "widgets", "summary", "properties" ,"instances", "schemes", "collections"])
+ KNOWN_PAGES = Set.new(["terms", "classes", "mappings", "notes", "widgets", "summary", "properties", "instances", "schemes", "collections", "sparql"])
EXTERNAL_MAPPINGS_GRAPH = "http://data.bioontology.org/metadata/ExternalMappings"
INTERPORTAL_MAPPINGS_GRAPH = "http://data.bioontology.org/metadata/InterportalMappings"
- $LEXVO_TO_FLAG = { 'http://lexvo.org/id/iso639-3/aar' => 'aa', 'http://lexvo.org/id/iso639-3/abk' => 'ab',
- 'http://lexvo.org/id/iso639-3/ave' => 'ae', 'http://lexvo.org/id/iso639-3/afr' => 'af',
- 'http://lexvo.org/id/iso639-3/aka' => 'ak', 'http://lexvo.org/id/iso639-3/amh' => 'am',
- 'http://lexvo.org/id/iso639-3/arg' => 'an', 'http://lexvo.org/id/iso639-3/ara' => 'ar', 'http://lexvo.org/id/iso639-3/asm' => 'as', 'http://lexvo.org/id/iso639-3/ava' => 'av', 'http://lexvo.org/id/iso639-3/aym' => 'ay', 'http://lexvo.org/id/iso639-3/aze' => 'az', 'http://lexvo.org/id/iso639-3/bak' => 'ba', 'http://lexvo.org/id/iso639-3/bel' => 'be', 'http://lexvo.org/id/iso639-3/bul' => 'bg', 'http://lexvo.org/id/iso639-3/bis' => 'bi', 'http://lexvo.org/id/iso639-3/bam' => 'bm', 'http://lexvo.org/id/iso639-3/ben' => 'bn', 'http://lexvo.org/id/iso639-3/bod' => 'bo', 'http://lexvo.org/id/iso639-3/bre' => 'br', 'http://lexvo.org/id/iso639-3/bos' => 'bs', 'http://lexvo.org/id/iso639-3/cat' => 'ca', 'http://lexvo.org/id/iso639-3/che' => 'ce', 'http://lexvo.org/id/iso639-3/cha' => 'ch', 'http://lexvo.org/id/iso639-3/cos' => 'co', 'http://lexvo.org/id/iso639-3/cre' => 'cr', 'http://lexvo.org/id/iso639-3/ces' => 'cs', 'http://lexvo.org/id/iso639-3/chu' => 'cu', 'http://lexvo.org/id/iso639-3/chv' => 'cv', 'http://lexvo.org/id/iso639-3/cym' => 'cy', 'http://lexvo.org/id/iso639-3/dan' => 'da', 'http://lexvo.org/id/iso639-3/deu' => 'de', 'http://lexvo.org/id/iso639-3/div' => 'dv', 'http://lexvo.org/id/iso639-3/dzo' => 'dz', 'http://lexvo.org/id/iso639-3/ewe' => 'ee', 'http://lexvo.org/id/iso639-3/ell' => 'el', 'http://lexvo.org/id/iso639-3/eng' => 'en', 'http://lexvo.org/id/iso639-3/epo' => 'eo', 'http://lexvo.org/id/iso639-3/spa' => 'es', 'http://lexvo.org/id/iso639-3/est' => 'et', 'http://lexvo.org/id/iso639-3/eus' => 'eu', 'http://lexvo.org/id/iso639-3/fas' => 'fa', 'http://lexvo.org/id/iso639-3/ful' => 'ff', 'http://lexvo.org/id/iso639-3/fin' => 'fi', 'http://lexvo.org/id/iso639-3/fij' => 'fj', 'http://lexvo.org/id/iso639-3/fao' => 'fo', 'http://lexvo.org/id/iso639-3/fra' => 'fr', 'http://lexvo.org/id/iso639-3/fry' => 'fy', 'http://lexvo.org/id/iso639-3/gle' => 'ga', 'http://lexvo.org/id/iso639-3/gla' => 'gd', 'http://lexvo.org/id/iso639-3/glg' => 'gl', 'http://lexvo.org/id/iso639-3/grn' => 'gn', 'http://lexvo.org/id/iso639-3/guj' => 'gu', 'http://lexvo.org/id/iso639-3/glv' => 'gv', 'http://lexvo.org/id/iso639-3/hau' => 'ha', 'http://lexvo.org/id/iso639-3/heb' => 'he', 'http://lexvo.org/id/iso639-3/hin' => 'hi', 'http://lexvo.org/id/iso639-3/hmo' => 'ho', 'http://lexvo.org/id/iso639-3/hrv' => 'hr', 'http://lexvo.org/id/iso639-3/hat' => 'ht', 'http://lexvo.org/id/iso639-3/hun' => 'hu', 'http://lexvo.org/id/iso639-3/hye' => 'hy', 'http://lexvo.org/id/iso639-3/her' => 'hz', 'http://lexvo.org/id/iso639-3/ina' => 'ia', 'http://lexvo.org/id/iso639-3/ind' => 'id', 'http://lexvo.org/id/iso639-3/ile' => 'ie', 'http://lexvo.org/id/iso639-3/ibo' => 'ig', 'http://lexvo.org/id/iso639-3/iii' => 'ii', 'http://lexvo.org/id/iso639-3/ipk' => 'ik', 'http://lexvo.org/id/iso639-3/ido' => 'io', 'http://lexvo.org/id/iso639-3/isl' => 'is', 'http://lexvo.org/id/iso639-3/ita' => 'it', 'http://lexvo.org/id/iso639-3/iku' => 'iu', 'http://lexvo.org/id/iso639-3/jpn' => 'ja', 'http://lexvo.org/id/iso639-3/jav' => 'jv', 'http://lexvo.org/id/iso639-3/kat' => 'ka', 'http://lexvo.org/id/iso639-3/kon' => 'kg', 'http://lexvo.org/id/iso639-3/kik' => 'ki', 'http://lexvo.org/id/iso639-3/kua' => 'kj', 'http://lexvo.org/id/iso639-3/kaz' => 'kk', 'http://lexvo.org/id/iso639-3/kal' => 'kl', 'http://lexvo.org/id/iso639-3/khm' => 'km', 'http://lexvo.org/id/iso639-3/kan' => 'kn', 'http://lexvo.org/id/iso639-3/kor' => 'ko', 'http://lexvo.org/id/iso639-3/kau' => 'kr', 'http://lexvo.org/id/iso639-3/kas' => 'ks', 'http://lexvo.org/id/iso639-3/kur' => 'ku', 'http://lexvo.org/id/iso639-3/kom' => 'kv', 'http://lexvo.org/id/iso639-3/cor' => 'kw', 'http://lexvo.org/id/iso639-3/kir' => 'ky', 'http://lexvo.org/id/iso639-3/lat' => 'la', 'http://lexvo.org/id/iso639-3/ltz' => 'lb', 'http://lexvo.org/id/iso639-3/lug' => 'lg', 'http://lexvo.org/id/iso639-3/lim' => 'li', 'http://lexvo.org/id/iso639-3/lin' => 'ln', 'http://lexvo.org/id/iso639-3/lao' => 'lo', 'http://lexvo.org/id/iso639-3/lit' => 'lt', 'http://lexvo.org/id/iso639-3/lub' => 'lu', 'http://lexvo.org/id/iso639-3/lav' => 'lv', 'http://lexvo.org/id/iso639-3/mlg' => 'mg', 'http://lexvo.org/id/iso639-3/mah' => 'mh', 'http://lexvo.org/id/iso639-3/mri' => 'mi', 'http://lexvo.org/id/iso639-3/mkd' => 'mk', 'http://lexvo.org/id/iso639-3/mal' => 'ml', 'http://lexvo.org/id/iso639-3/mon' => 'mn', 'http://lexvo.org/id/iso639-3/mar' => 'mr', 'http://lexvo.org/id/iso639-3/msa' => 'ms', 'http://lexvo.org/id/iso639-3/mlt' => 'mt', 'http://lexvo.org/id/iso639-3/mya' => 'my', 'http://lexvo.org/id/iso639-3/nau' => 'na', 'http://lexvo.org/id/iso639-3/nob' => 'nb', 'http://lexvo.org/id/iso639-3/nde' => 'nd', 'http://lexvo.org/id/iso639-3/nep' => 'ne', 'http://lexvo.org/id/iso639-3/ndo' => 'ng', 'http://lexvo.org/id/iso639-3/nld' => 'nl', 'http://lexvo.org/id/iso639-3/nno' => 'nn', 'http://lexvo.org/id/iso639-3/nor' => 'no', 'http://lexvo.org/id/iso639-3/nbl' => 'nr', 'http://lexvo.org/id/iso639-3/nav' => 'nv', 'http://lexvo.org/id/iso639-3/nya' => 'ny', 'http://lexvo.org/id/iso639-3/oci' => 'oc', 'http://lexvo.org/id/iso639-3/oji' => 'oj', 'http://lexvo.org/id/iso639-3/orm' => 'om', 'http://lexvo.org/id/iso639-3/ori' => 'or', 'http://lexvo.org/id/iso639-3/oss' => 'os', 'http://lexvo.org/id/iso639-3/pan' => 'pa', 'http://lexvo.org/id/iso639-3/pli' => 'pi', 'http://lexvo.org/id/iso639-3/pol' => 'pl', 'http://lexvo.org/id/iso639-3/pus' => 'ps', 'http://lexvo.org/id/iso639-3/por' => 'pt', 'http://lexvo.org/id/iso639-3/que' => 'qu', 'http://lexvo.org/id/iso639-3/roh' => 'rm', 'http://lexvo.org/id/iso639-3/run' => 'rn', 'http://lexvo.org/id/iso639-3/ron' => 'ro', 'http://lexvo.org/id/iso639-3/rus' => 'ru', 'http://lexvo.org/id/iso639-3/kin' => 'rw', 'http://lexvo.org/id/iso639-3/san' => 'sa', 'http://lexvo.org/id/iso639-3/srd' => 'sc', 'http://lexvo.org/id/iso639-3/snd' => 'sd', 'http://lexvo.org/id/iso639-3/sme' => 'se', 'http://lexvo.org/id/iso639-3/sag' => 'sg', 'http://lexvo.org/id/iso639-3/hbs' => 'sh', 'http://lexvo.org/id/iso639-3/sin' => 'si', 'http://lexvo.org/id/iso639-3/slk' => 'sk', 'http://lexvo.org/id/iso639-3/slv' => 'sl', 'http://lexvo.org/id/iso639-3/smo' => 'sm', 'http://lexvo.org/id/iso639-3/sna' => 'sn', 'http://lexvo.org/id/iso639-3/som' => 'so', 'http://lexvo.org/id/iso639-3/sqi' => 'sq', 'http://lexvo.org/id/iso639-3/srp' => 'sr', 'http://lexvo.org/id/iso639-3/ssw' => 'ss', 'http://lexvo.org/id/iso639-3/sot' => 'st', 'http://lexvo.org/id/iso639-3/sun' => 'su', 'http://lexvo.org/id/iso639-3/swe' => 'sv', 'http://lexvo.org/id/iso639-3/swa' => 'sw', 'http://lexvo.org/id/iso639-3/tam' => 'ta', 'http://lexvo.org/id/iso639-3/tel' => 'te', 'http://lexvo.org/id/iso639-3/tgk' => 'tg', 'http://lexvo.org/id/iso639-3/tha' => 'th', 'http://lexvo.org/id/iso639-3/tir' => 'ti', 'http://lexvo.org/id/iso639-3/tuk' => 'tk', 'http://lexvo.org/id/iso639-3/tgl' => 'tl', 'http://lexvo.org/id/iso639-3/tsn' => 'tn', 'http://lexvo.org/id/iso639-3/ton' => 'to', 'http://lexvo.org/id/iso639-3/tur' => 'tr', 'http://lexvo.org/id/iso639-3/tso' => 'ts', 'http://lexvo.org/id/iso639-3/tat' => 'tt', 'http://lexvo.org/id/iso639-3/twi' => 'tw', 'http://lexvo.org/id/iso639-3/tah' => 'ty', 'http://lexvo.org/id/iso639-3/uig' => 'ug', 'http://lexvo.org/id/iso639-3/ukr' => 'uk', 'http://lexvo.org/id/iso639-3/urd' => 'ur', 'http://lexvo.org/id/iso639-3/uzb' => 'uz', 'http://lexvo.org/id/iso639-3/ven' => 've', 'http://lexvo.org/id/iso639-3/vie' => 'vi', 'http://lexvo.org/id/iso639-3/vol' => 'vo', 'http://lexvo.org/id/iso639-3/wln' => 'wa', 'http://lexvo.org/id/iso639-3/wol' => 'wo', 'http://lexvo.org/id/iso639-3/xho' => 'xh', 'http://lexvo.org/id/iso639-3/yid' => 'yi', 'http://lexvo.org/id/iso639-3/yor' => 'yo', 'http://lexvo.org/id/iso639-3/zha' => 'za', 'http://lexvo.org/id/iso639-3/zho' => 'zh', 'http://lexvo.org/id/iso639-3/zul' => 'zu' }
-
-
# GET /ontologies
def index
- @app_name = 'FacetedBrowsing'
- @app_dir = '/browse'
- @base_path = @app_dir
- ontologies = LinkedData::Client::Models::Ontology.all(
-include: LinkedData::Client::Models::Ontology.include_params + ',viewOf', include_views: true, display_context: false)
- ontologies_hash = Hash[ontologies.map {|o| [o.id, o] }]
- @admin = session[:user] ? session[:user].admin? : false
- @development = Rails.env.development?
-
- # We could get naturalLanguages, isOfType and formalityLevels from the API, but for performance we are storing it in config/bioportal_config_production.rb
- #@metadata = submission_metadata
-
- # The attributes used when retrieving the submission. We are not retrieving all attributes to be faster
- browse_attributes = 'ontology,acronym,submissionStatus,description,pullLocation,creationDate,released,name,naturalLanguage,hasOntologyLanguage,hasFormalityLevel,isOfType,contact'
- submissions = LinkedData::Client::Models::OntologySubmission.all(include_views: true, display_links: false,
-display_context: false, include: browse_attributes)
- submissions_map = Hash[submissions.map {|sub| [sub.ontology.acronym, sub] }]
-
@categories = LinkedData::Client::Models::Category.all(display_links: false, display_context: false)
- @categories_hash = Hash[@categories.map {|c| [c.id, c] }]
-
@groups = LinkedData::Client::Models::Group.all(display_links: false, display_context: false)
- @groups_hash = Hash[@groups.map {|g| [g.id, g] }]
- #analytics = LinkedData::Client::Analytics.last_month
- #@analytics = Hash[analytics.onts.map {|o| [o[:ont].to_s, o[:views]]}]
+ @filters = ontology_filters_init(@categories, @groups)
+ init_filters(params)
+ render 'ontologies/browser/browse'
+ end
- reviews = {}
- LinkedData::Client::Models::Review.all(display_links: false, display_context: false).each do |r|
- reviews[r.reviewedOntology] ||= []
- reviews[r.reviewedOntology] << r
+ def ontologies_filter
+ @time = Benchmark.realtime do
+ @ontologies, @count, @count_objects, @request_params = submissions_paginate_filter(params)
end
- metrics_hash = get_metrics_hash
-
- @formats = Set.new
- #get fairscores of all ontologies
- @fair_scores = fairness_service_enabled? ? get_fair_score('all') : nil;
-
- @ontologies = []
- ontologies.each do |ont|
- o = {}
-
- if metrics_hash[ont.id]
- o[:class_count] = metrics_hash[ont.id].classes
- o[:individual_count] = metrics_hash[ont.id].individuals
- else
- o[:class_count] = 0
- o[:individual_count] = 0
- end
- o[:class_count_formatted] = number_with_delimiter(o[:class_count], delimiter: ',')
- o[:individual_count_formatted] = number_with_delimiter(o[:individual_count], delimiter: ',')
-
- o[:id] = ont.id
- o[:type] = ont.viewOf.nil? ? 'ontology' : 'ontology_view'
- o[:show] = ont.viewOf.nil? ? true : false # show ontologies only by default
- o[:reviews] = reviews[ont.id] || []
- o[:groups] = ont.group || []
- o[:categories] = ont.hasDomain || []
- o[:note_count] = ont.notes.length
- o[:review_count] = ont.reviews.length
- o[:project_count] = ont.projects.length
- o[:private] = ont.private?
- #o[:popularity] = @analytics[ont.acronym] || 0
- o[:submissionStatus] = []
- o[:administeredBy] = ont.administeredBy
- o[:name] = ont.name
- o[:acronym] = ont.acronym
- o[:projects] = ont.projects
- o[:notes] = ont.notes
-
- if !@fair_scores.nil? && !@fair_scores[ont.acronym].nil?
- o[:fairScore] = @fair_scores[ont.acronym]['score']
- o[:normalizedFairScore] = @fair_scores[ont.acronym]['normalizedScore']
- else
- o[:fairScore] = nil
- o[:normalizedFairScore] = 0
- end
-
- if o[:type].eql?('ontology_view')
- unless ontologies_hash[ont.viewOf].blank?
- o[:viewOfOnt] = {
- name: ontologies_hash[ont.viewOf].name,
- acronym: ontologies_hash[ont.viewOf].acronym
- }
+ if @page.page.eql?(1)
+ streams = [prepend("ontologies_list_view-page-#{@page.page}", partial: 'ontologies/browser/ontologies')]
+ streams += @count_objects.map do |section, values_count|
+ values_count.map do |value, count|
+ replace("count_#{section}_#{value}") do
+ helpers.turbo_frame_tag("count_#{section}_#{value}") do
+ helpers.content_tag(:span, count.to_s, class: "hide-if-loading #{count.zero? ? 'disabled' : ''}")
+ end
+ end
end
- end
-
- o[:artifacts] = []
- o[:artifacts] << 'notes' if ont.notes.length > 0
- o[:artifacts] << 'reviews' if ont.reviews.length > 0
- o[:artifacts] << 'projects' if ont.projects.length > 0
- o[:artifacts] << 'summary_only' if ont.summaryOnly
-
- sub = submissions_map[ont.acronym]
- if sub
- o[:submissionStatus] = sub.submissionStatus
- o[:submission] = true
- o[:pullLocation] = sub.pullLocation
- o[:description] = sub.description
- o[:creationDate] = sub.creationDate
- o[:released] = sub.released
- o[:naturalLanguage] = sub.naturalLanguage
- o[:hasFormalityLevel] = sub.hasFormalityLevel
- o[:isOfType] = sub.isOfType
- o[:submissionStatusFormatted] = submission_status2string(sub).gsub(/\(|\)/, '')
-
- o[:format] = sub.hasOntologyLanguage
- @formats << sub.hasOntologyLanguage
- else
- # Used to sort ontologies without submissions to the end when sorting on upload date
- o[:creationDate] = DateTime.parse('19900601')
- end
-
- @ontologies << o
+ end.flatten
+ else
+ streams = [replace("ontologies_list_view-page-#{@page.page}", partial: 'ontologies/browser/ontologies')]
end
- @ontologies.sort! {|a,b| b[:popularity] <=> a[:popularity]}
-
-
- render 'browse'
+ render turbo_stream: streams
end
def classes
@@ -158,7 +67,7 @@ def classes
get_class(params)
if @submission.hasOntologyLanguage == 'SKOS'
- @schemes = get_schemes(@ontology)
+ @schemes = get_schemes(@ontology)
@collections = get_collections(@ontology, add_colors: true)
else
@instance_details, type = get_instance_and_type(params[:instanceid])
@@ -168,19 +77,16 @@ def classes
@instances_concept_id = get_concept_id(params, @concept, @root)
end
-
if ['application/ld+json', 'application/json'].include?(request.accept)
render plain: @concept.to_jsonld, content_type: request.accept and return
end
@current_purl = @concept.purl if $PURL_ENABLED
- unless @concept.id == 'bp_fake_root'
+ unless @concept.nil? || @concept.id == 'bp_fake_root'
@notes = @concept.explore.notes
end
- update_tab(@ontology, @concept.id)
-
if request.xhr?
render 'ontologies/sections/visualize', layout: false
else
@@ -189,6 +95,9 @@ def classes
end
def properties
+ @acronym = @ontology.acronym
+ @properties = LinkedData::Client::HTTP.get("/ontologies/#{@acronym}/properties/roots", { lang: request_lang })
+
if request.xhr?
return render 'ontologies/sections/properties', layout: false
else
@@ -197,41 +106,40 @@ def properties
end
def create
- if params[:commit].eql? 'Cancel'
- redirect_to ontologies_path and return
+ @is_update_ontology = false
+ @ontology = ontology_from_params.save
+
+ if response_error?(@ontology)
+ show_new_errors(@ontology)
+ return
end
- @ontology = LinkedData::Client::Models::Ontology.new(values: ontology_params)
- @ontology_saved = @ontology.save
- if response_error?(@ontology_saved)
- @categories = LinkedData::Client::Models::Category.all
- @groups = LinkedData::Client::Models::Group.all(display_links: false, display_context: false)
- @user_select_list = LinkedData::Client::Models::User.all.map { |u| [u.username, u.id] }
- @user_select_list.sort! { |a, b| a[1].downcase <=> b[1].downcase }
- @errors = response_errors(@ontology_saved)
- render 'new'
+ @submission = save_submission(new_submission_hash(@ontology))
+
+ if response_error?(@submission)
+ @ontology.delete
+ show_new_errors(@submission)
else
- if @ontology_saved.summaryOnly
- redirect_to "/ontologies/success/#{@ontology.acronym}"
- else
- redirect_to new_ontology_submission_path(@ontology.acronym)
- end
+ redirect_to "/ontologies/success/#{@ontology.acronym}"
end
end
def edit
- # Note: find_by_acronym includes ontology views
@ontology = LinkedData::Client::Models::Ontology.find_by_acronym(params[:id]).first
redirect_to_home unless session[:user] && @ontology.administeredBy.include?(session[:user].id) || session[:user].admin?
- @categories = LinkedData::Client::Models::Category.all
- @groups = LinkedData::Client::Models::Group.all
- @user_select_list = LinkedData::Client::Models::User.all.map {|u| [u.username, u.id]}
- @user_select_list.sort! {|a,b| a[1].downcase <=> b[1].downcase}
+
+ submission = @ontology.explore.latest_submission(include: 'submissionId')
+ if submission
+ redirect_to edit_ontology_submission_path(@ontology.acronym, submission.submissionId)
+ else
+ redirect_to new_ontology_submission_path(@ontology.acronym)
+ end
end
def mappings
@ontology_acronym = @ontology.acronym || params[:id]
@mapping_counts = mapping_counts(@ontology_acronym)
+ @ontologies_mapping_count = LinkedData::Client::HTTP.get("#{MAPPINGS_URL}/statistics/ontologies")
if request.xhr?
render partial: 'ontologies/sections/mappings', layout: false
else
@@ -241,12 +149,14 @@ def mappings
def new
@ontology = LinkedData::Client::Models::Ontology.new
- @ontologies = LinkedData::Client::Models::Ontology.all(include: 'acronym', include_views: true,
-display_links: false, display_context: false)
+ @ontology.viewOf = params.dig(:ontology, :viewOf)
+ @submission = LinkedData::Client::Models::OntologySubmission.new
+ @submission.hasOntologyLanguage = 'OWL'
+ @ontologies = LinkedData::Client::Models::Ontology.all(include: 'acronym', include_views: true, display_links: false, display_context: false)
@categories = LinkedData::Client::Models::Category.all
@groups = LinkedData::Client::Models::Group.all
- @user_select_list = LinkedData::Client::Models::User.all.map {|u| [u.username, u.id]}
- @user_select_list.sort! {|a,b| a[1].downcase <=> b[1].downcase}
+ @user_select_list = LinkedData::Client::Models::User.all.map { |u| [u.username, u.id] }
+ @user_select_list.sort! { |a, b| a[1].downcase <=> b[1].downcase }
end
def notes
@@ -263,40 +173,50 @@ def notes
end
def instances
- if request.xhr?
- render partial: 'instances/instances', locals: { id: 'instances-data-table'}, layout: false
- else
- render partial: 'instances/instances', locals: { id: 'instances-data-table'}, layout: 'ontology_viewer'
+
+ if params[:instanceid]
+ @instance = helpers.get_instance_details_json(@ontology.acronym, params[:instanceid], {include: 'all'})
end
+
+ render partial: 'instances/instances', locals: { id: 'instances-data-table' }, layout: 'ontology_viewer'
end
def schemes
@schemes = get_schemes(@ontology)
- scheme_id = params[:scheme_id] || @submission_latest.URI || nil
+ scheme_id = params[:schemeid] || @submission_latest.URI || nil
@scheme = get_scheme(@ontology, scheme_id) if scheme_id
- if request.xhr?
- render partial: 'ontologies/sections/schemes', layout: false
- else
- render partial: 'ontologies/sections/schemes', layout: 'ontology_viewer'
- end
+ render partial: 'ontologies/sections/schemes', layout: 'ontology_viewer'
end
def collections
@collections = get_collections(@ontology)
- collection_id = params[:collection_id]
- @collection = get_collection(@ontology, collection_id) if collection_id
+ collection_id = params[:collectionid]
+ @collection = collection_id ? get_collection(@ontology, collection_id) : @collections.first
+
+ render partial: 'ontologies/sections/collections', layout: 'ontology_viewer'
+ end
+ def sparql
if request.xhr?
- render partial: 'ontologies/sections/collections', layout: false
+ render partial: 'ontologies/sections/sparql', layout: false
else
- render partial: 'ontologies/sections/collections', layout: 'ontology_viewer'
+ render partial: 'ontologies/sections/sparql', layout: 'ontology_viewer'
end
end
+ def content_serializer
+ @result, _ = serialize_content(ontology_acronym: params[:acronym],
+ concept_id: params[:id],
+ format: params[:output_format])
+
+ render 'ontologies/content_serializer', layout: nil
+ end
+
# GET /ontologies/ACRONYM
# GET /ontologies/1.xml
def show
+ return redirect_to_file if redirect_to_file?
# Hack to make ontologyid and conceptid work in addition to id and ontology params
params[:id] = params[:id].nil? ? params[:ontologyid] : params[:id]
@@ -326,21 +246,30 @@ def show
# Note: find_by_acronym includes ontology views
@ontology = LinkedData::Client::Models::Ontology.find_by_acronym(params[:ontology]).first
- ontology_not_found(params[:ontology]) if @ontology.nil?
+ ontology_not_found(params[:ontology]) if @ontology.nil? || @ontology.errors
# Handle the case where an ontology is converted to summary only.
# See: https://github.com/ncbo/bioportal_web_ui/issues/133.
- if @ontology.summaryOnly && params[:p].present?
- pages = KNOWN_PAGES - ['summary', 'notes']
- if pages.include?(params[:p])
- redirect_to(ontology_path(params[:ontology]), status: :temporary_redirect) and return
- end
+ data_pages = KNOWN_PAGES - %w[summary notes]
+ if @ontology.summaryOnly && params[:p].present? && data_pages.include?(params[:p].to_s)
+ params[:p] = "summary"
end
#@ob_instructions = helpers.ontolobridge_instructions_template(@ontology)
# Get the latest submission (not necessarily the latest 'ready' submission)
- @submission_latest = @ontology.explore.latest_submission(include: 'all') rescue @ontology.explore.latest_submission(include: '')
+
+ @submission_latest = @ontology.explore.latest_submission(include: 'all', invalidate_cache: invalidate_cache?) rescue @ontology.explore.latest_submission(include: '')
+
+
+ unless helpers.submission_ready?(@submission_latest)
+ submissions = @ontology.explore.submissions(include: 'submissionId,submissionStatus')
+ if submissions.any?{|x| helpers.submission_ready?(x)}
+ @old_submission_ready = true
+ elsif !params[:p].blank?
+ params[:p] = "summary"
+ end
+ end
# Is the ontology downloadable?
@ont_restricted = ontology_restricted?(@ontology.acronym)
@@ -354,15 +283,15 @@ def show
params[:p] = 'classes'
redirect_to "/ontologies/#{params[:ontology]}#{params_string_for_redirect(params)}", status: :moved_permanently
when 'classes'
- self.classes #rescue self.summary
+ self.classes # rescue self.summary
when 'mappings'
- self.mappings #rescue self.summary
+ self.mappings # rescue self.summary
when 'notes'
- self.notes #rescue self.summary
+ self.notes # rescue self.summary
when 'widgets'
- self.widgets #rescue self.summary
+ self.widgets # rescue self.summary
when 'properties'
- self.properties #rescue self.summary
+ self.properties # rescue self.summary
when 'summary'
self.summary
when 'instances'
@@ -371,10 +300,11 @@ def show
self.schemes
when 'collections'
self.collections
+ when 'sparql'
+ self.sparql
else
self.summary
end
-
end
def submit_success
@@ -382,31 +312,50 @@ def submit_success
render 'submit_success'
end
+
# Main ontology description page (with metadata): /ontologies/ACRONYM
def summary
- # Note: find_by_acronym includes ontology views
- @ontology = LinkedData::Client::Models::Ontology.find_by_acronym(params[:id]).first if @ontology.nil?
- ontology_not_found(params[:id]) if @ontology.nil?
- # Check to see if user is requesting json-ld, return the file from REST service if so
-
- if request.accept.to_s.eql?('application/ld+json') || request.accept.to_s.eql?('application/json')
- headers['Content-Type'] = request.accept.to_s
- render plain: @ontology.to_jsonld
- return
- end
@metrics = @ontology.explore.metrics rescue []
#@reviews = @ontology.explore.reviews.sort {|a,b| b.created <=> a.created} || []
- @projects = @ontology.explore.projects.sort {|a,b| a.name.downcase <=> b.name.downcase } || []
+ @projects = @ontology.explore.projects.sort { |a, b| a.name.downcase <=> b.name.downcase } || []
@analytics = LinkedData::Client::HTTP.get(@ontology.links['analytics'])
- #Call to fairness assessment service
+ # Call to fairness assessment service
tmp = fairness_service_enabled? ? get_fair_score(@ontology.acronym) : nil
@fair_scores_data = create_fair_scores_data(tmp.values.first) unless tmp.nil?
@views = get_views(@ontology)
- @view_decorators = @views.map{ |view| ViewDecorator.new(view, view_context) }
-
+ @view_decorators = @views.map { |view| ViewDecorator.new(view, view_context) }
+ @ontology_relations_data = ontology_relations_data
+
+ category_attributes = submission_metadata.group_by { |x| x['category'] }.transform_values { |x| x.map { |attr| attr['attribute'] } }
+ @relations_array_display = @relations_array.map do |relation|
+ attr = relation.split(':').last
+ ["#{helpers.attr_label(attr, attr_metadata: helpers.attr_metadata(attr), show_tooltip: false)}(#{relation})",
+ relation]
+ end
+ @config_properties = properties_hash_values(category_attributes["object description properties"])
+ @methodology_properties = properties_hash_values(category_attributes["methodology"])
+ @agents_properties = properties_hash_values(category_attributes["persons and organizations"])
+ @dates_properties = properties_hash_values(category_attributes["dates"])
+ @links_properties = properties_hash_values([:isFormatOf, :hasFormat, :source, :includedInDataCatalog])
+ @content_properties = properties_hash_values(category_attributes["content"])
+ @community_properties = properties_hash_values(category_attributes["community"] + [:notes])
+ @identifiers = properties_hash_values([:URI, :versionIRI, :identifier])
+ @identifiers["ontology_portal_uri"] = ["#{$UI_URL}/ontologies/#{@ontology.acronym}", "#{portal_name} URI"]
+ @projects_properties = properties_hash_values(category_attributes["usage"])
+ @ontology_icon_links = [%w[summary/download dataDump],
+ %w[summary/homepage homepage],
+ %w[summary/documentation documentation],
+ %w[icons/github repository],
+ %w[summary/sparql endpoint],
+ %w[icons/publication publication],
+ %w[icons/searching_database openSearchDescription]
+ ]
+ @ontology_icon_links.each do |icon|
+ icon << helpers.attr_label(icon[1], attr_metadata: helpers.attr_metadata(icon[1]), show_tooltip: false)
+ end
if request.xhr?
render partial: 'ontologies/sections/metadata', layout: false
else
@@ -414,31 +363,27 @@ def summary
end
end
- def update
- if params['commit'] == 'Cancel'
- acronym = params['id']
- redirect_to "/ontologies/#{acronym}"
- return
- end
- # Note: find_by_acronym includes ontology views
- @ontology = LinkedData::Client::Models::Ontology.find_by_acronym(params[:ontology][:acronym] || params[:id]).first
- @ontology.update_from_params(ontology_params)
- error_response = @ontology.update
- if response_error?(error_response)
- @categories = LinkedData::Client::Models::Category.all
- @user_select_list = LinkedData::Client::Models::User.all.map {|u| [u.username, u.id]}
- @user_select_list.sort! {|a,b| a[1].downcase <=> b[1].downcase}
- @errors = response_errors(error_response)
- @errors = { acronym: 'Acronym already exists, please use another' } if error_response.status == 409
- flash[:error] = @errors
- redirect_to "/ontologies/#{@ontology.acronym}/edit"
+ def subscriptions
+ ontology_id = params[:ontology_id]
+ return not_found if ontology_id.nil?
+
+ ontology_acronym = ontology_id.split('/').last
+
+ if session[:user].nil?
+ link = "/login?redirect=#{request.url}"
+ subscribed = false
+ user_id = nil
else
- # TODO_REV: Enable subscriptions
- # if params["ontology"]["subscribe_notifications"].eql?("1")
- # DataAccess.createUserSubscriptions(@ontology.administeredBy, @ontology.ontologyId, NOTIFICATION_TYPES[:all])
- # end
- redirect_to "/ontologies/#{@ontology.acronym}"
+ user = LinkedData::Client::Models::User.find(session[:user].id)
+ subscribed = helpers.subscribed_to_ontology?(ontology_acronym, user)
+ link = "javascript:void(0);"
+ user_id = user.id
end
+
+ count = helpers.count_subscriptions(params[:ontology_id])
+ render inline: helpers.turbo_frame_tag('subscribe_button') {
+ render_to_string(OntologySubscribeButtonComponent.new(id: '', ontology_id: ontology_id, subscribed: subscribed, user_id: user_id, count: count, link: link), layout: nil)
+ }
end
def virtual
@@ -457,20 +402,152 @@ def widgets
end
end
+ def show_licenses
+
+ @metadata = submission_metadata
+ @ontology = LinkedData::Client::Models::Ontology.find_by_acronym(params[:id]).first
+ @licenses = %w[hasLicense morePermissions copyrightHolder useGuidelines]
+ @submission_latest = @ontology.explore.latest_submission(include: @licenses.join(","))
+ render partial: 'ontologies/sections/licenses'
+ end
+
+ def ajax_ontologies
+
+ render json: LinkedData::Client::Models::Ontology.all(include_views: true,
+ display: 'acronym,name', display_links: false, display_context: false)
+ end
+
+ def metrics
+ @ontology = LinkedData::Client::Models::Ontology.find_by_acronym(params[:ontology_id]).first
+ @metrics = @ontology.explore.metrics(display_context: false, display_links: false)
+ render partial: 'ontologies/sections/metrics'
+ end
+
+ def metrics_evolution
+ @ontology = LinkedData::Client::Models::Ontology.find_by_acronym(params[:ontology_id]).first
+ key = params[:metrics_key]
+ ontology_not_found(params[:ontology_id]) if @ontology.nil?
+
+ # Retrieve submissions in descending submissionId order (should be reverse chronological order)
+ @submissions = @ontology.explore.submissions({ include: "metrics" })
+ .sort { |a, b| a.submissionId.to_i <=> b.submissionId.to_i }.reverse || []
+
+ metrics = @submissions.map { |s| s.metrics }
+
+ data = {
+ key => metrics.map { |m| m.nil? ? 0 : m[key] }
+ }
+
+ render partial: 'ontologies/sections/metadata/metrics_evolution_graph', locals: { data: data }
+ end
+
+ def ontologies_selector
+ @categories = LinkedData::Client::Models::Category.all(display_links: false, display_context: false)
+ @groups = LinkedData::Client::Models::Group.all(display_links: false, display_context: false)
+ @filters = ontology_filters_init(@categories, @groups)
+ @select_id = params[:id]
+ render 'ontologies/ontologies_selector/ontologies_selector', layout: false
+ end
+
+ def ontologies_selector_results
+ @ontologies = LinkedData::Client::Models::Ontology.all(include_views: params[:showOntologyViews])
+ @total_ontologies_number = @ontologies.length
+ @input = params[:input] || ''
+ @ontologies = @ontologies.select { |ontology| ontology.name.downcase.include?(@input.downcase) || ontology.acronym.downcase.include?(@input.downcase) }
+
+ if params[:groups]
+ @ontologies = @ontologies.select do |ontology|
+ (ontology.group & params[:groups]).any?
+ end
+ end
+
+ if params[:categories]
+ @ontologies = @ontologies.select do |ontology|
+ (ontology.hasDomain & params[:categories]).any?
+ end
+ end
+
+ if params[:formats] || params[:naturalLanguage] || params[:formalityLevel] || params[:isOfType] || params[:showRetiredOntologies]
+ submissions = LinkedData::Client::Models::OntologySubmission.all({ also_include_views: 'true' })
+ if params[:formats]
+ submissions = submissions.select { |submission| params[:formats].include?(submission.hasOntologyLanguage) }
+ end
+ if params[:naturalLanguage]
+ submissions = submissions.select do |submission|
+ (submission.naturalLanguage & params[:naturalLanguage]).any?
+ end
+ end
+ if params[:formalityLevel]
+ submissions = submissions.select { |submission| params[:formalityLevel].include?(submission.hasFormalityLevel) }
+ end
+ if params[:isOfType]
+ submissions = submissions.select { |submission| params[:isOfType].include?(submission.isOfType) }
+ end
+ if params[:showRetiredOntologies]
+ submissions = submissions.reject { |submission| submission.status.eql?('retired') }
+ end
+ @ontologies = @ontologies.select do |ontology|
+ submissions.any? { |submission| submission.ontology.id == ontology.id }
+ end
+ end
+ render 'ontologies/ontologies_selector/ontologies_selector_results'
+ end
private
- def ontology_params
- p = params.require(:ontology).permit(:name, :acronym, { administeredBy:[] }, :viewingRestriction, { acl:[] },
- { hasDomain:[] }, :isView, :viewOf, :subscribe_notifications, {group:[]})
+ def get_views(ontology)
+ views = ontology.explore.views || []
+ views.select! { |view| view.access?(session[:user]) }
+ views.sort { |a, b| a.acronym.downcase <=> b.acronym.downcase }
+ end
+
+ def ontology_relations_data(sub = @submission_latest)
+ ontology_relations_array = []
+ @relations_array = ["omv:useImports", "door:isAlignedTo", "door:ontologyRelatedTo", "omv:isBackwardCompatibleWith", "omv:isIncompatibleWith", "door:comesFromTheSameDomain", "door:similarTo",
+ "door:explanationEvolution", "voaf:generalizes", "door:hasDisparateModelling", "dct:hasPart", "voaf:usedBy", "schema:workTranslation", "schema:translationOfWork"]
+
+ return if sub.nil?
+
+ ont = sub.ontology
+ # Get ontology relations between each other (ex: STY isAlignedTo GO)
+ @relations_array.each do |relation_attr|
+ relation_values = sub.send(relation_attr.to_s.split(':')[1])
+ next if relation_values.nil? || relation_values.empty?
+
+ relation_values = [relation_values] unless relation_values.kind_of?(Array)
- p[:administeredBy].reject!(&:blank?)
- p[:acl].reject!(&:blank?)
- p[:hasDomain].reject!(&:blank?)
- p[:group].reject!(&:blank?)
- p.to_h
+ relation_values.each do |relation_value|
+ next if relation_value.eql?(ont.acronym)
+
+ target_id = relation_value
+ target_in_portal = false
+ target_ont = nil
+ # if we find our portal URL in the ontology URL, then we just keep the ACRONYM to try to get the ontology.
+ if relation_value.include?(helpers.portal_name.downcase)
+ relation_value = relation_value.split('/').last
+ target_ont = LinkedData::Client::Models::Ontology.find_by_acronym(relation_value).first
+ end
+
+ # Use acronym to get ontology from the portal
+ if target_ont
+ target_id = target_ont.acronym
+ target_in_portal = true
+ end
+
+ ontology_relations_array.push({ source: ont.acronym, target: target_id, relation: relation_attr.to_s, targetInPortal: target_in_portal })
+ end
+ end
+
+ ontology_relations_array
end
+ def properties_hash_values(properties, sub: @submission_latest, custom_labels: {})
+ return {} if sub.nil?
+
+ properties.map { |x| [x.to_s, [sub.send(x.to_s), custom_labels[x.to_sym]]] }.to_h
+ end
+
+
def determine_layout
case action_name
when 'index'
@@ -480,10 +557,5 @@ def determine_layout
end
end
- def get_views(ontology)
- views = ontology.explore.views || []
- views.select!{ |view| view.access?(session[:user]) }
- views.sort{ |a,b| a.acronym.downcase <=> b.acronym.downcase }
- end
end
diff --git a/app/controllers/ontologies_metadata_curator_controller.rb b/app/controllers/ontologies_metadata_curator_controller.rb
index 7b9c95cfb..b66c5df32 100644
--- a/app/controllers/ontologies_metadata_curator_controller.rb
+++ b/app/controllers/ontologies_metadata_curator_controller.rb
@@ -5,40 +5,46 @@ class OntologiesMetadataCuratorController < ApplicationController
before_action :submission_metadata, only: [:result, :edit, :update, :show_metadata_by_ontology]
def result
- @ontologies_ids = params[:ontology][:ontologyId].drop(1)
- @metadata_sel = params[:search][:metadata].drop(1)
+ @ontologies_ids = params[:ontology] ? Array(params[:ontology][:ontologyId]) : []
+ @metadata_sel = params[:search] ? params[:search][:metadata] : []
@show_submissions = !params[:show_submissions].nil?
- @ontologies = []
@submissions = []
- if @ontologies_ids.nil? || @ontologies_ids.empty?
- @ontologies = LinkedData::Client::Models::Ontology.all
- else
- @ontologies_ids.each do |data|
- @ontologies << LinkedData::Client::Models::Ontology.find_by_acronym(data).first
- end
- end
-
+ @ontologies = []
display_attribute = equivalent_properties(@metadata_sel) + %w[submissionId]
- @ontologies.each do |ont|
- if @show_submissions
- submissions = ont.explore.submissions({ include: display_attribute.join(',') })
+
+ if @show_submissions
+ if @ontologies_ids.nil? || @ontologies_ids.empty?
+ @ontologies = LinkedData::Client::Models::Ontology.all
else
- submissions = [ont.explore.latest_submission({ include: display_attribute.join(',') })]
+ @ontologies_ids.each do |data|
+ @ontologies << LinkedData::Client::Models::Ontology.find_by_acronym(data).first
+ end
+ end
+ @ontologies.each do |ont|
+ submissions = ont.explore.submissions({ include: display_attribute.join(',') })
+ submissions.each { |sub| append_submission(ont, sub) }
end
- submissions.each { |sub| append_submission(ont, sub) }
+ else
+ @submissions = LinkedData::Client::Models::OntologySubmission.all(acronym: @ontologies_ids.join('|'), display_links: false, display_context: false, include: display_attribute.join(','))
+ @submissions.reject! { |x| !@ontologies_ids.include?(x.id.split('/')[-3]) } unless @ontologies_ids.empty?
+ @submissions.sort_by! { |x| x.id }
end
+
+
+
respond_to do |format|
format.html { redirect_to admin_index_path }
format.turbo_stream { render turbo_stream: [
- replace("selection_metadata_form", partial: "ontologies_metadata_curator/metadata_table"),
- replace('edit_metadata_btn') do
- "
- #{helpers.button_tag("Start bulk edit", onclick: 'showEditForm(event)', class: "btn btn-outline-primary mx-1 w-100")}
- #{raw helpers.help_tooltip('To use the bulk edit select in the table submissions (the rows) and metadata properties (the columns) for which you want to edit')}
- ".html_safe
- end
- ]}
+ replace("selection_metadata_form", partial: "ontologies_metadata_curator/metadata_table")
+ # TODO put again when bulk edit fixed
+ # replace('edit_metadata_btn') do
+ # "
+ # #{helpers.button_tag(t('ontologies_metadata_curator.bulk_edit'), onclick: 'showEditForm(event)', class: "btn btn-outline-primary mx-1 w-100")}
+ # #{raw helpers.help_tooltip(t('ontologies_metadata_curator.use_the_bulk_edit'))}
+ # ".html_safe
+ # end
+ ] }
end
end
@@ -46,8 +52,7 @@ def show_metadata_by_ontology
@acronym = params[:ontology]
inline_save = params[:inline_save] && params[:inline_save].eql?('true')
display_submission_attributes(@acronym, params[:properties]&.split(','),
- submissionId: params[:submission_id],
- show_sections: false, inline_save: inline_save)
+ submissionId: params[:submission_id], inline_save: inline_save)
render partial: 'submissions/form_content', locals: { id: params[:form_id] || '', acronym: @acronym, submissionId: params[:submission_id] }
end
@@ -57,14 +62,15 @@ def show_metadata_value
submission_id = params[:submission_id]
@ontology = LinkedData::Client::Models::Ontology.find_by_acronym(acronym).first
@submission = @ontology.explore.submissions({ display: "#{attribute},submissionId" }, submission_id)
-
- render_submission_attribute(attribute)
+ id = attribute_input_frame_id(acronym, submission_id, attribute)
+ render_turbo_stream replace(id, partial: 'ontologies_metadata_curator/attribute', locals: { id: id, attribute: attribute,
+ submission: @submission, ontology: @ontology })
end
def edit
if params[:selected_acronyms].nil? || params[:selected_metadata].nil?
- render_turbo_stream alert_error(id: 'application_modal_content') {'Select in the table submissions (rows) and metadata properties (columns) to start the bulk edit'}
+ render_turbo_stream alert_error(id: 'application_modal_content') { t('ontologies_metadata_curator.start_the_bulk_edit') }
return
end
@@ -79,14 +85,14 @@ def update
@active_ontology = ontology_and_submission_id(params[:active_ontology])
@all_metadata = params[:all_metadata]&.split
error_responses = []
- @submissions = []
+ @submissions = []
active_submission_data = params['submission']["#{@active_ontology[0]}_#{@active_ontology[1]}"]
@selected_ontologies.each do |onto, sub_i|
new_data = active_submission_data
new_data[:ontology] = onto
new_data[:id] = sub_i
- error_responses << update_submission(new_data) if new_data
+ error_responses << update_submission(new_data, sub_i).last if new_data
@submissions << @submission
end
@@ -99,10 +105,10 @@ def update
if errors
render_turbo_stream(alert_error { errors.map { |e| e[:error] }.join(',') })
else
- streams = [alert_success { 'Submissions were successfully updated' }]
+ streams = [alert_success { t('ontologies_metadata_curator.alert_success_submissions') }]
@submissions.each do |submission|
- submission.ontology = OpenStruct.new({acronym: submission.ontology})
- streams << replace("#{ontology_submission_id_label(submission.ontology.acronym, submission.submissionId)}_row", partial: 'ontologies_metadata_curator/metadata_table_row', locals: {submission: submission, attributes: @all_metadata })
+ submission.ontology = OpenStruct.new({ acronym: submission.ontology })
+ streams << replace("#{ontology_submission_id_label(submission.ontology.acronym, submission.submissionId)}_row", partial: 'ontologies_metadata_curator/submission', locals: { submission: submission, attributes: @all_metadata })
end
render_turbo_stream(*streams)
end
@@ -121,45 +127,4 @@ def append_submission(ontology, submission)
@submissions << sub
end
- def metadata_params
- attributes = [
- :ontology,
- :description,
- :hasOntologyLanguage,
- :prefLabelProperty,
- :synonymProperty,
- :definitionProperty,
- :authorProperty,
- :obsoleteProperty,
- :obsoleteParent,
- :version,
- :status,
- :released,
- :isRemote,
- :pullLocation,
- :filePath,
- { contact: [:name, :email] },
- :homepage,
- :documentation,
- :publication
- ]
-
- @metadata.each do |m|
-
- m_attr = m["attribute"].to_sym
-
- attributes << if m["enforce"].include?("list")
- { m_attr => [] }
- else
- m_attr
- end
- end
- out = []
- params.require(:submission).permit!.tap do |x|
- x.keys.each do |y|
- out << x.require(y).permit(attributes.uniq)
- end
- end
- out
- end
end
diff --git a/app/controllers/ontologies_redirection_controller.rb b/app/controllers/ontologies_redirection_controller.rb
new file mode 100644
index 000000000..43269e788
--- /dev/null
+++ b/app/controllers/ontologies_redirection_controller.rb
@@ -0,0 +1,93 @@
+class OntologiesRedirectionController < ApplicationController
+ include UriRedirection
+ include OntologyContentSerializer
+
+ # GET /ontologies/:acronym/:id
+ def redirect
+ return not_found unless params[:acronym] && params[:id]
+
+ request_accept_header = request.env["HTTP_ACCEPT"].split(",")[0]
+ type, resource_id = find_type_by_id(params[:id], params[:acronym])
+
+ if resource_id.nil?
+ @ontology = LinkedData::Client::Models::Ontology.find_by_acronym(params[:acronym]).first
+ @submission_latest = @ontology.explore.latest_submission(include: "URI")
+ resource_id = @submission_latest.URI
+ end
+
+ if request_accept_header == "text/html"
+ if type.nil? || resource_id.blank?
+ redirect_to ontology_path(id: params[:acronym], p: 'summary')
+ else
+ redirect_to link_by_type(resource_id, params[:acronym], type)
+ end
+ else
+ content, serializer_content_type = serialize_content(ontology_acronym: params[:acronym], concept_id: resource_id, format: request_accept_header)
+ render plain: content, content_type: serializer_content_type
+ end
+ end
+
+ # GET /ontologies/:acronym/htaccess
+ def generate_htaccess
+ ontology = LinkedData::Client::Models::Ontology.find_by_acronym(params[:acronym]).first
+ ontology_uri = ontology.explore.latest_submission(include: 'URI').URI
+ ontology_portal_url = "#{$UI_URL}/ontologies/#{params[:acronym]}"
+
+ @htaccess_content = generate_htaccess_content(ontology_portal_url, ontology_uri)
+ @nginx_content = generate_nginx_content(ontology_portal_url, ontology_uri)
+
+ render 'ontologies/htaccess', layout: nil
+ end
+
+ # GET /ontologies/ACRONYM/download?format=FORMAT
+ def redirect_ontology
+ redirect_url = "#{rest_url}/ontologies/#{params[:acronym]}"
+ download_url = "#{redirect_url}/download?apikey=#{get_apikey}"
+ case params[:format]
+ when 'text/csv', 'csv'
+ redirect_to("#{download_url}&download_format=csv", allow_other_host: true)
+ when 'text/xml', 'text/rdf+xml', 'application/rdf+xml', 'application/xml', 'xml'
+ redirect_to("#{download_url}&download_format=rdf", allow_other_host: true)
+ when 'application/json', 'application/ld+json', 'application/*', 'json'
+ # redirect to the api
+ redirect_to("#{redirect_url}?apikey=#{get_apikey}", allow_other_host: true)
+ else
+ # redirect to download the original file
+ redirect_to("#{download_url}", allow_other_host: true)
+ end
+ end
+
+
+ private
+
+ def generate_htaccess_content(ontology_portal_url, ontology_uri)
+ ontology_rule = nil
+ if ontology_uri
+ ontology_uri += '/' unless ontology_uri.end_with?('/')
+ ontology_rule = "RewriteRule ^#{URI.parse(ontology_uri).path[1..-1]}?$ #{ontology_portal_url} [R=301,L]"
+ end
+
+ <<-HTACCESS.strip_heredoc
+ RewriteEngine On
+ #{ontology_rule if ontology_rule}
+ RewriteRule ^.*/([^/#]+)$ #{ontology_portal_url}/$1 [R=301,L]
+ HTACCESS
+ end
+
+ def generate_nginx_content(ontology_portal_url, ontology_uri)
+ ontology_rule = nil
+ if ontology_uri
+ ontology_uri += '/' unless ontology_uri.end_with?('/')
+ ontology_rule = "rewrite ^#{URI.parse(ontology_uri).path[1..-1]}?$ #{ontology_portal_url} permanent"
+ end
+
+ <<-NGINX.strip_heredoc
+ location / {
+ #{ontology_rule if ontology_rule}
+ if ($request_uri ~ ^.*/([^/]+)$){
+ return 301 #{ontology_portal_url}/$1;
+ }
+ }
+ NGINX
+ end
+end
\ No newline at end of file
diff --git a/app/controllers/precache_controller.rb b/app/controllers/precache_controller.rb
deleted file mode 100644
index 54f229074..000000000
--- a/app/controllers/precache_controller.rb
+++ /dev/null
@@ -1,96 +0,0 @@
-require 'uri'
-
-class PrecacheController < ApplicationController
-
- $UI_PORT = "80"
- # $UI_PORT = "3000"
-
-
- def self.precache_all(delete_cache = false)
- if delete_cache
- p "Deleting general cache info"
- CACHE.delete("act_ont_list")
- CACHE.delete("ont_list")
- CACHE.delete("ontology_acronyms")
- CACHE.delete("classes_all_ontologies")
- end
-
- get_url("http://localhost:#{$UI_PORT}")
- get_url("http://localhost:#{$UI_PORT}/ontologies")
- get_url("http://localhost:#{$UI_PORT}/mappings")
- precache_ontology_summary(delete_cache)
- precache_ontology_notes(delete_cache)
- precache_ontology_mappings(delete_cache)
- precache_ontology_classes(delete_cache)
- end
-
- def self.precache_ontology_classes(delete_cache = false)
- ontologies = DataAccess.getOntologyList
- ontologies.each do |ont|
- if delete_cache
- # remove relevant cache data
- end
-
- get_url("http://localhost:#{$UI_PORT}/ontologies/#{ont.ontologyId}?p=classes")
- end
- end
-
- def self.precache_ontology_summary(delete_cache = false)
- ontologies = DataAccess.getOntologyList
- ontologies.each do |ont|
- if delete_cache
- p "Deleting cache for #{ont.displayLabel}"
- CACHE.delete("#{ont.ontologyId}::_latest")
- CACHE.delete("#{ont.ontologyId}::_versions")
- CACHE.delete("#{ont.ontologyId}::_details")
- CACHE.delete("#{ont.ontologyId}::_metrics")
- end
-
- get_url("http://localhost:#{$UI_PORT}/ontologies/#{ont.ontologyId}")
- end
- end
-
- def self.precache_ontology_mappings(delete_cache = false)
- ontologies = DataAccess.getOntologyList
- ontologies.each do |ont|
- if delete_cache
- CACHE.delete("between_ontologies::map_count::#{ont.ontologyId}")
- end
-
- get_url("http://localhost:#{$UI_PORT}/ontologies/#{ont.ontologyId}?p=mappings")
- end
- end
-
- def self.precache_ontology_notes(delete_cache = false)
- ontologies = DataAccess.getOntologyList
- ontologies.each do |ont|
- if delete_cache
- # remove relevant cache data
- end
-
- get_url("http://localhost:#{$UI_PORT}/ontologies/#{ont.ontologyId}?p=notes")
- end
- end
-
- def self.get_url(url)
- p url
- uri = URI.parse(url)
-
- http = Net::HTTP.new(uri.host, uri.port)
- http.read_timeout = 360
-
- begin
- timer = Time.now
- res = http.start { |con|
- path = uri.path.empty? ? "/" : uri.path
- con.get(path)
- }
- p "Retrieved in #{(Time.now - timer).to_f.round(2)}s"
- rescue Exception => e
- p "Failed to get #{url}: #{e.message}"
- end
-
- res.body
- end
-
-end
diff --git a/app/controllers/projects_controller.rb b/app/controllers/projects_controller.rb
index eb9f35297..490072b4b 100644
--- a/app/controllers/projects_controller.rb
+++ b/app/controllers/projects_controller.rb
@@ -22,7 +22,7 @@ def index
def show
projects = LinkedData::Client::Models::Project.find_by_acronym(params[:id])
if projects.nil? || projects.empty?
- flash[:notice] = flash_error("Project not found: #{params[:id]}")
+ flash[:notice] = flash_error(t('projects.project_not_found', id: params[:id]))
redirect_to projects_path
return
end
@@ -55,7 +55,7 @@ def new
def edit
projects = LinkedData::Client::Models::Project.find_by_acronym(params[:id])
if projects.nil? || projects.empty?
- flash[:notice] = flash_error("Project not found: #{params[:id]}")
+ flash[:notice] = flash_error(t('projects.project_not_found', id: params[:id]))
redirect_to projects_path
return
end
@@ -79,14 +79,14 @@ def create
# Project successfully created.
if response_success?(@project_saved)
- flash[:notice] = 'Project successfully created'
+ flash[:notice] = t('projects.project_successfully_created')
redirect_to project_path(@project.acronym)
return
end
# Errors creating project.
if @project_saved.status == 409
- error = OpenStruct.new existence: "Project with acronym #{params[:project][:acronym]} already exists. Please enter a unique acronym."
+ error = OpenStruct.new existence: t('projects.error_unique_acronym', acronym: params[:project][:acronym])
@errors = Hash[:error, OpenStruct.new(acronym: error)]
else
@errors = response_errors(@project_saved)
@@ -107,7 +107,7 @@ def update
end
projects = LinkedData::Client::Models::Project.find_by_acronym(params[:id])
if projects.nil? || projects.empty?
- flash[:notice] = flash_error("Project not found: #{params[:id]}")
+ flash[:notice] = flash_error(t('projects.project_not_found', id: params[:id]))
redirect_to projects_path
return
end
@@ -122,7 +122,7 @@ def update
@errors = response_errors(error_response)
render :edit
else
- flash[:notice] = 'Project successfully updated'
+ flash[:notice] = t('projects.project_successfully_updated')
redirect_to project_path(@project.acronym)
end
end
@@ -132,7 +132,7 @@ def update
def destroy
projects = LinkedData::Client::Models::Project.find_by_acronym(params[:id])
if projects.nil? || projects.empty?
- flash[:notice] = flash_error("Project not found: #{params[:id]}")
+ flash[:notice] = flash_error(t('projects.project_not_found', id: params[:id]))
redirect_to projects_path
return
end
@@ -140,13 +140,13 @@ def destroy
error_response = @project.delete
if response_error?(error_response)
@errors = response_errors(error_response)
- flash[:notice] = "Project delete failed: #{@errors}"
+ flash[:notice] = t('projects.error_delete_project', errors: @errors)
respond_to do |format|
format.html { redirect_to projects_path }
format.xml { head :internal_server_error }
end
else
- flash[:notice] = 'Project successfully deleted'
+ flash[:notice] = t('projects.project_successfully_deleted')
respond_to do |format|
format.html { redirect_to projects_path }
format.xml { head :ok }
@@ -160,8 +160,9 @@ def destroy
def project_params
p = params.require(:project).permit(:name, :acronym, :institution, :contacts, { creator:[] }, :homePage,
:description, { ontologyUsed:[] })
- p[:creator].reject!(&:blank?)
- p[:ontologyUsed].reject!(&:blank?)
+
+ p[:creator]&.reject!(&:blank?)
+ p[:ontologyUsed]&.reject!(&:blank?)
p.to_h
end
diff --git a/app/controllers/properties_controller.rb b/app/controllers/properties_controller.rb
new file mode 100644
index 000000000..0ff2a3167
--- /dev/null
+++ b/app/controllers/properties_controller.rb
@@ -0,0 +1,94 @@
+class PropertiesController < ApplicationController
+ include TurboHelper, SearchContent
+
+ def index
+ acronym = params[:ontology]
+ @ontology = LinkedData::Client::Models::Ontology.find_by_acronym(acronym).first
+ ontology_not_found(acronym) if @ontology.nil?
+
+ if params[:search].blank?
+ index_tree('properties_sorted_list_view-page-1')
+ else
+ query, page, page_size = helpers.search_content_params
+
+ results, _, next_page, total_count = search_ontologies_content(query: query,
+ page: page,
+ page_size: page_size,
+ filter_by_ontologies: [acronym],
+ filter_by_types: %w[AnnotationProperty ObjectProperty DatatypeProperty])
+
+
+ render inline: helpers.render_search_paginated_list(container_id: 'properties_sorted_list',
+ next_page_url: "/ontologies/#{@ontology.acronym}/properties",
+ child_url: "/ontologies/#{@ontology.acronym}/properties/show",
+ child_turbo_frame: 'property_show',
+ child_param: :propertyid,
+ results: results, next_page: next_page, total_count: total_count)
+ end
+ end
+
+
+ def show
+ @acronym = params[:ontology]
+ @property = get_property(params[:id], @acronym, include: 'all')
+
+ redirect_to(ontology_path(id: params[:ontology], p: 'properties', propertyid: params[:id], lang: request_lang)) and return unless turbo_frame_request?
+
+ render partial: 'show'
+ end
+
+
+ def show_children
+ acronym = params[:ontology]
+ id = params[:propertyid]
+ @property = get_property(id, acronym)
+ @property.children = property_children(id, acronym)
+
+ render turbo_stream: [
+ replace(helpers.child_id(@property) + '_open_link') { TreeLinkComponent.tree_close_icon },
+ replace(helpers.child_id(@property) + '_childs') do
+ helpers.property_tree_component(@property, @property, acronym, request_lang, sub_tree: true)
+ end
+ ]
+ end
+
+ private
+
+ def get_property(id, acronym = params[:acronym], lang = request_lang, include: nil)
+ LinkedData::Client::HTTP.get("/ontologies/#{acronym}/properties/#{helpers.encode_param(id)}", { lang: lang , include: include})
+ end
+
+ def property_tree(id, acronym = params[:acronym], lang = request_lang)
+ LinkedData::Client::HTTP.get("/ontologies/#{acronym}/properties/#{helpers.encode_param(id)}/tree", { lang: lang })
+ end
+
+ def property_roots(acronym = params[:acronym], lang = request_lang)
+ LinkedData::Client::HTTP.get("/ontologies/#{acronym}/properties/roots", { lang: lang })
+ end
+
+ def property_children(id, acronym = params[:acronym], lang = request_lang)
+ LinkedData::Client::HTTP.get("/ontologies/#{acronym}/properties/#{helpers.encode_param(id)}/children", { lang: lang })
+ end
+
+
+ private
+
+ def index_tree(container_id)
+ if !params[:propertyid].blank?
+ @root = OpenStruct.new({ children: property_tree(params[:propertyid], params[:ontology]) })
+ not_found(@root.children.errors.join) if @root.children.respond_to?(:errors)
+
+ @property = get_property(params[:propertyid], params[:ontology])
+ else
+ @root = OpenStruct.new({ children: property_roots(params[:ontology]) })
+ not_found(@root.children.errors.join) if @root.children.respond_to?(:errors)
+
+ @property ||= @root.children.first
+ end
+
+ render inline: helpers.property_tree_component(@root, @property,
+ @ontology.acronym, request_lang,
+ id: container_id, auto_click: true)
+ end
+
+end
diff --git a/app/controllers/recommender_controller.rb b/app/controllers/recommender_controller.rb
index 591ffc326..64759cd50 100644
--- a/app/controllers/recommender_controller.rb
+++ b/app/controllers/recommender_controller.rb
@@ -1,49 +1,57 @@
class RecommenderController < ApplicationController
layout :determine_layout
+ include ApplicationHelper
# REST_URI is defined in application_controller.rb
RECOMMENDER_URI = "/recommender"
def index
+ @text = params[:text]
+ @results_table_header = [t('recommender.results_table.ontology'), t('recommender.results_table.final_score'),
+ t('recommender.results_table.coverage_score'), t('recommender.results_table.acceptance_score'),
+ t('recommender.results_table.detail_score'), t('recommender.results_table.specialization_score'),
+ t('recommender.results_table.annotations')
+ ]
+ @advanced_options_open = false
+ if params[:max_elements_set]
+ @not_valid_max_num_set = (params[:max_elements_set] < '2') || (params[:max_elements_set] > '4')
+ end
+ unless params[:input].nil? || params[:input].empty? || @not_valid_max_num_set
+ recommendations = LinkedData::Client::HTTP.post(RECOMMENDER_URI, params)
+ @advanced_options_open = !recommender_params_empty?
+ @results = []
+ @json_link = "#{$REST_URL}/recommender?input=#{params[:input]}&apikey=#{$API_KEY}&ontologies=#{params[:ontologies]}&max_elements_set=#{params[:max_elements_set]}&input_type=#{params[:input_type]}&output_type=#{params[:output_type]}&wc=#{params[:wc]}&wa=#{params[:wa]}&wd=#{params[:wd]}&ws=#{params[:ws]}"
+ recommendations.each do |recommendation|
+ row = {
+ ontologies: recommendation_ontologies(recommendation),
+ final_score: percentage(recommendation.evaluationScore),
+ coverage_score: percentage(recommendation.coverageResult.normalizedScore),
+ acceptance_score: percentage(recommendation.acceptanceResult.normalizedScore),
+ details_score: percentage(recommendation.detailResult.normalizedScore),
+ specialization_score: percentage(recommendation.specializationResult.normalizedScore),
+ annotations: recommendation_annotations(recommendation),
+ highlighted: false,
+ }
+ @results.push(row)
+ @results.max_by { |element| element[:final_score] }[:highlighted] = true
+ end
+ end
end
- # def create
- # # Parse params (default values are set at the service level)
- # input = params[:input].strip.gsub("\r\n", " ").gsub("\n", " ")
- # start = Time.now
- # query = RECOMMENDER_URI
- # query += "?input=" + CGI.escape(input)
- # query += "&ontologies=" + CGI.escape(params[:ontologies].join(',')) unless params[:ontologies].nil?
- # query += "&input_type=" + params[:input_type] unless params[:input_type].nil?
- # query += "&output_type=" + params[:output_type] unless params[:output_type].nil?
- # query += "&max_elements_set=" + params[:max_elements_set] unless params[:output_type].nil?
- # query += "&wc=" + params[:wc].to_s unless params[:wc].nil?
- # query += "&ws=" + params[:ws].to_s unless params[:ws].nil?
- # query += "&wa=" + params[:wa].to_s unless params[:wa].nil?
- # query += "&wd=" + params[:wd].to_s unless params[:wd].nil?
- # recommendations = parse_json(query) # See application_controller.rb
- # LOG.add :debug, "Retrieved #{recommendations.length} recommendations: #{Time.now - start}s"
- # render :json => recommendations
- # end
+ def recommendation_ontologies(recommendation)
+ recommendation.ontologies.map { |ont| { acronym: ont.acronym, link: ont.id } }
+ end
+
+ def recommendation_annotations(recommendation)
+ recommendation.coverageResult.annotations.map{|annotation| {text: annotation.text, link: url_to_endpoint(annotation.annotatedClass.links['self'])}}
+ end
- # NOTE: this call (POST) works at a local environment but not in staging
- def create
- start = Time.now
- input = params[:input].strip.gsub("\r\n", " ").gsub("\n", " ")
- # Default values are set at the service level)
- form_data = Hash.new
- form_data['input'] = input
- form_data['ontologies'] = params[:ontologies].join(',') unless params[:ontologies].nil?
- form_data['input_type'] = params[:input_type] unless params[:input_type].nil?
- form_data['output_type'] = params[:output_type] unless params[:output_type].nil?
- form_data['max_elements_set'] = params[:max_elements_set] unless params[:output_type].nil?
- form_data['wc'] = params[:wc].to_s unless params[:wc].nil?
- form_data['ws'] = params[:ws].to_s unless params[:ws].nil?
- form_data['wa'] = params[:wa].to_s unless params[:wa].nil?
- form_data['wd'] = params[:wd].to_s unless params[:wd].nil?
- recommendations = LinkedData::Client::HTTP.post(RECOMMENDER_URI, form_data, raw: true)
- LOG.add :debug, "Retrieved #{recommendations.length} recommendations: #{Time.now - start}s"
- render json: recommendations
+ def percentage(string)
+ result = string.to_f * 100
+ result.round(1).to_s
end
+ def recommender_params_empty?
+ (params[:wc].eql?('0.55') && params[:wa].eql?('0.15') && params[:wd].eql?('0.15') && params[:ws].eql?('0.15') && params[:max_elements_set].eql?('3') && params[:ontologies].nil?)
+ end
end
diff --git a/app/controllers/reviews_controller.rb b/app/controllers/reviews_controller.rb
deleted file mode 100644
index c36ef5b7b..000000000
--- a/app/controllers/reviews_controller.rb
+++ /dev/null
@@ -1,90 +0,0 @@
-class ReviewsController < ApplicationController
-
- layout 'ontology_viewer'
-
- RATING_TYPES = [
- :usabilityRating,
- :coverageRating,
- :qualityRating,
- :formalityRating,
- :correctnessRating,
- :documentationRating
- ].freeze
-
- def new
- @rating_types = RATING_TYPES
- @ontology = LinkedData::Client::Models::Ontology.find(params[:ontology])
- @review = LinkedData::Client::Models::Review.new(values: {ontologyReviewed: @ontology.id, creator: session[:user].id})
-
- if request.xhr?
- render layout: false
- end
- end
-
- # GET /reviews/1/edit
- def edit
- @review = Review.find(params[:id])
- @rating_types = RatingType.all
-
- if request.xhr?
- render layout: false
- end
- end
-
- def create
- @review = LinkedData::Client::Models::Review.new(values: params[:review])
- @ontology = LinkedData::Client::Models::Ontology.find(@review.ontologyReviewed)
- @review_saved = @review.save
- if response_error?(@review_saved)
- @errors = response_errors(@review_saved)
- render :action => "new"
- else
- respond_to do |format|
- format.html do
- flash[:notice] = 'Review was successfully created'
- redirect_to "/ontologies/#{@ontology.acronym}?p=summary"
- end
- format.js do
- render json: {}
- end
- end
- end
- end
-
- # PUT /reviews/1
- # PUT /reviews/1.xml
- def update
- @review = Review.find(params[:id])
- ratings = Hash[*(@review.ratings.map{|rate| [rate.id.to_i, rate] }.flatten)]
- #puts ratings.inspect
- for rating_key in params.keys
- if rating_key.include?("star")
- #puts rating_key.split("_")[1].to_i
- ratings[rating_key.split("_")[1].to_i].value=params[rating_key].to_i
- ratings[rating_key.split("_")[1].to_i].save
- end
- end
- if @review.update_attributes(params[:review])
- @review.reload
- if request.xhr?
- render :action=>'show', :layout=>false
- else
- redirect_to reviews(:ontology=>review.ontology_id)
- end
- else
- render :action => "edit"
- end
- end
-
- # DELETE /reviews/1
- # DELETE /reviews/1.xml
- def destroy
- @review = Review.find(params[:id])
- @review.destroy
-
- respond_to do |format|
- format.html { redirect_to(reviews_url) }
- format.xml { head :ok }
- end
- end
-end
diff --git a/app/controllers/schemes_controller.rb b/app/controllers/schemes_controller.rb
index 661bda5ab..bea96a89d 100644
--- a/app/controllers/schemes_controller.rb
+++ b/app/controllers/schemes_controller.rb
@@ -1,7 +1,39 @@
class SchemesController < ApplicationController
- include SchemesHelper
+ include SchemesHelper, SearchContent
+
+
+ def index
+ acronym = params[:ontology]
+ @ontology = LinkedData::Client::Models::Ontology.find_by_acronym(acronym).first
+ ontology_not_found(acronym) if @ontology.nil?
+
+ if params[:search].blank?
+ @submission_latest = @ontology.explore.latest_submission(include: 'all', invalidate_cache: invalidate_cache?) rescue @ontology.explore.latest_submission(include: '')
+ @schemes = get_schemes(@ontology)
+
+ render partial: 'schemes/tree_view'
+ else
+ query, page, page_size = helpers.search_content_params
+
+ results, _, next_page, total_count = search_ontologies_content(query: query,
+ page: page,
+ page_size: page_size,
+ filter_by_ontologies: [acronym],
+ filter_by_types: ['ConceptScheme'])
+
+
+ render inline: helpers.render_search_paginated_list(container_id: 'schemes_sorted_list',
+ next_page_url: "/ontologies/#{@ontology.acronym}/schemes",
+ child_url: "/ontologies/#{@ontology.acronym}/schemes/show", child_turbo_frame: 'scheme',
+ child_param: :schemeid,
+ results: results, next_page: next_page, total_count: total_count
+ )
+ end
+ end
def show
+ redirect_to(ontology_path(id: params[:ontology_id], p: 'schemes', schemeid: params[:id],lang: request_lang)) and return unless turbo_frame_request?
+
@scheme = get_request_scheme
end
@@ -10,17 +42,17 @@ def show_label
scheme_label = scheme ? scheme['prefLabel'] : params[:id]
scheme_label = scheme_label.nil? || scheme_label.empty? ? params[:id] : scheme_label
- render LabelLinkComponent.inline(params[:id], scheme_label)
+ render LabelLinkComponent.inline(params[:id], helpers.main_language_label(scheme_label))
end
private
def get_request_scheme
- params[:id] = params[:id] ? params[:id] : params[:scheme_id]
+ params[:id] = params[:id] ? params[:id] : params[:schemeid]
params[:ontology_id] = params[:ontology_id] ? params[:ontology_id] : params[:ontology]
if params[:id].nil? || params[:id].empty?
- render :text => "Error: You must provide a valid scheme id"
+ render :text => t('schemes.error_valid_scheme_id')
return
end
@ontology = LinkedData::Client::Models::Ontology.find_by_acronym(params[:ontology_id]).first
diff --git a/app/controllers/search_controller.rb b/app/controllers/search_controller.rb
index b5d052583..eeb510ca3 100644
--- a/app/controllers/search_controller.rb
+++ b/app/controllers/search_controller.rb
@@ -1,52 +1,72 @@
require 'uri'
class SearchController < ApplicationController
+ include SearchAggregator, SearchContent
skip_before_action :verify_authenticity_token
layout :determine_layout
def index
- @search_query = params[:query].nil? ? params[:q] : params[:query]
- @search_query ||= ""
+ @search_query = params[:query] || params[:q] || ''
+ params[:query] = nil
+ @advanced_options_open = false
+ @search_results = []
+ @json_url = json_link("#{rest_url}/search", {})
+
+ return if @search_query.empty?
+
+ params[:pagesize] = "150"
+ results = LinkedData::Client::Models::Class.search(@search_query, params).collection
+
+ @advanced_options_open = !search_params_empty?
+ @search_results = aggregate_results(@search_query, results)
+ @json_url = json_link("#{rest_url}/search", params.permit!.to_h)
end
def json_search
if params[:q].nil?
- render :text => "No search class provided"
+ render :text => t('search.no_search_class_provided')
return
end
check_params_query(params)
check_params_ontologies(params) # Filter on ontology_id
+ if params["id"]&.eql?('All')
+ params.delete("id")
+ params.delete("ontologies")
+ end
search_page = LinkedData::Client::Models::Class.search(params[:q], params)
@results = search_page.collection
response = ""
obsolete_response = ""
separator = (params[:separator].nil?) ? "~!~" : params[:separator]
- for result in @results
+
+ for result in Array(@results)
# TODO_REV: Format the response with type information, target information
# record_type = format_record_type(result[:recordType], result[:obsolete])
record_type = ""
- target_value = result.prefLabel
+ target_value = result.prefLabel.select{|x| x.include?( params[:q].delete('*'))}.first || result.prefLabel.first
+
case params[:target]
- when "name"
- target_value = result.prefLabel
- when "shortid"
- target_value = result.id
- when "uri"
- target_value = result.id
+ when "name"
+ target_value = result.prefLabel
+ when "shortid"
+ target_value = result.id
+ when "uri"
+ target_value = result.id
end
+ acronym = result.links["ontology"].split('/').last
json = []
json << "#{target_value}"
json << " [obsolete]" if result.obsolete? # used by JS in ontologies/visualize to markup obsolete classes
json << "|#{result.id}"
json << "|#{record_type}"
- json << "|#{result.explore.ontology.acronym}"
+ json << "|#{acronym}"
json << "|#{result.id}" # Duplicated because we used to have shortId and fullId
- json << "|#{result.prefLabel}"
+ json << "|#{target_value}"
# This is nasty, but hard to workaround unless we rewrite everything (form_autocomplete, jump_to, crossdomain_autocomplete)
# to use JSON from the bottom up. To avoid this, we pass a tab separated column list
# Columns: synonym
@@ -54,8 +74,8 @@ def json_search
if params[:id] && params[:id].split(",").length == 1
json << "|#{CGI.escape((result.definition || []).join(". "))}#{separator}"
else
- json << "|#{result.explore.ontology.name}"
- json << "|#{result.explore.ontology.acronym}"
+ json << "|#{acronym}"
+ json << "|#{acronym}"
json << "|#{CGI.escape((result.definition || []).join(". "))}#{separator}"
end
@@ -80,6 +100,22 @@ def json_search
render plain: response, content_type: content_type
end
+ def json_ontology_content_search
+ query = params[:search] || '*'
+ page = (params[:page] || 1).to_i
+ acronyms = params[:ontologies]&.split(',') || []
+ page_size = (params[:page_size] || 10).to_i
+ type = params[:types]&.split(',') || []
+
+
+ results, page, next_page, total_count = search_ontologies_content(query: query,
+ page: page,
+ page_size: page_size,
+ filter_by_ontologies: acronyms,
+ filter_by_types: type)
+
+ render json: results
+ end
private
@@ -103,21 +139,17 @@ def check_params_ontologies(params)
end
end
- def format_record_type(record_type, obsolete = false)
- case record_type
- when "apreferredname"
- record_text = "Preferred Name"
- when "bconceptid"
- record_text = "Class ID"
- when "csynonym"
- record_text = "Synonym"
- when "dproperty"
- record_text = "Property"
- else
- record_text = ""
- end
- record_text = "Obsolete Class" if obsolete
- record_text
+ def search_params
+ [
+ :ontologies, :categories,
+ :also_search_properties, :also_search_obsolete, :also_search_views,
+ :require_exact_match, :require_definition
+ ]
+ end
+
+ def search_params_empty?
+ (params[:lang].nil? || params[:lang].eql?('all')) &&
+ search_params.all?{|key| params[key].nil? || params[key].empty?}
end
end
diff --git a/app/controllers/statistics_controller.rb b/app/controllers/statistics_controller.rb
new file mode 100644
index 000000000..ac3828f02
--- /dev/null
+++ b/app/controllers/statistics_controller.rb
@@ -0,0 +1,14 @@
+class StatisticsController < ApplicationController
+ include StatisticsHelper, ComponentsHelper
+
+ layout :determine_layout
+
+ def index
+ projects = LinkedData::Client::Models::Project.all({include: 'created'})
+ users = LinkedData::Client::Models::User.all({include: 'created'})
+ year_month_count, @year_month_visits = ontologies_by_year_month
+ @merged_data = merge_time_evolution_data([group_by_year_month(users),
+ group_by_year_month(projects),
+ year_month_count])
+ end
+end
diff --git a/app/controllers/submissions_controller.rb b/app/controllers/submissions_controller.rb
index 5bb8b3501..d08a99055 100644
--- a/app/controllers/submissions_controller.rb
+++ b/app/controllers/submissions_controller.rb
@@ -1,5 +1,5 @@
class SubmissionsController < ApplicationController
- include SubmissionsHelper, SubmissionUpdater
+ include SubmissionsHelper, SubmissionUpdater, OntologyUpdater
include DoiRequest
layout :determine_layout
before_action :authorize_and_redirect, :only => [:edit, :update, :create, :new]
@@ -14,41 +14,44 @@ def index
@ont_restricted = ontology_restricted?(@ontology.acronym)
# Retrieve submissions in descending submissionId order (should be reverse chronological order)
- @submissions = @ontology.explore.submissions({include: "submissionId,creationDate,released,modificationDate,submissionStatus,hasOntologyLanguage,version,diffFilePath,ontology"})
+ @submissions = @ontology.explore.submissions({include: "submissionId,creationDate,released,modificationDate,submissionStatus,hasOntologyLanguage,version,diffFilePath,ontology", invalidate_cache: invalidate_cache?})
.sort {|a,b| b.submissionId.to_i <=> a.submissionId.to_i } || []
- LOG.add :error, "No submissions for ontology: #{@ontology.id}" if @submissions.empty?
-
+ LOG.add :error, t('submissions.no_submissions_for_ontology', ontology: @ontology.id) if @submissions.empty?
+ render :index, layout: nil
end
# When getting "Add submission" form to display
def new
- @required_only = params[:required].nil? || !params[:required]&.eql?('false')
- @ontology = LinkedData::Client::Models::Ontology.get(CGI.unescape(params[:ontology_id])) rescue nil
- @ontology = LinkedData::Client::Models::Ontology.find_by_acronym(params[:ontology_id]).first unless @ontology
- @submission = @ontology.explore.latest_submission
+ @ontology = LinkedData::Client::Models::Ontology.find_by_acronym(params[:ontology_id]).first
+ @submission = @ontology.explore.latest_submission || LinkedData::Client::Models::OntologySubmission.new
@identifier_request = first_pending_doi_request
- @submission ||= LinkedData::Client::Models::OntologySubmission.new
@submission.id = nil
+ @categories = LinkedData::Client::Models::Category.all
+ @groups = LinkedData::Client::Models::Group.all
+ @user_select_list = LinkedData::Client::Models::User.all.map {|u| [u.username, u.id]}
+ @user_select_list.sort! {|a,b| a[1].downcase <=> b[1].downcase}
+ @is_update_ontology = true
+ render "ontologies/new"
end
# Called when form to "Add submission" is submitted
def create
- # Make the contacts an array
- _, submission_params = params[:submission].each.first
- @required_only = !params['required-only'].nil?
- @filters_disabled = true
- @submission_saved = save_submission(submission_params)
- if response_error?(@submission_saved)
- @errors = response_errors(@submission_saved) # see application_controller::response_errors
- if @errors && @errors[:uploadFilePath]
- @errors = ["Please specify the location of your ontology"]
- elsif @errors && @errors[:contact]
- @errors = ["Please enter a contact"]
+ @is_update_ontology = true
+
+ if params[:ontology]
+ @ontology, response = update_existent_ontology(params[:ontology_id])
+
+ if response.nil? || response_error?(response)
+ show_new_errors(response)
+ return
end
+ end
+ @submission = @ontology.explore.latest_submission({ display: 'all' })
+ @submission = save_submission(new_submission_hash(@ontology, @submission))
- reset_agent_attributes
- render 'new', status: 422
+ if response_error?(@submission)
+ show_new_errors(@submission)
else
cancel_pending_doi_requests
submit_new_doi_request if doi_requested?
@@ -57,51 +60,70 @@ def create
end
# Called when form to "Edit submission" is submitted
- def edit
- display_submission_attributes params[:ontology_id], params[:properties]&.split(','), submissionId: params[:id],
- required: params[:required]&.eql?('true'),
- show_sections: params[:show_sections].nil? || params[:show_sections].eql?('true'),
+ def edit_properties
+ display_submission_attributes params[:ontology_id], params[:properties]&.split(','), submissionId: params[:submission_id],
inline_save: params[:inline_save]&.eql?('true')
@identifier_request = first_pending_doi_request
+
+ attribute_template_output = render_to_string(inline: helpers.render_submission_inputs(params[:container_id] || 'metadata_by_ontology', @submission))
+
+ render inline: attribute_template_output
+
+ end
+
+ def edit
+ @ontology = LinkedData::Client::Models::Ontology.find_by_acronym(params[:ontology_id]).first
+ ontology_not_found(params[:ontology_id]) unless @ontology
+ category_attributes = submission_metadata.group_by{|x| x['category']}.transform_values{|x| x.map{|attr| attr['attribute']} }
+ category_attributes = category_attributes.reject{|key| ['no'].include?(key.to_s)}
+ category_attributes['general'] << %w[acronym name groups administeredBy categories]
+ category_attributes['licensing'] << 'viewingRestriction'
+ category_attributes['relations'] << 'viewOf'
+ @selected_attributes = Array(params[:properties])
+ if @selected_attributes.empty?
+ @categories_order = ['general', 'description', 'dates', 'licensing', 'persons and organizations', 'links', 'media', 'community', 'usage' ,'relations', 'content','methodology', 'object description properties']
+ @category_attributes = category_attributes
+ end
+ render 'submissions/edit', layout: params[:container_id] ? nil : 'ontology'
end
# When editing a submission (called when submit "Edit submission information" form)
def update
- error_responses = []
- _, submission_params = params[:submission].each.first
-
- error_responses << update_submission(submission_params)
+ @is_update_ontology = true
+ acronym = params[:ontology_id]
+ submission_id = params[:id]
+ if params[:ontology]
+ @ontology, response = update_existent_ontology(acronym)
+
+ if response.nil? || response_error?(response)
+ show_new_errors(response, partial: 'submissions/form_content', id: 'test')
+ return
+ end
+ end
- if error_responses.compact.any? { |x| x.status != 204 }
- @errors = error_responses.map { |error_response| response_errors(error_response) }
+ if params[:submission].nil?
+ return redirect_to "/ontologies/#{acronym}",
+ notice: t('submissions.submission_updated_successfully')
end
- if @errors && !params[:attribute]
- @required_only = !params['required-only'].nil?
- @filters_disabled = true
- reset_agent_attributes
- render 'edit', status: 422
- elsif params[:attribute]
+ @submission, response = update_submission(update_submission_hash(acronym), submission_id, @ontology)
+ if params[:attribute].nil?
+ if response_error?(response)
+ show_new_errors(response, partial: 'submissions/form_content', id: 'test')
+ else
+ redirect_to "/ontologies/#{acronym}",
+ notice: t('submissions.submission_updated_successfully'), status: :see_other
+ end
+ else
+ @errors = response_errors(response) if response_error?(response)
+ @submission = submission_from_params(params[:submission])
+ @submission.submissionId = submission_id
reset_agent_attributes
render_submission_attribute(params[:attribute])
- else
submit_new_doi_request if doi_requested?
- redirect_to "/ontologies/#{@ontology.acronym}"
end
end
- private
-
- def reset_agent_attributes
- helpers.agent_attributes.each do |attr|
- current_val = @submission.send(attr)
- new_values = Array(current_val).map { |x| LinkedData::Client::Models::Agent.find(x) }
-
- new_values = new_values.first unless current_val.is_a?(Array)
-
- @submission.send("#{attr}=", new_values)
- end
- end
end
diff --git a/app/controllers/subscriptions_controller.rb b/app/controllers/subscriptions_controller.rb
index 54040a415..54d262c56 100644
--- a/app/controllers/subscriptions_controller.rb
+++ b/app/controllers/subscriptions_controller.rb
@@ -3,7 +3,7 @@ class SubscriptionsController < ApplicationController
def create
# Try to get the user linked data instance
user_id = params[:user_id]
- u = LinkedData::Client::Models::User.find(user_id)
+ u = LinkedData::Client::Models::User.get(helpers.escape(user_id), include: 'all')
raise Exception if u.nil?
# Try to get the ontology linked data instance
@@ -25,6 +25,8 @@ def create
# So here we re-generate a new subscription Array (instead of directly updating it, which causes error)
all_subs = []
u.subscription.each do |subs|
+ next if subs.ontology.nil?
+
# Add all subscription to the array, but not the one to be deleted
if !subs.ontology.split('/').last.eql?(ont.acronym)
all_subs.push({ontology: subs.ontology, notification_type: subs.notification_type})
@@ -42,6 +44,7 @@ def create
already_subscribed = false
all_subs = []
u.subscription.each do |subs|
+ next if subs.ontology.nil?
# add all existing subscriptions
all_subs.push({ontology: subs.ontology, notification_type: subs.notification_type})
if subs.ontology.split("/").last == ont.acronym && subs.notification_type == "NOTES"
diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb
index 288b352f3..f487637be 100644
--- a/app/controllers/users_controller.rb
+++ b/app/controllers/users_controller.rb
@@ -1,25 +1,36 @@
class UsersController < ApplicationController
- before_action :unescape_id, only: [:edit, :show, :update]
before_action :verify_owner, only: [:edit, :show, :subscribe, :un_subscribe]
before_action :authorize_admin, only: [:index,:subscribe, :un_subscribe]
layout :determine_layout
+ include TurboHelper
+
+
+ def index
+
+ onts = LinkedData::Client::Models::Ontology.all(include: 'administeredBy')
+ projects = LinkedData::Client::Models::Project.all(include: 'creator')
+
+ @users = LinkedData::Client::Models::User.all(include: 'all')
+ @users.each do |user|
+ user.ontologies = onts.select {|o| o.administeredBy.include? user.id }
+ user.project = projects.select {|p| p.creator.include? user.id }
+ end
+
+ end
# GET /users/1
# GET /users/1.xml
def show
@user = if session[:user].admin? && params.has_key?(:id)
- LinkedData::Client::Models::User.find_by_username(params[:id]).first
+ find_user(params[:id])
else
- LinkedData::Client::Models::User.find(session[:user].id)
+ find_user(session[:user].id)
end
@all_ontologies = LinkedData::Client::Models::Ontology.all(ignore_custom_ontologies: true)
- logger.info 'user show'
- logger.info @user.bring_remaining
- logger.info @user
@user_ontologies = @user.customOntology
## Copied from home controller , account action
@@ -37,10 +48,9 @@ def new
# GET /users/1;edit
def edit
- @user = LinkedData::Client::Models::User.find(params[:id])
- @user ||= LinkedData::Client::Models::User.find_by_username(params[:id]).first
+ @user = find_user
- if (params[:password].eql?("true"))
+ if params[:password].eql?("true")
@user.validate_password = true
end
end
@@ -63,7 +73,7 @@ def create
SubscribeMailer.register_for_announce_list(@user.email,@user.firstName,@user.lastName).deliver rescue nil
end
- flash[:notice] = 'Account was successfully created'
+ flash[:notice] = t('users.account_successfully_created')
session[:user] = LinkedData::Client::Models::User.authenticate(@user.username, @user.password)
redirect_to_browse
end
@@ -75,8 +85,7 @@ def create
# PUT /users/1
# PUT /users/1.xml
def update
- @user = LinkedData::Client::Models::User.find(params[:id])
- @user = LinkedData::Client::Models::User.find_by_username(params[:id]).first if @user.nil?
+ @user = find_user
@errors = validate_update(user_params)
if @errors.size < 1
@@ -98,7 +107,7 @@ def update
# @errors = {acronym: "Username already exists, please use another"} if error_response.status == 409
render action: "edit"
else
- flash[:notice] = 'Account was successfully updated'
+ flash[:notice] = t('users.account_successfully_updated')
if session[:user].username == @user.username
session[:user].update_from_params(user_params)
@@ -112,23 +121,33 @@ def update
# DELETE /users/1
def destroy
- response = {errors: '', success: ''}
- @user = LinkedData::Client::Models::User.find(params[:id])
- @user = LinkedData::Client::Models::User.find_by_username(params[:id]).first if @user.nil?
- if(session[:user].admin?)
+ response = {errors: nil, success: ''}
+ @user = find_user
+
+ if session[:user].admin?
@user.delete
- response[:success] << 'User deleted successfully '
+ response[:success] << t('users.user_deleted_successfully')
else
- response[:errors] << 'Not permitted '
+ response[:errors] << t('users.not_permitted')
end
- render json: response
+ respond_to do |format|
+ format.turbo_stream do
+ if response[:errors]
+ render_turbo_stream alert(type: 'danger') { response[:errors].to_s }
+ else
+ render turbo_stream: [
+ alert(type: 'success') { response[:success] },
+ turbo_stream.remove(params[:id])
+ ]
+ end
+ end
+ end
end
def custom_ontologies
- @user = LinkedData::Client::Models::User.find(params[:id])
- @user = LinkedData::Client::Models::User.find_by_username(params[:id]).first if @user.nil?
+ @user = find_user
custom_ontologies = params[:ontology] ? params[:ontology][:ontologyId] : []
custom_ontologies.reject!(&:blank?)
@@ -136,14 +155,14 @@ def custom_ontologies
error_response = !@user.update
if error_response
- flash[:notice] = 'Error saving Custom Ontologies, please try again'
+ flash[:notice] = t('users.error_saving_custom_ontologies')
else
updated_user = LinkedData::Client::Models::User.find(@user.id)
session[:user].update_from_params(customOntology: updated_user.customOntology)
flash[:notice] = if updated_user.customOntology.empty?
- 'Custom Ontologies were cleared'
+ t('users.custom_ontologies_cleared')
else
- 'Custom Ontologies were saved'
+ t('users.custom_ontologies_saved')
end
end
redirect_to user_path(@user.username)
@@ -151,10 +170,11 @@ def custom_ontologies
def subscribe
- @user = LinkedData::Client::Models::User.find_by_username(params[:username]).first
+ @user = find_user
deliver "subscribe", SubscribeMailer.register_for_announce_list(@user.email,@user.firstName,@user.lastName)
end
+
def un_subscribe
@email = params[:email]
deliver "unsubscribe", SubscribeMailer.unregister_for_announce_list(@email)
@@ -163,13 +183,23 @@ def un_subscribe
private
+ def find_user(id = params[:id])
+ id = helpers.unescape(id)
+ @user = LinkedData::Client::Models::User.find(helpers.escape(id), include: 'all')
+ @user ||= LinkedData::Client::Models::User.find_by_username(helpers.escape(id), include: 'all').first
+
+ not_found("User with id #{id} not found") if @user.nil?
+
+ @user
+ end
+
def deliver(action,job)
begin
job.deliver
to_or_from = action.eql?("subscribe") ? "to" : "from"
- flash[:success] = "You have successfully #{action} #{to_or_from} our user mailing list: #{$ANNOUNCE_LIST}"
+ flash[:success] = t('users.subscribe_flash_message', action: action, to_or_from: to_or_from, list: $ANNOUNCE_LIST)
rescue => exception
- flash[:error] = "Something went wrong ..."
+ flash[:error] = t('users.error_subscribe')
end
redirect_to '/account'
end
@@ -178,7 +208,7 @@ def user_params
params[:user]["orcidId"] = extract_id_from_url(params[:user]["orcidId"], 'orcid.org')
params[:user]["githubId"] = extract_id_from_url(params[:user]["githubId"], 'github.com')
p = params.require(:user).permit(:firstName, :lastName, :username, :orcidId, :githubId, :email, :email_confirmation, :password,
- :password_confirmation, :register_mail_list, :admin)
+ :password_confirmation, :register_mail_list, :admin, :terms_and_conditions)
p.to_h
end
@@ -213,25 +243,31 @@ def get_ontology_list(ont_hash)
def validate(params)
errors = []
if params[:email].nil? || params[:email].length < 1 || !params[:email].match(/^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$/i)
- errors << "Please enter an email address"
+ errors << t('users.validate_email_address')
end
if params[:password].nil? || params[:password].length < 1
- errors << "Please enter a password"
+ errors << t('users.validate_password')
end
if !params[:password].eql?(params[:password_confirmation])
- errors << "Your Password and Password Confirmation do not match"
+ errors << t('users.validate_password_confirmation')
end
if using_captcha?
if !verify_recaptcha
- errors << "Please fill in the proper text from the supplied image"
+ errors << t('users.recaptcha_validation')
end
end
+
+
if ((!params[:orcidId].match(/^\d{4}+(-\d{4})+$/)) || (params[:orcidId].length != 19)) && !(params[:orcidId].nil? || params[:orcidId].length < 1)
- errors << "Please enter a valide orcid id"
+ errors << t('users.validate_orcid')
end
if params[:username].nil? || params[:username].length < 1 || !params[:username].match(/^[a-zA-Z0-9]([._-](?![._-])|[a-zA-Z0-9]){3,18}[a-zA-Z0-9]$/)
- errors << "please enter a valid username"
+ errors << t('users.validate_username')
+ end
+
+ unless params[:terms_and_conditions]
+ errors << t('users.validate_terms_and_conditions')
end
return errors
end
@@ -239,22 +275,22 @@ def validate(params)
def validate_update(params)
errors = []
if params[:email].nil? || params[:email].length < 1 || !params[:email].match(/^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}$/i)
- errors << "Please enter a valid email adresse"
+ errors << t('users.valid_email_adresse')
end
if params[:firstName].nil? || params[:firstName].length < 1
- errors << "First name field is required"
+ errors << t('users.first_name_required')
end
if params[:lastName].nil? || params[:lastName].length < 1
- errors << "Last name field is required"
+ errors << t('users.last_name_required')
end
if params[:username].nil? || params[:username].length < 1
- errors << "Last name field is required"
+ errors << t('users.last_name_required')
end
if params[:orcidId].present? && ((!params[:orcidId].match(/^\d{4}-\d{4}-\d{4}-\d{4}$/)) || (params[:orcidId].length != 19))
- errors << "Please enter a valide orcide id"
+ errors << t('users.validate_orcid')
end
if !params[:password].eql?(params[:password_confirmation])
- errors << "Your Password and Password Confirmation do not match"
+ errors << t('users.validate_password_confirmation')
end
return errors
diff --git a/app/controllers/virtual_appliance_controller.rb b/app/controllers/virtual_appliance_controller.rb
index 5b3701711..c78b6603f 100644
--- a/app/controllers/virtual_appliance_controller.rb
+++ b/app/controllers/virtual_appliance_controller.rb
@@ -19,7 +19,7 @@ def create
user = LinkedData::Client::Models::User.find_by_username(params[:appliance_user][:user_id]).first
if user.nil?
- flash[:error] = "Problem adding account #{params[:appliance_user][:user_id]} : account does not exist".html_safe
+ flash[:error] = t('ontoportal_virtual_appliance.problem_adding_account', id: params[:appliance_user][:user_id]).html_safe
redirect_to action: 'index' and return
end
@@ -38,7 +38,7 @@ def create
def require_login
return if session[:user]
- flash[:error] = 'You must be logged in to access this section'
+ flash[:error] = t('ontoportal_virtual_appliance.require_login')
redirect_to login_index_path(redirect: virtual_appliance_index_path)
end
end
diff --git a/app/helpers/admin/licenses_helper.rb b/app/helpers/admin/licenses_helper.rb
index 4d11f0b1f..90fa67bbf 100644
--- a/app/helpers/admin/licenses_helper.rb
+++ b/app/helpers/admin/licenses_helper.rb
@@ -2,12 +2,11 @@ module Admin::LicensesHelper
def license_notification(license)
days = license.days_remaining
-
if (days == 0)
- msg = (t(".license_expired") << " " << t(".license_contact")).html_safe
+ msg = (t("admin.licenses.license_notification.license_expired") << " " << t("admin.licenses.license_notification.license_contact")).html_safe
notification = tag.div msg, class: "alert alert-danger mt-3", role: "alert"
elsif license.is_trial?
- msg = (t(".license_trial", count: days) << " " << t(".license_obtain") << " " << t(".license_contact")).html_safe
+ msg = (t("admin.licenses.license_notification.license_trial", count: days) << " " << t("admin.licenses.license_notification.license_obtain") << " " << t("admin.licenses.license_notification.license_contact")).html_safe
notification = tag.div msg, class: "alert alert-info mt-3", role: "alert"
end
diff --git a/app/helpers/admin_helper.rb b/app/helpers/admin_helper.rb
index 7553a567d..b7814bef3 100644
--- a/app/helpers/admin_helper.rb
+++ b/app/helpers/admin_helper.rb
@@ -3,4 +3,23 @@ def selected_admin_section?(section_title)
current_section = params[:section] || 'site'
current_section.eql?(section_title)
end
+
+
+ def new_ontologies_created_title
+ content_tag(:div,
+ t('admin.new_ontologies_created_title', count: @new_ontologies_count.join(', ')),
+ style: 'width: 400px; max-height: 300px')
+ end
+
+ def visits_evolution
+ return 0 if @users_visits[:visits].empty?
+
+ @users_visits[:visits].last - @users_visits[:visits][-2]
+ end
+
+ def action_button(name, link, method: :post, class_style: 'btn btn-link')
+ button_to name, link, method: method, class: class_style,
+ form: {data: { turbo: true, turbo_confirm: t('admin.turbo_confirm', name: name), turbo_frame: '_top'}}
+
+ end
end
diff --git a/app/helpers/agent_helper.rb b/app/helpers/agent_helper.rb
index 1b3630a55..00caebe47 100644
--- a/app/helpers/agent_helper.rb
+++ b/app/helpers/agent_helper.rb
@@ -41,17 +41,34 @@ def agent_id(agent)
def link_to_agent_edit_modal(agent, parent_id = nil)
- link_to_modal(nil, edit_agent_path(agent_id(agent), parent_id: parent_id, show_affiliations: parent_id.nil? || parent_id.empty?), class: 'btn btn-sm btn-light', data: { show_modal_title_value: "Edit agent #{agent.id}" }) do
+ link_to_modal(nil, edit_agent_path(agent_id(agent), parent_id: parent_id, show_affiliations: parent_id.nil? || parent_id.empty?), class: 'btn btn-sm btn-light', data: { show_modal_title_value: "Edit agent #{agent.name}" }) do
content_tag(:i, '', class: 'far fa-edit')
end
end
- def link_to_agent_edit(agent, parent_id = nil)
- link_to(edit_agent_path(agent_id(agent), parent_id: parent_id, show_affiliations: parent_id.nil? || parent_id.empty?), class: 'btn btn-sm btn-light') do
+ def link_to_agent_edit(agent, parent_id, name_prefix, deletable: false, show_affiliations: true)
+ link_to(edit_agent_path(agent_id(agent), name_prefix: name_prefix, deletable: deletable, parent_id: parent_id, show_affiliations: show_affiliations), class: 'btn btn-sm btn-light') do
content_tag(:i, '', class: 'far fa-edit')
end
end
+
+ def link_to_search_agent(id, parent_id , name_prefix, agent_type, deletable)
+ link_to("/agents/show_search?id=#{id}&parent_id=#{parent_id}&agent_type=#{agent_type}&deletable=#{deletable}&name_prefix=#{name_prefix}", class: 'btn btn-sm btn-light') do
+ inline_svg_tag "x.svg", width: "25", height: "25"
+ end
+ end
+
+ def agent_search_input(id, agent_type, parent_id: , name_prefix:, deletable: false)
+ render TurboFrameComponent.new(id: agent_id_frame_id(id, parent_id)) do
+ render AgentSearchInputComponent.new(id: id, agent_type: agent_type,
+ name_prefix: name_prefix,
+ parent_id: parent_id, deletable: deletable,
+ edit_on_modal: false)
+ end
+ end
+
+
def affiliation?(agent)
agent.agentType.eql?('organization')
end
@@ -78,15 +95,6 @@ def display_identifiers(identifiers, link: true)
end.join(', ')
end
- def display_agent(agent, link: true)
- out = agent.name.to_s.titleize
- identifiers = display_identifiers(agent.identifiers, link: link)
- out = "#{out} (#{identifiers})" unless identifiers.empty?
- affiliations = agent.affiliations.map { |a| display_agent(a, link: link) }.join(', ')
- out = "#{out} (affiliations: #{affiliations})" unless affiliations.empty?
- out
- end
-
def agent_field_name(name, name_prefix = '')
name_prefix&.empty? ? name : "#{name_prefix}[#{name}]"
end
@@ -101,4 +109,132 @@ def new_affiliation_obj
a.creator = session[:user].id
a
end
+
+ def agent_usages(agent = @agent)
+ usages = agent.usages.to_h
+ usages.delete(:links)
+ usages.delete(:context)
+ usages
+ end
+
+ def agent_usages_count(agent = @agent)
+ usages = agent_usages(agent)
+ usages.values.flatten.size
+ end
+
+ def agents_metadata
+ submission_metadata.select { |x| x["enforce"]&.include?('Agent') }.map do |x|
+ SubmissionInputsHelper::SubmissionMetadataInput.new(attribute_key: x["attribute"], attr_metadata: x)
+ end
+ end
+ def agents_metadata_attributes
+ agents_metadata.map { |x| [x.attr, x.label] }
+ end
+
+ def agents_used_properties(agent)
+ usages = agent_usages(agent)
+ attributes = agents_metadata_attributes
+
+ attributes.map do |attr, label|
+ [attr, usages.select { |x, v| v.any? { |uri| uri[attr] } }.keys.map { |x| x.to_s.split('/')[-3] }]
+ end.to_h
+ end
+
+ def agent_usage_errors_display(errors)
+ content_tag(:div) do
+ errors.map do |ont, message|
+ content_tag(:p) do
+ (content_tag(:strong, ont) + t('agents.ontology_not_valid') + agent_usage_error_display(message[:error])).html_safe
+ end
+ end.join.html_safe
+ end
+ end
+
+ def agent_usage_error_display(error)
+ error.map do |attr, details|
+ details.values.join(', ').html_safe
+ end.join('. ').html_safe
+ end
+
+ def display_agent(agent, link: true)
+ agent_chip_component(agent)
+ end
+
+ def agent_tooltip(agent)
+ name = agent.name
+ email = agent.email
+ type = agent.agentType
+ identifiers = display_identifiers(agent.identifiers, link: false)
+ identifiers = orcid_number(identifiers)
+ if agent.affiliations && agent.affiliations != []
+ affiliations = ""
+ agent.affiliations.each do |affiliation|
+ affiliations = affiliations + affiliation.acronym + " "
+ end
+ end
+ person_icon = inline_svg_tag 'icons/person.svg' , class: 'agent-type-icon'
+ organization_icon = inline_svg_tag 'icons/organization.svg', class: 'agent-type-icon'
+ ror_icon = inline_svg_tag 'icons/ror.svg', class: 'agent-dependency-icon ror'
+ orcid_icon = inline_svg_tag 'icons/orcid.svg', class: 'agent-dependency-icon'
+ agent_icon = type == "organization" ? organization_icon : person_icon
+ identifiers_icon = type == "organization" ? ror_icon : orcid_icon
+ tooltip_html = generate_agent_tooltip(agent_icon, name, email, identifiers, affiliations, identifiers_icon)
+ return tooltip_html
+ end
+
+ def generate_agent_tooltip(agent_icon, name, email = nil, identifiers = nil, affiliations = nil, identifiers_icon = nil)
+ content_tag(:div, class: 'agent-container') do
+ content_tag(:div, agent_icon, class: 'agent-circle') +
+ content_tag(:div) do
+ content_tag(:div, name, class: 'agent-name') +
+ content_tag(:div, email || '', class: 'agent-dependency') +
+ unless identifiers.to_s.empty?
+ content_tag(:div, class: 'agent-dependency') do
+ identifiers_icon +
+ identifiers || ''
+ end
+ end +
+ unless affiliations.to_s.empty?
+ content_tag(:div, class: 'agent-dependency') do
+ inline_svg_tag('icons/organization.svg', class: 'agent-dependency-icon') +
+ affiliations || ''
+ end
+ end
+ end
+ end
+ end
+
+
+ def agent_chip_component(agent)
+ person_icon = inline_svg_tag 'icons/person.svg' , class: 'agent-type-icon'
+ organization_icon = inline_svg_tag 'icons/organization.svg', class: 'agent-type-icon'
+ agent_icon = person_icon
+
+ if agent.is_a?(String)
+ name = agent
+ title = nil
+ else
+ name = agent.name
+ agent_icon = agent.agentType.eql?("organization") ? organization_icon : person_icon
+ title = agent_tooltip(agent)
+ end
+ render_chip_component(title, agent_icon, name)
+ end
+
+
+ def render_chip_component(title,agent_icon,name)
+ render ChipButtonComponent.new(type: "static",'data-controller':' tooltip', title: title , class: 'text-truncate', style: 'max-width: 280px; display:block; line-height: unset') do
+ content_tag(:div, class: 'agent-chip') do
+ content_tag(:div, agent_icon, class: 'agent-chip-circle') +
+ content_tag(:div, name, class: 'agent-chip-name text-truncate')
+ end
+ end
+ end
+
+ def orcid_number(orcid)
+ return orcid.split("/").last
+ end
+
+
+
end
diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb
index ddff53082..e768f3b95 100644
--- a/app/helpers/application_helper.rb
+++ b/app/helpers/application_helper.rb
@@ -6,6 +6,41 @@
require 'pry' # used in a rescue
module ApplicationHelper
+ REST_URI = $REST_URL
+ API_KEY = $API_KEY
+
+ include ModalHelper, MultiLanguagesHelper, UrlsHelper
+
+ RESOLVE_NAMESPACE = {:omv => "http://omv.ontoware.org/2005/05/ontology#", :skos => "http://www.w3.org/2004/02/skos/core#", :owl => "http://www.w3.org/2002/07/owl#",
+ :rdf => "http://www.w3.org/1999/02/22-rdf-syntax-ns#", :rdfs => "http://www.w3.org/2000/01/rdf-schema#", :metadata => "http://data.bioontology.org/metadata/",
+ :metadata_def => "http://data.bioontology.org/metadata/def/", :dc => "http://purl.org/dc/elements/1.1/", :xsd => "http://www.w3.org/2001/XMLSchema#",
+ :oboinowl_gen => "http://www.geneontology.org/formats/oboInOwl#", :obo_purl => "http://purl.obolibrary.org/obo/",
+ :umls => "http://bioportal.bioontology.org/ontologies/umls/", :door => "http://kannel.open.ac.uk/ontology#", :dct => "http://purl.org/dc/terms/",
+ :void => "http://rdfs.org/ns/void#", :foaf => "http://xmlns.com/foaf/0.1/", :vann => "http://purl.org/vocab/vann/", :adms => "http://www.w3.org/ns/adms#",
+ :voaf => "http://purl.org/vocommons/voaf#", :dcat => "http://www.w3.org/ns/dcat#", :mod => "http://www.isibang.ac.in/ns/mod#", :prov => "http://www.w3.org/ns/prov#",
+ :cc => "http://creativecommons.org/ns#", :schema => "http://schema.org/", :doap => "http://usefulinc.com/ns/doap#", :bibo => "http://purl.org/ontology/bibo/",
+ :wdrs => "http://www.w3.org/2007/05/powder-s#", :cito => "http://purl.org/spar/cito/", :pav => "http://purl.org/pav/", :nkos => "http://w3id.org/nkos/nkostype#",
+ :oboInOwl => "http://www.geneontology.org/formats/oboInOwl#", :idot => "http://identifiers.org/idot/", :sd => "http://www.w3.org/ns/sparql-service-description#",
+ :cclicense => "http://creativecommons.org/licenses/",
+ 'skos-xl' => "http://www.w3.org/2008/05/skos-xl#"}
+ def url_to_endpoint(url)
+ uri = URI.parse(url)
+ endpoint = uri.path.sub(/^\//, '')
+ endpoint
+ end
+
+ def search_json_link(link = @json_url, style: '')
+ custom_style = "font-size: 50px; line-height: 0.5; margin-left: 6px; #{style}".strip
+ render IconWithTooltipComponent.new(icon: "json.svg",link: link, target: '_blank', title: t('fair_score.go_to_api'), size:'small', style: custom_style)
+ end
+
+ def resolve_namespaces
+ RESOLVE_NAMESPACE
+ end
+ def ontologies_analytics
+ data = LinkedData::Client::Analytics.last_month.onts
+ data.map{|x| [x[:ont].to_s, x[:views]]}.to_h
+ end
def get_apikey
unless session[:user].nil?
@@ -15,6 +50,31 @@ def get_apikey
end
end
+ def rest_hostname
+ extract_hostname(REST_URI)
+ end
+
+ def extract_hostname(url)
+ begin
+ uri = URI.parse(url)
+ uri.hostname
+ rescue URI::InvalidURIError
+ url
+ end
+ end
+
+ def omniauth_providers_info
+ $OMNIAUTH_PROVIDERS
+ end
+
+ def omniauth_provider_info(strategy)
+ omniauth_providers_info.select {|k,v| v[:strategy].eql?(strategy.to_sym) || k.eql?(strategy)}
+ end
+
+ def omniauth_token_provider(strategy)
+ omniauth_provider_info(strategy.to_sym).keys.first
+ end
+
def isOwner?(id)
unless session[:user].nil?
if session[:user].admin?
@@ -27,16 +87,10 @@ def isOwner?(id)
end
end
- def encode_param(string)
- CGI.escape(string)
- end
- def escape(string)
- CGI.escape(string)
- end
- def unescape(string)
- CGI.unescape(string)
+ def encode_param(string)
+ CGI.escape(string)
end
def clean(string)
@@ -67,151 +121,13 @@ def current_user_admin?
session[:user] && session[:user].admin?
end
- def remove_owl_notation(string)
- # TODO_REV: No OWL notation, but should we modify the IRI?
- return string
-
- unless string.nil?
- strings = string.split(":")
- if strings.size<2
- #return string.titleize
- return string
- else
- #return strings[1].titleize
- return strings[1]
- end
- end
- end
-
- def draw_note_tree(notes,key)
- output = ""
- draw_note_tree_leaves(notes,0,output,key)
- return output
- end
-
- def draw_note_tree_leaves(notes,level,output,key)
- for note in notes
- name="Anonymous"
- unless note.user.nil?
- name=note.user.username
- end
- headertext=""
- notetext=""
- if note.note_type.eql?(5)
- headertext<< "
-%footer.footer.pt-4.mt-5
- %div.container-fluid
- %div.row
- %div.col
- = link_to(image_tag('logos/logoLW_eric_outline_white-01.svg', alt: "LifeWatch logo", class: "logo"), 'https://www.lifewatch.eu/', target: '_blank')
- .col.col-md
- %h6 Products
- %ul.list-unstyled
- %li
- %a{href: "#{$REST_URL.chomp('/') + "/documentation"}", target: "_blank"} EcoPortal REST API
- .col.footer-support
- %h6 Support
- %ul.list-unstyled
- %li
- %a.pop_window{href: "/feedback?location=http%253A%252F%252Fecoportal.lifewatchitaly.eu%252F"} Contact Us
- %li
- = link_to("Help", Rails.configuration.settings.links[:help], target: "_blank")
- %li
- %a{href: Rails.configuration.settings.links[:wiki], target: "_blank"} EcoPortal Wiki Documentation
- .col.col-md
- %h6 Disclaimers & Agreements
- %ul.list-unstyled
- %li
- = link_to('Terms & Conditions', Rails.configuration.settings.links[:terms], target: '_blank')
- %li
- = link_to('Privacy Policy', Rails.configuration.settings.links[:privacy_policy], target: '_blank')
- %li
- = link_to('Cite Us', Rails.configuration.settings.links[:cite], target: '_blank')
- .col.col-md
- %h6 About
- %ul.list-unstyled
- %li
- -# %a{href: "#", target: "_blank"} About Us
- = link_to("About Us", Rails.configuration.settings.links[:about])
- %li
- -# %a{href: "#", target: "_blank"} Team
- = link_to("Team", Rails.configuration.settings.links[:team])
- %li
- %a{href: "/projects"} Projects
- .col.col-md
- %ul.list-inline.social-icons
- %li.list-inline-item
- %a{href: Rails.configuration.settings.links[:twitter], target: "_blank"}
- %i.fab.fa-twitter
- %li.list-inline-item
- %a{href: Rails.configuration.settings.links[:facebook], target: "_blank"}
- %i.fab.fa-facebook
- %li.list-inline-item
- %a{href: Rails.configuration.settings.links[:youtube], target: "_blank"}
- %i.fab.fa-youtube
- %li.list-inline-item
- %a{href: Rails.configuration.settings.links[:linkedin], target: "_blank"}
- %i.fab.fa-linkedin-in
- %li.list-inline-item
- %a{href: Rails.configuration.settings.links[:github], target: "_blank"}
- %i.fab.fa-github
- .row
- .col-sm-12{:style => "text-align:center;clear:both;"}
- %a{:href => "http://ontoportal.org/", :title => "Powered by Ontoportal", target: "_blank"} Powered by Ontoportal
+%br
+%br/
+.footer-container
+ %footer
+ .footer-header
+ .footer-logo
+ %img{:src => "#{asset_path("logos/ontoportal.svg")}"}
+ %p
+ = portal_name
+ .footer-social-media-links
+ - $FOOTER_LINKS[:social].each do |link|
+ %a{:href => link[:link], :target => "_blank"}
+ = inline_svg(link[:logo], width: "32px", height: "32px")
+ .footer-nav-links
+ - $FOOTER_LINKS[:sections].each do |key, section_links|
+ %div
+ %h2
+ = t("layout.footer."+key.to_s)
+ %div
+ - section_links.each do |section , link|
+ %a{:href => link, :target => "_blank"}
+ = t("layout.footer."+section.to_s)
+
+
+
= javascript_include_tag "application"
-= render partial: "ga_tracking"
diff --git a/app/views/layouts/_header.html.erb b/app/views/layouts/_header.html.erb
index be11c10a1..7e23fd5f5 100644
--- a/app/views/layouts/_header.html.erb
+++ b/app/views/layouts/_header.html.erb
@@ -1,6 +1,7 @@
-
+ lang="<%=I18n.locale%>">
+ <%= render partial: 'ga_tracking' %>
@@ -16,18 +17,14 @@
<%if @title.nil?%><%=$ORG_SITE%><%else%><%="#{@title} | #{$ORG_SITE}"%><%end%>
-
-
<%= stylesheet_link_tag "https://use.fontawesome.com/releases/v5.2.0/css/all.css", integrity: "sha384-hWVjflwFxL6sNzntih27bfxkr27PmbbK/iSvJ+a4+0owXq79v+lsFkW54bOGbiDQ", crossorigin: "anonymous" %>
<%= stylesheet_link_tag "application" %>
<%= javascript_include_tag "vendor" %>
- <%= javascript_include_tag "//cdnjs.cloudflare.com/ajax/libs/handlebars.js/2.0.0/handlebars.min.js" %>
- <%= javascript_include_tag "//ajax.aspnetcdn.com/ajax/jquery.validate/1.11.1/jquery.validate.min.js" %>
- <%=render partial: 'layouts/topnav'%>
-
- <%=render partial: 'layouts/notices'%>
-
-
-
-
- <%=yield%>
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- <%= render partial: 'layouts/footer' %>
-
-
-
\ No newline at end of file
diff --git a/app/views/layouts/appliance.html.haml b/app/views/layouts/appliance.html.haml
index 20f13cb35..2497fd07e 100644
--- a/app/views/layouts/appliance.html.haml
+++ b/app/views/layouts/appliance.html.haml
@@ -1,6 +1,7 @@
!!! Strict
%html
%head
+ = render partial: 'ga_tracking'
@@ -15,8 +16,6 @@
= stylesheet_link_tag "application", media: "all"
= javascript_include_tag "vendor"
- = javascript_include_tag "//cdnjs.cloudflare.com/ajax/libs/handlebars.js/2.0.0/handlebars.min.js"
- = javascript_include_tag "//ajax.aspnetcdn.com/ajax/jquery.validate/1.11.1/jquery.validate.min.js"
%script
jQuery(document).data({bp: {config: #{bp_config_json.html_safe}, user: #{(session[:user] || {}).to_hash.to_json.html_safe}}});
@@ -28,9 +27,10 @@
%body{:class => "#{controller_name} #{action_name}"}
= render partial: "layouts/topnav"
- %div.container-fluid.flex-grow-1
+ %div.flex-grow-1
= render partial: "layouts/notices"
- = render TurboModalComponent.new(id: 'application_modal')
+ = modal_frame_container
+
= yield
= render partial: "layouts/footer"
diff --git a/app/views/layouts/application.html.erb b/app/views/layouts/application.html.erb
index 5ff643c32..8b025f31a 100644
--- a/app/views/layouts/application.html.erb
+++ b/app/views/layouts/application.html.erb
@@ -8,7 +8,7 @@
<%= javascript_include_tag "application"%>
-<%= render TurboModalComponent.new(id: 'application_modal') %>
+<%= modal_frame_container %>
<%= yield %>
diff --git a/app/views/layouts/component_preview.html.erb b/app/views/layouts/component_preview.html.erb
new file mode 100644
index 000000000..429f63010
--- /dev/null
+++ b/app/views/layouts/component_preview.html.erb
@@ -0,0 +1,60 @@
+
+
+ Component Preview
+
+ <%= stylesheet_link_tag "application" %>
+ <%= javascript_include_tag "vendor" %>
+
+
+
+ <%= modal_frame_container %>
+
+ <%= yield %>
+ <%= javascript_include_tag "application" %>
+
+
+
+
+
\ No newline at end of file
diff --git a/app/views/layouts/component_preview_not_centred.html.erb b/app/views/layouts/component_preview_not_centred.html.erb
new file mode 100644
index 000000000..81b1c2964
--- /dev/null
+++ b/app/views/layouts/component_preview_not_centred.html.erb
@@ -0,0 +1,56 @@
+
+
+ Component Preview
+
+ <%= stylesheet_link_tag "application" %>
+ <%= javascript_include_tag "vendor" %>
+
+
+
+ <%= modal_frame_container %>
+ <%= yield %>
+ <%= javascript_include_tag "application" %>
+
+
\ No newline at end of file
diff --git a/app/views/layouts/minimal.html.erb b/app/views/layouts/minimal.html.erb
deleted file mode 100644
index 808872a52..000000000
--- a/app/views/layouts/minimal.html.erb
+++ /dev/null
@@ -1,53 +0,0 @@
-
-
-
-
-
-
-
- <%= csrf_meta_tag %>
- <%if @title.nil?%><%=$ORG_SITE%><%else%><%="#{@title} | #{$ORG_SITE}"%><%end%>
-
-
- <%= stylesheet_link_tag "https://use.fontawesome.com/releases/v5.2.0/css/all.css", integrity: "sha384-hWVjflwFxL6sNzntih27bfxkr27PmbbK/iSvJ+a4+0owXq79v+lsFkW54bOGbiDQ", crossorigin: "anonymous" %>
- <%= stylesheet_link_tag "application" %>
- <%=render partial: 'layouts/js_data'%>
- <%=render partial: 'layouts/head_js'%>
-
-
-
-
-
- <%if flash[:notice] %>
-
-
- <%=flash[:notice] %>
-
-
- <%end %>
-
-
- <% message_name = "" %>
- <% unless $SITE_NOTICE.nil? || $SITE_NOTICE.empty? %>
- <% $SITE_NOTICE.each_key { |k| message_name = k } %>
- <% unless cookies[message_name.to_sym].eql?("true") %>
-
-
- <%=$SITE_NOTICE[message_name.to_sym]%>
[close]
-
- <% end %>
- <% end %>
-
- <%=yield%>
-
-
-
-
-
diff --git a/app/views/layouts/ontology.html.erb b/app/views/layouts/ontology.html.erb
index 78c31664c..b3d793d23 100644
--- a/app/views/layouts/ontology.html.erb
+++ b/app/views/layouts/ontology.html.erb
@@ -1,6 +1,6 @@
<%=render partial: 'layouts/header'%>
- <%= render TurboModalComponent.new(id: 'application_modal')%>
+ <%= modal_frame_container%>
<%=yield%>
<%=render partial: 'layouts/footer'%>
diff --git a/app/views/layouts/ontology_viewer/_header.html.haml b/app/views/layouts/ontology_viewer/_header.html.haml
new file mode 100644
index 000000000..877e8c408
--- /dev/null
+++ b/app/views/layouts/ontology_viewer/_header.html.haml
@@ -0,0 +1,46 @@
+- sub = @submission_latest
+
+
+-# A header of sorts to display ontology name and subset of details.
+.ontology-details-header-container
+ .ontology-details-path
+ %a{href: "/ontologies"} ontologies
+ - if @ontology.viewOf
+ = inline_svg_tag 'arrow-right-outlined.svg'
+ %div
+ = @ontology.viewOf.split('/').last
+ = inline_svg_tag 'arrow-right-outlined.svg'
+ %div
+ = @ontology.acronym
+ .ontology-details-header-sub-container
+ .ontology-details-header-left-container{style:'width: 70%'}
+ .ontology-details-name-bar
+ %div
+ = @ontology.name
+ %span{data: { controller: 'tooltip'}, title: ontology_alternative_names}
+ = "("+ @ontology.acronym+")"
+ - if @ontology.viewOf
+ = render ChipButtonComponent.new(class: 'chip_button_small mr-1', text: 'view', type: 'clickable', clickable: false)
+ - if @ontology.private?
+ = render ChipButtonComponent.new(class: 'chip_button_small mr-1') do
+ = private_ontology_icon(@ontology.private?)
+ - if @submission_latest&.hasOntologyLanguage
+ = render ChipButtonComponent.new(class: 'chip_button_small mr-1', text: @submission_latest.hasOntologyLanguage)
+ = ontology_retired_badge(@submission_latest, small: true, clickable: false)
+ = ontology_license_badge(@ontology.acronym, @submission_latest)
+
+ - unless sub.nil? || sub.creationDate.nil?
+ .ontology-details-last-update
+ %img{src: asset_path("update.svg")}/
+ %div
+ = t('ontology_details.header.last_submission_date')
+ = render DateTimeFieldComponent.new(value: sub.creationDate)
+ .ontology-details-header-right-container.justify-content-end{style: 'min-width: 20%;'}
+ %span.mx-1
+ = new_submission_button
+ - if @submission_latest
+ %span.mx-1
+ = ontology_edit_button
+ %span
+ = submission_json_button
+ = subscribe_button(@ontology.id)
diff --git a/app/views/layouts/popup.html.erb b/app/views/layouts/popup.html.erb
index d78ac254d..fda7af554 100644
--- a/app/views/layouts/popup.html.erb
+++ b/app/views/layouts/popup.html.erb
@@ -1,6 +1,7 @@
+ <%= render partial: "ga_tracking" %>
@@ -11,9 +12,7 @@
<%= stylesheet_link_tag "https://use.fontawesome.com/releases/v5.2.0/css/all.css", integrity: "sha384-hWVjflwFxL6sNzntih27bfxkr27PmbbK/iSvJ+a4+0owXq79v+lsFkW54bOGbiDQ", crossorigin: "anonymous" %>
<%= stylesheet_link_tag "application" %>
<%= javascript_include_tag "vendor" %>
- <%= javascript_include_tag "//cdnjs.cloudflare.com/ajax/libs/handlebars.js/2.0.0/handlebars.min.js" %>
<%= javascript_include_tag "//cdnjs.cloudflare.com/ajax/libs/Chart.js/1.0.1/Chart.min.js" %>
- <%= javascript_include_tag "//ajax.aspnetcdn.com/ajax/jquery.validate/1.11.1/jquery.validate.min.js" %>
- In order to access this ontology, you will need to comply with the following license conditions provided by the ontology owner:
- <%=@ontology.licenseInformation%>
-
-
-
- <%= form_tag "/users/submit_license" do %>
- <%= hidden_field_tag :ontologylicense, @ontology.ontologyId%>
- <%= text_area_tag :ontologylicensetext, "", :rows => 7, :style => "width: 500px;"%>
-
- Please contact <%= ontology_authors%> at <%= @ontology.contactEmail%> if you have questions regarding the license.
-
- <%= submit_tag "Submit", :id => "submit_license" %> <%=flash[:error] unless flash[:error].nil?%>
- <%end%>
- <%end%>
-
-
diff --git a/app/views/ontologies/_ontology_views.html.haml b/app/views/ontologies/_ontology_views.html.haml
new file mode 100644
index 000000000..5be50ab4f
--- /dev/null
+++ b/app/views/ontologies/_ontology_views.html.haml
@@ -0,0 +1,8 @@
+- if @views.empty?
+ = empty_state_message t("ontologies.no_views", acronym: @ontology.acronym)
+- else
+ %div.border-top
+ %dl
+ - @view_decorators.each do |view_decorator|
+ %dt= view_decorator.linked_name
+ %dd= view_decorator.description
\ No newline at end of file
diff --git a/app/views/ontologies/_private_ontology.html.erb b/app/views/ontologies/_private_ontology.html.erb
deleted file mode 100644
index 77143e4cd..000000000
--- a/app/views/ontologies/_private_ontology.html.erb
+++ /dev/null
@@ -1,10 +0,0 @@
-
-
This ontology is private
- <% ontology_authors = @ontology.contactName.nil? || @ontology.contactName.empty? ? "the authors" : @ontology.contactName%>
-
- This ontology is private and only those who have been granted access by the ontology author may browse its classes.
- Please contact <%= ontology_authors%> at <%= @ontology.contactEmail%> if you would like access.
-
- <%if session[:user].nil?%>If you have already been granted access then please log in and you will be taken to the class browser.<%end%>
-
-
diff --git a/app/views/ontologies/_submission_location_form.html.haml b/app/views/ontologies/_submission_location_form.html.haml
new file mode 100644
index 000000000..f26f07009
--- /dev/null
+++ b/app/views/ontologies/_submission_location_form.html.haml
@@ -0,0 +1,52 @@
+= render Input::InputFieldComponent.new(label: t("ontologies.location"), name: '') do
+ .location-choice
+ %input{type: "radio", name: "submission[isRemote]", value: "3", checked: summary_only?, id: "metadata_only", onchange: "displayMetadataOnlyForm()"}
+ %label.title{for: "metadata_only"}
+ = t("ontologies.metadata_only")
+ .upload-ontology-desc.mb-2
+ = t("ontologies.allow_users")
+ #metadata-only-form
+
+ .location-choice
+ %input{type: "radio", name: "submission[isRemote]", value: "1", id: "load_from_url", checked: ontology_pull_location?, onchange: "displayUrlForm()"}
+ %label.title{for: "load_from_url"}
+ = t("ontologies.load_from_url")
+ .upload-ontology-desc.mb-1
+ = t("ontologies.new_versions_loaded")
+ #url-form{style: ontology_pull_location? ? "" : "display:none;"}
+ = render Input::UrlComponent.new(label: "", name: "submission[pullLocation]", value: @submission.pullLocation)
+ .location-choice.mb-3.mt-3
+ - checked = !summary_only? && !ontology_pull_location?
+ %input{type: "radio", name: "submission[isRemote]", value: "0", id: "upload_local_file", checked: checked, onchange: "displayLocalFileForm()"}
+ %label.title{for: "upload_local_file"}
+ = t("ontologies.upload_local_file")
+ #local-file-form{style: checked ? "" : "display:none;" }
+ = render Input::FileInputComponent.new(name: "submission[filePath]")
+
+
+ :javascript
+ var MetadataOnlyForm = document.getElementById("metadata-only-form");
+ var UrlForm = document.getElementById("url-form");
+ var LocalFileForm = document.getElementById("local-file-form");
+
+ var displayForm = (formElement) => {
+ [MetadataOnlyForm, UrlForm, LocalFileForm].forEach((form) => {
+ if (form === formElement) {
+ form.style.display = "block";
+ } else {
+ form.style.display = "none";
+ }
+ });
+ };
+
+ var displayMetadataOnlyForm = () => {
+ displayForm(MetadataOnlyForm);
+ };
+
+ var displayUrlForm = () => {
+ displayForm(UrlForm);
+ };
+
+ var displayLocalFileForm = () => {
+ displayForm(LocalFileForm);
+ };
diff --git a/app/views/ontologies/_treeview.html.haml b/app/views/ontologies/_treeview.html.haml
deleted file mode 100644
index 1f5573c75..000000000
--- a/app/views/ontologies/_treeview.html.haml
+++ /dev/null
@@ -1,10 +0,0 @@
-= turbo_frame_tag 'concepts_tree_view' do
- #tree_wrapper.hide-if-loading
- %ul.simpleTree{data:{controller: 'simple-tree history',
- 'simple-tree': { 'auto-click-value': "#{autoCLick}" },
- action: 'clicked->history#updateURL'}}
- %li.root
- %ul
- = draw_tree(@root, @concept.id, (params[:concept_schemes] || '').split(','))
-
-
diff --git a/app/views/ontologies/_views.html.haml b/app/views/ontologies/_views.html.haml
index 08ce27a24..f71061d10 100644
--- a/app/views/ontologies/_views.html.haml
+++ b/app/views/ontologies/_views.html.haml
@@ -31,12 +31,14 @@
%div{:style => "clear: both;"}
#views_content
%h2{:style => "margin: 2em 0 0"}
- %span{:style => "font-size: x-large; margin-right: 1.5em;"} Views
+ %span{:style => "font-size: x-large; margin-right: 1.5em;"}= t('ontologies.views')
- ont_id_esc = CGI.escape(@ontology.id)
- if session[:user].nil?
- %a{:href => "/login?redirect=#{escape("/ontologies/new?ontology[viewOf]=#{ont_id_esc}")}"} Create new view
+ %a{:href => "/login?redirect=#{escape("/ontologies/new?ontology[viewOf]=#{ont_id_esc}")}"}
+ = t('ontologies.create_new_view')
- else
- %a{:href => "/ontologies/new?ontology[viewOf]=#{ont_id_esc}"} Create new view
+ %a{:href => "/ontologies/new?ontology[viewOf]=#{ont_id_esc}"}
+ = t('ontologies.create_new_view')
%div{:style => "float:left;"}
- if @views.empty? || @views.length < 1
@@ -55,9 +57,9 @@
}
%h4{:style => "margin-top: .5em;"}
- %a#expand_views{:href => "javascript:void(0);"} Expand All
+ %a#expand_views{:href => "javascript:void(0);"}= t('ontologies.expand_all')
|
- %a#collapse_views{:href => "javascript:void(0);"} Collapse All
+ %a#collapse_views{:href => "javascript:void(0);"}= t('ontologies.collapse_all')
- @views.each_with_index do |view, index|
- next unless view.access?(session[:user])
@@ -91,15 +93,16 @@
- if viewAdmin
- viewSubmitURL = "/ontologies/#{view.acronym}/submissions/new" # submit new view
%li
- %span.lead Administrator:
- %a{:href => viewSubmitURL} create new view submission
+ %span.lead= t('ontologies.administrator')
+ %a{:href => viewSubmitURL}
+ = t('ontologies.create_new_view_submission')
- unless view_description.nil?
%li
- %span.lead Description:
+ %span.lead= t('ontologies.description')
= view_description
- unless view_definition.nil?
%li
- %span.lead Definition:
+ %span.lead= t('ontologies.definition')
= view_definition
-# unless view_language.nil?
%li
@@ -107,7 +110,7 @@
= view_language
- unless view_contacts.nil?
%li
- %span.lead Created By:
+ %span.lead= t('ontologies.created_by')
= view_contacts
/ Display view submissions data (if any)
- unless view_submissions.empty?
@@ -115,12 +118,12 @@
%table.zebra{:cellpadding => "0", :cellspacing => "0", :width => "100%"}
%thead
%tr
- %th Submission
- %th Release Date
- %th Upload Date
- %th Downloads
+ %th= t('ontologies.submission')
+ %th= t('ontologies.release_date')
+ %th= t('ontologies.upload_date')
+ %th= t('ontologies.downloads')
- if viewAdmin
- %th Admin Links
+ %th= t('ontologies.admin_links')
- view_sub_latestId = -1
- view_sub_latestId = view_sub_latest.submissionId unless view_sub_latest.nil?
@@ -137,7 +140,7 @@
- if (view_index == 0) && viewAdmin
%td
- viewEditURL = "/ontologies/#{view.acronym}/submissions/#{view_sub.submissionId}/edit"
- #{link_to "Edit", viewEditURL}
+ #{link_to t('ontologies.edit_link'), viewEditURL}
/ view submission table
/ collapsible div
/ title div
diff --git a/app/views/ontologies/_visits.html.haml b/app/views/ontologies/_visits.html.haml
index bb2420bb2..92c006342 100644
--- a/app/views/ontologies/_visits.html.haml
+++ b/app/views/ontologies/_visits.html.haml
@@ -2,4 +2,4 @@
%canvas#visits_chart{data: {controller:'load-chart' , 'load-chart-labels-value': @visits_data[:labels].last(13),
'load-chart-datasets-value': visits_chart_dataset(@visits_data[:visits].last(13))}}
- else
- %p.font-italic= "We are still collecting data for #{@ontology.acronym}"
+ = empty_state_message t("ontologies.collecting_data_message", acronym: @ontology.acronym)
diff --git a/app/views/ontologies/browse.html.erb b/app/views/ontologies/browse.html.erb
deleted file mode 100644
index 5a7a9609a..000000000
--- a/app/views/ontologies/browse.html.erb
+++ /dev/null
@@ -1,319 +0,0 @@
-
-
-
-
-
-
Semantic resources loading
-
please wait...
-
-
-
- Browser
-
- <%= t('ontologies.intro').html_safe %>
- <%= link_to(Rails.configuration.settings.links[:help_ontology_browse], target: '_blank') do %>
-
- <% end %>
-
-
-
-
- Welcome admin This coloring indicates admin-only features.
-
-
-
-
Debug Info
- types: {{facets.types.active}}
- artifacts: {{facets.artifacts.active}}
- formats: {{facets.formats.active}}
- groups: {{facets.groups.active}}
- categories: {{facets.categories.active}}
- Selected ontologies: {{visible_ont_count}}
-
-
-
- <%if session[:user].nil?%>
-
Submit New Semantic Resource
- <%else%>
-
Submit New Semantic Resource
- <%end%>
-
-
-
-
Entry Type
-
-
-
-
- {{type.id | idToTitle}}
- ({{facet_counts["types"][type.id] || 0}})
-
-
-
-
-
-
-
-
Uploaded in the Last
-
-
-
- {{day | idToTitle}}
-
-
-
-
-
-
-
Category
-
-
-
- {{category.name}}
- ({{facet_counts["categories"][category.id] || 0}})
-
-
-
-
-
-
-
Group
-
-
-
- {{group.acronym}}
- ({{facet_counts["groups"][group.id] || 0}})
-
-
-
-
-
-
-
-
-
Ontology Content
-
-
-
- {{artifact | idToTitle}}
- ({{facet_counts["artifacts"][artifact] || 0}})
-
-
-
-
-
-
-
Natural Language
-
-
-
- {{language_label}}
- ({{facet_counts["natural_languages"][language_uri] || 0}})
-
-
-
-
-
-
-
-
-
Is of Type
-
-
-
- {{is_of_type_label}}
- ({{facet_counts["is_of_type"][is_of_type_uri] || 0}})
-
-
-
-
-
-
-
Missing Status
-
-
-
- {{status | idToTitle}}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Showing {{visible_ont_count}} of {{ontologies.length}}
- Sort:
-
- Popular
- Name
- Classes count
- Instances/Concepts count
- Projects
- Notes
-
- Upload Date
- Release Date
- FAIR score
- Search Rank
-
-
-
-
-
-
-
-
-
VIEW
-
-
-
{{ontology.description | descriptionToText}}
-
- Uploaded : {{ontology.creationDate | date:'shortDate'}}
-
-
- Format : {{ontology.format}}
-
-
- View of : {{ontology.viewOfOnt.acronym}}
-
-
- Summary Only
-
-
- Groups : {{groupAcronyms(ontology.groups).join(', ')}}
-
-
- Categories : {{categoryNames(ontology.categories).join(', ')}}
-
-
-
- Admins : {{adminUsernames(ontology.administeredBy).join(', ')}}
-
-
- Pull URL
-
-
- Status : {{ontology.submissionStatusFormatted}}
-
-
-
-
-
No submissions available
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/app/views/ontologies/browser/_ontologies.html.haml b/app/views/ontologies/browser/_ontologies.html.haml
new file mode 100644
index 000000000..8e3d8bd30
--- /dev/null
+++ b/app/views/ontologies/browser/_ontologies.html.haml
@@ -0,0 +1,17 @@
+= render InfiniteScrollComponent.new(id: 'ontologies_list',
+ collection: @ontologies,
+ next_url: ontologies_filter_url(@request_params, page: @page.nextPage),
+ current_page: @page.page, next_page: @page.nextPage) do |c|
+
+ - if @page.page.eql?(1)
+ = content_tag(:p, class: "browse-desc-text", style: "margin-bottom: 12px !important;") { "#{t("ontologies.showing_ontologies_size", ontologies_size: @count, analytics_size: @total_ontologies)} (#{sprintf("%.2f", @time)}s)" }
+
+ - ontologies = c.collection
+ - ontologies.each do |ontology|
+ = render OntologyBrowseCardComponent.new(ontology: ontology)
+ - c.loader do
+ - ontologies_browse_skeleton
+ - c.error do
+ .browse-empty-illustration
+ %img{:src => "#{asset_path("empty-box.svg")}"}
+ %p No result was found
\ No newline at end of file
diff --git a/app/views/ontologies/browser/browse.html.haml b/app/views/ontologies/browser/browse.html.haml
new file mode 100644
index 000000000..83da56b6c
--- /dev/null
+++ b/app/views/ontologies/browser/browse.html.haml
@@ -0,0 +1,85 @@
+.browse-center
+ .browse-container
+ .container.align-alert
+ - if session[:user]&.admin?
+ %div{style:'width: 70%;'}
+ = render Display::AlertComponent.new(type: 'info') do
+ %span.d-flex.align-items-center
+ %svg{:fill => "none", :height => "11", :viewbox => "0 0 11 11", :width => "11", :xmlns => "http://www.w3.org/2000/svg"}
+ %circle{:cx => "5.5", :cy => "5.5", :fill => 'var(--admin-color)', :r => "5.5"}
+ %p{style: "margin: 10px"}= t("ontologies.browser.admin_welcome")
+ .browse-submit-new-ontology-and-you-are-admin-container
+ %a#back_top_btn.btn.btn-primary.btn-floating.btn-lg
+ %i.fas.fa-arrow-up.text-white
+
+ :javascript
+ const btn = document.getElementById("back_top_btn");
+ window.addEventListener("scroll", function() {
+ if (window.scrollY > 300) {
+ btn.classList.add("show");
+ } else {
+ btn.classList.remove("show");
+ }
+ });
+
+ btn.addEventListener("click", function(e) {
+ e.preventDefault();
+ window.scrollTo({
+ top: 0,
+ behavior: "smooth"
+ });
+ });
+
+ %div{data: { controller: "turbo-frame history browse-filters" , "turbo-frame-url-value": "/ontologies_filter?page=1{request.original_url.split('?').last}", action: "change->browse-filters#dispatchFilterEvent changed->history#updateURL changed->turbo-frame#updateFrame"}}
+
+ .browse-sub-container
+ .browse-first-row{data:{controller: "browse-filters", action: "change->browse-filters#dispatchFilterEvent changed->history#updateURL"}}
+ %div.pt-1
+ = upload_ontology_button
+ %div{style:'margin-top: 30px'}
+ %p.browse-filters-title= t("ontologies.filters")
+ - if session[:user]&.admin?
+ %div.browse-filter.admin-border
+ = render SwitchInputComponent.new(id:'filter-private', name:'private_only', checked: @show_private_only) do
+ = t("ontologies.browser.show_private_ontology")
+ %div.browse-filter
+ = render SwitchInputComponent.new(id:'filter-views', name:'views', checked: @show_views) do
+ = t("ontologies.browser.show_ontology_views")
+ = render SwitchInputComponent.new(id:'filter-retired', name:'retired',checked: @show_retired) do
+ = t("ontologies.browser.show_retired_ontologies")
+
+ - @filters.each do |key, values|
+ - if session[:user]&.admin? || key != :missingStatus
+ .browse-filter{data:{controller: "show-filter-count browse-filters", action: "change->show-filter-count#updateCount change->browse-filters#dispatchFilterEvent"}, id: "#{key}_filter_container", style: "#{"border-color: var(--admin-color);" if key == :missingStatus}"}
+ .browse-filter-title-bar{"data-target" => "#browse-#{key}-filter", "data-toggle" => "collapse"}
+ %p
+ = browse_filter_section_label(key)
+ %span.badge.badge-primary{"data-show-filter-count-target":"countSpan", style: "#{values[2] && values[2].positive? ? '' : 'display: none;'}"}
+ = values[2]
+ = inline_svg_tag 'arrow-down.svg'
+ .collapse{id: "browse-#{key}-filter", class: "#{values[2].positive? ? 'show': ''}"}
+ .browse-filter-checks-container
+ - values.first.each do |object|
+ - title = (key.eql?(:categories) || key.eql?(:groups)) ? nil : ''
+ = group_chip_component(name: key, object: object, checked: values[1]&.include?(object["id"]) || values[1]&.include?(object["value"]) , title: title) do |c|
+ - c.count do
+ %span.badge.badge-light.ml-1
+ = turbo_frame_tag "count_#{key}_#{object["id"]}", busy: true
+ %span.show-if-loading
+ = render LoaderComponent.new(small:true)
+
+ .browse-second-row
+ .browse-search-bar
+ .browse-search-container
+ %input{:name => "search", :placeholder => t("ontologies.browser.search_placeholder"), :type => "text", :value => @search, data: {action: "input->browse-filters#dispatchInputEvent"}}
+ .browse-search-filters
+ %select#format.browse-format-filter{:name => "format"}
+ = options_for_select(@formats, @selected_format)
+ %select#Sort_by.browse-sort-by-filter{:name => "Sort_by"}
+ = options_for_select(@sorts_options, @sort_by)
+ .browse-ontologies
+ = render TurboFrameComponent.new(id: "ontologies_list_view-page-1" , src: "/ontologies_filter?page=1{request.original_url.split('?').last}", data:{"turbo-frame-target":"frame", "turbo-frame-url-value": "/ontologies_filter"}) do |list|
+ - list.loader do
+ = browser_counter_loader
+ - ontologies_browse_skeleton
+
diff --git a/app/views/ontologies/concepts_browsers/_collections_picker.html.haml b/app/views/ontologies/concepts_browsers/_collections_picker.html.haml
index 098d547b7..1191df3ac 100644
--- a/app/views/ontologies/concepts_browsers/_collections_picker.html.haml
+++ b/app/views/ontologies/concepts_browsers/_collections_picker.html.haml
@@ -7,6 +7,6 @@
.form-group
%label{:for => id} Collections
%div
- = select_tag(:collections,options_for_select(collections_labels.map{|s| [s["prefLabel"], s["@id"], {'data-color': s['color']}]}, selected_collection.map{|x| x["@id"]}),
+ = select_tag(:collections,options_for_select(collections_labels.map{|s| [s["prefLabel"].last, s["@id"], {'data-color': s['color']}]}, selected_collection.map{|x| x["@id"]}),
{ multiple: multiple, id: id, class:"form-control", include_blank: true,
- data:{controller:'chosen', 'chosen-name-value': :collection_id}.merge(data)})
\ No newline at end of file
+ data:{controller:'chosen', 'chosen-name-value': :collectionid}.merge(data)})
\ No newline at end of file
diff --git a/app/views/ontologies/concepts_browsers/_concepts_browser.html.haml b/app/views/ontologies/concepts_browsers/_concepts_browser.html.haml
index 4537606ab..98aad66d7 100644
--- a/app/views/ontologies/concepts_browsers/_concepts_browser.html.haml
+++ b/app/views/ontologies/concepts_browsers/_concepts_browser.html.haml
@@ -1,18 +1,25 @@
-%nav
- .nav.nav-tabs.text-center{:role => "tablist", style:"background-color: rgba(0, 0, 0, 0.03);"}
+%div#concept_browser.tree-container
+ = render TabsContainerComponent.new(type:'outline') do |c|
+ - c.item(id: 'tree-tab', selected: default_sub_menu?) do
+ %span{title: 'Hierarchy view', 'data-controller': "tooltip"}
+ = inline_svg('icons/list-tree.svg', style:'width: 18px; height: 18px')
- %a#concepts-tree-tab.nav-item.nav-link.active.flex-grow-1.border-radius-0{"data-toggle" => "tab", :href => "#concepts-tree-container", title: 'Hierarchy view', 'data-controller': "tooltip"}
- = inline_svg('list-tree.svg',style:'width: 25px; height: 25px')
- if skos?
- %a#concepts-list-tab.nav-item.nav-link.flex-grow-1.border-radius-0{"data-toggle" => "tab", :href => "#concepts-list-container", title: 'Collection view', 'data-controller': "tooltip"}
- %i.fas.fa-list{style:'font-size: 25px; color: var(--primary-color)'}
- %a#concepts-date-sort-tab.nav-item.nav-link.flex-grow-1.border-radius-0{"data-toggle" => "tab", :href => "#concepts-date-sort-container", title: 'Date view', 'data-controller': "tooltip"}
- %i.far.fa-calendar-alt{style:'font-size: 25px'}
-.tab-content.px-1.py-2
- #concepts-tree-container.tab-pane.fade.show.active
- = render partial: 'ontologies/concepts_browsers/concepts_tree'
- - if skos?
- #concepts-list-container.tab-pane.fade
- = render partial: 'ontologies/concepts_browsers/concepts_list'
- #concepts-date-sort-container.tab-pane.fade
- = render partial: 'ontologies/concepts_browsers/concepts_date_sort'
\ No newline at end of file
+ - c.item(id: 'list-tab', selected: sub_menu_active?('list')) do
+ %span{title: 'Collection view', 'data-controller': "tooltip"}
+ = inline_svg('icons/list.svg', style:'width: 18px; height: 18px')
+
+ - c.item(id: 'date-tab', selected: sub_menu_active?('date')) do
+ %span{title: 'Date view', 'data-controller': "tooltip"}
+ = inline_svg('icons/calendar.svg', style:'width: 18px; height: 18px')
+
+ - c.item_content do
+ %div.p-1
+ = render partial: 'ontologies/concepts_browsers/concepts_tree'
+ - if skos?
+ - c.item_content do
+ %div.p-1
+ = render partial: 'ontologies/concepts_browsers/concepts_list'
+ - c.item_content do
+ %div.p-1
+ = render partial: 'ontologies/concepts_browsers/concepts_date_sort'
diff --git a/app/views/ontologies/concepts_browsers/_concepts_list.html.haml b/app/views/ontologies/concepts_browsers/_concepts_list.html.haml
index 07d48f680..c293620e9 100644
--- a/app/views/ontologies/concepts_browsers/_concepts_list.html.haml
+++ b/app/views/ontologies/concepts_browsers/_concepts_list.html.haml
@@ -1,7 +1,7 @@
%div{data:{controller: 'turbo-frame',
'turbo-frame': {
- 'url-value': "/ajax/classes/list?ontology_id=#{@ontology.acronym}",
- 'place-holder-value': "Please select a collection to display"
+ 'url-value': "/ajax/classes/list?ontology_id=#{@ontology.acronym}&language=#{request_lang}",
+ 'place-holder-value': t("ontologies.concepts_browsers.select_collection")
}}}
%div.pb-2
%div.mb-1
@@ -12,6 +12,12 @@
locals: {multiple: false, id: 'collections_select',
data: {action: 'changed->turbo-frame#updateFrame'}}
- %div#sd_content.card.p-1{style: 'overflow-y: scroll; height: 60vh;'}
- = render TurboFrameComponent.new(id: 'concepts_list_view-page-1', data: {'turbo-frame-target': 'frame'}) do
- Please select a collection to display
\ No newline at end of file
+ - unless no_collections?
+ %div#sd_content.card.p-1{style: 'overflow-y: auto; height: 60vh;'}
+ = render TurboFrameComponent.new(id: 'concepts_list_view-page-1', data: {'turbo-frame-target': 'frame'}, src:params[:concept_collections] ? "/ajax/classes/list?ontology_id=#{@ontology.acronym}&collectionid=#{params[:concept_collections]}" : '') do
+ .select-collection-placeholder
+ = t("ontologies.concepts_browsers.select_collection")
+
+
+
+
\ No newline at end of file
diff --git a/app/views/ontologies/concepts_browsers/_concepts_tree.html.haml b/app/views/ontologies/concepts_browsers/_concepts_tree.html.haml
index 9e0460185..d4affe93f 100644
--- a/app/views/ontologies/concepts_browsers/_concepts_tree.html.haml
+++ b/app/views/ontologies/concepts_browsers/_concepts_tree.html.haml
@@ -1,8 +1,8 @@
-%div{data:{controller: 'skos-collection-colors turbo-frame history',
+%div{data:{controller: 'skos-collection-colors turbo-frame',
'skos-collection-colors': {'collections-color-select-target-value': 'collection-color-filter'},
'turbo-frame': {
'url-value': "/ajax/classes/treeview?ontology=#{@ontology.acronym}&conceptid=root",
- 'place-holder-value': "Please select a scheme to display"
+ 'place-holder-value': t("ontologies.concepts_browsers.select_scheme")
}}}
%div.pb-2
%div.mb-1
@@ -15,7 +15,13 @@
data: {action: 'changed->skos-collection-colors#updateCollectionTags' ,
'chosen-enable-colors-value': 'true'}}
-# Class tree
- %div#sd_content.card.p-1.py-3{style: 'overflow-y: scroll; height: 60vh;'}
- = render TurboFrameComponent.new(id: 'concepts_tree_view',
- src: "/ajax/classes/treeview?ontology=#{@ontology.acronym}&conceptid=#{escape(@concept.id)}&concept_schemes=#{params[:concept_schemes]}&auto_click=false",
+ %div#sd_content.px-1{style: 'overflow-y: scroll; height: 60vh;'}
+ - if skos? && @roots&.empty?
+ %div.text-wrap
+ = render Display::AlertComponent.new do
+ = t("ontologies.concepts_browsers.missing_roots", acronym: @ontology.acronym)
+ - else
+ - concept_schemes = skos? ? "&concept_schemes=#{params[:concept_schemes]}" : ''
+ = render TurboFrameComponent.new(id: 'concepts_tree_view',
+ src: "/ajax/classes/treeview?ontology=#{@ontology.acronym}&conceptid=#{escape(@concept.id)}#{concept_schemes}&auto_click=false&language=#{request_lang}",
data: {'turbo-frame-target': 'frame'})
\ No newline at end of file
diff --git a/app/views/ontologies/concepts_browsers/_jump_to.html.haml b/app/views/ontologies/concepts_browsers/_jump_to.html.haml
index f597488ed..5fa4248e5 100644
--- a/app/views/ontologies/concepts_browsers/_jump_to.html.haml
+++ b/app/views/ontologies/concepts_browsers/_jump_to.html.haml
@@ -2,7 +2,7 @@
%div.input-group-prepend
%span.input-group-text
%i.fas.fa-search
- = text_field_tag("search_box", nil, class: "form-control rounded-right", placeholder: "Jump to", aria: {label: "Jump to:"},
+ = text_field_tag("search_box", nil, class: "form-control rounded-right", placeholder: t("ontologies.concepts_browsers.placeholder_jump"), aria: {label: t("ontologies.concepts_browsers.label_jump")},
data: {controller: 'class-search-auto-complete',
'class-search-auto-complete-ontology-acronym-value': @ontology.acronym,
'class-search-auto-complete-spinner-src-value': asset_path("jquery.simple.tree/spinner.gif")})
@@ -11,4 +11,4 @@
%div.input-group-append
%button.btn.btn-outline-primary.dropdown-toggle{ "data-toggle": "collapse", href: id}
%i.fas.fa-sliders-h.mx-1
- Filter
\ No newline at end of file
+ = t("ontologies.concepts_browsers.filter")
\ No newline at end of file
diff --git a/app/views/ontologies/concepts_browsers/_scheme_picker.html.haml b/app/views/ontologies/concepts_browsers/_scheme_picker.html.haml
index ca3131e1b..958807977 100644
--- a/app/views/ontologies/concepts_browsers/_scheme_picker.html.haml
+++ b/app/views/ontologies/concepts_browsers/_scheme_picker.html.haml
@@ -10,7 +10,7 @@
%label{:for => "schemes_select"} Schemes
%div
= select_tag(:concept_schemes,
- options_for_select(schemes_labels.map{|s| [s["prefLabel"], s["@id"]]}, selected_scheme.compact.map{|x| x["@id"]} ),
+ options_for_select(schemes_labels.map{|s| [s["prefLabel"].last, s["@id"]]}, selected_scheme.compact.map{|x| x["@id"]} ),
{multiple: true, id: "schemes_select",
data:{controller:'chosen', 'chosen-name-value': :concept_schemes,
action: 'changed->history#updateURL changed->turbo-frame#updateFrame'}})
diff --git a/app/views/ontologies/content_serializer.html.haml b/app/views/ontologies/content_serializer.html.haml
new file mode 100644
index 000000000..beda31695
--- /dev/null
+++ b/app/views/ontologies/content_serializer.html.haml
@@ -0,0 +1,2 @@
+= render_in_modal do
+ = rdf_highlighter_container(@format, @result) if @result
diff --git a/app/views/ontologies/edit.html.haml b/app/views/ontologies/edit.html.haml
deleted file mode 100644
index fbbc47baf..000000000
--- a/app/views/ontologies/edit.html.haml
+++ /dev/null
@@ -1,5 +0,0 @@
-- @title = "Edit a Semantic Resource Information"
-
-%div{:style => "margin:10px;"}
- = form_for :ontology, url: ontology_path(@ontology.acronym), html: {method: :put, id: "ontologyForm"} do |f|
- = render partial: "form", locals: {f: f, button_text: "Save semantic resource", title_text: "Edit Semantic Resource Information"}
diff --git a/app/views/ontologies/htaccess.html.haml b/app/views/ontologies/htaccess.html.haml
new file mode 100644
index 000000000..bd59fcbe1
--- /dev/null
+++ b/app/views/ontologies/htaccess.html.haml
@@ -0,0 +1,68 @@
+= render_in_modal do
+ %p
+ = t("ontologies.htaccess_redirection_description")
+
+ %h5
+ %strong
+ = t("ontologies.instructions_servers", server: "Apache")
+ %ol
+ %li
+ %strong
+ = t("ontologies.htaccess_redirection.instruction_1")
+ = t("ontologies.htaccess_redirection.instruction_1_content")
+ %li
+ %strong
+ = t("ontologies.htaccess_redirection.instruction_2")
+ = t("ontologies.htaccess_redirection.instruction_2_content")
+ %li
+ %strong
+ = t("ontologies.htaccess_redirection.instruction_3")
+ = t("ontologies.htaccess_redirection.instruction_3_content")
+
+ .htacess-code-container
+ .clipboard-component-resource-content{style: 'position: absolute; right: 2%; top: 8%;'}
+ = render ClipboardComponent.new(message: @htaccess_content, show_content: false)
+ %pre.mb-0
+ %code.d-block{style: 'text-wrap: pretty; word-break: break-all; color: white;'}
+ = @htaccess_content
+
+ %hr
+
+ %h5
+ %strong
+ = t("ontologies.instructions_servers", server: "Nginx")
+ %ol
+ %li
+ %strong
+ = t("ontologies.nginx_redirection.instruction_1")
+ = t("ontologies.nginx_redirection.instruction_1_content")
+ %li
+ %strong
+ = t("ontologies.nginx_redirection.instruction_2")
+ = t("ontologies.nginx_redirection.instruction_2_content")
+ %li
+ %strong
+ = t("ontologies.nginx_redirection.instruction_3")
+ = t("ontologies.nginx_redirection.instruction_3_content")
+ %li
+ %strong
+ = t("ontologies.nginx_redirection.instruction_4")
+ = t("ontologies.nginx_redirection.instruction_4_content")
+ %li
+ %strong
+ = t("ontologies.nginx_redirection.instruction_5")
+ = t("ontologies.nginx_redirection.instruction_5_content")
+
+ .htacess-code-container
+ .clipboard-component-resource-content{style: 'position: absolute; right: 2%; top: 8%;'}
+ = render ClipboardComponent.new(message: @nginx_content, show_content: false)
+ %pre.mb-0
+ %code.d-block{style: 'text-wrap: pretty; word-break: break-all; color: white;'}
+ = @nginx_content
+
+ %h5
+ %strong Note
+ = render Display::AlertComponent.new(message: t("ontologies.redirection_note"), closable: false, type: "warning")
+
+ .contact-support{style: "width: 100%; display: flex; justify-content: end;"}
+ = render Buttons::RegularButtonComponent.new(id:'regular-button', value: t("ontologies.contact_support"), variant: "primary", href: "/feedback", target: "_blank", state: "regular")
\ No newline at end of file
diff --git a/app/views/ontologies/new.html.haml b/app/views/ontologies/new.html.haml
index 63165a10c..92f88fc21 100644
--- a/app/views/ontologies/new.html.haml
+++ b/app/views/ontologies/new.html.haml
@@ -1,5 +1,52 @@
-- @title = "Submit a New Semantic Resource"
+- @title = t("ontologies.submit_new_ontology")
%div{:style => "margin:10px;"}
- = form_for :ontology, url: {action: "create"}, html: {id: "ontologyForm"} do |f|
- = render partial: "form", locals: {f: f}
+ = form_for :ontology, url: {action: "create"}, html: {id: "ontologyForm", multipart: true} do
+ .upload-ontology-container
+ %div{style: 'width: 589px'}
+ = error_message_alert
+ .upload-ontology-card
+ .upload-ontology-center
+ .d-flex.justify-content-between
+ %a{:href => "javascript:javascript:history.go(-1)"}
+ %img.lost-password-arrowback{:src => "#{asset_path("arrow-back.svg")}"}
+ .register-title-container
+ %h2.register-title
+ = @is_update_ontology ? t("ontologies.add_new_submission", acronym: @ontology.acronym) : t("ontologies.submit_new_ontology")
+ %hr#register-title-line/
+ %div
+ .upload-ontology-progress
+ = render Layout::ProgressPagesComponent.new(pages_title: [t("ontologies.details"), t("ontologies.general_information"), t("ontologies.dates_and_contacts")]) do |c|
+ - c.page do
+ = render partial: 'ontologies/form'
+ - c.page do
+ .upload-ontology-desc
+ = metadata_help_link
+ .upload-ontology-input-field-container
+ = attribute_input('URI', label: t("ontologies.uri"))
+ .upload-ontology-input-field-container
+ = attribute_input('description', long_text: true)
+ - if @is_update_ontology
+ .upload-ontology-input-field-container{id: "submissionnotes_from_group_input"}
+ = attribute_input("notes", label: t("ontologies.change_notes"), long_text: true)
+ .upload-ontology-field-container
+ = has_ontology_language_input
+ .upload-ontology-field-container.mt-3
+ = render Layout::RevealComponent.new(selected: @submission.status, possible_values: ['retired']) do |c|
+ - c.button do
+ = attribute_input("status")
+ - c.container do
+ .upload-ontology-field-container
+ - @submission.valid = nil unless @submission.status&.eql?('retired')
+ = attribute_input("valid")
+ .upload-ontology-field-container
+ = render partial: 'ontologies/submission_location_form'
+
+ - c.page do
+ .upload-ontology-input-field-container
+ - if @is_update_ontology
+ = attribute_input('modificationDate', label: t("ontologies.modification_date"), max_date: Date.today)
+ - else
+ = attribute_input('released', label: t("ontologies.date_of_original_creation"), max_date: Date.today)
+ .upload-ontology-contact{id: "submissioncontact_from_group_input"}
+ = contact_input(show_help: false)
diff --git a/app/views/ontologies/ontologies_selector/ontologies_selector.html.haml b/app/views/ontologies/ontologies_selector/ontologies_selector.html.haml
new file mode 100644
index 000000000..932a061cd
--- /dev/null
+++ b/app/views/ontologies/ontologies_selector/ontologies_selector.html.haml
@@ -0,0 +1,73 @@
+= render_in_modal do
+ = form_tag('/ontologies_selector/results', method: :get, novalidate: true, data: {turbo_frame: 'selector_results_frame'}) do
+ .d-flex.align-items-center.justify-content-center{'data-controller': 'ontologies-selector', 'data-ontologies-selector-id-value': @select_id, 'data-ontologies-selector-select-all-value': t('ontologies_selector.select_all'), 'data-ontologies-selector-unselect-all-value': t('ontologies_selector.unselect_all')}
+ .ontologies-selector-container
+ .ontologies-selector-input
+ = text_input(label: '', placeholder: t('ontologies_selector.search_hint'), name: 'input', data: {action: 'input->ontologies-selector#input'})
+ = inline_svg_tag 'icons/search.svg'
+ .ontologies-selector-options{'data-action': 'change->ontologies-selector#change'}
+ .switch-filters
+ .show-ontology-views
+ .text
+ = t('ontologies_selector.show_ontology_view')
+ = render SwitchInputComponent.new(id: 'show-ontology-views', name: 'showOntologyViews')
+ .show-retired-ontologies
+ .text
+ = t('ontologies_selector.hide_retired_ontologies')
+ = render SwitchInputComponent.new(id: 'show-retired-ontologies', name: 'showRetiredOntologies')
+ - formats = @formats.drop(1)
+ %div{'data-ontologies-selector-target': 'table'}
+ = render TabsContainerComponent.new do |c|
+ = c.item(title: t('ontologies_selector.tabs_title.categories'), selected: true)
+ = c.item_content do
+ .chips.categories
+ - @filters[:categories][0].each do |item|
+ = chips_component(label: item.acronym, id: item.acronym, value: item.id, name: 'categories[]', tooltip: item.name)
+ = c.item(title: t('ontologies_selector.tabs_title.groups'))
+ = c.item_content do
+ .chips.groups
+ - @filters[:groups][0].each do |item|
+
+ = chips_component(label: item.acronym, id: item.acronym, value: item.id, name: 'groups[]', tooltip: item.name)
+
+ = c.item(title: t('ontologies_selector.tabs_title.format'))
+ = c.item_content do
+ .chips.format
+ - formats.each do |item|
+ = chips_component(label: item, id: item, name: 'formats[]', value: item)
+
+ = c.item(title: t('ontologies_selector.tabs_title.natural_languages'))
+ = c.item_content do
+ .chips.natural-language
+ - @filters[:naturalLanguage][0].each do |item|
+ = chips_component(label: item["acronym"], id: item["acronym"], name: 'naturalLanguage[]', value: item['id'])
+
+ = c.item(title: t('ontologies_selector.tabs_title.formality_levels'))
+ = c.item_content do
+ .chips
+ - @filters[:hasFormalityLevel][0].each do |item|
+ = chips_component(label: item["name"],id: item["acronym"], name: 'formalityLevel[]', value: item["id"])
+
+ = c.item(title: t('ontologies_selector.tabs_title.ontology_types'))
+ = c.item_content do
+ .chips
+ - @filters[:isOfType][0].each do |item|
+ = chips_component(label: item["name"],id: item["acronym"], name: 'isOfType[]', value: item["id"])
+ %input.d-none{type: 'submit', 'data-ontologies-selector-target': 'submit'}
+ = render TurboFrameComponent.new(id: 'selector_results_frame', src: '/ontologies_selector/results') do |container|
+ - container.loader do
+ = render LoaderComponent.new(type: 'pulsing')
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/views/ontologies/ontologies_selector/ontologies_selector_results.html.haml b/app/views/ontologies/ontologies_selector/ontologies_selector_results.html.haml
new file mode 100644
index 000000000..2aeafa23d
--- /dev/null
+++ b/app/views/ontologies/ontologies_selector/ontologies_selector_results.html.haml
@@ -0,0 +1,19 @@
+= render TurboFrameComponent.new(id:'selector_results_frame') do |container|
+ .ontologies-selector-results
+ .horizontal-line
+ .results-number
+ = t("ontologies.showing_ontologies_size", ontologies_size: @ontologies.length, analytics_size: @total_ontologies_number)
+ %span.select-all{'data-action': 'click->ontologies-selector#selectall'}
+ = t('ontologies_selector.select_all')
+ .ontologies
+ - @ontologies.each do |ontology|
+ .ontology{'data-ontologies-selector-target': 'ontology'}
+ = chips_component(id: "selector[#{ontology.acronym}]",value: ontology.acronym, label: "#{ontology.name} (#{ontology.acronym})", name: ontology.acronym)
+ .horizontal-line
+ .save-cancel-buttons
+ = cancel_button_component(class_name: 'button', id:'cancel-selector', value: t('ontologies_selector.cancel'), data: {action: "click->turbo-modal#hide", 'ontologies-selector-target': 'exit'})
+ = save_button_component(class_name: 'button', id:'apply-selector', value: t('ontologies_selector.apply'), data: {action: "click->ontologies-selector#apply"})
+
+
+ - container.loader do
+ = render LoaderComponent.new(type: 'pulsing')
\ No newline at end of file
diff --git a/app/views/ontologies/sections/_additional_metadata.html.haml b/app/views/ontologies/sections/_additional_metadata.html.haml
new file mode 100644
index 000000000..345656a7e
--- /dev/null
+++ b/app/views/ontologies/sections/_additional_metadata.html.haml
@@ -0,0 +1,8 @@
+= turbo_frame_tag 'application_modal_content' do
+ %div.card.overflow-hidden{style: 'border-radius: 20px;'}
+ %section{style:'height: 70vh; overflow-y: scroll'}
+ = render SubmissionMetadataComponent.new(submission: @submission_latest, submission_metadata: submission_metadata) unless @submission_latest.nil?
+ %div.scroll-message.text-center.py-3.bg-light.text-primary
+ %p.scroll-text.mb-0
+ = t("ontologies.sections.scroll_down_to_see_more")
+ %i.scroll-icon.fa.fa-chevron-down
\ No newline at end of file
diff --git a/app/views/ontologies/sections/_collections.html.haml b/app/views/ontologies/sections/_collections.html.haml
index 3ddd1d27d..280c64760 100644
--- a/app/views/ontologies/sections/_collections.html.haml
+++ b/app/views/ontologies/sections/_collections.html.haml
@@ -1,11 +1,15 @@
-= turbo_frame_tag 'collections' do
+= render TurboFrameComponent.new(id: "collections", data: {"turbo-frame-target": "frame"} ) do
- if no_collections?
= no_collections_alert
- else
%div.ont-collections{data:{controller: 'container-splitter'}}
- %div#collectionsTree{data:{'container-splitter-target': 'container'}}
- = render partial: 'collections/list_view'
- %div#collection_contents.pl-3{data:{'container-splitter-target': 'container'}}
+ %div#collectionsTree.card.sidebar{data:{'container-splitter-target': 'container'}}
+ = tree_container_component(id: "collections_sorted_list_view-page-1",
+ placeholder: t('ontologies.sections.collections_search_placeholder', acronym: @ontology.acronym),
+ frame_url: "/ontologies/#{@ontology.acronym}/collections",
+ tree_url: "/ontologies/#{@ontology.acronym}/collections?#{request.original_url.split('?')[1]}")
+
+ %div#collection_contents{data:{'container-splitter-target': 'container'}}
= render TurboFrameComponent.new(id: 'collection') do
- if @collection
= render partial: 'collections/collection', locals: {collection: @collection}
diff --git a/app/views/ontologies/sections/_licenses.html.haml b/app/views/ontologies/sections/_licenses.html.haml
new file mode 100644
index 000000000..3b5a15403
--- /dev/null
+++ b/app/views/ontologies/sections/_licenses.html.haml
@@ -0,0 +1,8 @@
+= render_in_modal do
+ = render Layout::ListComponent.new do |l|
+ - attrs = @licenses.reject{|x| x.to_s.eql?('copyrightHolder')}
+ - properties_list_component(l, attrs.map { |x| [x, @submission_latest.send(x.to_s)] }.to_h)
+ - properties_list_component(l, {copyrightHolder: [@submission_latest.copyrightHolder]}) do |values|
+ = horizontal_list_container(values) do |v|
+ = render ChipButtonComponent.new(type: "static",'data-controller':' tooltip', title: '', class: 'text-truncate', style: 'max-width: 280px; display:block; line-height: unset') do
+ = display_agent(v, link: false)
diff --git a/app/views/ontologies/sections/_metadata.html.haml b/app/views/ontologies/sections/_metadata.html.haml
old mode 100644
new mode 100755
index 71931d60a..9dd1a07df
--- a/app/views/ontologies/sections/_metadata.html.haml
+++ b/app/views/ontologies/sections/_metadata.html.haml
@@ -1,202 +1,76 @@
= turbo_frame_tag 'summary', target:"_top" do
- %div.ont-metadata
- -# Details pane
- %section.ont-metadata-card.ont-details-card
- %header.pb-2.font-weight-bold Details
- %table.table.table-sm
- %tr
- %td Acronym
- %td= @ontology.acronym
- %tr
- %td Visibility
- %td= strip_links(visibility_link(@ontology))
- - if @ontology.viewing_restricted?
- %tr
- %td Viewing restriction
- %td= @ontology.viewingRestriction.capitalize
- - unless @ontology.viewOf.nil?
- %tr
- %td View of ontology
- %td
- - ont_parent_acronym = @ontology.viewOf.split('/').last
- - if $PURL_ENABLED
- - ont_url = @ontology.purl.sub(@ontology.acronym, ont_parent_acronym)
- - else
- - ont_url = @ontology.links['ui'].sub(@ontology.acronym, ont_parent_acronym)
- = link_to(ont_parent_acronym, ont_url)
- - unless @submission_latest.nil?
- %tr
- %td Description
- %td= sanitize(@submission_latest.description)
- %tr
- %td Status
- %td= @submission_latest.status.capitalize unless @submission_latest.status.nil?
- %tr
- %td Format
- %td= @submission_latest.hasOntologyLanguage
- %tr
- %td Contact
- %td= raw @submission_latest.contact.map {|c| [c.name, c.email].join(", ") if c.member?(:name) && c.member?(:email)}.join(" ")
- - categories_hash = LinkedData::Client::Models::Category.all_to_hash
- - categories = @ontology.hasDomain
- - unless categories.empty?
- %tr
- %td Categories
- %td= categories.map {|c| categories_hash[c].name}.sort.join(", ")
- - groups_hash = LinkedData::Client::Models::Group.all_to_hash
- - groups = @ontology.group
- - unless groups.empty?
- %tr
- %td Groups
- %td= groups.map {|g| groups_hash[g].name}.sort.join(", ")
- - if @ontology.admin?(session[:user])
- %tr
- %td Pull URL
- %td
- = link_to @submission_latest.pullLocation, @submission_latest.pullLocation
- = raw additional_details
+ = not_ready_submission_alert(submission: @submission_latest)
+ .summary-page-center
+ .summary-page-first-row
+ = render partial: 'ontologies/sections/metadata/ontology_description_section'
+ = render partial: 'ontologies/sections/metadata/ontology_fairness_section'
+ = render partial: 'ontologies/sections/metadata/ontology_relations_network'
+ = render partial: 'ontologies/sections/metadata/ontology_submissions_section'
+ = render partial: 'ontologies/sections/metadata/ontology_metrics_section'
+ .summary-page-second-row
+ = ontology_depiction_card
+ = properties_card(t('ontologies.sections.identifiers'),t("ontologies.sections.identifiers"), @identifiers) do |values|
+ = horizontal_list_container(values) do |v|
+ - generate_htaccess = v.eql?(@identifiers["ontology_portal_uri"]&.first)
+ = render LinkFieldComponent.new(value: v, acronym: @ontology.acronym, raw: true, check_resolvability: true, generate_link: false, generate_htaccess: generate_htaccess)
- = render partial: 'additional_metadata'
+ = properties_dropdown('dates',t("ontologies.sections.dates"),'', @dates_properties) do |values|
+ - Array(values).sort.map do |v|
+ %div
+ = render DateTimeFieldComponent.new(value: v)
- -# Submissions pane
- %section.ont-metadata-card.ont-subs-card
- %div.ont-section-toolbar
- %header.pb-2.font-weight-bold Submissions
- - if @ontology.admin?(session[:user])
- = link_to(new_ontology_submission_path(@ontology.acronym, required: false), "aria-label": "Add submission", title: "Add submission") do
- %i.fas.fa-lg.fa-plus-circle{"aria-hidden": "true", style: "margin-left: 0.75rem;"}
- - unless (@submission_latest.nil? || (@submission_latest.respond_to?(:status) && @submission_latest.status == 404))
- = link_to(edit_ontology_submission_path(@ontology.acronym, @submission_latest.submissionId), "aria-label": "Edit latest submission", title: "Edit latest submission") do
- %i.fas.fa-user-edit{"aria-hidden": "true", style: "margin-left: 0.5rem;"}
- = render TurboFrameComponent.new(id: 'ontology_submissions', src: ontology_submissions_path(@ontology.acronym))
+ = properties_dropdown('person_and_organization',t("ontologies.sections.person_and_organization"),'', @agents_properties) do |values|
+ = horizontal_list_container(values) do |v|
+ = agent_chip_component(v)
+
+ = properties_dropdown('link',t("ontologies.sections.other_links"), t("ontologies.sections.info_tooltip_links") , @links_properties) do |values|
+ = horizontal_list_container(values) do |v|
+ = render LinkFieldComponent.new(value: v, raw: true)
+ = properties_dropdown('projects_section',t("ontologies.sections.projects_and_usage_information"),t("ontologies.sections.info_tooltip_projects"), nil) do |c|
+ - c.row do
+ = projects_field(@projects)
+ - properties_list_component(c, @projects_properties)
+ :javascript
+ var projectsUrl = document.location.hash
+ if (projectsUrl == "#projects_section"){
+ document.querySelector("[data-target='#projects_section']")?.click()
+ }
+ = properties_dropdown('methodology',t("ontologies.sections.methodology_and_provenance"), t("ontologies.sections.info_tooltip_properties_dropdown"), @methodology_properties)
+ = properties_dropdown('community',t("ontologies.sections.community"), t("ontologies.sections.info_tooltip_properties_dropdown"), nil ) do |c|
+ - properties_list_component(c, @community_properties, truncate: false)
+ - unless Array(@ontology.group).empty?
+ - c.row do
+ = render FieldContainerComponent.new(label: t("ontologies.sections.label_groups")) do
+ = horizontal_list_container(@ontology.group) do |v|
+ = render ChipButtonComponent.new(text: show_group_name(v), type: "static", tooltip: show_group_name(v))
+ = properties_dropdown('content',t("ontologies.sections.content"), t("ontologies.sections.info_tooltip_properties_dropdown"), nil) do |c|
+ - properties_list_component(c, @content_properties.reject{|k, v| %w[keyClasses metadataVoc].include?(k.to_s)})
+ - c.row do
+ = render FieldContainerComponent.new(label: attr_label('metadataVoc', attr_metadata: attr_metadata("metadataVoc"), show_tooltip: false)) do
+ = Array(@content_properties['metadataVoc']).map{|x| metadata_vocabulary_display(x)}.join.html_safe
+ = render Layout::CardComponent.new do |c|
+ - c.header do |h|
+ - h.text do
+ = t("ontologies.sections.visits")
+ - if visits_data(@ontology)
+ = link_to(@ontology.links["analytics"] + "?apikey=#{get_apikey}&format=csv", title: t("ontologies.sections.download_as_csv")) do
+ = inline_svg("summary/download.svg", width: '30px', height: '20px')
- -# Views pane (don't show if the ontology is a view - we don't allow views of views).
- - unless @ontology.view?
- %section.ont-metadata-card.ont-views-card
- %div.ont-section-toolbar
- %header.pb-2.font-weight-bold= "Views of #{@ontology.acronym}"
- - ont_id_esc = CGI.escape(@ontology.id)
- -# TODO: I don't think we should have brackets in the URL parameters.
- - if session[:user].nil?
- %a{href: "/login?redirect=#{escape("/ontologies/new?ontology[viewOf]=#{ont_id_esc}")}", "aria-label": "Create new view", title: "Create new view"}
- %i.fas.fa-lg.fa-plus-circle{"aria-hidden": "true", style: "margin-left: 0.5rem;"}
- - else
- %a{href: "/ontologies/new?ontology[viewOf]=#{ont_id_esc}"}
- %i.fas.fa-lg.fa-plus-circle{"aria-hidden": "true", style: "margin-left: 0.5rem;"}
- - if @views.empty?
- %p.font-italic= "No views of #{@ontology.acronym} available"
- - else
- %div.border-top
- %dl
- - @view_decorators.each do |view_decorator|
- %dt= view_decorator.linked_name
- %dd= view_decorator.description
+ = render Layout::ListComponent.new do |l|
+ - l.row do
+ = render partial: "visits"
- %div.right-hand-content
- -# Social share pane
- %section.ont-metadata-card.ont-socialshare-card
- %div.ont-section-toolbar
- %header.pb-2.font-weight-bold Share on socials
- = social_share_link(@ontology, "Facebook")
- = social_share_link(@ontology, "Twitter")
- = social_share_link(@ontology, "LinkedIn")
- :javascript
- window.Sharer.init()
- %div
- -# Misc links pane
- %section.ont-metadata-card.ont-links-card
- %div.ont-section-toolbar
- %header.pb-2.font-weight-bold Links
- %a{:href => "#{(@submission_latest || @ontology).id}?display=all", :target => '_blank', :class => "btn btn-primary"} Go to the REST API JSON entry
+ - unless @ontology.view?
+ = render Layout::CardComponent.new do |d|
+ - d.header do |h|
+ - h.text do
+ = t("ontologies.sections.views", acronym: @ontology.acronym)
+ = new_element_link(t("ontologies.sections.create_new_view"), new_view_path(@ontology.id))
+ = render Layout::ListComponent.new do |l|
+ - l.row do
+ = render partial: 'ontology_views'
- -# Metadata links pane
- %section.ont-metadata-card.ont-metadatalinks-card
- %div.ont-section-toolbar
- %header.pb-2.font-weight-bold Get my metadata back
- %div
- - unless @submission_latest.nil?
- %div{data:{controller: 'metadata-downloader'}}
- =javascript_include_tag "jsonld"
- %button.btn.btn-primary.my-1{'data-action': 'metadata-downloader#downloadDataCiteJSON'} JSON DATACITE
- %button.btn.btn-primary{'data-action': 'metadata-downloader#downloadEcoPortalJSON'} JSON ECOPORTAL
- %br
- %button{:id => "getMetadataBackNquadsBtn", :class => "btn btn-primary", 'data-action': 'metadata-downloader#downloadNQuads'} N-Triple
- %button{:id => "getMetadataBackJsonldBtn", :class => "btn btn-primary", 'data-action': 'metadata-downloader#downloadJsonLd'} JSON-LD
- %button{:id => "getMetadataBackXmlBtn", :class => "btn btn-primary", 'data-action': 'metadata-downloader#downloadXML'} RDF/XML
-
-
- -# Fair score pane
- -# TODO temporary hide fairness_service for AGROVOC after there demand
- - if fairness_service_enabled? && @ontology.acronym != 'AGROVOC'
- %section.ont-metadata-card.ont-fair-score-card#fair-summary
- %div.ont-section-toolbar
- %header.pb-2.font-weight-bold
- = render partial: "fair_score/fair_service_header"
- %div#fair-score-charts-container
- = render partial: "fairs_score"
-
- -# Metrics pane
- %section.ont-metadata-card.ont-metrics-card
- %div.ont-section-toolbar
- %header.pb-2.font-weight-bold Metrics
- = link_to(Rails.configuration.settings.links[:metrics], target: "_blank", "aria-label": "View individual metrics definitions", title: "View individual metrics definitions") do
- %i.fas.fa-lg.fa-question-circle{"aria-hidden": "true", style: "margin-left: 0.5rem"}
- - if @metrics.nil? || (@metrics.is_a?(Array) && @metrics.empty?) || (@metrics.respond_to?(:status) && @metrics.status == 404)
- %p.font-italic= "We have not yet calculated metrics for #{@ontology.acronym}"
- - else
- %table.table.table-sm
- %tr
- %td Classes
- %td{style: "text-align: right"}= number_with_delimiter(@metrics.classes)
- %tr
- %td Individuals
- %td= number_with_delimiter(@metrics.individuals)
- %tr
- %td Properties
- %td= number_with_delimiter(@metrics.properties)
- %tr
- %td Maximum depth
- %td= number_with_delimiter(@metrics.maxDepth)
- %tr
- %td Maximum number of children
- %td= number_with_delimiter(@metrics.maxChildCount)
- %tr
- %td Average number of children
- %td= number_with_delimiter(@metrics.averageChildCount)
- %tr
- %td Classes with a single child
- %td= number_with_delimiter(@metrics.classesWithOneChild)
- %tr
- %td Classes with more than 25 children
- %td= number_with_delimiter(@metrics.classesWithMoreThan25Children)
- %tr
- %td Classes with no definition
- %td= number_with_delimiter(@metrics.classesWithNoDefinition)
- -# Visits pane
- %section.ont-metadata-card.ont-analytics-card
- %div.ont-section-toolbar
- %header.pb-2.font-weight-bold Visits
- - if visits_data(@ontology)
- = link_to(@ontology.links["analytics"] + "?apikey=#{get_apikey}&format=csv", "aria-label": "Download as CSV", title: "Download as CSV") do
- %i.fas.fa-lg.fa-download{"aria-hidden": "true", style: "margin-left: 0.5rem"}
- = render partial: "visits"
-
- -# Included in data catalog pane
- = raw display_data_catalog(@submission_latest) unless @submission_latest.nil?
- -# Logo & depiction
- = raw display_logo(@submission_latest) unless @submission_latest.nil?
-
- -# Projects pane
- %section.ont-metadata-card.ont-projects-card
- %div.ont-section-toolbar
- %header.pb-2.font-weight-bold= "Projects using #{@ontology.acronym}"
- = link_to(new_project_path(), "aria-label": "Create new project", title: "Create new project") do
- %i.fas.fa-lg.fa-plus-circle{"aria-hidden": "true", style: "margin-left: 0.5rem"}
- - if @projects.empty?
- %p.font-italic= "No projects using #{@ontology.acronym}"
- - else
- %div.border-top
- - for project in @projects
- %p= link_to(project.name, project_path(project.acronym))
+ = admin_block do
+ = properties_dropdown('configuration',t("ontologies.sections.configuration_metadata"), t("ontologies.sections.info_tooltip_configuration"), @config_properties)
diff --git a/app/views/ontologies/sections/_metrics.html.haml b/app/views/ontologies/sections/_metrics.html.haml
new file mode 100644
index 000000000..c0b42d17f
--- /dev/null
+++ b/app/views/ontologies/sections/_metrics.html.haml
@@ -0,0 +1,11 @@
+= render_in_modal do
+ = render TableComponent.new do |t|
+ - t.add_row({th: t("ontologies.sections.classes")}, {td: number_with_delimiter(@metrics.classes)})
+ - t.add_row({th: t("ontologies.sections.individuals")}, {td: number_with_delimiter(@metrics.individuals)})
+ - t.add_row({th: t("ontologies.sections.properties")}, {td: number_with_delimiter(@metrics.properties)})
+ - t.add_row({th: t("ontologies.sections.maximum_depth")}, {td: number_with_delimiter(@metrics.maxDepth)})
+ - t.add_row({th: t("ontologies.sections.maximum_number_of_children")}, {td: number_with_delimiter(@metrics.maxChildCount)})
+ - t.add_row({th: t("ontologies.sections.average_number_of_children")}, {td: number_with_delimiter(@metrics.averageChildCount)})
+ - t.add_row({th: t("ontologies.sections.classes_with_a_single_child")}, {td: number_with_delimiter(@metrics.classesWithOneChild)})
+ - t.add_row({th: t("ontologies.sections.classes_with_more_than_25_children")}, { td: number_with_delimiter(@metrics.classesWithMoreThan25Children)})
+ - t.add_row({th: t("ontologies.sections.classes_with_no_definition")}, {td: number_with_delimiter(@metrics.classesWithNoDefinition)})
diff --git a/app/views/ontologies/sections/_notes.html.haml b/app/views/ontologies/sections/_notes.html.haml
index 11ee81c20..9f528fcb4 100644
--- a/app/views/ontologies/sections/_notes.html.haml
+++ b/app/views/ontologies/sections/_notes.html.haml
@@ -1,4 +1,3 @@
= turbo_frame_tag 'notes' do
%div#notes_content{style:"margin: 1em 0"}
- %h2{style:"margin-bottom: -0.5em; font-size: x-large; padding: .5em .5em 0; float: left;"} Notes
= render :partial => 'notes/ontology_list'
diff --git a/app/views/ontologies/sections/_schemes.html.haml b/app/views/ontologies/sections/_schemes.html.haml
index 5387f37a1..aa01c54aa 100644
--- a/app/views/ontologies/sections/_schemes.html.haml
+++ b/app/views/ontologies/sections/_schemes.html.haml
@@ -1,11 +1,15 @@
-= turbo_frame_tag 'schemes' do
+= render TurboFrameComponent.new(id: "schemes", data: {"turbo-frame-target": "frame"} ) do
%div.ont-schemes{data:{controller: 'container-splitter'}}
- %div#schemesTree{data:{'container-splitter-target': 'container'}}
+ %div#schemesTree.card.sidebar{data:{'container-splitter-target': 'container'}}
- if no_schemes?
= no_schemes_alert
- else
- = render partial: 'schemes/tree_view'
- %div#scheme_contents.pl-3{data:{'container-splitter-target': 'container'}}
+ = tree_container_component(id: "schemes_sorted_list_view-page-1",
+ placeholder: t('ontologies.sections.schemes_search_placeholder', acronym: @ontology.acronym),
+ frame_url: "/ontologies/#{@ontology.acronym}/schemes?#{request.original_url.split('?')[1]}",
+ tree_url: "/ontologies/#{@ontology.acronym}/schemes?#{request.original_url.split('?')[1]}")
+
+ %div#scheme_contents{data:{'container-splitter-target': 'container'}}
= render TurboFrameComponent.new(id:'scheme') do
= render partial: 'schemes/scheme', locals: {scheme: @scheme}
diff --git a/app/views/ontologies/sections/_sparql.html.haml b/app/views/ontologies/sections/_sparql.html.haml
new file mode 100644
index 000000000..3d2921c14
--- /dev/null
+++ b/app/views/ontologies/sections/_sparql.html.haml
@@ -0,0 +1,2 @@
+= render TurboFrameComponent.new(id: "sparql", data: {"turbo-frame-target": "frame"} ) do
+ = sparql_query_container(graph: @submission_latest.id )
\ No newline at end of file
diff --git a/app/views/ontologies/sections/_widgets.html.haml b/app/views/ontologies/sections/_widgets.html.haml
index 6930a21de..c6b171250 100644
--- a/app/views/ontologies/sections/_widgets.html.haml
+++ b/app/views/ontologies/sections/_widgets.html.haml
@@ -1,233 +1,194 @@
= turbo_frame_tag 'widgets' do
- :javascript
- $(document).ready(function(){
- tb_init('a.thickbox, area.thickbox, input.thickbox');//pass where to apply thickbox
- imgLoader = new Image();// preload image
- imgLoader.src = tb_pathToImage;
- });
-
- - ont_uri = "/ontologies/#{@ontology.acronym}"
- - get_code_prefix = ont_uri + '?p=widgets#TB_inline&height=400&width=600'
-
- if @ontology.metadata_only?
#widgets_content{:style => "padding: 1em;"}
%p
- Widgets are only available for ontologies stored in #{$SITE}.
+ = t("ontologies.sections.classes", site: "#{$SITE}")
- else
- #widgets_content
- %h5.pb-3 Add #{$ORG} Web Widgets to your site for #{@ontology.acronym}
- %table#widget_table{width: "100%"}
- %tr
- %th
- Widget type
- %th
- Widget demonstration
- %tr
- %td
- %div.card
- %div.card-body
- %h5.card-title Jump To
- %p.card-text Type a class name from #{@ontology.acronym} and jump to it in #{$SITE}
- %a.btn.btn-info.thickbox{href: "#{get_code_prefix}&inlineId=jump".html_safe} Get code
- %td
+ - first_class_id = @ontology.explore.classes["collection"].first&.id || ''
+ %div
+ %h5.p-4
+ = t("ontologies.sections.add_acronym_widgets", acronym: @ontology.acronym)
+ %div
+ = render WidgetBlockComponent.new(id:'jump-to-widget', title: t("ontologies.sections.widget_block_component_title_1"), description: t("ontologies.sections.widget_block_component_description_1", acronym: @ontology.acronym, site: "#{$SITE}")) do |c|
+ - c.widget do
#bp_quick_jump
- :javascript
- var BP_SEARCH_SERVER = "#{$UI_URL}";
- var BP_SITE = "#{$SITE}";
- var BP_ORG = "#{$ORG}";
- var BP_ontology_id = "#{@ontology.acronym}";
- = javascript_include_tag "/javascripts/widgets/quick_jump.js"
- #jump{:style => "display:none;"}
- %h2 Step 2: Follow the Instructions
- %hr/
- .enable-lists
- %ul
- %li
- Download the
- %a.external.free{:href => "/javascripts/widgets/quick_jump.js", :rel => "nofollow", :title => "/javascripts/widgets/quick_jump.js"}
- %b quick_jump.js file
- and put it on your server
- %li
- Copy the code below and paste it to your HTML page
- %li
- %b Note:
- If you would like to use Quick Jump across multiple ontologies:
- %ul
- %li
- You can enter a comma-separated list of ontology ids:
- %br/
- var BP_ontology_id = "NCIt,SNOMEDCT";
- %li
- You can set the variable to 'all' to search all ontologies in #{$SITE}:
- %br/
- var BP_ontology_id = "all";
- %li
- To include definitions in the Jump To drop-down, add the following variable in Javascript:
- %br/
- %pre var BP_include_definitions = true;
- %li
- In the code that you just pasted, make sure to change the path to the quick_jump.js file to point to the location where you put the file (relative to your HTML file)
- %ul
- %li
- For example, if you put the quick_jump.js file in the same directory as your HTML file, this is the code you would use:
- %pre
- = preserve do
- :escaped
-
-
-
+ :javascript
+ var BP_SEARCH_SERVER = "#{$UI_URL}";
+ var BP_SITE = "#{$SITE}";
+ var BP_ORG = "#{$ORG}";
+ var BP_ontology_id = "#{@ontology.acronym}";
+ = javascript_include_tag "/javascripts/widgets/quick_jump.js"
+ - c.help_text do
+ .enable-lists
+ %ul
+ %li
+ = t("ontologies.sections.download")
+ %a.external.free{:href => "/javascripts/widgets/quick_jump.js", :rel => "nofollow", :title => "/javascripts/widgets/quick_jump.js"}
+ %b quick_jump.js file
+ = t("ontologies.sections.put_on_server")
+ %li
+ = t("ontologies.sections.copy_and_paste")
+ %li
+ %b= t("ontologies.sections.note")
+ = t("ontologies.sections.use_quick_jump")
+ %ul
+ %li
+ = t("ontologies.sections.enter_list_of_ontologies")
+ %br/
+ var BP_ontology_id = "NCIt,SNOMEDCT";
+ %li
+ = t("ontologies.sections.set_the_variable", site: "#{$SITE}")
+ %br/
+ var BP_ontology_id = "all";
+ %li
+ = t("ontologies.sections.include_definitions")
+ %br/
+ %pre var BP_include_definitions = true;
+ %li
+ = t("ontologies.sections.info_pasted_code")
+ %ul
+ %li
+ = t("ontologies.sections.example_to_use_code")
+ %pre
+ = preserve do
+ :escaped
+
+
+
%p
- For more help visit
- %a{:href => "http://bioontology.org/wiki/index.php/NCBO_Widgets#How_to_use_NCBO_Widgets", :target => "_blank"} NCBO Widget Wiki
- %tr
- %td
- %div.card
- %div.card-body
- %h5.card-title Form Autocomplete
- %p.card-text Fill your form fields with classes from #{@ontology.acronym}
- %a.btn.btn-info.thickbox{href: "#{get_code_prefix}&inlineId=form".html_safe} Get code
- %td
- = javascript_include_tag "/javascripts/widgets/form_complete.js"
- Example 1 (start typing the class name to get its full URI)
- %br/
- %input{:class => "bp_form_complete-#{CGI.escape(@ontology.acronym).sub('-', '%2d')}-uri", :name => "a", :size => "100", :type => "text"}/
- %br/
- Example 2 (get the ID for a class)
- %br/
- %input{:class => "bp_form_complete-#{CGI.escape(@ontology.acronym).sub('-', '%2d')}-shortid", :name => "b", :size => "100", :type => "text"}/
- %br/
- Example 3 (get the preferred name for a class)
- %br/
- %input{:class => "bp_form_complete-#{CGI.escape(@ontology.acronym).sub('-', '%2d')}-name", :name => "c", :size => "100", :type => "text"}/
- #form{:style => "display:none;"}
- .enable-lists
- %h2 Step 2: Follow the Instructions
- %hr/
- %ul
- %li
- Download the
- %a.external.free{:href => "/javascripts/widgets/form_complete.js", :rel => "nofollow", :title => "/javascripts/widgets/form_complete.js"}
- %b form_complete.js file
- and put it on your server.
- %li
- In the header for the page where you want the form field, include the
- %b form_complete.js
- file.
- %li
- On your form, for the fields where you want to use the class-selection widget, specify the field's class in the following format:
- %code bp_form_complete-{ontology_id_list}-{value}
- %ul
- %li
- For example,
- %code bp_form_complete-NCIT-uri
- will use NCI Thesaurus (ontology id is NCIT) and will put the class URI in the field after the user selects the class from the pull-down list.
- %ul
- %li
- %b Note:
- In addition to single ontology ids, you can use a list:
- %br/
- %code bp_form_complete-NCIT,NCBITAXON-uri
- %li
- %b OR
- use 'all' to search across all #{$SITE} ontologies:
- %br/
- %code bp_form_complete-all-uri
- %li The autocomplete widget accesses ontology content from the latest version of the ontology.
- %li
- You can use the following parameters to select which value will be placed into the user-visible input field:
- %ul
- %li
- %code uri
- put the complete URI of the class (e.g.,
- = succeed ")" do
- %a.external.free{:href => @ontology.explore.classes["collection"].first.id, :rel => "nofollow", :title => "/visualize/39478/Common_Neoplasm"}
- = @ontology.explore.classes["collection"].first.id
- %li
- %code shortid
- put the short id of the class, as used in #{$SITE} (e.g., "Common_Neoplasm");
- %li
- %code name
- put the preferred name of the class (e.g., "Common Neoplasm");
- %li
- In addition to the input element you defined, there are four hidden form elements that are created and then set when a user selects a class from the list. For example, if you create a field with this code:
- %ul
- %pre= h ' '
- The 'name' attribute is used to create the four following fields (note how the 'a' from the name attribute is appended to the id attribute):
- %ul
- %li
- %pre= h ' '
- %li
- %pre= h ' '
- %li
- %pre= h ' '
- %li
- %pre= h ' '
- %li
- Additional parameters are documented on the
- %a{:href => "http://bioontology.org/wiki/index.php/NCBO_Widgets#How_to_use_NCBO_Widgets", :target => "_blank"} NCBO Widget Wiki
- %p
- For more help visit
+ = t("ontologies.sections.help_visit")
+ %a{:href => "http://bioontology.org/wiki/index.php/NCBO_Widgets#How_to_use_NCBO_Widgets", :target => "_blank"}
+ = t("ontologies.sections.ncbo_widget_wiki")
+ %div
+ = render WidgetBlockComponent.new(id:'form-autocomplete-widget', title: t("ontologies.sections.widget_block_component_title_2") , description: t("ontologies.sections.widget_block_component_description_2", acronym: @ontology.acronym)) do |c|
+ - c.widget do
+ %div.py-3.px-1
+ %p.card-text
+ = t("ontologies.sections.example_1")
+ %input{:class => "form-control bp_form_complete-#{CGI.escape(@ontology.acronym).sub('-', '%2d')}-uri", :name => "a", :size => "100", :type => "text"}/
+
+ %p.card-text
+ = t("ontologies.sections.example_2")
+ %input{:class => "form-control bp_form_complete-#{CGI.escape(@ontology.acronym).sub('-', '%2d')}-shortid", :name => "b", :size => "100", :type => "text"}/
+
+ %p.card-text
+ = t("ontologies.sections.example_3")
+ %input{:class => "form-control bp_form_complete-#{CGI.escape(@ontology.acronym).sub('-', '%2d')}-name", :name => "c", :size => "100", :type => "text"}/
+ = javascript_include_tag "/javascripts/widgets/form_complete.js"
+
+ - c.help_text do
+ .enable-lists
+ %ul
+ %li
+ = t("ontologies.sections.download")
+ %a.external.free{:href => "/javascripts/widgets/form_complete.js", :rel => "nofollow", :title => "/javascripts/widgets/form_complete.js"}
+ %b form_complete.js file
+ = t("ontologies.sections.put_on_server")
+ %li
+ = t("ontologies.sections.include_file")
+ %b form_complete.js
+ = t("ontologies.sections.include_file")
+ %li
+ = t("ontologies.sections.use_widget")
+ %code bp_form_complete-{ontology_id_list}-{value}
+ %ul
+ %li
+ = t("ontologies.sections.for_example")
+ %code bp_form_complete-NCIT-uri
+ = t("ontologies.sections.use_ontology")
+ %ul
+ %li
+ %b= t("ontologies.sections.note")
+ = t("ontologies.sections.use_list")
+ %br/
+ %code bp_form_complete-NCIT,NCBITAXON-uri
+ %li
+ %b= t("ontologies.sections.or")
+ = t("ontologies.sections.use_all_to_search", site: "#{$SITE}")
+ %br/
+ %code bp_form_complete-all-uri
+ %li= t("ontologies.sections.autocomplete_widget_accesses")
+ %li
+ = t("ontologies.sections.use_following_parameters")
+ %ul
+ %li
+ %code= t("ontologies.sections.uri")
+ = t("ontologies.sections.class_uri_description")
+ = succeed ")" do
+ %a.external.free{:href => @ontology.explore.classes["collection"].first&.id, :rel => "nofollow", :title => "/visualize/39478/Common_Neoplasm"}
+ = first_class_id
+ %li
+ %code= t("ontologies.sections.shortid")
+ = t("ontologies.sections.class_shortid_description", site: "#{$SITE}")
+ %li
+ %code= t("ontologies.sections.name")
+ = t("ontologies.sections.class_name_description")
+ %li
+ = t("ontologies.sections.hidden_elements_description")
+ %ul
+ %pre= h ' '
+ = t("ontologies.sections.hidden_elements_example")
+ %ul
+ %li
+ %pre= h ' '
+ %li
+ %pre= h ' '
+ %li
+ %pre= h ' '
+ %li
+ %pre= h ' '
+ %li
+ = t("ontologies.sections.additional_parameters")
%a{:href => "http://bioontology.org/wiki/index.php/NCBO_Widgets#How_to_use_NCBO_Widgets", :target => "_blank"} NCBO Widget Wiki
- %tr
- %td
- %div.card
- %div.card-body
- %h5.card-title Visualization
- %p.card-text Display a visualization for a given class in #{@ontology.acronym}
- %a.btn.btn-info.thickbox{href: "#{get_code_prefix}&inlineId=vis".html_safe} Get code
- %td
- #bp_vis_container
- - rest_domain = $REST_URL.sub(/https?:\/\//, "")
-
- #vis{:style => "display:none;"}
- %h2 Step 2: Follow the Instructions
- %hr/
- %b Copy the code below and paste it to your HTML page
- %br/
- %br/
- %pre
- = preserve do
- :escaped
-
%p
- For more help visit
+ = t("ontologies.sections.more_help_visit")
%a{:href => "http://bioontology.org/wiki/index.php/NCBO_Widgets#How_to_use_NCBO_Widgets", :target => "_blank"} NCBO Widget Wiki
- - unless @ontology.flat?
- %tr
- %td
- %div.card
- %div.card-body
- %h5.card-title Tree Widget
- %p.card-text Display a class tree with a search field for #{@ontology.acronym}
- %a.btn.btn-info.thickbox{href: "#{get_code_prefix}&inlineId=widget_tree_popup".html_safe} Get code
- %td
- %link{rel:"stylesheet", type:"text/css", href:"/widgets/jquery.ncbo.tree.css"}
- #bp_widget_tree_container
- #widget_tree
- :javascript
- $.getScript( "/widgets/jquery.ncbo.tree-2.0.2.js", () => {
- var widget_tree = $("#widget_tree").NCBOTree({
- apikey: "#{$API_KEY}",
- ontology: "#{@ontology.acronym}",
- ncboUIURL: "#{$UI_URL}",
- ncboAPIURL: "#{$REST_URL}"
- });
- })
+ %div
+ = render WidgetBlockComponent.new(id: 'visualization-widget', title: t("ontologies.sections.widget_block_component_title_3"), description: t("ontologies.sections.widget_block_component_description_3", acronym: @ontology.acronym)) do |c|
+ - c.widget do
+ #bp_vis_container
+ - rest_domain = $REST_URL.sub(/https?:\/\//, "")
+
+ - c.help_text do
+ %b= t("ontologies.sections.copy_and_paste")
+ %br
+ %br
+ %pre
+ = preserve do
+ :escaped
+
+ %p
+ = t("ontologies.sections.more_help_visit")
+ %a{:href => "http://bioontology.org/wiki/index.php/NCBO_Widgets#How_to_use_NCBO_Widgets", :target => "_blank"} NCBO Widget Wiki
+ - unless @ontology.flat?
+ %div
+ = render WidgetBlockComponent.new(id: 'tree-widget', title: t("ontologies.sections.widget_block_component_title_4"), description: t("ontologies.sections.widget_block_component_description_4", acronym: @ontology.acronym)) do |c|
+ - c.widget do
+ %link{rel:"stylesheet", type:"text/css", href:"/widgets/jquery.ncbo.tree.css"}
+ #widget_tree
+ :javascript
+ $.getScript( "/widgets/jquery.ncbo.tree-2.0.2.js", () => {
+ var widget_tree = $("#widget_tree").NCBOTree({
+ apikey: "#{$API_KEY}",
+ ontology: "#{@ontology.acronym}",
+ ncboUIURL: "#{$UI_URL}",
+ ncboAPIURL: "#{$REST_URL}"
+ });
+ })
- #widget_tree_popup{:style => "display:none;"}
- %h2 Step 2: Follow the Instructions
- %hr/
- %b Copy the code below and paste it to your HTML page
- %br/
- %br/
- %pre
- = preserve do
- :escaped
+
+ - c.help_text do
+ %b= t("ontologies.sections.copy_and_paste")
+ %br/
+ %br/
+ %pre
+ = preserve do
+ :escaped
@@ -236,9 +197,12 @@
ontology: "#{@ontology.acronym}"
});
- %p
- You can also view a
- %a{href: "/widgets/ncbo_tree.html"} detailed demonstration
- %p
- For more help visit
- %a{:href => "http://bioontology.org/wiki/index.php/NCBO_Widgets#How_to_use_NCBO_Widgets", :target => "_blank"} NCBO Widget Wiki
+ %p
+ = t("ontologies.sections.can_also_view")
+ %a{href: "/widgets/ncbo_tree.html", target: '_blank'}
+ = t("ontologies.sections.detailed_demonstration")
+ %p
+ = t("ontologies.sections.more_help_visit")
+ %a{:href => "http://bioontology.org/wiki/index.php/NCBO_Widgets#How_to_use_NCBO_Widgets", :target => "_blank"}
+ = t("ontologies.sections.ncbo_widget_wiki")
+
diff --git a/app/views/ontologies/sections/metadata/_metrics_evolution_graph.html.haml b/app/views/ontologies/sections/metadata/_metrics_evolution_graph.html.haml
new file mode 100644
index 000000000..918c5275a
--- /dev/null
+++ b/app/views/ontologies/sections/metadata/_metrics_evolution_graph.html.haml
@@ -0,0 +1,6 @@
+= turbo_frame_tag 'application_modal_content' do
+ - data = data.values.first.each_with_index.map{|x, i| ["Submission #{i + 1}", x]}.reject{|_, count| count.zero?}.to_h
+
+ = chart_component(title: '', type: 'line',
+ labels: data.keys,
+ datasets: visits_chart_dataset_array({ count: data.to_a}, fill: false))
diff --git a/app/views/ontologies/sections/metadata/_ontology_description_section.html.haml b/app/views/ontologies/sections/metadata/_ontology_description_section.html.haml
new file mode 100644
index 000000000..dc0c5221f
--- /dev/null
+++ b/app/views/ontologies/sections/metadata/_ontology_description_section.html.haml
@@ -0,0 +1,73 @@
+= render Layout::CardComponent.new do |c|
+ - c.header(text: t("ontologies.sections.metadata.general_information"))
+ = render Layout::ListComponent.new do |l|
+ - l.row do
+ %div
+ - if @submission_latest&.abstract.blank?
+ .creation_text.d-flex.align-items-center
+ = render TextAreaFieldComponent.new(value: @submission_latest&.description)
+ - unless @submission_latest&.logo.nil? || !link?(@submission_latest&.logo)
+ = image_tag(@submission_latest&.logo, class: 'description_img ml-2', width: '145px')
+ - else
+ .d-flex.align-items-center
+ = render FieldContainerComponent.new(label: t("ontologies.sections.metadata.abstract")) do
+ .creation_text
+ = render TextAreaFieldComponent.new(value: @submission_latest&.abstract)
+ - unless @submission_latest&.logo.nil? || !link?(@submission_latest&.logo)
+ = image_tag(@submission_latest&.logo, class: 'description_img ml-2', width: '145px')
+ = render FieldContainerComponent.new(label: t("ontologies.sections.metadata.description")) do
+ .creation_text
+ = render TextAreaFieldComponent.new(value: @submission_latest&.description)
+
+
+
+
+ - l.row do
+ %div.creation_text
+ - if @submission_latest&.released
+ = t("ontologies.sections.metadata.initial_created_on")
+ %span.date_creation_text= l(Date.parse(@submission_latest.released), format: :monthfull_day_year) + '.'
+ - if @submission_latest&.contact
+ = t("ontologies.sections.metadata.additional_information")
+ %span
+ #{display_contact(@submission_latest.contact).html_safe}.
+
+ - unless Array(@submission_latest&.naturalLanguage).empty?
+ - l.row do
+ = render FieldContainerComponent.new(label: t("ontologies.sections.metadata.languages")) do
+ = horizontal_list_container(Array(@submission_latest&.naturalLanguage)) do |v|
+ = render LanguageFieldComponent.new(value: v)
+
+
+ - unless Array(@submission_latest&.keywords).empty? && Array(@submission_latest&.keyClasses).empty?
+ - l.row do
+ = render FieldContainerComponent.new(label: t("ontologies.sections.metadata.keywords_and_classes")) do
+ - values = (Array(@submission_latest&.keywords) + Array(@submission_latest&.keyClasses))
+ - values = values.map{|x| x.split(',')}.flatten
+ = horizontal_list_container(values) do |v|
+ - if link?(v)
+ = raw get_link_for_cls_ajax(v, @ontology.acronym, '_blank')
+ - else
+ = render ChipButtonComponent.new(text: v, type: "static")
+ - domains = Array(@ontology&.hasDomain) + Array(@submission_latest&.hasDomain)
+ - unless domains.empty?
+ - l.row do
+ = render FieldContainerComponent.new(label: t("ontologies.sections.metadata.categories_and_subjects")) do
+ = horizontal_list_container(show_ontology_domains(domains).uniq) do |v|
+ = render ChipButtonComponent.new(text: show_category_name(v), type: "static")
+
+ - if @submission_latest&.pullLocation
+ - l.row do
+ = admin_block(class_css: '') do
+ = render FieldContainerComponent.new(label: t("ontologies.sections.metadata.pull_location") ) do
+ = horizontal_list_container([@submission_latest&.pullLocation]) do |v|
+ %span.admin-background
+ = render LinkFieldComponent.new(value: v)
+ %hr.w-100.my-3
+ .icons_container
+ = ontology_icon_links(@ontology_icon_links, @submission_latest)
+ %hr.w-100.my-3
+ %div.text-center.pb-3
+ = link_to_modal(nil, metadata_export_index_path(ontology: @ontology.acronym), {data: {show_modal_title_value: metadata_filled_count, show_modal_size_value: 'modal-xl' }}) do
+ = t("ontologies.sections.metadata.export_metadata")
+
diff --git a/app/views/ontologies/sections/metadata/_ontology_fairness_section.html.haml b/app/views/ontologies/sections/metadata/_ontology_fairness_section.html.haml
new file mode 100644
index 000000000..87c9bb5c1
--- /dev/null
+++ b/app/views/ontologies/sections/metadata/_ontology_fairness_section.html.haml
@@ -0,0 +1,15 @@
+- if fairness_service_enabled? && @ontology.acronym != 'AGROVOC' && @fair_scores_data
+ = render SummarySectionComponent.new(title: t("ontologies.sections.metadata.fair_score_title")) do |s|
+ - s.action_link do
+ = render partial: "fair_score/fair_service_header"
+
+ %div.p-2
+ %section.ont-metadata-card.ont-fair-score-card#fair-summary
+ %div.ont-section-toolbar.justify-content-between.flex-row-reverse
+ %div.align-items-start
+ .btn.btn-primary.rounded-pill.right-button
+ .span{ style: 'cursor: default;' }= t("ontologies.sections.metadata.total_score", score: @fair_scores_data[:score], normalized_score: @fair_scores_data[:normalizedScore])
+
+ %div#fair-score-charts-container
+ = render partial: "fairs_score"
+ .account-page-card-sub-container
\ No newline at end of file
diff --git a/app/views/ontologies/sections/metadata/_ontology_metrics_section.html.haml b/app/views/ontologies/sections/metadata/_ontology_metrics_section.html.haml
new file mode 100644
index 000000000..130dbefa5
--- /dev/null
+++ b/app/views/ontologies/sections/metadata/_ontology_metrics_section.html.haml
@@ -0,0 +1,20 @@
+= render SummarySectionComponent.new(title: t("ontologies.sections.metadata.metrics") , link: Rails.configuration.settings.links[:metrics], link_title: t("ontologies.sections.metadata.metrics_link_title"), show_card: false, service_link: "#{@ontology.id}/metrics?display=all") do |s|
+ - s.action_link do
+ = link_to_modal '', ontology_path(@ontology.acronym) + "/metrics",
+ class: "metrics-item", title: t("ontologies.sections.metadata.see_all_metrics", acronym: @ontology.acronym),
+ data: { controller: "tooltip", show_modal_size_value: 'modal-md' , show_modal_title_value: t("ontologies.sections.metadata.show_modal_title_1", acronym: @ontology.acronym)}
+
+ - if @metrics.nil? || (@metrics.is_a?(Array) && @metrics.empty?) || (@metrics.respond_to?(:status) && @metrics.status == 404)
+ = empty_state_message(t("ontologies.sections.metadata.not_calculated_metrics", acronym: @ontology.acronym))
+ - else
+ .metrics-container.metrics
+ - %w[classes individuals properties].each do |metric|
+ = link_to_modal nil, ontology_path(@ontology.acronym) + "/metrics_evolution?metrics_key=#{metric}",
+ class: "metrics-item", data: { show_modal_title_value: t("ontologies.sections.metadata.show_modal_title_2", metric: metric, acronym: @ontology.acronym) } do
+ %hr
+ %div
+ %h4
+ = @metrics.send(metric)
+ %p
+ = render PopupLinkTextComponent.new(text: t("ontologies.sections.#{metric}"))
+
diff --git a/app/views/ontologies/sections/metadata/_ontology_relations_network.html.haml b/app/views/ontologies/sections/metadata/_ontology_relations_network.html.haml
new file mode 100644
index 000000000..13d3f1a64
--- /dev/null
+++ b/app/views/ontologies/sections/metadata/_ontology_relations_network.html.haml
@@ -0,0 +1,14 @@
+- unless @ontology_relations_data.nil? || @ontology_relations_data.empty?
+ = render SummarySectionComponent.new(title: t("ontologies.sections.metadata.relations_network"), link: "", link_title: generate_link_title) do
+ %div.d-flex.flex-column.justify-content-center{data: {controller: "ontology-relations-network", "ontology-relations-network-data-value": @ontology_relations_data.to_json.html_safe }}
+ %button.btn.btn-link.m-2{'data-toggle': "collapse",'data-target': "#ontologyRelations"}
+ %span= t("landscape.filter_network")
+ %i.fas.fa-chevron-down
+ %div#ontologyRelations.collapse.flex-row.flex-wrap.px-2.my-1.fade{'data-action': "change->ontology-relations-network#build"}
+ - values = @relations_array_display
+ = render SelectInputComponent.new(id:'relation-network', name: 'selectedRelations[]', values: values, selected:@relations_array , multiple: true)
+
+ %div{:style => "width: 100%;"}
+ %div#networkContainer{:style => "height: 465px; width: 100%;", "data-ontology-relations-network-target": "container" }
+ %div#ontologyNetwork
+ %button#fullscreen-button
\ No newline at end of file
diff --git a/app/views/ontologies/sections/metadata/_ontology_submissions_section.html.haml b/app/views/ontologies/sections/metadata/_ontology_submissions_section.html.haml
new file mode 100644
index 000000000..d7375b8bb
--- /dev/null
+++ b/app/views/ontologies/sections/metadata/_ontology_submissions_section.html.haml
@@ -0,0 +1,2 @@
+= render SummarySectionComponent.new(title: t("ontologies.sections.metadata.submissions") , link: "", link_title: t("ontologies.sections.metadata.submissions_link_title", site: portal_name), service_link: "#{@ontology.id}/submissions?display=all") do |s|
+ = render TurboFrameComponent.new(id: 'ontology_submissions', src: ontology_submissions_path(@ontology.acronym, invalidate_cache: params[:invalidate_cache]))
\ No newline at end of file
diff --git a/app/views/ontologies/sections/properties.html.haml b/app/views/ontologies/sections/properties.html.haml
index dc3f796fa..99fb1873a 100644
--- a/app/views/ontologies/sections/properties.html.haml
+++ b/app/views/ontologies/sections/properties.html.haml
@@ -1,84 +1,13 @@
-= turbo_frame_tag 'properties' do
- %div.ont-properties{data:{controller: 'container-splitter'}}
- %div#propTree{data:{'container-splitter-target': 'container'}}
- %div#prop_contents.pl-3{data:{'container-splitter-target': 'container'}}
-
- :plain
-
-
- :javascript
- $(document).ready(function(){
- jQuery(document).data().bp.ontPropertiesTab = {};
-
- jQuery(document).data().bp.ontPropertiesTab.init = function() {
- var source = jQuery("#property-details").html();
- var propDetailsTemp = Handlebars.compile(source);
-
- $("#propTree").NCBOPropertyTree({
- ontology: "#{@ontology.acronym}",
- ncboUIURL: jQuery(document).data().bp.config.ui_url,
- width: "100%",
- onInit: function() {
- var ontPropTree = $("#propTree").data().NCBOPropertyTree;
- var data = $("#propTree").find("a:first").data();
- if (data) {
- ontPropTree.selectClass(data.id);
- data.id = decodeURIComponent(data.id);
- jQuery("#prop_contents").html(propDetailsTemp(data));
- }
- }
- }).on("afterSelect", function (e, classId, label, node) {
- var data = node.data();
- data.id = decodeURIComponent(data.id);
- jQuery("#prop_contents").html(propDetailsTemp(data));
- });
- }
-
- jQuery(document).data().bp.ontPropertiesTab.init();
-
- })
+= render TurboFrameComponent.new(id: "properties", data: {"turbo-frame-target": "frame"} ) do
+ - if no_properties?
+ = no_properties_alert
+ - else
+ %div.ont-properties{data: {controller: 'container-splitter turbo-frame', 'turbo-frame-url-value': "/ontologies/#{@ontology.acronym}/properties/show"}}
+ %div.sidebar.position-relative.card{data: {'container-splitter-target': 'container', action: 'change->turbo-frame#updateFrame'}}
+ = tree_container_component(id: 'properties_sorted_list_view-page-1',
+ placeholder: t('ontologies.sections.properties_search_placeholder', acronym: @ontology.acronym),
+ frame_url: "/ontologies/#{@ontology.acronym}/properties",
+ tree_url: "/ontologies/#{@ontology.acronym}/properties?propertyid=#{escape(params[:propertyid])}&ontology=#{@ontology.acronym}&auto_click=false&language=#{request_lang}")
+
+ %div#prop_contents{data: {'container-splitter-target': 'container'}}
+ = render partial: 'properties/show'
diff --git a/app/views/ontologies/sections/visualize.html.haml b/app/views/ontologies/sections/visualize.html.haml
index 14dee3422..121b57daa 100644
--- a/app/views/ontologies/sections/visualize.html.haml
+++ b/app/views/ontologies/sections/visualize.html.haml
@@ -1,31 +1,21 @@
-= turbo_frame_tag 'classes' do
- - unless @error
- - @title = "#{@ontology.name} - #{@concept.prefLabel}"
+= render TurboFrameComponent.new(id: "classes", data: {"turbo-frame-target": "frame"} ) do
+ - unless @error || @concept.nil?
+ - @title = "#{@ontology.acronym} - #{@concept.prefLabel}"
- @new_term_request_ontologies
- @enable_ontolobridge = !$NEW_TERM_REQUEST_ONTOLOGIES.nil? && $NEW_TERM_REQUEST_ONTOLOGIES.include?(@ontology.acronym)
%div.tooltip
%div#bd_content.bd_content.explore{data:{controller: 'container-splitter'}}
- %div.sidebar.d-flex.flex-column.mr-2.card{data:{'container-splitter-target': 'container'}}
+ %div.sidebar{data:{'container-splitter-target': 'container'}}
= render partial: 'ontologies/concepts_browsers/concepts_browser'
- %div#concept_content.d-flex.flex-column.card.p-1.ml-2{data:{'container-splitter-target': 'container'}}
+ %div#concept_content.d-flex.flex-column{data:{'container-splitter-target': 'container'}}
= render partial: 'concepts/show'
- form_for(:search, :url => {:controller =>'search',:action=>'fetch_results'},:html=>{:id=>'search_form'}) do |f|
%input{:name => "search[ontologies][]", :type => "hidden", :value => @ontology.acronym}/
= hidden_field :search, :search_type, :value=>"contains"
= hidden_field :search, :keyword, :value=>"",:id=>"search_keyword"
- - else # found an error
- = "
#{@error} "
-
- :javascript
- $(document).ready(function() {
- const ontology_acronym = "#{@ontology.acronym}"
- let data = #{raw @instance_details.to_json} || null
-
- if(data && Object.keys(data).length !== 0){
- $.facebox({ajax: `/ontologies/${ontology_acronym}/instances/${encodeURIComponent(data["@id"])}`})
- }
- })
-
+ - else
+ = render Display::AlertComponent.new(type: 'danger') do
+ = @concept.nil? ? t("ontologies.sections.no_class_concept_found") : @error
diff --git a/app/views/ontologies/submit_success.html.haml b/app/views/ontologies/submit_success.html.haml
index b77274868..5836a272f 100644
--- a/app/views/ontologies/submit_success.html.haml
+++ b/app/views/ontologies/submit_success.html.haml
@@ -1,24 +1,22 @@
%div.p-4
- %h2.pb-3 Ontology submitted successfully!
+ %h2.pb-3= t("ontologies.ontology_submitted")
-if @ontology.summaryOnly
- %p Thank you for submitting your metadata-only ontology to #{$SITE}.
+ %p= t("ontologies.ontology_submitted", site: "#{$SITE}")
%p
- Users can now see
- = link_to "your ontology", ontology_path(@ontology.acronym)
- in our ontology list but they cannot explore or search it. To enable exploring and searching,
- please upload a full version of your ontology.
+ = t("ontologies.users_can_see")
+ = link_to t("ontologies.your_ontology"), ontology_path(@ontology.acronym)
+ = t("ontologies.exploring_and_searching")
-else
-if @ontology.viewOf
- %p Thank you for submitting your ontology view to #{$SITE}.
+ %p= t("ontologies.submitting_ontology_view", site: "#{$SITE}")
-else
- %p Thank you for submitting your ontology to #{$SITE}.
+ %p= t("ontologies.submitting_ontology", site: "#{$SITE}")
%p
- We will now put your ontology in the queue to be processed. Please keep in mind that it may take up to several
- hours before #{$SITE} users will be able to explore and search your ontology.
+ = t("ontologies.processing_message", site: "#{$SITE}")
%p
- When your ontology is ready for viewing, it will be available here:
+ = t("ontologies.notification_message")
= link_to ontology_url(@ontology.acronym), ontology_path(@ontology.acronym)
%p
- If you have any questions or problems, please email the #{$SITE} support team at:
+ = t("ontologies.contact_support_at", site: "#{$SITE}")
= mail_to "#{$SUPPORT_EMAIL}", "#{$SUPPORT_EMAIL}"
diff --git a/app/views/ontologies_metadata_curator/_attribute.html.haml b/app/views/ontologies_metadata_curator/_attribute.html.haml
new file mode 100644
index 000000000..135be1b01
--- /dev/null
+++ b/app/views/ontologies_metadata_curator/_attribute.html.haml
@@ -0,0 +1,36 @@
+- acronym = ontology ? ontology.acronym : submission.id.split('/')[-3]
+= render TurboFrameComponent.new(id: id) do
+ %div.d-flex.justify-content-between.align-items-center
+ %div.d-flex.justify-content-between
+ %div
+ - equivalents = equivalent_properties(attribute)
+ - equivalents.each do |attr|
+ %div.d-flex
+ - if equivalents.size > 1
+ %span= "#{attr}: "
+ %div
+ %div
+ = error_message_alert
+ %div
+ - if attribute == "contact"
+ = raw submission.contact.map {|c| [c["name"], c["email"]].join(", ") if c.member?(:name) && c.member?(:email)}.join(" ")
+ - elsif attribute == "naturalLanguage"
+ - submission.send(attribute).each do |lang|
+ = render LanguageFieldComponent.new(value: lang)
+ - elsif attribute == "ontology"
+ = acronym
+ - else
+ - values = submission.instance_values[attribute.to_s]
+ - if values.is_a?(String) && %w[http https].include?(values[0..3])
+ = render LinkFieldComponent.new(value: values, raw: true, check_resolvability: true)
+ - else
+ - Array(values).each do |value|
+ - if value.is_a?(LinkedData::Client::Models::Agent)
+ %div
+ = display_agent(value, link: false)
+ - else
+ %p
+ = value
+ %div
+ = edit_submission_property_link(acronym, submission.submissionId, attribute) do
+ %i.far.fa-edit
\ No newline at end of file
diff --git a/app/views/ontologies_metadata_curator/_attribute_inline.html.haml b/app/views/ontologies_metadata_curator/_attribute_inline.html.haml
deleted file mode 100644
index 58d6c0244..000000000
--- a/app/views/ontologies_metadata_curator/_attribute_inline.html.haml
+++ /dev/null
@@ -1,33 +0,0 @@
-%div
- - if @errors
- %div
- = render AlertMessageComponent.new(id:acronym+'-'+attribute+'-error', type: 'danger') do
- = @errors.map{|e| e[:error]}.join(',')
-%div
- - if attribute == "contact"
- = raw submission.contact.map {|c| [c["name"], c["email"]].join(", ") if c.member?(:name) && c.member?(:email)}.join(" ")
- - elsif attribute == "naturalLanguage"
- - lang_codes = []
- - submission.send(attribute).each do |lang|
- - if (lang.to_s.eql?("en") || lang.to_s.eql?("eng") || lang.to_s.eql?("http://lexvo.org/id/iso639-3/eng"))
- - lang_codes << "gb"
- - elsif lang.to_s.start_with?("http://lexvo.org")
- - lang_codes << $LEXVO_TO_FLAG[lang]
- - else
- - lang_codes << lang
- %ul{:class => "f32"}
- - lang_codes.each do |lang_code|
- %li{:class => "flag " + lang_code, :style => "margin-right: 0.5em;"}
- - elsif attribute == "ontology"
- = acronym
- - else
- - if submission.instance_values[attribute.to_s].is_a?(String) && %w[http https].include?(submission.instance_values[attribute.to_s][0..3])
- %a{:href=> ""+ submission.instance_values[attribute.to_s] +""}= submission.instance_values[attribute.to_s]
- - else
- - Array(submission.instance_values[attribute.to_s]).each do |value|
- - if value.is_a?(LinkedData::Client::Models::Agent)
- %div
- = display_agent(value, link: false)
- - else
- %p
- = value
\ No newline at end of file
diff --git a/app/views/ontologies_metadata_curator/_attribute_inline_editable.html.haml b/app/views/ontologies_metadata_curator/_attribute_inline_editable.html.haml
index b2fdeedcb..dedff5c0c 100644
--- a/app/views/ontologies_metadata_curator/_attribute_inline_editable.html.haml
+++ b/app/views/ontologies_metadata_curator/_attribute_inline_editable.html.haml
@@ -1,4 +1,4 @@
-- acronym = ontology.acronym
+- acronym = ontology ? ontology.acronym : submission.id.split('/')[-3]
- submission_id = submission.submissionId
- id = attribute_input_frame_id(acronym, submission_id, attribute)
= render TurboFrameComponent.new(id: id+'_form') do
@@ -6,19 +6,5 @@
= hidden_field object_name(acronym, submission_id), :ontology, value: acronym
= hidden_field object_name(acronym, submission_id), :id, value: submission_id
= hidden_field_tag :attribute, attribute
- = render TurboFrameComponent.new(id: id) do
- %div.d-flex.justify-content-between.align-items-center
- %div.d-flex.justify-content-between
- %div
- - equivalents = equivalent_properties(attribute)
- - equivalents.each do |attr|
- %div.d-flex
- - if equivalents.size > 1
- %span= "#{attr}: "
- %div
- = render_submission_attribute_inline(attr.to_s, submission, acronym)
-
-
- %div
- %a.btn.btn-sm.btn-light{href: "ontologies_metadata_curator/#{ontology.acronym}/submissions/#{submission_id}?properties=#{attribute}&inline_save=true", data: {turbo: true}}
- %i.far.fa-edit
+ = render partial: "ontologies_metadata_curator/attribute", locals: { id: id, attribute: attribute,
+ submission: submission , ontology: ontology}
diff --git a/app/views/ontologies_metadata_curator/_form_edit.html.haml b/app/views/ontologies_metadata_curator/_form_edit.html.haml
index 24ed94da2..1f9228f06 100644
--- a/app/views/ontologies_metadata_curator/_form_edit.html.haml
+++ b/app/views/ontologies_metadata_curator/_form_edit.html.haml
@@ -1,4 +1,4 @@
-= turbo_frame_tag 'application_modal_content' do
+= render_in_modal do
:javascript
function saveSelectedTab(value){
const input = document.getElementById("active_ontology")
@@ -23,9 +23,9 @@
%a.nav-link{id: "pills-"+onto+sub_i+"-tab", "data-toggle": "pill", href: "#pills-"+onto+sub_i, class: index.zero? ? 'active' : ''}
= ontology_submission_id_label(onto, sub_i)
%div#change_all_warning_container
- = render AlertMessageComponent.new(id:'change_all_warning', type: 'warning') do
- %strong Apply the change for all
- will update the current displayed content to all the following submssions:
+ = render Display::AlertComponent.new(type: 'warning') do
+ %strong= t("ontologies_metadata_curator.apply_the_change_for_all")
+ = t("ontologies_metadata_curator.update_the_current_displayed_content")
- @selected_ontologies.map{|x| ontology_submission_id_label(*x)}.each do |onto|
%span.badge.badge-primary
= onto
@@ -36,4 +36,4 @@
.tab-pane{id: "pills-"+ onto+sub_i, class: index.zero? ? 'active' : ''}
= render TurboFrameComponent.new(id: 'metadata_by_ontology', src: "ontologies_metadata_curator/#{onto}/submissions/#{sub_i}"+"?properties=#{@selected_metadata.join(',')}&form_id=metadata_by_ontology", loading:"lazy")
- = submit_tag "Save", class: "btn btn-primary btn-block"
+ = submit_tag t("ontologies_metadata_curator.save"), class: "btn btn-primary btn-block"
diff --git a/app/views/ontologies_metadata_curator/_metadata_tab.html.haml b/app/views/ontologies_metadata_curator/_metadata_tab.html.haml
index 7e52d3ff8..2a7a15b59 100644
--- a/app/views/ontologies_metadata_curator/_metadata_tab.html.haml
+++ b/app/views/ontologies_metadata_curator/_metadata_tab.html.haml
@@ -1,23 +1,22 @@
-%div.mt-5.d-flex
- %div.mx-auto.w-75
+%div
+ %div
= form_tag("/ontologies_metadata_curator/result", method: "post", data: { turbo: true, turbo_frame: 'selection_metadata_form'}) do
%div
%div.mx-1.pt-3
- = render FormGroupComponent.new(label:' Ontologies', inline: false) do
- = render :partial => "shared/ontology_picker", locals: {sel_text: '', selected_ontologies: @ontologies_ids}
+ = ontologies_selector(id:'metadata_curator_ontologies_selector', label: t("ontologies_metadata_curator.ontologies") ,name: 'ontology[ontologyId][]', selected: @ontologies_ids)
%div.d-flex.align-items-center.mb-5
%div.mx-1{style: 'width: 65%'}
- = render MetadataSelectorComponent.new(label: 'Metadata Properties', values: submission_editable_properties , selected: @metadata_sel)
+ = submission_metadata_selector
%div.mx-1.mt-3{style: 'width: 15%'}
- = render SwitchInputComponent.new(id:"show_submissions", name: "show_submissions", label: "Include all submissions")
+ = render SwitchInputComponent.new(id:"show_submissions", name: "show_submissions", label: t("ontologies_metadata_curator.include_all_submissions"))
%div.mt-3.flex-shrink-0
- %button{type: "submit", class: "btn btn-primary"}
- Get values
+ = save_button_component(type: 'submit', id: 'curator-save-btn', value: t("ontologies_metadata_curator.get_values"), size: 'slim')
%div.mt-3.flex-shrink-0.flex-fill.d-flex.align-items-center
+ .mx-2
+ = rounded_button_component("#{$REST_URL}/submissions?display=all&apikey=#{get_apikey}")
= turbo_frame_tag "edit_metadata_btn"
= render TurboFrameComponent.new(id: 'selection_metadata_form') do
%div.alert.alert-light.text-center
- select ontologies and the metadata properties
-
+ = t("ontologies_metadata_curator.select_ontologies_and_metadata")
diff --git a/app/views/ontologies_metadata_curator/_metadata_table.html.haml b/app/views/ontologies_metadata_curator/_metadata_table.html.haml
index 73850816d..a9fe6d167 100644
--- a/app/views/ontologies_metadata_curator/_metadata_table.html.haml
+++ b/app/views/ontologies_metadata_curator/_metadata_table.html.haml
@@ -9,17 +9,12 @@
= hidden_field_tag :all_metadata, @metadata_sel
= submit_to_modal("Edit metadata values" , id:"show_bulk_edit_from_btn", class: "d-none",
data: { show_modal_title_value: "Metadata curator editor", show_modal_size_value: 'modal-xl' })
- %div.table-container.mx-3
- %table.zebra
- %thead
- %tr
- %th Ontologies
- - @metadata_sel.each do |meta|
- %th
- %div
- = render SwitchInputComponent.new(id: meta, name: 'selected_metadata[]', value: meta) do
- %h6{style:'margin-top: 0.2rem'}=generate_attribute_label(meta, label_tag_sym: :span)
+ = render TableComponent.new(id: 'metadata-curator-table', custom_class: 'border rounded p-1') do |t|
+ - t.header do |h|
+ - h.th {'Ontologies'}
+ - @metadata_sel.each do |meta|
+ - h.th do
+ %div
+ %h6{style:'margin-top: 0.2rem'}=attr_label(meta, attr_metadata: attr_metadata(meta))
- %tbody
- - @submissions.each do |submission|
- = render partial: 'metadata_table_row', locals: {submission: submission, attributes: @metadata_sel}
+ = render partial: 'submission', collection: @submissions, locals: {attributes: @metadata_sel}
diff --git a/app/views/ontologies_metadata_curator/_metadata_table_row.html.haml b/app/views/ontologies_metadata_curator/_submission.html.haml
similarity index 56%
rename from app/views/ontologies_metadata_curator/_metadata_table_row.html.haml
rename to app/views/ontologies_metadata_curator/_submission.html.haml
index dd687bfba..07dddee34 100644
--- a/app/views/ontologies_metadata_curator/_metadata_table_row.html.haml
+++ b/app/views/ontologies_metadata_curator/_submission.html.haml
@@ -1,10 +1,9 @@
-- acronym = submission.ontology.acronym
+- acronym = submission.id.split('/')[-3]
- id = ontology_submission_id_label(acronym, submission.submissionId)
%tr{id: id+'_row'}
%th{scope:"row", style: 'width: 5%'}
%div
- = render SwitchInputComponent.new(id: submission.id, name: 'selected_acronyms[]', value: id) do
- %h6{style:'margin-top: 0.2rem'}=id
+ %h6{style:'margin-top: 0.2rem'}=id
- attributes.each do |meta|
%td{style: "width: #{95 / attributes.size}%; vertical-align: top; word-break: break-word;"}
- = render partial: 'attribute_inline_editable', locals: {attribute: meta, submission: submission, ontology: submission.ontology}
\ No newline at end of file
+ = render partial: 'attribute_inline_editable', locals: {attribute: meta, submission: submission, ontology: nil}
\ No newline at end of file
diff --git a/app/views/projects/_form.html.haml b/app/views/projects/_form.html.haml
index 59af9a2e8..cd3eea423 100644
--- a/app/views/projects/_form.html.haml
+++ b/app/views/projects/_form.html.haml
@@ -1,11 +1,6 @@
-:javascript
- jQuery(document).ready(function(){
- jQuery("#project_creator").chosen();
- });
-
- unless @errors.nil?
.enable-lists{style: "color:red; padding-left:10px;"}
- %strong Errors On Form
+ %strong= t('projects.form.errors_on_form')
%ul
- @errors = @errors[:error ] if @errors[:error]
%ul
@@ -28,33 +23,35 @@
%div{:style => "padding:10px"}
%table.form
%tr
- %th Name: *
+ %th= t('projects.form.name')
%td.top= text_field :project, :name, value: @project.name, :class => "required", :tabindex => 1
%tr
- disabled = @project.id ? "disabled" : nil
- %th Acronym: *
+ %th= t('projects.form.acronym')
%td.top= text_field :project, :acronym, value: @project.acronym, :class => "required", :tabindex => 1, disabled: disabled
%tr
- %th Institution:
+ %th= t('projects.show.institution')
%td= text_field :project, :institution, value: @project.institution, :tabindex => 2
%tr
- %th Contacts:
+ %th= t('projects.show.contacts')
%td= text_field :project, :contacts, value: @project.contacts, :tabindex => 3
%tr
- %th Administrators: *
- %td= f.select :creator, @user_select_list, { selected: @project.creator || session[:user].id }, { multiple: true, :"data-placeholder" => "Select administrators", tabindex: 4 }
+ %th= t('projects.form.administrators')
+ %td= select_input(name: "project[creator][]", values: @user_select_list, selected: @project.creator || session[:user].id, multiple: true,placeholder: t('projects.form.select_administrators'))
+
%tr
%th
- Homepage: *
+ = t('projects.form.home_page')
%br/
%span.default_owl
- Example:
+ = t('projects.form.example')
%a{:href => "http://en.wikipedia.org/wiki/SNOMED_CT", :target => "_blank"} http://en.wikipedia.org/wiki/SNOMED_CT
%td= text_field :project, :homePage, value: @project.homePage, :class => "required url", :tabindex => 5
%tr
- %th Description:*
+ %th= t('projects.form.description')
%td= text_area :project, :description, value: @project.description, :rows=>6, :class=>"required", :tabindex => 6
%div#ontology_picker_project{style: "padding-top: 2em;"}
- selected_ontologies = @project.ontologyUsed && @project.ontologyUsed.map {|id| id.split('/').last } || []
- - locals = { sel_text: "Select Ontologies Used", selected_ontologies: selected_ontologies, form_object: :project, form_attribute: "ontologyUsed" }
- = render :partial => "shared/ontology_picker", locals: locals
+ - locals = { sel_text: t('projects.form.select_ontologies'), selected_ontologies: selected_ontologies, form_object: :project, form_attribute: "ontologyUsed" }
+ = ontologies_selector(id:'projects_page_ontologies_selector' ,name: 'ontologies')
+
diff --git a/app/views/projects/edit.html.haml b/app/views/projects/edit.html.haml
index b4112b506..602aba68f 100644
--- a/app/views/projects/edit.html.haml
+++ b/app/views/projects/edit.html.haml
@@ -1,11 +1,13 @@
-- @title = "Editing Project #{@project.name}"
-%h1{:style => "padding: 10px;"}
- Editing project
-%p{:style => "padding-left: 10px;"}
- / TODO_REV: Enable project delete
- / = link_to("Delete Project", @project, :confirm => "Are you sure?", :method => :delete)
-= form_for(:project, url: project_path(@project.acronym), html: {method: :put}) do |f|
- = render partial: 'form', locals: { f: f }
+- @title = t('projects.edit.title', name: @project.name)
+%div.container
+
+ %h1{:style => "padding: 10px;"}
+ = t('projects.edit.editing_project')
%p{:style => "padding-left: 10px;"}
- = submit_tag "Cancel"
- = f.submit "Update Project", :class => "blueButton"
+ / TODO_REV: Enable project delete
+ / = link_to("Delete Project", @project, :confirm => "Are you sure?", :method => :delete)
+ = form_for(:project, url: project_path(@project.acronym), html: {method: :put}) do |f|
+ = render partial: 'form', locals: { f: f }
+ %p{:style => "padding-left: 10px;"}
+ = submit_tag t('projects.edit.cancel')
+ = f.submit t('projects.edit.update_project'), :class => "blueButton"
diff --git a/app/views/projects/index.html.haml b/app/views/projects/index.html.haml
index 6fbf37407..9193d98ca 100644
--- a/app/views/projects/index.html.haml
+++ b/app/views/projects/index.html.haml
@@ -1,76 +1,78 @@
-- @title = "Project Listing"
+- @title = t("projects.title")
+%div.container
+ #DescriptionDialog{:style => "display: none", :title => t("projects.project_description")}
+ %p= t("projects.description_text")
+ %h1.tab_header= t("projects.self")
+ %p.tab_description
+ = t("projects.index.intro", site: "#{$SITE}")
+ = link_to(help_path(anchor: "Projects_Tab"), id: "projects-help", aria: {label: t("projects.view_projects_help")}) do
+ %i.fas.fa-question-circle.fa-lg{aria: {hidden: "true"}, style: "margin-left: .25em"}
-#DescriptionDialog{:style => "display: none", :title => "project description"}
- %p Description text
-%h1.tab_header Projects
-%p.tab_description
- = t(".intro", site: "#{$SITE}")
-
-%div{:style => "padding:10px;"}
- %span
- - if session[:user].nil?
- = button_to "Create New Project", "/login", :method => :get, class: 'btn btn-primary'
- - else
- = button_to "Create New Project", new_project_path, :method => :get, class: 'btn btn-primary'
- %br/
- %br/
- %table#projects.zebra{:cellpadding => "0", :cellspacing => "0"}
- %thead
- %tr
- %th Project
- %th Description
- %th Contacts
- %th Institutions
- %th Ontologies
- - if current_user_admin?
- %th User
- %th Created
- %tbody
- - for project in @projects
+ %div{:style => "padding:10px;"}
+ %span
+ - if session[:user].nil?
+ = button_to t("projects.create_new_project"), "/login", :method => :get
+ - else
+ = button_to t("projects.create_new_project"), new_project_path, :method => :get
+ %br/
+ %br/
+ %table#projects.zebra{:cellpadding => "0", :cellspacing => "0"}
+ %thead
%tr
- / Project name, home page, and controls for editors
- %td{:style => "vertical-align:top;", :width => "30%"}
- %strong= link_to(project.name, project_path(project.acronym))
- %br/
- %span{:style => "font-size:75%; vertical-align:bottom;"}
- = link_to("Home Page", project.homePage, target: "_blank", rel: "nofollow")
- %span.ui-icon.ui-icon-extlink{:style => "display: inline-block; vertical-align: text-bottom;"}
- \
- - if session[:user] && (project.creator == session[:user].id || session[:user].admin?)
- = link_to("Edit", edit_project_path(project.acronym))
- / TODO_REV: Enable delete project for admins
- - if current_user_admin?
-
- = link_to("Delete (admin only)", project_path(project.acronym), :method => :delete, :confirm => "Are you sure?")
- / Project description (may be truncated with a dialog)
- %td{:style => "vertical-align:top;", :width => "50%"}
- - if ! project.description.nil?
- - descLength = 250
- - if project.description.length < descLength
- = project.description
- - else
- - descShort = smart_truncate(project.description, :words => 20)
- %span{:style => "cursor:help;", :title => project.description}
- = descShort
- / Contacts
- %td{:style => "vertical-align:top;", :width => "10%"}
- = raw project.contacts
- / Institutions
- %td{:style => "vertical-align:top;", :width => "8%"}
- = raw project.institution
- / Ontologies
- %td{:style => "vertical-align:top;", :width => "2%"}
- - ontologyCount = 0
- - ontologyLabels = ""
- - for ontology in project.ontologyUsed
- - ontologyLabels += @ontologies_hash[ontology].name + "\n" rescue next
- - ontologyCount += 1
- - if ontologyCount > 0
- %span{:style => "cursor:help;text-decoration: none; border-bottom:1px dotted;", :title => ontologyLabels}= ontologyCount
- - else
- = ontologyCount
+ %th= t("projects.self")
+ %th= t("projects.description")
+ %th= t("projects.contacts")
+ %th= t("projects.institutions")
+ %th= t("projects.ontologies")
- if current_user_admin?
- %td
- = project.creator.map {|c| c.split("/").last}.join(", ")
- %td
- = project.created
+ %th= t("projects.creator")
+ %th= t("projects.created")
+ %tbody
+ - for project in @projects
+ %tr
+ / Project name, home page, and controls for editors
+ %td{:style => "vertical-align:top;"}
+ %strong= link_to(project.name, project_path(project.acronym))
+ %br/
+ %span{:style => "font-size:75%; vertical-align:bottom;"}
+ = link_to(t('projects.home_page'), project.homePage, target: "_blank", rel: "nofollow")
+ %span.ui-icon.ui-icon-extlink{:style => "display: inline-block; vertical-align: text-bottom;"}
+ \
+ - if session[:user] && (project.creator == session[:user].id || session[:user].admin?)
+ = link_to(t("projects.edit_text"), edit_project_path(project.acronym))
+ / TODO_REV: Enable delete project for admins
+ - if current_user_admin?
+
+ = link_to(t("projects.delete_admin_only"), project_path(project.acronym), :method => :delete, :confirm => t("projects.delete_confirm"))
+ / Project description (may be truncated with a dialog)
+ %td{:style => "vertical-align:top;"}
+ - if ! project.description.nil?
+ - descLength = 250
+ - if project.description.length < descLength
+ = project.description
+ - else
+ - descShort = smart_truncate(project.description, :words => 20)
+ %span{:style => "cursor:help;", :title => project.description}
+ = descShort
+ / Contacts
+ %td{:style => "vertical-align:top;"}
+ = raw project.contacts
+ / Institutions
+ %td{:style => "vertical-align:top;"}
+ = raw project.institution
+ / Ontologies
+ %td{:style => "vertical-align:top;"}
+ - ontologyCount = 0
+ - ontologyLabels = ""
+ - for ontology in project.ontologyUsed
+ - ontologyLabels += @ontologies_hash[ontology].name + "\n" rescue next
+ - ontologyCount += 1
+ - if ontologyCount > 0
+ %span{:style => "cursor:help;text-decoration: none; border-bottom:1px dotted;", :title => ontologyLabels}= ontologyCount
+ - else
+ = ontologyCount
+ - if current_user_admin?
+ %td
+ = project.creator.map {|c| c.split("/").last}.join(", ")
+ %td
+ = project.created
diff --git a/app/views/projects/new.html.haml b/app/views/projects/new.html.haml
index a4a23121a..34e59a292 100644
--- a/app/views/projects/new.html.haml
+++ b/app/views/projects/new.html.haml
@@ -1,8 +1,8 @@
-- @title = "Add your project"
+- @title = t('projects.new.title')
%h1{:style => "padding: 10px;"}
- New project
+ = t('projects.new.new_project')
= form_for :project, url: {action: "create"}, html: {id: 'form'} do |f|
= render partial: 'form', locals: { f: f }
%p{:style => "padding: 10px;"}
- = submit_tag "Cancel"
- = f.submit "Create Project", class: "blueButton"
+ = submit_tag t('projects.edit.cancel')
+ = f.submit t('projects.new.create_project'), class: "blueButton"
diff --git a/app/views/projects/show.html.haml b/app/views/projects/show.html.haml
index 7cfacc454..b5df4a2fd 100644
--- a/app/views/projects/show.html.haml
+++ b/app/views/projects/show.html.haml
@@ -1,28 +1,30 @@
-- @title = "Project #{@project.name}"
-%div{:style => "padding: 1em;"}
- %h1{:style => "font-size: xx-large;"}= @project.name
- - if session[:user] && (@project.creator.include?(session[:user].id) || session[:user].admin?)
- = link_to "Edit Project", edit_project_path(@project.acronym)
- %br/
- %br/
- %p{:style => "margin-bottom: 5px;"}
- %strong Description:
- = @project.description
- %p{:style => "margin-bottom: 5px;"}
- %strong Institution:
- = @project.institution
- %p{:style => "margin-bottom: 5px;"}
- %strong Contacts:
- = @project.contacts
- %p
- %strong Home Page:
- - if @project.homePage
- = link_to @project.homePage, @project.homePage, rel: "nofollow"
- %h2{:style => "padding-top: 1em;"} Used Ontologies
- - if @ontologies_used.empty?
- No ontologies are currently associated with this project
- - else
- %div.ml-5
+- @title = t('projects.show.title', name: @project.name)
+
+%div.container
+
+ %div{:style => "padding: 1em;"}
+ %h1{:style => "font-size: xx-large;"}= @project.name
+ - if session[:user] && (@project.creator.include?(session[:user].id) || session[:user].admin?)
+ = link_to t('projects.show.edit_project'), edit_project_path(@project.acronym)
+ %br/
+ %br/
+ %p{:style => "margin-bottom: 5px;"}
+ %strong= t('projects.show.description')
+ = @project.description
+ %p{:style => "margin-bottom: 5px;"}
+ %strong= t('projects.show.institution')
+ = @project.institution
+ %p{:style => "margin-bottom: 5px;"}
+ %strong= t('projects.show.contacts')
+ = @project.contacts
+ %p
+ %strong= t('projects.show.home_page')
+ - if @project.homePage
+ = link_to @project.homePage, @project.homePage, rel: "nofollow"
+ %h2{:style => "padding-top: 1em;"}= t('projects.show.ontologies_used')
+ - if @ontologies_used.empty?
+ = t('projects.show.no_ontologies_associated')
+ %table.zebra{:cellpadding => "0", :cellspacing => "0", :width => "70%"}
%ul
- for ontology in @ontologies_used
%li= link_to(ontology["name"], ontology_path(ontology["acronym"]))
\ No newline at end of file
diff --git a/app/views/properties/_show.html.haml b/app/views/properties/_show.html.haml
new file mode 100644
index 000000000..c03430149
--- /dev/null
+++ b/app/views/properties/_show.html.haml
@@ -0,0 +1,16 @@
+= render TurboFrameComponent.new(id: 'property_show', data: {"turbo-frame-target": "frame"}) do
+ - if @property
+ - if @property.errors
+ = render Display::AlertComponent.new(type:'info', message: @property.errors.join)
+ - else
+ = render ConceptDetailsComponent.new(id:'property-details', acronym: @acronym, concept_id: @property.id,
+ properties: OpenStruct.new(LinkedData::Client::Models::Property.properties_to_hash(@property).first),
+ top_keys: [],
+ bottom_keys: [],
+ exclude_keys: []) do |c|
+ - c.header(stripped: true) do |t|
+ - t.add_row({th: t('properties.id')}, {td: link_to_with_actions(c.concept_properties[:id][:values], acronym: @acronym)}) if c.concept_properties[:id][:values].present?
+ - t.add_row({th: t('properties.type')}, {td: c.concept_properties[:type][:values] }) if c.concept_properties[:id][:values].present?
+ - t.add_row({th: t('properties.preferred_name')}, {td: display_in_multiple_languages(c.concept_properties[:label][:values])}) if c.concept_properties[:label][:values].present?
+ - t.add_row({th: t('properties.definitions')}, {td: display_in_multiple_languages(c.concept_properties[:definition][:values])}) if c.concept_properties[:definition][:values].present?
+ - t.add_row({th: t('properties.parent')}, {td: display_in_multiple_languages(c.concept_properties[:parents][:values])}) if c.concept_properties[:parents][:values].present?
\ No newline at end of file
diff --git a/app/views/recommender/index.html.haml b/app/views/recommender/index.html.haml
index f71096bd8..10a5c8333 100644
--- a/app/views/recommender/index.html.haml
+++ b/app/views/recommender/index.html.haml
@@ -1,107 +1,126 @@
-- @title = "Recommender"
+- @title = t('recommender.title')
+.recommender-page-container{'data-controller': 'recommender'}
+ .recommender-page-subcontainer
+ .recommender-page-title
+ .text
+ = t('recommender.title')
+ .line
+ .recommender-page-decription
+ = t('recommender.intro')
-%h1.mt-5 Semantic Resource Recommender
-%p
- = t('recommender.intro').html_safe
- = link_to(Rails.configuration.settings.links[:help_recommender], target: '_blank') do
- %i.fas.fa-question-circle.fa-lg
+ = form_tag('/recommender', method: :get, 'data-turbo': true, novalidate: true, 'data-action': 'submit->form-url#submit', 'data-controller': 'form-url') do
+ .recommender-page-inputs{'data-controller': 'reveal-component'}
+ .inputs
+ %div
+ - is_input = @results.nil? || @results.empty?
+ .recommender-page-text-area{class: is_input ? "" : "d-none", 'data-recommender-target': 'input', 'data-controller': 'sample-text'}
+ %textarea#recommender-text-area{rows: "4" , placeholder: t('recommender.hint'), name: "input", 'data-action': "input->recommender#handleInput", maxlength: "9678", 'data-sample-text-target': "input"}
+ = params[:input]
+ = insert_sample_text_button(t('annotator.insert_sample_text'))
-%form
- = hidden_field_tag :recommender_sample_text, t('recommender.sample_text')
- = hidden_field_tag :recommender_sample_keywords, t('recommender.sample_keywords')
- -# Specify input format
- %h5 Input
- %div.form-check.form-check-inline
- %input#radioItText.form-check-input{name: "input_type", type: "radio", value: "1", checked: "checked"}
- %label.form-check-label{for: "radioItText"} Text
- %div.form-check.form-check-inline
- %input#radioItKeywords.form-check-input{name: "input_type", type: "radio", value: "2"}
- %label.form-check-label{for: "radioItKeywords"} Keywords (separated by commas)
-
- -# Specify output format
- %h5.pt-3 Output
- %div.form-check.form-check-inline
- %input#radioOtSingle.form-check-input{name: "output_type", type: "radio", value: "1", checked: "checked"}
- %label.form-check-label{for: "radioOtSingle"} Semantic Resources
- %div.form-check.form-check-inline
- %input#radioOtSets.form-check-input{name: "output_type", type: "radio", value: "2"}
- %label.form-check-label{for: "radioOtSets"} Semantic Resources sets
-
- -# Input text or keywords
- %div.form-group.mt-4
- = text_area_tag("inputText", nil, rows: 10, class: "form-control default", placeholder: "Paste a paragraph of text or some keywords to use in calculating semantic resources recommendations", aria: {describedby: "inputTextHelpBlock"})
- %div.card#inputTextHighlighted
- %div.card-body
- %small#inputTextHelpBlock.form-text
- %a#insertInputLink{href: "javascript:void(0);"} insert sample input
+ .recommender-page-text-area-results{class: is_input ? "d-none" : "", 'data-recommender-target': 'result'}
+ .text
+ = params[:input]
+ .recommender-page-options
+ .section-text
+ = t('recommender.options')
+ .input
+ .title
+ = t('recommender.input')
+ .radios
+ - check_input = !params[:input_type].eql?('2')
+ .text-choice
+ = render Input::RadioChipComponent.new(label: t('recommender.text'), name: 'input_type', value: '1', checked: check_input)
+ .keywords-choice{'data-controller':' tooltip', title: 'Keywords separated by commas'}
+ = render Input::RadioChipComponent.new(label: t('recommender.keywords'), name: 'input_type', value: '2', checked: !check_input)
+ .output
+ .title
+ = t('recommender.output')
+ .radios{'data-action': 'change->recommender#togglesets'}
+ - check_output = !params[:output_type].eql?('2')
+ .ontologies-choice{'data-recommender-target': 'ontologieschoice'}
+ = render Input::RadioChipComponent.new(label: t('recommender.ontologies'), name: 'output_type', value: '1', checked: check_output)
+ .ontology-sets-choice
+ = render Input::RadioChipComponent.new(label: t('recommender.ontology_sets'), name: 'output_type', value: '2', checked: !check_output)
- %a#advancedOptionsLink{:href => "javascript:void(0);"} Show advanced options >>
+ = show_advanced_options_button(text: t('show_advanced_options'), init: @advanced_options_open || @not_valid_max_num_set)
+ = hide_advanced_options_button(text: t('hide_advanced_options'), init: @advanced_options_open || @not_valid_max_num_set)
+
+ .recommender-advanced-options{'data-reveal-component-target': 'item', class: "#{@advanced_options_open || @not_valid_max_num_set ? '' : 'd-none'}"}
+ .weights-configuration
+ .title
+ = t('recommender.weights_configuration')
+ .inputs-container
+ -#binding.pry
+ .ninput
+ = render Input::RangeSliderComponent.new(label: t('recommender.coverage'), name: "wc", value: params[:wc] || 0.55, min: '0', max: '1', step: '0.01')
+ .ninput
+ = render Input::RangeSliderComponent.new(label: t('recommender.acceptance'), name: "wa", value: params[:wa] || 0.15, min: '0', max: '1', step: '0.01')
+ .ninput
+ = render Input::RangeSliderComponent.new(label: t('recommender.knowledge_detail'), name: "wd", value: params[:wd] || 0.15, min: '0', max: '1', step: '0.01')
+ .ninput
+ = render Input::RangeSliderComponent.new(label: t('recommender.specialization'), name: "ws", value: params[:ws] || 0.15, min: '0', max: '1', step: '0.01')
+ .ontologies-configuration
+ .title
+ = t('recommender.ontologies_configuration')
+ .inputs-container
+ .ontologies.input
+ = ontologies_selector(id:'recommender_page_ontologies', label: t('recommender.select_ontologies') ,name: 'ontologies[]', selected: params[:ontologies]&.split(','))
+ .maxsets.input.d-none{'data-recommender-target': 'maxset'}
+ = render Input::NumberComponent.new(label: t('recommender.max_ont_set'), name: "max_elements_set", value: params[:max_elements_set] || 3, min: '2', max: '4', step: '1', error_message: "#{@not_valid_max_num_set ? 'Valid values are: 2, 3, 4' : ''}")
+ .input{'data-recommender-target': 'empty'}
- -# Advanced options
- %div#advancedOptions.optionsBox
- -# Specify weights
- %h6 Weights configuration
- %div.form-row
- %div.form-group.col-md-2
- %label{for: "input_wc"} Coverage
- = number_field_tag("input_wc", "0.55", min: "0", step: "1", class: "form-control")
- %div.form-group.col-md-2
- %label{for: "input_wa"} Acceptance
- = number_field_tag("input_wa", "0.15", min: "0", step: "1", class: "form-control")
- %div.form-group.col-md-2
- %label{for: "input_wd"} Knowledge detail
- = number_field_tag("input_wd", "0.15", min: "0", step: "1", class: "form-control")
- %div.form-group.col-md-2
- %label{for: "input_ws"} Specialization
- = number_field_tag("input_ws", "0.15", min: "0", step: "1", class: "form-control")
- -# Specify ontology set size
- %h6 Maximum semantic resources per set
- %div.form-row
- %div.form-group.col-md-2
- = number_field_tag("input_max_ontologies", "3", in: 2...5, class: "form-control")
- -# Specify ontologies
- %div#ontologyPicker
- = render(partial: "shared/ontology_picker")
+ .recommender-page-button#get_recommendations_button{class: is_input ? "" : "d-none", 'data-recommender-target': 'button'}
+ = render Buttons::RegularButtonComponent.new(id:'recommender', value: t('recommender.get_recommendations'), variant: "primary", type: 'submit')
- %div.my-4
- = submit_tag("Get Recommendations", id: "recommenderButton", type: "button", class: "btn btn-primary")
- = submit_tag("Edit Input", id: "editButton", type: "button", style: "display: none;", class: "btn btn-primary")
- = content_tag(:span, class: "recommenderSpinner") do
- = image_tag("spinners/spinner_000000_16px.gif", style: "vertical-align: middle;")
+ .recommender-page-button{class: is_input ? "d-none" : "", 'data-action': 'click->recommender#edit', id: 'recommender-edit-button'}
+ = render Buttons::RegularButtonComponent.new(id:'edit-recommender', value: t('recommender.edit'), variant: "primary") do |btn|
+ - btn.icon_left do
+ = inline_svg_tag "edit.svg"
+ - if @results && @results.empty?
+ = empty_state(t('no_result_was_found'))
+ - unless @results.nil? || @results.empty?
+ .recommender-page-results
+ .title
+ = t('recommender.results_title')
+ .recommender-table-container
+ = render TableComponent.new(id: 'recommender-table', borderless: true, layout_fixed: true, small_text: true, outline: true, sort_column: '1') do |t|
+ - t.header do |h|
+ - @results_table_header.each do |header|
+ - h.th do
+ = header
+ - @results.each do |result|
+ - t.row do |r|
+ - r.td do
+ - ontologies = ""
+ - result[:ontologies].each do |ontology|
+ %a.recommender-result-ontology{href: ontology_path(id: ontology[:acronym], p: 'summary')}
+ = ontology[:acronym]
+ - r.td do
+ = render Display::ProgressBarComponent.new(progress: result[:final_score])
+ - r.td do
+ = render Display::ProgressBarComponent.new(progress: result[:coverage_score])
+ - r.td do
+ = render Display::ProgressBarComponent.new(progress: result[:acceptance_score])
+ - r.td do
+ = render Display::ProgressBarComponent.new(progress: result[:details_score])
+ - r.td do
+ = render Display::ProgressBarComponent.new(progress: result[:specialization_score])
+ - r.td do
+ .recommender-result-highlighted{'data-action': 'change->recommender#handleHighlightedChange'}
+ = render Input::RadioChipComponent.new(label: result[:annotations].length.to_s+' annotations', name: 'highlighted_recommendation', value: result[:annotations], checked: result[:highlighted])
+ .recommender-bottom-actions
+ .json-button
+ = render Buttons::RegularButtonComponent.new(id:'recommender_cite_json', value: "JSON", variant: "secondary", href: @json_link, size: "slim", target: '_blank', state: "regular") do |btn|
+ - btn.icon_left do
+ = inline_svg_tag "json.svg"
+ .cite-us-button
+ = render Buttons::RegularButtonComponent.new(id:'recommender_cite_us', value: t('recommender.cite'), variant: "secondary", href: $CITE_RECOMMENDER, size: "slim", target: '_blank', state: "regular") do |btn|
+ - btn.icon_left do
+ = inline_svg_tag "icons/cite.svg"
+ .go-to-annotator
+ = render Buttons::RegularButtonComponent.new(id:'recommender_go_annotator', value: t('recommender.call_annotator'), variant: "secondary", href: "/annotator?text=#{params[:input]}&ontologies=#{params[:ontologies]}", size: "slim", target: '_blank', state: "regular") do |btn|
+ - btn.icon_right do
+ = inline_svg_tag "arrow-right-outlined.svg"
-%div.row#recommenderErrorsDisplay.mb-4
- %div.col
- %span.notTextError
- Please paste a paragraph of text or some keywords to use in calculating semantic resources recommendations.
- %br/
- %span.sumWeightsError
- The sum of the weights must be greater than zero.
- %br/
- %span.rangeWeightsError
- All the weights must be greater or equal to zero.
- %br/
- %span.invalidWeightsError
- All the weights must be valid numeric values.
- %br/
- %span.invalidMaxOntError
- The maximum semantic resources per set must be a valid integer value.
- %br/
- %span.maxOntologiesError
- The maximum semantic resources per set must be a number between 2 and 4.
- %br/
- %span.generalError
- Problem getting recommendations, please try again.
- %br/
- %span#noResults
- No recommendations found.
- %br/
- %span#noResultsSets
- There are no semantic resource sets recommended for the input provided. Please try the "Semantic Resources" output.
- %br/
- %span.inputSizeError
- Please use less than 500 words. If you need to annotate larger pieces of text you can use the Recommender Web Service
-
-%div.row#resultsDisplay
- %div.col
- %h5#resultsHeader
- %div#recommender-results.mb-5
+
diff --git a/app/views/reviews/_review.html.haml b/app/views/reviews/_review.html.haml
deleted file mode 100644
index 0f38d2884..000000000
--- a/app/views/reviews/_review.html.haml
+++ /dev/null
@@ -1,30 +0,0 @@
-%div{:id => "review_table_container_#{@review.hash}"}
- %table.zebra{:cellpadding => "0", :cellspacing => "0", :id => "review_table_#{@review.hash}", :style => "margin-bottom: 1em;"}
- %thead
- %tr
- %th
- Review By #{@review.creator.split("/").last}
- on #{DateTime.parse(@review.created).strftime('%m/%d/%Y')}
- / TODO_REV: Support user review editing
- /- if isOwner?(@review.user_id)
- / \ #{link_to "Edit Review", edit_review_path(review) + "?height=500&width=600", :class => "thickbox"}
- %tbody
- %tr
- %td
- .star_ratings{:style => "padding: .5em .5em .3em;"}
- - ratings = organize_ratings(@review)
- - if !ratings.any? {|r| r[:value] > 0}
- No ratings submitted with this review
- - else
- %ul
- - ratings.each_with_index do |rating, rating_count|
- - next if rating[:value].to_i.eql?(0)
- %li
- - (1..5).each do |i|
- - checked = rating[:value].to_i.eql?(i) ? "checked" : ""
- = radio_button "review[#{@review.hash}]", rating[:name], "", class: "star", name: "review_#{@review.hash}_star_#{rating_count}", checked: checked, disabled: "disabled"
- %b
- \ #{rating[:name].capitalize}
-
- %p
- = @review.body
diff --git a/app/views/reviews/edit.html.erb b/app/views/reviews/edit.html.erb
deleted file mode 100644
index 0bf7a272e..000000000
--- a/app/views/reviews/edit.html.erb
+++ /dev/null
@@ -1,56 +0,0 @@
-
-
-<%= form_for(:review, :url=>review_path(@review), :html=>{:onsubmit=>"ajaxForm(this, '#review_table_container_#{@review.id}', editReview); return false;"}) do %>
-
-
-<%=hidden_field :review,:ontology_id%>
-<%=hidden_field :review,:project_id%>
-<%=hidden_field :review,:user_id%>
-
- Review For <%=@review.ontology.displayLabel%>
-
-
-
-
-
- <%=submit_tag "Submit Reviews",:class=>"blueButton"%>
-
-<%end%>
-
-
-
diff --git a/app/views/reviews/index.html.erb b/app/views/reviews/index.html.erb
deleted file mode 100644
index 4f42e1faa..000000000
--- a/app/views/reviews/index.html.erb
+++ /dev/null
@@ -1,56 +0,0 @@
-<%@title = "Reviews of the #{@ontology.displayLabel}"%>
-
-
-<%if session[:user].nil?%>
-
-<%else%>
-<%=link_to "Review Ontology",new_review_path(:ontology=>@ontology.ontologyId)%>
-<%end%>
-
-
-
-Reviews for <%=@ontology.displayLabel%>
-
-
-
-
-
diff --git a/app/views/reviews/new.html.haml b/app/views/reviews/new.html.haml
deleted file mode 100644
index a71e4b267..000000000
--- a/app/views/reviews/new.html.haml
+++ /dev/null
@@ -1,24 +0,0 @@
-= form_for(:review, :url => reviews_path, :remote => true, :id => "new_review_form") do |f|
- = f.hidden_field :ontologyReviewed, value: @review.ontologyReviewed
- = f.hidden_field :creator, value: @review.creator
- %fieldset
- %legend
- %b
- Review For #{@ontology.name}
- %table
- %tr
- %td
- Ratings
- %br/
- - for rating in @rating_types
- %div{:style => "padding:2px;border-top:1px solid gray;"}
- - (1..5).each do |i|
- = f.radio_button rating, i, class: "star"
- #{rating.to_s.chomp("Rating").capitalize}
- %tr
- %td= f.text_area :body, value: @review.body, cols: 80, rows: 5
- = submit_tag "Submit Review", class: "blueButton"
-
-:javascript
- // Do this after the HTML above loads
- jQuery('input.star').rating();
diff --git a/app/views/reviews/show.html.erb b/app/views/reviews/show.html.erb
deleted file mode 100644
index fee6e546d..000000000
--- a/app/views/reviews/show.html.erb
+++ /dev/null
@@ -1,37 +0,0 @@
-
-
-
-
-
- Review By <%=@review.user.username %><%unless @review.project.nil? %> From Project <%=link_to @review.project.name,project_path(@review.project) %><%end %><%if isOwner?(@review.user_id) %> <%=link_to "Edit Review", edit_review_path(@review) + "?height=500&width=600", :class => "thickbox" %><%end %>
-
-
-
-
-
-
-
-
- <%=@review.review%>
-
-
-
-
-
\ No newline at end of file
diff --git a/app/views/schemes/_scheme.html.haml b/app/views/schemes/_scheme.html.haml
index 91607bf91..5cfac8c31 100644
--- a/app/views/schemes/_scheme.html.haml
+++ b/app/views/schemes/_scheme.html.haml
@@ -1,23 +1,13 @@
= turbo_frame_tag 'scheme' do
- if @scheme && !@scheme.empty?
- = render ConceptDetailsComponent.new(id:'scheme-label', acronym: @ontology.acronym,
+ = render ConceptDetailsComponent.new(id:'scheme-label', acronym: @ontology.acronym, concept_id: @scheme.id,
properties: scheme.properties,
top_keys: %w[description comment],
bottom_keys: %w[disjoint subclass is_a has_part],
exclude_keys: []) do |c|
- = c.header do
- %tr
- %td.label
- ID
- %td
- %p= scheme["@id"]
- %tr
- %td{nowrap: ""} Preferred Name
- %td
- %p= get_scheme_label(scheme)
- %tr
- %td.label
- Type
- %td
- %p= scheme["@type"]
+ - c.header(stripped: true) do |t|
+ - t.add_row({th: t('schemes.id')} , {td: link_to_with_actions(scheme["@id"], acronym: @ontology.acronym)})
+ - t.add_row({th: t('schemes.preferred_name')} , {td: display_in_multiple_languages(get_scheme_label(scheme))})
+ - t.add_row({th: t('schemes.type')} , {td: scheme["@type"]})
+
diff --git a/app/views/schemes/_tree_view.html.haml b/app/views/schemes/_tree_view.html.haml
index 333f4223d..f036242ae 100644
--- a/app/views/schemes/_tree_view.html.haml
+++ b/app/views/schemes/_tree_view.html.haml
@@ -1,24 +1,13 @@
+= turbo_frame_tag "schemes_sorted_list_view-page-1" do
+ - if no_schemes?
+ %div
+ = no_schemes_alert
+ - else
+ - schemes_labels, main_scheme_label = get_schemes_labels(@schemes, @submission_latest.URI)
+ - selected_scheme_id = params[:schemeid].nil? && !main_scheme_label.nil? ? main_scheme_label["@id"] : CGI.unescape(params[:schemeid] || '')
+ - if main_scheme_label.nil?
+ = no_main_scheme_alert
+ %div
+ = schemes_tree(schemes_labels, main_scheme_label, selected_scheme_id)
+
-- if no_schemes?
- %div
- = no_schemes_alert
-- else
- - schemes_labels, main_scheme_label = get_schemes_labels(@schemes, @submission_latest.URI)
- - selected_scheme_id = params[:scheme_id].nil? && !main_scheme_label.nil? ? main_scheme_label["@id"] : CGI.unescape(params[:scheme_id] || '')
- - if main_scheme_label.nil?
- = no_main_scheme_alert
- %div
- %ul.simpleTree{data:{controller: 'simple-tree history', action: 'clicked->history#updateURL'}}
- %li.root
- %ul
- - if main_scheme_label.nil?
- = raw tree_link_to_schemes(schemes_labels ,main_scheme_label, selected_scheme_id)
- - else
- %li.open
- %a{id: main_scheme_label["@id"],
- href: scheme_path(main_scheme_label["@id"]),
- data: { turbo: "true", 'turbo-frame': 'scheme', schemeid: main_scheme_label["@id"]},
- class: selected_scheme_id.eql?(main_scheme_label["@id"]) ? "active" : nil }
- = get_scheme_label(main_scheme_label)
- %ul
- = raw tree_link_to_schemes(schemes_labels ,main_scheme_label, selected_scheme_id)
\ No newline at end of file
diff --git a/app/views/search/_concept_preview.html.erb b/app/views/search/_concept_preview.html.erb
deleted file mode 100644
index 5d8cdc1fe..000000000
--- a/app/views/search/_concept_preview.html.erb
+++ /dev/null
@@ -1,17 +0,0 @@
-
-Preview of <%=link_to "#{@concept.label_html},#{@concept.id}",uri_url(:ontology=>@ontology,:conceptid=>@concept.id),:target=>"_new"%>
-
-
-
-
-<%@concept.properties.each_pair{|key,value| %>
-
-
- <%="#{remove_owl_notation(key)}:"%> <%="#{value}"%>
-
-
-<% } %>
-
-
-
-
\ No newline at end of file
diff --git a/app/views/search/_concepts.html.erb b/app/views/search/_concepts.html.erb
deleted file mode 100644
index b0593ccee..000000000
--- a/app/views/search/_concepts.html.erb
+++ /dev/null
@@ -1,22 +0,0 @@
-<%if @concepts.size > 0%>
-
-
-
- <%for option in @concepts%>
- <%=option[:preferredName]%>
- <%end%>
-
-
-
-
-
-
Comment <%=text_area(:mapping, :comment, :size => "30x10")%>
-
-
-
- <%= select("mapping", "directionality", { "Bidirectional" => "bidirectional", "Unidirectional" => "unidirectional" })%>
- <%= submit_tag "Create", :class=>'blueButton'%>
-
-<%else%>
- No Results Found
-<%end%>
\ No newline at end of file
diff --git a/app/views/search/_results.html.erb b/app/views/search/_results.html.erb
deleted file mode 100644
index 314707ad3..000000000
--- a/app/views/search/_results.html.erb
+++ /dev/null
@@ -1,69 +0,0 @@
-
-<%if @results.size > 0%>
-
- <%if params[:page].to_i > 1 %>
- << Previous Page
-
- <%end%>
- Page <%=params[:page] || 1%> of <%=@pages%>
- <%if !params[:page].to_i.eql?(@pages.to_i)%>
- Next Page >>
-
- <%end%>
-
-
-
-
-
- <%if params[:page].to_i >1 %> << Previous Page <%end%> Page <%=params[:page] || 1%> of <%=@pages%> <%if !params[:page].to_i.eql?(@pages.to_i)%> Next Page >> <%end%>
-
-
-
-
- Class Name
- Found In
- Ontology
-
-
- <%for result in @results%>
- <%begin
- #catch exceptions and dont draw row
- row = "
- #{link_to highlight(result[:contents],@keyword), uri_url(:ontology => result[:ontologyVersionId], :conceptid => result[:conceptIdShort]), :onclick => "YAHOO.tabwait.container.wait.show();"}
- #{result[:recordType].titleize.gsub("Record Type","")}
- #{link_to result[:ontologyDisplayLabel], ontology_path(:id=>result[:ontologyVersionId])}
- "%>
- <%=row%>
- <%rescue
- end
- %>
- <%end%>
-
-
-
- <%if params[:page].to_i >1 %> << Previous Page <%end%> Page <%=params[:page] || 1%> of <%=@pages%> <%if !params[:page].to_i.eql?(@pages.to_i)%> Next Page >> <%end%>
-
-
-
-
-<%else%>
- No Results Found
-<%end%>
diff --git a/app/views/search/index.html.haml b/app/views/search/index.html.haml
index 6b8246641..28ecbf2ee 100644
--- a/app/views/search/index.html.haml
+++ b/app/views/search/index.html.haml
@@ -1,67 +1,72 @@
-- @title = "Search"
+.search-page-container
+ .search-page-subcontainer{'data-controller': 'reveal-component'}
+ = form_tag(search_path, method: :get,data:{turbo: true, controller: 'form-url', action: 'submit->form-url#submit'}) do
+ = search_page_input_component(placeholder: t('search.search_place_holder'), name: "q", value: @search_query) do
+ .search-page-advanced{'data-reveal-component-target': 'item', class: "#{@advanced_options_open ? '' : 'd-none'}"}
+ .left
+ .filter-container
+ .title
+ = t('search.advanced_options.search_language')
+ .field
+ = search_language_selector(name: 'lang', selected: params[:lang])
-%div.container.mt-5
- %h1
- Class Search
+ .filter-container
+ .title
+ = t("search.advanced_options.ontologies")
+ .field
+ = ontologies_selector(id:'search_page_ontologies' ,name: 'ontologies[]', selected: params[:ontologies]&.split(','))
- = form_tag("/search", method: "post") do
- %div.form-group
- = text_field_tag("search_keywords", nil, class: "form-control", aria: {describedby: "classSearchHelpBlock"})
- %small#classSearchHelpBlock.form-text.text-muted
- = t(".search_keywords_placeholder")
- = link_to("help", Rails.configuration.settings.links[:help_search], target: '_blank',
- aria: {label: "View search documentation"}, class: "float-right")
- %div.form-group
- = link_to("Show advanced options", "javascript:void(0)", id: "advanced_options", data: {text_swap: "Hide advanced options"}, class: "form-text")
+ .right
+ .filter-container
+ .title
+ = t("search.advanced_options.include_in_search_title")
+ .d-flex
+ = render(ChipsComponent.new(name: 'also_search_properties', label: t("search.advanced_options.include_in_search_values.property_values"), checked: params[:also_search_properties]))
+ = render(ChipsComponent.new(name: 'also_search_obsolete', label: t("search.advanced_options.include_in_search_values.obolete_classses"), checked: params[:also_search_obsolete]))
+ = render(ChipsComponent.new(name: 'also_search_views', label: t("search.advanced_options.include_in_search_values.ontology_views"), checked: params[:also_search_views]))
- -# Advanced search options
- %div#search_options{style: "display: none;"}
- %div.form-group.row
- %div.col-sm-2 Include in search:
- %div.col-sm-10
- %div.form-check
- = check_box(:search, :include_properties, class: "form-check-input")
- = label(:search, :include_properties, "Property values", class: "form-check-label definition", title: t(".property_definition"))
- %div.form-check
- = check_box(:search, :include_obsolete, class: "form-check-input")
- = label(:search, :include_obsolete, "Obsolete classes", class: "form-check-label definition", title: t(".obsolete_definition"))
- %div.form-check
- = check_box(:search, :include_views, class: "form-check-input")
- = label(:search, :include_views, "Ontology views", class: "form-check-label")
- %div.form-group.row
- %div.col-sm-2 Narrow search to:
- %div.col-sm-10
- %div.form-check
- = check_box(:search, :exact_match, class: "form-check-input")
- = label(:search, :exact_match, "Exact matches", class: "form-check-label")
- %div.form-check
- = check_box(:search, :require_definition, class: "form-check-input")
- = label(:search, :require_definition, "Classes with definitions", class: "form-check-label")
- %div.form-group
- %h2{style: "font-size: 10pt !important"} Categories
- = select(:search, :categories, options_for_select(categories_for_select), {}, style: "width: 432px", multiple: "true", data: {placeholder: t(".categories_placeholder")})
- %div.form-group.mb-5{style: "width:432px"}
- = render :partial => "shared/ontology_picker", locals: {sel_text: "Ontologies"}
+ .filter-container
+ .title
+ =t('search.advanced_options.show_only_title')
+ .d-flex
+ = render(ChipsComponent.new(name: 'require_exact_match', label: t('search.advanced_options.show_only_values.exact_matches'), checked: params[:require_exact_match]))
+ = render(ChipsComponent.new(name: 'require_definition', label: t('search.advanced_options.show_only_values.classes_with_definitions'), checked: params[:require_definition]))
- = button_tag("Search", id: "search_button", class: "btn btn-primary")
- = content_tag(:span, id: "search_spinner") do
- %img{src: asset_path('spinners/spinner_000000_16px.gif'), style: "vertical-align: middle;"}
+ .search-page-options{class: @search_results.empty? ? 'justify-content-end': ''}
+ - unless @search_results.empty?
+ .search-page-number-of-results
+ = "#{t('search.match_in')} #{@search_results.length} #{t('search.ontologies')}"
+ %div.d-flex
+ .search-page-json.mx-4.mt-1
+ = search_json_link
+ .search-page-advanced-button.show-options{class: "#{@advanced_options_open ? 'd-none' : ''}",'data': {'action': 'click->reveal-component#show', 'reveal-component-target': 'showButton'}}
+ .icon
+ =inline_svg_tag 'icons/settings.svg'
+ .text
+ = t('search.show_advanced_options')
+ .search-page-advanced-button.hide-options{class: "#{@advanced_options_open ? '' : 'd-none'}", 'data': {'action': 'click->reveal-component#hide', 'reveal-component-target': 'hideButton'}}
+ .icon
+ =inline_svg_tag 'icons/hide.svg'
+ .text
+ = t('search.hide_advanced_options')
+ - if @search_results
+ .search-page-results-container
+ - number = 0
+ - @search_results.each do |result|
+ .search-page-result-element
+ - number = number + 1
+ - descendants = result[:descendants]
+ - reuses = result[:reuses]
+ - result[:root][:number] = number
+ = render Display::SearchResultComponent.new(result[:root]) do |c|
+ - descendants.each { |d| c.subresult(d.merge(is_sub_component: true))}
+ - reuses.each do |r|
+ - number = number + 1
+ - c.reuse(r[:root].merge(is_sub_component: true, number: number)) do |b|
+ - r[:descendants].each { |dd| b.subresult(dd.merge(is_sub_component: true))}
- -# Search results
- %div.row.mt-4#search_results_container
- %div.col
- #result_stats
- #search_messages
- #search_results
-
-%div#biomixer{style: "display: none;"}
-
-:javascript
- // Hash of ontology id => name, acronym for lookup use via JS
- jQuery(document).ready(function() {
- jQuery(document).data().bp.ontologies = #{Hash[LinkedData::Client::Models::Ontology.all(include_views: true).map {|o| [o.id, {name: o.name, acronym: o.acronym}]}].to_json.html_safe}
-
- if (jQuery("#search_keywords").val() !== "") {
- performSearch();
- }
- });
+ - if @search_results.empty? && !@search_query.empty?
+ .browse-empty-illustration
+ %img{:src => "#{asset_path("empty-box.svg")}"}
+ %p No result was found
+
\ No newline at end of file
diff --git a/app/views/search/search.html.erb b/app/views/search/search.html.erb
deleted file mode 100644
index 3eb433b1c..000000000
--- a/app/views/search/search.html.erb
+++ /dev/null
@@ -1,6 +0,0 @@
-
-<%for result in @results%>
- <%=result.name%>
-
-<%end%>
-
\ No newline at end of file
diff --git a/app/views/shared/_concept_picker.html.haml b/app/views/shared/_concept_picker.html.haml
index d1b32729a..a3b61e816 100644
--- a/app/views/shared/_concept_picker.html.haml
+++ b/app/views/shared/_concept_picker.html.haml
@@ -1,5 +1,5 @@
= text_field_tag(name, concept_label, class: "search_autocomplete form-control",
- placeholder: "Start typing to select a class",
+ placeholder: 'Start typing to select a class/concept',
data: {controller: "form-auto-complete",
"form-auto-complete-ontology_id-value": ontology_acronym ,
"form-auto-complete-target_property-value": 'name',
diff --git a/app/views/shared/_not_browsable.html.erb b/app/views/shared/_not_browsable.html.erb
deleted file mode 100644
index 17a5d9dbf..000000000
--- a/app/views/shared/_not_browsable.html.erb
+++ /dev/null
@@ -1,21 +0,0 @@
-
-
-
-
Not Browsable
-
- <%= ErrorHelpers::not_browsable_text(@concept) %>
- From here you can:
-
-
- Go back to your previous page
- View <%=link_to @ontology.displayLabel, visualize_url(:ontology => @ontology.id)%>, which contains <%=@concept.name%>
-
-
-
-
-
\ No newline at end of file
diff --git a/app/views/shared/_ontology_picker.html.erb b/app/views/shared/_ontology_picker.html.erb
deleted file mode 100644
index 7db05cab0..000000000
--- a/app/views/shared/_ontology_picker.html.erb
+++ /dev/null
@@ -1,49 +0,0 @@
-<%custom_ontologies ||= nil%>
-<%selected_ontologies ||= []%>
-<%init_ontology_picker(custom_ontologies, selected_ontologies)%>
-<%form_object ||= :ontology%>
-<%form_attribute ||= "ontologyId"%>
-<%sel_text ||= "Select semantic resources"%>
-<%@select_id = "#{form_object}_#{form_attribute}"%>
-
-
-
-
-
-
- <%=sel_text%>
-
-
-
- <%=select form_object, form_attribute, options_for_select(@onts_for_select, selected_ontologies), { }, :multiple => 'true', "data-placeholder".to_sym => "Start typing to select ontologies or leave blank to use all", :style => "width: 432px;" %>
-
-
-
-
- <%=render_advanced_picker(custom_ontologies, selected_ontologies)%>
-
-
diff --git a/app/views/shared/_ontology_picker_advanced.html.erb b/app/views/shared/_ontology_picker_advanced.html.erb
deleted file mode 100644
index 3cab37ef4..000000000
--- a/app/views/shared/_ontology_picker_advanced.html.erb
+++ /dev/null
@@ -1,384 +0,0 @@
-
-
-
-
-
-
Select Multiple Ontologies close
-
-
-
-
-
-
-
-
-
Filtered Groups and Categories:
-
-
-
-
-
- <%= check_box_tag "ont_select_all_filtered" %>
- <%= label_tag "ont_select_all_filtered", "Select all filtered ontologies", :style => "color: var(--primary-color); font-weight: bold;" %> (show all )
-
-
- <% @onts_for_select.each do |ont| %>
-
- <%= check_box_tag "ont_select_adv_check", ont[1], false, :id => "ont_select_adv_check#{ont[1]}" %>
- <%= label_tag "ont_select_adv_check#{ont[1]}", ont[0] %>
-
- <% end %>
-
-
-
-
diff --git a/app/views/shared/_ontology_picker_single.html.erb b/app/views/shared/_ontology_picker_single.html.erb
deleted file mode 100644
index dbcb73125..000000000
--- a/app/views/shared/_ontology_picker_single.html.erb
+++ /dev/null
@@ -1,21 +0,0 @@
-<%custom_ontologies ||= nil%>
-<%selected ||= ""%>
-<%selected = selected.split("/").last if selected.start_with?("http")%>
-<%init_ontology_picker(custom_ontologies, [selected])%>
-<%placeholder ||= "Select an Ontology"%>
-<%picker_id ||= "ontology_picker_single"%>
-<%selected ||= nil%>
-<%field_name ||= "ontologyId"%>
-<%object_name ||= :ontology%>
-<%disabled ||= nil%>
-
-
-
-
- <%= select object_name, field_name, @onts_for_select, { :include_blank => true, :selected => selected }, :id => picker_id, :class => "ontology_picker_single form-control", "data-placeholder".to_sym => placeholder, disabled: disabled %>
-
-
diff --git a/app/views/statistics/index.html.haml b/app/views/statistics/index.html.haml
new file mode 100644
index 000000000..e42fac412
--- /dev/null
+++ b/app/views/statistics/index.html.haml
@@ -0,0 +1,33 @@
+%div.px-3.py-3.pt-md-5.pb-md-4.text-center
+ %h1.display-4
+ = t('statistics.title', portal: portal_name)
+ %p.lead
+ = t('statistics.lead', last_years: Date.today.year - Date.parse(@merged_data[:labels].first).year)
+%div.container
+ %div
+ = chart_component(title: nil, type: 'line', show_legend: true,
+ labels: @merged_data[:labels], datasets: visits_chart_dataset_array({ t('statistics.ontologies') => @merged_data[:visits][2],
+ t('statistics.users') => @merged_data[:visits][0], t('statistics.projects') => @merged_data[:visits][1] }, fill: false))
+
+ %div.pb-3.pb-md-4
+ - size = @merged_data[:labels].size - 1
+ - visits = @year_month_visits
+ = render TableComponent.new(id: 'statistics_table') do |t|
+ - t.header do |h|
+ - h.th {t('statistics.date')}
+ - h.th {t('statistics.ontologies')}
+ - h.th {t('statistics.users')}
+ - h.th {t('statistics.projects')}
+ - h.th {t('statistics.ontology_visits')}
+
+ - @merged_data[:labels].reverse.each_with_index do |year_month, i|
+ - t.row do |r|
+ - r.td {year_month}
+ - r.td {@merged_data[:visits][2][size - i].to_s}
+ - r.td {@merged_data[:visits][0][size - i].to_s}
+ - r.td {@merged_data[:visits][1][size - i].to_s}
+ - r.td do
+ - year = Date.parse(year_month).year
+ - month = Date.parse(year_month).month
+ = visits[[year, month]] || 0
+
diff --git a/app/views/submissions/_form.html.haml b/app/views/submissions/_form.html.haml
deleted file mode 100644
index 04410cfbe..000000000
--- a/app/views/submissions/_form.html.haml
+++ /dev/null
@@ -1,25 +0,0 @@
-:javascript
- $(document).ready(function() {
- jQuery("#ontology_submission_form").validate();
- });
-
-
- function onMetadataChange(){
- let frame = document.getElementById('metadata_by_ontology')
- let properties = document.getElementById('search_metadata')
- let required = document.getElementById('filter-required-only')
- let selectedProperties = "all"
- if(properties){
- selectedProperties = Array.from(properties.selectedOptions).map(({ value }) => value).join(',')
- }
- frame.src = "?properties=" + selectedProperties + "&required=" + required.checked + "&show_sections=true"
- }
-
-
-= render partial: 'form_content', locals: {id: 'metadata_by_ontology', acronym: @ontology.acronym, submissionId: @submission.submissionId}
-
-%div.d-flex.justify-content-end.mt-1
- %div
- = link_to "Cancel", :back, class: "btn btn-secondary"
- %div.ml-1
- = submit_tag button_text, class: "btn btn-primary"
diff --git a/app/views/submissions/_form_content.html.haml b/app/views/submissions/_form_content.html.haml
index 68de9b3bf..f7d97aed5 100644
--- a/app/views/submissions/_form_content.html.haml
+++ b/app/views/submissions/_form_content.html.haml
@@ -1,178 +1,12 @@
-= render TurboFrameComponent.new(id:id) do
- %div#editMetadataDiv
- %div
- %p
- To understand the ontologies metadata:
- %a{:href => "https://github.com/agroportal/documentation/wiki/Ontology-metadata", :target => "_blank"} see the Wiki
- %div.d-flex.align-items-center.justify-content-between{onchange: "onMetadataChange()", style: "visibility: #{@filters_disabled ? 'hidden' : 'visible'}"}
- %div.w-75.mt-3
- - if @submission.id
- = render MetadataSelectorComponent.new(label: 'Filter properties to show', values: submission_editable_properties , selected: nil, inline: true)
- %div
- = render SwitchInputComponent.new(id:"filter-required-only", name: "required-only", label: "Required only", checked: @required_only)
+- unless @errors.nil?
+ = turbo_frame_tag 'test', target: '_top' do
+ = error_message_alert
+ = form_for :submission, url: ontology_submission_path(params["ontology_id"], params["id"]), html: { id: "ontology_submission_form", method: :put, multipart: true, 'data-turbo': true, novalidate: 'true'} do
+ = render_submission_inputs('', @submission)
+ %hr#edit-ontology-actions-devider
+ .edit-ontology-actions
+ .save-button
+ = render Buttons::RegularButtonComponent.new(id:'save-button', value: t('submissions.save_button'), variant: "primary", size: "slim", type: "submit") do |btn|
+ - btn.icon_left do
+ - inline_svg_tag "check.svg"
-
- - unless @errors.nil?
- %div
- %div.enable-lists{style: "color:red;"}
- %strong Errors On Form
- %ul
- - Array(@errors).each do |error|
- - error = error[:error] if error.is_a?(Hash) && error[:error]
- - if error.is_a?(String)
- = error
- - else
- - error.each do |key, value|
- %li
- - value = value.values if value.is_a?(Hash)
- #{key}: #{Array(value).join(', ')}
-
- = hidden_field object_name, :ontology, value: acronym
- = hidden_field object_name, :id, value: submissionId
- %div#general-card.mt-4
- = metadata_section('general', 'General', collapsed: false) do
- = attribute_container('format', required: true) do
- = turbo_frame_tag "#{object_name(acronym, submissionId)}Format_from_group_input" do
- = render partial: 'submissions/submission_format_form'
- = attribute_text_field_container('version', required: true)
-
- = attribute_form_group_container('status', required: true) do |c|
- - selected_status = c.value ? c.value : "alpha"
- - status_options = %w[alpha beta production retired]
- = select c.name, c.method_name, status_options, {selected: selected_status, required: true}, class: "form-control"
-
- = attribute_form_group_container('location', required: true) do
- = render partial: 'submissions/submission_location_form'
-
-
- %div#key-properties-card.mt-4
- = metadata_section('key-properties', 'Key properties', collapsed: false) do
- = form_group_attribute("URI", required: true)
- = render partial: 'submissions/submission_identifier_form'
-
- = form_group_attribute('hasCreator', label: 'Creator(s)', required: true)
- = form_group_attribute('publisher', required: true)
-
- = attribute_form_group_container('description', required: true) do |c|
- = text_area c.name, c.method_name, rows: 5, value: @submission.description, required: true, class: "form-control"
-
- = form_group_attribute('alternative', required: true)
-
- -# Publications page
- = form_group_attribute('publication', label: 'Publication(s)', required: true) do
- %p
- Enter a URL for a page that lists publications about your ontology.
-
- = form_group_attribute("released", default: Date.today, required: true)
-
- = form_group_attribute("hasFormalityLevel", required: true)
-
- %div#description-card.mt-4
- = metadata_section('more-description-details', 'More description details', parent_id: "description-card") do
- = form_group_attribute("deprecated")
- = form_group_attribute("isOfType")
- = form_group_attribute("hasOntologySyntax") do
- %p
- Properties taken from
- = link_to "W3C URIs for file format", "https://www.w3.org/ns/formats/", target: "_blank"
-
- = form_group_attribute("naturalLanguage") do
- %p
- Consider using a
- = link_to "Lexvo URI", "http://www.lexvo.org", target: "_blank"
- with ISO639-3 code
- %br
- e.g.: http://lexvo.org/id/iso639-3/eng
-
- -# Home page
- = form_group_attribute('homepage') do
- Enter a URL for the main page of your ontology.
-
- -# Documentation page
- = form_group_attribute('documentation') do
- Enter a URL for a page that provides ontology documentation.
-
-
- -# Used ontology engineering tool
- = form_group_attribute("usedOntologyEngineeringTool")
-
- - for attr_name in %w[abstract notes keywords]
- = form_group_attribute(attr_name)
-
- - data = sections
-
- - data.each do |d|
- = metadata_section(d[0], d[1], parent_id: "description-card") do
- - for attr in @metadata.select { |m| m['category'] == d[2] }
- = form_group_attribute(attr["attribute"])
-
- %div#ontology-dates-card.mt-4
- = metadata_section('more-dates', 'More dates', parent_id: "ontology-dates-card") do
- = form_group_attribute("modificationDate")
- - for attr in @metadata.select { |m| m['category'] == 'dates' }
- = form_group_attribute(attr["attribute"])
-
- %div#licenses-card.mt-4
- = metadata_section('licenses', 'Licenses') do
- = form_group_attribute("hasLicense") do
- %p
- Consider using a
- = link_to "URI to describe your License", "http://rdflicense.appspot.com", target: "_blank"
- %p
- Consider using
- = link_to "INRIA licentia", "http://licentia.inria.fr/", target: "_blank"
- to choose your license
-
- = metadata_section('more-licensing-info', 'More licensing information', parent_id: "licenses-card") do
- = form_group_attribute("morePermissions")
- = form_group_attribute("copyrightHolder")
-
- %div#community.mt-4
- = metadata_section('contacts-panel', 'Contacts', parent_id: "community", collapsed: !@required_only || !@submission.id.nil?) do
- -# Contact(s)
- = attribute_form_group_container('contact' ,required: true) do |c|
- - @submission.contact = [] unless @submission.contact && @submission.contact.size > 0
- = render NestedFormInputsComponent.new do |c|
- - c.template do
- = render partial: "submissions/submission_contact_form", locals: {contact: nil, index: 'NEW_RECORD'}
- - c.empty_state do
- = hidden_field_tag object_name+"[contact][#{@submission.contact.size}][email]"
- = hidden_field_tag object_name+"[contact][#{@submission.contact.size}][name]"
- - @submission.contact.each_with_index do |contact, i|
- - c.row do
- = render partial: "submissions/submission_contact_form", locals: {contact: contact, index: i}
-
- = form_group_attribute("hasContributor")
-
- = metadata_section('more-community-info', 'More community information', parent_id: "community") do
- - for attr in @metadata.select { |m| m['category'] == 'community' }
- = form_group_attribute(attr["attribute"])
-
- = metadata_section('more-people-info', 'More people information', parent_id: "community") do
- - for attr in @metadata.select { |m| m['category'] == 'people' }
- = form_group_attribute(attr["attribute"])
-
- %div#ontology-relations-more.mt-4
- = metadata_section('ontology-relations', 'Ontology relations', parent_id: "ontology-relations-more") do
- = form_group_attribute("useImports")
- = form_group_attribute("hasPriorVersion")
- = form_group_attribute("isAlignedTo")
- = form_group_attribute("ontologyRelatedTo")
-
- = metadata_section('more-relations', 'More relations', parent_id: "ontology-relations-more") do
- - for attr in @metadata
- - if attr["category"].eql?("relations")
- = form_group_attribute(attr["attribute"])
-
- %div#ontology-content-metrics.mt-4
- = metadata_section('ontology-content', 'Ontology content', parent_id: "ontology-content-metrics") do
- = form_group_attribute("preferredNamespacePrefix")
- = form_group_attribute("preferredNamespaceUri")
-
- = metadata_section('more-informations', 'More content informations', parent_id: "ontology-content-metrics") do
- - for attr in @metadata.select { |m| m['category'] == 'content' }
- = form_group_attribute(attr["attribute"])
-
- = metadata_section('more-metrics-informations', 'More metrics informations', parent_id: "ontology-content-metrics") do
- - for attr in @metadata.select { |m| m['category'] == 'metrics' }
- = form_group_attribute(attr["attribute"])
\ No newline at end of file
diff --git a/app/views/submissions/_submission_contact_form.html.haml b/app/views/submissions/_submission_contact_form.html.haml
deleted file mode 100644
index 55248fe65..000000000
--- a/app/views/submissions/_submission_contact_form.html.haml
+++ /dev/null
@@ -1,5 +0,0 @@
-%div.d-flex
- %div.w-50.mx-1
- = text_field object_name, "contact[#{index.to_s.upcase}][name]", placeholder: 'Name', value: contact ? contact["name"] : '' , class: "form-control flex-grow-1 mx-2"
- %div.w-50.mx-1
- = text_field object_name, "contact[#{index.to_s.upcase}][email]", placeholder: 'Email', value: contact ? contact["email"] : '', class: "form-control flex-grow-1 mx-2"
diff --git a/app/views/submissions/_submission_format_form.html.haml b/app/views/submissions/_submission_format_form.html.haml
deleted file mode 100644
index d47d9284f..000000000
--- a/app/views/submissions/_submission_format_form.html.haml
+++ /dev/null
@@ -1,26 +0,0 @@
-:javascript
-
- function ontologyFormatChange(event){
- let selected = event.target.selectedOptions.item(0)
- let options = document.querySelectorAll('.format_options')
- Array.from(options).forEach( x => $(x).hide())
- switch(selected.value){
- case 'OWL':
- jQuery("#owl_options").show()
- break
- case 'SKOS':
- jQuery("#skos_options").show()
- break
- }
- }
-
-= attribute_form_group_container('hasOntologyLanguage', label: 'Format', required: true) do |c|
- - ont_formats = %w[OBO OWL UMLS SKOS].sort
- - selected = @submission.hasOntologyLanguage ? @submission.hasOntologyLanguage : "OWL"
- = select c.name, c.method_name, options_for_select(ont_formats, selected), {required: true}, {class: "form-control", onchange: 'ontologyFormatChange(event)'}
- - c.help do
- %div#skos_options.format_options{style: "display:#{skos? ? 'block': 'none'}"}
- SKOS vocabularies submitted to BioPortal must contain a minimum of one concept scheme and top concept assertion.
- Please refer to the NCBO wiki for a more #{link_to 'detailed explanation', 'https://www.bioontology.org/wiki/index.php/SKOSSupport', target: "_blank" }
- with examples.
-
\ No newline at end of file
diff --git a/app/views/submissions/_submission_location_form.html.haml b/app/views/submissions/_submission_location_form.html.haml
deleted file mode 100644
index 07faedf61..000000000
--- a/app/views/submissions/_submission_location_form.html.haml
+++ /dev/null
@@ -1,61 +0,0 @@
-:javascript
- $(document).ready(function() {
-
- // Properly display the information for 'File Location' based on radio button
- if (jQuery("#submission_isRemote_0").is(":checked")) {
- location_toggle("upload");
- }
- if (jQuery("#submission_isRemote_1").is(":checked")) {
- location_toggle("remote");
- }
-
- // Select default 'File Location' radio button
- if (!jQuery("#submission_isRemote_0").is(":checked") && !jQuery("#submission_isRemote_1").is(":checked") && !jQuery("#submission_isRemote_2").is(":checked")) {
- jQuery("#submission_isRemote_0").attr("checked", "checked")
- }
- });
-
- // Show/hide location inputs
- function location_toggle(input_div) {
- jQuery('.hidden_field').hide();
- jQuery('.hidden_field input').attr("disabled", true);
- jQuery('#' + input_div + " input").removeAttr("disabled");
- jQuery('#' + input_div).show();
- }
-
-
-- if !@masterFileOptions
- %div.form-check
- - checked = @ontology.summaryOnly
- = radio_button(object_name, :isRemote, 3, :onclick=>"$('.hidden_field').hide();", checked: checked, aria: {describedBy: "metadataHelpBlock"}, class: "form-check-input")
- %label.form-check-label{for: "submission_isRemote_3"}
- Metadata only
- %small.form-text.text-muted#metadataHelpBlock Allow users to view and search your ontology metadata, but not its classes and properties.
- %div.form-check
- - checked = !(@submission.pullLocation.nil? || @submission.pullLocation.empty?)
- = radio_button(object_name, :isRemote, 1, :onclick=>"location_toggle('remote');", checked: checked, aria: {describedBy: "loadFromURLHelpBlock"}, class: "form-check-input")
- %label.form-check-label{for: "submission_isRemote_1"}
- Load from URL
- %small.form-text.text-muted#loadFromURLHelpBlock New versions loaded on a nightly basis.
- - display = (checked and "" or "display:none;")
- %div.hidden_field#remote{style: display}
- = text_field(object_name, :pullLocation, value: @submission.pullLocation, aria: {describedBy: "enterURLHelpBlock"}, class: "form-control")
- %small.form-text.text-muted#enterURLHelpBlock Enter a URL, including the name of your ontology source file, e.g., http://www.example.com/my_ontology.owl.
- %div.form-check
- - checked = (!@ontology.summaryOnly) && @submission.pullLocation.nil?
- = radio_button(object_name, :isRemote, 0, :onclick=>"location_toggle('upload');", checked: checked, class: "form-check-input")
- %label.form-check-label{for: "submission_isRemote_0"}
- Upload local file
- - display = (checked and "" or "display:none;")
- %div.hidden_field#upload{style: display}
- = file_field(object_name, :filePath, class: "mt-2")
-- else
- -# TODO: Has this section of code actually been tested?
- = radio_button object_name, :isRemote, 0, :onclick=>"location_toggle('upload');", checked: true
- Upload Local File
- %br/
- %span{:style => "font-size:11px;"} (choose a file on your local file system to upload)
- - display = (checked and "" or "display:none;")
- %div#upload{style: display}
- = file_field object_name, :filePath, required: true
- = select(object_name, "masterFileName", @masterFileOptions, { include_blank: "Select primary file from zip contents", required: true}, {style: "border-color: red;"})
diff --git a/app/views/submissions/_submissions.html.haml b/app/views/submissions/_submissions.html.haml
index 827862902..49ab54333 100644
--- a/app/views/submissions/_submissions.html.haml
+++ b/app/views/submissions/_submissions.html.haml
@@ -4,59 +4,64 @@
- more_colspan = 7
- more_colspan = 6 if @ont_restricted
- %div.click_versions_collapse
+ %div.click_versions_collapse.p-1
= render_alerts_container(AdminController)
- %table#ontology_versions.table.table-sm.table-striped
- %thead
- %tr
- - if @ontology.admin?(session[:user])
- %th.align-middle ID
- %th.align-middle Version
- %th
- = generate_attribute_text("released", "Released")
- %th
- = generate_attribute_text("modificationDate", "Modified")
- %th
- = generate_attribute_text("creationDate", "Uploaded")
- - unless @ont_restricted
- %th.align-middle Downloads
- - if @ontology.admin?(session[:user])
- %th.align-middle Actions
+ = render TableComponent.new(id: 'ontology_versions', stripped: false, borderless: true) do |t|
+ - t.header do |header|
+ - if @ontology.admin?(session[:user])
+ - header.th do
+ %div.align-middle
+ = t('submissions.id')
+ - header.th do
+ %div.align-middle
+ = t('submissions.version')
+ - header.th do
+ = attr_label("modificationDate", t('submissions.modified'), show_tooltip: false)
+ - header.th do
+ = attr_label("creationDate", t('submissions.submitted'), show_tooltip: false)
+ - unless @ont_restricted
+ - header.th do
+ %div.align-middle{style: 'text-align: center; margin-right: 33px;'}
+ = t('submissions.actions')
- - begin
- - submission_ready = @ontology.explore.latest_submission({:include_status => 'ready', display: 'submissionId'})
- - submission_readyId = submission_ready.submissionId unless submission_ready.nil?
- - rescue
- - submission_readyId = -1
- @submissions.each_with_index do |sub, index|
- hidden_row_class = index >= 5 ? "hidden_ont hidden_select" : ""
- %tr{class: "#{hidden_row_class}", id: "submission_#{sub.submissionId}"}
+ - t.row(id:"submission_#{sub.submissionId}" , class_css: hidden_row_class) do |r|
- if @ontology.admin?(session[:user])
- %td
- = sub.submissionId
- %td
- = raw status_link(sub, sub.submissionId==submission_readyId)
- %td
- = xmldatetime_to_date(sub.released) unless sub.released.nil?
- %td
- = xmldatetime_to_date(sub.modificationDate) unless sub.modificationDate.nil?
- %td
- = xmldatetime_to_date(sub.creationDate) unless sub.creationDate.nil?
+ - r.td { raw sub.submissionId }
+ - r.td do
+ = render SubmissionStatusComponent.new(sub, sub.submissionId==submission_ready?(sub))
+ - r.td { render DateTimeFieldComponent.new(value: sub.modificationDate) unless sub.modificationDate.nil? }
+ - r.td { render DateTimeFieldComponent.new(value: sub.creationDate) unless sub.creationDate.nil? }
+
+
- unless @ont_restricted
- %td
- = raw download_link(sub, @ontology)
- - if @ontology.admin?(session[:user])
- %td
+ - r.td do
%div.d-flex
- -#%a.btn.btn-sm.btn-link{:href => "/ontologies/#{@ontology.acronym}/submissions/#{sub.submissionId}/edit", 'data-turbo-frame':"_top"}
- -# %span Edit
- - unless sub.submissionId.eql?(submission_readyId)
- - alert_text = "Are you sure you want to delete submission " + sub.submissionId.to_s + " for ontology " + @ontology.acronym + " ?This action CAN NOT be undone!!! "
- = button_to "Delete", "/admin/ontologies/#{@ontology.acronym}/submissions/#{sub.submissionId}?turbo_stream=true", method: :delete, class:'btn btn-sm btn-link', form: {data: { turbo: true, turbo_confirm: alert_text, turbo_frame: '_top'}}
+ %div.dropdown
+ %button.btn.btn-outline-primary.rounded-pill.dropdown-toggle{type:"button", 'data-toggle':"dropdown", 'aria-expanded': "false", style:'white-space: nowrap; width: 94%;font-size: small;'}
+ = t('submissions.download')
+ %span.sr-only= t('submissions.toggle_dropdown')
+ .dropdown-menu
+ - links = download_link(sub,@ontology)
+ - links.each do |value|
+ - link,label = value.values
+ %a.dropdown-item{ href: link }= label
+
+ -# = raw download_link(sub, @ontology)
+ - if @ontology.admin?(session[:user])
+ %div.d-flex
+ %div{style: 'margin-right: 10px;'}
+ = service_button(link: "#{@ontology.id}/submissions/#{sub.submissionId}?display=all", title: t('submissions.go_to_api'))
+ = edit_button(link: "/ontologies/#{@ontology.acronym}/submissions/#{sub.submissionId}/edit", title: t('submissions.edit_button'))
+ - unless index.zero?
+ - alert_text = t('submissions.delete_submission_alert.content_1') + sub.submissionId.to_s + t('submissions.delete_submission_alert.content_2') + @ontology.acronym + t('submissions.delete_submission_alert.content_3')
+ = button_to "/admin/ontologies/#{@ontology.acronym}/submissions/#{sub.submissionId}?turbo_stream=true", method: :delete, class: 'btn btn-sm btn-link', form: {data: { turbo: true, turbo_confirm: alert_text, turbo_frame: '_top'}} do
+ = inline_svg_tag('icons/delete.svg')
- if @submissions.length > 5
- %tr
- %td{colspan: more_colspan, class: "show_more_subs"}
+ - t.row(class_css: "show_more_subs") do |r|
+ - r.td(colspan: more_colspan) do
%a#version_toggle{:href => ""} more...
:javascript
diff --git a/app/views/submissions/edit.html.haml b/app/views/submissions/edit.html.haml
index 1977ef4b1..848e3da82 100644
--- a/app/views/submissions/edit.html.haml
+++ b/app/views/submissions/edit.html.haml
@@ -1,6 +1,59 @@
-%div.container.py-4.py-md-5
- %h1
- Edit submission information
- %small.text-muted for #{@ontology.acronym}
- = form_for :submission, url: ontology_submission_path(@ontology.acronym, @submission.submissionId), html: { id: "ontology_submission_form", method: :put, multipart: true, 'data-turbo': true } do |f|
- = render partial: "form", locals: {f: f, button_text: "Save submission"}
+- section = params[:section] || 'general'
+.center
+ .edit-ontology-container
+ = turbo_frame_tag(params[:container_id] || 'test') do
+ = form_for :submission, url: ontology_submission_path(@ontology.acronym, params["id"]), html: { id: "ontology_submission_form", method: :put, multipart: true, 'data-turbo': true, 'data-turbo-frame': '_top', novalidate: 'true'} do
+ .edit-ontology-title
+ %div
+ = t('submission_inputs.edit_ontology_title')
+ %hr
+ .edit-ontology-sub-container
+ - if @selected_attributes.empty?
+ .edit-ontology-left-column{:role => "tablist",onchange:"onMetadataChange()"}
+ .edit-ontology-desc
+ = submission_metadata_selector
+ %div.nav.nav-pills.flex-column#categories-tabs
+ - @categories_order.each_with_index do |key, index|
+ %a.edit-ontology-tab-item.d-block{href: "##{key.parameterize}-tab", "data-toggle" => "pill", class: section.eql?(key.parameterize) ? 'active show' : ''}
+ = key.humanize
+
+ #myTabContent.edit-ontology-right-column.w-100
+ = render TurboFrameComponent.new(id:"metadata_by_ontology") do
+ = metadata_help_link
+ %div.tab-content
+ - if @selected_attributes.empty?
+ - @categories_order.each_with_index do |key, index|
+ - properties = @category_attributes[key]
+ .edit-ontology-tab.tab-pane.fade{id: key.parameterize+'-tab', class: section.eql?(key.parameterize) ? 'active show' : ''}
+ = render TurboFrameComponent.new(id: "ontology-content-#{index}", loading:"lazy", src: "edit_properties?properties=#{properties.join(',')}&container_id=ontology-content-#{index}")
+ - else
+ - link = ontology_submission_edit_properties_path(@ontology.acronym, params[:id], properties: @selected_attributes.join(','), container_id: 'ontology-content-0')
+ = render TurboFrameComponent.new(id: "ontology-content-0", loading:"lazy", src: link)
+
+ %hr#edit-ontology-actions-devider
+ .edit-ontology-actions
+ - unless params[:container_id]
+ .cancel-button.mx-2{onClick: 'window.history.back();'}
+ = form_cancel_button
+ .save-button
+ = form_save_button
+
+
+ :javascript
+ function onMetadataChange(){
+ document.querySelector('.edit-ontology-tab-item.d-block.active.show')?.classList.remove('active', 'show')
+ document.querySelector('.edit-ontology-tab.tab-pane.fade.active.show')?.classList.remove('active', 'show')
+ document.getElementById('categories-tabs')?.classList.add('disabled')
+
+ let frame = document.getElementById('metadata_by_ontology')
+ let properties = document.getElementById('select_search_metadata')
+
+ let selectedProperties = "all"
+ if(properties && properties.selectedOptions.length > 0){
+ selectedProperties = Array.from(properties.selectedOptions).map(({ value }) => value).join(',')
+ frame.src = "./edit_properties?properties=" + selectedProperties
+ } else {
+ Turbo.visit(location.href)
+ }
+
+ }
diff --git a/app/views/submissions/index.html.haml b/app/views/submissions/index.html.haml
index d31fd94d2..df4cbe078 100644
--- a/app/views/submissions/index.html.haml
+++ b/app/views/submissions/index.html.haml
@@ -1 +1 @@
-= render partial: "submissions", locals: {id: 'ontology_submissions'}
\ No newline at end of file
+= render partial: "submissions", locals: {id: params['container_id'] || 'ontology_submissions'}
\ No newline at end of file
diff --git a/app/views/submissions/new.html.haml b/app/views/submissions/new.html.haml
deleted file mode 100644
index c4871177c..000000000
--- a/app/views/submissions/new.html.haml
+++ /dev/null
@@ -1,9 +0,0 @@
-- @title = "Add new ontology submission"
-
-%div.container.py-4.py-md-5
- %h1
- Add new submission
- - if !(@submission.ontology.nil? || (@submission.ontology.is_a? String))
- %small.text-muted for #{@submission.ontology.acronym}
- = form_for :submission, url: {action: "create"}, html: {id: "ontology_submission_form", multipart: true, 'data-turbo': true} do |f|
- = render partial: "form", locals: {f: f, button_text: "Add submission"}
diff --git a/app/views/users/_form.html.haml b/app/views/users/_form.html.haml
index 2b1e13d4c..3a2f38b52 100644
--- a/app/views/users/_form.html.haml
+++ b/app/views/users/_form.html.haml
@@ -5,49 +5,60 @@
%img.lost-password-arrowback{:src => "#{asset_path("arrow-back.svg")}"}
.register-title-container
%h2.register-title
- Create a new account
+ = t('register.create_account')
%hr#register-title-line/
%div
.register-double-input
.register-first-input
%p.register-input-title
- First name
+ = t('register.first_name')
%font{:color => "red"} *
- = text_field :user, :firstName, value: @user.firstname, class: "register-input-short"
+ = text_field :user, :firstName, value: @user.firstName, class: "register-input-short"
%div
%p.register-input-title
- Last name
+ = t('register.last_name')
%font{:color => "red"} *
- = text_field :user, :lastName, value: @user.lastname, class: "register-input-short"
+ = text_field :user, :lastName, value: @user.lastName, class: "register-input-short"
%p.register-input-title
- Username
+ = t('register.username')
%font{:color => "red"} *
= text_field :user, :username, value: @user.username, class: "register-input-long"
%p.register-input-title
ORCID ID
- %font.register-optional (optional)
+ %font.register-optional
+ = t('register.optional')
%img.register-input-icon{:src => "#{asset_path("orcid.svg")}"}/
= text_field :user, :orcidId, value: @user.orcidId, class: "register-input-long register-input-with-icon"
%p.register-input-title
Github ID
- %font.register-optional (optional)
+ %font.register-optional
+ = t('register.optional')
%img.register-input-icon{:src => "#{asset_path("github-icon.svg")}"}/
= text_field :user, :githubId, value: @user.githubId, class: "register-input-long register-input-with-icon"
%p.register-input-title
- Email
+ = t('register.email')
%font{:color => "red"} *
= text_field :user, :email, value: @user.email, class: "register-input-long"
%p.register-input-title
- Password
+ = t('register.password')
%font{:color => "red"} *
= password_field :user, :password, class: "register-input-long"
%p.register-input-title
- Confirm password
+ = t('register.confirm_password')
%font{:color => "red"} *
= password_field :user, :password_confirmation, class: "register-input-long"
- if using_captcha?
= recaptcha_tags
.d-flex
- %input#user_register_mail_list{:checked => "checked", :name => "user[register_mail_list]", :type => "checkbox", :value => "1"}/
- %p#register-check-text Register for the Ecoportal's mailing list
- %input.register-button{:type => "submit", :value => "Register"}/
+ %input.user_register_checkbox{:checked => "checked", :name => "user[register_mail_list]", :type => "checkbox", :value => "1"}/
+ %p#register-check-text
+ = t('register.mailing_list', site: portal_name)
+ .d-flex
+ %input.user_register_checkbox{:name => "user[terms_and_conditions]", :type => "checkbox"}/
+ %p#register-check-text
+ = t('register.accept_terms_and_conditions')
+ %a{href: $TERMS_AND_CONDITIONS_LINK, target: '_blank'}
+ = t('register.terms_and_conditions', site: portal_name)
+ %font{:color => "red"} *
+ .register-button-container
+ = render Buttons::RegularButtonComponent.new(id: 'register-button', value: "Register", type:'submit')
diff --git a/app/views/users/edit.html.haml b/app/views/users/edit.html.haml
index da8327ff0..d00e8c61b 100644
--- a/app/views/users/edit.html.haml
+++ b/app/views/users/edit.html.haml
@@ -7,7 +7,7 @@
event.preventDefault()
let admin_checkbox = jQuery('input[id=user_admin]')
if(admin_checkbox.attr('checked') && !admin_checkbox.hasClass('admin')){
- alertify.confirm('Are you sure you want to make this user an admin?', (e) => {
+ alertify.confirm(t('users.edit.user_to_admin'), (e) => {
if(e){
this.submit()
}else {
@@ -15,7 +15,7 @@
}
})
} else if (!admin_checkbox.attr('checked') && admin_checkbox.hasClass('admin')){
- alertify.confirm('Are you sure you want to revoke admin privileges for this user?', (e) => {
+ alertify.confirm(t('users.edit.admin_privileges'), (e) => {
if(e){
this.submit()
}else {
@@ -62,7 +62,7 @@
= form_for(:user, :url => user_path(@user.username), :html => { :id => "user_info", :method => :put }) do |f|
- unless @errors.nil?
.enable-lists{:style => "color: red; padding: 1em;"}
- Errors creating your account:
+ = t('users.edit.errors_creating_account')
%ul
- for error in @errors
%li= error
@@ -73,36 +73,36 @@
%img.lost-password-arrowback{:src => "#{asset_path("arrow-back.svg")}"}
.register-title-container
%h2.register-title
- Edit personal information
+ = t('users.edit.edit_information')
%hr#register-title-line/
%div
- if @user.validate_password.nil?
.register-double-input
.register-first-input
%p.register-input-title
- First name
+ = t('users.edit.first_name')
%font{:color => "red"} *
= text_field :user, :firstName, value: @user.firstName, class: "register-input-short"
%div
%p.register-input-title
- Last name
+ = t('users.edit.last_name')
%font{:color => "red"} *
= text_field :user, :lastName, value: @user.lastName, class: "register-input-short"
%p.register-input-title
- Username
+ = t('users.edit.username')
%font{:color => "red"} *
= text_field :user, :username, value: @user.username, class: "register-input-long"
%p.register-input-title
- Email
+ = t('users.edit.email')
%font{:color => "red"} *
= text_field :user, :email, value: @user.email, class: "register-input-long"
%p.register-input-title
- ORCID ID
+ = t('users.edit.orcid_id')
%font.register-optional (optional)
%img.register-input-icon{:src => "#{asset_path("orcid.svg")}"}/
= text_field :user, :orcidId, value: @user.orcidId, class: "register-input-long register-input-with-icon"
%p.register-input-title
- Github ID
+ = t('users.edit.github_id')
%font.register-optional (optional)
%img.register-input-icon{:src => "#{asset_path("github-icon.svg")}"}/
= text_field :user, :githubId, value: @user.githubId, class: "register-input-long register-input-with-icon no-margin"
@@ -116,17 +116,17 @@
= hidden_field :user, :lastName, value: @user.lastName
= hidden_field :user, :email, value: @user.email
%p.register-input-title
- New password
+ = t('users.edit.new_password')
%font{:color => "red"} *
= password_field :user, :password, class: "register-input-long"
%p.register-input-title
- Confirm password
+ = t('users.edit.confirm_password')
%font{:color => "red"} *
= password_field :user, :password_confirmation, class: "register-input-long"
%br
- %input.register-button{:type => "submit", :value => "Save", :name => "Update"}/
+ = render Buttons::RegularButtonComponent.new(id: 'update-button', value: "Save", type:'submit')
- unless params[:password].eql?("true")
.change-password
%a{:href => edit_user_path(@user.username, password: true)}
- Change password
\ No newline at end of file
+ = t('users.edit.change_password')
\ No newline at end of file
diff --git a/app/views/users/index.html.haml b/app/views/users/index.html.haml
new file mode 100644
index 000000000..20a3c0bdb
--- /dev/null
+++ b/app/views/users/index.html.haml
@@ -0,0 +1,40 @@
+= turbo_frame_tag 'users-list' do
+ %div.my-1
+ = render_alerts_container
+ .d-flex.justify-content-end.my-1
+ = rounded_button_component("#{$REST_URL}/users?display=all&apikey=#{get_apikey}")
+
+ = render TableComponent.new(id: 'admin_users', custom_class: 'border rounded p-1', searching: true, paging: true, sort_column: '7') do |t|
+ - t.header do |h|
+ - h.th {t('users.index.first_name')}
+ - h.th {t('users.index.last_name')}
+ - h.th {t('users.index.username')}
+ - h.th {t('users.index.email')}
+ - h.th {t('users.index.roles')}
+ - h.th {t('users.index.ontologies')}
+ - h.th {t('users.index.project')}
+ - h.th {t('users.index.created')}
+ - h.th {t('users.index.actions')}
+ - @users.each do |user|
+ - t.row(id: user.id.split('/').last) do |r|
+ - r.td {user.firstName}
+ - r.td {user.lastName}
+ - r.td {user.username}
+ - r.td {user.email}
+ - r.td {user.role.join(', ')}
+ - r.td {(user.ontologies&.size || 0).to_s}
+ - r.td {(user.projects&.size || 0).to_s}
+ - r.td {Date.parse(user.created).to_s}
+ - r.td do
+ - count = (user.ontologies&.size || 0) + (user.projects&.size || 0)
+ %div.d-flex.align-items-center{style: 'min-width: 200px'}
+ %span
+ = link_to t('users.index.detail'), user_path(user.id.split('/').last), {data: {turbo_frame: '_top'}}
+ %span
+ - if count.zero?
+ = button_to t('users.index.delete'), user_path(user.id.split('/').last), method: :delete, class: 'btn btn-link', form: {data: { turbo: true, turbo_confirm: t('users.index.turbo_confirm'), turbo_frame: '_top'}}
+ - else
+ %span{data: { controller: 'tooltip' }, title:t('users.index.error_delete_message')}
+ = link_to t('users.index.delete'), "", class: 'btn btn-link disabled'
+ %span
+ = link_to t('users.index.login_as'), "login_as/#{user.username}", {data: {turbo_frame: '_top'}}
\ No newline at end of file
diff --git a/app/views/users/new.html.haml b/app/views/users/new.html.haml
index 95b41374e..cb42a4ac0 100644
--- a/app/views/users/new.html.haml
+++ b/app/views/users/new.html.haml
@@ -1,9 +1,10 @@
-- @title = "Register"
+- @title = t('register.title')
= form_for(:user, :url => users_path) do |f|
- unless @errors.nil?
- .enable-lists{:style => "color: red; padding: 1em;"}
- Errors creating your account:
- %ul
- - for error in @errors
- %li= error
+ .d-flex.justify-content-center.mt-4
+ = render Display::AlertComponent.new(type: "danger", closable: false) do
+ = t('register.account_errors')
+ %ul.mb-0
+ - for error in @errors
+ %li= error.is_a?(Array) ? error.last : error
= render :partial => 'form', :locals => {:f => f}
diff --git a/app/views/users/show.html.haml b/app/views/users/show.html.haml
index 96e462eb1..3c4f28597 100644
--- a/app/views/users/show.html.haml
+++ b/app/views/users/show.html.haml
@@ -1,78 +1,76 @@
.account-page-center
.account-page-container
- %h3.account-page-title My account
+ %h3.account-page-title= t('users.show.my_account')
%hr#account-page-title-line/
.account-page-sub-container
.account-page-first-row
.account-page-card
.account-page-personal-informations-title-bar
- %h4.account-page-card-title Personal information
+ %h4.account-page-card-title Personal Information
%a.account-page-rounded-button{:href => edit_user_path(url_encode(@user.username))}
= render partial: "shared/svgs/edit_icon"
.account-page-info-column
- %p.title First name:
+ %p.title= t('users.show.first_name')
%p.info
= @user.firstName
.account-page-info-column
- %p.title Last name:
+ %p.title= t('users.show.last_name')
%p.info
= @user.lastName
.account-page-info-column
- %p.title Email address:
+ %p.title= t('users.show.email')
%p.info
= @user.email
.account-page-info-column
- %p.title Username:
+ %p.title= t('users.show.username')
%p.info
= @user.username
.account-page-info-column
- %p.title ORCID ID:
+ %p.title= t('users.show.orcid_id')
%p.info
=@user.orcidId
.account-page-info-column
- %p.title Github ID:
+ %p.title= t('users.show.github_id')
%p.info
=@user.githubId
.account-page-card
.account-page-card-container
.account-page-card-sub-container
- %h4.account-page-card-title Mailing list subscription
- %p.account-page-card-desc #{$SITE} announcements email list
+ %h4.account-page-card-title= t('users.show.mailing_list_subscription')
+ %p.account-page-card-desc= t('users.show.mailing_list_description', portal: portal_name)
- subscribed = false
- - if subscribed
- %a.btn.btn-primary{:href =>"mailto:#{$ANNOUNCE_SERVICE_HOST}?Subject=unsubscribe%20#{$ANNOUNCE_LIST}"}
- Unsubscribe
+ - if subscribed
+ %a.account-page-subscribe-button{:href =>"mailto:#{$ANNOUNCE_SERVICE_HOST}?subject=unsubscribe%20#{$ANNOUNCE_LIST}"}
+ = t('users.show.unsubscribe')
- else
- %a.btn.btn-primary{:href => "mailto:#{$ANNOUNCE_SERVICE_HOST}?Subject=subscribe%20#{$ANNOUNCE_LIST}%20#{@user.firstName}%20#{@user.lastName}"}
- Subscribe
+ %a.account-page-subscribe-button{:href => "mailto:#{$ANNOUNCE_SERVICE_HOST}?subject=subscribe%20#{$ANNOUNCE_LIST}%20#{@user.firstName}%20#{@user.lastName}"}
+ = t('users.show.subscribe')
.account-page-card
.account-page-card-container
.account-page-card-sub-container
%h4.account-page-card-title API Key
- %p.account-page-card-desc Your API Key can be used to access the NCBO API (REST) Services
- %p.apikey
- = session[:user].apikey
- %a{:href => "javascript:navigator.clipboard.writeText('"+session[:user].apikey+"');"}
- = render partial: "shared/svgs/copy_icon"
+ %p.account-page-card-desc
+ = t('users.show.api_key_description', portal: portal_name)
+ %div.apikey
+ = render ClipboardComponent.new(message: session[:user].apikey)
.account-page-api-documentation-link
- %a{href: "#{$REST_URL.chomp('/')}/documentation", target: "_blank"}
- API documentation
+ %a{href: "#{$REST_URL}/documentation", target: "_blank"}
+ = t('users.show.api_documentation')
= render partial: "shared/svgs/external_link_icon"
.account-page-card
%h4.account-page-card-title
- Custom semantic resource set
+ = t('users.show.custom_semantic_resource')
#custom_ontologies.enable-lists
- if at_slice?
%p{style: "padding-left: 7px; font-size: 10pt; margin: -3px 0 7px;"}
- Please
- %a{href: "#{$UI_URL}/account"} visit the main site
- to modify your Custom semantic resource set.
+ = t('users.show.please')
+ %a{href: "#{$UI_URL}/account"}= t('users.show.modify_custom_semantic_resource')
- else
%p.account-page-card-desc
- Customize your #{$SITE} display: pick the semantic resources that you want to see on #{$SITE}. Pay attention: this will hide all other Semantic Resources.
+ = t('users.show.customize_portal_display', portal: portal_name)
%p
%span{style: "font-weight: normal; font-size: 9pt; padding-left: 7px;"}
- %a#edit_custom_ontologies{href: "javascript:void(0);"} Select semantic resources
+ %a#edit_custom_ontologies{href: "javascript:void(0);"}= t('users.show.select_semantic_resources')
- if @user_ontologies && !@user_ontologies.empty?
%ul
- @user_ontologies.each do |ont|
@@ -80,17 +78,19 @@
%li
#{ont.name} (#{ont.acronym})
- else
- %p{style: "padding-left: 7px;"} You haven't picked any Semantic Resources yet.
+ %p{style: "padding-left: 7px;"}= t('users.show.no_semantic_resources')
+ %p.account-page-card-desc= t('users.show.note_feature_logged_in')
#custom_ontologies_picker{style: "left: -9999px; position: absolute;"}
= form_tag custom_ontologies_path(url_encode(@user.username)) do
- selected = @user.customOntology.map {|o| LinkedData::Client::Models::Ontology.get(o).acronym}
- - locals = { custom_ontologies: @all_ontologies, selected_ontologies: selected, sel_text: "Select Custom Semantic Resources" }
- = render partial: "shared/ontology_picker", locals: locals
- = submit_tag "Save custom semantic resources", class: "bnt btn-primary"
+ = ontologies_selector(id:'account_page_ontologies_selector' ,name: 'ontologies', selected: selected)
+ = submit_tag t('users.show.save_custom_semantic_resources'), class: "link_button"
.account-page-second-row
- - unless @user.subscription.nil? || @user.subscription.empty?
- .account-page-card
- %h4.account-page-card-title Subscriptions
+ .account-page-card
+ %h4.account-page-card-title= t('users.show.subscriptions')
+ - if @user.subscription.nil? || @user.subscription.empty?
+ = t('users.show.not_subscribed')
+ - else
- @user.subscription.each do |subscription|
- ont_id = subscription[:ontology]
- ont = (!subscription[:ontology].nil? ? subscription[:ontology].split('/').last: nil) # ensure we get the acronym
@@ -99,33 +99,37 @@
%a{:href => "/ontologies/#{ont}?p=notes"}= ont
%div
- if type == "notes"
- %a.notes{:href => "/ontologies/#{ont}?p=notes"} Notes
+ %a.notes{:href => "/ontologies/#{ont}?p=notes"}= t('users.show.notes')
- else
= type
= subscribe_button(ont_id)
- - no_ontologies = true
- - unless @admin_ontologies.nil? || @admin_ontologies.empty?
- - no_ontologies = false
- .account-page-card
- %h4.account-page-card-title Submitted semantic resources
- .account-page-small-cards-container
+ .account-page-card
+ %h4.account-page-card-title= t('users.show.submitted_semantic_resources')
+ .account-page-small-cards-container
+ - if @admin_ontologies.nil? || @admin_ontologies.empty?
+ .account-page-no-ontology.w-100
+ %img{:src => "#{asset_path("empty-box.svg")}"}/
+ %p= t('users.show.no_uploaded_resources')
+ %a.account-page-upload-ontology-button{href: "/ontologies/new"}= t('users.show.upload_semantic_resources')
+ - else
- @admin_ontologies.each do |ont|
- .account-page-submitted-ontology
- %a{href: "/ontologies/#{ont.acronym}"}= ont.name
- - unless @user_projects.nil? || @user_projects.empty?
- - no_ontologies = false
- .account-page-card
- %h4.account-page-card-title Projects Created
- .account-page-small-cards-container
+ .account-page-submitted-ontology{data: {controller: 'tooltip'}, title: ont.name}
+ %a{href: "/ontologies/#{ont.acronym}"}= ont.acronym
+ - unless ont.views.nil? || ont.views.empty?
+ - ont.views.each do |view|
+ .account-page-submitted-ontology{data: {controller: 'tooltip'}, title: ont.name}
+ %a{href: "/ontologies/#{view.match(/\/([^\/]+)$/)[1]}"}= view.match(/\/([^\/]+)$/)[1]
+
+ .account-page-card
+ %h4.account-page-card-title= t('users.show.projects_created')
+ .account-page-small-cards-container
+ - if @user_projects.nil? || @user_projects.empty?
+ = t('users.show.no_project_created')
+ - else
- @user_projects.each do |project|
.account-page-submitted-ontology
%a{href: "/projects/#{project.acronym}"}= project.name
- - if no_ontologies
- .account-page-card
- .account-page-no-ontology
- %img{:src => "#{asset_path("empty-box.svg")}"}/
- %p You didn't upload any semantic resources yet
- %a.account-page-upload-ontology-button{href: "/ontologies/new"} Upload Semantic Resource
+
:javascript
jQuery(document).ready(function(){
jQuery("#edit_custom_ontologies").click(editCustomOntologies);
diff --git a/app/views/virtual_appliance/index.html.haml b/app/views/virtual_appliance/index.html.haml
index 7e13ec310..867d25c02 100644
--- a/app/views/virtual_appliance/index.html.haml
+++ b/app/views/virtual_appliance/index.html.haml
@@ -1,23 +1,19 @@
--@title = "OntoPortal Virtual Appliance Download"
+-@title = t("ontoportal_virtual_appliance.title")
%div{:style => "padding: 13px; max-width: 800px;", :class => "enable-lists"}
- %h1 OntoPortal Virtual Appliance Download
- %p
- OntoPortal Virtual Appliance distribution contains a pre-installed,
- pre-configured version of commonly-used open source NCBO software running
- on a Linux operating system.
- %p The following software is included on the image:
+ %h1= t("ontoportal_virtual_appliance.title")
+ %p= t("ontoportal_virtual_appliance.intro_paragraph.main")
+ %p= t("ontoportal_virtual_appliance.included_software")
%ul
- %li Ontologies API (REST service)
- %li Annotator
- %li Recommender
- %li BioPortal Web User Interface (including ontology visualization, widgets, and Annotator UI)
+ %li= t("ontoportal_virtual_appliance.ontologies_api")
+ %li= t("ontoportal_virtual_appliance.annotator")
+ %li= t("ontoportal_virtual_appliance.recommender")
+ %li= t("ontoportal_virtual_appliance.web_user_interface")
%p
- Please see our
+ = t("ontoportal_virtual_appliance.see_documentation")
=link_to 'documentation', 'https://ontoportal.github.io/administration/steps/getting_started/', target: '_blank'
- for more information on working with the Appliance.
- %h2 Download Latest OntoPortal
- %ul
+ = t("ontoportal_virtual_appliance.more_information")
+ %h2= t("ontoportal_virtual_appliance.download_button_text")
%li
Version 3.1.1
OVA
@@ -55,33 +51,30 @@
Amazon EC2
-if @virtual_appliance_access
- %h3 Archives
- %p
- The OntoPortal 2.5 Virtual Appliance is not longer offered for new
- users. This archival distribution is available only as a backup for
- those who registered for the Appliance before June 2020
+ %h3= t("ontoportal_virtual_appliance.archives.title")
+ %p= t("ontoportal_virtual_appliance.archives.archival_distribution")
%ul
%li
- Version 2.5
+ = t("ontoportal_virtual_appliance.archives.version")
=link_to 'OVF', 'https://www.bioontology.org/ontoportal-appliance/ontoportal-2.5.zip'
-if @user.admin?
%div{:style => "margin: 2em 0 0; padding: 1em 1em; border: solid thin gray; background-color: lightGray;"}
- %h1{:style => "margin-bottom: 15px;"} Admin: Add Users
+ %h1{:style => "margin-bottom: 15px;"}= t("ontoportal_virtual_appliance.admin_add_users.title")
=form_for :appliance_user do |f|
- = f.label :user_id, "Account Name: "
+ = f.label :user_id, t("ontoportal_virtual_appliance.admin_add_users.label_account_name")
= f.text_field :user_id
- = f.submit "Add User"
+ = f.submit t("ontoportal_virtual_appliance.admin_add_users.add_user_button")
%h2{:style => "margin-top: 1em;"}
- Accounts with access
+ = t("ontoportal_virtual_appliance.admin_add_users.accounts_with_access")
%a#export{href: "#", style: "margin-left: 2em; margin-top: -1em; font-size: 11px;"}
- Export Appliance Users As CSV
+ = t("ontoportal_virtual_appliance.admin_add_users.export_users_link")
%table#user_table.zebra{style: "border: thin lightGray solid; background-color: white;"}
%thead
%tr
- %th BioPortal User ID
+ %th= t("ontoportal_virtual_appliance.admin_add_users.bioportal_user")
%tbody
-@va_users.each do |u|
%tr
diff --git a/app/views/visits/index.html.haml b/app/views/visits/index.html.haml
index ee7e1cee1..57da2545c 100644
--- a/app/views/visits/index.html.haml
+++ b/app/views/visits/index.html.haml
@@ -1,16 +1,15 @@
-%div.container.pb-3.pb-md-4
-
- %h1.mt-5
- Ontology Visits
- %small.text-muted (#{@analytics.date.strftime("%B %Y")})
+%div.px-3.py-3.pt-md-5.pb-md-4.text-center
+ %h1.display-4
+ = t('visits.ontology_visits')
+ %p.lead (#{@analytics.date.strftime("%B %Y")})
%div.table-responsive
%table.table.table-hover
%thead.thead-light
%tr
%th #
- %th name
- %th # visits
+ %th= t('visits.name')
+ %th= t('visits.visits')
%tbody
- count = 0
- @analytics.onts.each do |visits|
diff --git a/config/bioportal_config_test.rb b/config/bioportal_config_test.rb
new file mode 100644
index 000000000..44169096b
--- /dev/null
+++ b/config/bioportal_config_test.rb
@@ -0,0 +1,224 @@
+# frozen_string_literal: true
+
+$SITE = 'Testportal'
+$HOSTNAME = 'testportal'
+$UI_HOSTNAME = 'localhost'
+$UI_URL = "http://#{$UI_HOSTNAME}:3000"
+
+$API_KEY = ENV['API_KEY']
+$REST_URL = ENV['API_URL']
+$BIOMIXER_URL = ENV['BIOMIXER_URL']
+$ANNOTATOR_URL = $PROXY_URL = ENV['ANNOTATOR_URL']
+$FAIRNESS_URL = ENV['FAIRNESS_URL']
+
+# Resource term
+$RESOURCE_TERM = ENV['RESOURCE_TERM'] || 'ontology'
+
+# config/initializers/omniauth_providers.rb
+$OMNIAUTH_PROVIDERS = {
+ github: {
+ client_id: 'CLIENT_ID',
+ client_secret: 'CLIENT_SECRET',
+ icon: 'github.svg',
+ enable: true
+ },
+ google: {
+ strategy: :google_oauth2,
+ client_id: 'CLIENT_ID',
+ client_secret: 'CLIENT_SECRET',
+ icon: 'google.svg',
+ enable: true
+ },
+ orcid: {
+ client_id: 'CLIENT_SECRET',
+ client_secret: 'CLIENT_SECRET',
+ icon: 'orcid.svg',
+ enable: false
+ },
+ keycloak: {
+ strategy: :keycloak_openid,
+ client_id: 'YOUR_KEYCLOAK_CLIENT_ID',
+ client_secret: 'YOUR_KEYCLOAK_CLIENT_SECRET',
+ client_options: { site: 'KEYCLOAK_SITE', realm: 'KEYCLOAK_REALM' },
+ name: 'keycloak',
+ icon: 'keycloak.svg',
+ enable: false
+ }
+}.freeze
+
+$INTERPORTAL_HASH = {}
+
+# If your BioPortal installation includes Fairness score set this to true
+$FAIRNESS_DISABLED = false
+
+# Pairing a name with an array of ontology virtual ids will allow you to filter ontologies based on a subdomain.
+# If your main UI is hosted at example.org and you add custom.example.org pointing to the same Rails installation
+# you could filter the ontologies visible at custom.example.org by adding this to the hash: "custom" => { :name => "Custom Slice", :ontologies => [1032, 1054, 1099] }
+# Any number of slices can be added. Groups are added automatically using the group acronym as the subdomain.
+$ENABLE_SLICES = false
+$ONTOLOGY_SLICES = {}
+
+# Cube metrics reporting
+$ENABLE_CUBE = false
+
+$NOT_DOWNLOADABLE = {}
+# Enable client request caching
+$CLIENT_REQUEST_CACHING = true
+
+# If you don't use Airbrake you can have exceptions emailed to the $ERROR_EMAIL address by setting this to 'true'
+$EMAIL_EXCEPTIONS = false
+
+# Announcements mailman mailing list REQUEST address, EX: list-request@lists.example.org
+# NOTE: You must use the REQUEST address for the mailing list. ONLY WORKS WITH MAILMAN LISTS.
+$ANNOUNCE_LIST ||= 'appliance-users-request@localhost'
+
+# Email addresses used for sending notifications (errors, feedback, support)
+$SUPPORT_EMAIL ||= 'support@localhost'
+$ADMIN_EMAIL ||= 'admin@localhost'
+$ERROR_EMAIL ||= 'errors@localhost'
+
+# Custom BioPortal logging
+require 'log'
+$REMOTE_LOGGING = false
+
+##
+# Custom Ontology Details
+# Custom details can be added on a per ontology basis using a key/value pair as columns of the details table
+#
+# Example:
+# $ADDITIONAL_ONTOLOGY_DETAILS = { 1000 => { "Additional Detail" => "Text to be shown in the right-hand column." } }
+##
+$ADDITIONAL_ONTOLOGY_DETAILS = {}
+
+# Site notice appears on all pages and remains closed indefinitely. Stored below as a hash with a unique key and a
+# EX: $SITE_NOTICE = { :unique_key => 'Put your message here (can include html if you use
+$SITE_NOTICE = {}
+################################
+## AUTO-GENERATED DO NOT MODIFY
+#################################
+
+# Full string for site, EX: "NCBO BioPortal"
+$ORG_SITE = $ORG.nil? || $ORG.empty? ? $SITE : "#{$ORG} #{$SITE}"
+
+$HOME_PAGE_LOGOS = [
+ {
+ img_src: 'logos/supports/numev.png',
+ url: 'http://www.lirmm.fr/numev',
+ target: '_blank'
+ },
+ {
+ img_src: 'logos/supports/anr.png',
+ url: 'https://anr.fr/en',
+ target: '_blank'
+ },
+ {
+ img_src: 'logos/supports/eu.png',
+ url: 'https://commission.europa.eu/research-and-innovation_en',
+ target: '_blank'
+ },
+ {
+ img_src: 'logos/collaboration/d2kab.png',
+ url: 'http://d2kab.mystrikingly.com',
+ target: '_blank'
+ },
+ {
+ img_src: 'logos/collaboration/lirmm.png',
+ url: 'http://www.lirmm.fr',
+ target: '_blank'
+ },
+ {
+ img_src: 'logos/collaboration/inrae.png',
+ url: 'https://www.inrae.fr/enm',
+ target: '_blank'
+ },
+ {
+ img_src: 'logos/collaboration/stanford.png',
+ url: 'https://www.stanford.edu',
+ target: '_blank'
+ }
+]
+
+$FOOTER_LINKS = {
+ social: [
+ { logo: 'social/people.svg', link: 'https://github.com/orgs/agroportal/people' },
+ { logo: 'social/github.svg', link: 'https://github.com/agroportal' },
+ { logo: 'social/twitter.svg', link: 'https://twitter.com/lagroportal' }
+ ],
+ sections: {
+ products: {
+ ontoportal: 'https://ontoportal.org/',
+ release_notes: 'https://doc.jonquetlab.lirmm.fr/share/e6158eda-c109-4385-852c-51a42de9a412/doc/release-notes-btKjZk5tU2',
+ api: 'https://data.agroportal.lirmm.fr/',
+ sparql: 'https://sparql.agroportal.lirmm.fr/test/'
+ },
+ support: {
+ contact_us: 'https://agroportal.lirmm.fr/feedback',
+ wiki: 'https://www.bioontology.org/wiki/',
+ documentation: 'https://ontoportal.github.io/documentation/'
+ },
+ agreements: {
+ terms: '',
+ privacy_policy: '',
+ cite_us: '',
+ acknowledgments: ''
+ },
+ about: {
+ about_us: 'https://github.com/agroportal/project-management',
+ projects: 'https://d2kab.mystrikingly.com/',
+ team: 'https://github.com/orgs/agroportal/people'
+ }
+ }
+}
+
+$PORTALS_INSTANCES = [
+ {
+ color: '#31b403',
+ portal: 'AgroPortal',
+ link: 'https://agroportal.lirmm.fr/'
+ },
+ {
+ color: '#234979',
+ portal: 'BioPortal',
+ link: 'https://bioportal.bioontology.org/'
+ },
+ {
+ color: '#74a9cb',
+ portal: 'SIFR BioPortal',
+ link: 'https://bioportal.lirmm.fr/'
+ },
+ {
+ color: '#0d508a',
+ portal: 'EcoPortal',
+ link: 'https://ecoportal.lifewatch.eu/'
+ },
+ {
+ color: '#234979',
+ portal: 'MedPortal',
+ link: 'http://medportal.bmicc.cn/'
+ },
+ {
+ color: '#009574',
+ portal: 'MatPortal',
+ link: 'https://matportal.org/'
+ },
+ {
+ color: '#1c0f5d',
+ portal: 'IndustryPortal',
+ link: 'http://industryportal.enit.fr'
+ },
+ {
+ color: '#1e2251',
+ portal: 'EarthPortal',
+ link: 'https://earthportal.eu/'
+ },
+ {
+ color: '#33691B',
+ portal: 'BiodivPortal',
+ link: 'https://biodivportal.gfbio.org/'
+ }
+]
+
+$UI_THEME = :stageportal
+if File.exist?('config/bioportal_config_development_testportal.lirmm.fr.rb')
+ require_relative 'bioportal_config_development_testportal.lirmm.fr' # local credentials
+end
\ No newline at end of file
diff --git a/config/deploy/staging.rb b/config/deploy/staging.rb
new file mode 100644
index 000000000..47b158aec
--- /dev/null
+++ b/config/deploy/staging.rb
@@ -0,0 +1,17 @@
+# Simple Role Syntax
+# ==================
+# Supports bulk-adding hosts to roles, the primary
+# server in each group is considered to be the first
+# unless any hosts have the primary property set.
+# Don't declare `role :all`, it's a meta role
+role :app, %w{stageportal.lirmm.fr}
+role :db, %w{stageportal.lirmm.fr} # sufficient to run db:migrate only on one system
+set :branch, ENV.include?('BRANCH') ? ENV['BRANCH'] : 'stage'
+# Extended Server Syntax
+# ======================
+# This can be used to drop a more detailed server
+# definition into the server list. The second argument
+# something that quacks like a hash can be used to set
+# extended properties on the server.
+#server 'example.com', user: 'deploy', roles: %w{web app}, my_property: :my_value
+set :log_level, :error
diff --git a/config/deploy/test.rb b/config/deploy/test.rb
new file mode 100644
index 000000000..fcbe1efce
--- /dev/null
+++ b/config/deploy/test.rb
@@ -0,0 +1,17 @@
+# Simple Role Syntax
+# ==================
+# Supports bulk-adding hosts to roles, the primary
+# server in each group is considered to be the first
+# unless any hosts have the primary property set.
+# Don't declare `role :all`, it's a meta role
+role :app, %w{testportal.lirmm.fr}
+role :db, %w{testportal.lirmm.fr} # sufficient to run db:migrate only on one system
+# Extended Server Syntax
+# ======================
+# This can be used to drop a more detailed server
+# definition into the server list. The second argument
+# something that quacks like a hash can be used to set
+# extended properties on the server.
+#server 'example.com', user: 'deploy', roles: %w{web app}, my_property: :my_value
+set :log_level, :error
+set :branch, ENV.include?('BRANCH') ? ENV['BRANCH'] : 'test'
diff --git a/package.json b/package.json
index d112843e7..392e650aa 100644
--- a/package.json
+++ b/package.json
@@ -4,11 +4,25 @@
"dependencies": {
"@hotwired/stimulus": "^3.0.1",
"@hotwired/turbo-rails": "^7.1.1",
+ "@triply/yasgui": "^4.2.28",
+ "chart.js": "^4.4.1",
+ "d3": "^7.8.5",
+ "datatables.net-dt": "^1.13.8",
+ "debounce": "^1.2.1",
"esbuild": "^0.14.41",
"flatpickr": "^4.6.13",
+ "highlight.js": "^11.9.0",
+ "jsonld": "^8.3.2",
"split.js": "^1.6.5",
"stimulus-flatpickr": "^3.0.0-0",
- "stimulus-rails-nested-form": "^4.0.0"
+ "stimulus-rails-nested-form": "^4.0.0",
+ "stimulus-read-more": "^4.1.0",
+ "stimulus-timeago": "^4.1.0",
+ "tippy.js": "^6.3.7",
+ "tom-select": "^2.2.2",
+ "vis-data": "^7.1.6",
+ "vis-network": "^9.1.6",
+ "vis-util": "^5.0.3"
},
"scripts": {
"build": "esbuild app/javascript/*.* --bundle --sourcemap --outdir=app/assets/builds"
diff --git a/vendor/assets/javascripts/ajax-chosen.js b/vendor/assets/javascripts/ajax-chosen.js
deleted file mode 100644
index 8d9b4ae5b..000000000
--- a/vendor/assets/javascripts/ajax-chosen.js
+++ /dev/null
@@ -1,164 +0,0 @@
-
-/*
-ajax-chosen
-A complement to the jQuery library Chosen that adds ajax autocomplete
-Contributors:
-https://github.com/jobvite/ajax-chosen
-https://github.com/bicouy0/ajax-chosen
-*/
-
-(function() {
-
- (function($) {
- return $.fn.ajaxChosen = function(options, callback) {
- var clickSelector, container, defaultedOptions, field, inputSelector, multiple, search, select, currentSearchId,
- _this = this;
- defaultedOptions = {
- minLength: 3,
- queryLimit: 10,
- delay: 100,
- chosenOptions: {},
- searchingText: "Searching...",
- noresultsText: "No results.",
- initialQuery: false
- };
- $.extend(defaultedOptions, options);
- defaultedOptions.chosenOptions.no_results_text = defaultedOptions.searchingText;
- select = this;
- multiple = select.attr('multiple') != null;
- if (multiple) {
- inputSelector = ".search-field > input";
- clickSelector = ".chzn-choices";
- } else {
- inputSelector = ".chzn-search > input";
- clickSelector = ".chzn-single";
- }
- select.chosen(defaultedOptions.chosenOptions);
- select.data('chosen').winnow_results = function(){};
- container = select.next('.chzn-container');
- field = container.find(inputSelector);
- if (defaultedOptions.initialQuery) {
- field.bind('focus', function(evt) {
- if (this.previousSearch || !container.hasClass('chzn-container-active')) {
- return;
- }
- return search(evt);
- });
- }
- field.bind('keyup', function(evt) {
- if (this.previousSearch) clearTimeout(this.previousSearch);
- return this.previousSearch = setTimeout((function() {
- return search(evt);
- }), defaultedOptions.delay);
- });
- return search = function(evt) {
- var clearSearchingLabel, currentOptions, prevVal, response, val, _ref, thisSearchId;
- val = $.trim(field.attr('value'));
- prevVal = (_ref = field.data('prevVal')) != null ? _ref : false;
- field.data('prevVal', val);
- thisSearchId = new Date().getTime() + val;
- currentSearchId = thisSearchId;
- var resultsDiv;
- if (multiple) {
- resultsDiv = field.parent().parent().siblings();
- } else {
- resultsDiv = field.parent().parent();
- }
- clearSearchingLabel = function(val) {
- if (typeof val === "undefined" || val === null || val === "") val = $(_this).attr('value');
- return resultsDiv.find('.no-results').html(defaultedOptions.noresultsText + " '" + val + "'");
- };
- if (val === prevVal || (val.length < defaultedOptions.minLength && evt.type === 'keyup')) {
- clearSearchingLabel(val);
- return false;
- }
- if (resultsDiv.find(".no-results").length < 1) {
- resultsDiv.find(".no-results").remove();
- resultsDiv.find(".chzn-results").prepend($(" ").addClass("no-results"));
- }
- resultsDiv.find(".active-result").remove();
- resultsDiv.find('.no-results').addClass("searching").html(defaultedOptions.searchingText + " '" + val + "'");
- currentOptions = select.find('option');
- defaultedOptions.term = val;
- response = function(items, success) {
- var currentOpt, keydownEvent, latestVal, newOpt, newOptions, noResult, _fn, _fn2, _i, _j, _len, _len2;
- if (!field.is(':focus') && evt.type === 'keyup') return;
- if (thisSearchId !== currentSearchId) return;
- newOptions = [];
- $.each(items, function(value, text) {
- var newOpt;
- newOpt = $('');
- newOpt.attr('value', value).html(text);
- return newOptions.push($(newOpt));
- });
- _fn = function(currentOpt) {
- var $currentOpt, newOption, presenceInNewOptions;
- $currentOpt = $(currentOpt);
- if ($currentOpt.attr('selected') && multiple) return;
- if ($currentOpt.attr('value') === '' && $currentOpt.html() === '' && !multiple) {
- return;
- }
- presenceInNewOptions = (function() {
- var _j, _len2, _results;
- _results = [];
- for (_j = 0, _len2 = newOptions.length; _j < _len2; _j++) {
- newOption = newOptions[_j];
- if (newOption.attr('value') === $currentOpt.attr('value')) {
- _results.push(newOption);
- }
- }
- return _results;
- })();
- if (presenceInNewOptions.length === 0) return $currentOpt.remove();
- };
- for (_i = 0, _len = currentOptions.length; _i < _len; _i++) {
- currentOpt = currentOptions[_i];
- _fn(currentOpt);
- }
- select.html(select.find("option:selected"));
- currentOptions = select.find('option');
- _fn2 = function(newOpt) {
- var currentOption, presenceInCurrentOptions, _fn3, _k, _len3;
- presenceInCurrentOptions = false;
- _fn3 = function(currentOption) {
- if ($(currentOption).attr('value') === newOpt.attr('value')) {
- return presenceInCurrentOptions = true;
- }
- };
- for (_k = 0, _len3 = currentOptions.length; _k < _len3; _k++) {
- currentOption = currentOptions[_k];
- _fn3(currentOption);
- }
- if (!presenceInCurrentOptions) return select.append(newOpt);
- };
- for (_j = 0, _len2 = newOptions.length; _j < _len2; _j++) {
- newOpt = newOptions[_j];
- _fn2(newOpt);
- }
- latestVal = field.val();
- if ($.isEmptyObject(items)) {
- noResult = $(' ');
- noResult.addClass('no-results');
- noResult.html(defaultedOptions.noresultsText + " '" + latestVal + "'").attr('value', '');
- select.find('.no-results').remove();
- select.append(noResult);
- } else {
- select.change();
- }
- select.trigger("liszt:updated");
- $('.no-results').removeClass('active-result');
- field.val(latestVal);
- field.trigger($.Event("keydown"))
- if (!$.isEmptyObject(items)) {
- keydownEvent = $.Event('keydown');
- keydownEvent.which = 40;
- field.trigger(keydownEvent);
- }
- if (success) return success(items);
- };
- return callback(defaultedOptions, response, evt);
- };
- };
- })(jQuery);
-
-}).call(this);
diff --git a/vendor/assets/javascripts/dataTables.fixedHeader.js b/vendor/assets/javascripts/dataTables.fixedHeader.js
deleted file mode 100644
index 90df87867..000000000
--- a/vendor/assets/javascripts/dataTables.fixedHeader.js
+++ /dev/null
@@ -1,1028 +0,0 @@
-/*! FixedHeader 2.1.2
- * ©2010-2014 SpryMedia Ltd - datatables.net/license
- */
-
-/**
- * @summary FixedHeader
- * @description Fix a table's header or footer, so it is always visible while
- * Scrolling
- * @version 2.1.2
- * @file dataTables.fixedHeader.js
- * @author SpryMedia Ltd (www.sprymedia.co.uk)
- * @contact www.sprymedia.co.uk/contact
- * @copyright Copyright 2009-2014 SpryMedia Ltd.
- *
- * This source file is free software, available under the following license:
- * MIT license - http://datatables.net/license/mit
- *
- * This source file is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE. See the license files for details.
- *
- * For details please refer to: http://www.datatables.net
- */
-
-/* Global scope for FixedColumns for backwards compatibility - will be removed
- * in future. Not documented in 1.1.x.
- */
-
-/* Global scope for FixedColumns */
-var FixedHeader;
-
-(function(window, document, undefined) {
-
-
-var factory = function( $, DataTable ) {
-"use strict";
-
-/*
- * Function: FixedHeader
- * Purpose: Provide 'fixed' header, footer and columns for a DataTable
- * Returns: object:FixedHeader - must be called with 'new'
- * Inputs: mixed:mTable - target table
- * @param {object} dt DataTables instance or HTML table node. With DataTables
- * 1.10 this can also be a jQuery collection (with just a single table in its
- * result set), a jQuery selector, DataTables API instance or settings
- * object.
- * @param {object} [oInit] initialisation settings, with the following
- * properties (each optional)
- * * bool:top - fix the header (default true)
- * * bool:bottom - fix the footer (default false)
- * * int:left - fix the left column(s) (default 0)
- * * int:right - fix the right column(s) (default 0)
- * * int:zTop - fixed header zIndex
- * * int:zBottom - fixed footer zIndex
- * * int:zLeft - fixed left zIndex
- * * int:zRight - fixed right zIndex
- */
-FixedHeader = function ( mTable, oInit ) {
- /* Sanity check - you just know it will happen */
- if ( ! this instanceof FixedHeader )
- {
- alert( "FixedHeader warning: FixedHeader must be initialised with the 'new' keyword." );
- return;
- }
-
- var that = this;
- var oSettings = {
- "aoCache": [],
- "oSides": {
- "top": true,
- "bottom": false,
- "left": 0,
- "right": 0
- },
- "oZIndexes": {
- "top": 104,
- "bottom": 103,
- "left": 102,
- "right": 101
- },
- "oCloneOnDraw": {
- "top": false,
- "bottom": false,
- "left": true,
- "right": true
- },
- "oMes": {
- "iTableWidth": 0,
- "iTableHeight": 0,
- "iTableLeft": 0,
- "iTableRight": 0, /* note this is left+width, not actually "right" */
- "iTableTop": 0,
- "iTableBottom": 0 /* note this is top+height, not actually "bottom" */
- },
- "oOffset": {
- "top": 0
- },
- "nTable": null,
- "bFooter": false,
- "bInitComplete": false
- };
-
- /*
- * Function: fnGetSettings
- * Purpose: Get the settings for this object
- * Returns: object: - settings object
- * Inputs: -
- */
- this.fnGetSettings = function () {
- return oSettings;
- };
-
- /*
- * Function: fnUpdate
- * Purpose: Update the positioning and copies of the fixed elements
- * Returns: -
- * Inputs: -
- */
- this.fnUpdate = function () {
- this._fnUpdateClones();
- this._fnUpdatePositions();
- };
-
- /*
- * Function: fnPosition
- * Purpose: Update the positioning of the fixed elements
- * Returns: -
- * Inputs: -
- */
- this.fnPosition = function () {
- this._fnUpdatePositions();
- };
-
-
- var dt = $.fn.dataTable.Api ?
- new $.fn.dataTable.Api( mTable ).settings()[0] :
- mTable.fnSettings();
-
- dt._oPluginFixedHeader = this;
-
- /* Let's do it */
- this.fnInit( dt, oInit );
-
-};
-
-
-/*
- * Variable: FixedHeader
- * Purpose: Prototype for FixedHeader
- * Scope: global
- */
-FixedHeader.prototype = {
- /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
- * Initialisation
- */
-
- /*
- * Function: fnInit
- * Purpose: The "constructor"
- * Returns: -
- * Inputs: {as FixedHeader function}
- */
- fnInit: function ( oDtSettings, oInit )
- {
- var s = this.fnGetSettings();
- var that = this;
-
- /* Record the user definable settings */
- this.fnInitSettings( s, oInit );
-
- if ( oDtSettings.oScroll.sX !== "" || oDtSettings.oScroll.sY !== "" )
- {
- alert( "FixedHeader 2 is not supported with DataTables' scrolling mode at this time" );
- return;
- }
-
- s.nTable = oDtSettings.nTable;
- oDtSettings.aoDrawCallback.unshift( {
- "fn": function () {
- FixedHeader.fnMeasure();
- that._fnUpdateClones.call(that);
- that._fnUpdatePositions.call(that);
- },
- "sName": "FixedHeader"
- } );
-
- s.bFooter = ($('>tfoot', s.nTable).length > 0) ? true : false;
-
- /* Add the 'sides' that are fixed */
- if ( s.oSides.top )
- {
- s.aoCache.push( that._fnCloneTable( "fixedHeader", "FixedHeader_Header", that._fnCloneThead ) );
- }
- if ( s.oSides.bottom )
- {
- s.aoCache.push( that._fnCloneTable( "fixedFooter", "FixedHeader_Footer", that._fnCloneTfoot ) );
- }
- if ( s.oSides.left )
- {
- s.aoCache.push( that._fnCloneTable( "fixedLeft", "FixedHeader_Left", that._fnCloneTLeft, s.oSides.left ) );
- }
- if ( s.oSides.right )
- {
- s.aoCache.push( that._fnCloneTable( "fixedRight", "FixedHeader_Right", that._fnCloneTRight, s.oSides.right ) );
- }
-
- /* Event listeners for window movement */
- FixedHeader.afnScroll.push( function () {
- that._fnUpdatePositions.call(that);
- } );
-
- $(window).resize( function () {
- FixedHeader.fnMeasure();
- that._fnUpdateClones.call(that);
- that._fnUpdatePositions.call(that);
- } );
-
- $(s.nTable)
- .on('column-reorder.dt', function () {
- FixedHeader.fnMeasure();
- that._fnUpdateClones( true );
- that._fnUpdatePositions();
- } )
- .on('column-visibility.dt', function () {
- FixedHeader.fnMeasure();
- that._fnUpdateClones( true );
- that._fnUpdatePositions();
- } );
-
- /* Get things right to start with */
- FixedHeader.fnMeasure();
- that._fnUpdateClones();
- that._fnUpdatePositions();
-
- s.bInitComplete = true;
- },
-
-
- /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
- * Support functions
- */
-
- /*
- * Function: fnInitSettings
- * Purpose: Take the user's settings and copy them to our local store
- * Returns: -
- * Inputs: object:s - the local settings object
- * object:oInit - the user's settings object
- */
- fnInitSettings: function ( s, oInit )
- {
- if ( oInit !== undefined )
- {
- if ( oInit.top !== undefined ) {
- s.oSides.top = oInit.top;
- }
- if ( oInit.bottom !== undefined ) {
- s.oSides.bottom = oInit.bottom;
- }
- if ( typeof oInit.left == 'boolean' ) {
- s.oSides.left = oInit.left ? 1 : 0;
- }
- else if ( oInit.left !== undefined ) {
- s.oSides.left = oInit.left;
- }
- if ( typeof oInit.right == 'boolean' ) {
- s.oSides.right = oInit.right ? 1 : 0;
- }
- else if ( oInit.right !== undefined ) {
- s.oSides.right = oInit.right;
- }
-
- if ( oInit.zTop !== undefined ) {
- s.oZIndexes.top = oInit.zTop;
- }
- if ( oInit.zBottom !== undefined ) {
- s.oZIndexes.bottom = oInit.zBottom;
- }
- if ( oInit.zLeft !== undefined ) {
- s.oZIndexes.left = oInit.zLeft;
- }
- if ( oInit.zRight !== undefined ) {
- s.oZIndexes.right = oInit.zRight;
- }
-
- if ( oInit.offsetTop !== undefined ) {
- s.oOffset.top = oInit.offsetTop;
- }
- if ( oInit.alwaysCloneTop !== undefined ) {
- s.oCloneOnDraw.top = oInit.alwaysCloneTop;
- }
- if ( oInit.alwaysCloneBottom !== undefined ) {
- s.oCloneOnDraw.bottom = oInit.alwaysCloneBottom;
- }
- if ( oInit.alwaysCloneLeft !== undefined ) {
- s.oCloneOnDraw.left = oInit.alwaysCloneLeft;
- }
- if ( oInit.alwaysCloneRight !== undefined ) {
- s.oCloneOnDraw.right = oInit.alwaysCloneRight;
- }
- }
- },
-
- /*
- * Function: _fnCloneTable
- * Purpose: Clone the table node and do basic initialisation
- * Returns: -
- * Inputs: -
- */
- _fnCloneTable: function ( sType, sClass, fnClone, iCells )
- {
- var s = this.fnGetSettings();
- var nCTable;
-
- /* We know that the table _MUST_ has a DIV wrapped around it, because this is simply how
- * DataTables works. Therefore, we can set this to be relatively position (if it is not
- * alreadu absolute, and use this as the base point for the cloned header
- */
- if ( $(s.nTable.parentNode).css('position') != "absolute" )
- {
- s.nTable.parentNode.style.position = "relative";
- }
-
- /* Just a shallow clone will do - we only want the table node */
- nCTable = s.nTable.cloneNode( false );
- nCTable.removeAttribute( 'id' );
-
- var nDiv = document.createElement( 'div' );
- nDiv.style.position = "absolute";
- nDiv.style.top = "0px";
- nDiv.style.left = "0px";
- nDiv.className += " FixedHeader_Cloned "+sType+" "+sClass;
-
- /* Set the zIndexes */
- if ( sType == "fixedHeader" )
- {
- nDiv.style.zIndex = s.oZIndexes.top;
- }
- if ( sType == "fixedFooter" )
- {
- nDiv.style.zIndex = s.oZIndexes.bottom;
- }
- if ( sType == "fixedLeft" )
- {
- nDiv.style.zIndex = s.oZIndexes.left;
- }
- else if ( sType == "fixedRight" )
- {
- nDiv.style.zIndex = s.oZIndexes.right;
- }
-
- /* remove margins since we are going to position it absolutely */
- nCTable.style.margin = "0";
-
- /* Insert the newly cloned table into the DOM, on top of the "real" header */
- nDiv.appendChild( nCTable );
- document.body.appendChild( nDiv );
-
- return {
- "nNode": nCTable,
- "nWrapper": nDiv,
- "sType": sType,
- "sPosition": "",
- "sTop": "",
- "sLeft": "",
- "fnClone": fnClone,
- "iCells": iCells
- };
- },
-
- /*
- * Function: _fnMeasure
- * Purpose: Get the current positioning of the table in the DOM
- * Returns: -
- * Inputs: -
- */
- _fnMeasure: function ()
- {
- var
- s = this.fnGetSettings(),
- m = s.oMes,
- jqTable = $(s.nTable),
- oOffset = jqTable.offset(),
- iParentScrollTop = this._fnSumScroll( s.nTable.parentNode, 'scrollTop' ),
- iParentScrollLeft = this._fnSumScroll( s.nTable.parentNode, 'scrollLeft' );
-
- m.iTableWidth = jqTable.outerWidth();
- m.iTableHeight = jqTable.outerHeight();
- m.iTableLeft = oOffset.left + s.nTable.parentNode.scrollLeft;
- m.iTableTop = oOffset.top + iParentScrollTop;
- m.iTableRight = m.iTableLeft + m.iTableWidth;
- m.iTableRight = FixedHeader.oDoc.iWidth - m.iTableLeft - m.iTableWidth;
- m.iTableBottom = FixedHeader.oDoc.iHeight - m.iTableTop - m.iTableHeight;
- },
-
- /*
- * Function: _fnSumScroll
- * Purpose: Sum node parameters all the way to the top
- * Returns: int: sum
- * Inputs: node:n - node to consider
- * string:side - scrollTop or scrollLeft
- */
- _fnSumScroll: function ( n, side )
- {
- var i = n[side];
- while ( n = n.parentNode )
- {
- if ( n.nodeName == 'HTML' || n.nodeName == 'BODY' )
- {
- break;
- }
- i = n[side];
- }
- return i;
- },
-
- /*
- * Function: _fnUpdatePositions
- * Purpose: Loop over the fixed elements for this table and update their positions
- * Returns: -
- * Inputs: -
- */
- _fnUpdatePositions: function ()
- {
- var s = this.fnGetSettings();
- this._fnMeasure();
-
- for ( var i=0, iLen=s.aoCache.length ; i oWin.iScrollTop + s.oOffset.top )
- {
- /* Above the table */
- this._fnUpdateCache( oCache, 'sPosition', "absolute", 'position', nTable.style );
- this._fnUpdateCache( oCache, 'sTop', oMes.iTableTop+"px", 'top', nTable.style );
- this._fnUpdateCache( oCache, 'sLeft', oMes.iTableLeft+"px", 'left', nTable.style );
- }
- else if ( oWin.iScrollTop + s.oOffset.top > oMes.iTableTop+iTbodyHeight )
- {
- /* At the bottom of the table */
- this._fnUpdateCache( oCache, 'sPosition', "absolute", 'position', nTable.style );
- this._fnUpdateCache( oCache, 'sTop', (oMes.iTableTop+iTbodyHeight)+"px", 'top', nTable.style );
- this._fnUpdateCache( oCache, 'sLeft', oMes.iTableLeft+"px", 'left', nTable.style );
- }
- else
- {
- /* In the middle of the table */
- this._fnUpdateCache( oCache, 'sPosition', 'fixed', 'position', nTable.style );
- this._fnUpdateCache( oCache, 'sTop', s.oOffset.top+"px", 'top', nTable.style );
- this._fnUpdateCache( oCache, 'sLeft', (oMes.iTableLeft-oWin.iScrollLeft)+"px", 'left', nTable.style );
- }
- },
-
- /*
- * Function: _fnUpdateCache
- * Purpose: Check the cache and update cache and value if needed
- * Returns: -
- * Inputs: object:oCache - local cache object
- * string:sCache - cache property
- * string:sSet - value to set
- * string:sProperty - object property to set
- * object:oObj - object to update
- */
- _fnUpdateCache: function ( oCache, sCache, sSet, sProperty, oObj )
- {
- if ( oCache[sCache] != sSet )
- {
- oObj[sProperty] = sSet;
- oCache[sCache] = sSet;
- }
- },
-
-
-
- /**
- * Copy the classes of all child nodes from one element to another. This implies
- * that the two have identical structure - no error checking is performed to that
- * fact.
- * @param {element} source Node to copy classes from
- * @param {element} dest Node to copy classes too
- */
- _fnClassUpdate: function ( source, dest )
- {
- var that = this;
-
- if ( source.nodeName.toUpperCase() === "TR" || source.nodeName.toUpperCase() === "TH" ||
- source.nodeName.toUpperCase() === "TD" || source.nodeName.toUpperCase() === "SPAN" )
- {
- dest.className = source.className;
- }
-
- $(source).children().each( function (i) {
- that._fnClassUpdate( $(source).children()[i], $(dest).children()[i] );
- } );
- },
-
-
- /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
- * Cloning functions
- */
-
- /*
- * Function: _fnCloneThead
- * Purpose: Clone the thead element
- * Returns: -
- * Inputs: object:oCache - the cached values for this fixed element
- */
- _fnCloneThead: function ( oCache )
- {
- var s = this.fnGetSettings();
- var nTable = oCache.nNode;
-
- if ( s.bInitComplete && !s.oCloneOnDraw.top )
- {
- this._fnClassUpdate( $('thead', s.nTable)[0], $('thead', nTable)[0] );
- return;
- }
-
- /* Set the wrapper width to match that of the cloned table */
- var iDtWidth = $(s.nTable).outerWidth();
- oCache.nWrapper.style.width = iDtWidth+"px";
- nTable.style.width = iDtWidth+"px";
-
- /* Remove any children the cloned table has */
- while ( nTable.childNodes.length > 0 )
- {
- $('thead th', nTable).unbind( 'click' );
- nTable.removeChild( nTable.childNodes[0] );
- }
-
- /* Clone the DataTables header */
- var nThead = $('thead', s.nTable).clone(true)[0];
- nTable.appendChild( nThead );
-
- /* Copy the widths across - apparently a clone isn't good enough for this */
- var a = [];
- var b = [];
-
- $("thead>tr th", s.nTable).each( function (i) {
- a.push( $(this).width() );
- } );
-
- $("thead>tr td", s.nTable).each( function (i) {
- b.push( $(this).width() );
- } );
-
- $("thead>tr th", s.nTable).each( function (i) {
- $("thead>tr th:eq("+i+")", nTable).width( a[i] );
- $(this).width( a[i] );
- } );
-
- $("thead>tr td", s.nTable).each( function (i) {
- $("thead>tr td:eq("+i+")", nTable).width( b[i] );
- $(this).width( b[i] );
- } );
-
- // Stop DataTables 1.9 from putting a focus ring on the headers when
- // clicked to sort
- $('th.sorting, th.sorting_desc, th.sorting_asc', nTable).bind( 'click', function () {
- this.blur();
- } );
- },
-
- /*
- * Function: _fnCloneTfoot
- * Purpose: Clone the tfoot element
- * Returns: -
- * Inputs: object:oCache - the cached values for this fixed element
- */
- _fnCloneTfoot: function ( oCache )
- {
- var s = this.fnGetSettings();
- var nTable = oCache.nNode;
-
- /* Set the wrapper width to match that of the cloned table */
- oCache.nWrapper.style.width = $(s.nTable).outerWidth()+"px";
-
- /* Remove any children the cloned table has */
- while ( nTable.childNodes.length > 0 )
- {
- nTable.removeChild( nTable.childNodes[0] );
- }
-
- /* Clone the DataTables footer */
- var nTfoot = $('tfoot', s.nTable).clone(true)[0];
- nTable.appendChild( nTfoot );
-
- /* Copy the widths across - apparently a clone isn't good enough for this */
- $("tfoot:eq(0)>tr th", s.nTable).each( function (i) {
- $("tfoot:eq(0)>tr th:eq("+i+")", nTable).width( $(this).width() );
- } );
-
- $("tfoot:eq(0)>tr td", s.nTable).each( function (i) {
- $("tfoot:eq(0)>tr td:eq("+i+")", nTable).width( $(this).width() );
- } );
- },
-
- /*
- * Function: _fnCloneTLeft
- * Purpose: Clone the left column(s)
- * Returns: -
- * Inputs: object:oCache - the cached values for this fixed element
- */
- _fnCloneTLeft: function ( oCache )
- {
- var s = this.fnGetSettings();
- var nTable = oCache.nNode;
- var nBody = $('tbody', s.nTable)[0];
-
- /* Remove any children the cloned table has */
- while ( nTable.childNodes.length > 0 )
- {
- nTable.removeChild( nTable.childNodes[0] );
- }
-
- /* Is this the most efficient way to do this - it looks horrible... */
- nTable.appendChild( $("thead", s.nTable).clone(true)[0] );
- nTable.appendChild( $("tbody", s.nTable).clone(true)[0] );
- if ( s.bFooter )
- {
- nTable.appendChild( $("tfoot", s.nTable).clone(true)[0] );
- }
-
- /* Remove unneeded cells */
- var sSelector = 'gt(' + (oCache.iCells - 1) + ')';
- $('thead tr', nTable).each( function (k) {
- $('th:' + sSelector, this).remove();
- } );
-
- $('tfoot tr', nTable).each( function (k) {
- $('th:' + sSelector, this).remove();
- } );
-
- $('tbody tr', nTable).each( function (k) {
- $('td:' + sSelector, this).remove();
- } );
-
- this.fnEqualiseHeights( 'thead', nBody.parentNode, nTable );
- this.fnEqualiseHeights( 'tbody', nBody.parentNode, nTable );
- this.fnEqualiseHeights( 'tfoot', nBody.parentNode, nTable );
-
- var iWidth = 0;
- for (var i = 0; i < oCache.iCells; i++) {
- iWidth += $('thead tr th:eq(' + i + ')', s.nTable).outerWidth();
- }
- nTable.style.width = iWidth+"px";
- oCache.nWrapper.style.width = iWidth+"px";
- },
-
- /*
- * Function: _fnCloneTRight
- * Purpose: Clone the right most column(s)
- * Returns: -
- * Inputs: object:oCache - the cached values for this fixed element
- */
- _fnCloneTRight: function ( oCache )
- {
- var s = this.fnGetSettings();
- var nBody = $('tbody', s.nTable)[0];
- var nTable = oCache.nNode;
- var iCols = $('tbody tr:eq(0) td', s.nTable).length;
-
- /* Remove any children the cloned table has */
- while ( nTable.childNodes.length > 0 )
- {
- nTable.removeChild( nTable.childNodes[0] );
- }
-
- /* Is this the most efficient way to do this - it looks horrible... */
- nTable.appendChild( $("thead", s.nTable).clone(true)[0] );
- nTable.appendChild( $("tbody", s.nTable).clone(true)[0] );
- if ( s.bFooter )
- {
- nTable.appendChild( $("tfoot", s.nTable).clone(true)[0] );
- }
- $('thead tr th:lt('+(iCols-oCache.iCells)+')', nTable).remove();
- $('tfoot tr th:lt('+(iCols-oCache.iCells)+')', nTable).remove();
-
- /* Remove unneeded cells */
- $('tbody tr', nTable).each( function (k) {
- $('td:lt('+(iCols-oCache.iCells)+')', this).remove();
- } );
-
- this.fnEqualiseHeights( 'thead', nBody.parentNode, nTable );
- this.fnEqualiseHeights( 'tbody', nBody.parentNode, nTable );
- this.fnEqualiseHeights( 'tfoot', nBody.parentNode, nTable );
-
- var iWidth = 0;
- for (var i = 0; i < oCache.iCells; i++) {
- iWidth += $('thead tr th:eq('+(iCols-1-i)+')', s.nTable).outerWidth();
- }
- nTable.style.width = iWidth+"px";
- oCache.nWrapper.style.width = iWidth+"px";
- },
-
-
- /**
- * Equalise the heights of the rows in a given table node in a cross browser way. Note that this
- * is more or less lifted as is from FixedColumns
- * @method fnEqualiseHeights
- * @returns void
- * @param {string} parent Node type - thead, tbody or tfoot
- * @param {element} original Original node to take the heights from
- * @param {element} clone Copy the heights to
- * @private
- */
- "fnEqualiseHeights": function ( parent, original, clone )
- {
- var that = this;
- var originals = $(parent +' tr', original);
- var height;
-
- $(parent+' tr', clone).each( function (k) {
- height = originals.eq( k ).css('height');
-
- // This is nasty :-(. IE has a sub-pixel error even when setting
- // the height below (the Firefox fix) which causes the fixed column
- // to go out of alignment. Need to add a pixel before the assignment
- // Can this be feature detected? Not sure how...
- if ( navigator.appName == 'Microsoft Internet Explorer' ) {
- height = parseInt( height, 10 ) + 1;
- }
-
- $(this).css( 'height', height );
-
- // For Firefox to work, we need to also set the height of the
- // original row, to the value that we read from it! Otherwise there
- // is a sub-pixel rounding error
- originals.eq( k ).css( 'height', height );
- } );
- }
-};
-
-
-/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
- * Static properties and methods
- * We use these for speed! This information is common to all instances of FixedHeader, so no
- * point if having them calculated and stored for each different instance.
- */
-
-/*
- * Variable: oWin
- * Purpose: Store information about the window positioning
- * Scope: FixedHeader
- */
-FixedHeader.oWin = {
- "iScrollTop": 0,
- "iScrollRight": 0,
- "iScrollBottom": 0,
- "iScrollLeft": 0,
- "iHeight": 0,
- "iWidth": 0
-};
-
-/*
- * Variable: oDoc
- * Purpose: Store information about the document size
- * Scope: FixedHeader
- */
-FixedHeader.oDoc = {
- "iHeight": 0,
- "iWidth": 0
-};
-
-/*
- * Variable: afnScroll
- * Purpose: Array of functions that are to be used for the scrolling components
- * Scope: FixedHeader
- */
-FixedHeader.afnScroll = [];
-
-/*
- * Function: fnMeasure
- * Purpose: Update the measurements for the window and document
- * Returns: -
- * Inputs: -
- */
-FixedHeader.fnMeasure = function ()
-{
- var
- jqWin = $(window),
- jqDoc = $(document),
- oWin = FixedHeader.oWin,
- oDoc = FixedHeader.oDoc;
-
- oDoc.iHeight = jqDoc.height();
- oDoc.iWidth = jqDoc.width();
-
- oWin.iHeight = jqWin.height();
- oWin.iWidth = jqWin.width();
- oWin.iScrollTop = jqWin.scrollTop();
- oWin.iScrollLeft = jqWin.scrollLeft();
- oWin.iScrollRight = oDoc.iWidth - oWin.iScrollLeft - oWin.iWidth;
- oWin.iScrollBottom = oDoc.iHeight - oWin.iScrollTop - oWin.iHeight;
-};
-
-
-FixedHeader.version = "2.1.2";
-
-
-/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
- * Global processing
- */
-
-/*
- * Just one 'scroll' event handler in FixedHeader, which calls the required components. This is
- * done as an optimisation, to reduce calculation and proagation time
- */
-$(window).scroll( function () {
- FixedHeader.fnMeasure();
-
- for ( var i=0, iLen=FixedHeader.afnScroll.length ; iTerms
- * Loads the #terms div in the box
- *
- * Terms
- * Loads the terms.html page in the box
- *
- * Terms
- * Loads the terms.png image in the box
- *
- *
- * You can also use it programmatically:
- *
- * jQuery.facebox('some html')
- * jQuery.facebox('some html', 'my-groovy-style')
- *
- * The above will open a facebox with "some html" as the content.
- *
- * jQuery.facebox(function($) {
- * $.get('blah.html', function(data) { $.facebox(data) })
- * })
- *
- * The above will show a loading screen before the passed function is called,
- * allowing for a better ajaxy experience.
- *
- * The facebox function can also display an ajax page, an image, or the contents of a div:
- *
- * jQuery.facebox({ ajax: 'remote.html' })
- * jQuery.facebox({ ajax: 'remote.html' }, 'my-groovy-style')
- * jQuery.facebox({ image: 'stairs.jpg' })
- * jQuery.facebox({ image: 'stairs.jpg' }, 'my-groovy-style')
- * jQuery.facebox({ div: '#box' })
- * jQuery.facebox({ div: '#box' }, 'my-groovy-style')
- *
- * Want to close the facebox? Trigger the 'close.facebox' document event:
- *
- * jQuery(document).trigger('close.facebox')
- *
- * Facebox also has a bunch of other hooks:
- *
- * loading.facebox
- * beforeReveal.facebox
- * reveal.facebox (aliased as 'afterReveal.facebox')
- * init.facebox
- * afterClose.facebox
- *
- * Simply bind a function to any of these hooks:
- *
- * $(document).bind('reveal.facebox', function() { ...stuff to do after the facebox and contents are revealed... })
- *
- */
-(function($) {
- $.facebox = function(data, klass) {
- $.facebox.loading()
-
- if (data.ajax) fillFaceboxFromAjax(data.ajax, klass)
- else if (data.image) fillFaceboxFromImage(data.image, klass)
- else if (data.div) fillFaceboxFromHref(data.div, klass)
- else if ($.isFunction(data)) data.call($)
- else $.facebox.reveal(data, klass)
- }
-
- /*
- * Public, $.facebox methods
- */
-
- $.extend($.facebox, {
- settings: {
- opacity : 0.2,
- overlay : true,
- loadingImage : '/facebox/loading.gif',
- closeImage : '/facebox/closelabel.png',
- imageTypes : [ 'png', 'jpg', 'jpeg', 'gif' ],
- faceboxHtml : '\
- \
- \
-
'
- },
-
- loading: function() {
- init()
- if ($('#facebox .loading').length == 1) return true
- showOverlay()
-
- $('#facebox .content').empty()
- $('#facebox .body').children().hide().end().
- append(' ')
-
- $('#facebox').css({
- top: getPageScroll()[1] + (getPageHeight() / 10),
- left: $(window).width() / 2 - 205
- }).show()
-
- $(document).bind('keydown.facebox', function(e) {
- if (e.keyCode == 27) $.facebox.close()
- return true
- })
- $(document).trigger('loading.facebox')
- },
-
- reveal: function(data, klass) {
- $(document).trigger('beforeReveal.facebox')
- if (klass) $('#facebox .content').addClass(klass)
- $('#facebox').css('left', $(window).width() / 2 - ($(data).width() / 2))
- $('#facebox .content').append(data)
- $('#facebox .loading').remove()
- $('#facebox .body').children().fadeIn('fast')
- $('#facebox').css('left', $(window).width() / 2 - ($('#facebox .popup').width() / 2))
- $(document).trigger('reveal.facebox').trigger('afterReveal.facebox')
- },
-
- close: function() {
- $(document).trigger('close.facebox')
- return false
- }
- })
-
- /*
- * Public, $.fn methods
- */
-
- $.fn.facebox = function(settings) {
- if ($(this).length == 0) return
-
- init(settings)
-
- function clickHandler() {
- $.facebox.loading(true)
-
- // support for rel="facebox.inline_popup" syntax, to add a class
- // also supports deprecated "facebox[.inline_popup]" syntax
- var klass = this.rel.match(/facebox\[?\.(\w+)\]?/)
- if (klass) klass = klass[1]
-
- var method = jQuery(this).attr("data-method")
- var width = jQuery(this).attr("data-width")
- var height = jQuery(this).attr("data-height")
-
- fillFaceboxFromHref(this.href, klass, method, height, width)
- return false
- }
-
- return this.bind('click.facebox', clickHandler)
- }
-
- $.fn.centerElement = function() {
- $(this).css({
- top: getPageScroll()[1] + (getPageHeight() / 10),
- left: $(window).width() / 2 - $(this).width() / 2
- });
- }
-
- /*
- * Private methods
- */
-
- // called one time to setup facebox on this page
- function init(settings) {
- if ($.facebox.settings.inited) return true
- else $.facebox.settings.inited = true
-
- $(document).trigger('init.facebox')
- makeCompatible()
-
- var imageTypes = $.facebox.settings.imageTypes.join('|')
- $.facebox.settings.imageTypesRegexp = new RegExp('\.(' + imageTypes + ')$', 'i')
-
- if (settings) $.extend($.facebox.settings, settings)
- $('body').append($.facebox.settings.faceboxHtml)
-
- var preload = [ new Image(), new Image() ]
- preload[0].src = $.facebox.settings.closeImage
- preload[1].src = $.facebox.settings.loadingImage
-
- $('#facebox').find('.b:first, .bl').each(function() {
- preload.push(new Image())
- preload.slice(-1).src = $(this).css('background-image').replace(/url\((.+)\)/, '$1')
- })
-
- $('#facebox .close').click($.facebox.close)
- $('#facebox .close_image').attr('src', $.facebox.settings.closeImage)
- }
-
- // getPageScroll() by quirksmode.com
- function getPageScroll() {
- var xScroll, yScroll;
- if (self.pageYOffset) {
- yScroll = self.pageYOffset;
- xScroll = self.pageXOffset;
- } else if (document.documentElement && document.documentElement.scrollTop) { // Explorer 6 Strict
- yScroll = document.documentElement.scrollTop;
- xScroll = document.documentElement.scrollLeft;
- } else if (document.body) {// all other Explorers
- yScroll = document.body.scrollTop;
- xScroll = document.body.scrollLeft;
- }
- return new Array(xScroll,yScroll)
- }
-
- // Adapted from getPageSize() by quirksmode.com
- function getPageHeight() {
- var windowHeight
- if (self.innerHeight) { // all except Explorer
- windowHeight = self.innerHeight;
- } else if (document.documentElement && document.documentElement.clientHeight) { // Explorer 6 Strict Mode
- windowHeight = document.documentElement.clientHeight;
- } else if (document.body) { // other Explorers
- windowHeight = document.body.clientHeight;
- }
- return windowHeight
- }
-
- // Backwards compatibility
- function makeCompatible() {
- var $s = $.facebox.settings
-
- $s.loadingImage = $s.loading_image || $s.loadingImage
- $s.closeImage = $s.close_image || $s.closeImage
- $s.imageTypes = $s.image_types || $s.imageTypes
- $s.faceboxHtml = $s.facebox_html || $s.faceboxHtml
- }
-
- // Figures out what you want to display and displays it
- // formats are:
- // div: #id
- // image: blah.extension
- // ajax: anything else
- function fillFaceboxFromHref(href, klass, method, height, width) {
- if (typeof method === "undefined")
- method = null;
-
- // div
- if (href.match(/#/)) {
- var url = window.location.href.split('#')[0]
- var target = href.replace(url,'')
- if (target == '#') return
- $.facebox.reveal($(target), klass)
- $(target).show()
-
- // image
- } else if (href.match($.facebox.settings.imageTypesRegexp)) {
- fillFaceboxFromImage(href, klass)
- } else if (method == "iframe") {
- // iframe
- $.facebox.reveal($(jQuery("").attr("src", href)))
- } else if (method != null && method.indexOf("element") >= 0) {
- // alternate div usage that keeps href in place
- var elemId = method.split("#")[1]
- $.facebox.reveal($("#" + elemId), klass)
- } else {
- // ajax
- fillFaceboxFromAjax(href, klass)
- }
- }
-
- function fillFaceboxFromImage(href, klass) {
- var image = new Image()
- image.onload = function() {
- $.facebox.reveal(' ', klass)
- }
- image.src = href
- }
-
- function fillFaceboxFromAjax(href, klass) {
- $.get(href, function(data) { $.facebox.reveal(data, klass) })
- }
-
- function skipOverlay() {
- return $.facebox.settings.overlay == false || $.facebox.settings.opacity === null
- }
-
- function showOverlay() {
- if (skipOverlay()) return
-
- if ($('#facebox_overlay').length == 0)
- $("body").append('
')
-
- $('#facebox_overlay').hide().addClass("facebox_overlayBG")
- .css('opacity', $.facebox.settings.opacity)
- .click(function() { $(document).trigger('close.facebox') })
- .fadeIn(200)
- return false
- }
-
- function hideOverlay() {
- if (skipOverlay()) return
-
- $('#facebox_overlay').fadeOut(200, function(){
- $("#facebox_overlay").removeClass("facebox_overlayBG")
- $("#facebox_overlay").addClass("facebox_hide")
- $("#facebox_overlay").remove()
- })
-
- return false
- }
-
- /*
- * Bindings
- */
-
- $(document).bind('close.facebox', function() {
- $(document).unbind('keydown.facebox')
- $('#facebox').fadeOut(function() {
- $(document.body).append(jQuery("").hide().append($('#facebox .content').children()))
- $('#facebox .content').removeClass().addClass('content')
- $('#facebox .loading').remove()
- $(document).trigger('afterClose.facebox')
- })
- hideOverlay()
- })
-
-})(jQuery);
diff --git a/vendor/assets/javascripts/fg.menu.js b/vendor/assets/javascripts/fg.menu.js
deleted file mode 100755
index 5d1b92c51..000000000
--- a/vendor/assets/javascripts/fg.menu.js
+++ /dev/null
@@ -1,645 +0,0 @@
-/*--------------------------------------------------------------------
-Scripts for creating and manipulating custom menus based on standard
markup
-Version: 3.0, 03.31.2009
-
-By: Maggie Costello Wachs (maggie@filamentgroup.com) and Scott Jehl (scott@filamentgroup.com)
- http://www.filamentgroup.com
- * reference articles: http://www.filamentgroup.com/lab/jquery_ipod_style_drilldown_menu/
-
-Copyright (c) 2009 Filament Group
-Dual licensed under the MIT (filamentgroup.com/examples/mit-license.txt) and GPL (filamentgroup.com/examples/gpl-license.txt) licenses.
---------------------------------------------------------------------*/
-
-
-var allUIMenus = [];
-
-$.fn.fgmenu = function(options){
- var caller = this;
- var options = options;
- var m = new Menu(caller, options);
- allUIMenus.push(m);
-
- $(this)
- .mousedown(function(){
- if (!m.menuOpen) { m.showLoading(); };
- })
- .click(function(){
- if (m.menuOpen == false) { m.showMenu(); }
- else { m.kill(); };
- return false;
- });
-};
-
-function Menu(caller, options){
- var menu = this;
- var caller = $(caller);
- var container = $('');
-
- this.menuOpen = false;
- this.menuExists = false;
-
- var options = jQuery.extend({
- content: null,
- width: 180, // width of menu container, must be set or passed in to calculate widths of child menus
- maxHeight: 180, // max height of menu (if a drilldown: height does not include breadcrumb)
- positionOpts: {
- posX: 'left',
- posY: 'bottom',
- offsetX: 0,
- offsetY: 0,
- directionH: 'right',
- directionV: 'down',
- detectH: true, // do horizontal collision detection
- detectV: true, // do vertical collision detection
- linkToFront: false
- },
- showSpeed: 200, // show/hide speed in milliseconds
- callerOnState: 'ui-state-active', // class to change the appearance of the link/button when the menu is showing
- loadingState: 'ui-state-loading', // class added to the link/button while the menu is created
- linkHover: 'ui-state-hover', // class for menu option hover state
- linkHoverSecondary: 'li-hover', // alternate class, may be used for multi-level menus
- // ----- multi-level menu defaults -----
- crossSpeed: 200, // cross-fade speed for multi-level menus
- crumbDefaultText: 'Choose an option:',
- backLink: true, // in the ipod-style menu: instead of breadcrumbs, show only a 'back' link
- backLinkText: 'Back',
- flyOut: false, // multi-level menus are ipod-style by default; this parameter overrides to make a flyout instead
- flyOutOnState: 'ui-state-default',
- nextMenuLink: 'ui-icon-triangle-1-e', // class to style the link (specifically, a span within the link) used in the multi-level menu to show the next level
- topLinkText: 'All',
- nextCrumbLink: 'ui-icon-carat-1-e',
- afterItemChosen: function(item){}
-
- }, options);
-
- var killAllMenus = function(){
- $.each(allUIMenus, function(i){
- if (allUIMenus[i].menuOpen) { allUIMenus[i].kill(); };
- });
- };
-
- this.kill = function(){
- caller
- .removeClass(options.loadingState)
- .removeClass('fg-menu-open')
- .removeClass(options.callerOnState);
- container.find('li').removeClass(options.linkHoverSecondary).find('a').removeClass(options.linkHover);
- if (options.flyOutOnState) { container.find('li a').removeClass(options.flyOutOnState); };
- if (options.callerOnState) { caller.removeClass(options.callerOnState); };
- if (container.is('.fg-menu-ipod')) { menu.resetDrilldownMenu(); };
- if (container.is('.fg-menu-flyout')) { menu.resetFlyoutMenu(); };
- container.parent().hide();
- menu.menuOpen = false;
- $(document).unbind('click', killAllMenus);
- $(document).unbind('keydown');
- };
-
- this.showLoading = function(){
- caller.addClass(options.loadingState);
- };
-
- this.showMenu = function(){
- killAllMenus();
- if (!menu.menuExists) { menu.create() };
- caller
- .addClass('fg-menu-open')
- .addClass(options.callerOnState);
- container.parent().show().click(function(){ menu.kill(); return false; });
- container.hide().slideDown(options.showSpeed).find('.fg-menu:eq(0)');
- menu.menuOpen = true;
- caller.removeClass(options.loadingState);
- $(document).click(killAllMenus);
-
- // assign key events
- $(document).keydown(function(event){
- var e;
- if (event.which !="") { e = event.which; }
- else if (event.charCode != "") { e = event.charCode; }
- else if (event.keyCode != "") { e = event.keyCode; }
-
- var menuType = ($(event.target).parents('div').is('.fg-menu-flyout')) ? 'flyout' : 'ipod' ;
-
- switch(e) {
- case 37: // left arrow
- if (menuType == 'flyout') {
- $(event.target).trigger('mouseout');
- if ($('.'+options.flyOutOnState).size() > 0) { $('.'+options.flyOutOnState).trigger('mouseover'); };
- };
-
- if (menuType == 'ipod') {
- $(event.target).trigger('mouseout');
- if ($('.fg-menu-footer').find('a').size() > 0) { $('.fg-menu-footer').find('a').trigger('click'); };
- if ($('.fg-menu-header').find('a').size() > 0) { $('.fg-menu-current-crumb').prev().find('a').trigger('click'); };
- if ($('.fg-menu-current').prev().is('.fg-menu-indicator')) {
- $('.fg-menu-current').prev().trigger('mouseover');
- };
- };
- return false;
- break;
-
- case 38: // up arrow
- if ($(event.target).is('.' + options.linkHover)) {
- var prevLink = $(event.target).parent().prev().find('a:eq(0)');
- if (prevLink.size() > 0) {
- $(event.target).trigger('mouseout');
- prevLink.trigger('mouseover');
- };
- }
- else { container.find('a:eq(0)').trigger('mouseover'); }
- return false;
- break;
-
- case 39: // right arrow
- if ($(event.target).is('.fg-menu-indicator')) {
- if (menuType == 'flyout') {
- $(event.target).next().find('a:eq(0)').trigger('mouseover');
- }
- else if (menuType == 'ipod') {
- $(event.target).trigger('click');
- setTimeout(function(){
- $(event.target).next().find('a:eq(0)').trigger('mouseover');
- }, options.crossSpeed);
- };
- };
- return false;
- break;
-
- case 40: // down arrow
- if ($(event.target).is('.' + options.linkHover)) {
- var nextLink = $(event.target).parent().next().find('a:eq(0)');
- if (nextLink.size() > 0) {
- $(event.target).trigger('mouseout');
- nextLink.trigger('mouseover');
- };
- }
- else { container.find('a:eq(0)').trigger('mouseover'); }
- return false;
- break;
-
- case 27: // escape
- killAllMenus();
- break;
-
- case 13: // enter
- if ($(event.target).is('.fg-menu-indicator') && menuType == 'ipod') {
- $(event.target).trigger('click');
- setTimeout(function(){
- $(event.target).next().find('a:eq(0)').trigger('mouseover');
- }, options.crossSpeed);
- };
- break;
- };
- });
- };
-
- this.create = function(){
- container.css({ width: options.width }).appendTo('body').find('ul:first').not('.fg-menu-breadcrumb').addClass('fg-menu');
- container.find('ul, li a').addClass('ui-corner-all');
-
- // aria roles & attributes
- container.find('ul').attr('role', 'menu').eq(0).attr('aria-activedescendant','active-menuitem').attr('aria-labelledby', caller.attr('id'));
- container.find('li').attr('role', 'menuitem');
- container.find('li:has(ul)').attr('aria-haspopup', 'true').find('ul').attr('aria-expanded', 'false');
- container.find('a').attr('tabindex', '-1');
-
- // when there are multiple levels of hierarchy, create flyout or drilldown menu
- if (container.find('ul').size() > 1) {
- if (options.flyOut) { menu.flyout(container, options); }
- else { menu.drilldown(container, options); }
- }
- else {
- container.find('a').click(function(){
- menu.chooseItem(this);
- return false;
- });
- };
-
- if (options.linkHover) {
- var allLinks = container.find('.fg-menu li a');
- allLinks.hover(
- function(){
- var menuitem = $(this);
- $('.'+options.linkHover).removeClass(options.linkHover).blur().parent().removeAttr('id');
- $(this).addClass(options.linkHover).focus().parent().attr('id','active-menuitem');
- },
- function(){
- $(this).removeClass(options.linkHover).blur().parent().removeAttr('id');
- }
- );
- };
-
- if (options.linkHoverSecondary) {
- container.find('.fg-menu li').hover(
- function(){
- $(this).siblings('li').removeClass(options.linkHoverSecondary);
- if (options.flyOutOnState) { $(this).siblings('li').find('a').removeClass(options.flyOutOnState); }
- $(this).addClass(options.linkHoverSecondary);
- },
- function(){ $(this).removeClass(options.linkHoverSecondary); }
- );
- };
-
- menu.setPosition(container, caller, options);
- menu.menuExists = true;
- };
-
- this.chooseItem = function(item){
- menu.kill();
- options.afterItemChosen(item);
- };
-};
-
-Menu.prototype.flyout = function(container, options) {
- var menu = this;
-
- this.resetFlyoutMenu = function(){
- var allLists = container.find('ul ul');
- allLists.removeClass('ui-widget-content').hide();
- };
-
- container.addClass('fg-menu-flyout').find('li:has(ul)').each(function(){
- var linkWidth = container.width();
- var showTimer, hideTimer;
- var allSubLists = $(this).find('ul');
-
- allSubLists.css({ left: linkWidth, width: linkWidth }).hide();
-
- $(this).find('a:eq(0)').addClass('fg-menu-indicator').html('' + $(this).find('a:eq(0)').text() + ' ').hover(
- function(){
- clearTimeout(hideTimer);
- var subList = $(this).next();
- if (!fitVertical(subList, $(this).offset().top)) { subList.css({ top: 'auto', bottom: 0 }); };
- if (!fitHorizontal(subList, $(this).offset().left + 100)) { subList.css({ left: 'auto', right: linkWidth, 'z-index': 999 }); };
- showTimer = setTimeout(function(){
- subList.addClass('ui-widget-content').show(options.showSpeed).attr('aria-expanded', 'true');
- }, 300);
- },
- function(){
- clearTimeout(showTimer);
- var subList = $(this).next();
- hideTimer = setTimeout(function(){
- subList.removeClass('ui-widget-content').hide(options.showSpeed).attr('aria-expanded', 'false');
- }, 400);
- }
- );
-
- $(this).find('ul a').hover(
- function(){
- clearTimeout(hideTimer);
- if ($(this).parents('ul').prev().is('a.fg-menu-indicator')) {
- $(this).parents('ul').prev().addClass(options.flyOutOnState);
- }
- },
- function(){
- hideTimer = setTimeout(function(){
- allSubLists.hide(options.showSpeed);
- container.find(options.flyOutOnState).removeClass(options.flyOutOnState);
- }, 500);
- }
- );
- });
-
- container.find('a').click(function(){
- menu.chooseItem(this);
- return false;
- });
-};
-
-
-Menu.prototype.drilldown = function(container, options) {
- var menu = this;
- var topList = container.find('.fg-menu');
- var breadcrumb = $('');
- var crumbDefaultHeader = $('');
- var firstCrumbText = (options.backLink) ? options.backLinkText : options.topLinkText;
- var firstCrumbClass = (options.backLink) ? 'fg-menu-prev-list' : 'fg-menu-all-lists';
- var firstCrumbLinkClass = (options.backLink) ? 'ui-state-default ui-corner-all' : '';
- var firstCrumbIcon = (options.backLink) ? ' ' : '';
- var firstCrumb = $(''+firstCrumbIcon+firstCrumbText+' ');
-
- container.addClass('fg-menu-ipod');
-
- if (options.backLink) { breadcrumb.addClass('fg-menu-footer').appendTo(container).hide(); }
- else { breadcrumb.addClass('fg-menu-header').prependTo(container); };
- breadcrumb.append(crumbDefaultHeader);
-
- var checkMenuHeight = function(el){
- if (el.height() > options.maxHeight) { el.addClass('fg-menu-scroll') };
- el.css({ height: options.maxHeight });
- };
-
- var resetChildMenu = function(el){ el.removeClass('fg-menu-scroll').removeClass('fg-menu-current').height('auto'); };
-
- this.resetDrilldownMenu = function(){
- $('.fg-menu-current').removeClass('fg-menu-current');
- topList.animate({ left: 0 }, options.crossSpeed, function(){
- $(this).find('ul').each(function(){
- $(this).hide();
- resetChildMenu($(this));
- });
- topList.addClass('fg-menu-current');
- });
- $('.fg-menu-all-lists').find('span').remove();
- breadcrumb.empty().append(crumbDefaultHeader);
- $('.fg-menu-footer').empty().hide();
- checkMenuHeight(topList);
- };
-
- topList
- .addClass('fg-menu-content fg-menu-current ui-widget-content ui-helper-clearfix')
- .css({ width: container.width() })
- .find('ul')
- .css({ width: container.width(), left: container.width() })
- .addClass('ui-widget-content')
- .hide();
- checkMenuHeight(topList);
-
- topList.find('a').each(function(){
- // if the link opens a child menu:
- if ($(this).next().is('ul')) {
- $(this)
- .addClass('fg-menu-indicator')
- .each(function(){ $(this).html('' + $(this).text() + ' '); })
- .click(function(){ // ----- show the next menu
- var nextList = $(this).next();
- var parentUl = $(this).parents('ul:eq(0)');
- var parentLeft = (parentUl.is('.fg-menu-content')) ? 0 : parseFloat(topList.css('left'));
- var nextLeftVal = Math.round(parentLeft - parseFloat(container.width()));
- var footer = $('.fg-menu-footer');
-
- // show next menu
- resetChildMenu(parentUl);
- checkMenuHeight(nextList);
- topList.animate({ left: nextLeftVal }, options.crossSpeed);
- nextList.show().addClass('fg-menu-current').attr('aria-expanded', 'true');
-
- var setPrevMenu = function(backlink){
- var b = backlink;
- var c = $('.fg-menu-current');
- var prevList = c.parents('ul:eq(0)');
- c.hide().attr('aria-expanded', 'false');
- resetChildMenu(c);
- checkMenuHeight(prevList);
- prevList.addClass('fg-menu-current').attr('aria-expanded', 'true');
- if (prevList.hasClass('fg-menu-content')) { b.remove(); footer.hide(); };
- };
-
- // initialize "back" link
- if (options.backLink) {
- if (footer.find('a').size() == 0) {
- footer.show();
- $(' Back ')
- .appendTo(footer)
- .click(function(){ // ----- show the previous menu
- var b = $(this);
- var prevLeftVal = parseFloat(topList.css('left')) + container.width();
- topList.animate({ left: prevLeftVal }, options.crossSpeed, function(){
- setPrevMenu(b);
- });
- return false;
- });
- }
- }
- // or initialize top breadcrumb
- else {
- if (breadcrumb.find('li').size() == 1){
- breadcrumb.empty().append(firstCrumb);
- firstCrumb.find('a').click(function(){
- menu.resetDrilldownMenu();
- return false;
- });
- }
- $('.fg-menu-current-crumb').removeClass('fg-menu-current-crumb');
- var crumbText = $(this).find('span:eq(0)').text();
- var newCrumb = $('');
- newCrumb
- .appendTo(breadcrumb)
- .find('a').click(function(){
- if ($(this).parent().is('.fg-menu-current-crumb')){
- menu.chooseItem(this);
- }
- else {
- var newLeftVal = - ($('.fg-menu-current').parents('ul').size() - 1) * 180;
- topList.animate({ left: newLeftVal }, options.crossSpeed, function(){
- setPrevMenu();
- });
-
- // make this the current crumb, delete all breadcrumbs after this one, and navigate to the relevant menu
- $(this).parent().addClass('fg-menu-current-crumb').find('span').remove();
- $(this).parent().nextAll().remove();
- };
- return false;
- });
- newCrumb.prev().append(' ');
- };
- return false;
- });
- }
- // if the link is a leaf node (doesn't open a child menu)
- else {
- $(this).click(function(){
- menu.chooseItem(this);
- return false;
- });
- };
- });
-};
-
-
-/* Menu.prototype.setPosition parameters (defaults noted with *):
- referrer = the link (or other element) used to show the overlaid object
- settings = can override the defaults:
- - posX/Y: where the top left corner of the object should be positioned in relation to its referrer.
- X: left*, center, right
- Y: top, center, bottom*
- - offsetX/Y: the number of pixels to be offset from the x or y position. Can be a positive or negative number.
- - directionH/V: where the entire menu should appear in relation to its referrer.
- Horizontal: left*, right
- Vertical: up, down*
- - detectH/V: detect the viewport horizontally / vertically
- - linkToFront: copy the menu link and place it on top of the menu (visual effect to make it look like it overlaps the object) */
-
-Menu.prototype.setPosition = function(widget, caller, options) {
- var el = widget;
- var referrer = caller;
- var dims = {
- refX: referrer.offset().left,
- refY: referrer.offset().top,
- refW: referrer.getTotalWidth(),
- refH: referrer.getTotalHeight()
- };
- var options = options;
- var xVal, yVal;
-
- var helper = $('
');
- helper.css({ position: 'absolute', left: dims.refX, top: dims.refY, width: dims.refW, height: dims.refH });
- el.wrap(helper);
-
- // get X pos
- switch(options.positionOpts.posX) {
- case 'left': xVal = 0;
- break;
- case 'center': xVal = dims.refW / 2;
- break;
- case 'right': xVal = dims.refW;
- break;
- };
-
- // get Y pos
- switch(options.positionOpts.posY) {
- case 'top': yVal = 0;
- break;
- case 'center': yVal = dims.refH / 2;
- break;
- case 'bottom': yVal = dims.refH;
- break;
- };
-
- // add the offsets (zero by default)
- xVal += options.positionOpts.offsetX;
- yVal += options.positionOpts.offsetY;
-
- // position the object vertically
- if (options.positionOpts.directionV == 'up') {
- el.css({ top: 'auto', bottom: yVal });
- if (options.positionOpts.detectV && !fitVertical(el)) {
- el.css({ bottom: 'auto', top: yVal });
- }
- }
- else {
- el.css({ bottom: 'auto', top: yVal });
- if (options.positionOpts.detectV && !fitVertical(el)) {
- el.css({ top: 'auto', bottom: yVal });
- }
- };
-
- // and horizontally
- if (options.positionOpts.directionH == 'left') {
- el.css({ left: 'auto', right: xVal });
- if (options.positionOpts.detectH && !fitHorizontal(el)) {
- el.css({ right: 'auto', left: xVal });
- }
- }
- else {
- el.css({ right: 'auto', left: xVal });
- if (options.positionOpts.detectH && !fitHorizontal(el)) {
- el.css({ left: 'auto', right: xVal });
- }
- };
-
- // if specified, clone the referring element and position it so that it appears on top of the menu
- if (options.positionOpts.linkToFront) {
- referrer.clone().addClass('linkClone').css({
- position: 'absolute',
- top: 0,
- right: 'auto',
- bottom: 'auto',
- left: 0,
- width: referrer.width(),
- height: referrer.height()
- }).insertAfter(el);
- };
-};
-
-
-/* Utilities to sort and find viewport dimensions */
-
-function sortBigToSmall(a, b) { return b - a; };
-
-jQuery.fn.getTotalWidth = function(){
- return $(this).width() + parseInt($(this).css('paddingRight')) + parseInt($(this).css('paddingLeft')) + parseInt($(this).css('borderRightWidth')) + parseInt($(this).css('borderLeftWidth'));
-};
-
-jQuery.fn.getTotalHeight = function(){
- return $(this).height() + parseInt($(this).css('paddingTop')) + parseInt($(this).css('paddingBottom')) + parseInt($(this).css('borderTopWidth')) + parseInt($(this).css('borderBottomWidth'));
-};
-
-function getScrollTop(){
- return self.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop;
-};
-
-function getScrollLeft(){
- return self.pageXOffset || document.documentElement.scrollLeft || document.body.scrollLeft;
-};
-
-function getWindowHeight(){
- var de = document.documentElement;
- return self.innerHeight || (de && de.clientHeight) || document.body.clientHeight;
-};
-
-function getWindowWidth(){
- var de = document.documentElement;
- return self.innerWidth || (de && de.clientWidth) || document.body.clientWidth;
-};
-
-/* Utilities to test whether an element will fit in the viewport
- Parameters:
- el = element to position, required
- leftOffset / topOffset = optional parameter if the offset cannot be calculated (i.e., if the object is in the DOM but is set to display: 'none') */
-
-function fitHorizontal(el, leftOffset){
- var leftVal = parseInt(leftOffset) || $(el).offset().left;
- return (leftVal + $(el).width() <= getWindowWidth() + getScrollLeft() && leftVal - getScrollLeft() >= 0);
-};
-
-function fitVertical(el, topOffset){
- var topVal = parseInt(topOffset) || $(el).offset().top;
- return (topVal + $(el).height() <= getWindowHeight() + getScrollTop() && topVal - getScrollTop() >= 0);
-};
-
-/*--------------------------------------------------------------------
- * javascript method: "pxToEm"
- * by:
- Scott Jehl (scott@filamentgroup.com)
- Maggie Wachs (maggie@filamentgroup.com)
- http://www.filamentgroup.com
- *
- * Copyright (c) 2008 Filament Group
- * Dual licensed under the MIT (filamentgroup.com/examples/mit-license.txt) and GPL (filamentgroup.com/examples/gpl-license.txt) licenses.
- *
- * Description: Extends the native Number and String objects with pxToEm method. pxToEm converts a pixel value to ems depending on inherited font size.
- * Article: http://www.filamentgroup.com/lab/retaining_scalable_interfaces_with_pixel_to_em_conversion/
- * Demo: http://www.filamentgroup.com/examples/pxToEm/
- *
- * Options:
- scope: string or jQuery selector for font-size scoping
- reverse: Boolean, true reverses the conversion to em-px
- * Dependencies: jQuery library
- * Usage Example: myPixelValue.pxToEm(); or myPixelValue.pxToEm({'scope':'#navigation', reverse: true});
- *
- * Version: 2.0, 08.01.2008
- * Changelog:
- * 08.02.2007 initial Version 1.0
- * 08.01.2008 - fixed font-size calculation for IE
---------------------------------------------------------------------*/
-
-Number.prototype.pxToEm = String.prototype.pxToEm = function(settings){
- //set defaults
- settings = jQuery.extend({
- scope: 'body',
- reverse: false
- }, settings);
-
- var pxVal = (this == '') ? 0 : parseFloat(this);
- var scopeVal;
- var getWindowWidth = function(){
- var de = document.documentElement;
- return self.innerWidth || (de && de.clientWidth) || document.body.clientWidth;
- };
-
- /* When a percentage-based font-size is set on the body, IE returns that percent of the window width as the font-size.
- For example, if the body font-size is 62.5% and the window width is 1000px, IE will return 625px as the font-size.
- When this happens, we calculate the correct body font-size (%) and multiply it by 16 (the standard browser font size)
- to get an accurate em value. */
-
- if (settings.scope == 'body' && $.browser.msie && (parseFloat($('body').css('font-size')) / getWindowWidth()).toFixed(1) > 0.0) {
- var calcFontSize = function(){
- return (parseFloat($('body').css('font-size'))/getWindowWidth()).toFixed(3) * 16;
- };
- scopeVal = calcFontSize();
- }
- else { scopeVal = parseFloat(jQuery(settings.scope).css("font-size")); };
-
- var result = (settings.reverse == true) ? (pxVal * scopeVal).toFixed(2) + 'px' : (pxVal / scopeVal).toFixed(2) + 'em';
- return result;
-};
\ No newline at end of file
diff --git a/vendor/assets/javascripts/history/README.md b/vendor/assets/javascripts/history/README.md
deleted file mode 100644
index 1269bb647..000000000
--- a/vendor/assets/javascripts/history/README.md
+++ /dev/null
@@ -1,4 +0,0 @@
-= Forked version of history.js
-
-This file is being included from a forked version of history.js, specifically a branch that doesn't unencode parameters passed in via URL:
-https://github.com/palexander/history.js/tree/fix_unencoding_of_params
\ No newline at end of file
diff --git a/vendor/assets/javascripts/history/jquery.history.js b/vendor/assets/javascripts/history/jquery.history.js
deleted file mode 100644
index 6bd993b38..000000000
--- a/vendor/assets/javascripts/history/jquery.history.js
+++ /dev/null
@@ -1 +0,0 @@
-window.JSON||(window.JSON={}),function(){"use strict";function f(e){return e<10?"0"+e:e}function quote(e){return escapable.lastIndex=0,escapable.test(e)?'"'+e.replace(escapable,function(e){var t=meta[e];return typeof t=="string"?t:"\\u"+("0000"+e.charCodeAt(0).toString(16)).slice(-4)})+'"':'"'+e+'"'}function str(e,t){var n,r,i,s,o=gap,u,a=t[e];a&&typeof a=="object"&&typeof a.toJSON=="function"&&(a=a.toJSON(e)),typeof rep=="function"&&(a=rep.call(t,e,a));switch(typeof a){case"string":return quote(a);case"number":return isFinite(a)?String(a):"null";case"boolean":case"null":return String(a);case"object":if(!a)return"null";gap+=indent,u=[];if(Object.prototype.toString.apply(a)==="[object Array]"){s=a.length;for(n=0;n ")&&n[0]);return e>4?e:!1}();return e},h.isInternetExplorer=function(){var e=h.isInternetExplorer.cached=typeof h.isInternetExplorer.cached!="undefined"?h.isInternetExplorer.cached:Boolean(h.getInternetExplorerMajorVersion());return e},h.emulated={pushState:!Boolean(e.history&&e.history.pushState&&e.history.replaceState&&!/ Mobile\/([1-7][a-z]|(8([abcde]|f(1[0-8]))))/i.test(i.userAgent)&&!/AppleWebKit\/5([0-2]|3[0-2])/i.test(i.userAgent)),hashChange:Boolean(!("onhashchange"in e||"onhashchange"in r)||h.isInternetExplorer()&&h.getInternetExplorerMajorVersion()<8)},h.enabled=!h.emulated.pushState,h.bugs={setHash:Boolean(!h.emulated.pushState&&i.vendor==="Apple Computer, Inc."&&/AppleWebKit\/5([0-2]|3[0-3])/.test(i.userAgent)),safariPoll:Boolean(!h.emulated.pushState&&i.vendor==="Apple Computer, Inc."&&/AppleWebKit\/5([0-2]|3[0-3])/.test(i.userAgent)),ieDoubleCheck:Boolean(h.isInternetExplorer()&&h.getInternetExplorerMajorVersion()<8),hashEscape:Boolean(h.isInternetExplorer()&&h.getInternetExplorerMajorVersion()<7)},h.isEmptyObject=function(e){for(var t in e)return!1;return!0},h.cloneObject=function(e){var t,n;return e?(t=l.stringify(e),n=l.parse(t)):n={},n},h.getRootUrl=function(){var e=r.location.protocol+"//"+(r.location.hostname||r.location.host);if(r.location.port||!1)e+=":"+r.location.port;return e+="/",e},h.getBaseHref=function(){var e=r.getElementsByTagName("base"),t=null,n="";return e.length===1&&(t=e[0],n=t.href.replace(/[^\/]+$/,"")),n=n.replace(/\/+$/,""),n&&(n+="/"),n},h.getBaseUrl=function(){var e=h.getBaseHref()||h.getBasePageUrl()||h.getRootUrl();return e},h.getPageUrl=function(){var e=h.getState(!1,!1),t=(e||{}).url||r.location.href,n;return n=t.replace(/\/+$/,"").replace(/[^\/]+$/,function(e,t,n){return/\./.test(e)?e:e+"/"}),n},h.getBasePageUrl=function(){var e=r.location.href.replace(/[#\?].*/,"").replace(/[^\/]+$/,function(e,t,n){return/[^\/]$/.test(e)?"":e}).replace(/\/+$/,"")+"/";return e},h.getFullUrl=function(e,t){var n=e,r=e.substring(0,1);return t=typeof t=="undefined"?!0:t,/[a-z]+\:\/\//.test(e)||(r==="/"?n=h.getRootUrl()+e.replace(/^\/+/,""):r==="#"?n=h.getPageUrl().replace(/#.*/,"")+e:r==="?"?n=h.getPageUrl().replace(/[\?#].*/,"")+e:t?n=h.getBaseUrl()+e.replace(/^(\.\/)+/,""):n=h.getBasePageUrl()+e.replace(/^(\.\/)+/,"")),n.replace(/\#$/,"")},h.getShortUrl=function(e){var t=e,n=h.getBaseUrl(),r=h.getRootUrl();return h.emulated.pushState&&(t=t.replace(n,"")),t=t.replace(r,"/"),h.isTraditionalAnchor(t)&&(t="./"+t),t=t.replace(/^(\.\/)+/g,"./").replace(/\#$/,""),t},h.store={},h.idToState=h.idToState||{},h.stateToId=h.stateToId||{},h.urlToId=h.urlToId||{},h.storedStates=h.storedStates||[],h.savedStates=h.savedStates||[],h.normalizeStore=function(){h.store.idToState=h.store.idToState||{},h.store.urlToId=h.store.urlToId||{},h.store.stateToId=h.store.stateToId||{}},h.getState=function(e,t){typeof e=="undefined"&&(e=!0),typeof t=="undefined"&&(t=!0);var n=h.getLastSavedState();return!n&&t&&(n=h.createStateObject()),e&&(n=h.cloneObject(n),n.url=n.cleanUrl||n.url),n},h.getIdByState=function(e){var t=h.extractId(e.url),n;if(!t){n=h.getStateString(e);if(typeof h.stateToId[n]!="undefined")t=h.stateToId[n];else if(typeof h.store.stateToId[n]!="undefined")t=h.store.stateToId[n];else{for(;;){t=(new Date).getTime()+String(Math.random()).replace(/\D/g,"");if(typeof h.idToState[t]=="undefined"&&typeof h.store.idToState[t]=="undefined")break}h.stateToId[n]=t,h.idToState[t]=e}}return t},h.normalizeState=function(e){var t,n;if(!e||typeof e!="object")e={};if(typeof e.normalized!="undefined")return e;if(!e.data||typeof e.data!="object")e.data={};t={},t.normalized=!0,t.title=e.title||"",t.url=h.getFullUrl(e.url||r.location.href),t.hash=h.getShortUrl(t.url),t.data=h.cloneObject(e.data),t.id=h.getIdByState(t),t.cleanUrl=t.url.replace(/\??\&_suid.*/,""),t.url=t.cleanUrl,n=!h.isEmptyObject(t.data);if(t.title||n)t.hash=h.getShortUrl(t.url).replace(/\??\&_suid.*/,""),/\?/.test(t.hash)||(t.hash+="?"),t.hash+="&_suid="+t.id;return t.hashedUrl=h.getFullUrl(t.hash),(h.emulated.pushState||h.bugs.safariPoll)&&h.hasUrlDuplicate(t)&&(t.url=t.hashedUrl),t},h.createStateObject=function(e,t,n){var r={data:e,title:t,url:n};return r=h.normalizeState(r),r},h.getStateById=function(e){e=String(e);var n=h.idToState[e]||h.store.idToState[e]||t;return n},h.getStateString=function(e){var t,n,r;return t=h.normalizeState(e),n={data:t.data,title:e.title,url:e.url},r=l.stringify(n),r},h.getStateId=function(e){var t,n;return t=h.normalizeState(e),n=t.id,n},h.getHashByState=function(e){var t,n;return t=h.normalizeState(e),n=t.hash,n},h.extractId=function(e){var t,n,r;return n=/(.*)\&_suid=([0-9]+)$/.exec(e),r=n?n[1]||e:e,t=n?String(n[2]||""):"",t||!1},h.isTraditionalAnchor=function(e){var t=!/[\/\?\.]/.test(e);return t},h.extractState=function(e,t){var n=null,r,i;return t=t||!1,r=h.extractId(e),r&&(n=h.getStateById(r)),n||(i=h.getFullUrl(e),r=h.getIdByUrl(i)||!1,r&&(n=h.getStateById(r)),!n&&t&&!h.isTraditionalAnchor(e)&&(n=h.createStateObject(null,null,i))),n},h.getIdByUrl=function(e){var n=h.urlToId[e]||h.store.urlToId[e]||t;return n},h.getLastSavedState=function(){return h.savedStates[h.savedStates.length-1]||t},h.getLastStoredState=function(){return h.storedStates[h.storedStates.length-1]||t},h.hasUrlDuplicate=function(e){var t=!1,n;return n=h.extractState(e.url),t=n&&n.id!==e.id,t},h.storeState=function(e){return h.urlToId[e.url]=e.id,h.storedStates.push(h.cloneObject(e)),e},h.isLastSavedState=function(e){var t=!1,n,r,i;return h.savedStates.length&&(n=e.id,r=h.getLastSavedState(),i=r.id,t=n===i),t},h.saveState=function(e){return h.isLastSavedState(e)?!1:(h.savedStates.push(h.cloneObject(e)),!0)},h.getStateByIndex=function(e){var t=null;return typeof e=="undefined"?t=h.savedStates[h.savedStates.length-1]:e<0?t=h.savedStates[h.savedStates.length+e]:t=h.savedStates[e],t},h.getHash=function(){var e=h.unescapeHash(r.location.hash);return e},h.unescapeString=function(t){var n=t,r;for(;;){r=e.unescape(n);if(r===n)break;n=r}return n},h.unescapeHash=function(e){var t=h.normalizeHash(e);return t=h.unescapeString(t),t},h.normalizeHash=function(e){var t=e.replace(/[^#]*#/,"").replace(/#.*/,"");return t},h.setHash=function(e,t){var n,i,s;return t!==!1&&h.busy()?(h.pushQueue({scope:h,callback:h.setHash,args:arguments,queue:t}),!1):(n=h.escapeHash(e),h.busy(!0),i=h.extractState(e,!0),i&&!h.emulated.pushState?h.pushState(i.data,i.title,i.url,!1):r.location.hash!==n&&(h.bugs.setHash?(s=h.getPageUrl(),h.pushState(null,null,s+"#"+n,!1)):r.location.hash=n),h)},h.escapeHash=function(t){var n=h.normalizeHash(t);return n=e.escape(n),h.bugs.hashEscape||(n=n.replace(/\%21/g,"!").replace(/\%26/g,"&").replace(/\%3D/g,"=").replace(/\%3F/g,"?")),n},h.getHashByUrl=function(e){var t=String(e).replace(/([^#]*)#?([^#]*)#?(.*)/,"$2");return t=h.unescapeHash(t),t},h.setTitle=function(e){var t=e.title,n;t||(n=h.getStateByIndex(0),n&&n.url===e.url&&(t=n.title||h.options.initialTitle));try{r.getElementsByTagName("title")[0].innerHTML=t.replace("<","<").replace(">",">").replace(" & "," & ")}catch(i){}return r.title=t,h},h.queues=[],h.busy=function(e){typeof e!="undefined"?h.busy.flag=e:typeof h.busy.flag=="undefined"&&(h.busy.flag=!1);if(!h.busy.flag){u(h.busy.timeout);var t=function(){var e,n,r;if(h.busy.flag)return;for(e=h.queues.length-1;e>=0;--e){n=h.queues[e];if(n.length===0)continue;r=n.shift(),h.fireQueueItem(r),h.busy.timeout=o(t,h.options.busyDelay)}};h.busy.timeout=o(t,h.options.busyDelay)}return h.busy.flag},h.busy.flag=!1,h.fireQueueItem=function(e){return e.callback.apply(e.scope||h,e.args||[])},h.pushQueue=function(e){return h.queues[e.queue||0]=h.queues[e.queue||0]||[],h.queues[e.queue||0].push(e),h},h.queue=function(e,t){return typeof e=="function"&&(e={callback:e}),typeof t!="undefined"&&(e.queue=t),h.busy()?h.pushQueue(e):h.fireQueueItem(e),h},h.clearQueue=function(){return h.busy.flag=!1,h.queues=[],h},h.stateChanged=!1,h.doubleChecker=!1,h.doubleCheckComplete=function(){return h.stateChanged=!0,h.doubleCheckClear(),h},h.doubleCheckClear=function(){return h.doubleChecker&&(u(h.doubleChecker),h.doubleChecker=!1),h},h.doubleCheck=function(e){return h.stateChanged=!1,h.doubleCheckClear(),h.bugs.ieDoubleCheck&&(h.doubleChecker=o(function(){return h.doubleCheckClear(),h.stateChanged||e(),!0},h.options.doubleCheckInterval)),h},h.safariStatePoll=function(){var t=h.extractState(r.location.href),n;if(!h.isLastSavedState(t))return n=t,n||(n=h.createStateObject()),h.Adapter.trigger(e,"popstate"),h;return},h.back=function(e){return e!==!1&&h.busy()?(h.pushQueue({scope:h,callback:h.back,args:arguments,queue:e}),!1):(h.busy(!0),h.doubleCheck(function(){h.back(!1)}),p.go(-1),!0)},h.forward=function(e){return e!==!1&&h.busy()?(h.pushQueue({scope:h,callback:h.forward,args:arguments,queue:e}),!1):(h.busy(!0),h.doubleCheck(function(){h.forward(!1)}),p.go(1),!0)},h.go=function(e,t){var n;if(e>0)for(n=1;n<=e;++n)h.forward(t);else{if(!(e<0))throw new Error("History.go: History.go requires a positive or negative integer passed.");for(n=-1;n>=e;--n)h.back(t)}return h};if(h.emulated.pushState){var d=function(){};h.pushState=h.pushState||d,h.replaceState=h.replaceState||d}else h.onPopState=function(t,n){var i=!1,s=!1,o,u;return h.doubleCheckComplete(),o=h.getHash(),o?(u=h.extractState(o||r.location.href,!0),u?h.replaceState(u.data,u.title,u.url,!1):(h.Adapter.trigger(e,"anchorchange"),h.busy(!1)),h.expectedStateId=!1,!1):(i=h.Adapter.extractEventData("state",t,n)||!1,i?s=h.getStateById(i):h.expectedStateId?s=h.getStateById(h.expectedStateId):s=h.extractState(r.location.href),s||(s=h.createStateObject(null,null,r.location.href)),h.expectedStateId=!1,h.isLastSavedState(s)?(h.busy(!1),!1):(h.storeState(s),h.saveState(s),h.setTitle(s),h.Adapter.trigger(e,"statechange"),h.busy(!1),!0))},h.Adapter.bind(e,"popstate",h.onPopState),h.pushState=function(t,n,r,i){if(h.getHashByUrl(r)&&h.emulated.pushState)throw new Error("History.js does not support states with fragement-identifiers (hashes/anchors).");if(i!==!1&&h.busy())return h.pushQueue({scope:h,callback:h.pushState,args:arguments,queue:i}),!1;h.busy(!0);var s=h.createStateObject(t,n,r);return h.isLastSavedState(s)?h.busy(!1):(h.storeState(s),h.expectedStateId=s.id,p.pushState(s.id,s.title,s.url),h.Adapter.trigger(e,"popstate")),!0},h.replaceState=function(t,n,r,i){if(h.getHashByUrl(r)&&h.emulated.pushState)throw new Error("History.js does not support states with fragement-identifiers (hashes/anchors).");if(i!==!1&&h.busy())return h.pushQueue({scope:h,callback:h.replaceState,args:arguments,queue:i}),!1;h.busy(!0);var s=h.createStateObject(t,n,r);return h.isLastSavedState(s)?h.busy(!1):(h.storeState(s),h.expectedStateId=s.id,p.replaceState(s.id,s.title,s.url),h.Adapter.trigger(e,"popstate")),!0};if(s){try{h.store=l.parse(s.getItem("History.store"))||{}}catch(v){h.store={}}h.normalizeStore()}else h.store={},h.normalizeStore();h.Adapter.bind(e,"beforeunload",h.clearAllIntervals),h.Adapter.bind(e,"unload",h.clearAllIntervals),h.saveState(h.storeState(h.extractState(r.location.href,!0))),s&&(h.onUnload=function(){var e,t;try{e=l.parse(s.getItem("History.store"))||{}}catch(n){e={}}e.idToState=e.idToState||{},e.urlToId=e.urlToId||{},e.stateToId=e.stateToId||{};for(t in h.idToState){if(!h.idToState.hasOwnProperty(t))continue;e.idToState[t]=h.idToState[t]}for(t in h.urlToId){if(!h.urlToId.hasOwnProperty(t))continue;e.urlToId[t]=h.urlToId[t]}for(t in h.stateToId){if(!h.stateToId.hasOwnProperty(t))continue;e.stateToId[t]=h.stateToId[t]}h.store=e,h.normalizeStore(),s.setItem("History.store",l.stringify(e))},h.intervalList.push(a(h.onUnload,h.options.storeInterval)),h.Adapter.bind(e,"beforeunload",h.onUnload),h.Adapter.bind(e,"unload",h.onUnload));if(!h.emulated.pushState){h.bugs.safariPoll&&h.intervalList.push(a(h.safariStatePoll,h.options.safariPollInterval));if(i.vendor==="Apple Computer, Inc."||(i.appCodeName||"")==="Mozilla")h.Adapter.bind(e,"hashchange",function(){h.Adapter.trigger(e,"popstate")}),h.getHash()&&h.Adapter.onDomLoad(function(){h.Adapter.trigger(e,"hashchange")})}},h.init()}(window)
\ No newline at end of file
diff --git a/vendor/assets/javascripts/ie6notice.js b/vendor/assets/javascripts/ie6notice.js
deleted file mode 100644
index 74c35aa12..000000000
--- a/vendor/assets/javascripts/ie6notice.js
+++ /dev/null
@@ -1,105 +0,0 @@
-function ie6CookieCheck()
-{
- /*------------------------------
- Check if a cookie has been set
- ------------------------------*/
- if (document.cookie.length > 0)
- {
- if(document.cookie.indexOf("ie6Notice") == -1)
- {
- /*------------------------------
- Check user has hidden notice. If not show it.
- ------------------------------*/
- ie6Notice();
- }
- }
-}
-function ie6Notice()
-{
- /*------------------------------
- Set variables
- ------------------------------*/
- var head, body, noticeDiv, noticeParagraph, noticeText, ie6css, hideText, hideLink, hideParagraph;
-
- /*------------------------------
- Check getElementsByTagName support
- ------------------------------*/
- if(!document.getElementsByTagName) { return; }
-
- /*------------------------------
- Get head element
- ------------------------------*/
- head = document.getElementsByTagName("head")[0];
- if (!head) { return;}
-
- /*------------------------------
- Create and insert CSS link into head
- ------------------------------*/
- ie6Css = document.createElement('link');
- ie6Css.setAttribute("rel", "stylesheet");
- ie6Css.setAttribute("href", "http://shapeshed.github.com/ie6-notice/css/ie6_notice.css");
- ie6Css.setAttribute("type", "text/css");
- ie6Css.setAttribute("media", "screen");
-
- head.appendChild(ie6Css);
-
- /*------------------------------
- Get body element
- ------------------------------*/
- body = document.getElementsByTagName("body")[0];
- if (!body) { return;}
-
- /*------------------------------
- Create and insert notice div
- ------------------------------*/
- noticeDiv = document.createElement('div');
- noticeDiv.id = "ie6-notice";
- body.appendChild(noticeDiv);
-
- /*------------------------------
- Create and insert notice paragraph
- ------------------------------*/
- noticeParagraph = document.createElement('p');
- noticeParagraph.id = "ie6-text";
- noticeDiv.appendChild(noticeParagraph);
-
- /*------------------------------
- Create and insert notice text
- ------------------------------*/
- noticeText = 'You appear to be browsing this site using Internet Explorer 6. This browser is no longer supported by Microsoft or this site. For safer, more reliable browsing it is recommended that you upgrade to the most recent version of Firefox , Safari , Chrome , or Internet Explorer ';
- noticeParagraph.innerHTML=noticeText;
-
- /*------------------------------
- Create and insert hide paragraph
- ------------------------------*/
- hideParagraph = document.createElement('p');
- hideParagraph.id = "ie6-hide-notice";
- noticeDiv.appendChild(hideParagraph);
-
- /*------------------------------
- Create and insert hide link
- ------------------------------*/
- hideLink = document.createElement('a');
- hideLink.setAttribute("href", "#");
- hideParagraph.appendChild(hideLink);
-
- /*------------------------------
- Create and insert hide text
- ------------------------------*/
- hideText = document.createTextNode('Hide this message');
- hideLink.appendChild(hideText);
-
- hideParagraph.onclick = function()
- {
- var today = new Date();
- var expiry = new Date(today.getTime() + 30 * 86400 * 1000);
- document.cookie = name + "=" + "ie6Notice" + "; expires=" + expiry.toGMTString() + "; path=/";
- noticeDiv.style.display="none";
- ie6Css.removeAttribute("href");
- ie6css = null;
- noticeDiv = null;
- return false;
- }
-
-}
-ie6CookieCheck();
diff --git a/vendor/assets/javascripts/jquery.cookie.js b/vendor/assets/javascripts/jquery.cookie.js
deleted file mode 100644
index 927190008..000000000
--- a/vendor/assets/javascripts/jquery.cookie.js
+++ /dev/null
@@ -1,117 +0,0 @@
-/*!
- * jQuery Cookie Plugin v1.4.0
- * https://github.com/carhartl/jquery-cookie
- *
- * Copyright 2013 Klaus Hartl
- * Released under the MIT license
- */
-(function (factory) {
- if (typeof define === 'function' && define.amd) {
- // AMD. Register as anonymous module.
- define(['jquery'], factory);
- } else {
- // Browser globals.
- factory(jQuery);
- }
-}(function ($) {
-
- var pluses = /\+/g;
-
- function encode(s) {
- return config.raw ? s : encodeURIComponent(s);
- }
-
- function decode(s) {
- return config.raw ? s : decodeURIComponent(s);
- }
-
- function stringifyCookieValue(value) {
- return encode(config.json ? JSON.stringify(value) : String(value));
- }
-
- function parseCookieValue(s) {
- if (s.indexOf('"') === 0) {
- // This is a quoted cookie as according to RFC2068, unescape...
- s = s.slice(1, -1).replace(/\\"/g, '"').replace(/\\\\/g, '\\');
- }
-
- try {
- // Replace server-side written pluses with spaces.
- // If we can't decode the cookie, ignore it, it's unusable.
- s = decodeURIComponent(s.replace(pluses, ' '));
- } catch(e) {
- return;
- }
-
- try {
- // If we can't parse the cookie, ignore it, it's unusable.
- return config.json ? JSON.parse(s) : s;
- } catch(e) {}
- }
-
- function read(s, converter) {
- var value = config.raw ? s : parseCookieValue(s);
- return $.isFunction(converter) ? converter(value) : value;
- }
-
- var config = $.cookie = function (key, value, options) {
-
- // Write
- if (value !== undefined && !$.isFunction(value)) {
- options = $.extend({}, config.defaults, options);
-
- if (typeof options.expires === 'number') {
- var days = options.expires, t = options.expires = new Date();
- t.setDate(t.getDate() + days);
- }
-
- return (document.cookie = [
- encode(key), '=', stringifyCookieValue(value),
- options.expires ? '; expires=' + options.expires.toUTCString() : '', // use expires attribute, max-age is not supported by IE
- options.path ? '; path=' + options.path : '',
- options.domain ? '; domain=' + options.domain : '',
- options.secure ? '; secure' : ''
- ].join(''));
- }
-
- // Read
-
- var result = key ? undefined : {};
-
- // To prevent the for loop in the first place assign an empty array
- // in case there are no cookies at all. Also prevents odd result when
- // calling $.cookie().
- var cookies = document.cookie ? document.cookie.split('; ') : [];
-
- for (var i = 0, l = cookies.length; i < l; i++) {
- var parts = cookies[i].split('=');
- var name = decode(parts.shift());
- var cookie = parts.join('=');
-
- if (key && key === name) {
- // If second argument (value) is a function it's a converter...
- result = read(cookie, value);
- break;
- }
-
- // Prevent storing a cookie that we couldn't decode.
- if (!key && (cookie = read(cookie)) !== undefined) {
- result[name] = cookie;
- }
- }
-
- return result;
- };
-
- config.defaults = {};
-
- $.removeCookie = function (key, options) {
- if ($.cookie(key) !== undefined) {
- // Must not alter options, thus extending a fresh object...
- $.cookie(key, '', $.extend({}, options, { expires: -1 }));
- return true;
- }
- return false;
- };
-
-}));
diff --git a/vendor/assets/javascripts/jquery.hoverIntent.js b/vendor/assets/javascripts/jquery.hoverIntent.js
deleted file mode 100644
index e9ebcfc09..000000000
--- a/vendor/assets/javascripts/jquery.hoverIntent.js
+++ /dev/null
@@ -1,107 +0,0 @@
-/**
-* hoverIntent is similar to jQuery's built-in "hover" function except that
-* instead of firing the onMouseOver event immediately, hoverIntent checks
-* to see if the user's mouse has slowed down (beneath the sensitivity
-* threshold) before firing the onMouseOver event.
-*
-* hoverIntent r6 // 2011.02.26 // jQuery 1.5.1+
-*
-*
-* hoverIntent is currently available for use in all personal or commercial
-* projects under both MIT and GPL licenses. This means that you can choose
-* the license that best suits your project, and use it accordingly.
-*
-* // basic usage (just like .hover) receives onMouseOver and onMouseOut functions
-* $("ul li").hoverIntent( showNav , hideNav );
-*
-* // advanced usage receives configuration object only
-* $("ul li").hoverIntent({
-* sensitivity: 7, // number = sensitivity threshold (must be 1 or higher)
-* interval: 100, // number = milliseconds of polling interval
-* over: showNav, // function = onMouseOver callback (required)
-* timeout: 0, // number = milliseconds delay before onMouseOut function call
-* out: hideNav // function = onMouseOut callback (required)
-* });
-*
-* @param f onMouseOver function || An object with configuration options
-* @param g onMouseOut function || Nothing (use configuration options object)
-* @author Brian Cherne
-*/
-(function($) {
- $.fn.hoverIntent = function(f,g) {
- // default configuration options
- var cfg = {
- sensitivity: 7,
- interval: 100,
- timeout: 0
- };
- // override configuration options with user supplied object
- cfg = $.extend(cfg, g ? { over: f, out: g } : f );
-
- // instantiate variables
- // cX, cY = current X and Y position of mouse, updated by mousemove event
- // pX, pY = previous X and Y position of mouse, set by mouseover and polling interval
- var cX, cY, pX, pY;
-
- // A private function for getting mouse position
- var track = function(ev) {
- cX = ev.pageX;
- cY = ev.pageY;
- };
-
- // A private function for comparing current and previous mouse position
- var compare = function(ev,ob) {
- ob.hoverIntent_t = clearTimeout(ob.hoverIntent_t);
- // compare mouse positions to see if they've crossed the threshold
- if ( ( Math.abs(pX-cX) + Math.abs(pY-cY) ) < cfg.sensitivity ) {
- $(ob).unbind("mousemove",track);
- // set hoverIntent state to true (so mouseOut can be called)
- ob.hoverIntent_s = 1;
- return cfg.over.apply(ob,[ev]);
- } else {
- // set previous coordinates for next time
- pX = cX; pY = cY;
- // use self-calling timeout, guarantees intervals are spaced out properly (avoids JavaScript timer bugs)
- ob.hoverIntent_t = setTimeout( function(){compare(ev, ob);} , cfg.interval );
- }
- };
-
- // A private function for delaying the mouseOut function
- var delay = function(ev,ob) {
- ob.hoverIntent_t = clearTimeout(ob.hoverIntent_t);
- ob.hoverIntent_s = 0;
- return cfg.out.apply(ob,[ev]);
- };
-
- // A private function for handling mouse 'hovering'
- var handleHover = function(e) {
- // copy objects to be passed into t (required for event object to be passed in IE)
- var ev = jQuery.extend({},e);
- var ob = this;
-
- // cancel hoverIntent timer if it exists
- if (ob.hoverIntent_t) { ob.hoverIntent_t = clearTimeout(ob.hoverIntent_t); }
-
- // if e.type == "mouseenter"
- if (e.type == "mouseenter") {
- // set "previous" X and Y position based on initial entry point
- pX = ev.pageX; pY = ev.pageY;
- // update "current" X and Y position based on mousemove
- $(ob).bind("mousemove",track);
- // start polling interval (self-calling timeout) to compare mouse coordinates over time
- if (ob.hoverIntent_s != 1) { ob.hoverIntent_t = setTimeout( function(){compare(ev,ob);} , cfg.interval );}
-
- // else e.type == "mouseleave"
- } else {
- // unbind expensive mousemove event
- $(ob).unbind("mousemove",track);
- // if hoverIntent state is true, then call the mouseOut function after the specified delay
- if (ob.hoverIntent_s == 1) { ob.hoverIntent_t = setTimeout( function(){delay(ev,ob);} , cfg.timeout );}
- }
- };
-
- // bind the function to the two event listeners
- return this.bind('mouseenter',handleHover).bind('mouseleave',handleHover);
- };
-})(jQuery);
-
diff --git a/vendor/assets/javascripts/jquery.rating.pack.js b/vendor/assets/javascripts/jquery.rating.pack.js
deleted file mode 100755
index 94c096874..000000000
--- a/vendor/assets/javascripts/jquery.rating.pack.js
+++ /dev/null
@@ -1,11 +0,0 @@
-/*
- ### jQuery Star Rating Plugin v3.13 - 2009-03-26 ###
- * Home: http://www.fyneworks.com/jquery/star-rating/
- * Code: http://code.google.com/p/jquery-star-rating-plugin/
- *
- * Dual licensed under the MIT and GPL licenses:
- * http://www.opensource.org/licenses/mit-license.php
- * http://www.gnu.org/licenses/gpl.html
- ###
-*/
-eval(function(p,a,c,k,e,r){e=function(c){return(c35?String.fromCharCode(c+29):c.toString(36))};if(!''.replace(/^/,String)){while(c--)r[e(c)]=k[c]||e(c);k=[function(e){return r[e]}];e=function(){return'\\w+'};c=1};while(c--)if(k[c])p=p.replace(new RegExp('\\b'+e(c)+'\\b','g'),k[c]);return p}(';5(29.1j)(7($){5($.1L.1J)1I{1t.1H("1K",J,H)}1M(e){};$.n.3=7(i){5(4.Q==0)k 4;5(A I[0]==\'1h\'){5(4.Q>1){8 j=I;k 4.W(7(){$.n.3.y($(4),j)})};$.n.3[I[0]].y(4,$.1T(I).1U(1)||[]);k 4};8 i=$.12({},$.n.3.1s,i||{});$.n.3.K++;4.2a(\'.9-3-1f\').o(\'9-3-1f\').W(7(){8 a,l=$(4);8 b=(4.23||\'21-3\').1v(/\\[|\\]/g,\'Z\').1v(/^\\Z+|\\Z+$/g,\'\');8 c=$(4.1X||1t.1W);8 d=c.6(\'3\');5(!d||d.18!=$.n.3.K)d={z:0,18:$.n.3.K};8 e=d[b];5(e)a=e.6(\'3\');5(e&&a)a.z++;x{a=$.12({},i||{},($.1b?l.1b():($.1S?l.6():s))||{},{z:0,F:[],v:[]});a.w=d.z++;e=$(\'<1R V="9-3-1Q"/>\');l.1P(e);e.o(\'3-15-T-17\');5(l.S(\'R\'))a.m=H;e.1c(a.E=$(\'\'+a.1d+\'
\').1g(7(){$(4).3(\'O\');$(4).o(\'9-3-N\')}).1i(7(){$(4).3(\'u\');$(4).G(\'9-3-N\')}).1l(7(){$(4).3(\'r\')}).6(\'3\',a))};8 f=$(\'\'+4.1p+\'
\');e.1c(f);5(4.11)f.S(\'11\',4.11);5(4.1r)f.o(4.1r);5(a.1F)a.t=2;5(A a.t==\'1u\'&&a.t>0){8 g=($.n.10?f.10():0)||a.1w;8 h=(a.z%a.t),Y=1y.1z(g/a.t);f.10(Y).1A(\'a\').1B({\'1C-1D\':\'-\'+(h*Y)+\'1E\'})};5(a.m)f.o(\'9-3-1o\');x f.o(\'9-3-1G\').1g(7(){$(4).3(\'1n\');$(4).3(\'D\')}).1i(7(){$(4).3(\'u\');$(4).3(\'C\')}).1l(7(){$(4).3(\'r\')});5(4.L)a.p=f;l.1q();l.1N(7(){$(4).3(\'r\')});f.6(\'3.l\',l.6(\'3.9\',f));a.F[a.F.Q]=f[0];a.v[a.v.Q]=l[0];a.q=d[b]=e;a.1O=c;l.6(\'3\',a);e.6(\'3\',a);f.6(\'3\',a);c.6(\'3\',d)});$(\'.3-15-T-17\').3(\'u\').G(\'3-15-T-17\');k 4};$.12($.n.3,{K:0,D:7(){8 a=4.6(\'3\');5(!a)k 4;5(!a.D)k 4;8 b=$(4).6(\'3.l\')||$(4.U==\'13\'?4:s);5(a.D)a.D.y(b[0],[b.M(),$(\'a\',b.6(\'3.9\'))[0]])},C:7(){8 a=4.6(\'3\');5(!a)k 4;5(!a.C)k 4;8 b=$(4).6(\'3.l\')||$(4.U==\'13\'?4:s);5(a.C)a.C.y(b[0],[b.M(),$(\'a\',b.6(\'3.9\'))[0]])},1n:7(){8 a=4.6(\'3\');5(!a)k 4;5(a.m)k;4.3(\'O\');4.1a().19().X(\'.q-\'+a.w).o(\'9-3-N\')},O:7(){8 a=4.6(\'3\');5(!a)k 4;5(a.m)k;a.q.1V().X(\'.q-\'+a.w).G(\'9-3-1k\').G(\'9-3-N\')},u:7(){8 a=4.6(\'3\');5(!a)k 4;4.3(\'O\');5(a.p){a.p.6(\'3.l\').S(\'L\',\'L\');a.p.1a().19().X(\'.q-\'+a.w).o(\'9-3-1k\')}x $(a.v).1m(\'L\');a.E[a.m||a.1Y?\'1q\':\'1Z\']();4.20()[a.m?\'o\':\'G\'](\'9-3-1o\')},r:7(a,b){8 c=4.6(\'3\');5(!c)k 4;5(c.m)k;c.p=s;5(A a!=\'B\'){5(A a==\'1u\')k $(c.F[a]).3(\'r\',B,b);5(A a==\'1h\')$.W(c.F,7(){5($(4).6(\'3.l\').M()==a)$(4).3(\'r\',B,b)})}x c.p=4[0].U==\'13\'?4.6(\'3.9\'):(4.22(\'.q-\'+c.w)?4:s);4.6(\'3\',c);4.3(\'u\');8 d=$(c.p?c.p.6(\'3.l\'):s);5((b||b==B)&&c.1e)c.1e.y(d[0],[d.M(),$(\'a\',c.p)[0]])},m:7(a,b){8 c=4.6(\'3\');5(!c)k 4;c.m=a||a==B?H:J;5(b)$(c.v).S("R","R");x $(c.v).1m("R");4.6(\'3\',c);4.3(\'u\')},1x:7(){4.3(\'m\',H,H)},24:7(){4.3(\'m\',J,J)}});$.n.3.1s={E:\'25 26\',1d:\'\',t:0,1w:16};$(7(){$(\'l[27=28].9\').3()})})(1j);',62,135,'|||rating|this|if|data|function|var|star|||||||||||return|input|readOnly|fn|addClass|current|rater|select|null|split|draw|inputs|serial|else|apply|count|typeof|undefined|blur|focus|cancel|stars|removeClass|true|arguments|false|calls|checked|val|hover|drain|div|length|disabled|attr|be|tagName|class|each|filter|spw|_|width|id|extend|INPUT|title|to||drawn|call|andSelf|prevAll|metadata|append|cancelValue|callback|applied|mouseover|string|mouseout|jQuery|on|click|removeAttr|fill|readonly|value|hide|className|options|document|number|replace|starWidth|disable|Math|floor|find|css|margin|left|px|half|live|execCommand|try|msie|BackgroundImageCache|browser|catch|change|context|before|control|span|meta|makeArray|slice|children|body|form|required|show|siblings|unnamed|is|name|enable|Cancel|Rating|type|radio|window|not'.split('|'),0,{}))
\ No newline at end of file
diff --git a/vendor/assets/javascripts/jquery.scrollTo-1.4.0-min.js b/vendor/assets/javascripts/jquery.scrollTo-1.4.0-min.js
deleted file mode 100644
index 453382d24..000000000
--- a/vendor/assets/javascripts/jquery.scrollTo-1.4.0-min.js
+++ /dev/null
@@ -1,11 +0,0 @@
-/**
- * jQuery.ScrollTo - Easy element scrolling using jQuery.
- * Copyright (c) 2007-2008 Ariel Flesler - aflesler(at)gmail(dot)com | http://flesler.blogspot.com
- * Dual licensed under MIT and GPL.
- * Date: 9/11/2008
- * @author Ariel Flesler
- * @version 1.4
- *
- * http://flesler.blogspot.com/2007/10/jqueryscrollto.html
- */
-;(function(h){var m=h.scrollTo=function(b,c,g){h(window).scrollTo(b,c,g)};m.defaults={axis:'y',duration:1};m.window=function(b){return h(window).scrollable()};h.fn.scrollable=function(){return this.map(function(){var b=this.parentWindow||this.defaultView,c=this.nodeName=='#document'?b.frameElement||b:this,g=c.contentDocument||(c.contentWindow||c).document,i=c.setInterval;return c.nodeName=='IFRAME'||i&&h.browser.safari?g.body:i?g.documentElement:this})};h.fn.scrollTo=function(r,j,a){if(typeof j=='object'){a=j;j=0}if(typeof a=='function')a={onAfter:a};a=h.extend({},m.defaults,a);j=j||a.speed||a.duration;a.queue=a.queue&&a.axis.length>1;if(a.queue)j/=2;a.offset=n(a.offset);a.over=n(a.over);return this.scrollable().each(function(){var k=this,o=h(k),d=r,l,e={},p=o.is('html,body');switch(typeof d){case'number':case'string':if(/^([+-]=)?\d+(px)?$/.test(d)){d=n(d);break}d=h(d,this);case'object':if(d.is||d.style)l=(d=h(d)).offset()}h.each(a.axis.split(''),function(b,c){var g=c=='x'?'Left':'Top',i=g.toLowerCase(),f='scroll'+g,s=k[f],t=c=='x'?'Width':'Height',v=t.toLowerCase();if(l){e[f]=l[i]+(p?0:s-o.offset()[i]);if(a.margin){e[f]-=parseInt(d.css('margin'+g))||0;e[f]-=parseInt(d.css('border'+g+'Width'))||0}e[f]+=a.offset[i]||0;if(a.over[i])e[f]+=d[v]()*a.over[i]}else e[f]=d[i];if(/^\d+$/.test(e[f]))e[f]=e[f]<=0?0:Math.min(e[f],u(t));if(!b&&a.queue){if(s!=e[f])q(a.onAfterFirst);delete e[f]}});q(a.onAfter);function q(b){o.animate(e,j,a.easing,b&&function(){b.call(this,r,a)})};function u(b){var c='scroll'+b,g=k.ownerDocument;return p?Math.max(g.documentElement[c],g.body[c]):k[c]}}).end()};function n(b){return typeof b=='object'?b:{top:b,left:b}}})(jQuery);
\ No newline at end of file
diff --git a/vendor/assets/javascripts/jquery.simple.tree.js.erb b/vendor/assets/javascripts/jquery.simple.tree.js.erb
deleted file mode 100755
index 3b134b334..000000000
--- a/vendor/assets/javascripts/jquery.simple.tree.js.erb
+++ /dev/null
@@ -1,468 +0,0 @@
-/*
-* jQuery SimpleTree Drag&Drop plugin
-* Update on 22th May 2008
-* Version 0.3
-*
-* Licensed under BSD
-* Copyright (c) 2008, Peter Panov , IKEEN Group http://www.ikeen.com
-* All rights reserved.
-*
-* Redistribution and use in source and binary forms, with or without
-* modification, are permitted provided that the following conditions are met:
-* * Redistributions of source code must retain the above copyright
-* notice, this list of conditions and the following disclaimer.
-* * Redistributions in binary form must reproduce the above copyright
-* notice, this list of conditions and the following disclaimer in the
-* documentation and/or other materials provided with the distribution.
-* * Neither the name of the Peter Panov, IKEEN Group nor the
-* names of its contributors may be used to endorse or promote products
-* derived from this software without specific prior written permission.
-*
-* THIS SOFTWARE IS PROVIDED BY Peter Panov, IKEEN Group ``AS IS'' AND ANY
-* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-* DISCLAIMED. IN NO EVENT SHALL Peter Panov, IKEEN Group BE LIABLE FOR ANY
-* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
-* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-*/
-
-
-$.fn.simpleTree = function(opt){
- return this.each(function(){
- var TREE = this;
- var ROOT = $('.root',this);
- var mousePressed = false;
- var mouseMoved = false;
- var dragMoveType = false;
- var dragNode_destination = false;
- var dragNode_source = false;
- var dragDropTimer = false;
- var ajaxCache = Array();
-
- TREE.option = {
- drag: true,
- animate: false,
- autoclose: false,
- speed: 'fast',
- beforeAjax: false,
- afterAjax: false,
- afterAjaxError: false,
- afterMove: false,
- afterClick: false,
- afterDblClick: false,
- timeout: 999999,
- // added by Erik Dohmen (2BinBusiness.nl) to make context menu cliks available
- afterContextMenu: false,
- docToFolderConvert:false
- };
- TREE.option = $.extend(TREE.option,opt);
- $.extend(this, {getSelected: function(){
- return $('span.active', this).parent();
- }});
- TREE.closeNearby = function(obj)
- {
- $(obj).siblings().filter('.folder-open, .folder-open-last').each(function(){
- var childUl = $('>ul',this);
- var className = this.className;
- this.className = className.replace('open','close');
- if(TREE.option.animate)
- {
- childUl.animate({height:"toggle"},TREE.option.speed);
- }else{
- childUl.hide();
- }
- });
- };
- TREE.nodeToggle = function(obj)
- {
- var childUl = $('>ul',obj);
- if(childUl.is(':visible')){
- obj.className = obj.className.replace('open','close');
-
- if(TREE.option.animate)
- {
- childUl.animate({height:"toggle"},TREE.option.speed);
- }else{
- childUl.hide();
- }
- }else{
- obj.className = obj.className.replace('close','open');
- if(TREE.option.animate)
- {
- childUl.animate({height:"toggle"},TREE.option.speed, function(){
- if(TREE.option.autoclose)TREE.closeNearby(obj);
- if(childUl.is('.ajax'))TREE.setAjaxNodes(childUl, obj.id);
- });
- }else{
- childUl.show();
- if(TREE.option.autoclose)TREE.closeNearby(obj);
- if(childUl.is('.ajax'))TREE.setAjaxNodes(childUl, obj.id);
- }
- }
- };
- TREE.setAjaxNodes = function(node, parentId, successCallback, errorCallback)
- {
- if($.inArray(parentId,ajaxCache) == -1){
- if(typeof TREE.option.beforeAjax == 'function')
- {
- TREE.option.beforeAjax(node);
- }
- var url = $.trim($('a', node).attr("href"));
- if(url)
- {
- $.ajax({
- type: "GET",
- url: url,
- contentType:'text/html',
- cache:false,
- timeout:TREE.option.timeout,
- success: function(response){
- ajaxCache[ajaxCache.length]=parentId;
- node.removeAttr('class');
- node.html(response);
- $.extend(node,{url:url});
- TREE.setTreeNodes(node, true);
- if(typeof TREE.option.afterAjax == 'function')
- {
- TREE.option.afterAjax(node);
- }
- if(typeof successCallback == 'function')
- {
- successCallback(node);
- }
- },
- error: function(response){
- if(typeof TREE.option.afterAjaxError == 'function')
- {
- TREE.option.afterAjaxError(node);
- }
- if(typeof errorCallback == 'function')
- {
- errorCallback(node);
- }
- }
- });
- }
-
- }
- };
- TREE.setTreeNodes = function(obj, useParent){
- obj = useParent? obj.parent():obj;
- $('li>a', obj).addClass('text')
- .bind('selectstart', function() {
- return false;
- }).click(function(){
- $('.active',TREE).attr('class','text');
- if(this.className=='text')
- {
- this.className='active';
- }
- if(typeof TREE.option.afterClick == 'function')
- {
- TREE.option.afterClick($(this).parent());
- }
- return true;
- }).dblclick(function(){
- mousePressed = false;
- TREE.nodeToggle($(this).parent().get(0));
- if(typeof TREE.option.afterDblClick == 'function')
- {
- TREE.option.afterDblClick($(this).parent());
- }
- return false;
- // added by Erik Dohmen (2BinBusiness.nl) to make context menu actions
- // available
- }).bind("contextmenu",function(){
- $('.active',TREE).attr('class','text');
- if(this.className=='text')
- {
- this.className='active';
- }
- if(typeof TREE.option.afterContextMenu == 'function')
- {
- TREE.option.afterContextMenu($(this).parent());
- }
- return false;
- }).mousedown(function(event){
- mousePressed = true;
- cloneNode = $(this).parent().clone();
- var LI = $(this).parent();
- if(TREE.option.drag)
- {
- $('>ul', cloneNode).hide();
- $('body').append('');
- $('#drag_container').hide().css({opacity:'0.8'});
- $('#drag_container >ul').append(cloneNode);
- $(" ").attr({id : "tree_plus", src: "<%= asset_path("jquery.simple.tree/plus.gif") %>"}).css({width: "7px",display: "block",position: "absolute",left : "5px",top: "5px", display:'none'}).appendTo("body");
- $(document).bind("mousemove", {LI:LI}, TREE.dragStart).bind("mouseup",TREE.dragEnd);
- }
- return false;
- }).mouseup(function(){
- if(mousePressed && mouseMoved && dragNode_source)
- {
- TREE.moveNodeToFolder($(this).parent());
- }
- TREE.eventDestroy();
- });
- $('li', obj).each(function(i){
- var className = this.className;
- var open = false;
- var cloneNode=false;
- var LI = this;
- var childNode = $('>ul',this);
- if(childNode.size()>0){
- var setClassName = 'folder-';
- if(className && className.indexOf('open')>=0){
- setClassName=setClassName+'open';
- open=true;
- }else{
- setClassName=setClassName+'close';
- }
- this.className = setClassName + ($(this).is(':last-child')? '-last':'');
-
- if(!open || className.indexOf('ajax')>=0)childNode.hide();
-
- TREE.setTrigger(this);
- }else{
- var setClassName = 'doc';
- this.className = setClassName + ($(this).is(':last-child')? '-last':'');
- }
- }).before(' ')
- .filter(':last-child').after(' ');
- TREE.setEventLine($('.line, .line-last', obj));
- };
- TREE.setTrigger = function(node){
- $('>a',node).before('<%= image_tag("jquery.simple.tree/spacer.gif", class: "trigger", border: "0") %>');
- var trigger = $('>.trigger', node);
- trigger.click(function(event){
- TREE.nodeToggle(node);
- });
- if(!$.browser.msie)
- {
- trigger.css('float','left');
- }
- };
- TREE.dragStart = function(event){
- var LI = $(event.data.LI);
- if(mousePressed)
- {
- mouseMoved = true;
- if(dragDropTimer) clearTimeout(dragDropTimer);
- if($('#drag_container:not(:visible)')){
- $('#drag_container').show();
- LI.prev('.line').hide();
- dragNode_source = LI;
- }
- $('#drag_container').css({position:'absolute', "left" : (event.pageX + 5), "top": (event.pageY + 15) });
- if(LI.is(':visible'))LI.hide();
- var temp_move = false;
- if(event.target.tagName.toLowerCase()=='a' && $.inArray(event.target.className, Array('text','active','trigger'))!= -1)
- {
- var parent = event.target.parentNode;
- var offs = $(parent).offset({scroll:false});
- var screenScroll = {x : (offs.left - 3),y : event.pageY - offs.top};
- var isrc = $("#tree_plus").attr('src');
- var ajaxChildSize = $('>ul.ajax',parent).size();
- var ajaxChild = $('>ul.ajax',parent);
- screenScroll.x += 19;
- screenScroll.y = event.pageY - screenScroll.y + 5;
-
- if(parent.className.indexOf('folder-close')>=0 && ajaxChildSize==0)
- {
- if(isrc.indexOf('minus')!=-1)$("#tree_plus").attr('src','<%= asset_path("jquery.simple.tree/plus.gif") %>');
- $("#tree_plus").css({"left": screenScroll.x, "top": screenScroll.y}).show();
- dragDropTimer = setTimeout(function(){
- parent.className = parent.className.replace('close','open');
- $('>ul',parent).show();
- }, 700);
- }else if(parent.className.indexOf('folder')>=0 && ajaxChildSize==0){
- if(isrc.indexOf('minus')!=-1)$("#tree_plus").attr('src','<%= asset_path("jquery.simple.tree/plus.gif") %>');
- $("#tree_plus").css({"left": screenScroll.x, "top": screenScroll.y}).show();
- }else if(parent.className.indexOf('folder-close')>=0 && ajaxChildSize>0)
- {
- mouseMoved = false;
- $("#tree_plus").attr('src','<%= asset_path("jquery.simple.tree/plus.gif") %>');
- $("#tree_plus").css({"left": screenScroll.x, "top": screenScroll.y}).show();
-
- $('>ul',parent).show();
- /*
- Thanks for the idea of Erik Dohmen
- */
- TREE.setAjaxNodes(ajaxChild, parent.id, function(){
- parent.className = parent.className.replace('close','open');
- mouseMoved = true;
- $("#tree_plus").attr('src','<%= asset_path("jquery.simple.tree/plus.gif") %>');
- $("#tree_plus").css({"left": screenScroll.x, "top": screenScroll.y}).show();
- });
-
- }else{
- if(TREE.option.docToFolderConvert)
- {
- $("#tree_plus").css({"left": screenScroll.x, "top": screenScroll.y}).show();
- }else{
- $("#tree_plus").hide();
- }
- }
- }else{
- $("#tree_plus").hide();
- }
- return false;
- }
- return true;
- };
- TREE.dragEnd = function(){
- if(dragDropTimer) clearTimeout(dragDropTimer);
- TREE.eventDestroy();
- };
- TREE.setEventLine = function(obj){
- obj.mouseover(function(){
- if(this.className.indexOf('over')<0 && mousePressed && mouseMoved)
- {
- this.className = this.className.replace('line','line-over');
- }
- }).mouseout(function(){
- if(this.className.indexOf('over')>=0)
- {
- this.className = this.className.replace('-over','');
- }
- }).mouseup(function(){
- if(mousePressed && dragNode_source && mouseMoved)
- {
- dragNode_destination = $(this).parents('li:first');
- TREE.moveNodeToLine(this);
- TREE.eventDestroy();
- }
- });
- };
- TREE.checkNodeIsLast = function(node)
- {
- if(node.className.indexOf('last')>=0)
- {
- var prev_source = dragNode_source.prev().prev();
- if(prev_source.size()>0)
- {
- prev_source[0].className+='-last';
- }
- node.className = node.className.replace('-last','');
- }
- };
- TREE.checkLineIsLast = function(line)
- {
- if(line.className.indexOf('last')>=0)
- {
- var prev = $(line).prev();
- if(prev.size()>0)
- {
- prev[0].className = prev[0].className.replace('-last','');
- }
- dragNode_source[0].className+='-last';
- }
- };
- TREE.eventDestroy = function()
- {
- // added by Erik Dohmen (2BinBusiness.nl), the unbind mousemove TREE.dragStart action
- // like this other mousemove actions binded through other actions ain't removed (use it myself
- // to determine location for context menu)
- $(document).unbind('mousemove',TREE.dragStart).unbind('mouseup').unbind('mousedown');
- $('#drag_container, #tree_plus').remove();
- if(dragNode_source)
- {
- $(dragNode_source).show().prev('.line').show();
- }
- dragNode_destination = dragNode_source = mousePressed = mouseMoved = false;
- //ajaxCache = Array();
- };
- TREE.convertToFolder = function(node){
- node[0].className = node[0].className.replace('doc','folder-open');
- node.append('');
- TREE.setTrigger(node[0]);
- TREE.setEventLine($('.line, .line-last', node));
- };
- TREE.convertToDoc = function(node){
- $('>ul', node).remove();
- $('img', node).remove();
- node[0].className = node[0].className.replace(/folder-(open|close)/gi , 'doc');
- };
- TREE.moveNodeToFolder = function(node)
- {
- if(!TREE.option.docToFolderConvert && node[0].className.indexOf('doc')!=-1)
- {
- return true;
- }else if(TREE.option.docToFolderConvert && node[0].className.indexOf('doc')!=-1){
- TREE.convertToFolder(node);
- }
- TREE.checkNodeIsLast(dragNode_source[0]);
- var lastLine = $('>ul >.line-last', node);
- if(lastLine.size()>0)
- {
- TREE.moveNodeToLine(lastLine[0]);
- }
- };
- TREE.moveNodeToLine = function(node){
- TREE.checkNodeIsLast(dragNode_source[0]);
- TREE.checkLineIsLast(node);
- var parent = $(dragNode_source).parents('li:first');
- var line = $(dragNode_source).prev('.line');
- $(node).before(dragNode_source);
- $(dragNode_source).before(line);
- node.className = node.className.replace('-over','');
- var nodeSize = $('>ul >li', parent).not('.line, .line-last').filter(':visible').size();
- if(TREE.option.docToFolderConvert && nodeSize==0)
- {
- TREE.convertToDoc(parent);
- }else if(nodeSize==0)
- {
- parent[0].className=parent[0].className.replace('open','close');
- $('>ul',parent).hide();
- }
-
- // added by Erik Dohmen (2BinBusiness.nl) select node
- if($('span:first',dragNode_source).attr('class')=='text')
- {
- $('.active',TREE).attr('class','text');
- $('span:first',dragNode_source).attr('class','active');
- }
-
- if(typeof(TREE.option.afterMove) == 'function')
- {
- var pos = $(dragNode_source).prevAll(':not(.line)').size();
- TREE.option.afterMove($(node).parents('li:first'), $(dragNode_source), pos);
- }
- };
-
- TREE.addNode = function(id, text, link, callback)
- {
- var temp_node = $(' ');
- TREE.setTreeNodes(temp_node);
- dragNode_destination = TREE.getSelected();
- dragNode_source = $('.doc-last',temp_node);
- TREE.moveNodeToFolder(dragNode_destination);
- temp_node.remove();
- if(typeof(callback) == 'function')
- {
- callback(dragNode_destination, dragNode_source);
- }
- };
- TREE.delNode = function(callback)
- {
- dragNode_source = TREE.getSelected();
- TREE.checkNodeIsLast(dragNode_source[0]);
- dragNode_source.prev().remove();
- dragNode_source.remove();
- if(typeof(callback) == 'function')
- {
- callback(dragNode_destination);
- }
- };
-
- TREE.init = function(obj)
- {
- TREE.setTreeNodes(obj, false);
- };
- TREE.init(ROOT);
- });
-}
diff --git a/vendor/assets/javascripts/jquery.tools.min.js b/vendor/assets/javascripts/jquery.tools.min.js
deleted file mode 100644
index 95890591d..000000000
--- a/vendor/assets/javascripts/jquery.tools.min.js
+++ /dev/null
@@ -1,118 +0,0 @@
-/*!
- * jQuery Tools v1.2.7 - The missing UI library for the Web
- *
- * dateinput/dateinput.js
- * overlay/overlay.js
- * overlay/overlay.apple.js
- * rangeinput/rangeinput.js
- * scrollable/scrollable.js
- * scrollable/scrollable.autoscroll.js
- * scrollable/scrollable.navigator.js
- * tabs/tabs.js
- * tabs/tabs.slideshow.js
- * toolbox/toolbox.expose.js
- * toolbox/toolbox.flashembed.js
- * toolbox/toolbox.history.js
- * toolbox/toolbox.mousewheel.js
- * tooltip/tooltip.js
- * tooltip/tooltip.dynamic.js
- * tooltip/tooltip.slide.js
- * validator/validator.js
- *
- * NO COPYRIGHTS OR LICENSES. DO WHAT YOU LIKE.
- *
- * http://flowplayer.org/tools/
- *
- * jquery.event.wheel.js - rev 1
- * Copyright (c) 2008, Three Dub Media (http://threedubmedia.com)
- * Liscensed under the MIT License (MIT-LICENSE.txt)
- * http://www.opensource.org/licenses/mit-license.php
- * Created: 2008-07-01 | Updated: 2008-07-14
- *
- * -----
- *
- */
-(function(d,D){function M(b,a){b=""+b;for(a=a||2;b.lengthg?(f.addMonth(-1),j=d("#"+c.weeks+" a:eq("+(g+42)+")")):j=h.eq(g);j.addClass(c.focus);return a.preventDefault()}if(34==e)return f.addMonth();if(33==e)return f.addMonth(-1);if(36==e)return f.today();13==e&&(d(a.target).is("select")||d("."+c.focus).click());return 0<=d([16,17,18,9]).index(e)});d(document).on("click.d",function(a){var e=a.target;!d(e).parents("#"+c.root).length&&e!=b[0]&&(!E||e!=E[0])&&f.hide(a)})}var f=this,q=new Date,k=q.getFullYear(),c=a.css,F=r[a.lang],i=d("#"+c.root),
-K=i.find("#"+c.title),E,G,H,z,B,A,o=b.attr("data-value")||a.value||b.val(),n=b.attr("min")||a.min,p=b.attr("max")||a.max,u,I;0===n&&(n="0");o=w(o)||q;n=w(n||new Date(k+a.yearRange[0],1,1));p=w(p||new Date(k+a.yearRange[1]+1,1,-1));if(!F)throw"Dateinput: invalid language: "+a.lang;"date"==b.attr("type")&&(I=b.clone(),k=I.wrap("
").parent().html(),k=d(k.replace(/type/i,"type=text data-orig-type")),a.value&&k.val(a.value),b.replaceWith(k),b=k);b.addClass(c.input);var C=b.add(f);if(!i.length){i=
-d("").hide().css({position:"absolute"}).attr("id",c.root);i.children().eq(0).attr("id",c.head).end().eq(1).attr("id",c.body).children().eq(0).attr("id",c.days).end().eq(1).attr("id",c.weeks).end().end().end().find("a").eq(0).attr("id",c.prev).end().eq(1).attr("id",c.next);K=i.find("#"+c.head).find("div").attr("id",c.title);if(a.selectors){var x=d(" ").attr("id",c.month),y=d(" ").attr("id",c.year);K.html(x.add(y))}for(var k=
-i.find("#"+c.days),L=0;7>L;L++)k.append(d(" ").text(F.shortDays[(L+a.firstDay)%7]));d("body").append(i)}a.trigger&&(E=d(" ").attr("href","#").addClass(c.trigger).click(function(e){a.toggle?f.toggle():f.show();return e.preventDefault()}).insertAfter(b));var J=i.find("#"+c.weeks),y=i.find("#"+c.year),x=i.find("#"+c.month);d.extend(f,{show:function(e){if(!b.attr("readonly")&&!b.attr("disabled")&&!u){e=e||d.Event();e.type="onBeforeShow";C.trigger(e);if(!e.isDefaultPrevented()){d.each(R,function(){this.hide()});
-u=true;x.off("change").change(function(){f.setValue(l(y.val()),l(d(this).val()))});y.off("change").change(function(){f.setValue(l(d(this).val()),l(x.val()))});G=i.find("#"+c.prev).off("click").click(function(){G.hasClass(c.disabled)||f.addMonth(-1);return false});H=i.find("#"+c.next).off("click").click(function(){H.hasClass(c.disabled)||f.addMonth();return false});f.setValue(o);var t=b.offset();if(/iPad/i.test(navigator.userAgent))t.top=t.top-d(window).scrollTop();i.css({top:t.top+b.outerHeight({margins:true})+
-a.offset[0],left:t.left+a.offset[1]});if(a.speed)i.show(a.speed,function(){g(e)});else{i.show();g(e)}return f}}},setValue:function(e,b,g){var h=l(b)>=-1?new Date(l(e),l(b),l(g==D||isNaN(g)?1:g)):e||o;hp&&(h=p);typeof e=="string"&&(h=w(e));e=h.getFullYear();b=h.getMonth();g=h.getDate();if(b==-1){b=11;e--}else if(b==12){b=0;e++}if(!u){j(h,a);return f}B=b;z=e;A=g;var g=(new Date(e,b,1-a.firstDay)).getDay(),i=(new Date(e,b+1,0)).getDate(),k=(new Date(e,b-1+1,0)).getDate(),r;if(a.selectors){x.empty();
-d.each(F.months,function(a,b){nnew Date(e,a,0)&&x.append(d(" ").html(b).attr("value",a))});y.empty();for(var h=q.getFullYear(),m=h+a.yearRange[0];mnew Date(m,0,0)&&y.append(d(" ").text(m));x.val(b);y.val(e)}else K.html(F.months[b]+" "+e);J.empty();G.add(H).removeClass(c.disabled);for(var m=!g?-7:0,s,v;m<(!g?35:42);m++){s=d(" ");if(m%7===0){r=d("
").addClass(c.week);J.append(r)}if(m=g+i){s.addClass(c.off);v=m-i-g+1;h=new Date(e,b+1,v)}else{v=m-g+1;h=new Date(e,b,v);P(o,h)?s.attr("id",c.current).addClass(c.focus):P(q,h)&&s.attr("id",c.today)}n&&hp&&s.add(H).addClass(c.disabled);s.attr("href","#"+v).text(v).data("date",h);r.append(s)}J.find("a").click(function(b){var e=d(this);if(!e.hasClass(c.disabled)){d("#"+c.current).removeAttr("id");e.attr("id",c.current);j(e.data("date"),a,b)}return false});c.sunday&&
-J.find("."+c.week).each(function(){var b=a.firstDay?7-a.firstDay:0;d(this).children().slice(b,b+1).addClass(c.sunday)});return f},setMin:function(a,b){n=w(a);b&&op&&f.setValue(p);return f},today:function(){return f.setValue(q)},addDay:function(a){return this.setValue(z,B,A+(a||1))},addMonth:function(a){var a=B+(a||1),b=(new Date(z,a+1,0)).getDate();return this.setValue(z,a,A<=b?A:b)},addYear:function(a){return this.setValue(z+(a||1),B,A)},
-destroy:function(){b.add(document).off("click.d keydown.d");i.add(E).remove();b.removeData("dateinput").removeClass(c.input);I&&b.replaceWith(I)},hide:function(a){if(u){a=d.Event();a.type="onHide";C.trigger(a);if(a.isDefaultPrevented())return;d(document).off("click.d keydown.d");i.hide();u=false}return f},toggle:function(){return f.isOpen()?f.hide():f.show()},getConf:function(){return a},getInput:function(){return b},getCalendar:function(){return i},getValue:function(b){return b?N(a.formatter,o,b,
-a.lang):o},isOpen:function(){return u}});d.each(["onBeforeShow","onShow","change","onHide"],function(b,c){if(d.isFunction(a[c]))d(f).on(c,a[c]);f[c]=function(a){if(a)d(f).on(c,a);return f}});a.editable||b.on("focus.d click.d",f.show).keydown(function(a){var c=a.keyCode;if(!u&&d(Q).index(c)>=0){f.show(a);return a.preventDefault()}(c==8||c==46)&&b.val("");return a.shiftKey||a.ctrlKey||a.altKey||c==9?true:a.preventDefault()});w(b.val())&&j(o,a)}d.tools=d.tools||{version:"@VERSION"};var R=[],O={},q,Q=
-[75,76,38,39,74,72,40,37],r={};q=d.tools.dateinput={conf:{format:"mm/dd/yy",formatter:"default",selectors:!1,yearRange:[-5,5],lang:"en",offset:[0,0],speed:0,firstDay:0,min:D,max:D,trigger:0,toggle:0,editable:0,css:{prefix:"cal",input:"date",root:0,head:0,title:0,prev:0,next:0,month:0,year:0,days:0,body:0,weeks:0,today:0,current:0,week:0,off:0,sunday:0,focus:0,disabled:0,trigger:0}},addFormatter:function(b,a){O[b]=a},localize:function(b,a){d.each(a,function(b,d){a[b]=d.split(",")});r[b]=a}};q.localize("en",
-{months:"January,February,March,April,May,June,July,August,September,October,November,December",shortMonths:"Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec",days:"Sunday,Monday,Tuesday,Wednesday,Thursday,Friday,Saturday",shortDays:"Sun,Mon,Tue,Wed,Thu,Fri,Sat"});var S=d(" ");q.addFormatter("default",function(b,a,d){return b.replace(/d{1,4}|m{1,4}|yy(?:yy)?|"[^"]*"|'[^']*'/g,function(a){return a in d?d[a]:a})});q.addFormatter("prefixed",function(b,a,d){return b.replace(/%(d{1,4}|m{1,4}|yy(?:yy)?|"[^"]*"|'[^']*')/g,
-function(a,b){return b in d?d[b]:a})});d.expr[":"].date=function(b){var a=b.getAttribute("type");return a&&"date"==a||!!d(b).data("dateinput")};d.fn.dateinput=function(b){if(this.data("dateinput"))return this;b=d.extend(!0,{},q.conf,b);d.each(b.css,function(a,d){!d&&"prefix"!=a&&(b.css[a]=(b.css.prefix||"")+(d||a))});var a;this.each(function(){var j=new T(d(this),b);R.push(j);j=j.getInput().data("dateinput",j);a=a?a.add(j):j});return a?a:this}})(jQuery);(function(b){function m(a,c){var d=this,h=a.add(d),n=b(window),e,f,k,g=b.tools.expose&&(c.mask||c.expose),l=Math.random().toString().slice(10);g&&("string"==typeof g&&(g={color:g}),g.closeOnClick=g.closeOnEsc=!1);var i=c.target||a.attr("rel");f=i?b(i):a;if(!f.length)throw"Could not find Overlay: "+i;a&&-1==a.index(f)&&a.click(function(b){d.load(b);return b.preventDefault()});b.extend(d,{load:function(a){if(d.isOpened())return d;var p=o[c.effect];if(!p)throw'Overlay: cannot find effect : "'+c.effect+
-'"';c.oneInstance&&b.each(q,function(){this.close(a)});a=a||b.Event();a.type="onBeforeLoad";h.trigger(a);if(a.isDefaultPrevented())return d;k=true;g&&b(f).expose(g);var j=c.top,e=c.left,i=f.outerWidth({margin:true}),m=f.outerHeight({margin:true});typeof j=="string"&&(j=j=="center"?Math.max((n.height()-m)/2,0):parseInt(j,10)/100*n.height());e=="center"&&(e=Math.max((n.width()-i)/2,0));p[0].call(d,{top:j,left:e},function(){if(k){a.type="onLoad";h.trigger(a)}});if(g&&c.closeOnClick)b.mask.getMask().one("click",
-d.close);if(c.closeOnClick)b(document).on("click."+l,function(a){b(a.target).parents(f).length||d.close(a)});if(c.closeOnEsc)b(document).on("keydown."+l,function(a){a.keyCode==27&&d.close(a)});return d},close:function(a){if(!d.isOpened())return d;a=a||b.Event();a.type="onBeforeClose";h.trigger(a);if(!a.isDefaultPrevented()){k=false;o[c.effect][1].call(d,function(){a.type="onClose";h.trigger(a)});b(document).off("click."+l+" keydown."+l);g&&b.mask.close();return d}},getOverlay:function(){return f},
-getTrigger:function(){return a},getClosers:function(){return e},isOpened:function(){return k},getConf:function(){return c}});b.each(["onBeforeLoad","onStart","onLoad","onBeforeClose","onClose"],function(a,e){if(b.isFunction(c[e]))b(d).on(e,c[e]);d[e]=function(a){if(a)b(d).on(e,a);return d}});e=f.find(c.close||".close");!e.length&&!c.close&&(e=b(' '),f.prepend(e));e.click(function(a){d.close(a)});c.load&&d.load()}b.tools=b.tools||{version:"@VERSION"};b.tools.overlay={addEffect:function(a,
-b,d){o[a]=[b,d]},conf:{close:null,closeOnClick:!0,closeOnEsc:!0,closeSpeed:"fast",effect:"default",fixed:!b.browser.msie||6 ');c.css({border:0,display:"none"}).width(m);h("body").append(c);b.data("img",c)}var j=d.start.top||Math.round(f.height()/2),k=d.start.left||Math.round(f.width()/2);g&&(g=l(g),j=g.top,k=g.left);d.fixed?(j-=f.scrollTop(),k-=f.scrollLeft()):(a.top+=f.scrollTop(),a.left+=f.scrollLeft());c.css({position:"absolute",top:j,left:k,width:0,zIndex:d.zIndex}).show();a.position=n;b.css(a);c.animate({top:a.top,left:a.left,
-width:m},d.speed,function(){b.css("zIndex",d.zIndex+1).fadeIn(d.fadeInSpeed,function(){i.isOpened()&&!h(this).index(b)?e.call():b.hide()})}).css("position",n)},function(a){var e=this.getOverlay().hide(),b=this.getConf(),d=this.getTrigger(),e=e.data("img"),g={top:b.start.top,left:b.start.left,width:0};d&&h.extend(g,l(d));b.fixed&&e.css({position:"absolute"}).animate({top:"+="+f.scrollTop(),left:"+="+f.scrollLeft()},0);e.animate(g,b.closeSpeed,a)})})(jQuery);(function(a){function z(c,b){var a=Math.pow(10,b);return Math.round(c*a)/a}function m(c,b){var a=parseInt(c.css(b),10);return a?a:(a=c[0].currentStyle)&&a.width&&parseInt(a.width,10)}function y(a){return(a=a.data("events"))&&a.onSlide}function A(c,b){function e(a,d,f,e){void 0===f?f=d/i*v:e&&(f-=b.min);s&&(f=Math.round(f/s)*s);if(void 0===d||s)d=f*i/v;if(isNaN(f))return g;d=Math.max(0,Math.min(d,i));f=d/i*v;if(e||!n)f+=b.min;n&&(e?d=i-d:f=b.max-f);var f=z(f,r),h="click"==a.type;if(u&&void 0!==k&&
-!h&&(a.type="onSlide",w.trigger(a,[f,d]),a.isDefaultPrevented()))return g;e=h?b.speed:0;h=h?function(){a.type="change";w.trigger(a,[f])}:null;n?(j.animate({top:d},e,h),b.progress&&x.animate({height:i-d+j.height()/2},e)):(j.animate({left:d},e,h),b.progress&&x.animate({width:d+j.width()/2},e));k=f;c.val(f);return g}function o(){(n=b.vertical||m(h,"height")>m(h,"width"))?(i=m(h,"height")-m(j,"height"),l=h.offset().top+i):(i=m(h,"width")-m(j,"width"),l=h.offset().left)}function q(){o();g.setValue(void 0!==
-b.value?b.value:b.min)}var g=this,p=b.css,h=a("").data("rangeinput",g),n,k,l,i;c.before(h);var j=h.addClass(p.slider).find("a").addClass(p.handle),x=h.find("div").addClass(p.progress);a.each(["min","max","step","value"],function(a,d){var f=c.attr(d);parseFloat(f)&&(b[d]=parseFloat(f,10))});var v=b.max-b.min,s="any"==b.step?0:b.step,r=b.precision;void 0===r&&(r=s.toString().split("."),r=2===r.length?r[1].length:0);if("range"==c.attr("type")){var t=c.clone().wrap("
").parent().html(),
-t=a(t.replace(/type/i,"type=text data-orig-type"));t.val(b.value);c.replaceWith(t);c=t}c.addClass(p.input);var w=a(g).add(c),u=!0;a.extend(g,{getValue:function(){return k},setValue:function(b,d){o();return e(d||a.Event("api"),void 0,b,true)},getConf:function(){return b},getProgress:function(){return x},getHandle:function(){return j},getInput:function(){return c},step:function(c,d){d=d||a.Event();g.setValue(k+(b.step=="any"?1:b.step)*(c||1),d)},stepUp:function(a){return g.step(a||1)},stepDown:function(a){return g.step(-a||
--1)}});a.each(["onSlide","change"],function(c,d){if(a.isFunction(b[d]))a(g).on(d,b[d]);g[d]=function(b){if(b)a(g).on(d,b);return g}});j.drag({drag:!1}).on("dragStart",function(){o();u=y(a(g))||y(c)}).on("drag",function(a,b,f){if(c.is(":disabled"))return false;e(a,n?b:f)}).on("dragEnd",function(a){if(!a.isDefaultPrevented()){a.type="change";w.trigger(a,[k])}}).click(function(a){return a.preventDefault()});h.click(function(a){if(c.is(":disabled")||a.target==j[0])return a.preventDefault();o();var b=
-n?j.height()/2:j.width()/2;e(a,n?i-l-b+a.pageY:a.pageX-l-b)});b.keyboard&&c.keydown(function(b){if(!c.attr("readonly")){var d=b.keyCode,f=a([75,76,38,33,39]).index(d)!=-1,e=a([74,72,40,34,37]).index(d)!=-1;if((f||e)&&!b.shiftKey&&!b.altKey&&!b.ctrlKey){f?g.step(d==33?10:1,b):e&&g.step(d==34?-10:-1,b);return b.preventDefault()}}});c.blur(function(b){var c=a(this).val();c!==k&&g.setValue(c,b)});a.extend(c[0],{stepUp:g.stepUp,stepDown:g.stepDown});q();i||a(window).load(q)}a.tools=a.tools||{version:"@VERSION"};
-var u;u=a.tools.rangeinput={conf:{min:0,max:100,step:"any",steps:0,value:0,precision:void 0,vertical:0,keyboard:!0,progress:!1,speed:100,css:{input:"range",slider:"slider",progress:"progress",handle:"handle"}}};var q,l;a.fn.drag=function(c){document.ondragstart=function(){return!1};c=a.extend({x:!0,y:!0,drag:!0},c);q=q||a(document).on("mousedown mouseup",function(b){var e=a(b.target);if("mousedown"==b.type&&e.data("drag")){var o=e.position(),m=b.pageX-o.left,g=b.pageY-o.top,p=!0;q.on("mousemove.drag",
-function(a){var b=a.pageX-m,a=a.pageY-g,k={};c.x&&(k.left=b);c.y&&(k.top=a);p&&(e.trigger("dragStart"),p=!1);c.drag&&e.css(k);e.trigger("drag",[a,b]);l=e});b.preventDefault()}else try{l&&l.trigger("dragEnd")}finally{q.off("mousemove.drag"),l=null}});return this.data("drag",!0)};a.expr[":"].range=function(c){var b=c.getAttribute("type");return b&&"range"==b||!!a(c).filter("input").data("rangeinput")};a.fn.rangeinput=function(c){if(this.data("rangeinput"))return this;var c=a.extend(!0,{},u.conf,c),
-b;this.each(function(){var e=new A(a(this),a.extend(!0,{},c)),e=e.getInput().data("rangeinput",e);b=b?b.add(e):e});return b?b:this}})(jQuery);(function(d){function p(f,b){var c=d(b);return 2>c.length?c:f.parent().find(b)}function u(f,b){var c=this,n=f.add(c),g=f.children(),l=0,j=b.vertical;k||(k=c);1c.getSize()||a<-1)return c;var i=a;a.jquery?a=c.getItems().index(a):i=c.getItems().eq(a);var h=d.Event("onBeforeSeek");if(!f){n.trigger(h,[a,e]);if(h.isDefaultPrevented()||!i.length)return c}i=j?{top:-i.position().top}:{left:-i.position().left};l=a;k=c;if(e===void 0)e=b.speed;g.animate(i,e,b.easing,f||function(){n.trigger("onSeek",[a])});return c}});d.each(["onBeforeSeek","onSeek","onAddItem"],function(a,e){if(d.isFunction(b[e]))d(c).on(e,
-b[e]);c[e]=function(a){if(a)d(c).on(e,a);return c}});if(b.circular){var q=c.getItems().slice(-1).clone().prependTo(g),r=c.getItems().eq(1).clone().appendTo(g);q.add(r).addClass(b.clonedClass);c.onBeforeSeek(function(a,b,d){if(!a.isDefaultPrevented()){if(b==-1){c.seekTo(q,d,function(){c.end(0)});return a.preventDefault()}b==c.getSize()&&c.seekTo(r,d,function(){c.begin(0)})}});var o=f.parents().add(f).filter(function(){if(d(this).css("display")==="none")return true});o.length?(o.show(),c.seekTo(0,0,
-function(){}),o.hide()):c.seekTo(0,0,function(){})}var h=p(f,b.prev).click(function(a){a.stopPropagation();c.prev()}),m=p(f,b.next).click(function(a){a.stopPropagation();c.next()});b.circular||(c.onBeforeSeek(function(a,e){setTimeout(function(){if(!a.isDefaultPrevented()){h.toggleClass(b.disabledClass,e<=0);m.toggleClass(b.disabledClass,e>=c.getSize()-1)}},1)}),b.initialIndex||h.addClass(b.disabledClass));2>c.getSize()&&h.add(m).addClass(b.disabledClass);b.mousewheel&&d.fn.mousewheel&&f.mousewheel(function(a,
-e){if(b.mousewheel){c.move(e<0?1:-1,b.wheelSpeed||50);return false}});if(b.touch){var s,t;g[0].ontouchstart=function(a){a=a.touches[0];s=a.clientX;t=a.clientY};g[0].ontouchmove=function(a){if(a.touches.length==1&&!g.is(":animated")){var b=a.touches[0],d=s-b.clientX,b=t-b.clientY;c[j&&b>0||!j&&d>0?"next":"prev"]();a.preventDefault()}}}if(b.keyboard)d(document).on("keydown.scrollable",function(a){if(b.keyboard&&!a.altKey&&!a.ctrlKey&&!a.metaKey&&!d(a.target).is(":input")&&!(b.keyboard!="static"&&k!=
-c)){var e=a.keyCode;if(j&&(e==38||e==40)){c.move(e==38?-1:1);return a.preventDefault()}if(!j&&(e==37||e==39)){c.move(e==37?-1:1);return a.preventDefault()}}});b.initialIndex&&c.seekTo(b.initialIndex,0,function(){})}d.tools=d.tools||{version:"@VERSION"};d.tools.scrollable={conf:{activeClass:"active",circular:!1,clonedClass:"cloned",disabledClass:"disabled",easing:"swing",initialIndex:0,item:"> *",items:".items",keyboard:!0,mousewheel:!1,next:".next",prev:".prev",size:1,speed:400,vertical:!1,touch:!0,
-wheelSpeed:0}};var k;d.fn.scrollable=function(f){var b=this.data("scrollable");if(b)return b;f=d.extend({},d.tools.scrollable.conf,f);this.each(function(){b=new u(d(this),f);d(this).data("scrollable",b)});return f.api?b:this}})(jQuery);(function(d){var h=d.tools.scrollable;h.autoscroll={conf:{autoplay:!0,interval:3E3,autopause:!0}};d.fn.autoscroll=function(b){"number"==typeof b&&(b={interval:b});var e=d.extend({},h.autoscroll.conf,b),i;this.each(function(){function b(){c&&clearTimeout(c);c=setTimeout(function(){a.next()},e.interval)}var a=d(this).data("scrollable"),f=a.getRoot(),c,g=!1;a&&(i=a);a.play=function(){c||(g=!1,f.on("onSeek",b),b())};a.pause=function(){c=clearTimeout(c);f.off("onSeek",b)};a.resume=function(){g||a.play()};
-a.stop=function(){g=!0;a.pause()};e.autopause&&f.add(a.getNaviButtons()).hover(a.pause,a.resume);e.autoplay&&a.play()});return e.api?i:this}})(jQuery);(function(b){function m(a,f){var d=b(f);return 2>d.length?d:a.parent().find(f)}var g=b.tools.scrollable;g.navigator={conf:{navi:".navi",naviItem:null,activeClass:"active",indexed:!1,idPrefix:null,history:!1}};b.fn.navigator=function(a){"string"==typeof a&&(a={navi:a});var a=b.extend({},g.navigator.conf,a),f;this.each(function(){function d(){return i.find(a.naviItem||"> *")}function g(h){var e=b("<"+(a.naviItem||"a")+"/>").click(function(a){b(this);c.seekTo(h);a.preventDefault();j&&history.pushState({i:h},
-"")});0===h&&e.addClass(k);a.indexed&&e.text(h+1);a.idPrefix&&e.attr("id",a.idPrefix+h);return e.appendTo(i)}var c=b(this).data("scrollable"),i=a.navi.jquery?a.navi:m(c.getRoot(),a.navi),n=c.getNaviButtons(),k=a.activeClass,j=a.history&&!!history.pushState,l=c.getConf().size;c&&(f=c);c.getNaviButtons=function(){return n.add(i)};j&&(history.pushState({i:0},""),b(window).on("popstate",function(a){(a=a.originalEvent.state)&&c.seekTo(a.i)}));d().length?d().each(function(a){b(this).click(function(e){b(this);
-c.seekTo(a);e.preventDefault();j&&history.pushState({i:a},"")})}):b.each(c.getItems(),function(a){a%l==0&&g(a)});c.onBeforeSeek(function(a,c){setTimeout(function(){if(!a.isDefaultPrevented()){var b=c/l;d().eq(b).length&&d().removeClass(k).eq(b).addClass(k)}},1)});c.onAddItem(function(a,b){var d=c.getItems().index(b);d%l==0&&g(d)})});return a.api?f:this}})(jQuery);(function(d){function n(c,a,b){var e=this,l=c.add(this),g=c.find(b.tabs),f=a.jquery?a:c.children(a),i;g.length||(g=c.children());f.length||(f=c.parent().find(a));f.length||(f=d(a));d.extend(this,{click:function(a,h){var f=g.eq(a),j=!c.data("tabs");"string"==typeof a&&a.replace("#","")&&(f=g.filter('[href*="'+a.replace("#","")+'"]'),a=Math.max(g.index(f),0));if(b.rotate){var k=g.length-1;if(0>a)return e.click(k,h);if(a>k)return e.click(0,h)}if(!f.length){if(0<=i)return e;a=b.initialIndex;f=g.eq(a)}if(a===
-i)return e;h=h||d.Event();h.type="onBeforeClick";l.trigger(h,[a]);if(!h.isDefaultPrevented())return m[j?b.initialEffect&&b.effect||"default":b.effect].call(e,a,function(){i=a;h.type="onClick";l.trigger(h,[a])}),g.removeClass(b.current),f.addClass(b.current),e},getConf:function(){return b},getTabs:function(){return g},getPanes:function(){return f},getCurrentPane:function(){return f.eq(i)},getCurrentTab:function(){return g.eq(i)},getIndex:function(){return i},next:function(){return e.click(i+1)},prev:function(){return e.click(i-
-1)},destroy:function(){g.off(b.event).removeClass(b.current);f.find('a[href^="#"]').off("click.T");return e}});d.each(["onBeforeClick","onClick"],function(a,c){if(d.isFunction(b[c]))d(e).on(c,b[c]);e[c]=function(a){if(a)d(e).on(c,a);return e}});b.history&&d.fn.history&&(d.tools.history.init(g),b.event="history");g.each(function(a){d(this).on(b.event,function(b){e.click(a,b);return b.preventDefault()})});f.find('a[href^="#"]').on("click.T",function(a){e.click(d(this).attr("href"),a)});location.hash&&
-"a"==b.tabs&&c.find('[href="'+location.hash+'"]').length?e.click(location.hash):(0===b.initialIndex||0b.length?b:c.parent().find(a)}function i(){g=setTimeout(function(){e.next()},a.interval)}var b=this,f=c.add(this),e=c.data("tabs"),g,j=!0,m=h(a.next).click(function(){e.next()}),k=h(a.prev).click(function(){e.prev()});d.extend(b,{getTabs:function(){return e},getConf:function(){return a},play:function(){if(g)return b;var a=d.Event("onBeforePlay");f.trigger(a);if(a.isDefaultPrevented())return b;j=!1;f.trigger("onPlay");f.on("onClick",i);
-i();return b},pause:function(){if(!g)return b;var a=d.Event("onBeforePause");f.trigger(a);if(a.isDefaultPrevented())return b;g=clearTimeout(g);f.trigger("onPause");f.off("onClick",i);return b},resume:function(){j||b.play()},stop:function(){b.pause();j=!0}});d.each(["onBeforePlay","onPlay","onBeforePause","onPause"],function(e,c){if(d.isFunction(a[c]))d(b).on(c,a[c]);b[c]=function(a){return d(b).on(c,a)}});a.autopause&&e.getTabs().add(m).add(k).add(e.getPanes()).hover(b.pause,b.resume);a.autoplay&&
-b.play();a.clickable&&e.getPanes().click(function(){e.next()});if(!e.getConf().rotate){var l=a.disabledClass;e.getIndex()||k.addClass(l);e.onBeforeClick(function(a,b){k.toggleClass(l,!b);m.toggleClass(l,b==e.getTabs().length-1)})}}var h;h=d.tools.tabs.slideshow={conf:{next:".forward",prev:".backward",disabledClass:"disabled",autoplay:!1,autopause:!0,interval:3E3,clickable:!0,api:!1}};d.fn.slideshow=function(c){var a=this.data("slideshow");if(a)return a;c=d.extend({},h.conf,c);this.each(function(){a=
-new n(d(this),c);d(this).data("slideshow",a)});return c.api?a:this}})(jQuery);(function(b){function j(){if(b.browser.msie){var a=b(document).height(),c=b(window).height();return[window.innerWidth||document.documentElement.clientWidth||document.body.clientWidth,20>a-c?c:a]}return[b(document).width(),b(document).height()]}function g(a){if(a)return a.call(b.mask)}b.tools=b.tools||{version:"@VERSION"};var k;k=b.tools.expose={conf:{maskId:"exposeMask",loadSpeed:"slow",closeSpeed:"fast",closeOnClick:!0,closeOnEsc:!0,zIndex:9998,opacity:0.8,startOpacity:0,color:"#fff",onLoad:null,
-onClose:null}};var c,h,d,e,i;b.mask={load:function(a,f){if(d)return this;"string"==typeof a&&(a={color:a});a=a||e;e=a=b.extend(b.extend({},k.conf),a);c=b("#"+a.maskId);c.length||(c=b("
").attr("id",a.maskId),b("body").append(c));var l=j();c.css({position:"absolute",top:0,left:0,width:l[0],height:l[1],display:"none",opacity:a.startOpacity,zIndex:a.zIndex});a.color&&c.css("backgroundColor",a.color);if(!1===g(a.onBeforeLoad))return this;if(a.closeOnEsc)b(document).on("keydown.mask",function(a){a.keyCode==
-27&&b.mask.close(a)});if(a.closeOnClick)c.on("click.mask",function(a){b.mask.close(a)});b(window).on("resize.mask",function(){b.mask.fit()});f&&f.length&&(i=f.eq(0).css("zIndex"),b.each(f,function(){var a=b(this);/relative|absolute|fixed/i.test(a.css("position"))||a.css("position","relative")}),h=f.css({zIndex:Math.max(a.zIndex+1,"auto"==i?0:i)}));c.css({display:"block"}).fadeTo(a.loadSpeed,a.opacity,function(){b.mask.fit();g(a.onLoad);d="full"});d=!0;return this},close:function(){if(d){if(!1===g(e.onBeforeClose))return this;
-c.fadeOut(e.closeSpeed,function(){g(e.onClose);h&&h.css({zIndex:i});d=!1});b(document).off("keydown.mask");c.off("click.mask");b(window).off("resize.mask")}return this},fit:function(){if(d){var a=j();c.css({width:a[0],height:a[1]})}},getMask:function(){return c},isLoaded:function(a){return a?"full"==d:d},getConf:function(){return e},getExposed:function(){return h}};b.fn.mask=function(a){b.mask.load(a);return this};b.fn.expose=function(a){b.mask.load(a,this);return this}})(jQuery);(function(){function h(a,b){if(b)for(var c in b)b.hasOwnProperty(c)&&(a[c]=b[c]);return a}function k(a,b){var c=[],d;for(d in a)a.hasOwnProperty(d)&&(c[d]=b(a[d]));return c}function l(a,b,c){if(e.isSupported(b.version))a.innerHTML=e.getHTML(b,c);else if(b.expressInstall&&e.isSupported([6,65]))a.innerHTML=e.getHTML(h(b,{src:b.expressInstall}),{MMredirectURL:location.href,MMplayerType:"PlugIn",MMdoctitle:document.title});else if(a.innerHTML.replace(/\s/g,"")||(a.innerHTML="Flash version "+b.version+
-" or greater is required "+(0"+("A"==a.tagName?"Click here to download latest version
":"Download latest version from here
"),"A"==a.tagName&&(a.onclick=function(){location.href=j})),b.onFail){var d=b.onFail.call(this);"string"==typeof d&&(a.innerHTML=d)}i&&(window[b.id]=document.getElementById(b.id));h(this,{getRoot:function(){return a},getOptions:function(){return b},getConf:function(){return c},
-getApi:function(){return a.firstChild}})}var i=document.all,j="http://www.adobe.com/go/getflashplayer",m="function"==typeof jQuery,n=/(\d+)[^\d]+(\d+)[^\d]*(\d*)/,g={width:"100%",height:"100%",id:"_"+(""+Math.random()).slice(9),allowfullscreen:!0,allowscriptaccess:"always",quality:"high",version:[3,0],onFail:null,expressInstall:null,w3c:!1,cachebusting:!1};window.attachEvent&&window.attachEvent("onbeforeunload",function(){__flash_unloadHandler=function(){};__flash_savedUnloadHandler=function(){}});
-window.flashembed=function(a,b,c){"string"==typeof a&&(a=document.getElementById(a.replace("#","")));if(a)return"string"==typeof b&&(b={src:b}),new l(a,h(h({},g),b),c)};var e=h(window.flashembed,{conf:g,getVersion:function(){var a,b;try{b=navigator.plugins["Shockwave Flash"].description.slice(16)}catch(c){try{b=(a=new ActiveXObject("ShockwaveFlash.ShockwaveFlash.7"))&&a.GetVariable("$version")}catch(d){try{b=(a=new ActiveXObject("ShockwaveFlash.ShockwaveFlash.6"))&&a.GetVariable("$version")}catch(e){}}}return(b=
-n.exec(b))?[b[1],b[3]]:[0,0]},asString:function(a){if(null===a||void 0===a)return null;var b=typeof a;"object"==b&&a.push&&(b="array");switch(b){case "string":return a=a.replace(RegExp('(["\\\\])',"g"),"\\$1"),a=a.replace(/^\s?(\d+\.?\d*)%/,"$1pct"),'"'+a+'"';case "array":return"["+k(a,function(a){return e.asString(a)}).join(",")+"]";case "function":return'"function()"';case "object":var b=[],c;for(c in a)a.hasOwnProperty(c)&&b.push('"'+c+'":'+e.asString(a[c]));return"{"+b.join(",")+"}"}return(""+
-a).replace(/\s/g," ").replace(/\'/g,'"')},getHTML:function(a,b){var a=h({},a),c='";if(a.w3c||i)c+=' ';a.width=a.height=a.id=a.w3c=a.src=null;a.onFail=a.version=a.expressInstall=
-null;for(var d in a)a[d]&&(c+=' ');d="";if(b){for(var f in b)if(b[f]){var g=b[f];d+=f+"="+encodeURIComponent(/function|object/.test(typeof g)?e.asString(g):g)+"&"}d=d.slice(0,-1);c+=' "}return c+" "},isSupported:function(a){return f[0]>a[0]||f[0]==a[0]&&f[1]>=a[1]}}),f=e.getVersion();m&&(jQuery.tools=jQuery.tools||{version:"@VERSION"},jQuery.tools.flashembed={conf:g},jQuery.fn.flashembed=function(a,b){return this.each(function(){jQuery(this).data("flashembed",
-flashembed(this,a,b))})})})();(function(a){function g(a){if(a){var b=d.contentWindow.document;b.open().close();b.location.hash=a}}var f,d,e,h;a.tools=a.tools||{version:"@VERSION"};a.tools.history={init:function(c){h||(a.browser.msie&&"8">a.browser.version?d||(d=a("").attr("src","javascript:false;").hide().get(0),a("body").append(d),setInterval(function(){var b=d.contentWindow.document.location.hash;f!==b&&a(window).trigger("hash",b)},100),g(location.hash||"#")):setInterval(function(){var b=location.hash;b!==f&&a(window).trigger("hash",
-b)},100),e=!e?c:e.add(c),c.click(function(b){var c=a(this).attr("href");d&&g(c);if(c.slice(0,1)!="#"){location.href="#"+c;return b.preventDefault()}}),h=!0)}};a(window).on("hash",function(c,b){b?e.filter(function(){var c=a(this).attr("href");return c==b||c==b.replace("#","")}).trigger("history",[b]):e.eq(0).trigger("history",[b]);f=b});a.fn.history=function(c){a.tools.history.init(this);return this.on("history",c)}})(jQuery);(function(b){function c(a){switch(a.type){case "mousemove":return b.extend(a.data,{clientX:a.clientX,clientY:a.clientY,pageX:a.pageX,pageY:a.pageY});case "DOMMouseScroll":b.extend(a,a.data);a.delta=-a.detail/3;break;case "mousewheel":a.delta=a.wheelDelta/120}a.type="wheel";return b.event.handle.call(this,a,a.delta)}b.fn.mousewheel=function(a){return this[a?"on":"trigger"]("wheel",a)};b.event.special.wheel={setup:function(){b.event.add(this,d,c,{})},teardown:function(){b.event.remove(this,d,c)}};var d=
-!b.browser.mozilla?"mousewheel":"DOMMouseScroll"+("1.9">b.browser.version?" mousemove":"")})(jQuery);(function(e){function p(a,b,d){var f=d.relative?a.position().top:a.offset().top,c=d.relative?a.position().left:a.offset().left,h=d.position[0],f=f-(b.outerHeight()-d.offset[0]),c=c+(a.outerWidth()+d.offset[1]);/iPad/i.test(navigator.userAgent)&&(f-=e(window).scrollTop());var i=b.outerHeight()+a.outerHeight();"center"==h&&(f+=i/2);"bottom"==h&&(f+=i);h=d.position[1];a=b.outerWidth()+a.outerWidth();"center"==h&&(c-=a/2);"left"==h&&(c-=a);return{top:f,left:c}}function n(a,b){var d=this,f=a.add(d),c,
-h=0,i=0,m=a.attr("title"),q=a.attr("data-tooltip"),r=o[b.effect],l,s=a.is(":input"),n=s&&a.is(":checkbox, :radio, select, :button, :submit"),t=a.attr("type"),j=b.events[t]||b.events[s?n?"widget":"input":"def"];if(!r)throw'Nonexistent effect "'+b.effect+'"';j=j.split(/,\s*/);if(2!=j.length)throw"Tooltip: bad events configuration for "+t;a.on(j[0],function(a){clearTimeout(h);b.predelay?i=setTimeout(function(){d.show(a)},b.predelay):d.show(a)}).on(j[1],function(a){clearTimeout(i);b.delay?h=setTimeout(function(){d.hide(a)},
-b.delay):d.hide(a)});m&&b.cancelDefault&&(a.removeAttr("title"),a.data("title",m));e.extend(d,{show:function(k){if(!c){if(q)c=e(q);else if(b.tip)c=e(b.tip).eq(0);else if(m)c=e(b.layout).addClass(b.tipClass).appendTo(document.body).hide().append(m);else{c=a.next();c.length||(c=a.parent().next())}if(!c.length)throw"Cannot find tooltip for "+a;}if(d.isShown())return d;c.stop(true,true);var g=p(a,c,b);b.tip&&c.html(a.data("title"));k=e.Event();k.type="onBeforeShow";f.trigger(k,[g]);if(k.isDefaultPrevented())return d;
-g=p(a,c,b);c.css({position:"absolute",top:g.top,left:g.left});l=true;r[0].call(d,function(){k.type="onShow";l="full";f.trigger(k)});g=b.events.tooltip.split(/,\s*/);if(!c.data("__set")){c.off(g[0]).on(g[0],function(){clearTimeout(h);clearTimeout(i)});if(g[1]&&!a.is("input:not(:checkbox, :radio), textarea"))c.off(g[1]).on(g[1],function(b){b.relatedTarget!=a[0]&&a.trigger(j[1].split(" ")[0])});b.tip||c.data("__set",true)}return d},hide:function(a){if(!c||!d.isShown())return d;a=e.Event();a.type="onBeforeHide";
-f.trigger(a);if(!a.isDefaultPrevented()){l=false;o[b.effect][1].call(d,function(){a.type="onHide";f.trigger(a)});return d}},isShown:function(a){return a?l=="full":l},getConf:function(){return b},getTip:function(){return c},getTrigger:function(){return a}});e.each(["onHide","onBeforeShow","onShow","onBeforeHide"],function(a,c){if(e.isFunction(b[c]))e(d).on(c,b[c]);d[c]=function(a){if(a)e(d).on(c,a);return d}})}e.tools=e.tools||{version:"@VERSION"};e.tools.tooltip={conf:{effect:"toggle",fadeOutSpeed:"fast",
-predelay:0,delay:30,opacity:1,tip:0,fadeIE:!1,position:["top","center"],offset:[0,0],relative:!1,cancelDefault:!0,events:{def:"mouseenter,mouseleave",input:"focus,blur",widget:"focus mouseenter,blur mouseleave",tooltip:"mouseenter,mouseleave"},layout:"
",tipClass:"tooltip"},addEffect:function(a,b,d){o[a]=[b,d]}};var o={toggle:[function(a){var b=this.getConf(),d=this.getTip(),b=b.opacity;1>b&&d.css({opacity:b});d.show();a.call()},function(a){this.getTip().hide();a.call()}],fade:[function(a){var b=
-this.getConf();!e.browser.msie||b.fadeIE?this.getTip().fadeTo(b.fadeInSpeed,b.opacity,a):(this.getTip().show(),a())},function(a){var b=this.getConf();!e.browser.msie||b.fadeIE?this.getTip().fadeOut(b.fadeOutSpeed,a):(this.getTip().hide(),a())}]};e.fn.tooltip=function(a){var b=this.data("tooltip");if(b)return b;a=e.extend(!0,{},e.tools.tooltip.conf,a);"string"==typeof a.position&&(a.position=a.position.split(/,?\s/));this.each(function(){b=new n(e(this),a);e(this).data("tooltip",b)});return a.api?
-b:this}})(jQuery);(function(c){var i=c.tools.tooltip;i.dynamic={conf:{classNames:"top right bottom left"}};c.fn.dynamic=function(f){"number"==typeof f&&(f={speed:f});var f=c.extend({},i.dynamic.conf,f),l=c.extend(!0,{},f),j=f.classNames.split(/\s/),e;this.each(function(){var h=c(this).tooltip().onBeforeShow(function(f,h){var d=this.getTip(),a=this.getConf();e||(e=[a.position[0],a.position[1],a.offset[0],a.offset[1],c.extend({},a)]);c.extend(a,e[4]);a.position=[e[0],e[1]];a.offset=[e[2],e[3]];d.css({visibility:"hidden",
-position:"absolute",top:h.top,left:h.left}).show();var k=c.extend(!0,{},l),b;b=c(window);var g=b.width()+b.scrollLeft(),i=b.height()+b.scrollTop();b=[d.offset().top<=b.scrollTop(),g<=d.offset().left+d.width(),i<=d.offset().top+d.height(),b.scrollLeft()>=d.offset().left];a:{for(g=b.length;g--;)if(b[g]){g=!1;break a}g=!0}if(!g){b[2]&&(c.extend(a,k.top),a.position[0]="top",d.addClass(j[0]));b[3]&&(c.extend(a,k.right),a.position[1]="right",d.addClass(j[1]));b[0]&&(c.extend(a,k.bottom),a.position[0]="bottom",
-d.addClass(j[2]));b[1]&&(c.extend(a,k.left),a.position[1]="left",d.addClass(j[3]));if(b[0]||b[2])a.offset[0]*=-1;if(b[1]||b[3])a.offset[1]*=-1}d.css({visibility:"visible"}).hide()});h.onBeforeShow(function(){var c=this.getConf();this.getTip();setTimeout(function(){c.position=[e[0],e[1]];c.offset=[e[2],e[3]]},0)});h.onHide(function(){this.getTip().removeClass(f.classNames)});ret=h});return f.api?ret:this}})(jQuery);(function(b){var e=b.tools.tooltip;b.extend(e.conf,{direction:"up",bounce:!1,slideOffset:10,slideInSpeed:200,slideOutSpeed:200,slideFade:!b.browser.msie});var f={up:["-","top"],down:["+","top"],left:["-","left"],right:["+","left"]};e.addEffect("slide",function(b){var a=this.getConf(),g=this.getTip(),c=a.slideFade?{opacity:a.opacity}:{},d=f[a.direction]||f.up;c[d[1]]=d[0]+"="+a.slideOffset;a.slideFade&&g.css({opacity:0});g.show().animate(c,a.slideInSpeed,b)},function(e){var a=this.getConf(),g=a.slideOffset,
-c=a.slideFade?{opacity:0}:{},d=f[a.direction]||f.up,h=""+d[0];a.bounce&&(h="+"==h?"-":"+");c[d[1]]=h+"="+g;this.getTip().animate(c,a.slideOutSpeed,function(){b(this).hide();e.call()})})})(jQuery);(function(c){function i(b,a,f){var a=c(a).first()||a,d=b.offset().top,e=b.offset().left,g=f.position.split(/,?\s+/),j=g[0],g=g[1],d=d-(a.outerHeight()-f.offset[0]),e=e+(b.outerWidth()+f.offset[1]);/iPad/i.test(navigator.userAgent)&&(d-=c(window).scrollTop());f=a.outerHeight()+b.outerHeight();"center"==j&&(d+=f/2);"bottom"==j&&(d+=f);b=b.outerWidth();"center"==g&&(e-=(b+a.outerWidth())/2);"left"==g&&(e-=b);return{top:d,left:e}}function q(b){function a(){return this.getAttribute("type")==b}a.key='[type="'+
-b+'"]';return a}function n(b,a,f){function p(a,b,e){if(f.grouped||!a.length){var g;!1===e||c.isArray(e)?(g=d.messages[b.key||b]||d.messages["*"],g=g[f.lang]||d.messages["*"].en,(b=g.match(/\$\d/g))&&c.isArray(e)&&c.each(b,function(a){g=g.replace(this,e[a])})):g=e[f.lang]||e;a.push(g)}}var e=this,g=a.add(e),b=b.not(":button, :image, :reset, :submit");a.attr("novalidate","novalidate");c.extend(e,{getConf:function(){return f},getForm:function(){return a},getInputs:function(){return b},reflow:function(){b.each(function(){var a=
-c(this),b=a.data("msg.el");b&&(a=i(a,b,f),b.css({top:a.top,left:a.left}))});return e},invalidate:function(a,h){if(!h){var d=[];c.each(a,function(a,f){var c=b.filter("[name='"+a+"']");c.length&&(c.trigger("OI",[f]),d.push({input:c,messages:[f]}))});a=d;h=c.Event()}h.type="onFail";g.trigger(h,[a]);h.isDefaultPrevented()||l[f.effect][0].call(e,a,h);return e},reset:function(a){a=a||b;a.removeClass(f.errorClass).each(function(){var a=c(this).data("msg.el");a&&(a.remove(),c(this).data("msg.el",null))}).off(f.errorInputEvent+
-".v"||"");return e},destroy:function(){a.off(f.formEvent+".V reset.V");b.off(f.inputEvent+".V change.V");return e.reset()},checkValidity:function(a,h){var a=a||b,a=a.not(":disabled"),d={},a=a.filter(function(){var a=c(this).attr("name");if(!d[a])return d[a]=!0,c(this)});if(!a.length)return!0;h=h||c.Event();h.type="onBeforeValidate";g.trigger(h,[a]);if(h.isDefaultPrevented())return h.result;var k=[];a.each(function(){var a=[],b=c(this).data("messages",a),d=m&&b.is(":date")?"onHide.v":f.errorInputEvent+
-".v";b.off(d);c.each(o,function(){var c=this[0];if(b.filter(c).length){var d=this[1].call(e,b,b.val());if(!0!==d){h.type="onBeforeFail";g.trigger(h,[b,c]);if(h.isDefaultPrevented())return!1;var j=b.attr(f.messageAttr);if(j)return a=[j],!1;p(a,c,d)}}});if(a.length&&(k.push({input:b,messages:a}),b.trigger("OI",[a]),f.errorInputEvent))b.on(d,function(a){e.checkValidity(b,a)});if(f.singleError&&k.length)return!1});var i=l[f.effect];if(!i)throw'Validator: cannot find effect "'+f.effect+'"';if(k.length)return e.invalidate(k,
-h),!1;i[1].call(e,a,h);h.type="onSuccess";g.trigger(h,[a]);a.off(f.errorInputEvent+".v");return!0}});c.each(["onBeforeValidate","onBeforeFail","onFail","onSuccess"],function(a,b){if(c.isFunction(f[b]))c(e).on(b,f[b]);e[b]=function(a){if(a)c(e).on(b,a);return e}});if(f.formEvent)a.on(f.formEvent+".V",function(b){if(!e.checkValidity(null,b))return b.preventDefault();b.target=a;b.type=f.formEvent});a.on("reset.V",function(){e.reset()});b[0]&&b[0].validity&&b.each(function(){this.oninvalid=function(){return!1}});
-a[0]&&(a[0].checkValidity=e.checkValidity);if(f.inputEvent)b.on(f.inputEvent+".V",function(a){e.checkValidity(c(this),a)});b.filter(":checkbox, select").filter("[required]").on("change.V",function(a){var b=c(this);(this.checked||b.is("select")&&c(this).val())&&l[f.effect][1].call(e,b,a)});b.filter(":radio[required]").on("change.V",function(a){var b=c("[name='"+c(a.srcElement).attr("name")+"']");b!=null&&b.length!=0&&e.checkValidity(b,a)});c(window).resize(function(){e.reflow()})}c.tools=c.tools||
-{version:"@VERSION"};var r=/\[type=([a-z]+)\]/,s=/^-?[0-9]*(\.[0-9]+)?$/,m=c.tools.dateinput,t=/^([a-z0-9_\.\-\+]+)@([\da-z\.\-]+)\.([a-z\.]{2,6})$/i,u=/^(https?:\/\/)?[\da-z\.\-]+\.[a-z\.]{2,6}[#&+_\?\/\w \.\-=]*$/i,d;d=c.tools.validator={conf:{grouped:!1,effect:"default",errorClass:"invalid",inputEvent:null,errorInputEvent:"keyup",formEvent:"submit",lang:"en",message:"
",messageAttr:"data-message",messageClass:"error",offset:[0,0],position:"center right",singleError:!1,speed:"normal"},messages:{"*":{en:"Please correct this value"}},
-localize:function(b,a){c.each(a,function(a,c){d.messages[a]=d.messages[a]||{};d.messages[a][b]=c})},localizeFn:function(b,a){d.messages[b]=d.messages[b]||{};c.extend(d.messages[b],a)},fn:function(b,a,f){c.isFunction(a)?f=a:("string"==typeof a&&(a={en:a}),this.messages[b.key||b]=a);(a=r.exec(b))&&(b=q(a[1]));o.push([b,f])},addEffect:function(b,a,f){l[b]=[a,f]}};var o=[],l={"default":[function(b){var a=this.getConf();c.each(b,function(b,d){var e=d.input;e.addClass(a.errorClass);var g=e.data("msg.el");
-g||(g=c(a.message).addClass(a.messageClass).appendTo(document.body),e.data("msg.el",g));g.css({visibility:"hidden"}).find("p").remove();c.each(d.messages,function(a,b){c("
").html(b).appendTo(g)});g.outerWidth()==g.parent().width()&&g.add(g.find("p")).css({display:"inline"});e=i(e,g,a);g.css({visibility:"visible",position:"absolute",top:e.top,left:e.left}).fadeIn(a.speed)})},function(b){var a=this.getConf();b.removeClass(a.errorClass).each(function(){var a=c(this).data("msg.el");a&&a.css({visibility:"hidden"})})}]};
-c.each(["email","url","number"],function(b,a){c.expr[":"][a]=function(b){return b.getAttribute("type")===a}});c.fn.oninvalid=function(b){return this[b?"on":"trigger"]("OI",b)};d.fn(":email","Please enter a valid email address",function(b,a){return!a||t.test(a)});d.fn(":url","Please enter a valid URL",function(b,a){return!a||u.test(a)});d.fn(":number","Please enter a numeric value.",function(b,a){return s.test(a)});d.fn("[max]","Please enter a value no larger than $1",function(b,a){if(""===a||m&&b.is(":date"))return!0;
-var c=b.attr("max");return parseFloat(a)<=parseFloat(c)?!0:[c]});d.fn("[min]","Please enter a value of at least $1",function(b,a){if(""===a||m&&b.is(":date"))return!0;var c=b.attr("min");return parseFloat(a)>=parseFloat(c)?!0:[c]});d.fn("[required]","Please complete this mandatory field.",function(b,a){return b.is(":checkbox")?b.is(":checked"):!!a});d.fn("[pattern]",function(b,a){return""===a||RegExp("^"+b.attr("pattern")+"$").test(a)});d.fn(":radio","Please select an option.",function(b){var a=!1;
-c("[name='"+b.attr("name")+"']").each(function(b,d){c(d).is(":checked")&&(a=!0)});return a?!0:!1});c.fn.validator=function(b){var a=this.data("validator");a&&(a.destroy(),this.removeData("validator"));b=c.extend(!0,{},d.conf,b);if(this.is("form"))return this.each(function(){var d=c(this);a=new n(d.find(":input"),d,b);d.data("validator",a)});a=new n(this,this.eq(0).closest("form"),b);return this.data("validator",a)}})(jQuery);
diff --git a/vendor/assets/javascripts/jquery.tooltip.js b/vendor/assets/javascripts/jquery.tooltip.js
deleted file mode 100644
index 63b715f15..000000000
--- a/vendor/assets/javascripts/jquery.tooltip.js
+++ /dev/null
@@ -1,294 +0,0 @@
-/*
- * jQuery Tooltip plugin 1.3
- *
- * http://bassistance.de/jquery-plugins/jquery-plugin-tooltip/
- * http://docs.jquery.com/Plugins/Tooltip
- *
- * Copyright (c) 2006 - 2008 Jörn Zaefferer
- *
- * $Id: jquery.tooltip.js 5741 2008-06-21 15:22:16Z joern.zaefferer $
- *
- * Dual licensed under the MIT and GPL licenses:
- * http://www.opensource.org/licenses/mit-license.php
- * http://www.gnu.org/licenses/gpl.html
- */
-
-;(function($) {
-
- // the tooltip element
- var helper = {},
- // the current tooltipped element
- current,
- // the title of the current element, used for restoring
- title,
- // timeout id for delayed tooltips
- tID,
- // IE 5.5 or 6
- IE = $.browser.msie && /MSIE\s(5\.5|6\.)/.test(navigator.userAgent),
- // flag for mouse tracking
- track = false;
-
- $.tooltip = {
- blocked: false,
- defaults: {
- delay: 200,
- fade: false,
- showURL: true,
- extraClass: "",
- top: 15,
- left: 15,
- id: "tooltip"
- },
- block: function() {
- $.tooltip.blocked = !$.tooltip.blocked;
- }
- };
-
- $.fn.extend({
- tooltip: function(settings) {
- settings = $.extend({}, $.tooltip.defaults, settings);
- createHelper(settings);
- return this.each(function() {
- $.data(this, "tooltip", settings);
- this.tOpacity = helper.parent.css("opacity");
- // copy tooltip into its own expando and remove the title
- this.tooltipText = this.title;
- $(this).removeAttr("title");
- // also remove alt attribute to prevent default tooltip in IE
- this.alt = "";
- })
- .mouseover(save)
- .mouseout(hide)
- .click(hide);
- },
- fixPNG: IE ? function() {
- return this.each(function () {
- var image = $(this).css('backgroundImage');
- if (image.match(/^url\(["']?(.*\.png)["']?\)$/i)) {
- image = RegExp.$1;
- $(this).css({
- 'backgroundImage': 'none',
- 'filter': "progid:DXImageTransform.Microsoft.AlphaImageLoader(enabled=true, sizingMethod=crop, src='" + image + "')"
- }).each(function () {
- var position = $(this).css('position');
- if (position != 'absolute' && position != 'relative')
- $(this).css('position', 'relative');
- });
- }
- });
- } : function() { return this; },
- unfixPNG: IE ? function() {
- return this.each(function () {
- $(this).css({'filter': '', backgroundImage: ''});
- });
- } : function() { return this; },
- hideWhenEmpty: function() {
- return this.each(function() {
- $(this)[ $(this).html() ? "show" : "hide" ]();
- });
- },
- url: function() {
- return this.attr('href') || this.attr('src');
- }
- });
-
- function createHelper(settings) {
- // there can be only one tooltip helper
- if( helper.parent )
- return;
- // create the helper, h3 for title, div for url
- helper.parent = $('')
- // add to document
- .appendTo(document.body)
- // hide it at first
- .hide();
-
- // apply bgiframe if available
- if ( $.fn.bgiframe )
- helper.parent.bgiframe();
-
- // save references to title and url elements
- helper.title = $('h3', helper.parent);
- helper.body = $('div.body', helper.parent);
- helper.url = $('div.url', helper.parent);
- }
-
- function settings(element) {
- return $.data(element, "tooltip");
- }
-
- // main event handler to start showing tooltips
- function handle(event) {
- // show helper, either with timeout or on instant
- if( settings(this).delay )
- tID = setTimeout(show, settings(this).delay);
- else
- show();
-
- // if selected, update the helper position when the mouse moves
- track = !!settings(this).track;
- $(document.body).bind('mousemove', update);
-
- // update at least once
- update(event);
- }
-
- // save elements title before the tooltip is displayed
- function save() {
- // if this is the current source, or it has no title (occurs with click event), stop
- if ( $.tooltip.blocked || this == current || (!this.tooltipText && !settings(this).bodyHandler) )
- return;
-
- // save current
- current = this;
- title = this.tooltipText;
-
- if ( settings(this).bodyHandler ) {
- helper.title.hide();
- var bodyContent = settings(this).bodyHandler.call(this);
- if (bodyContent.nodeType || bodyContent.jquery) {
- helper.body.empty().append(bodyContent)
- } else {
- helper.body.html( bodyContent );
- }
- helper.body.show();
- } else if ( settings(this).showBody ) {
- var parts = title.split(settings(this).showBody);
- helper.title.html(parts.shift()).show();
- helper.body.empty();
- for(var i = 0, part; (part = parts[i]); i++) {
- if(i > 0)
- helper.body.append(" ");
- helper.body.append(part);
- }
- helper.body.hideWhenEmpty();
- } else {
- helper.title.html(title).show();
- helper.body.hide();
- }
-
- // if element has href or src, add and show it, otherwise hide it
- if( settings(this).showURL && $(this).url() )
- helper.url.html( $(this).url().replace('http://', '') ).show();
- else
- helper.url.hide();
-
- // add an optional class for this tip
- helper.parent.addClass(settings(this).extraClass);
-
- // fix PNG background for IE
- if (settings(this).fixPNG )
- helper.parent.fixPNG();
-
- handle.apply(this, arguments);
- }
-
- // delete timeout and show helper
- function show() {
- tID = null;
- if ((!IE || !$.fn.bgiframe) && settings(current).fade) {
- if (helper.parent.is(":animated"))
- helper.parent.stop().show().fadeTo(settings(current).fade, current.tOpacity);
- else
- helper.parent.is(':visible') ? helper.parent.fadeTo(settings(current).fade, current.tOpacity) : helper.parent.fadeIn(settings(current).fade);
- } else {
- helper.parent.show();
- }
- update();
- }
-
- /**
- * callback for mousemove
- * updates the helper position
- * removes itself when no current element
- */
- function update(event) {
- if($.tooltip.blocked)
- return;
-
- if (event && event.target.tagName == "OPTION") {
- return;
- }
-
- // stop updating when tracking is disabled and the tooltip is visible
- if ( !track && helper.parent.is(":visible")) {
- $(document.body).unbind('mousemove', update)
- }
-
- // if no current element is available, remove this listener
- if( current == null ) {
- $(document.body).unbind('mousemove', update);
- return;
- }
-
- // remove position helper classes
- helper.parent.removeClass("viewport-right").removeClass("viewport-bottom");
-
- var left = helper.parent[0].offsetLeft;
- var top = helper.parent[0].offsetTop;
- if (event) {
- // position the helper 15 pixel to bottom right, starting from mouse position
- left = event.pageX + settings(current).left;
- top = event.pageY + settings(current).top;
- var right='auto';
- if (settings(current).positionLeft) {
- right = $(window).width() - left;
- left = 'auto';
- }
- helper.parent.css({
- left: left,
- right: right,
- top: top
- });
- }
-
- var v = viewport(),
- h = helper.parent[0];
- // check horizontal position
- if (v.x + v.cx < h.offsetLeft + h.offsetWidth) {
- left -= h.offsetWidth + 20 + settings(current).left;
- helper.parent.css({left: left + 'px'}).addClass("viewport-right");
- }
- // check vertical position
- if (v.y + v.cy < h.offsetTop + h.offsetHeight) {
- top -= h.offsetHeight + 20 + settings(current).top;
- helper.parent.css({top: top + 'px'}).addClass("viewport-bottom");
- }
- }
-
- function viewport() {
- return {
- x: $(window).scrollLeft(),
- y: $(window).scrollTop(),
- cx: $(window).width(),
- cy: $(window).height()
- };
- }
-
- // hide helper and restore added classes and the title
- function hide(event) {
- if($.tooltip.blocked)
- return;
- // clear timeout if possible
- if(tID)
- clearTimeout(tID);
- // no more current element
- current = null;
-
- var tsettings = settings(this);
- function complete() {
- helper.parent.removeClass( tsettings.extraClass ).hide().css("opacity", "");
- }
- if ((!IE || !$.fn.bgiframe) && tsettings.fade) {
- if (helper.parent.is(':animated'))
- helper.parent.stop().fadeTo(tsettings.fade, 0, complete);
- else
- helper.parent.stop().fadeOut(tsettings.fade, complete);
- } else
- complete();
-
- if( settings(this).fixPNG )
- helper.parent.unfixPNG();
- }
-
-})(jQuery);
diff --git a/vendor/assets/javascripts/thickbox.js.erb b/vendor/assets/javascripts/thickbox.js.erb
deleted file mode 100644
index d19667735..000000000
--- a/vendor/assets/javascripts/thickbox.js.erb
+++ /dev/null
@@ -1,319 +0,0 @@
-/*
- * Thickbox 3.1 - One Box To Rule Them All.
- * By Cody Lindley (http://www.codylindley.com)
- * Copyright (c) 2007 cody lindley
- * Licensed under the MIT License: http://www.opensource.org/licenses/mit-license.php
-*/
-
-var tb_pathToImage = "<%= asset_path("thickbox/loadingAnimation.gif") %>";
-
-/*!!!!!!!!!!!!!!!!! edit below this line at your own risk !!!!!!!!!!!!!!!!!!!!!!!*/
-
-//on page load call tb_init
-$(document).ready(function(){
- tb_init('a.thickbox, area.thickbox, input.thickbox');//pass where to apply thickbox
- imgLoader = new Image();// preload image
- imgLoader.src = tb_pathToImage;
-});
-
-//add thickbox to href & area elements that have a class of .thickbox
-function tb_init(domChunk){
- $(domChunk).click(function(){
- var t = this.title || this.name || null;
- var a = this.href || this.alt;
- var g = this.rel || false;
- tb_show(t,a,g);
- this.blur();
- return false;
- });
-}
-
-function tb_show(caption, url, imageGroup) {//function called when the user clicks on a thickbox link
-
- try {
- if (typeof document.body.style.maxHeight === "undefined") {//if IE 6
- $("body","html").css({height: "100%", width: "100%"});
- $("html").css("overflow","hidden");
- if (document.getElementById("TB_HideSelect") === null) {//iframe to hide select elements in ie6
- $("body").append("
");
- $("#TB_overlay").click(tb_remove);
- }
- }else{//all others
- if(document.getElementById("TB_overlay") === null){
- $("body").append("
");
- $("#TB_overlay").click(tb_remove);
- }
- }
-
- if(tb_detectMacXFF()){
- $("#TB_overlay").addClass("TB_overlayMacFFBGHack");//use png overlay so hide flash
- }else{
- $("#TB_overlay").addClass("TB_overlayBG");//use background and opacity
- }
-
- if(caption===null){caption="";}
- $("body").append("");//add loader to the page
- $('#TB_load').show();//show loader
-
- var baseURL;
- if(url.indexOf("?")!==-1){ //ff there is a query string involved
- baseURL = url.substr(0, url.indexOf("?"));
- }else{
- baseURL = url;
- }
-
- var urlString = /\.jpg$|\.jpeg$|\.png$|\.gif$|\.bmp$/;
- var urlType = baseURL.toLowerCase().match(urlString);
-
- if(urlType == '.jpg' || urlType == '.jpeg' || urlType == '.png' || urlType == '.gif' || urlType == '.bmp'){//code to show images
-
- TB_PrevCaption = "";
- TB_PrevURL = "";
- TB_PrevHTML = "";
- TB_NextCaption = "";
- TB_NextURL = "";
- TB_NextHTML = "";
- TB_imageCount = "";
- TB_FoundURL = false;
- if(imageGroup){
- TB_TempArray = $("a[@rel="+imageGroup+"]").get();
- for (TB_Counter = 0; ((TB_Counter < TB_TempArray.length) && (TB_NextHTML === "")); TB_Counter++) {
- var urlTypeTemp = TB_TempArray[TB_Counter].href.toLowerCase().match(urlString);
- if (!(TB_TempArray[TB_Counter].href == url)) {
- if (TB_FoundURL) {
- TB_NextCaption = TB_TempArray[TB_Counter].title;
- TB_NextURL = TB_TempArray[TB_Counter].href;
- TB_NextHTML = " Next > ";
- } else {
- TB_PrevCaption = TB_TempArray[TB_Counter].title;
- TB_PrevURL = TB_TempArray[TB_Counter].href;
- TB_PrevHTML = " < Prev ";
- }
- } else {
- TB_FoundURL = true;
- TB_imageCount = "Image " + (TB_Counter + 1) +" of "+ (TB_TempArray.length);
- }
- }
- }
-
- imgPreloader = new Image();
- imgPreloader.onload = function(){
- imgPreloader.onload = null;
-
- // Resizing large images - orginal by Christian Montoya edited by me.
- var pagesize = tb_getPageSize();
- var x = pagesize[0] - 150;
- var y = pagesize[1] - 150;
- var imageWidth = imgPreloader.width;
- var imageHeight = imgPreloader.height;
- if (imageWidth > x) {
- imageHeight = imageHeight * (x / imageWidth);
- imageWidth = x;
- if (imageHeight > y) {
- imageWidth = imageWidth * (y / imageHeight);
- imageHeight = y;
- }
- } else if (imageHeight > y) {
- imageWidth = imageWidth * (y / imageHeight);
- imageHeight = y;
- if (imageWidth > x) {
- imageHeight = imageHeight * (x / imageWidth);
- imageWidth = x;
- }
- }
- // End Resizing
-
- TB_WIDTH = imageWidth + 30;
- TB_HEIGHT = imageHeight + 60;
- $("#TB_window").append(" " + ""+caption+"
" + TB_imageCount + TB_PrevHTML + TB_NextHTML + "
");
-
- $("#TB_closeWindowButton").click(tb_remove);
-
- if (!(TB_PrevHTML === "")) {
- function goPrev(){
- if($(document).unbind("click",goPrev)){$(document).unbind("click",goPrev);}
- $("#TB_window").remove();
- $("body").append("
");
- tb_show(TB_PrevCaption, TB_PrevURL, imageGroup);
- return false;
- }
- $("#TB_prev").click(goPrev);
- }
-
- if (!(TB_NextHTML === "")) {
- function goNext(){
- $("#TB_window").remove();
- $("body").append("
");
- tb_show(TB_NextCaption, TB_NextURL, imageGroup);
- return false;
- }
- $("#TB_next").click(goNext);
-
- }
-
- document.onkeydown = function(e){
- if (e == null) { // ie
- keycode = event.keyCode;
- } else { // mozilla
- keycode = e.which;
- }
- if(keycode == 27){ // close
- tb_remove();
- } else if(keycode == 190){ // display previous image
- if(!(TB_NextHTML == "")){
- document.onkeydown = "";
- goNext();
- }
- } else if(keycode == 188){ // display next image
- if(!(TB_PrevHTML == "")){
- document.onkeydown = "";
- goPrev();
- }
- }
- };
-
- tb_position();
- $("#TB_load").remove();
- $("#TB_ImageOff").click(tb_remove);
- $("#TB_window").css({display:"block"}); //for safari using css instead of show
- };
-
- imgPreloader.src = url;
- }else{//code to show html
-
- var queryString = url.replace(/^[^\?]+\??/,'');
- var params = tb_parseQuery( queryString );
-
- TB_WIDTH = (params['width']*1) + 30 || 630; //defaults to 630 if no paramaters were added to URL
- TB_HEIGHT = (params['height']*1) + 40 || 440; //defaults to 440 if no paramaters were added to URL
- ajaxContentW = TB_WIDTH - 30;
- ajaxContentH = TB_HEIGHT - 45;
-
- if(url.indexOf('TB_iframe') != -1){// either iframe or ajax window
- urlNoQuery = url.split('TB_');
- $("#TB_iframeContent").remove();
- if(params['modal'] != "true"){//iframe no modal
- $("#TB_window").append("");
- }else{//iframe modal
- $("#TB_overlay").unbind();
- $("#TB_window").append("");
- }
- }else{// not an iframe, ajax
- if($("#TB_window").css("display") != "block"){
- if(params['modal'] != "true"){//ajax no modal
- $("#TB_window").append("
");
- }else{//ajax modal
- $("#TB_overlay").unbind();
- $("#TB_window").append("
");
- }
- }else{//this means the window is already up, we are just loading new content via ajax
- $("#TB_ajaxContent")[0].style.width = ajaxContentW +"px";
- $("#TB_ajaxContent")[0].style.height = ajaxContentH +"px";
- $("#TB_ajaxContent")[0].scrollTop = 0;
- $("#TB_ajaxWindowTitle").html(caption);
- }
- }
-
- $("#TB_closeWindowButton").click(tb_remove);
-
- if(url.indexOf('TB_inline') != -1){
- $("#TB_ajaxContent").append($('#' + params['inlineId']).children());
- $("#TB_window").unload(function () {
- $('#' + params['inlineId']).append( $("#TB_ajaxContent").children() ); // move elements back when you're finished
- });
- tb_position();
- $("#TB_load").remove();
- $("#TB_window").css({display:"block"});
- }else if(url.indexOf('TB_iframe') != -1){
- tb_position();
- if($.browser.safari){//safari needs help because it will not fire iframe onload
- $("#TB_load").remove();
- $("#TB_window").css({display:"block"});
- }
- }else{
- $("#TB_ajaxContent").load(url += "&random=" + (new Date().getTime()),function(){//to do a post change this load method
- tb_position();
- $("#TB_load").remove();
- tb_init("#TB_ajaxContent a.thickbox");
- $("#TB_window").css({display:"block"});
- });
- }
-
- }
-
- if(!params['modal']){
- document.onkeyup = function(e){
- if (e == null) { // ie
- keycode = event.keyCode;
- } else { // mozilla
- keycode = e.which;
- }
- if(keycode == 27){ // close
- tb_remove();
- }
- };
- }
-
- } catch(e) {
- //nothing here
- }
-}
-
-//helper functions below
-function tb_showIframe(){
- $("#TB_load").remove();
- $("#TB_window").css({display:"block"});
-}
-
-function tb_remove() {
- $("#TB_imageOff").unbind("click");
- $("#TB_closeWindowButton").unbind("click");
- $("#TB_window").fadeOut("fast",function(){$('#TB_window,#TB_overlay,#TB_HideSelect').trigger("unload").unbind().remove();});
- $("#TB_load").remove();
- if (typeof document.body.style.maxHeight == "undefined") {//if IE 6
- $("body","html").css({height: "auto", width: "auto"});
- $("html").css("overflow","");
- }
- document.onkeydown = "";
- document.onkeyup = "";
- return false;
-}
-
-function tb_position() {
-$("#TB_window").css({marginLeft: '-' + parseInt((TB_WIDTH / 2),10) + 'px', width: TB_WIDTH + 'px'});
- if ( !(jQuery.browser.msie && jQuery.browser.version < 7)) { // take away IE6
- $("#TB_window").css({marginTop: '-' + parseInt((TB_HEIGHT / 2),10) + 'px'});
- }
-}
-
-function tb_parseQuery ( query ) {
- var Params = {};
- if ( ! query ) {return Params;}// return empty object
- var Pairs = query.split(/[;&]/);
- for ( var i = 0; i < Pairs.length; i++ ) {
- var KeyVal = Pairs[i].split('=');
- if ( ! KeyVal || KeyVal.length != 2 ) {continue;}
- var key = unescape( KeyVal[0] );
- var val = unescape( KeyVal[1] );
- val = val.replace(/\+/g, ' ');
- Params[key] = val;
- }
- return Params;
-}
-
-function tb_getPageSize(){
- var de = document.documentElement;
- var w = window.innerWidth || self.innerWidth || (de&&de.clientWidth) || document.body.clientWidth;
- var h = window.innerHeight || self.innerHeight || (de&&de.clientHeight) || document.body.clientHeight;
- arrayPageSize = [w,h];
- return arrayPageSize;
-}
-
-function tb_detectMacXFF() {
- var userAgent = navigator.userAgent.toLowerCase();
- if (userAgent.indexOf('mac') != -1 && userAgent.indexOf('firefox')!=-1) {
- return true;
- }
-}
-
-