diff --git a/.gitignore b/.gitignore index 18d7ad1..983a96c 100755 --- a/.gitignore +++ b/.gitignore @@ -4,5 +4,7 @@ src/public/uploads src/public/uploads/* src/log src/log/* +postgres-data/* .env +.ruby-version diff --git a/Dockerfile b/Dockerfile index ea374d7..c325a29 100755 --- a/Dockerfile +++ b/Dockerfile @@ -34,6 +34,9 @@ RUN apt-get install -y curl # For image conversion RUN apt-get install -y imagemagick +# Create old uploads stub in the container +RUN mkdir -p /old-uploads + # Create the server direcotory in the container RUN mkdir -p /lacr-search WORKDIR /lacr-search @@ -42,7 +45,8 @@ WORKDIR /lacr-search ADD src/Gemfile /lacr-search/Gemfile ADD src/Gemfile.lock /lacr-search/Gemfile.lock -# Install requered gems +# Install required gems +RUN bundle update --bundler RUN bundle install diff --git a/docker-compose.yml b/docker-compose.yml index 5bd37dc..09d690b 100755 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -13,12 +13,14 @@ services: expose: - 5433 - 5432 + volumes: + - ./postgres-data:/var/lib/postgresql/data environment: POSTGRES_USER: postgres POSTGRES_PASSWORD: ${POSTGRES_PASSWORD} es: - image: elasticsearch:latest + image: elasticsearch:5 restart: unless-stopped expose: - 9200 @@ -35,9 +37,12 @@ services: command: bundle exec rails s -p 80 -b '0.0.0.0' volumes: - ./src:/lacr-search + - /docker/lacr-search/src/public/uploads:/old-uploads environment: BASEX_ADMIN: ${BASEX_ADMIN} DATABASE_PASSWORD: ${DATABASE_PASSWORD} + BASEX_READONLY: ${BASEX_READONLY} + BASEX_CREATEONLY: ${BASEX_READONLY} ports: - "80:80" diff --git a/src/Gemfile b/src/Gemfile index aea4d83..2b3faab 100755 --- a/src/Gemfile +++ b/src/Gemfile @@ -1,18 +1,18 @@ source 'https://rubygems.org' git_source(:github) do |repo_name| - repo_name = "#{repo_name}/#{repo_name}" unless repo_name.include?("/") + repo_name = "#{repo_name}/#{repo_name}" unless repo_name.include?('/') "https://github.com/#{repo_name}.git" end gem 'rspec' gem 'lograge' # Bundle edge Rails instead: gem 'rails', github: 'rails/rails' -gem 'rails' +gem 'rails', '>= 5.2.2.1' # Use PostgreSQL as the database for Active Record gem 'pg' # Use Puma as the app server -gem 'puma' +gem 'puma', '~> 3.12' # Use SCSS for stylesheets gem 'sass-rails' # Use Uglifier as compressor for JavaScript assets @@ -27,7 +27,7 @@ gem 'jquery-ui-rails' # Add JavaScript for UI # Ruby Gem of the Bootstrap gem 'less-rails' # Javascript runtime gem 'twitter-bootstrap-rails' -gem "font-awesome-rails" +gem 'font-awesome-rails' gem 'carrierwave' # File upload gem 'groupdate' # Simple way to group by: day, week, etc. @@ -37,29 +37,37 @@ gem 'prawn' # PDF file generator gem 'will_paginate-bootstrap' # Pagination library # API for Elasticsearch -gem 'searchkick' +gem 'searchkick', '~> 3.1.2' gem 'oj' # Significantly increase performance with faster JSON generation. gem 'typhoeus' # Significantly increase performance with persistent HTTP connections -#User Authentication -gem 'devise' +# User Authentication +gem 'devise', '>= 4.6.0' gem 'devise-bootstrap-views' +group :development, :test do + # gem security audit + gem 'bundler-audit' +end + group :development do - # Access an IRB console on exception pages or by using <%= console %> anywhere in the code. - gem 'web-console', '>= 3.3.0' + gem 'byebug' gem 'listen', '~> 3.0.5' - # Spring speeds up development by keeping your application running in the background. Read more: https://github.com/rails/spring + # Spring speeds up development by keeping your application running in the + # background. Read more: https://github.com/rails/spring gem 'spring' gem 'spring-watcher-listen', '~> 2.0.0' - gem 'byebug' + # Access an IRB console on exception pages or by using <%= console %> + # anywhere in the code. + gem 'web-console', '>= 3.3.0' end group :test do - gem 'cucumber-rails', :require => false - # database_cleaner is not required, but highly recommended - gem 'database_cleaner' - # for testing JavaScript, require older version selenium and firefox version 47.0.1 for more info check: + gem 'cucumber-rails', require: false + # database_cleaner is not required, but highly recommended + gem 'database_cleaner' + # for testing JavaScript, require older version selenium and + # firefox version 47.0.1 for more info check: # https://github.com/teamcapybara/capybara#drivers gem 'selenium-webdriver', '~> 2.53.4' -end \ No newline at end of file +end diff --git a/src/Gemfile.lock b/src/Gemfile.lock index 5ab8cb4..3f7e1a7 100755 --- a/src/Gemfile.lock +++ b/src/Gemfile.lock @@ -1,56 +1,59 @@ GEM remote: https://rubygems.org/ specs: - actioncable (5.2.2) - actionpack (= 5.2.2) + actioncable (5.2.4.4) + actionpack (= 5.2.4.4) nio4r (~> 2.0) websocket-driver (>= 0.6.1) - actionmailer (5.2.2) - actionpack (= 5.2.2) - actionview (= 5.2.2) - activejob (= 5.2.2) + actionmailer (5.2.4.4) + actionpack (= 5.2.4.4) + actionview (= 5.2.4.4) + activejob (= 5.2.4.4) mail (~> 2.5, >= 2.5.4) rails-dom-testing (~> 2.0) - actionpack (5.2.2) - actionview (= 5.2.2) - activesupport (= 5.2.2) - rack (~> 2.0) + actionpack (5.2.4.4) + actionview (= 5.2.4.4) + activesupport (= 5.2.4.4) + rack (~> 2.0, >= 2.0.8) rack-test (>= 0.6.3) rails-dom-testing (~> 2.0) rails-html-sanitizer (~> 1.0, >= 1.0.2) - actionview (5.2.2) - activesupport (= 5.2.2) + actionview (5.2.4.4) + activesupport (= 5.2.4.4) builder (~> 3.1) erubi (~> 1.4) rails-dom-testing (~> 2.0) rails-html-sanitizer (~> 1.0, >= 1.0.3) - activejob (5.2.2) - activesupport (= 5.2.2) + activejob (5.2.4.4) + activesupport (= 5.2.4.4) globalid (>= 0.3.6) - activemodel (5.2.2) - activesupport (= 5.2.2) - activerecord (5.2.2) - activemodel (= 5.2.2) - activesupport (= 5.2.2) + activemodel (5.2.4.4) + activesupport (= 5.2.4.4) + activerecord (5.2.4.4) + activemodel (= 5.2.4.4) + activesupport (= 5.2.4.4) arel (>= 9.0) - activestorage (5.2.2) - actionpack (= 5.2.2) - activerecord (= 5.2.2) + activestorage (5.2.4.4) + actionpack (= 5.2.4.4) + activerecord (= 5.2.4.4) marcel (~> 0.3.1) - activesupport (5.2.2) + activesupport (5.2.4.4) concurrent-ruby (~> 1.0, >= 1.0.2) i18n (>= 0.7, < 2) minitest (~> 5.1) tzinfo (~> 1.1) - addressable (2.5.2) + addressable (2.6.0) public_suffix (>= 2.0.2, < 4.0) arel (9.0.0) - backports (3.11.4) - bcrypt (3.1.12) - bindex (0.5.0) - builder (3.2.3) - byebug (10.0.2) - capybara (3.12.0) + backports (3.13.0) + bcrypt (3.1.16) + bindex (0.7.0) + builder (3.2.4) + bundler-audit (0.6.1) + bundler (>= 1.2.0, < 3) + thor (~> 0.18) + byebug (11.0.1) + capybara (3.16.2) addressable mini_mime (>= 0.1.3) nokogiri (~> 1.8) @@ -58,7 +61,7 @@ GEM rack-test (>= 0.6.3) regexp_parser (~> 1.2) xpath (~> 3.2) - carrierwave (1.2.3) + carrierwave (1.3.1) activemodel (>= 4.0.0) activesupport (>= 4.0.0) mime-types (>= 1.16) @@ -72,8 +75,8 @@ GEM execjs coffee-script-source (1.12.2) commonjs (0.2.7) - concurrent-ruby (1.1.3) - crass (1.0.4) + concurrent-ruby (1.1.7) + crass (1.0.6) cucumber (3.1.2) builder (>= 2.1.2) cucumber-core (~> 3.2.0) @@ -97,40 +100,40 @@ GEM cucumber-tag_expressions (1.1.1) cucumber-wire (0.0.1) database_cleaner (1.7.0) - devise (4.5.0) + devise (4.7.2) bcrypt (~> 3.0) orm_adapter (~> 0.1) - railties (>= 4.1.0, < 6.0) + railties (>= 4.1.0) responders warden (~> 1.2.3) devise-bootstrap-views (1.1.0) diff-lcs (1.3) - elasticsearch (6.1.0) - elasticsearch-api (= 6.1.0) - elasticsearch-transport (= 6.1.0) - elasticsearch-api (6.1.0) + elasticsearch (6.3.0) + elasticsearch-api (= 6.3.0) + elasticsearch-transport (= 6.3.0) + elasticsearch-api (6.3.0) multi_json - elasticsearch-transport (6.1.0) + elasticsearch-transport (6.3.0) faraday multi_json - erubi (1.7.1) - ethon (0.11.0) + erubi (1.9.0) + ethon (0.12.0) ffi (>= 1.3.0) execjs (2.7.0) faraday (0.15.4) multipart-post (>= 1.2, < 3) - ffi (1.9.25) + ffi (1.10.0) font-awesome-rails (4.7.0.4) railties (>= 3.2, < 6.0) gherkin (5.1.0) - globalid (0.4.1) + globalid (0.4.2) activesupport (>= 4.2.0) - groupdate (4.1.0) + groupdate (4.1.1) activesupport (>= 4.2) hashie (3.6.0) - i18n (1.1.1) + i18n (1.8.5) concurrent-ruby (~> 1.0) - jquery-rails (4.3.3) + jquery-rails (4.4.0) rails-dom-testing (>= 1, < 3) railties (>= 4.2.0) thor (>= 0.14, < 2.0) @@ -147,80 +150,82 @@ GEM listen (3.0.8) rb-fsevent (~> 0.9, >= 0.9.4) rb-inotify (~> 0.9, >= 0.9.7) - lograge (0.10.0) + lograge (0.11.0) actionpack (>= 4) activesupport (>= 4) railties (>= 4) request_store (~> 1.0) - loofah (2.2.3) + loofah (2.7.0) crass (~> 1.0.2) nokogiri (>= 1.5.9) mail (2.7.1) mini_mime (>= 0.1.1) marcel (0.3.3) mimemagic (~> 0.3.2) - method_source (0.9.2) + method_source (1.0.0) mime-types (3.2.2) mime-types-data (~> 3.2015) - mime-types-data (3.2018.0812) - mimemagic (0.3.2) - mini_magick (4.9.2) - mini_mime (1.0.1) - mini_portile2 (2.3.0) - minitest (5.11.3) + mime-types-data (3.2019.0331) + mimemagic (0.3.5) + mini_magick (4.10.1) + mini_mime (1.0.2) + mini_portile2 (2.5.0) + minitest (5.14.2) multi_json (1.13.1) multi_test (0.1.2) multipart-post (2.0.0) - nio4r (2.3.1) - nokogiri (1.8.5) - mini_portile2 (~> 2.3.0) - oj (3.7.4) + nio4r (2.5.4) + nokogiri (1.11.1) + mini_portile2 (~> 2.5.0) + racc (~> 1.4) + oj (3.7.12) orm_adapter (0.5.0) pdf-core (0.7.0) - pg (1.1.3) + pg (1.1.4) prawn (2.2.2) pdf-core (~> 0.7.0) ttfunk (~> 1.5) public_suffix (3.0.3) - puma (3.12.0) - rack (2.0.6) + puma (3.12.6) + racc (1.5.2) + rack (2.2.3) rack-test (1.1.0) rack (>= 1.0, < 3) - rails (5.2.2) - actioncable (= 5.2.2) - actionmailer (= 5.2.2) - actionpack (= 5.2.2) - actionview (= 5.2.2) - activejob (= 5.2.2) - activemodel (= 5.2.2) - activerecord (= 5.2.2) - activestorage (= 5.2.2) - activesupport (= 5.2.2) + rails (5.2.4.4) + actioncable (= 5.2.4.4) + actionmailer (= 5.2.4.4) + actionpack (= 5.2.4.4) + actionview (= 5.2.4.4) + activejob (= 5.2.4.4) + activemodel (= 5.2.4.4) + activerecord (= 5.2.4.4) + activestorage (= 5.2.4.4) + activesupport (= 5.2.4.4) bundler (>= 1.3.0) - railties (= 5.2.2) + railties (= 5.2.4.4) sprockets-rails (>= 2.0.0) rails-dom-testing (2.0.3) activesupport (>= 4.2.0) nokogiri (>= 1.6) - rails-html-sanitizer (1.0.4) - loofah (~> 2.2, >= 2.2.2) - railties (5.2.2) - actionpack (= 5.2.2) - activesupport (= 5.2.2) + rails-html-sanitizer (1.3.0) + loofah (~> 2.3) + railties (5.2.4.4) + actionpack (= 5.2.4.4) + activesupport (= 5.2.4.4) method_source rake (>= 0.8.7) thor (>= 0.19.0, < 2.0) - rake (12.3.2) + rake (13.0.1) rb-fsevent (0.10.3) - rb-inotify (0.9.10) - ffi (>= 0.5.0, < 2) + rb-inotify (0.10.0) + ffi (~> 1.0) ref (2.0.0) - regexp_parser (1.3.0) + regexp_parser (1.4.0) request_store (1.4.1) rack (>= 1.4) - responders (2.4.0) - actionpack (>= 4.2.0, < 5.3) - railties (>= 4.2.0, < 5.3) + responders (3.0.1) + actionpack (>= 5.0) + railties (>= 5.0) rspec (3.8.0) rspec-core (~> 3.8.0) rspec-expectations (~> 3.8.0) @@ -234,8 +239,8 @@ GEM diff-lcs (>= 1.2.0, < 2.0) rspec-support (~> 3.8.0) rspec-support (3.8.0) - rubyzip (1.2.2) - sass (3.7.2) + rubyzip (1.3.0) + sass (3.7.4) sass-listen (~> 4.0.0) sass-listen (4.0.0) rb-fsevent (~> 0.9, >= 0.9.4) @@ -246,7 +251,7 @@ GEM sprockets (>= 2.8, < 4.0) sprockets-rails (>= 2.0, < 4.0) tilt (>= 1.1, < 3) - searchkick (3.1.2) + searchkick (3.1.3) activemodel (>= 4.2) elasticsearch (>= 5) hashie @@ -262,7 +267,7 @@ GEM sprockets (3.7.2) concurrent-ruby (~> 1.0) rack (> 1, < 3) - sprockets-rails (3.2.1) + sprockets-rails (3.2.2) actionpack (>= 4.0) activesupport (>= 4.0) sprockets (>= 3.0.0) @@ -280,23 +285,23 @@ GEM railties (~> 5.0, >= 5.0.1) typhoeus (1.3.1) ethon (>= 0.9.0) - tzinfo (1.2.5) + tzinfo (1.2.7) thread_safe (~> 0.1) uglifier (4.1.20) execjs (>= 0.3.0, < 3) - warden (1.2.8) - rack (>= 2.0.6) + warden (1.2.9) + rack (>= 2.0.9) web-console (3.7.0) actionview (>= 5.0) activemodel (>= 5.0) bindex (>= 0.4.0) railties (>= 5.0) websocket (1.2.8) - websocket-driver (0.7.0) + websocket-driver (0.7.3) websocket-extensions (>= 0.1.0) - websocket-extensions (0.1.3) - will_paginate (3.1.6) - will_paginate-bootstrap (1.0.1) + websocket-extensions (0.1.5) + will_paginate (3.1.7) + will_paginate-bootstrap (1.0.2) will_paginate (>= 3.0.3) xpath (3.2.0) nokogiri (~> 1.8) @@ -305,12 +310,13 @@ PLATFORMS ruby DEPENDENCIES + bundler-audit byebug carrierwave coffee-rails cucumber-rails database_cleaner - devise + devise (>= 4.6.0) devise-bootstrap-views font-awesome-rails groupdate @@ -323,12 +329,12 @@ DEPENDENCIES oj pg prawn - puma - rails + puma (~> 3.12) + rails (>= 5.2.2.1) rspec rubyzip sass-rails - searchkick + searchkick (~> 3.1.2) selenium-webdriver (~> 2.53.4) spring spring-watcher-listen (~> 2.0.0) @@ -340,4 +346,4 @@ DEPENDENCIES will_paginate-bootstrap BUNDLED WITH - 1.17.1 + 1.17.2 diff --git a/src/app/assets/javascripts/documents.js b/src/app/assets/javascripts/documents.js index 302f241..2350ada 100755 --- a/src/app/assets/javascripts/documents.js +++ b/src/app/assets/javascripts/documents.js @@ -17,6 +17,20 @@ var load_document = function (p, v){ } catch (e) {} }); + $('#image-chooser').css('display', 'block'); + + $('#doc-image img:not(:first-child)').css('display','none'); + + $('#image-chooser').change(function() { + chosenId = $('#image-chooser').val(); + $('#doc-image img').css('display','none'); + $('#doc-image img#' + chosenId).css('display','initial'); + $('#doc-image').trigger('zoom.destroy'); + $('#doc-image').zoom({ + url: $('#doc-image img#' + chosenId).data('largeImage') + }); + }); + // Image zoom on hover $('#doc-image').zoom({ url: $('#doc-image img').data('largeImage') diff --git a/src/app/assets/javascripts/home.js b/src/app/assets/javascripts/home.js index f7bb367..0e0ec3e 100755 --- a/src/app/assets/javascripts/home.js +++ b/src/app/assets/javascripts/home.js @@ -1,17 +1,21 @@ $(document).ready(function() { - var dateFormat = 'yy-mm-dd'; - var minDate = '1398-01-01'; - var maxDate = '1511-12-31'; + var dateFormat = 'dd/mm/yy'; + var minDate = '01/01/1398'; + var maxDate = '31/12/1511'; // Initialise date fields for Advanced Search $( "#date_from" ).datepicker({ showOtherMonths: true, selectOtherMonths: true, - dateFormat: 'yy-mm-dd', + dateFormat: dateFormat, minDate: $.datepicker.parseDate( dateFormat, minDate ), maxDate: $.datepicker.parseDate( dateFormat, maxDate ), defaultDate: $.datepicker.parseDate( dateFormat, minDate ) }).on( "change", function() { $( "#date_to" ).datepicker( "option", "minDate", getDate( this ) ); + if ($("#date_to").val() == ""){ + $("#date_to").val($("#date_from").val()); + } + // if date_to not set, set to same value. }); $( "#date_to" ).datepicker({ @@ -50,6 +54,7 @@ $(document).ready(function() { anchors:['homepage', 'advsearch', 'about'], navigation: true, paddingTop: '60px', + scrollBar: true, onLeave: function(index, nextIndex, direction){ // Hide datepicer after leaving Advanced Search section if(index == 2){ @@ -62,15 +67,6 @@ $(document).ready(function() { } }); - // Initialise spelling variants slider - $('#slider-spellVar').slider({ range: "max", - min: 0, max: 4, value: 1, - slide: function( event, ui ) { - $( "#spellVar" ).val( ui.value ); - } - }); - $( "#spellVar" ).val( $( "#slider-spellVar" ).slider( "value" ) ); - // Toggle spelling variants on Regular expressions selected $('input[name="sm"]').on('click', toggleMisspellings); toggleMisspellings(); @@ -79,7 +75,6 @@ $(document).ready(function() { var toggleMisspellings = function () { $disabled = $('input:checked[name="sm"]').val() == 5; - $("#slider-spellVar").slider( "option", "disabled", $disabled); $('#spellVar').prop('disabled', $disabled); }; @@ -99,6 +94,18 @@ $('.fp-controlArrow-down').click(function(){ $.fn.fullpage.moveSectionDown(); }); +$('input[name=vc]').on('change', function() { + toggle_volume_list(); +}); + +toggle_volume_list = function() { + if ($("input[name=vc]:checked").val() == 0) { + $('.volume-chooser .list').css('display', 'none'); + $("input.vol").prop('checked', true); + } else { + $('.volume-chooser .list').css('display', 'block'); + } +} function submitForm(){ var name=$('.vol'); diff --git a/src/app/assets/javascripts/search.js b/src/app/assets/javascripts/search.js index a75932d..1f508c4 100755 --- a/src/app/assets/javascripts/search.js +++ b/src/app/assets/javascripts/search.js @@ -1,72 +1,18 @@ //= require highlightRegex.min.js -var chartData = []; -var loadChart = function (chartAPI) { - chartAPI = (chartAPI !== 'undefined') ? chartAPI : ""; - - if (chartData.length === 0) - { - if (chartAPI !== '') - { - $.getJSON( chartAPI ) - .done(function( data ) { - if (data.length > 1) { - for(i=0; i< data.length; i++) - { - var row = data[i]; - newRow = row.slice(0, 3); - newRow.push(new Date(row[3])); - newRow.push(new Date(row[4])); - chartData[i] = newRow; - } - $('#toggleChart-1').show(); - } - }); - } - } - else if ($('#chart-1').css('visibility') === 'hidden') { - google.charts.load('current', {'packages':['timeline']}); - google.charts.setOnLoadCallback(drawChart); - var drawChart = function () { - var container = document.getElementById('chart-1'); - var chart = new google.visualization.Timeline(container); - var dataTable = new google.visualization.DataTable(); - - dataTable.addColumn({type: "string", id: "Name"}); - dataTable.addColumn({type: "string", id: 'dummy bar label' }); - dataTable.addColumn({type: "string", role: 'tooltip', 'p': {'html': true} }); - dataTable.addColumn({type: "date", id: "Start"}); - dataTable.addColumn({type: "date", id: "End"}); - dataTable.addRows(chartData); - - var options = { - timeline: { colorByRowLabel: true }, - tooltip: {isHtml: true}, - }; - - chart.draw(dataTable, options); - - $('#chart-1').css('visibility', 'visible'); - $('#chart-1').css('height', 'auto'); - $(window).trigger('resize'); - }; drawChart(); - } - else { - $('#chart-1').fadeToggle(); - $(window).trigger('resize'); - } -}; - toggle_search_tools_when_regex = function(){ $disabled = $("select[name='sm']").val() == 5; $("select[name='m']").prop("disabled", $disabled); }; + + $(function() { // Search method is Regex $('select').on('change', function() { toggle_search_tools_when_regex(); }); + toggle_search_tools_when_regex(); if($("select[name='sm']").val() == 5){ $('.list-group-item').highlightRegex(new RegExp($("input.simple-search").val(), "ig")); diff --git a/src/app/assets/stylesheets/application.css b/src/app/assets/stylesheets/application.css index 2c920c7..c20ee21 100755 --- a/src/app/assets/stylesheets/application.css +++ b/src/app/assets/stylesheets/application.css @@ -122,6 +122,11 @@ a { #search-method .radio-inline { display: inline-block; } + + #search-method ul { + padding-left: 0; + } + @media (max-width: 767px) { /*Align search methods on multiple lines*/ @@ -178,7 +183,8 @@ a { z-index: 1000; float: left; min-width: 140px; - max-width: 140px; + max-width: 280px; + width: 280px; max-height: 500px; overflow-y: auto; padding:0; @@ -193,6 +199,27 @@ a { text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5); } + @media only screen and (min-width: 1241px) { + .sidebar-nav .nav { + width: 210px; + } + } + + @media only screen and (min-width: 1661px) { + .sidebar-nav .nav { + width: 280px; + } +} + + .sidebar-nav .nav .btn-primary{ + padding: 12px; + } + + .nav > div > div > a { + padding: 6px 12px; + font-size: 13px; + color: #444444; + } /*Small box for Upload files*/ .center-box-sm{ @@ -219,6 +246,7 @@ a { } .navbar-brand{ text-align: center; + padding-right: 0; } #noty_topRight_layout_container{ @@ -242,12 +270,8 @@ a { } .list-group-item{ - /* Concise the pages in Document Browse */ - padding: 1px; -} - -.tr-text{ - font-family: "museo-slab-1","museo-slab-2",serif; + padding: 10px; + margin-bottom: 10px; } .navbar-fixed-top .navbar-collapse { diff --git a/src/app/assets/stylesheets/documents.scss b/src/app/assets/stylesheets/documents.scss index 7ce8e65..da5dbf9 100755 --- a/src/app/assets/stylesheets/documents.scss +++ b/src/app/assets/stylesheets/documents.scss @@ -2,7 +2,7 @@ * They will automatically be included in application.css. * You can use Sass (SCSS) here: http://sass-lang.com/ -*= require annotation.css +*= require annotation.scss */ // Styles for image zoom jquery plugin @@ -30,9 +30,22 @@ .doc-tools { display: none; } + #doc-browse { display: none; + #volume { + .btn { + background-color: #88b5dd; + &.active { + background-color: #3071a9; + } + &:hover { + background-color: #3071a9; + } + } + } } + #doc_view { display: none; } @@ -48,3 +61,51 @@ .list-group-item{ cursor: pointer; } + +.cert-low, .cert-medium, .cert-high{ + cursor: pointer; + padding: 5px; + border-radius: 5px; + background-color: green; + position: relative; + top: -5px; + vertical-align: top; + display: inline-block; + + &:hover{ + &:after{ + content: "(Certainty: High)"; + width: auto; + height: auto; + color: white; + display: block; + border-radius: 5px; + } + } +} + +.cert-medium{ + background-color: orange; + &:hover{ + &:after{ + content: "(Certainty: Medium)"; + } + } +} + +.cert-low{ + background-color: red; + &:hover{ + &:after{ + content: "(Certainty: Low)"; + } + } +} + +.tr-text{ + font-family: "museo-slab-1","museo-slab-2",serif; + lb{ + display: inline-block; + width: 0.2em; + } +} diff --git a/src/app/assets/stylesheets/home.scss b/src/app/assets/stylesheets/home.scss index 916487f..7e7b371 100755 --- a/src/app/assets/stylesheets/home.scss +++ b/src/app/assets/stylesheets/home.scss @@ -238,3 +238,51 @@ max-width: 150px; } } + +.volume-chooser { + padding-left: 0; + .list { + display: none; + li:first-child { + padding-top: 0; + } + } +} + +.form-control{ + &:focus{ + border-color: #66afe9 !important; + outline: 1px solid blue !important; + -webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(102, 175, 233, 0.6) !important; + box-shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(102, 175, 233, 0.6) !important; + } +} + +input[type=radio], input[type=checkbox]{ + &:focus{ + outline: 2px solid blue !important; + } +} + +a, .documents-button button, .documents-selected-button button, .btn-link { + &:focus{ + outline: 1px dotted black !important; + } +} + +.ui-datepicker{ + font-size: 16px; + .ui-state-default{ + background-color: white; + } + .ui-state-hover{ + border: 1px solid black; + background-color: #b1c7e7; + font-weight: bold; + } + .ui-state-active{ + background-color: #0052a3; + font-weight: bold; + color: white; + } +} \ No newline at end of file diff --git a/src/app/assets/stylesheets/search.scss b/src/app/assets/stylesheets/search.scss index 720ca4c..cd874f0 100755 --- a/src/app/assets/stylesheets/search.scss +++ b/src/app/assets/stylesheets/search.scss @@ -3,3 +3,22 @@ .highlight, mark{ background-color: #ffff4d; } + + +.results-count{ + font-size: 16px; + font-weight: bold; + margin: 15px 0; +} + +.list-group.search-results { + .list-group-item { + padding: 5px; + margin: 15px 0; + } +} + +#back-to-search-results { + margin-left: 15px; +} + diff --git a/src/app/controllers/documents_controller.rb b/src/app/controllers/documents_controller.rb index 7345d24..06876c8 100755 --- a/src/app/controllers/documents_controller.rb +++ b/src/app/controllers/documents_controller.rb @@ -16,10 +16,11 @@ def selected cookies.delete :selected_entries redirect_to doc_path, :alert => "No selected paragraphs!" end + @document_images = [] end def list - @documents = Search.select(:page, :volume).distinct.order(volume: :asc, page: :asc).group(:volume, :page) + @documents = Search.select(:page, :volume).distinct.order(volume: :asc).group(:volume, :page) respond_to do |format| format.html { redirect_to doc_path } format.json { render json: @documents } @@ -55,7 +56,7 @@ def page_simplified # Store the volume and page from the input @volume, @page = params[:v].to_i, params[:p].to_i # Select Documents - @documents = Search.order(:paragraph).where('volume' => @volume).rewhere('page' => @page) + @documents = Search.order(:entry, :id).where('volume' => @volume).rewhere('page' => @page) if @documents.length > 0 # Select image respond_to do |format| @@ -76,14 +77,17 @@ def page # Store the volume and page from the input @volume, @page = params[:v].to_i, params[:p].to_i # Select Documents - @documents = Search.order(:paragraph).where('volume' => @volume).rewhere('page' => @page) + @documents = Search.order(:entry, :id).where('volume' => @volume).rewhere('page' => @page) if @documents.length > 0 # Select image - page_image = PageImage.find_by_volume_and_page(@volume, @page) - if page_image # Has been uploaded - # Simple Fix of the file extension after image convert - @document_image_normal = page_image.image.normal.url.split('.')[0...-1].join + '.jpeg' - @document_image_large = page_image.image.large.url.split('.')[0...-1].join + '.jpeg' + page_image = PageImage.where(volume: @volume, page: @page) + @document_images = [] + page_image.each do |img| + @document_images << { + id: img.image.to_s.split('/').last.split('.').first, + normal: img.image.normal.url.split('.')[0...-1].join + '.jpeg', + large: img.image.large.url.split('.')[0...-1].join + '.jpeg' + } end respond_to do |format| format.html { render :partial => "documents/page" } diff --git a/src/app/controllers/download_controller.rb b/src/app/controllers/download_controller.rb index db4437e..9d6e5a1 100755 --- a/src/app/controllers/download_controller.rb +++ b/src/app/controllers/download_controller.rb @@ -10,8 +10,10 @@ def index xml_paths = Set.new # For each selected page selected.each do |s| - entry = selected[s] + + entry = selected[s[0]] # Continue if volume and page are spacified + if entry.key?("volume") and entry.key?("page") vol, page = entry['volume'], entry['page'] @@ -106,7 +108,7 @@ def selected_gen_pdf send_data TrParagraph.new().print_data(documents), filename:'Selected_entries.pdf', type: "application/pdf", disposition: :attachment else page_not_found - end + end else page_not_found end diff --git a/src/app/controllers/search_controller.rb b/src/app/controllers/search_controller.rb index 6a47ed1..a916297 100755 --- a/src/app/controllers/search_controller.rb +++ b/src/app/controllers/search_controller.rb @@ -48,6 +48,7 @@ def search # Use strong params permited = simple_search_params + @page = permited[:page] # Parse Spelling variants and Results per page get_search_tools_params(permited) @@ -57,7 +58,7 @@ def search @searchMethod = 5 # Regexp @documents = Search.search '*', - page: permited[:page], per_page: @results_per_page, # Pagination + page: @page, per_page: @results_per_page, # Pagination where: {content:{"regexp":".*" + @query + ".*"}}.merge(get_adv_search_params(permited)), match: get_serch_method(permited), # Parse search method parameter order: get_order_by(permited), # Parse order_by parameter @@ -66,7 +67,7 @@ def search else @documents = Search.search @query, misspellings: {edit_distance: @misspellings,transpositions: false}, - page: permited[:page], per_page: @results_per_page, # Pagination + page: @page, per_page: @results_per_page, # Pagination where: get_adv_search_params(permited), # Parse adv search parameters match: get_serch_method(permited), # Parse search method parameter order: get_order_by(permited), # Parse order_by parameter @@ -143,11 +144,12 @@ def get_search_tools_params(permited) def get_order_by(permited) # Get the orderBy mode - # 0 -> Most relevant first - # 1 -> Volume/Page in ascending order + # 0 -> Most relevant / frequent first + # 1 -> Volume/Page in ascending order (Default) # 2 -> Volume/Page in descending order # 3 -> Chronological orther @orderBy = permited[:o].to_i + @orderBy = 1 unless permited[:o] # Set Default 1 order_by = {} if @orderBy == 0 order_by['_score'] = :desc # most relevant first - default @@ -191,30 +193,16 @@ def get_adv_search_params(permited) date_range = {} if permited[:date_from] # Filter by lower date bound begin - date_str = permited[:date_from] # Get date - # Fix incorrect date format - case date_str.split('-').length - when 3 then date_range[:gte] = date_str.to_date - when 2 then date_range[:gte] = "#{date_str}-1".to_date - when 1 then date_range[:gte] = "#{date_str}-1-1".to_date - else flash[:notice] = "Incorrect \"Date from\" format" - end - rescue - flash[:notice] = "Incorrect \"Date from\" format" + date_range[:gte] = extract_date(permited[:date_from], fix: :from) + rescue StandardError => e + flash[:notice] = "#{e.message}: Incorrect \"Date from\" format" end end if permited[:date_to] # Filter by upper date bound begin - date_str = permited[:date_to] # Get date - # Fix incorrect date format - case date_str.split('-').length - when 3 then date_range[:lte] = date_str.to_date - when 2 then date_range[:lte] = "#{date_str}-28".to_date - when 1 then date_range[:lte] = "#{date_str}-12-31".to_date - else flash[:notice] = "Incorrect \"Date to\" format" - end - rescue - flash[:notice] = "Incorrect \"Date to\" format" + date_range[:lte] = extract_date(permited[:date_to], fix: :to) + rescue StandardError => e + flash[:notice] = "#{e.message}: Incorrect \"Date to\" format" end end # Append to where_query @@ -234,4 +222,24 @@ def get_adv_search_params(permited) end return where_query end + + def extract_date(date, fix: :from) + fixes = { + from: ['1/', '1/1/'], + to: ['28/', '31/12/'] + } + + case date.split('/').length + when 3 + date.to_date + when 2 + "#{fixes[fix][0]}#{date}".to_date + when 1 + "#{fixes[fix][1]}#{date}".to_date + else + raise 'Illegal Date Range' + end + end end + + diff --git a/src/app/helpers/documents_helper.rb b/src/app/helpers/documents_helper.rb index 242b4fc..77abb1e 100755 --- a/src/app/helpers/documents_helper.rb +++ b/src/app/helpers/documents_helper.rb @@ -1,2 +1,15 @@ +# Helper functions for displaying documents module DocumentsHelper + def date_block(document) + date_str = 'Date: ' + date_str += "" + if document.date_incorrect + date_str += document.date_incorrect + elsif document.date_not_after + date_str += "between #{document.date} and #{document.date_not_after}" + else + date_str += "#{document.date}" + end + date_str + '' + end end diff --git a/src/app/helpers/search_helper.rb b/src/app/helpers/search_helper.rb index b3ce20a..b70976a 100755 --- a/src/app/helpers/search_helper.rb +++ b/src/app/helpers/search_helper.rb @@ -1,2 +1,31 @@ module SearchHelper + def search_result_header + if @documents.total_count == 1 + 'Showing 1 result' + elsif @documents.total_count <= @results_per_page + "Showing #{@documents.total_count} results" + else + (start_cnt, end_cnt) = page_range(@page, @results_per_page, @documents.total_count) + "Showing #{start_cnt} to #{end_cnt} of #{@documents.total_count} results" + end + end + + def page_range(page, per_page, maximum) + page_i = page ? page.to_i : 1 + + s = ((page_i - 1) * per_page) + 1 + e = s + per_page - 1 + + [[s, maximum].min, [e, maximum].min] + end + + def date_block_search(document) + if document.date_incorrect + document.date_incorrect + elsif document.date_not_after + "between #{document.date} and #{document.date_not_after}" + else + document.date + end + end end diff --git a/src/app/models/transcription_xml.rb b/src/app/models/transcription_xml.rb index 64b89a2..61abd11 100755 --- a/src/app/models/transcription_xml.rb +++ b/src/app/models/transcription_xml.rb @@ -51,6 +51,8 @@ def histei_split_to_paragraphs # Volume = the volume of any div in the document (Assuming it is always the same) volume = splitEntryID(doc.xpath('//xmlns:div[@xml:id]/@xml:id', 'xmlns' => HISTEI_NS)[0])[0] + # search_xml_order = [] + # Fix for empty pages page_breaks.each do |pb| begin @@ -70,8 +72,9 @@ def histei_split_to_paragraphs s.tr_paragraph = pr s.transcription_xml = self s.save + # search_xml_order << s end - rescue Exception => e + rescue StandardError => e logger.error(e) end end @@ -81,44 +84,17 @@ def histei_split_to_paragraphs #----------------------------------- # Extract all "div" tags with atribute "xml:id" - entries = doc.xpath("//xmlns:div[@xml:id]", 'xmlns' => HISTEI_NS) + entries = doc.xpath('//xmlns:div[@xml:id]', 'xmlns' => HISTEI_NS) # Parse each entry as follows entries.each do |entry| + date_info = parse_date_from_entry(entry) - d = entry.xpath("ancestor::xmlns:div[1]//xmlns:date/@when", 'xmlns' => HISTEI_NS) - if d.count > 1 - date_str = '' - for entry_date in d - entry_date_str = entry_date.to_s - if date_str.length < entry_date_str.length - date_str = entry_date_str - end - end - else - date_str = d.to_s - end - - # Go to the closest parent "div" of the entry and find a child "date" - # and extract the 'when' argument - date_from = entry.xpath("ancestor::xmlns:div[1]//xmlns:date/@from", 'xmlns' => HISTEI_NS).to_s - date_to = entry.xpath("ancestor::xmlns:div[1]//xmlns:date/@to", 'xmlns' => HISTEI_NS).to_s - if date_str.split('-').length == 3 - entry_date_incorrect = nil - entry_date = date_str.to_date - elsif date_str.split('-').length == 2 - entry_date_incorrect = date_str - entry_date = "#{date_str}-1".to_date # If the day is missing set ot 1-st - elsif date_str.split('-').length == 1 - entry_date_incorrect = date_str - entry_date = "#{date_str}-1-1".to_date # If the day and month are missing set ot 1-st Jan. - else - entry_date_incorrect = date_from.length != 0 ? "#{date_from} : #{date_to}": 'N/A' - entry_date = nil # The date is missing - end + dc = entry.xpath("ancestor::xmlns:div[1]//xmlns:date/@cert", 'xmlns' => HISTEI_NS) + date_certainty = dc.to_s # Convert the 'entry' and 'date' Nokogiri objects to Ruby Hashes - entry_id = entry.xpath("@xml:id").to_s - entry_lang = entry.xpath("@xml:lang").to_s + entry_id = entry.xpath('@xml:id').to_s + entry_lang = entry.xpath('@xml:lang').to_s case entry_lang # Fix language standad when 'sc' entry_lang = 'sco' @@ -135,8 +111,8 @@ def histei_split_to_paragraphs # Split entryID volume, page, paragraph = splitEntryID(entry) # Overwrite if exists - if Search.exists?(page: page, volume: volume, paragraph: paragraph) - s = Search.find_by(page: page, volume: volume, paragraph: paragraph) + if Search.exists?(entry: entry_id) + s = Search.find_by(entry: entry_id) # Get existing paragraph pr = s.tr_paragraph else @@ -159,11 +135,15 @@ def histei_split_to_paragraphs s.tr_paragraph = pr s.transcription_xml = self s.lang = entry_lang - s.date = entry_date - s.date_incorrect = entry_date_incorrect + s.date = date_info[:entry_date] + s.date_not_after = date_info[:entry_date_not_after] + s.date_incorrect = date_info[:entry_date_incorrect] + s.date_certainty = date_certainty + # Replace line-break tag with \n and normalize whitespace s.content = entry_text s.save + # search_xml_order << s end doc = Nokogiri::XML (File.open(xml.current_path)) @@ -175,93 +155,146 @@ def histei_split_to_paragraphs # -> Page breaks inside entries #----------------------------------- - # Get all entries with page break inside - + # Get all entries with page break(s) inside entries_with_page_break.each do |entry| begin + # Split the string of content by the page break(s) + xml_content_parts = parse_entry_with_page_breaks(entry.to_s) + + xml_content_first_part = xml_content_parts.shift.gsub('xml:lang="sc"', 'xml:lang="sco"').gsub('xml:lang="la"', 'xml:lang="lat"').gsub('xml:lang="nl"', 'xml:lang="nld"') + entry_obj = Nokogiri::XML(xml_content_first_part) + xml_to_html(entry_obj) + html_content_first_part = entry_obj.to_xml + + # Get the problematic entry + old_entry_id = entry.xpath('@xml:id').to_s + volume, page, paragraph = splitEntryID(old_entry_id) + old_search = Search.find_by(entry: old_entry_id, page: page) + + pr = old_search.tr_paragraph + # Store the updated content for the paragraph record + pr.content_xml = xml_content_first_part + pr.content_html = html_content_first_part + pr.save + + # Now iterate the other entries, creating records for them: + current_page = page + + xml_content_parts.each do |part| + # if part is a page number, set the current page number + if part =~ /]*\/>/ + current_page = number_from_page_element(part) + next + end - # Split the string of content by the page break - xmlContentFirstPart, xmlContentSecondPart = entry.to_s.split(/<.*pb.*\/>/) - xmlContentFirstPart = xmlContentFirstPart.gsub('xml:lang="sc"', 'xml:lang="sco"').gsub('xml:lang="la"', 'xml:lang="lat"').gsub('xml:lang="nl"', 'xml:lang="nld"') - xmlContentSecondPart = xmlContentSecondPart.gsub('xml:lang="sc"', 'xml:lang="sco"').gsub('xml:lang="la"', 'xml:lang="lat"').gsub('xml:lang="nl"', 'xml:lang="nld"') - - htmlContentFirstPart = Nokogiri::XML("

#{xmlContentFirstPart}

") - htmlContentSecondPart = Nokogiri::XML("

#{xmlContentSecondPart}

") - - # Get the id of the problematic entry - oldEntryId = entry.xpath('@xml:id').to_s - - # Split the id into page, paragraph, volume - volume, page, paragraph = splitEntryID(oldEntryId) - newPage = page + 1 - - # - # Insert the extracted content in the new paragraph - # - - # if the new paragraph is not created - # This is false when: - # -> There is inconcistency the first paragraph of the page - # has started in the previous entry - # -> The document is overwritten - # - if Search.exists?(page: newPage, volume: volume, paragraph: 1) - # Get existing paragraph - s = Search.find_by(page: newPage, volume: volume, paragraph: 1) - # Get paragraph record - pr = s.tr_paragraph - # Store the updated content for the paragraph record - pr.content_xml = xmlContentSecondPart - pr.content_html = htmlContentSecondPart.to_xml+""+ pr.content_html - pr.save + # if part is a block, create a Search object for that block using + # the existing ID but the new page number. + xml_part = part.gsub('xml:lang="sc"', 'xml:lang="sco"').gsub('xml:lang="la"', 'xml:lang="lat"').gsub('xml:lang="nl"', 'xml:lang="nld"') + entry_obj = Nokogiri::XML('
' + xml_part) + xml_to_html(entry_obj) + html_part = entry_obj.to_xml + pr = TrParagraph.create(content_xml: xml_part, content_html: html_part) + s = Search.create( + tr_paragraph: pr, + entry: old_entry_id, + volume: volume, + page: current_page, + paragraph: 1, + transcription_xml: old_search.transcription_xml, + lang: old_search.lang, + date: old_search.date, + date_incorrect: old_search.date_incorrect, + # date_not_after: old_search.date_not_after, + content: Nokogiri::XML("

#{part.gsub('', "\n")}

").xpath('normalize-space()'), + ) + end + rescue StandardError => e + logger.error(e) + end + end - else + # Clean up unneeded empty pages + Search.where(entry: nil).each do |empty| + empty.delete unless Search.where(volume: empty.volume, page: empty.page, paragraph: empty.paragraph).count == 1 + end + end - # Create new search record - s = Search.new + def parse_entry_with_page_breaks(entry_str) + parts = entry_str.match(/(.*)(]*\/>)(.*)/im) - # Create TrParagraph record - pr = TrParagraph.new - pr.content_xml = xmlContentSecondPart - pr.content_html = htmlContentSecondPart.to_xml - pr.save + # parts[1] # The start block + # parts[2] # the last page number + # parts[3] # the block after the last page number - end + return [entry_str] unless parts - textContentFirstPart =(Nokogiri::XML("

"+xmlContentFirstPart.gsub('', "\n")+"

")).xpath('normalize-space()') - textContentSecondPart =(Nokogiri::XML("

"+xmlContentSecondPart.gsub('', "\n")+"

")).xpath('normalize-space()') - - # Find the original record - previousEntry = Search.find_by(volume: volume,page: page,paragraph: paragraph) - - # Create Search record - s.tr_paragraph = pr - s.entry = previousEntry.entry - s.volume = volume - s.page = newPage - s.paragraph = 1 - s.transcription_xml = self - s.lang = previousEntry.lang - s.date = previousEntry.date - s.date_incorrect = previousEntry.date_incorrect - # Replace line-break tag with \n and normalize whitespace - s.content = "#{textContentSecondPart}\n#{s.content}" - s.save - - previousEntry.content = textContentFirstPart - # Get paragraph record - prPreviusEntry = previousEntry.tr_paragraph - # Remove duplicated content from entry which contains the page break - prPreviusEntry.content_xml = xmlContentFirstPart - prPreviusEntry.content_html = htmlContentFirstPart.to_xml - prPreviusEntry.save - # Save the change - previousEntry.tr_paragraph = prPreviusEntry - previousEntry.save - rescue Exception => e - logger.error(e) + parse_entry_with_page_breaks(parts[1]) + [parts[2], parts[3]] + end + + def number_from_page_element(page_str) + regex = /n="(.*)"/ + page_str.match(regex)[1].to_i + end + + def parse_date_from_entry(entry) + # Get date from when, failing that, from notBefore + d = entry.xpath('ancestor::xmlns:div[1]//xmlns:date/@when', 'xmlns' => HISTEI_NS) + d = entry.xpath('ancestor::xmlns:div[1]//xmlns:date/@notBefore', 'xmlns' => HISTEI_NS) if d.count.zero? + + # if date is an array, crunch to 1 string + if d.count > 1 + date_str = '' + d.each do |entry_date| + entry_date_str = entry_date.to_s + date_str = entry_date_str if date_str.length < entry_date_str.length end + else + date_str = d.to_s end + # Get notAfter, if one exists + d = entry.xpath('ancestor::xmlns:div[1]//xmlns:date/@notAfter', 'xmlns' => HISTEI_NS) + date_not_after_str = d.count == 1 ? d.to_s : nil + + # Go to the closest parent "div" of the entry and find a child "date" + # and extract the 'when' argument + # date_from = entry.xpath("ancestor::xmlns:div[1]//xmlns:date/@from", 'xmlns' => HISTEI_NS).to_s + # date_to = entry.xpath("ancestor::xmlns:div[1]//xmlns:date/@to", 'xmlns' => HISTEI_NS).to_s + + if date_format_correct?(date_str) + entry_date_incorrect = nil + else + if [1, 2, 3].include?(date_str.split('-').length) + entry_date_incorrect = date_str + else + date_from = entry.xpath("ancestor::xmlns:div[1]//xmlns:date/@from", 'xmlns' => HISTEI_NS).to_s + date_to = entry.xpath("ancestor::xmlns:div[1]//xmlns:date/@to", 'xmlns' => HISTEI_NS).to_s + entry_date_incorrect = date_from.length != 0 ? "#{date_from}-#{date_to}": 'N/A' + entry_date = nil # The date is missing + end + end + + entry_date = correct_date(date_str) + entry_date_not_after = date_not_after_str ? correct_date(date_not_after_str) : nil + + { + entry_date: entry_date, + entry_date_not_after: entry_date_not_after, + entry_date_incorrect: entry_date_incorrect + } + end + + def date_format_correct?(date_str) + date_str.split('-').length == 3 + end + + def correct_date(date_str) + if date_str.split('-').length == 3 + date_str.to_date + elsif date_str.split('-').length == 2 + "#{date_str}-1".to_date # If the day is missing set ot 1-st + elsif date_str.split('-').length == 1 + "#{date_str}-1-1".to_date # If the day and month are missing set ot 1-st Jan. + end end end diff --git a/src/app/views/documents/_page.html.erb b/src/app/views/documents/_page.html.erb index 1ca2756..6008251 100755 --- a/src/app/views/documents/_page.html.erb +++ b/src/app/views/documents/_page.html.erb @@ -1,5 +1,5 @@ -
+
<% @documents.each do |document| %>
@@ -11,15 +11,15 @@ <%end%> <%if document.date or document.date_incorrect %> -
- Date: <% if document.date_incorrect %><%= document.date_incorrect %><% else %><%= document.date %><% end %> +
+ <%= date_block(document).html_safe %>
<%end%> <%if document.lang %> -
+
Language: <%= document.lang %> -
+
<%end%>
@@ -40,11 +40,29 @@ -<% if @document_image_normal %> +<% if @document_images.any? %>
- - <%= image_tag(@document_image_normal, class:"img-rounded img-responsive", data: {large_image: @document_image_large}) %> - + <% if @document_images.count > 1 %> +
+
+ Multiple images available: +
+
+ +
+
+ <% end %> +
+ + <% @document_images.each do |img| %> + <%= image_tag(img[:normal], class:"img-rounded img-responsive", id: img[:id], data: {large_image: img[:large]}) %> + <% end %> + +
<% end %> diff --git a/src/app/views/documents/_page_simplified.html.erb b/src/app/views/documents/_page_simplified.html.erb index 0292f1a..1ecadd2 100755 --- a/src/app/views/documents/_page_simplified.html.erb +++ b/src/app/views/documents/_page_simplified.html.erb @@ -10,15 +10,15 @@ <%end%> <%if document.date or document.date_incorrect %> -
- Date: <% if document.date_incorrect %><%= document.date_incorrect %><% else %><%= document.date %><% end %> +
+ <%= date_block(document).html_safe %>
<%end%> <%if document.lang %> -
+
Language: <%= document.lang %> -
+
<%end%>
diff --git a/src/app/views/documents/index.html.erb b/src/app/views/documents/index.html.erb index 8e91aac..2299663 100755 --- a/src/app/views/documents/index.html.erb +++ b/src/app/views/documents/index.html.erb @@ -1,19 +1,5 @@
-
- - -
- <% if user_signed_in? and current_user.admin? %>
diff --git a/src/app/views/layouts/menu/_registration_items.html.erb b/src/app/views/layouts/menu/_registration_items.html.erb deleted file mode 100755 index 31a51d2..0000000 --- a/src/app/views/layouts/menu/_registration_items.html.erb +++ /dev/null @@ -1,5 +0,0 @@ -<% if user_signed_in? %> -
  • <%= link_to('Edit registration', edit_user_registration_path) %>
  • -<% else %> -
  • <%= link_to('Register', new_user_registration_path) %>
  • -<% end %> diff --git a/src/app/views/search/_search_tools.html.erb b/src/app/views/search/_search_tools.html.erb index f8a9f8f..fdc2242 100755 --- a/src/app/views/search/_search_tools.html.erb +++ b/src/app/views/search/_search_tools.html.erb @@ -51,7 +51,7 @@
    Keywords -
  • -
  • -
  • -
  • -
  • - +
    +
      +
    • +
    • +
    • +
    • +
    • +
    • +
    +
    @@ -37,11 +39,17 @@
    -
    - +
    +
    -
    -
    +
    +
    @@ -50,12 +58,19 @@
    - <% @volumes.each do |v| %> - - <% end %> +
      +
    • +
    • +
        + <% @volumes.each do |v| %> +
      • + <% end %> +
      +
    • +
    @@ -82,13 +97,13 @@
    from - <%= search_field_tag('date_from','', placeholder: "yyyy-mm-dd", describedby: "date_from-label", class: "form-control datepicker") %> + <%= search_field_tag('date_from','', placeholder: "dd/mm/yyyy", describedby: "date_from-label", class: "form-control datepicker") %>
    to - <%= search_field_tag('date_to','', placeholder: "yyyy-mm-dd ", describedby: "date_to-label", class: "form-control datepicker") %> + <%= search_field_tag('date_to','', placeholder: "dd/mm/yyyy", describedby: "date_to-label", class: "form-control datepicker") %>
    diff --git a/src/app/views/search/search.html.erb b/src/app/views/search/search.html.erb index 7d27f8b..c34c68f 100755 --- a/src/app/views/search/search.html.erb +++ b/src/app/views/search/search.html.erb @@ -2,25 +2,21 @@ <%= render '/search/search_tools' %> <% begin defined? @documents.suggestions %>
    - <% if @documents.try(:suggestions).length > 0 %> -
    +
    + <%= search_result_header %> +
    +
    + <% if @documents.try(:suggestions).length > 0 %> +
    +
    -
    - <%= @documents.total_count %> <%if @documents.total_count == 1 %>result<% else %>results<%end%> (<%= @documents.took / 1000.0 %> sec) - -
    - <%else%> -
    - <%= @documents.total_count %> <%if @documents.total_count == 1 %>result<% else %>results<%end%> (<%= @documents.took / 1000.0 %> sec) - -
    - <%end%>
    + <% end %> <%rescue%> <%end%> <% if @documents.length > 0 %> @@ -29,21 +25,18 @@
    -
    + @@ -77,7 +70,7 @@
    -
    @@ -96,10 +89,6 @@ <% if @documents.length > 0 %> <% content_for :javascript_includes do %> - <%= javascript_include_tag "search.js" %> - <%end%> <%end%> diff --git a/src/app/views/xquery/index.html.erb b/src/app/views/xquery/index.html.erb index f05175e..88b9a6e 100755 --- a/src/app/views/xquery/index.html.erb +++ b/src/app/views/xquery/index.html.erb @@ -39,13 +39,13 @@

    Search through time period by using regular expressions

    for $i in //ns:div[@xml:lang="lat"]
    where $i/ancestor::ns:div//ns:date[@when >"1501-1-1"][@when <"1502-12-31"]
    return $i
      -
    • Simmilar to Specify a year in query where the results are filtered by only a specific date in this instance the date is filtered using date range from 1501-1-1 until 1501-12-31. +
    • Similar to Specify a year in query where the results are filtered by only a specific date in this instance the date is filtered using date range from 1501-1-1 until 1501-12-31.
    -

    Count number of in prticular language words

    +

    Count number of words in a particular language

    XQuery expression which counts the number of words in Scots and Latin

    for $lang in ("lat", "sco")
     return (
    diff --git a/src/config/environments/development.rb b/src/config/environments/development.rb
    index bfae29c..424c5ce 100755
    --- a/src/config/environments/development.rb
    +++ b/src/config/environments/development.rb
    @@ -55,18 +55,14 @@
       config.file_watcher = ActiveSupport::EventedFileUpdateChecker
     
       # mailer config
    -  config.action_mailer.default_url_options = { host: 'lacr-demo.abdn.ac.uk'}
    +  config.action_mailer.default_url_options = { host: 'sar.abdn.ac.uk' }
       # Disable delivery errors, bad email addresses will be ignored
       config.action_mailer.raise_delivery_errors = true
       config.action_mailer.perform_deliveries = true
    -  config.action_mailer.default :charset => "utf-8"
    +  config.action_mailer.default charset: 'utf-8'
       config.action_mailer.delivery_method = :smtp
       ActionMailer::Base.smtp_settings = {
    -    :address => "smtp.gmail.com",
    -    :port => 587,
    -    :domain => "gmail.com",
    -    :authentication => :login,
    -    :user_name => "lacrdemo@gmail.com",
    -    :password => "lacrapp987"
    +    address: 'mailhost.abdn.ac.uk',
    +    port: 25
       }
     end
    diff --git a/src/config/environments/production.rb b/src/config/environments/production.rb
    index 6611db0..93d4d87 100755
    --- a/src/config/environments/production.rb
    +++ b/src/config/environments/production.rb
    @@ -24,9 +24,9 @@
     
       # Do not fallback to assets pipeline if a precompiled asset is missed.
       # config.assets.compile = false
    -  
    +
       config.assets.compile = true
    -  config.assets.precompile =  ['*.js', '*.css', '*.css.erb'] 
    +  config.assets.precompile =  ['*.js', '*.css', '*.css.erb']
     
       # `config.assets.precompile` and `config.assets.version` have moved to config/initializers/assets.rb
     
    @@ -95,18 +95,14 @@
       end
     
       # mailer config
    -  config.action_mailer.default_url_options = { host: 'lacr-demo.abdn.ac.uk'}
    +  config.action_mailer.default_url_options = { host: 'sar.abdn.ac.uk' }
       # Disable delivery errors, bad email addresses will be ignored
       config.action_mailer.raise_delivery_errors = true
       config.action_mailer.perform_deliveries = true
    -  config.action_mailer.default :charset => "utf-8"
    +  config.action_mailer.default charset: 'utf-8'
       config.action_mailer.delivery_method = :smtp
       ActionMailer::Base.smtp_settings = {
    -    :address => "smtp.gmail.com",
    -    :port => 587,
    -    :domain => "gmail.com",
    -    :authentication => :login,
    -    :user_name => "lacrdemo@gmail.com",
    -    :password => "lacrapp987"
    +    address: 'mailhost.abdn.ac.uk',
    +    port: 25
       }
     end
    diff --git a/src/config/initializers/basex.rb b/src/config/initializers/basex.rb
    index 6f27e82..0d8d917 100755
    --- a/src/config/initializers/basex.rb
    +++ b/src/config/initializers/basex.rb
    @@ -8,9 +8,9 @@
     ENV['BASEX_URL'] = 'xmldb'
     
     # Generate radnom passowords
    -password_length = 64
    -ENV['BASEX_READONLY'] = rand(36**password_length).to_s(36)
    -ENV['BASEX_CREATEONLY'] = rand(36**password_length).to_s(36)
    +# password_length = 64
    +# ENV['BASEX_READONLY'] = rand(36**password_length).to_s(36)
    +# ENV['BASEX_CREATEONLY'] = rand(36**password_length).to_s(36)
     
     # Change default admin password
     begin
    diff --git a/src/config/initializers/devise.rb b/src/config/initializers/devise.rb
    index 1c97f6c..22aa1ed 100755
    --- a/src/config/initializers/devise.rb
    +++ b/src/config/initializers/devise.rb
    @@ -12,7 +12,7 @@
       # Configure the e-mail address which will be shown in Devise::Mailer,
       # note that it will be overwritten if you use your own mailer class
       # with default "from" parameter.
    -  config.mailer_sender = 'please-change-me-at-config-initializers-devise@example.com'
    +  config.mailer_sender = 'noreply@abdn.ac.uk'
     
       # Configure the class responsible to send e-mails.
       # config.mailer = 'Devise::Mailer'
    diff --git a/src/db/migrate/20190423100655_add_date_certainty_to_searches.rb b/src/db/migrate/20190423100655_add_date_certainty_to_searches.rb
    new file mode 100755
    index 0000000..7d265bd
    --- /dev/null
    +++ b/src/db/migrate/20190423100655_add_date_certainty_to_searches.rb
    @@ -0,0 +1,5 @@
    +class AddDateCertaintyToSearches < ActiveRecord::Migration[5.2]
    +  def change
    +    add_column :searches, :date_certainty, :string, default: 'high'
    +  end
    +end
    diff --git a/src/db/migrate/20190423114857_add_date_not_after_to_searches.rb b/src/db/migrate/20190423114857_add_date_not_after_to_searches.rb
    new file mode 100755
    index 0000000..3773395
    --- /dev/null
    +++ b/src/db/migrate/20190423114857_add_date_not_after_to_searches.rb
    @@ -0,0 +1,5 @@
    +class AddDateNotAfterToSearches < ActiveRecord::Migration[5.2]
    +  def change
    +    add_column :searches, :date_not_after, :date
    +  end
    +end
    diff --git a/src/db/schema.rb b/src/db/schema.rb
    index e469d6e..2ebd4ab 100755
    --- a/src/db/schema.rb
    +++ b/src/db/schema.rb
    @@ -10,8 +10,7 @@
     #
     # It's strongly recommended that you check this file into your version control system.
     
    -ActiveRecord::Schema.define(version: 2017_02_13_221951) do
    -
    +ActiveRecord::Schema.define(version: 2019_04_23_114857) do
       # These are extensions that must be enabled in order to support this database
       enable_extension "plpgsql"
     
    @@ -36,6 +35,8 @@
         t.string "date_incorrect"
         t.datetime "created_at", null: false
         t.datetime "updated_at", null: false
    +    t.string "date_certainty", default: "high"
    +    t.date "date_not_after"
         t.index ["page"], name: "index_searches_on_page"
         t.index ["paragraph"], name: "index_searches_on_paragraph"
         t.index ["volume"], name: "index_searches_on_volume"
    diff --git a/src/lib/assets/stylesheets/annotation.css b/src/lib/assets/stylesheets/annotation.scss
    similarity index 97%
    rename from src/lib/assets/stylesheets/annotation.css
    rename to src/lib/assets/stylesheets/annotation.scss
    index cac8aec..53e6b13 100755
    --- a/src/lib/assets/stylesheets/annotation.css
    +++ b/src/lib/assets/stylesheets/annotation.scss
    @@ -51,9 +51,25 @@
         background-color: rgba(128, 0, 255, 0.7);
     }
     
    -.choice > .sic{
    +.sic {
       color: gray;
       font-style: italic;
    +  &:hover {
    +    &:after {
    +      content: '[sic]';
    +      vertical-align: sub;
    +      font-size: small;
    +    }
    +  }
    +}
    +
    +.choice > .sic{
    +  &:hover {
    +    &:after {
    +      content: '';
    +      padding-left: 0;
    +    }
    +  }
     }
     
     .choice > .corr{
    @@ -272,10 +288,27 @@
         text-decoration: line-through;
     }
     
    +.space {
    +  &:before {
    +    color:orange;
    +    content: "[...]";
    +    font-style: italic;
    +    padding-right: 0;
    +  }
    +  &:hover:before {
    +    font-size: small;
    +    font-style: normal;
    +    color: black;
    +    vertical-align: sub;
    +    content: 'space';
    +  }
    +}
    +
     .gap::before {
         color:orange;
         content: "[...]";
         font-style: italic;
    +    padding-right: 0;
     }
     
     .unclear {
    diff --git a/src/lib/tasks/diagnostics.rake b/src/lib/tasks/diagnostics.rake
    new file mode 100644
    index 0000000..1ce8dec
    --- /dev/null
    +++ b/src/lib/tasks/diagnostics.rake
    @@ -0,0 +1,50 @@
    +begin
    +  namespace :diagnostics do
    +    desc 'Run all diagnostic tasks'
    +    task all: [:environment] do
    +      diagnostics_images
    +      diagnostics_entries
    +    end
    +
    +    desc 'Check for missing images for pages'
    +    task images: [:environment] do
    +      diagnostics_images
    +    end
    +
    +    desc 'Check for multiple identical entries on one page'
    +    task entries: [:environment] do
    +      diagnostics_entries
    +    end
    +  end
    +end
    +
    +def diagnostics_images
    +  puts('Checking images')
    +  volumes = Search.all.collect(&:volume).uniq.sort
    +  volumes.each do |volume|
    +    pages = Search.where(volume: volume).collect(&:page).uniq.sort
    +    pages.each do |page|
    +      next if PageImage.where(volume: volume, page: page).any?
    +
    +      puts("Volume #{volume} - missing image for page #{page}")
    +    end
    +  end
    +end
    +
    +def diagnostics_entries
    +  puts('Checking entries')
    +  entries = Search.where('entry IS NOT NULL').all.collect(&:entry).uniq.sort
    +  entries.each do |entry|
    +    related_searches = Search.where(entry: entry)
    +    problems = []
    +    related_searches.each do |rs|
    +      next if Search.where(entry: rs.entry, page: rs.page).count == 1
    +
    +      problems << rs.page
    +    end
    +    problems = problems.uniq
    +    next unless problems.any?
    +
    +    puts("Entry: #{entry} appears multiple times on page(s) #{problems}")
    +  end
    +end
    diff --git a/src/lib/tasks/imports.rake b/src/lib/tasks/imports.rake
    new file mode 100644
    index 0000000..9afedcf
    --- /dev/null
    +++ b/src/lib/tasks/imports.rake
    @@ -0,0 +1,95 @@
    +begin
    +  namespace :import do
    +    desc 'Imports all xml files and images in the uploads directory'
    +    task :uploads, [:uploads_location] => [:environment] do |_t, args|
    +      args.with_defaults(uploads_location: '/lacr-search/public/uploads')
    +
    +      directory = args[:uploads_location]
    +
    +      import_xml_from(directory)
    +      import_images_from(directory)
    +    end
    +
    +    desc 'Imports all xml files in the uploads directory'
    +    task :xml_uploads, [:uploads_location] => [:environment] do |_t, args|
    +      args.with_defaults(uploads_location: '/lacr-search/public/uploads')
    +
    +      directory = args[:uploads_location]
    +
    +      import_xml_from(directory)
    +    end
    +
    +    desc 'Imports all images in the uploads directory'
    +    task :image_uploads, [:uploads_location] => [:environment] do |_t, args|
    +      args.with_defaults(uploads_location: '/lacr-search/public/uploads')
    +
    +      directory = args[:uploads_location]
    +
    +      import_images_from(directory)
    +    end
    +  end
    +end
    +
    +def import_xml_from(directory)
    +  xml_files_content = []
    +  xml_dir = Dir.new(File.join(directory, 'xml'))
    +  xml_dir.entries.reject { |f| ['.', '..'].include?(f) }.each do |filename|
    +    file_path = File.join(xml_dir.path, filename)
    +    file_content = []
    +
    +    puts("Importing XML #{filename}")
    +
    +    # Create the TranscriptionXml Object
    +    nokogiri_obj = Nokogiri::XML(File.open(file_path))
    +    if nokogiri_obj.collect_namespaces.values.include? TranscriptionXml::HISTEI_NS
    +      t = TranscriptionXml.find_or_create_by(filename: filename)
    +      # Store the information about the uploaded file
    +      t.xml = File.new(file_path)
    +      # If the save was successful
    +
    +      if t.save!
    +        # Store file content and filename for import to BaseX
    +        xml_files_content.push([filename, nokogiri_obj.to_xml.gsub('xml:lang="sc"', 'xml:lang="sco"').gsub('xml:lang="la"', 'xml:lang="lat"').gsub('xml:lang="nl"', 'xml:lang="nld"')])
    +        # Proccess the XML file
    +        t.histei_split_to_paragraphs
    +      end
    +    end
    +  end
    +
    +  # Upload xml content to BaseX
    +  begin
    +    session = BaseXClient::Session.new(ENV['BASEX_URL'], 1984, "createOnly", ENV['BASEX_CREATEONLY'])
    +    session.execute('open xmldb') # Open XML database
    +    xml_files_content.each do |file_name, file_content|
    +      begin
    +        session.replace(file_name, file_content)
    +      rescue StandardError => e
    +        logger.error(e)
    +      end
    +    end
    +    session.close
    +  rescue StandardError => e
    +    logger.error(e)
    +  end
    +
    +  # Generate new index for Elasticsearch
    +  Search.reindex
    +end
    +
    +def import_images_from(directory)
    +  image_dir = Dir.new(File.join(directory, 'image'))
    +  image_dir.entries.select { |f| is_valid_image?(f) }.each do |filename|
    +    file_path = File.join(image_dir.path, filename)
    +    puts("Importing Image: #{filename}")
    +    t = PageImage.new
    +    t.image = File.new(file_path)
    +    t.parse_filename_to_volume_page filename
    +    t.save!
    +  end
    +end
    +
    +def is_valid_image?(f)
    +  return false if ['.', '..'].include?(f)
    +
    +  f.downcase.ends_with?('.tiff') || f.downcase.ends_with?('.tif')
    +end