crimson 0.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 +7 -0
- data/.github/workflows/gempush.yml +44 -0
- data/.gitignore +9 -0
- data/.travis.yml +4 -0
- data/.vscode/launch.json +14 -0
- data/CODE_OF_CONDUCT.md +49 -0
- data/Gemfile +11 -0
- data/LICENSE.txt +21 -0
- data/README.md +41 -0
- data/Rakefile +10 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/crimson.gemspec +25 -0
- data/example/ets.rb +22 -0
- data/example/example.rb +66 -0
- data/lib/crimson.js +10 -0
- data/lib/crimson.rb +5 -0
- data/lib/crimson/client.rb +86 -0
- data/lib/crimson/icons/close.png +0 -0
- data/lib/crimson/icons/hide.png +0 -0
- data/lib/crimson/icons/resize.png +0 -0
- data/lib/crimson/mash.rb +9 -0
- data/lib/crimson/model.rb +98 -0
- data/lib/crimson/model_change.rb +20 -0
- data/lib/crimson/notification_bus.rb +35 -0
- data/lib/crimson/object.rb +196 -0
- data/lib/crimson/server.rb +69 -0
- data/lib/crimson/utilities.rb +13 -0
- data/lib/crimson/version.rb +3 -0
- data/lib/crimson/webserver.rb +17 -0
- data/lib/crimson/widgets/bottom_resizer.rb +22 -0
- data/lib/crimson/widgets/desktop.rb +44 -0
- data/lib/crimson/widgets/form.rb +12 -0
- data/lib/crimson/widgets/input.rb +10 -0
- data/lib/crimson/widgets/left_resizer.rb +27 -0
- data/lib/crimson/widgets/resizer.rb +38 -0
- data/lib/crimson/widgets/right_resizer.rb +22 -0
- data/lib/crimson/widgets/taskbar.rb +0 -0
- data/lib/crimson/widgets/titlebar.rb +75 -0
- data/lib/crimson/widgets/top_resizer.rb +27 -0
- data/lib/crimson/widgets/window.rb +134 -0
- data/lib/html/template.html +13 -0
- data/lib/javascript/Application.js +13 -0
- data/lib/javascript/Logger.js +11 -0
- data/lib/javascript/MessageHandler.js +142 -0
- data/lib/javascript/ObjectManager.js +33 -0
- data/lib/javascript/ServerInteractor.js +42 -0
- data/lib/javascript/Utilities.js +26 -0
- metadata +135 -0
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'resizer'
|
4
|
+
|
5
|
+
module Crimson
|
6
|
+
class BottomResizer < Resizer
|
7
|
+
def initialize
|
8
|
+
super('ns-resize')
|
9
|
+
|
10
|
+
style.width = '100%'
|
11
|
+
style.height = '5px'
|
12
|
+
style.position = 'absolute'
|
13
|
+
style.bottom = 0
|
14
|
+
style.left = 0
|
15
|
+
end
|
16
|
+
|
17
|
+
def on_mousemove(data)
|
18
|
+
parent.style.height = "#{data.clientY - parent.style.top.delete_suffix('px').to_i - data.movementY}px"
|
19
|
+
parent.commit!
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../object'
|
4
|
+
require_relative 'window'
|
5
|
+
|
6
|
+
module Crimson
|
7
|
+
class Desktop < Crimson::Object
|
8
|
+
def initialize
|
9
|
+
super(:div)
|
10
|
+
|
11
|
+
self.style = {
|
12
|
+
"height": '100vh',
|
13
|
+
"width": '100vw',
|
14
|
+
"max-height": '100vh',
|
15
|
+
"max-width": '100vw',
|
16
|
+
"overflow": 'hidden',
|
17
|
+
"position": 'fixed',
|
18
|
+
"left": "0px",
|
19
|
+
"top": "0px"
|
20
|
+
}
|
21
|
+
|
22
|
+
self.ondragover = 'event.preventDefault();'
|
23
|
+
self.ondrop = 'event.preventDefault();'
|
24
|
+
|
25
|
+
on('drop', method(:on_drop))
|
26
|
+
end
|
27
|
+
|
28
|
+
def on_drop(data)
|
29
|
+
window = find_descendant(data.target.to_sym).parent
|
30
|
+
|
31
|
+
unless window.nil?
|
32
|
+
window.style.left = "#{data.clientX + window.offset.left}px"
|
33
|
+
window.style.top = "#{data.clientY + window.offset.top}px"
|
34
|
+
window.commit!
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def create_window(*args)
|
39
|
+
window = Crimson::Window.new(*args)
|
40
|
+
add(window)
|
41
|
+
window
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'resizer'
|
4
|
+
|
5
|
+
module Crimson
|
6
|
+
class LeftResizer < Resizer
|
7
|
+
def initialize
|
8
|
+
super('ew-resize')
|
9
|
+
|
10
|
+
style.width = '5px'
|
11
|
+
style.height = '100%'
|
12
|
+
style.position = 'absolute'
|
13
|
+
style.top = 0
|
14
|
+
style.left = 0
|
15
|
+
end
|
16
|
+
|
17
|
+
def on_mousemove(data)
|
18
|
+
min_width = parent.style.minWidth.delete_suffix('px').to_i
|
19
|
+
new_width = parent.style.width.delete_suffix('px').to_i - data.movementX
|
20
|
+
new_left = parent.style.left.delete_suffix('px').to_i + data.movementX
|
21
|
+
|
22
|
+
parent.style.width = "#{new_width}px"
|
23
|
+
parent.style.left = "#{new_left}px" unless new_width < min_width
|
24
|
+
parent.commit!
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../object'
|
4
|
+
|
5
|
+
module Crimson
|
6
|
+
class Resizer < Crimson::Object
|
7
|
+
attr_reader :cursor
|
8
|
+
|
9
|
+
def initialize(cursor)
|
10
|
+
super(:div)
|
11
|
+
|
12
|
+
@cursor = cursor
|
13
|
+
self.style = {}
|
14
|
+
|
15
|
+
enable
|
16
|
+
end
|
17
|
+
|
18
|
+
def enable
|
19
|
+
style.cursor = cursor
|
20
|
+
on(:mousedown, method(:on_mousedown))
|
21
|
+
end
|
22
|
+
|
23
|
+
def disable
|
24
|
+
style.cursor = "auto"
|
25
|
+
un(:mousedown, method(:on_mousedown))
|
26
|
+
end
|
27
|
+
|
28
|
+
def on_mousedown(_data)
|
29
|
+
parent.parent.on(:mousemove, method(:on_mousemove))
|
30
|
+
parent.parent.on(:mouseup, method(:on_mouseup))
|
31
|
+
end
|
32
|
+
|
33
|
+
def on_mouseup(_data)
|
34
|
+
parent.parent.un(:mousemove, method(:on_mousemove))
|
35
|
+
parent.parent.un(:mouseup, method(:on_mouseup))
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'resizer'
|
4
|
+
|
5
|
+
module Crimson
|
6
|
+
class RightResizer < Resizer
|
7
|
+
def initialize
|
8
|
+
super('ew-resize')
|
9
|
+
|
10
|
+
style.width = '5px'
|
11
|
+
style.height = '100%'
|
12
|
+
style.position = 'absolute'
|
13
|
+
style.top = 0
|
14
|
+
style.right = 0
|
15
|
+
end
|
16
|
+
|
17
|
+
def on_mousemove(data)
|
18
|
+
parent.style.width = "#{data.clientX - parent.style.left.delete_suffix('px').to_i - data.movementX}px"
|
19
|
+
parent.commit!
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
File without changes
|
@@ -0,0 +1,75 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../object'
|
4
|
+
|
5
|
+
module Crimson
|
6
|
+
class Titlebar < Crimson::Object
|
7
|
+
attr_reader :title, :hide_button, :resize_button, :close_button
|
8
|
+
|
9
|
+
def initialize(window_title)
|
10
|
+
super(:div)
|
11
|
+
|
12
|
+
@title = Object.new(:div)
|
13
|
+
self.title = window_title
|
14
|
+
title.style.color = 'white'
|
15
|
+
title.style.fontFamily = 'Verdana'
|
16
|
+
title.style.fontWeight = 'bold'
|
17
|
+
title.style.textAlign = 'center'
|
18
|
+
title.style.margin = 'auto'
|
19
|
+
add(title)
|
20
|
+
|
21
|
+
@hide_button = Object.new(:img)
|
22
|
+
hide_button.src = 'crimson/icons/hide.png'
|
23
|
+
hide_button.style.padding = '10px 20px'
|
24
|
+
hide_button.on('mouseenter') do |_data|
|
25
|
+
hide_button.style.backgroundColor = 'rgba(0, 0, 0, 0.6)'
|
26
|
+
hide_button.commit!
|
27
|
+
end
|
28
|
+
hide_button.on('mouseleave') do |_data|
|
29
|
+
hide_button.style.backgroundColor = 'rgba(0, 0, 0, 0.0)'
|
30
|
+
hide_button.commit!
|
31
|
+
end
|
32
|
+
add(hide_button)
|
33
|
+
|
34
|
+
@resize_button = Object.new(:img)
|
35
|
+
resize_button.src = 'crimson/icons/resize.png'
|
36
|
+
resize_button.style.padding = '8px 16px'
|
37
|
+
resize_button.on('mouseenter') do |_data|
|
38
|
+
resize_button.style.backgroundColor = 'rgba(0, 0, 0, 0.6)'
|
39
|
+
resize_button.commit!
|
40
|
+
end
|
41
|
+
resize_button.on('mouseleave') do |_data|
|
42
|
+
resize_button.style.backgroundColor = 'rgba(0, 0, 0, 0.0)'
|
43
|
+
resize_button.commit!
|
44
|
+
end
|
45
|
+
add(resize_button)
|
46
|
+
|
47
|
+
@close_button = Object.new(:img)
|
48
|
+
close_button.src = 'crimson/icons/close.png'
|
49
|
+
close_button.style.padding = '10px 20px'
|
50
|
+
close_button.on('mouseenter') do |_data|
|
51
|
+
close_button.style.backgroundColor = 'rgba(0, 0, 0, 0.6)'
|
52
|
+
close_button.commit!
|
53
|
+
end
|
54
|
+
close_button.on('mouseleave') do |_data|
|
55
|
+
close_button.style.backgroundColor = 'rgba(0, 0, 0, 0.0)'
|
56
|
+
close_button.commit!
|
57
|
+
end
|
58
|
+
add(close_button)
|
59
|
+
|
60
|
+
style.backgroundColor = '#2ecc71'
|
61
|
+
style.width = '100%'
|
62
|
+
style.height = '35px'
|
63
|
+
style.display = 'flex'
|
64
|
+
style.userSelect = 'none'
|
65
|
+
end
|
66
|
+
|
67
|
+
def title=(window_title)
|
68
|
+
title.innerHTML = window_title
|
69
|
+
end
|
70
|
+
|
71
|
+
def buttons
|
72
|
+
[hide_button, resize_button, close_button]
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'resizer'
|
4
|
+
|
5
|
+
module Crimson
|
6
|
+
class TopResizer < Resizer
|
7
|
+
def initialize
|
8
|
+
super('ns-resize')
|
9
|
+
|
10
|
+
style.width = '100%'
|
11
|
+
style.height = '5px'
|
12
|
+
style.position = 'absolute'
|
13
|
+
style.top = 0
|
14
|
+
style.left = 0
|
15
|
+
end
|
16
|
+
|
17
|
+
def on_mousemove(data)
|
18
|
+
min_height = parent.style.minHeight.delete_suffix('px').to_i
|
19
|
+
new_height = parent.style.height.delete_suffix('px').to_i - data.movementY
|
20
|
+
new_top = parent.style.top.delete_suffix('px').to_i + data.movementY
|
21
|
+
|
22
|
+
parent.style.height = "#{new_height}px"
|
23
|
+
parent.style.top = "#{new_top}px" unless new_height < min_height
|
24
|
+
parent.commit!
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,134 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'hashie'
|
4
|
+
require_relative '../object'
|
5
|
+
require_relative 'titlebar'
|
6
|
+
require_relative 'left_resizer'
|
7
|
+
require_relative 'right_resizer'
|
8
|
+
require_relative 'top_resizer'
|
9
|
+
require_relative 'bottom_resizer'
|
10
|
+
|
11
|
+
module Crimson
|
12
|
+
class Window < Crimson::Object
|
13
|
+
attr_reader :offset, :titlebar, :previous_dimensions, :content
|
14
|
+
attr_reader :resizable, :left_resizer, :right_resizer, :top_resizer, :bottom_resizer
|
15
|
+
|
16
|
+
def initialize(title, width = '800px', height = '600px')
|
17
|
+
super(:div)
|
18
|
+
|
19
|
+
@resizable = true
|
20
|
+
@offset = Hashie::Mash.new
|
21
|
+
@previous_dimensions = Hashie::Mash.new
|
22
|
+
|
23
|
+
@titlebar = Titlebar.new(title)
|
24
|
+
titlebar.draggable = true
|
25
|
+
titlebar.on('dragstart', method(:on_dragstart))
|
26
|
+
titlebar.resize_button.on('click') do |_data|
|
27
|
+
maximized? ? minimize : maximize
|
28
|
+
commit_tree!
|
29
|
+
end
|
30
|
+
titlebar.close_button.on('click') do |_data|
|
31
|
+
old_parent = parent
|
32
|
+
old_parent.remove(self)
|
33
|
+
old_parent.commit_tree!
|
34
|
+
end
|
35
|
+
add(titlebar)
|
36
|
+
|
37
|
+
@left_resizer = LeftResizer.new
|
38
|
+
add(left_resizer)
|
39
|
+
|
40
|
+
@right_resizer = RightResizer.new
|
41
|
+
add(right_resizer)
|
42
|
+
|
43
|
+
@top_resizer = TopResizer.new
|
44
|
+
top_resizer.style.height = '10px'
|
45
|
+
add(top_resizer)
|
46
|
+
|
47
|
+
@bottom_resizer = BottomResizer.new
|
48
|
+
add(bottom_resizer)
|
49
|
+
|
50
|
+
@content = Crimson::Object.new(:div)
|
51
|
+
content.style.width = '100%'
|
52
|
+
content.style.height = "calc(100% - #{titlebar.style.height})"
|
53
|
+
content.style.padding = 0
|
54
|
+
content.style.margin = 0
|
55
|
+
add(content)
|
56
|
+
|
57
|
+
style.left = '0px'
|
58
|
+
style.top = '0px'
|
59
|
+
style.height = height
|
60
|
+
style.width = width
|
61
|
+
style.minHeight = '200px'
|
62
|
+
style.minWidth = '400px'
|
63
|
+
style.position = 'absolute'
|
64
|
+
style.backgroundColor = 'white'
|
65
|
+
style.boxShadow = '0 4px 8px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19)'
|
66
|
+
|
67
|
+
on('mousedown', method(:on_mousedown))
|
68
|
+
end
|
69
|
+
|
70
|
+
def content=(widget)
|
71
|
+
content.children.each { |child| content.remove(child) }
|
72
|
+
content.add(widget)
|
73
|
+
end
|
74
|
+
|
75
|
+
def on_dragstart(data)
|
76
|
+
offset.top = style.top.delete_suffix('px').to_i - data.clientY
|
77
|
+
offset.left = style.left.delete_suffix('px').to_i - data.clientX
|
78
|
+
end
|
79
|
+
|
80
|
+
def on_mousedown(_data)
|
81
|
+
parent.move(self, -1)
|
82
|
+
parent.commit_tree!(:children)
|
83
|
+
end
|
84
|
+
|
85
|
+
def maximized?
|
86
|
+
style.height == '100vh' && style.width == '100vw'
|
87
|
+
end
|
88
|
+
|
89
|
+
def minimized?
|
90
|
+
!maximized?
|
91
|
+
end
|
92
|
+
|
93
|
+
def resizable?
|
94
|
+
resizable
|
95
|
+
end
|
96
|
+
|
97
|
+
def resizable=(bool)
|
98
|
+
@resizable = bool
|
99
|
+
|
100
|
+
if resizable?
|
101
|
+
resizers.each(&:enable)
|
102
|
+
else
|
103
|
+
resizers.each(&:disable)
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
def resizers
|
108
|
+
[left_resizer, right_resizer, top_resizer, bottom_resizer]
|
109
|
+
end
|
110
|
+
|
111
|
+
def maximize
|
112
|
+
self.resizable = false
|
113
|
+
|
114
|
+
previous_dimensions.top = style.top.dup
|
115
|
+
previous_dimensions.left = style.left.dup
|
116
|
+
previous_dimensions.width = style.width.dup
|
117
|
+
previous_dimensions.height = style.height.dup
|
118
|
+
|
119
|
+
style.top = '0px'
|
120
|
+
style.left = '0px'
|
121
|
+
style.width = '100vw'
|
122
|
+
style.height = '100vh'
|
123
|
+
end
|
124
|
+
|
125
|
+
def minimize
|
126
|
+
style.top = previous_dimensions.top.dup
|
127
|
+
style.left = previous_dimensions.left.dup
|
128
|
+
style.width = previous_dimensions.width.dup
|
129
|
+
style.height = previous_dimensions.height.dup
|
130
|
+
|
131
|
+
self.resizable = true
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|