shenmegui 0.0.1
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/lib/shenmegui.rb +153 -0
- data/static/script.js +49 -0
- data/static/style.css +11 -0
- data/templates/body.erb +17 -0
- data/templates/button.erb +1 -0
- data/templates/flow.erb +1 -0
- data/templates/stack.erb +1 -0
- data/templates/textarea.erb +1 -0
- data/templates/textline.erb +1 -0
- metadata +65 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: cc17fa7f8f6c46479ee3911e123e3a1695bb1e35
|
4
|
+
data.tar.gz: 3064fa81b892c8547595cf50bffcd81e7baccb12
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 1bc7fa600054cdf7b63829eb1cea9a4704cf3996829ba78a956a53b20edbb04aa4bb5073d56d1a9fa59f11f189eaff3f7b8e4303f9d63115f132b27175a383f8
|
7
|
+
data.tar.gz: bf49c7234618ea340f252d46411e6db30345f5eed597d678ac18e7949f89ce3680feef92e5419a8927b37d34a78c974008eeb113930c44a6be5f2948f603c012
|
data/lib/shenmegui.rb
ADDED
@@ -0,0 +1,153 @@
|
|
1
|
+
require 'erb'
|
2
|
+
require 'json'
|
3
|
+
require 'em-websocket'
|
4
|
+
|
5
|
+
module ShenmeGUI
|
6
|
+
|
7
|
+
class << self
|
8
|
+
attr_accessor :elements, :socket
|
9
|
+
attr_reader :temp_stack
|
10
|
+
|
11
|
+
%w{stack flow button radio checkbox image select textline textarea}.each do |x|
|
12
|
+
define_method "#{x}" do |value=nil, &block|
|
13
|
+
params = {value: value}
|
14
|
+
el = Control.new(x.to_sym, params)
|
15
|
+
temp_stack.last.children << el
|
16
|
+
el.parent = temp_stack.last
|
17
|
+
temp_stack << el
|
18
|
+
instance_eval &block unless block.nil?
|
19
|
+
temp_stack.pop
|
20
|
+
el
|
21
|
+
end
|
22
|
+
private x.to_sym
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
|
27
|
+
@elements = []
|
28
|
+
@temp_stack = []
|
29
|
+
|
30
|
+
def self.app(params={}, &block)
|
31
|
+
el = Control.new(:body, params)
|
32
|
+
temp_stack << el
|
33
|
+
instance_eval &block unless block.nil?
|
34
|
+
temp_stack.pop
|
35
|
+
File.open('index.html', 'w'){ |f| f.write el.render }
|
36
|
+
el
|
37
|
+
end
|
38
|
+
|
39
|
+
class Control
|
40
|
+
attr_accessor :id, :type, :properties, :events, :children, :parent
|
41
|
+
|
42
|
+
@available_events = %w{click input}.collect(&:to_sym)
|
43
|
+
@available_properties = {
|
44
|
+
body: %i{style},
|
45
|
+
button: %i{value},
|
46
|
+
input: %i{value},
|
47
|
+
textarea: %i{value cursor},
|
48
|
+
textline: %i{value cursor},
|
49
|
+
stack: %i{style},
|
50
|
+
flow: %i{style}
|
51
|
+
}
|
52
|
+
|
53
|
+
def self.available_properties
|
54
|
+
@available_properties
|
55
|
+
end
|
56
|
+
|
57
|
+
def inspect
|
58
|
+
"##{@type}.#{@id} #{@properties}"
|
59
|
+
end
|
60
|
+
|
61
|
+
def update
|
62
|
+
msg = "update:#{@id}->#{@properties.to_json}"
|
63
|
+
::ShenmeGUI.socket.send(msg)
|
64
|
+
end
|
65
|
+
|
66
|
+
def initialize(type, params={})
|
67
|
+
self.type = type
|
68
|
+
self.properties = params
|
69
|
+
self.id = ::ShenmeGUI.elements.size
|
70
|
+
::ShenmeGUI.elements << self
|
71
|
+
self.children = []
|
72
|
+
self.events = {}
|
73
|
+
self.class.available_properties[type].each do |x|
|
74
|
+
define_singleton_method(x) do
|
75
|
+
@properties[x]
|
76
|
+
end
|
77
|
+
|
78
|
+
define_singleton_method("#{x}=") do |v|
|
79
|
+
@properties[x] = v
|
80
|
+
update
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
def render
|
86
|
+
lib_path = $LOADED_FEATURES.grep(/.*\/lib\/shenmegui.rb/)[0]
|
87
|
+
template_path = lib_path.match(/(.*)\/lib/)[1] + "/templates"
|
88
|
+
if type == :body
|
89
|
+
static_path = lib_path.match(/(.*)\/lib/)[1] + "/static"
|
90
|
+
style = File.open("#{static_path}/style.css", 'r'){ |f| f.read }
|
91
|
+
script = File.open("#{static_path}/script.js", 'r'){ |f| f.read }
|
92
|
+
end
|
93
|
+
template = ::ERB.new File.open("#{template_path}/#{type}.erb", 'r') { |f| f.read }
|
94
|
+
content = self.children.collect{|x| x.render}.join("\n")
|
95
|
+
template.result(binding)
|
96
|
+
end
|
97
|
+
|
98
|
+
@available_events.each do |x|
|
99
|
+
define_method("on#{x}") do |&block|
|
100
|
+
return events[x] if block.nil?
|
101
|
+
events[x] = lambda &block
|
102
|
+
end
|
103
|
+
self
|
104
|
+
end
|
105
|
+
|
106
|
+
end
|
107
|
+
|
108
|
+
def self.handle(msg)
|
109
|
+
match_data = msg.match(/(.+?):(\d+)(?:->)?({.+?})?/)
|
110
|
+
command = match_data[1].to_sym
|
111
|
+
id = match_data[2].to_i
|
112
|
+
data = JSON.parse(match_data[3]) unless match_data[3].nil?
|
113
|
+
target = elements[id]
|
114
|
+
case command
|
115
|
+
when :update
|
116
|
+
data.each do |k,v|
|
117
|
+
target.properties[k.to_sym] = v
|
118
|
+
end
|
119
|
+
else
|
120
|
+
event_lambda = elements[id].events[command]
|
121
|
+
ShenmeGUI.instance_exec(&event_lambda) if event_lambda
|
122
|
+
end
|
123
|
+
target
|
124
|
+
end
|
125
|
+
|
126
|
+
module Server
|
127
|
+
def self.start!
|
128
|
+
ws_thread = Thread.new do
|
129
|
+
EM.run do
|
130
|
+
EM::WebSocket.run(:host => "0.0.0.0", :port => 80) do |ws|
|
131
|
+
ws.onopen { puts "WebSocket connection open" }
|
132
|
+
|
133
|
+
ws.onclose { puts "Connection closed" }
|
134
|
+
|
135
|
+
ws.onmessage do |msg|
|
136
|
+
puts "Recieved message: #{msg}"
|
137
|
+
ShenmeGUI.handle msg
|
138
|
+
end
|
139
|
+
|
140
|
+
ShenmeGUI.socket = ws
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
index_path = "#{Dir.pwd}/index.html"
|
146
|
+
`start file:///#{index_path}`
|
147
|
+
|
148
|
+
ws_thread.join
|
149
|
+
end
|
150
|
+
|
151
|
+
end
|
152
|
+
|
153
|
+
end
|
data/static/script.js
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
var wsUrl = "ws://localhost/";
|
2
|
+
|
3
|
+
websocket = new WebSocket(wsUrl);
|
4
|
+
websocket.onopen = function(evt){ console.log("Connected."); };
|
5
|
+
websocket.onmessage = function(evt){ console.log(evt.data); handleMessage(evt.data); };
|
6
|
+
websocket.onclose = function(evt){
|
7
|
+
console.log("Closed.");
|
8
|
+
};
|
9
|
+
|
10
|
+
function handleMessage(msg){
|
11
|
+
var match_data = msg.match(/(.+?):(\d+)(?:->)?({.+?})?/);
|
12
|
+
var command = match_data[1];
|
13
|
+
var target = document.getElementById('item-' + match_data[2]);
|
14
|
+
var data = JSON.parse(match_data[3]);
|
15
|
+
switch (command){
|
16
|
+
case 'update':
|
17
|
+
target.properties = data;
|
18
|
+
target.value = data.value;
|
19
|
+
}
|
20
|
+
}
|
21
|
+
|
22
|
+
function getId(obj){
|
23
|
+
return obj.id.match(/item-(\d+)/)[1];
|
24
|
+
}
|
25
|
+
|
26
|
+
var buttons = document.getElementsByTagName('input');
|
27
|
+
var i;
|
28
|
+
for(i=0; i<buttons.length; i++){
|
29
|
+
buttons[i].addEventListener('click', function(){
|
30
|
+
websocket.send("click:" + getId(this));
|
31
|
+
});
|
32
|
+
}
|
33
|
+
|
34
|
+
var inputs = document.getElementsByTagName('input');
|
35
|
+
for(i=0; i<inputs.length; i++){
|
36
|
+
inputs[i].addEventListener('input', function(){
|
37
|
+
var value = {value: this.value};
|
38
|
+
websocket.send("update:" + getId(this) + "->" + JSON.stringify(value));
|
39
|
+
websocket.send("input:" + getId(this));
|
40
|
+
});
|
41
|
+
}
|
42
|
+
|
43
|
+
var textareas = document.getElementsByTagName('textarea');
|
44
|
+
for(i=0; i<textareas.length; i++){
|
45
|
+
textareas[i].addEventListener('change', function(){
|
46
|
+
var value = {value: this.value};
|
47
|
+
websocket.send("change:" + getId(this) + "->" + JSON.stringify(value));
|
48
|
+
});
|
49
|
+
}
|
data/static/style.css
ADDED
data/templates/body.erb
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html lang="zh">
|
3
|
+
<head>
|
4
|
+
<meta charset="UTF-8">
|
5
|
+
<title>Document</title>
|
6
|
+
<link rel="stylesheet" type="text/css" href="http://cdn.amazeui.org/amazeui/2.2.1/css/amazeui.min.css">
|
7
|
+
<style>
|
8
|
+
<%= style %>
|
9
|
+
</style>
|
10
|
+
</head>
|
11
|
+
<body id="item-<%= id %>">
|
12
|
+
<%= content %>
|
13
|
+
<script>
|
14
|
+
<%= script %>
|
15
|
+
</script>
|
16
|
+
</body>
|
17
|
+
</html>
|
@@ -0,0 +1 @@
|
|
1
|
+
<input id="item-<%= id %>" type="button" class="am-btn am-btn-primary" value="<%= properties[:value] %>" />
|
data/templates/flow.erb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
<div id="item-<%= id %>" class="flow"><%= content %></div>
|
data/templates/stack.erb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
<div id="item-<%= id %>" class="stack"><%= content %></div>
|
@@ -0,0 +1 @@
|
|
1
|
+
<div class="am-form"><textarea id="item-<%= id %>"><%= properties[:value] %></textarea></div>
|
@@ -0,0 +1 @@
|
|
1
|
+
<input id="item-<%= id %>" class="am-form-field" type="text" value="<%= properties[:value] %>"/>
|
metadata
ADDED
@@ -0,0 +1,65 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: shenmegui
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- CicholGricenchos
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2015-03-07 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: em-websocket
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
description: a simple HTML GUI for Ruby
|
28
|
+
email: cichol@live.cn
|
29
|
+
executables: []
|
30
|
+
extensions: []
|
31
|
+
extra_rdoc_files: []
|
32
|
+
files:
|
33
|
+
- lib/shenmegui.rb
|
34
|
+
- static/style.css
|
35
|
+
- static/script.js
|
36
|
+
- templates/body.erb
|
37
|
+
- templates/button.erb
|
38
|
+
- templates/flow.erb
|
39
|
+
- templates/stack.erb
|
40
|
+
- templates/textarea.erb
|
41
|
+
- templates/textline.erb
|
42
|
+
homepage: https://github.com/CicholGricenchos/shenmegui
|
43
|
+
licenses: []
|
44
|
+
metadata: {}
|
45
|
+
post_install_message:
|
46
|
+
rdoc_options: []
|
47
|
+
require_paths:
|
48
|
+
- lib
|
49
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
50
|
+
requirements:
|
51
|
+
- - ">="
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '0'
|
54
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
55
|
+
requirements:
|
56
|
+
- - ">="
|
57
|
+
- !ruby/object:Gem::Version
|
58
|
+
version: '0'
|
59
|
+
requirements: []
|
60
|
+
rubyforge_project:
|
61
|
+
rubygems_version: 2.0.14
|
62
|
+
signing_key:
|
63
|
+
specification_version: 4
|
64
|
+
summary: "什么鬼!"
|
65
|
+
test_files: []
|