plok 2.0.4 → 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 4ce8383e982a9b8691a5dad5088d8c0c3b93905e7c105206d49f9cdc98f20bc9
4
- data.tar.gz: 480e83ddb884312a9f1eeb7767d6d4cdab08a6bd95e8854f83aea79327faed19
3
+ metadata.gz: 5c12946cd0b1f1f23073f8b34059867e92e2485534c5337ae30695139c4c6bba
4
+ data.tar.gz: ad241a51b95d3a9032ffdf42a596c63155bf4788522726d76890bf9fc7af6e73
5
5
  SHA512:
6
- metadata.gz: a6670f56eaa52d221d9ff57461b431d9886daa070d181773296d2e07b93fce5554b3d09681715878f7264bbc507476019c9e8876bdfe113570d84190604d7272
7
- data.tar.gz: e13bec29ecca73fef218876dc1c736484a38bbdff91d34a4009782b494c090428a2b53a3ab150e298a952cffaac0ca0531c7ecc56d516003318f3aff6b12f8a8
6
+ metadata.gz: 5bc8507b13dbf3bc89e2f431bd1edc811d3a97e868db6b7c76e93f3e223fc8e22f426309e56ee4abf652378518ccbf8487d8efbee3ef33ab17729873adbb5992
7
+ data.tar.gz: 55ebcff954367ce8c14ce285ec8e26f553501a6e77fdf116adf160bc2af31b8c153f622c34bb5d1ba11cdf694474fc4bab504fbd784efe677e6702b0d18db487
@@ -1,21 +1,98 @@
1
+ // Lightweight search autocomplete built on plain jQuery + Bootstrap 5 dropdown
2
+ // markup. Replaces the old jquery-ui.autocomplete widget.
3
+ //
4
+ // It fetches a JSON list of { label: <html>, value: <url> } from the form's
5
+ // action (see Backend::SearchController#query) and renders them as Bootstrap
6
+ // dropdown items. The HTML label embeds a type badge (see the result object
7
+ // partials in app/views/plok/search/result_objects/).
1
8
  var search = search || {
9
+ active: -1,
10
+
2
11
  init: function() {
3
- this.target().autocomplete({
4
- minLength: 2,
5
- source: search.target().parents('form').attr('action'),
6
- select: search.select,
7
- html: true
8
- }).on('keypress', this.keypress_listener);
12
+ var $input = this.target();
13
+ if(!$input.length) return;
14
+
15
+ this.$menu = $('<ul class="plok-autocomplete dropdown-menu"></ul>');
16
+ $input
17
+ .attr('autocomplete', 'off')
18
+ .parent().css('position', 'relative').append(this.$menu);
19
+
20
+ $input
21
+ .on('input', this.debounce(this.query.bind(this), 200))
22
+ .on('keydown', this.keydown.bind(this))
23
+ .on('blur', function() { setTimeout(function(){ search.close(); }, 150); });
24
+
25
+ $(document).on('click', function(e) {
26
+ if(!$(e.target).closest('[data-plok-searchable]').length) search.close();
27
+ });
28
+ },
29
+
30
+ query: function() {
31
+ var $input = this.target();
32
+ var term = $input.val();
33
+ if(term.length < 2) return this.close();
34
+
35
+ $.getJSON($input.parents('form').attr('action'), { term: term })
36
+ .done(function(items) { search.render(items); });
9
37
  },
10
38
 
11
- keypress_listener: function(e) {
39
+ render: function(items) {
40
+ this.$menu.empty();
41
+ this.active = -1;
42
+
43
+ if(!items.length) return this.close();
44
+
45
+ items.forEach(function(item) {
46
+ $('<li></li>')
47
+ .append($('<a class="dropdown-item" href="' + item.value + '"></a>').html(item.label))
48
+ .appendTo(search.$menu);
49
+ });
50
+
51
+ this.$menu.addClass('show');
52
+ },
53
+
54
+ keydown: function(e) {
12
55
  var code = (e.keyCode ? e.keyCode : e.which);
13
- if(code == 13) return false;
56
+ var $items = this.$menu.children('li');
57
+
58
+ if(code == 13) { // Enter: follow the active item, never submit the form.
59
+ if(this.active >= 0) {
60
+ window.location = $items.eq(this.active).find('a').attr('href');
61
+ }
62
+ return false;
63
+ }
64
+
65
+ if(!this.$menu.hasClass('show')) return;
66
+
67
+ if(code == 40) { // Down
68
+ this.move(1, $items);
69
+ e.preventDefault();
70
+ } else if(code == 38) { // Up
71
+ this.move(-1, $items);
72
+ e.preventDefault();
73
+ } else if(code == 27) { // Escape
74
+ this.close();
75
+ }
76
+ },
77
+
78
+ move: function(dir, $items) {
79
+ $items.eq(this.active).find('a').removeClass('active');
80
+ this.active = (this.active + dir + $items.length) % $items.length;
81
+ $items.eq(this.active).find('a').addClass('active');
82
+ },
83
+
84
+ close: function() {
85
+ if(this.$menu) this.$menu.removeClass('show').empty();
86
+ this.active = -1;
14
87
  },
15
88
 
16
- select: function(event, ui) {
17
- window.location = ui.item.value;
18
- return false;
89
+ debounce: function(fn, wait) {
90
+ var timeout;
91
+ return function() {
92
+ var context = this, args = arguments;
93
+ clearTimeout(timeout);
94
+ timeout = setTimeout(function(){ fn.apply(context, args); }, wait);
95
+ };
19
96
  },
20
97
 
21
98
  target: function() {
@@ -1,42 +1,30 @@
1
- .ui-autocomplete {
2
- width: 24rem !important;
1
+ // Dropdown for the backend search autocomplete (see plok/searchable.js).
2
+ // Built on Bootstrap 5 .dropdown-menu / .dropdown-item markup.
3
+ .plok-autocomplete {
4
+ width: 24rem;
5
+ max-width: 90vw;
6
+ max-height: 70vh;
7
+ overflow-y: auto;
8
+ top: 100%;
9
+ left: 0;
10
+ margin-top: 0.25rem;
3
11
  padding: 0;
4
- z-index: 9999;
5
- filter: drop-shadow(5px 5px 5px #666);
6
- }
7
-
8
- // Shows up during autocompletion sometimes.
9
- .ui-helper-hidden-accessible {
10
- display: none;
11
- }
12
12
 
13
- li.ui-menu-item {
14
- list-style: none;
15
- cursor: pointer;
16
- border-bottom: 1px solid #ccc;
17
- padding: 5px;
18
-
19
- &:last-child {
20
- border: none;
21
- margin-bottom: 0;
22
- padding-bottom: 0;
23
- }
13
+ .dropdown-item {
14
+ white-space: normal;
15
+ padding: 0.5rem 0.75rem;
16
+ border-bottom: 1px solid var(--bs-border-color);
17
+ cursor: pointer;
24
18
 
25
- &:hover {
26
- background-color: $primary;
27
- color: white !important;
28
- }
29
-
30
- a.ui-menu-item-wrapper {
31
- border: none;
32
-
33
- &.ui-state-active {
34
- background: none;
35
- color: inherit;
36
- text-decoration: none;
19
+ &:last-child {
20
+ border-bottom: 0;
21
+ }
37
22
 
38
- .text-muted {
39
- color: white !important;
23
+ // Keep muted helper text legible when the row is highlighted.
24
+ &.active {
25
+ .text-muted,
26
+ small {
27
+ color: rgba(255, 255, 255, 0.85) !important;
40
28
  }
41
29
  }
42
30
  }
@@ -1,4 +1,4 @@
1
1
  <% [name] = [name].decorate if [name].respond_to?(:decorate) %>
2
2
 
3
- <strong><%= t 'b.[name]' %></strong><br>
3
+ <span class="badge bg-secondary me-1"><%= t 'b.[name]' %></span><br>
4
4
  <small class="text-muted"><%= [name].id %></small>
data/lib/plok/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Plok
2
- VERSION = '2.0.4'
2
+ VERSION = '2.1.0'
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: plok
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.4
4
+ version: 2.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Davy Hellemans
@@ -91,15 +91,11 @@ files:
91
91
  - MIT-LICENSE
92
92
  - Rakefile
93
93
  - app/assets/config/plok_manifest.js
94
- - app/assets/javascripts/jquery-ui.autocomplete.html.js
95
94
  - app/assets/javascripts/plok/searchable.js
96
95
  - app/assets/javascripts/plok/sidebar.js
97
96
  - app/assets/stylesheets/plok/_autocomplete.scss
98
97
  - app/assets/stylesheets/plok/_sidebar.scss
99
98
  - app/assets/stylesheets/plok/_sidebar_compact.scss
100
- - app/assets/stylesheets/plok/backend/bs5/_autocomplete.scss
101
- - app/assets/stylesheets/plok/backend/bs5/_sidebar.scss
102
- - app/assets/stylesheets/plok/backend/bs5/_sidebar_compact.scss
103
99
  - app/controllers/catch_all_controller.rb
104
100
  - app/controllers/plok/version_controller.rb
105
101
  - app/models/concerns/plok/loggable.rb
@@ -169,7 +165,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
169
165
  - !ruby/object:Gem::Version
170
166
  version: '0'
171
167
  requirements: []
172
- rubygems_version: 3.6.9
168
+ rubygems_version: 4.0.11
173
169
  specification_version: 4
174
170
  summary: CMS basics
175
171
  test_files: []
@@ -1,40 +0,0 @@
1
- /*
2
- * jQuery UI Autocomplete HTML Extension
3
- *
4
- * Copyright 2010, Scott González (http://scottgonzalez.com)
5
- * Dual licensed under the MIT or GPL Version 2 licenses.
6
- *
7
- * http://github.com/scottgonzalez/jquery-ui-extensions
8
- */
9
- (function( $ ) {
10
-
11
- var proto = $.ui.autocomplete.prototype,
12
- initSource = proto._initSource;
13
-
14
- function filter( array, term ) {
15
- var matcher = new RegExp( $.ui.autocomplete.escapeRegex(term), "i" );
16
- return $.grep( array, function(value) {
17
- return matcher.test( $( "<div>" ).html( value.label || value.value || value ).text() );
18
- });
19
- }
20
-
21
- $.extend( proto, {
22
- _initSource: function() {
23
- if ( this.options.html && $.isArray(this.options.source) ) {
24
- this.source = function( request, response ) {
25
- response( filter( this.options.source, request.term ) );
26
- };
27
- } else {
28
- initSource.call( this );
29
- }
30
- },
31
-
32
- _renderItem: function( ul, item) {
33
- return $( "<li></li>" )
34
- .data( "item.autocomplete", item )
35
- .append( $( "<a></a>" )[ this.options.html ? "html" : "text" ]( item.label ) )
36
- .appendTo( ul );
37
- }
38
- });
39
-
40
- })( jQuery );
@@ -1,43 +0,0 @@
1
- .ui-autocomplete {
2
- width: 24rem !important;
3
- padding: 0;
4
- z-index: 9999;
5
- filter: drop-shadow(5px 5px 5px #666);
6
- }
7
-
8
- // Shows up during autocompletion sometimes.
9
- .ui-helper-hidden-accessible {
10
- display: none;
11
- }
12
-
13
- li.ui-menu-item {
14
- list-style: none;
15
- cursor: pointer;
16
- border-bottom: 1px solid #ccc;
17
- padding: 5px;
18
-
19
- &:last-child {
20
- border: none;
21
- margin-bottom: 0;
22
- padding-bottom: 0;
23
- }
24
-
25
- &:hover {
26
- background-color: $primary;
27
- color: white !important;
28
- }
29
-
30
- a.ui-menu-item-wrapper {
31
- border: none;
32
-
33
- &.ui-state-active {
34
- background: none;
35
- color: inherit;
36
- text-decoration: none;
37
-
38
- .text-muted {
39
- color: white !important;
40
- }
41
- }
42
- }
43
- }
@@ -1,86 +0,0 @@
1
- .sidebar-menu {
2
- bottom: 0;
3
- position: fixed;
4
- top: 0;
5
- width: var(--sidebar-width);
6
- transition: .5s;
7
- z-index: 10;
8
-
9
- a.logo {
10
- display: block;
11
- letter-spacing: 0.1em;
12
- line-height: 45px;
13
- text-decoration: none;
14
- text-transform: uppercase;
15
- }
16
-
17
- a.home-icon {
18
- display: none !important;
19
- }
20
-
21
- ul {
22
- list-style-type: none;
23
- padding-left: 0;
24
-
25
- li {
26
- cursor: pointer;
27
-
28
- a {
29
- color: #fff; // $color-contrast-light from the Bootstrap gem.
30
- display: block;
31
- font-size: 1rem;
32
- padding: 10px;
33
- padding-left: var(--sidebar-menu-item-left-margin);
34
- text-decoration: none !important;
35
-
36
- &:hover {
37
- background-color: #6c757d; // $secondary from the Bootstrap gem.
38
- }
39
- }
40
-
41
- &.top-level {
42
- letter-spacing: .05em;
43
- position: relative;
44
-
45
- .fa {
46
- font-size: 14px;
47
- width: var(--sidebar-icon-width);
48
- }
49
-
50
- .text {
51
- cursor: default;
52
- font-size: 0.8rem;
53
- padding: 16px 0 12px 0;
54
- pointer-events: none;
55
- text-transform: uppercase;
56
- }
57
-
58
- div[id^=nav-] {
59
- h4 {
60
- display: none;
61
- }
62
-
63
- ul li {
64
- position: relative;
65
-
66
- &::before {
67
- content: '\25A1';
68
- font-size: 0.4rem;
69
- left: calc(var(--sidebar-menu-item-left-margin) + 15px);
70
- position: absolute;
71
- top: 15px;
72
- }
73
-
74
- a {
75
- font-size: 0.8rem;
76
- padding-left: calc(var(--sidebar-menu-item-left-margin) + var(--sidebar-icon-width) + 10px);
77
- text-transform: uppercase;
78
- }
79
- }
80
- }
81
-
82
- }
83
- }
84
- }
85
-
86
- }
@@ -1,66 +0,0 @@
1
- .wrapper.compact {
2
- .content {
3
- margin-left: var(--sidebar-compact-width);
4
-
5
- @include media-breakpoint-down(md) {
6
- margin-left: 0;
7
- }
8
- }
9
-
10
- .sidebar-menu {
11
- width: var(--sidebar-compact-width);
12
-
13
- @include media-breakpoint-down(md) {
14
- width: 0;
15
- }
16
-
17
- a.logo {
18
- display: none !important;
19
- }
20
-
21
- a.home-icon {
22
- display: block !important;
23
- }
24
-
25
- ul li.top-level {
26
- > a { // The icons in the compact view.
27
- padding: 10px 0;
28
- text-align: center;
29
- }
30
-
31
- h4 {
32
- cursor: default;
33
- display: inline-block;
34
- font-size: .9rem;
35
- padding: 13px 0 0 5px;
36
- vertical-align: middle;
37
- text-transform: uppercase;
38
- }
39
-
40
- ul li {
41
- &::before {
42
- left: calc(var(--sidebar-icon-width) - 5px);
43
- }
44
-
45
- a {
46
- padding-left: calc(var(--sidebar-icon-width) + 10px);
47
-
48
- &:hover {
49
- background-color: $primary;
50
- }
51
- }
52
- }
53
-
54
- .fa { font-size: 20px; }
55
- .text { display: none; }
56
-
57
- .collapse {
58
- background-color: $secondary;
59
- left: var(--sidebar-compact-width);
60
- position: absolute;
61
- top: 0;
62
- width: 240px;
63
- }
64
- }
65
- }
66
- }