diff --git a/lib/controllers/base_controller.rb b/lib/controllers/base_controller.rb index 933058a5..e1a4fd3e 100644 --- a/lib/controllers/base_controller.rb +++ b/lib/controllers/base_controller.rb @@ -50,5 +50,20 @@ def prevent_unauthorized_modifications redirect back end end + + def javascript_imports + imports = + { + imports: { + "@hotwired/turbo": "https://cdn.jsdelivr.net/npm/@hotwired/turbo@8.0.5/+esm", + "@hotwired/stimulus": "https://cdn.jsdelivr.net/npm/@hotwired/stimulus@3.2.2/+esm", + "controllers/page_navigation_controller": "/javascripts/controllers/page_navigation_controller.js", + "controllers/search_navigation_controller": "/javascripts/controllers/search_navigation_controller.js", + "application": "/javascripts/application.js" + } + } + + JSON.pretty_generate(imports) + end end end diff --git a/lib/controllers/page_controller.rb b/lib/controllers/page_controller.rb index cac5b80a..a36c0e55 100644 --- a/lib/controllers/page_controller.rb +++ b/lib/controllers/page_controller.rb @@ -54,10 +54,10 @@ def restrict_concealed(page) case @pages.count when 0 flash[:notice] = "Din sökning gav inga träffar" - redirect request.referrer + redirect request.referrer, 303 when 1 flash[:confirm] = "Din sökning gav bara denna sida som träff" - redirect @pages.first.slug + redirect @pages.first.slug, 303 else flash.now[:confirm] = "Din sökning gav #{@pages.count} träffar" haml :search diff --git a/public/javascripts/application.js b/public/javascripts/application.js new file mode 100644 index 00000000..e617f594 --- /dev/null +++ b/public/javascripts/application.js @@ -0,0 +1,9 @@ +import { Application } from "@hotwired/stimulus" +import "@hotwired/turbo" + +import PageNavigationController from "controllers/page_navigation_controller" +import SearchNavigationController from "controllers/search_navigation_controller" + +window.Stimulus = Application.start() +Stimulus.register("page-navigation", PageNavigationController) +Stimulus.register("search-navigation", SearchNavigationController) diff --git a/public/javascripts/controllers/page_navigation_controller.js b/public/javascripts/controllers/page_navigation_controller.js new file mode 100644 index 00000000..12c3d6bb --- /dev/null +++ b/public/javascripts/controllers/page_navigation_controller.js @@ -0,0 +1,59 @@ +import {Controller} from "@hotwired/stimulus" +import * as Turbo from "@hotwired/turbo" + +export default class extends Controller { + home(event) { + if (this.#isInputField(event.target)) { + Turbo.visit("/") + } + } + + list(event) { + if (this.#isInputField(event.target)) { + Turbo.visit("/list") + } + } + + latest(event) { + if (this.#isInputField(event.target)) { + Turbo.visit("/latest") + } + } + + new(event) { + if (this.#isInputField(event.target)) { + Turbo.visit("/new") + } + } + + edit(event) { + if (this.#isInputField(event.target)) { + let editPageLink = document.querySelector("#edit_page") + if (editPageLink) { + Turbo.visit(editPageLink.href) + } + } + } + + focusSearch(event) { + if (this.#isInputField(event.target)) { + let searchInput = document.getElementById('q') + searchInput.focus() + searchInput.select() + event.preventDefault() + } + } + + blurSearch(event) { + let searchInput = document.getElementById('q'); + if (event.target === searchInput) { + searchInput.blur(); + } + event.preventDefault() + } + + #isInputField(target) { + let targetTag = target.tagName.toLowerCase() + return targetTag !== 'input' && targetTag !== 'textarea' && targetTag !== 'select' + } +} diff --git a/public/javascripts/controllers/search_navigation_controller.js b/public/javascripts/controllers/search_navigation_controller.js new file mode 100644 index 00000000..4963b299 --- /dev/null +++ b/public/javascripts/controllers/search_navigation_controller.js @@ -0,0 +1,75 @@ +import {Controller} from "@hotwired/stimulus" +import * as Turbo from "@hotwired/turbo" + +export default class extends Controller { + connect() { + let selectedLink = this.#getSelectedElement(); + if (!selectedLink) { + let pageLinks = document.getElementsByClassName('page-link'); + if (pageLinks && pageLinks.length > 0) { + this.#selectElement(pageLinks[0]); + } + } + } + + down() { + let selectedLink = this.#getSelectedElement(); + if (selectedLink) { + let pageLinks = document.getElementsByClassName('page-link'); + + for (let i = 0; i < pageLinks.length; i++) { + let page = pageLinks[i]; + if (page === selectedLink && i < (pageLinks.length - 1)) { + this.#selectElement(pageLinks[i + 1]) + this.#deselectElement(pageLinks[i]); + break; + } + } + return false; + } + } + + up() { + let selectedLink = this.#getSelectedElement(); + if (selectedLink) { + let pageLinks = document.getElementsByClassName('page-link'); + + for (let i = 0; i < pageLinks.length; i++) { + let page = pageLinks[i]; + if (page === selectedLink && i > 0) { + this.#selectElement(pageLinks[i - 1]) + this.#deselectElement(pageLinks[i]); + break; + } + } + return false; + } + } + + open() { + let selectedLink = this.#getSelectedElement(); + if (selectedLink) { + selectedLink.click() + return false; + } + } + + #getSelectedElement() { + return document.getElementById('navigation-selected'); + } + + #selectElement(element) { + element.id = "navigation-selected"; + return true; + } + + #deselectElement(element) { + element.id = ""; + return true; + } + + #isInputField(target) { + let targetTag = target.tagName.toLowerCase() + return targetTag !== 'input' && targetTag !== 'textarea' && targetTag !== 'select' + } +} diff --git a/public/javascripts/mousetrap-global-bind.min.js b/public/javascripts/mousetrap-global-bind.min.js deleted file mode 100755 index 636b25e0..00000000 --- a/public/javascripts/mousetrap-global-bind.min.js +++ /dev/null @@ -1 +0,0 @@ -Mousetrap=function(a){var d={},e=a.stopCallback;a.stopCallback=function(b,c,a){return d[a]?!1:e(b,c,a)};a.bindGlobal=function(b,c,e){a.bind(b,c,e);if(b instanceof Array)for(c=0;cg||h.hasOwnProperty(g)&&(p[h[g]]=g)}e=p[d]?"keydown":"keypress"}"keypress"==e&&f.length&&(e="keydown");return{key:c,modifiers:f,action:e}}function F(a,b,d,c,e){q[a+":"+d]=b;a=a.replace(/\s+/g," ");var f=a.split(" ");1":".","?":"/","|":"\\"},G={option:"alt",command:"meta","return":"enter",escape:"esc",mod:/Mac|iPod|iPhone|iPad/.test(navigator.platform)?"meta":"ctrl"},p,l={},q={},n={},D,z=!1,I=!1,u=!1;for(f=1;20>f;++f)h[111+f]="f"+f;for(f=0;9>=f;++f)h[f+96]=f;s(r,"keypress",y);s(r,"keydown",y);s(r,"keyup",y);var m={bind:function(a,b,d){a=a instanceof Array?a:[a];for(var c=0;cpage-navigation#home | + keydown.i->page-navigation#list | + keydown.l->page-navigation#latest | + keydown.n->page-navigation#new | + keydown.e->page-navigation#edit | + keydown.s->page-navigation#focusSearch | + keydown.esc->page-navigation#blurSearch | + keydown.down->search-navigation#down | + keydown.j->search-navigation#down | + keydown.up->search-navigation#up | + keydown.k->search-navigation#up | + keydown.o->search-navigation#open | + keydown.enter->search-navigation#open" + }} %div{ id: @edit_mode ? 'container-lg' : 'container' } #header #login @@ -33,39 +50,3 @@ !=yield #footer != haml :'../layouts/_footer', layout: false - - :javascript - Mousetrap.bind(['/', 's'], function() { - var searchInput = document.getElementById('q'); - searchInput.focus(); - searchInput.select(); - return false; - }); - - Mousetrap.bind('h', function() { - window.location = "/"; - return false; - }); - - Mousetrap.bind('i', function() { - window.location = "/list"; - return false; - }); - - Mousetrap.bind('l', function() { - window.location = "/latest"; - return false; - }); - - Mousetrap.bind('n', function() { - window.location = "/new"; - return false; - }); - - Mousetrap.bindGlobal('escape', function() { - var searchInput = document.getElementById('q'); - if (document.activeElement == searchInput) { - searchInput.blur(); - } - return false; - }); diff --git a/views/page/_actions.haml b/views/page/_actions.haml index f77bb3a2..82c631f3 100644 --- a/views/page/_actions.haml +++ b/views/page/_actions.haml @@ -2,7 +2,7 @@ %ul - if logged_in? %li - %a{ href: "/#{@page.slug}/edit" } Ändra + %a{ href: "/#{@page.slug}/edit", id: "edit_page" } Ändra - if starkast? %form{ action: "/#{@page.slug}/conceal", method: :post } %button diff --git a/views/page/search.haml b/views/page/search.haml index 0ced90c7..a1f1f26b 100644 --- a/views/page/search.haml +++ b/views/page/search.haml @@ -6,53 +6,3 @@ - if page.concealed 🔐 %span.description= page.description - -:javascript - (function(){ - function getSelectedElement() { - return document.getElementById('navigation-selected'); - } - function selectElement(element) { - element.id = "navigation-selected"; - return true; - } - function deselectElement(element) { - element.id = ""; - return true; - } - - var pageLinks = document.getElementsByClassName('page-link'); - selectElement(pageLinks[0]); - - Mousetrap.bind(['o', 'enter'], function() { - getSelectedElement().click(); - return false; - }); - - Mousetrap.bind(['j', 'down'], function() { - var selectedLink = getSelectedElement(); - for (var i = 0; i < pageLinks.length; i++) { - var page = pageLinks[i]; - if (page == selectedLink && i < (pageLinks.length - 1)) { - selectElement(pageLinks[i + 1]) - deselectElement(pageLinks[i]); - break; - } - } - return false; - }); - - Mousetrap.bind(['k', 'up'], function() { - var selectedLink = getSelectedElement(); - for (var i = 0; i < pageLinks.length; i++) { - var page = pageLinks[i]; - if (page == selectedLink && i > 0) { - selectElement(pageLinks[i - 1]) - deselectElement(pageLinks[i]); - break; - } - } - return false; - }); - })(); - diff --git a/views/page/show.haml b/views/page/show.haml index 1b636110..8da4d760 100644 --- a/views/page/show.haml +++ b/views/page/show.haml @@ -1,9 +1,3 @@ %h1.title= @page.title !~ @page.compiled_content - -:javascript - Mousetrap.bind('e', function() { - window.location = "#{@page.slug}/edit"; - return false; - });