shenmegui 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- 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: []
|