added dictionary feature

This commit is contained in:
Adrian Hinz 2022-06-29 11:54:48 +02:00
parent a86b2b8995
commit abbb95ecb7
23 changed files with 368 additions and 8 deletions

View File

@ -15,11 +15,11 @@
//= require turbolinks
function reloadFunctionsOnAjax() {
$(".tooltip").tooltip("hide");
//$('.popover').popover('hide');
$('.popover').popover('hide');
// Reload tootltips
$('[data-toggle="tooltip"]').tooltip({ trigger : 'hover' })
// Reload popovers
//$('[data-toggle="popover"]').popover()
$('[data-toggle="popover"]').popover()
}

View File

@ -109,3 +109,9 @@
.text-navy-new:hover {
color: #0a3a7e;
}
.dictionary-word {
text-decoration: underline;
-webkit-text-decoration-color: blue; /* Safari */
text-decoration-color: blue;
}

View File

@ -0,0 +1,77 @@
# frozen_string_literal: true
# Dictionary class
class DictionariesController < ApplicationController
before_action :authenticate_user!
include ApplicationHelper
before_action :check_access
before_action :set_dictionary, only: %i[show edit update destroy]
def check_access
redirect_to not_found unless role?('dictionaries')
end
# GET /tags or /tags.json
def index
@dictionaries = Dictionary.all
end
# GET /tags/1 or /tags/1.json
def show; end
# GET /tags/new
def new
@dictionary = Dictionary.new
end
# GET /tags/1/edit
def edit; end
# POST /tags or /tags.json
def create
@dictionary = Dictionary.new(dictionary_params)
respond_to do |format|
if @dictionary.save
format.html { redirect_to dictionaries_url, notice: 'Utworzono pomyślnie.' }
format.json { render :show, status: :created, location: @dictionary }
else
format.html { render :new, status: :unprocessable_entity }
format.json { render json: @dictionary.errors, status: :unprocessable_entity }
end
end
end
def update
respond_to do |format|
if @dictionary.update(dictionary_params)
format.html { redirect_to dictionaries_url, notice: 'Zaktualizowano pomyślnie.' }
format.json { render :show, status: :ok, location: @dictionary }
else
format.html { render :edit, status: :unprocessable_entity }
format.json { render json: @dictionary.errors, status: :unprocessable_entity }
end
end
end
def destroy
@dictionary.destroy
respond_to do |format|
format.html { redirect_to dictionaries_url, notice: 'Usunięto pomyślnie.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_dictionary
@dictionary = Dictionary.find(params[:id])
end
# Only allow a list of trusted parameters through.
def dictionary_params
params.require(:dictionary).permit(:shortcut, :name, :description)
end
end

View File

@ -13,6 +13,7 @@ module ApplicationHelper
ret += menu_item('far fa-circle', 'Przedsięwzięcia', '/projects', 'projects') if role?('projects')
ret += menu_item('far fa-circle', 'Eksperci', '/experts', 'experts') if role?('experts')
ret += menu_item('far fa-circle', 'Partnerzy', '/partners', 'partners') if role?('partners')
ret += menu_item('far fa-circle', 'Słownik', '/dictionaries', 'dictionaries') if role?('dictionaries')
ret += menu_item('far fa-user', 'Użytkownicy', '/settings/users', 'users') if admin?
ret

40
app/models/dictionary.rb Normal file
View File

@ -0,0 +1,40 @@
# frozen_string_literal: true
# Model Dictionary
class Dictionary < ApplicationRecord
# == Constants ============================================================
# == Attributes ===========================================================
# == Extensions ===========================================================
# == Relationships ========================================================
# == Validations ==========================================================
validates :name, presence: true, length: { maximum: 255 }
validates :shortcut, presence: true, length: { maximum: 50 }
validates :description, presence: true, length: { maximum: 1000 }
# == Scopes ===============================================================
scope :by_short, ->(val) { where(shortcut: val) }
# == Callbacks ============================================================
# == Class Methods ========================================================
def self.ret_all_to_tinymce
ret = ''
Dictionary.all.each do |dict|
ret += dict.ret_a_tinymce_element
end
ret.chomp
end
# == Instance Methods =====================================================
def ret_a_tag
"<a tabindex='0' data-toggle='popover' data-trigger='hover' title='#{name}"\
"' data-content='#{description}' class='dictionary-word'>#{name}</a>"
end
def ret_a_tinymce_element
"{type: 'menuitem',text: '#{name}',onAction: function ()"\
" {editor.insertContent('&nbsp;#{shortcut}');}},"
end
end

View File

@ -152,6 +152,19 @@ class Dotation < ApplicationRecord
friendly_id
end
def replace_dictionary(text, form)
ret = text
dictionaries = Dictionary.all
dictionaries.each do |dictionary|
if form == 'pdf'
ret = ret.gsub(dictionary.shortcut, dictionary.name)
elsif form == 'html'
ret = ret.gsub(dictionary.shortcut, dictionary.ret_a_tag)
end
end
ret
end
def replace_video
require 'nokogiri'
ret = full_descr

View File

@ -0,0 +1,20 @@
<%= form_with(model: dictionary, local: true) do |form| %>
<%= render '/shared/errors_list', error_object: dictionary %>
<div class="form-group">
<%= form.label :shortcut %>
<%= form.text_field :shortcut, class: 'form-control', placeholder: 'Wprowadź skrót' %>
</div>
<div class="form-group">
<%= form.label :name %>
<%= form.text_field :name, class: 'form-control', placeholder: 'Wprowadź nazwę' %>
</div>
<div class="form-group">
<%= form.label :description %>
<%= form.text_area :description, class: 'form-control', placeholder: 'Wprowadź opis' %>
</div>
<div class="card-footer">
<%= link_to '< Wróć', dictionaries_path, class: 'btn btn-info' %>
<button type="submit" class="btn btn-primary">Zapisz</button>
</div>
<% end %>

View File

@ -0,0 +1,31 @@
<% if @dictionaries.blank? %>
<div class="alert alert-info alert-dismissible">
<h5><i class="icon fas fa-info"></i> Informacja</h5>
Brak elementów na liście
</div>
<% else %>
<table class="table table-bordered">
<thead>
<tr>
<th>Nazwa</th>
<th>Opis</th>
<th style="width: 200px">Akcje</th>
</tr>
</thead>
<tbody>
<% @dictionaries.each do |dictionary| %>
<tr>
<td><%= dictionary.name %></td>
<td><%= dictionary.description %></td>
<td>
<%= link_to raw('<i class="fas fa-edit"></i> Edycja'), edit_dictionary_path(dictionary), class: 'btn-sm btn-info' %>
<%= link_to raw('<i class="fas fa-trash-can"></i> Usuń'), dictionary, class: 'btn-sm btn-danger', method: :delete, data: { confirm: 'Czy na pewno?' } %>
</td>
</tr>
<% end %>
</tbody>
</table>
<% end %>

View File

@ -0,0 +1,30 @@
<div class="content-header">
<div class="container-fluid">
<div class="row mb-2">
<div class="col-sm-6">
<h1 class="m-0">Słownik</h1>
</div>
<div class="col-sm-6"></div>
</div>
</div>
</div>
<div class="content">
<div class="container-fluid">
<div class="row">
<div class="col-md-12">
<div class="card">
<div class="card-header">
<h3 class="card-title"><i class="fas fa-edit"></i> Edycja pojęcia</h3>
</div>
<div class="card-body">
<p id="notice"><%= notice %></p>
<%= render 'form', dictionary: @dictionary %>
</div>
</div>
</div>
</div>
</div>
</div>

View File

@ -0,0 +1,33 @@
<div class="content-header">
<div class="container-fluid">
<div class="row mb-2">
<div class="col-sm-6">
<h1 class="m-0">Słownik pojęć</h1>
</div>
<div class="col-sm-6"></div>
</div>
</div>
</div>
<div class="content">
<div class="container-fluid">
<div class="row">
<div class="col-md-12">
<div class="card">
<div class="card-header">
<h3 class="card-title"><i class="fas fa-folder"></i> Słownik pojęć</h3>
<div class="card-tools">
<%= link_to raw('<button type="button" class="btn-sm btn-block btn-primary">Dodaj</button>'), new_dictionary_path %>
</div>
</div>
<div class="card-body">
<p id="notice"><%= notice %></p>
<%= render partial: 'list' %>
</div>
</div>
</div>
</div>
</div>
</div>

View File

@ -0,0 +1,35 @@
<!-- Content Header (Page header) -->
<div class="content-header">
<div class="container-fluid">
<div class="row mb-2">
<div class="col-sm-6">
<h1 class="m-0">Słownik</h1>
</div>
<!-- /.col -->
<div class="col-sm-6"></div>
<!-- /.col -->
</div>
<!-- /.row -->
</div>
<!-- /.container-fluid -->
</div>
<div class="content">
<div class="container-fluid">
<div class="row">
<div class="col-md-12">
<div class="card">
<div class="card-header">
<h3 class="card-title"><i class="fas fa-edit"></i> Nowe pojęcie</h3>
</div>
<div class="card-body">
<p id="notice"><%= notice %></p>
<%= render 'form', dictionary: @dictionary %>
</div>
</div>
</div>
</div>
</div>
</div>

View File

@ -264,7 +264,7 @@
'insertdatetime', 'media', 'table', 'code', 'wordcount'
],
toolbar: 'undo redo | blocks | ' +
'bold italic backcolor | alignleft aligncenter ' +
'bold italic backcolor | customDictionary | alignleft aligncenter ' +
'alignright alignjustify | bullist numlist outdent indent | ' +
'removeformat link image media | table tableinsertdialog tablecellprops tableprops advtablerownumbering',
/* enable title field in the Image dialog*/
@ -276,6 +276,17 @@
images_upload_url: 'postAcceptor.php',
here we add custom filepicker only to Image dialog
*/
setup: function (editor) {
editor.ui.registry.addMenuButton('customDictionary', {
icon: 'user',
tooltip: 'Pojęcie słownikowe',
fetch: function (callback) {
var items = [<%= raw Dictionary.ret_all_to_tinymce %>];
callback(items);
}
});
},
file_picker_types: 'image',
/* and here's our custom image picker*/
file_picker_callback: (cb, value, meta) => {

View File

@ -34,7 +34,7 @@
<%= render 'activate', dotation: dotation %>
</td>
<td>
<%= link_to raw('<i class="fas fa-eye"></i> Pokaż'), edit_grant_path(dotation), class: 'btn-sm btn-info' %>
<%= link_to raw('<i class="fas fa-eye"></i> Pokaż'), grant_path(dotation), class: 'btn-sm btn-info' %>
<%= link_to raw('<i class="fas fa-trash-can"></i> Usuń'), grant_path(dotation), class: 'btn-sm btn-danger', method: :delete, data: { confirm: 'Czy na pewno?' } %>
</td>
</tr>

View File

@ -115,7 +115,7 @@
</div>
<div class="row">
<div class="col-md-12">
<%= raw @dotation.full_descr %>
<%= raw @dotation.replace_dictionary(@dotation.full_descr, 'html') %>
</div>
</div>
<hr />

View File

@ -89,7 +89,7 @@
<h3 style='text-transform: uppercase;'><b>Szczegółowy opis dotacji</b></h3>
<div class="row">
<div class="col-md-12">
<%= raw @dotation.full_descr %>
<%= raw @dotation.replace_dictionary(@dotation.full_descr, 'html') %>
</div>
</div>
</div>

View File

@ -74,7 +74,7 @@
<h3 style='text-transform: uppercase;'><b>Szczegółowy opis dotacji</b></h3>
<div class="row">
<div class="col-md-12">
<%= raw dotation.replace_video %>
<%= raw dotation.replace_dictionary(dotation.replace_video, 'pdf') %>
</div>
</div>
</div>

View File

@ -107,5 +107,8 @@
<script type="text/javascript">
<%= yield :foot_scripts %>
</script>
<script type="text/javascript">
reloadFunctionsOnAjax();
</script>
</body>
</html>

View File

@ -0,0 +1,22 @@
pl:
activerecord:
models:
tag: Słownik
attributes:
dictionary:
name: "Nazwa"
description: "Opis"
shortcut: "Skrót"
errors:
models:
dictionary:
attributes:
name:
blank: nie może być pusta
too_long: jest za długa (max 255 znaków)
description:
blank: nie może być pusty
too_long: jest za długi (max 1000 znaków)
shortcut:
blank: nie może być pusty
too_long: jest za długi (max 50 znaków)

View File

@ -24,6 +24,7 @@ Rails.application.routes.draw do
resources :projects
resources :partners
resources :experts
resources :dictionaries
get 'grants/activate'
post 'grants/activate'
resources :grants

View File

@ -0,0 +1,11 @@
class CreateDictionaries < ActiveRecord::Migration[5.2]
def change
create_table :dictionaries do |t|
t.string :shortcut
t.string :name
t.longtext :description
t.timestamps
end
end
end

View File

@ -10,7 +10,7 @@
#
# It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema.define(version: 2022_06_28_085754) do
ActiveRecord::Schema.define(version: 2022_06_29_060749) do
create_table "active_storage_attachments", options: "ENGINE=InnoDB DEFAULT CHARSET=utf8", force: :cascade do |t|
t.string "name", null: false
@ -83,6 +83,14 @@ ActiveRecord::Schema.define(version: 2022_06_28_085754) do
t.datetime "updated_at", null: false
end
create_table "dictionaries", options: "ENGINE=InnoDB DEFAULT CHARSET=utf8", force: :cascade do |t|
t.string "shortcut"
t.string "name"
t.text "description", limit: 4294967295
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "dotations", options: "ENGINE=InnoDB DEFAULT CHARSET=utf8", force: :cascade do |t|
t.string "slug"
t.string "name"

11
test/fixtures/dictionaries.yml vendored Normal file
View File

@ -0,0 +1,11 @@
# Read about fixtures at http://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html
one:
shortcut: MyString
name: MyString
description:
two:
shortcut: MyString
name: MyString
description:

View File

@ -0,0 +1,7 @@
require 'test_helper'
class DictionaryTest < ActiveSupport::TestCase
# test "the truth" do
# assert true
# end
end