| @@ -49,15 +49,16 @@ def create_resource(): | |||
| db.session.add(new_tool) | |||
| db.session.commit() | |||
| if request.form.get('linked_practice_id'): | |||
| tool = Resource.query.filter_by(type='tool').filter_by(name=name).first() | |||
| first_resource_id = tool.id | |||
| second_resource_id = request.form.get('linked_practice_id') | |||
| new_relationship = Relationship(first_resource_id=first_resource_id, second_resource_id=second_resource_id) | |||
| # add the new relationship to the database | |||
| db.session.add(new_relationship) | |||
| db.session.commit() | |||
| if request.form.getlist('linked_resources'): | |||
| for linked_resource in request.form.getlist('linked_resources'): | |||
| tool = Resource.query.filter_by(type='tool').filter_by(name=name).first() | |||
| first_resource_id = tool.id | |||
| second_resource_id = linked_resource | |||
| new_relationship = Relationship(first_resource_id=first_resource_id, second_resource_id=second_resource_id) | |||
| # add the new relationship to the database | |||
| db.session.add(new_relationship) | |||
| db.session.commit() | |||
| elif request.form.get('resource_type') == 'practice': | |||
| type = 'practice' | |||
| @@ -23,17 +23,19 @@ def get_resource(resource_id): | |||
| def get_linked_resources(resource_id): | |||
| relationships = Relationship.query.filter_by(first_resource_id=resource_id).all() | |||
| if relationships: | |||
| links = [] | |||
| for relationship in relationships: | |||
| resource_id = relationship.second_resource_id | |||
| links = Resource.query.filter_by(id=resource_id).all() | |||
| return links | |||
| resource_id = relationship.second_resource_id | |||
| links.extend(Resource.query.filter_by(id=resource_id).all()) | |||
| return links | |||
| else: | |||
| relationships = Relationship.query.filter_by(second_resource_id=resource_id).all() | |||
| if relationships: | |||
| links = [] | |||
| for relationship in relationships: | |||
| resource_id = relationship.first_resource_id | |||
| links = Resource.query.filter_by(id=resource_id).all() | |||
| return links | |||
| links.extend(Resource.query.filter_by(id=resource_id).all()) | |||
| return links | |||
| # function to delete a single resource | |||
| def delete_resource(resource_id): | |||
| @@ -0,0 +1,29 @@ | |||
| /* | |||
| # @name: main.js | |||
| # @version: 0.1 | |||
| # @creation_date: 2022-04-07 | |||
| # @license: The MIT License <https://opensource.org/licenses/MIT> | |||
| # @author: Simon Bowie <ad7588@coventry.ac.uk> | |||
| # @purpose: JavaScript functions for various functions | |||
| # @acknowledgements: | |||
| # https://stackoverflow.com/questions/67942546/bootstrap-5-select-dropdown-with-the-multiple-attribute-collapsed | |||
| */ | |||
| // Dynamic HTML forms based on dropdown menu | |||
| $("#resource_type").change(function() { | |||
| var $ = jQuery.noConflict(); | |||
| var resource_type = $(this).val(); | |||
| $(".resource_type_input").hide("fast", function() { | |||
| $("#resource_type_" + resource_type).show("slow"); | |||
| }); | |||
| }); | |||
| // Testing a couple of ways to expand text | |||
| var tooltipTriggerList = [].slice.call(document.querySelectorAll('[data-bs-toggle="tooltip"]')) | |||
| var tooltipList = tooltipTriggerList.map(function (tooltipTriggerEl) { | |||
| return new bootstrap.Tooltip(tooltipTriggerEl) | |||
| }) | |||
| var popoverTriggerList = [].slice.call(document.querySelectorAll('[data-bs-toggle="popover"]')) | |||
| var popoverList = popoverTriggerList.map(function (popoverTriggerEl) { | |||
| return new bootstrap.Popover(popoverTriggerEl) | |||
| }) | |||
| @@ -1036,3 +1036,253 @@ main > .container { | |||
| --bs-bg-opacity: 1; | |||
| background-color: rgba(var(--bs-practice-rgb),var(--bs-bg-opacity))!important; | |||
| } | |||
| .drop { | |||
| position: relative; | |||
| -webkit-user-select: none; | |||
| -moz-user-select: none; | |||
| -ms-user-select: none; | |||
| user-select: none; | |||
| } | |||
| .drop.open { | |||
| z-index: 100; | |||
| } | |||
| .drop.open .drop-screen { | |||
| z-index: 100; | |||
| display: block; | |||
| } | |||
| .drop.open .drop-options { | |||
| z-index: 200; | |||
| max-height: 200px; | |||
| } | |||
| .drop.open .drop-display { | |||
| z-index: 200; | |||
| border-color: #465; | |||
| } | |||
| .drop select { | |||
| display: none; | |||
| } | |||
| .drop .drop-screen { | |||
| position: fixed; | |||
| width: 100%; | |||
| height: 100%; | |||
| background: #000; | |||
| top: 0px; | |||
| left: 0px; | |||
| opacity: 0; | |||
| display: none; | |||
| z-index: 1; | |||
| } | |||
| .link { | |||
| text-align: center; | |||
| margin: 20px 0px; | |||
| color:#8CACD7; | |||
| } | |||
| .drop .drop-display { | |||
| position: relative; | |||
| padding: 0px 20px 5px 5px; | |||
| border: 4px solid #444; | |||
| width: 100%; | |||
| background: #FFF; | |||
| z-index: 1; | |||
| margin: 0px; | |||
| font-size: 16px; | |||
| min-height: 58px; | |||
| } | |||
| .drop .drop-display:hover:after { | |||
| opacity: 0.75; | |||
| } | |||
| .drop .drop-display:after { | |||
| font-family: 'Material Icons'; | |||
| content: "\e5c6"; | |||
| position: absolute; | |||
| right: 10px; | |||
| top: 12px; | |||
| font-size: 24px; | |||
| color: #444; | |||
| } | |||
| .drop .drop-display .item { | |||
| position: relative; | |||
| display: inline-block; | |||
| border: 2px solid #333; | |||
| margin: 5px 5px -4px 0px; | |||
| padding: 0px 25px 0px 10px; | |||
| overflow: hidden; | |||
| height: 40px; | |||
| line-height: 36px; | |||
| } | |||
| .drop .drop-display .item .btnclose { | |||
| color: #444; | |||
| position: absolute; | |||
| font-size: 16px; | |||
| right: 5px; | |||
| top: 10px; | |||
| cursor: pointer; | |||
| } | |||
| .drop .drop-display .item .btnclose:hover { | |||
| opacity: 0.75; | |||
| } | |||
| .drop .drop-display .item.remove { | |||
| -webkit-animation: removeSelected 0.2s, hide 1s infinite; | |||
| animation: removeSelected 0.2s, hide 1s infinite; | |||
| -webkit-animation-delay: 0s, 0.2s; | |||
| animation-delay: 0s, 0.2s; | |||
| } | |||
| .drop .drop-display .item.add { | |||
| -webkit-animation: addSelected 0.2s; | |||
| animation: addSelected 0.2s; | |||
| } | |||
| .drop .drop-display .item.hide { | |||
| display: none; | |||
| } | |||
| .drop .drop-options { | |||
| background: #444; | |||
| box-shadow: 0px 2px 4px rgba(0, 0, 0, 0.25); | |||
| position: absolute; | |||
| width: 100%; | |||
| max-height: 0px; | |||
| overflow-y: auto; | |||
| transition: all 0.25s linear; | |||
| z-index: 1; | |||
| } | |||
| .drop .drop-options a { | |||
| display: block; | |||
| height: 40px; | |||
| line-height: 40px; | |||
| padding: 0px 20px; | |||
| color: white; | |||
| position: relative; | |||
| max-height: 40px; | |||
| transition: all 1s; | |||
| overflow: hidden; | |||
| } | |||
| .drop .drop-options a:hover { | |||
| background: #465; | |||
| cursor: pointer; | |||
| } | |||
| .drop .drop-options a.remove { | |||
| -webkit-animation: removeOption 0.2s; | |||
| animation: removeOption 0.2s; | |||
| max-height: 0px; | |||
| } | |||
| .drop .drop-options a.add { | |||
| -webkit-animation: addOption 0.2s; | |||
| animation: addOption 0.2s; | |||
| } | |||
| .drop .drop-options a.hide { | |||
| display: none; | |||
| } | |||
| @-webkit-keyframes pop { | |||
| from { | |||
| -webkit-transform: scale(0); | |||
| transform: scale(0); | |||
| } | |||
| to { | |||
| -webkit-transform: scale(1); | |||
| transform: scale(1); | |||
| } | |||
| } | |||
| @keyframes pop { | |||
| from { | |||
| -webkit-transform: scale(0); | |||
| transform: scale(0); | |||
| } | |||
| to { | |||
| -webkit-transform: scale(1); | |||
| transform: scale(1); | |||
| } | |||
| } | |||
| @-webkit-keyframes removeOption { | |||
| from { | |||
| max-height: 40px; | |||
| } | |||
| to { | |||
| max-height: 0px; | |||
| } | |||
| } | |||
| @keyframes removeOption { | |||
| from { | |||
| max-height: 40px; | |||
| } | |||
| to { | |||
| max-height: 0px; | |||
| } | |||
| } | |||
| @-webkit-keyframes addOption { | |||
| from { | |||
| max-height: 0px; | |||
| } | |||
| to { | |||
| max-height: 40px; | |||
| } | |||
| } | |||
| @keyframes addOption { | |||
| from { | |||
| max-height: 0px; | |||
| } | |||
| to { | |||
| max-height: 40px; | |||
| } | |||
| } | |||
| @-webkit-keyframes removeSelected { | |||
| from { | |||
| -webkit-transform: scale(1); | |||
| transform: scale(1); | |||
| } | |||
| to { | |||
| -webkit-transform: scale(0); | |||
| transform: scale(0); | |||
| } | |||
| } | |||
| @keyframes removeSelected { | |||
| from { | |||
| -webkit-transform: scale(1); | |||
| transform: scale(1); | |||
| } | |||
| to { | |||
| -webkit-transform: scale(0); | |||
| transform: scale(0); | |||
| } | |||
| } | |||
| @-webkit-keyframes addSelected { | |||
| from { | |||
| -webkit-transform: scale(0); | |||
| transform: scale(0); | |||
| } | |||
| to { | |||
| -webkit-transform: scale(1); | |||
| transform: scale(1); | |||
| } | |||
| } | |||
| @keyframes addSelected { | |||
| from { | |||
| -webkit-transform: scale(0); | |||
| transform: scale(0); | |||
| } | |||
| to { | |||
| -webkit-transform: scale(1); | |||
| transform: scale(1); | |||
| } | |||
| } | |||
| @-webkit-keyframes hide { | |||
| from, to { | |||
| max-height: 0px; | |||
| max-width: 0px; | |||
| padding: 0px; | |||
| margin: 0px; | |||
| border-width: 0px; | |||
| } | |||
| } | |||
| @keyframes hide { | |||
| from, to { | |||
| max-height: 0px; | |||
| max-width: 0px; | |||
| padding: 0px; | |||
| margin: 0px; | |||
| border-width: 0px; | |||
| } | |||
| } | |||
| @@ -23,6 +23,7 @@ | |||
| <!-- Bootstrap CSS --> | |||
| <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous"> | |||
| <link href="{{ url_for('static',filename='styles/custom.css') }}" rel="stylesheet"> | |||
| <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-select/1.14.0-beta2/css/bootstrap-select.min.css" integrity="sha512-mR/b5Y7FRsKqrYZou7uysnOdCIJib/7r5QeJMFvLNHNhtye3xJp1TdJVPLtetkukFn227nKpXD9OjUc09lx97Q==" crossorigin="anonymous" referrerpolicy="no-referrer" /> | |||
| </head> | |||
| <body class="d-flex flex-column min-vh-100"> | |||
| @@ -149,28 +150,8 @@ | |||
| <!-- jQuery first, then Popper JS, then Bootstrap JS --> | |||
| <script src="https://code.jquery.com/jquery-3.6.0.js" integrity="sha256-H+K7U5CnXl1h5ywQfKtSj8PCmoN9aaq30gDh27Xc0jk=" crossorigin="anonymous"></script> | |||
| <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/js/bootstrap.bundle.min.js" integrity="sha384-MrcW6ZMFYlzcLA8Nl+NtUVF0sA7MsXsP1UyJoMp4YLEuNSfAP+JcXn/tWtIaxVXM" crossorigin="anonymous"></script> | |||
| <script> | |||
| $("#resource_type").change(function() { | |||
| var resource_type = $(this).val(); | |||
| $(".resource_type_input").hide("fast", function() { | |||
| $("#resource_type_" + resource_type).show("slow"); | |||
| }); | |||
| }); | |||
| </script> | |||
| <script> | |||
| // Initialize tooltips | |||
| var tooltipTriggerList = [].slice.call(document.querySelectorAll('[data-bs-toggle="tooltip"]')) | |||
| var tooltipList = tooltipTriggerList.map(function (tooltipTriggerEl) { | |||
| return new bootstrap.Tooltip(tooltipTriggerEl) | |||
| }) | |||
| </script> | |||
| <script> | |||
| var popoverTriggerList = [].slice.call(document.querySelectorAll('[data-bs-toggle="popover"]')) | |||
| var popoverList = popoverTriggerList.map(function (popoverTriggerEl) { | |||
| return new bootstrap.Popover(popoverTriggerEl) | |||
| }) | |||
| </script> | |||
| <script src="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-select/1.14.0-beta2/js/bootstrap-select.min.js" integrity="sha512-FHZVRMUW9FsXobt+ONiix6Z0tIkxvQfxtCSirkKc5Sb4TKHmqq1dZa8DphF0XqKb3ldLu/wgMa8mT6uXiLlRlw==" crossorigin="anonymous" referrerpolicy="no-referrer"></script> | |||
| <script src="{{ url_for('static',filename='js/main.js') }}"></script> | |||
| </body> | |||
| </html> | |||
| @@ -70,12 +70,14 @@ | |||
| </div> | |||
| <div class="mb-3 mt-3"> | |||
| <label for="linked_practice_id">Linked practices</label> | |||
| <select class="form-select" aria-label="Linked practices" name="linked_practice_id"> | |||
| <option selected>Select a linked practice</option> | |||
| <label for="linked_practice_id">Linked resources</label> | |||
| <!--<select class="form-select" aria-label="Linked practices" name="linked_practice_id" multiple="multiple" id="linked_practice_id">--> | |||
| <select name="linked_resources" id="linked_resources" aria-label="Linked resources" class="selectpicker" data-live-search="true" multiple> | |||
| <optgroup label="Practices"> | |||
| {% for practice_dropdown in practice_dropdown %} | |||
| <option value="{{ practice_dropdown['id'] }}">{{ practice_dropdown['name'] }}</option> | |||
| {% endfor %} | |||
| </optgroup> | |||
| </select> | |||
| </div> | |||
| </div> | |||