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 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
@@ -0,0 +1,11 @@
1
+ body {
2
+ margin: 50px;
3
+ width: 600px; }
4
+
5
+ .stack * {
6
+ display: block; }
7
+
8
+ .flow * {
9
+ display: inline; }
10
+
11
+ /*# sourceMappingURL=style.css.map */
@@ -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] %>" />
@@ -0,0 +1 @@
1
+ <div id="item-<%= id %>" class="flow"><%= content %></div>
@@ -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: []