servel 0.28.0 → 0.33.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: 8f15c64ad7143343fa43beea82a7c09813ffda5d38c64cf3933fe5033bb78270
4
- data.tar.gz: 4a37029622423e52a260f26b3dd71a2ac0943e605370364a85e206fd644f6951
3
+ metadata.gz: 36dac91c1fba1bbaa2ab70a7dc39404996216867968c93438f503ccc8dd15631
4
+ data.tar.gz: fedf2fb5c899e69de6715c40b64c4d7c652f6f01c6bec40c99cea1780ce6c16a
5
5
  SHA512:
6
- metadata.gz: bea3930d3199941d249401dfae0f25a27dc03cf43dd39af5914d2ae7ef9af64ce49c73b47099758611e076f96396f30564404451b9f8f58a78fbfaf34b2f2622
7
- data.tar.gz: 0d3f892f937a3046e75a8a61fad8678252a88e7f657ef84da82ee7f46d852492368cc42aa17cda7ac869236a4ae3ae12200f6b48dd8a35c8648afd9460b02b52
6
+ metadata.gz: 6b52f97da999645b081ad452866fb032e841f073dbb9e3be5c28b4501062cca015d131872c237fc14cf5920421a0671ef8114d984c7bc320c4183f407da66cb3
7
+ data.tar.gz: 3d621057dd5499b01a69251a08e3d18c3dab29435fde99313f43484d0ae53ba443ca9aec6c16b71369a8e0a25dd5319bf029104cf7c385bf32913cc4d928cc92
data/app/_gallery.haml CHANGED
@@ -6,9 +6,10 @@
6
6
  #page-back.paginator ◀
7
7
  #page-next.paginator ▶
8
8
  #content
9
- %img#image
10
- %video#video{controls: false, loop: true}
11
- %audio#audio{controls: true}
12
- #text
13
- %a#text-anchor{href: '#'}
14
- #text-content
9
+ #scroller
10
+ %img#image
11
+ %video#video{controls: false, loop: true}
12
+ %audio#audio{controls: true}
13
+ #text
14
+ %a#text-anchor{href: '#'}
15
+ #text-content
data/app/css/common.css CHANGED
@@ -16,6 +16,14 @@ body {
16
16
  user-select: none;
17
17
  }
18
18
 
19
+ .text-selectable {
20
+ -webkit-user-select: text;
21
+ -moz-user-select: text;
22
+ -khtml-user-select: text;
23
+ -ms-user-select: text;
24
+ user-select: text;
25
+ }
26
+
19
27
  a {
20
28
  text-decoration: none;
21
29
  }
data/app/css/gallery.css CHANGED
@@ -1,25 +1,85 @@
1
1
  #gallery {
2
2
  background: #333;
3
3
  display: none;
4
- flex-direction: column;
5
4
  }
6
5
 
7
6
  body.has-gallery.gallery #gallery {
8
7
  display: flex;
9
8
  }
10
9
 
10
+ #controls {
11
+ display: flex;
12
+ }
13
+
14
+ #page-jump-listing {
15
+ flex-grow: 1;
16
+ }
17
+
18
+ .paginator {
19
+ display: flex;
20
+ align-items: center;
21
+ justify-content: center;
22
+ height: 75px;
23
+
24
+ font-size: 2em;
25
+ font-weight: bold;
26
+ text-align: center;
27
+ background-color: #1f1f1f;
28
+ color: #858585;
29
+
30
+ cursor: pointer;
31
+ }
32
+
33
+ .paginator:hover {
34
+ background-color: #0f0f0f;
35
+ color: #c1c1c1;
36
+ }
37
+
11
38
  #content {
12
39
  display: flex;
13
40
  align-items: center;
14
41
  justify-content: center;
15
42
  flex-grow: 1;
43
+ min-width: 0;
44
+ min-height: 0;
45
+ }
46
+
47
+ #scroller {
48
+ width: 100%;
49
+ max-height: 100%;
50
+ overflow: auto;
51
+ }
52
+
53
+ body.portrait #gallery {
54
+ flex-direction: column;
55
+ }
56
+
57
+ body.portrait .paginator {
58
+ width: 100px;
59
+ }
60
+
61
+ body.portrait #page-jump-listing {
62
+ width: auto;
63
+ }
64
+
65
+ body.landscape #gallery {
66
+ flex-direction: row;
67
+ }
68
+
69
+ body.landscape #controls {
70
+ flex-direction: column;
71
+ flex-shrink: 0;
72
+ width: 100px;
73
+ }
74
+
75
+ body.landscape #page-jump-listing {
76
+ writing-mode: vertical-rl;
77
+ transform: rotate(180deg);
16
78
  }
17
79
 
18
80
  #image, #video, #audio, #text {
19
81
  display: none;
20
- max-width: 100%;
21
82
  margin: 0 auto 0 auto;
22
- padding-top: 75px;
23
83
  }
24
84
 
25
85
  #video:focus, #audio:focus {
@@ -51,36 +111,6 @@ body.has-gallery.gallery #gallery {
51
111
  display: block;
52
112
  }
53
113
 
54
- #controls {
55
- position: fixed;
56
- left: 0;
57
- right: 0;
58
- display: flex;
59
- z-index: 10;
60
- }
61
-
62
- .paginator {
63
- display: flex;
64
- align-items: center;
65
- justify-content: center;
66
- width: 100px;
67
- height: 75px;
68
-
69
- font-size: 2em;
70
- font-weight: bold;
71
- text-align: center;
72
- background-color: #000000;
73
- color: #ffffff;
74
-
75
- opacity: 0.4;
76
- cursor: pointer;
77
- }
78
-
79
- #page-jump-listing {
80
- flex-grow: 1;
81
- width: auto;
82
- }
83
-
84
114
  @media screen and (max-width: 767px) {
85
115
  #gallery.video, #gallery.audio, #gallery.text {
86
116
  padding: 0;
@@ -101,9 +131,3 @@ body.has-gallery.gallery #gallery {
101
131
  display: none;
102
132
  }
103
133
  }
104
-
105
- @media screen and (min-width: 768px) {
106
- .paginator:hover {
107
- opacity: 0.7;
108
- }
109
- }
data/app/js/gallery.js CHANGED
@@ -1,9 +1,11 @@
1
1
  "use strict";
2
2
 
3
3
  var Gallery = (function() {
4
- var LAYOUT_MODES = ["fit-both", "fit-width", "clamp-width"];
4
+ var LAYOUT_MODES = ["fit-both", "fit-width", "clamp-width", "full-size"];
5
5
 
6
+ var $body;
6
7
  var $gallery;
8
+ var $image;
7
9
  var $video;
8
10
  var $audio;
9
11
  var currentIndex;
@@ -155,15 +157,38 @@ var Gallery = (function() {
155
157
  }
156
158
 
157
159
  function layout() {
158
- var viewportHeight = document.documentElement.clientHeight + "px";
159
- $gallery.style.minHeight = viewportHeight;
160
+ var vw = document.documentElement.clientWidth;
161
+ var vh = document.documentElement.clientHeight;
162
+
163
+ var viewportOrientation = vw > vh ? "landscape" : "portrait";
164
+ $body.classList.remove("landscape", "portrait");
165
+ $body.classList.add(viewportOrientation);
166
+
167
+ $gallery.style.height = vh + "px";
168
+
169
+ var scrollerMaxHeight = viewportOrientation == "landscape" ? vh : vh - 75;
160
170
 
161
171
  var layoutMode = LAYOUT_MODES[layoutModeIndex];
162
- var maxHeight = layoutMode == "fit-both" ? viewportHeight : "none";
163
- var maxWidth = layoutMode == "clamp-width" ? "1000px" : "100%";
164
172
 
165
- $("#image").style.maxWidth = maxWidth;
166
- $("#image").style.maxHeight = maxHeight;
173
+ if(layoutMode == "fit-both") {
174
+ var maxWidth = "100%";
175
+ var maxHeight = (scrollerMaxHeight + "px");
176
+ }
177
+ else if(layoutMode == "fit-width") {
178
+ var maxWidth = "100%";
179
+ var maxHeight = "none";
180
+ }
181
+ else if(layoutMode == "clamp-width") {
182
+ var maxWidth = "1000px";
183
+ var maxHeight = "none";
184
+ }
185
+ else if(layoutMode == "full-size") {
186
+ var maxWidth = "none";
187
+ var maxHeight = "none";
188
+ }
189
+
190
+ $image.style.maxWidth = maxWidth;
191
+ $image.style.maxHeight = maxHeight;
167
192
  $video.style.maxWidth = maxWidth;
168
193
  $video.style.maxHeight = maxHeight;
169
194
  $audio.style.maxWidth = maxWidth;
@@ -181,7 +206,9 @@ var Gallery = (function() {
181
206
  }
182
207
 
183
208
  function init() {
209
+ $body = $("body");
184
210
  $gallery = $("#gallery");
211
+ $image = $("#image");
185
212
  $video = $("#video");
186
213
  $audio = $("#audio");
187
214
 
data/app/js/index.js CHANGED
@@ -19,52 +19,8 @@ var Index = (function() {
19
19
  document.body.classList.add("gallery");
20
20
  }
21
21
 
22
- function jumpScroll() {
23
- if(galleryVisible()) {
24
- jumpListing();
25
- window.scrollTo(0, 0);
26
- }
27
- else {
28
- jumpGallery();
29
- window.scrollTo(0, document.body.scrollHeight);
30
- }
31
- }
32
-
33
- function atTop() {
34
- return window.scrollY == 0;
35
- }
36
-
37
- function bottomScrollDown(event) {
38
- return galleryVisible() && atBottom() && event.deltaY > 0;
39
- }
40
-
41
- function topScrollUp(event) {
42
- return listingVisible() && atTop() && event.deltaY < 0;
43
- }
44
-
45
- function initEvents() {
46
- var scrollSize = 0;
47
-
48
- window.addEventListener("wheel", function(event) {
49
- if(bottomScrollDown(event) || topScrollUp(event)) {
50
- scrollSize += Math.abs(event.deltaY);
51
-
52
- if(scrollSize >= 1500) {
53
- scrollSize = 0;
54
- jumpScroll();
55
- }
56
- }
57
- else {
58
- scrollSize = 0;
59
- }
60
- });
61
- }
62
-
63
22
  function init() {
64
- if((Entries.media().length / Entries.all().length) >= 0.5) jumpGallery();
65
- else jumpListing();
66
-
67
- initEvents();
23
+ jumpListing();
68
24
  }
69
25
 
70
26
  return {
data/app/js/listing.js CHANGED
@@ -27,7 +27,7 @@ var Listing = (function() {
27
27
  function renderRow(file) {
28
28
  return HTMLSafe`
29
29
  <tr>
30
- <td class="name">
30
+ <td class="name text-selectable">
31
31
  <span class="icon">${file.icon}</span>
32
32
  <a href="${file.href}" class="default ${file.class}" data-url="${file.href}" data-type="${file.mediaType}">${file.name}</a>
33
33
  </td>
data/bin/servel CHANGED
@@ -2,4 +2,4 @@
2
2
 
3
3
  require "servel"
4
4
 
5
- Servel::CLI.new(ARGV).start
5
+ Servel::CLI.new.start
data/lib/servel.rb CHANGED
@@ -1,20 +1,59 @@
1
1
  require 'rack'
2
2
  require 'rack/handler/puma'
3
+ require 'puma/configuration'
3
4
  require 'hamlit'
4
5
  require 'active_support/all'
5
6
  require 'lru_redux'
7
+ require 'tty-config'
6
8
 
7
9
  require 'thread'
8
10
  require 'pathname'
9
11
  require 'json'
12
+ require 'digest'
10
13
 
11
14
  module Servel
12
- def self.build_app(path_map)
15
+ def self.build_app(listings:, username: nil, password: nil)
16
+ app = build_listings_app(build_path_map(listings))
17
+
18
+ if username && username != ""
19
+ build_authentication_app(app: app, username: username, password: password)
20
+ else
21
+ app
22
+ end
23
+ end
24
+
25
+ def self.build_authentication_app(app:, username:, password:)
26
+ hashed_username = Digest::SHA512.digest(username)
27
+ hashed_password = Digest::SHA512.digest(password)
28
+
29
+ Rack::Auth::Basic.new(app) do |submitted_username, submitted_password|
30
+ hashed_submitted_username = Digest::SHA512.digest(submitted_username)
31
+ hashed_submitted_password = Digest::SHA512.digest(submitted_password)
32
+
33
+ Rack::Utils.secure_compare(
34
+ "#{hashed_username}#{hashed_password}",
35
+ "#{hashed_submitted_username}#{hashed_submitted_password}"
36
+ )
37
+ end
38
+ end
39
+
40
+ def self.build_path_map(listings)
41
+ listings.map do |listing|
42
+ listing = { listing => nil } if listing.is_a?(String)
43
+
44
+ root, url_root = listing.keys.first, listing.values.first || "/"
45
+ [Pathname.new(root).realpath, url_root]
46
+ end.to_h
47
+ end
48
+
49
+ def self.build_listings_app(path_map)
13
50
  url_map = path_map.map { |root, url_root| [url_root, Servel::App.new(root)] }.to_h
14
51
  url_map["/"] = Servel::HomeApp.new(path_map.values) unless url_map.keys.include?("/")
15
52
 
16
53
  Rack::URLMap.new(url_map)
17
54
  end
55
+
56
+
18
57
  end
19
58
 
20
59
  require "servel/version"
@@ -25,4 +64,5 @@ require "servel/haml_context"
25
64
  require "servel/index"
26
65
  require "servel/app"
27
66
  require "servel/home_app"
67
+ require "servel/config_parser"
28
68
  require "servel/cli"
data/lib/servel/cli.rb CHANGED
@@ -1,18 +1,16 @@
1
- class Servel::CLI
2
- def initialize(argv)
3
- @argv = argv
4
- end
5
-
6
- def start
7
- Rack::Handler::Puma.run(Servel.build_app(path_map))
8
- end
9
-
10
- def path_map
11
- @argv.map do |arg|
12
- root, url_root = arg.split(":" , 2)
13
- root = Pathname.new(root).realpath
14
-
15
- [root, url_root || "/"]
16
- end.to_h
17
- end
18
- end
1
+ class Servel::CLI
2
+ ALLOWED_PUMA_OPTIONS = [
3
+ :Host,
4
+ :Port,
5
+ :binds
6
+ ]
7
+
8
+ def initialize
9
+ @config = Servel::ConfigParser.new.config
10
+ end
11
+
12
+ def start
13
+ app = Servel.build_app(**@config.slice(:listings, :username, :password))
14
+ Rack::Handler::Puma.run(app, **@config.slice(*ALLOWED_PUMA_OPTIONS))
15
+ end
16
+ end
@@ -0,0 +1,45 @@
1
+ class Servel::ConfigParser
2
+ attr_reader :config
3
+
4
+ def initialize
5
+ @tty_config = TTY::Config.new
6
+ @tty_config.filename = "servel"
7
+ @tty_config.append_path(Dir.pwd)
8
+ @tty_config.append_path((Pathname.new(Dir.home) + ".servel").to_s)
9
+ @tty_config.append_path(Dir.home)
10
+ @tty_config.env_prefix = "servel"
11
+ @tty_config.autoload_env
12
+ @tty_config.read if @tty_config.exist?
13
+
14
+ @tty_config.append(*parse_argv, to: :listings)
15
+ parse_binds
16
+
17
+ @config = @tty_config.to_h.transform_keys(&:to_sym)
18
+ end
19
+
20
+ def parse_argv
21
+ ARGV.map do |arg|
22
+ root, url_root = arg.split(":" , 2)
23
+ { root => url_root }
24
+ end
25
+ end
26
+
27
+ def parse_binds
28
+ return parse_ssl_bind if @tty_config.fetch(:cert) && @tty_config.fetch(:key)
29
+
30
+ host = @tty_config.fetch(:host)
31
+ port = @tty_config.fetch(:port)
32
+ @tty_config.set(:Host, value: host) if host
33
+ @tty_config.set(:Port, value: port) if port
34
+ end
35
+
36
+ def parse_ssl_bind
37
+ host = @tty_config.fetch(:host, default: ::Puma::ConfigDefault::DefaultTCPHost)
38
+ port = @tty_config.fetch(:port, default: ::Puma::ConfigDefault::DefaultTCPPort)
39
+ key = Pathname.new(@tty_config.fetch(:key)).expand_path
40
+ cert = Pathname.new(@tty_config.fetch(:cert)).expand_path
41
+
42
+ query = URI.encode_www_form(key: key, cert: cert)
43
+ @tty_config.append("ssl://#{host}:#{port}?#{query}", to: :binds)
44
+ end
45
+ end
@@ -1,3 +1,3 @@
1
1
  module Servel
2
- VERSION = "0.28.0"
2
+ VERSION = "0.33.0"
3
3
  end
data/servel.gemspec CHANGED
@@ -28,4 +28,5 @@ Gem::Specification.new do |spec|
28
28
  spec.add_dependency "hamlit"
29
29
  spec.add_dependency "activesupport"
30
30
  spec.add_dependency "lru_redux"
31
+ spec.add_dependency "tty-config"
31
32
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: servel
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.28.0
4
+ version: 0.33.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Brenton "B-Train" Fletcher
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-09-24 00:00:00.000000000 Z
11
+ date: 2021-03-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -108,6 +108,20 @@ dependencies:
108
108
  - - ">="
109
109
  - !ruby/object:Gem::Version
110
110
  version: '0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: tty-config
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ">="
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ type: :runtime
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - ">="
123
+ - !ruby/object:Gem::Version
124
+ version: '0'
111
125
  description: Serves files and directories over HTTP.
112
126
  email:
113
127
  - i@bloople.net
@@ -143,6 +157,7 @@ files:
143
157
  - lib/servel.rb
144
158
  - lib/servel/app.rb
145
159
  - lib/servel/cli.rb
160
+ - lib/servel/config_parser.rb
146
161
  - lib/servel/entry.rb
147
162
  - lib/servel/entry_factory.rb
148
163
  - lib/servel/haml_context.rb
@@ -170,8 +185,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
170
185
  - !ruby/object:Gem::Version
171
186
  version: '0'
172
187
  requirements: []
173
- rubyforge_project:
174
- rubygems_version: 2.7.6
188
+ rubygems_version: 3.0.3
175
189
  signing_key:
176
190
  specification_version: 4
177
191
  summary: Serves files and directories over HTTP.