erd 0.1.0 → 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,152 +1,241 @@
1
- $ ->
2
- window.paper = Raphael('erd', $('#erd').css('width'), $('#erd').css('height'))
1
+ class ERD
2
+ constructor: (@name, @elem, @edges) ->
3
+ @paper = Raphael(name, @elem.css('width'), @elem.css('height'))
4
+ @setup_handlers()
5
+ @connect_arrows()
3
6
 
4
- # $('#erd').on 'click', (ev) ->
5
- # console.log 'click'
6
- $('div.model_name_text, span.column_name_text, span.column_type_text').on('click', (ev) ->
7
- $(this).hide()
8
- .next('form').show().find('input[name=to]').val($(this).text()).focus()
9
- )
7
+ upsert_change: (action, model, column, from, to) ->
8
+ rows = ($(tr).find('td') for tr in $('#changes > tbody > tr'))
9
+ existing = null
10
+ $(rows).each (i, row) ->
11
+ existing = row if (action == $(row[0]).html()) && (model == $(row[1]).html()) && (column == $(row[2]).html())
12
+ if existing == null
13
+ $('#changes > tbody').append("<tr><td>#{action}</td><td>#{model}</td><td>#{column}</td><td>#{from}</td><td>#{to}</td></tr>")
14
+ else
15
+ $(existing[3]).text(from)
16
+ $(existing[4]).text(to)
17
+ $('#changes').show()
18
+
19
+ positions: (div) ->
20
+ [left, width, top, height] = [parseInt(div.css('left')), parseInt(div.css('width')), parseInt(div.css('top')), parseInt(div.css('height'))]
21
+ {left: left, right: left + width, top: top, bottom: top + height, center: {x: (left + left + width) / 2, y: (top + top + height) / 2}, vertex: {}}
22
+
23
+ connect_arrows: ->
24
+ $.each @edges, (i, edge) =>
25
+ @connect_arrow $("##{edge.from}"), $("##{edge.to}")
26
+
27
+ connect_arrow: (from_elem, to_elem) ->
28
+ #TODO handle self referential associations
29
+ return if from_elem.attr('id') == to_elem.attr('id')
30
+
31
+ from = @positions(from_elem)
32
+ to = @positions(to_elem)
33
+ #FIXME terrible code
34
+ a = (to.center.y - from.center.y) / (to.center.x - from.center.x)
35
+ b = from.center.y - from.center.x * a
36
+
37
+ x2y = (x) -> ( a * x + b )
38
+ y2x = (y) -> ( (y - b) / a )
39
+
40
+ if from.center.x > to.center.x
41
+ [from.vertex.x, from.vertex.y] = [from.left, x2y(from.left)]
42
+ [to.vertex.x, to.vertex.y] = [to.right, x2y(to.right)]
43
+ else
44
+ [from.vertex.x, from.vertex.y] = [from.right, x2y(from.right)]
45
+ [to.vertex.x, to.vertex.y] = [to.left, x2y(to.left)]
46
+ for rect in [from, to]
47
+ if rect.vertex.y < rect.top
48
+ [rect.vertex.x, rect.vertex.y, rect.vertex.direction] = [y2x(rect.top), rect.top, 'v']
49
+ else if rect.vertex.y > rect.bottom
50
+ [rect.vertex.x, rect.vertex.y, rect.vertex.direction] = [y2x(rect.bottom), rect.bottom, 'v']
51
+ else
52
+ from.vertex.direction = 'h'
53
+
54
+ if from.vertex.direction == 'h'
55
+ path = "M#{parseInt(from.vertex.x)} #{parseInt(from.vertex.y)}H#{parseInt((from.vertex.x + to.vertex.x) / 2)} V#{parseInt(to.vertex.y)} H#{parseInt(to.vertex.x)}"
56
+ else
57
+ path = "M#{parseInt(from.vertex.x)} #{parseInt(from.vertex.y)}V#{parseInt((from.vertex.y + to.vertex.y) / 2)} H#{parseInt(to.vertex.x)} V#{parseInt(to.vertex.y)}"
58
+
59
+ @paper.path(path).attr({'stroke-width': 2, opacity: 0.5, 'arrow-end': 'classic-wide-long'})
60
+
61
+ setup_handlers: ->
62
+ @setup_click_handlers()
63
+ @setup_submit_handlers()
64
+ $('div.model').draggable(drag: @handle_drag)
65
+
66
+ handle_drag: (ev, ui) =>
67
+ target = $(ev.target)
68
+ target.addClass('noclick')
69
+ model = target.data('model_name')
70
+ from = target.data('original_position')
71
+ to = [target.css('left').replace(/px$/, ''), target.css('top').replace(/px$/, '')].join()
72
+ @upsert_change 'move', model, '', '', to
73
+ @paper.clear()
74
+ @connect_arrows(@edges)
75
+
76
+ setup_click_handlers: ->
77
+ text_elems = [
78
+ 'div.model_name_text',
79
+ 'span.column_name_text',
80
+ 'span.column_type_text'
81
+ ].join()
82
+
83
+ $(text_elems).on 'click', @handle_text_elem_click
84
+ $('div.model a.add_column').on 'click', @handle_add_column_click
85
+ $('div.model a.close').on 'click', @handle_remove_model_click
86
+
87
+ setup_submit_handlers: ->
88
+ $('form.rename_model_form').on 'submit', @handle_rename_model
89
+ $('form.rename_column_form').on 'submit', @handle_rename_column
90
+ $('form.alter_column_form').on 'submit', @handle_change_column_type
91
+ $('form.add_column_form').on 'submit', @handle_add_column
92
+ $('#changes_form').on 'submit', @handle_save
93
+
94
+ handle_save: ->
95
+ j = '['
96
+ rows = ($(tr).find('td') for tr in $('#changes > tbody > tr'))
97
+ $(rows).each (i, row) ->
98
+ j += "{\"action\": \"#{$(row[0]).html()}\", \"model\": \"#{$(row[1]).html()}\", \"column\": \"#{$(row[2]).html()}\", \"from\": \"#{$(row[3]).html()}\", \"to\": \"#{$(row[4]).html()}\"}"
99
+ j += ',' if i < rows.length - 1
100
+ j += ']'
101
+ $('#changes_form').find('input[name=changes]').val(j)
10
102
 
11
- $('div.model a.add_column').on 'click', (ev) ->
103
+ handle_add_column: (ev) ->
12
104
  ev.preventDefault()
13
- $(this).hide()
14
- .next('form').show().find('input[name=type]').val('string').end().find('input[name=name]').val('').focus()
15
-
16
- $('div.model a.close').on 'click', (ev) ->
105
+ target = $(ev.target)
106
+ name = target.find('input[name=name]').val()
107
+ return if name == ''
108
+
109
+ model = target.find('input[name=model]').val()
110
+ type = target.find('input[name=type]').val()
111
+ upsert_change 'add_column', model, "#{name}(#{type})", '', ''
112
+
113
+ name_span = $("<span/>", class: 'column_name_text')
114
+ .append(name)
115
+
116
+ type_span = $("<span/>", class: 'column_type_text')
117
+ .append(type)
118
+
119
+ li_node = $("<li/>", class: 'column')
120
+ .append(name_span)
121
+ .append("&nbsp;")
122
+ .append(type_span)
123
+
124
+ target.hide()
125
+ .parent()
126
+ .siblings('.columns')
127
+ .find('ul')
128
+ .append(li_node)
129
+ .end()
130
+ .end()
131
+ .find('a.add_column')
132
+ .show()
133
+
134
+ handle_change_column_type: (ev) ->
17
135
  ev.preventDefault()
18
- if confirm('remove this table?')
19
- [model_id, model_name] = [$(this).parent().attr('id'), $(this).parent().data('model_name')]
20
- upsert_change 'remove_model', model_name, '', '', ''
21
- $(this).parent().hide()
22
-
23
- $.each window.edges, (i, edge) ->
24
- window.edges.splice i, 1 if (edge.from == model_id) || (edge.to == model_id)
25
- window.paper.clear()
26
- connect_arrows(window.edges)
27
-
28
- $('div.model').draggable
29
- drag: (_event, _ui) ->
30
- model = $(this).data('model_name')
31
- from = $(this).data('original_position')
32
- to = [$(this).css('left').replace(/px$/, ''), $(this).css('top').replace(/px$/, '')].join()
33
- upsert_change 'move', model, '', '', to
34
- window.paper.clear()
35
- connect_arrows(window.edges)
36
-
37
- $('form.rename_model_form').on('submit', (ev) ->
136
+ target = $(ev.target)
137
+ to = target.find('input[name=to]').val()
138
+ return if to == ''
139
+
140
+ model = target.find('input[name=model]').val()
141
+ column = target.find('input[name=column]').val()
142
+ type = target.find('input[name=type]').val()
143
+ if to != type
144
+ upsert_change 'alter_column', model, column, type, to
145
+
146
+ target.hide()
147
+ .siblings('.column_type_text')
148
+ .text(to)
149
+ .show()
150
+
151
+ handle_rename_column: (ev) ->
38
152
  ev.preventDefault()
39
- to = $(this).find('input[name=to]').val()
153
+ target = $(ev.target)
154
+ to = target.find('input[name=to]').val()
155
+ return if to == ''
40
156
 
41
- if to != ''
42
- model = $(this).find('input[name=model]').val()
43
- if to != model
44
- upsert_change 'rename_model', model, '', model, to
157
+ model = target.find('input[name=model]').val()
158
+ column = target.find('input[name=column]').val()
159
+ if to != column
160
+ upsert_change 'rename_column', model, column, column, to
45
161
 
46
- $(this).hide().siblings('.model_name_text').text(to).show()
47
- )
162
+ target.hide()
163
+ .siblings('.column_name_text')
164
+ .text(to)
165
+ .show()
48
166
 
49
- $('form.rename_column_form').on('submit', (ev) ->
167
+ handle_rename_model: (ev) ->
50
168
  ev.preventDefault()
51
- to = $(this).find('input[name=to]').val()
169
+ target = $(ev.target)
170
+ to = target.find('input[name=to]').val()
171
+ return if to == ''
52
172
 
53
- if to != ''
54
- model = $(this).find('input[name=model]').val()
55
- column = $(this).find('input[name=column]').val()
56
- if to != column
57
- upsert_change 'rename_column', model, column, column, to
173
+ model = target.find('input[name=model]').val()
174
+ if to != model
175
+ upsert_change 'rename_model', model, '', model, to
58
176
 
59
- $(this).hide().siblings('.column_name_text').text(to).show()
60
- )
177
+ target.hide()
178
+ .siblings('.model_name_text')
179
+ .text(to)
180
+ .show()
61
181
 
62
- $('form.alter_column_form').on('submit', (ev) ->
182
+ handle_add_column_click: (ev) ->
63
183
  ev.preventDefault()
64
- to = $(this).find('input[name=to]').val()
65
-
66
- if to != ''
67
- model = $(this).find('input[name=model]').val()
68
- column = $(this).find('input[name=column]').val()
69
- type = $(this).find('input[name=type]').val()
70
- if to != type
71
- upsert_change 'alter_column', model, column, type, to
72
-
73
- $(this).hide().siblings('.column_type_text').text(to).show()
74
- )
75
-
76
- $('form.add_column_form').on('submit', (ev) ->
184
+ target = $(@)
185
+
186
+ m = target.parents('div.model')
187
+ if m.hasClass('noclick')
188
+ m.removeClass('noclick')
189
+ return false
190
+
191
+ target.hide()
192
+ .next('form')
193
+ .show()
194
+ .find('input[name=type]')
195
+ .val('string')
196
+ .end()
197
+ .find('input[name=name]')
198
+ .val('')
199
+ .focus()
200
+
201
+ handle_text_elem_click: (ev) ->
202
+ target = $(@)
203
+ text = target.text()
204
+
205
+ m = target.parents('div.model')
206
+ if m.hasClass('noclick')
207
+ m.removeClass('noclick')
208
+ return false
209
+
210
+ target.hide()
211
+ .next('form')
212
+ .show()
213
+ .find('input[name=to]')
214
+ .val(text)
215
+ .focus()
216
+
217
+ handle_remove_model_click: (ev) =>
77
218
  ev.preventDefault()
78
- name = $(this).find('input[name=name]').val()
79
219
 
80
- if name != ''
81
- model = $(this).find('input[name=model]').val()
82
- type = $(this).find('input[name=type]').val()
83
- upsert_change 'add_column', model, "#{name}(#{type})", '', ''
220
+ target = $(ev.target)
221
+ parent = target.parent()
84
222
 
85
- $(this).hide().parent().siblings('.columns').find('ul').append("<li class=\"column\"><span class=\"column_name_text\">#{name}</span>&nbsp;<span class=\"column_type_text\">#{type}</span></li>").end().end()
86
- .find('a.add_column').show()
87
- )
223
+ m = target.parents('div.model')
224
+ if m.hasClass('noclick')
225
+ m.removeClass('noclick')
226
+ return false
88
227
 
89
- $('#changes_form').on 'submit', (ev) ->
90
- j = '['
91
- rows = ($(tr).find('td') for tr in $('#changes > tbody > tr'))
92
- $(rows).each (i, row) ->
93
- j += "{\"action\": \"#{$(row[0]).html()}\", \"model\": \"#{$(row[1]).html()}\", \"column\": \"#{$(row[2]).html()}\", \"from\": \"#{$(row[3]).html()}\", \"to\": \"#{$(row[4]).html()}\"}"
94
- j += ',' if i < rows.length - 1
95
- j += ']'
96
- $('#changes_form').find('input[name=changes]').val(j)
228
+ return unless confirm('remove this table?')
97
229
 
98
- upsert_change = (action, model, column, from, to) ->
99
- rows = ($(tr).find('td') for tr in $('#changes > tbody > tr'))
100
- existing = null
101
- $(rows).each (i, row) ->
102
- existing = row if (action == $(row[0]).html()) && (model == $(row[1]).html()) && (column == $(row[2]).html())
103
- if existing == null
104
- $('#changes > tbody').append("<tr><td>#{action}</td><td>#{model}</td><td>#{column}</td><td>#{from}</td><td>#{to}</td></tr>")
105
- else
106
- $(existing[3]).text(from)
107
- $(existing[4]).text(to)
108
- $('#changes').show()
109
-
110
- positions = (div) ->
111
- [left, width, top, height] = [parseInt(div.css('left')), parseInt(div.css('width')), parseInt(div.css('top')), parseInt(div.css('height'))]
112
- {left: left, right: left + width, top: top, bottom: top + height, center: {x: (left + left + width) / 2, y: (top + top + height) / 2}, vertex: {}}
113
-
114
-
115
- window.connect_arrows = (edges) ->
116
- $.each(edges, (i, edge) ->
117
- window.connect_arrow $("##{edge.from}"), $("##{edge.to}")
118
- )
119
-
120
- window.connect_arrow = (from_elem, to_elem) ->
121
- #TODO handle self referential associations
122
- return if from_elem.attr('id') == to_elem.attr('id')
123
-
124
- from = positions(from_elem)
125
- to = positions(to_elem)
126
- #FIXME terrible code
127
- a = (to.center.y - from.center.y) / (to.center.x - from.center.x)
128
- b = from.center.y - from.center.x * a
129
-
130
- x2y = (x) -> ( a * x + b )
131
- y2x = (y) -> ( (y - b) / a )
132
-
133
- if from.center.x > to.center.x
134
- [from.vertex.x, from.vertex.y] = [from.left, x2y(from.left)]
135
- [to.vertex.x, to.vertex.y] = [to.right, x2y(to.right)]
136
- else
137
- [from.vertex.x, from.vertex.y] = [from.right, x2y(from.right)]
138
- [to.vertex.x, to.vertex.y] = [to.left, x2y(to.left)]
139
- for rect in [from, to]
140
- if rect.vertex.y < rect.top
141
- [rect.vertex.x, rect.vertex.y, rect.vertex.direction] = [y2x(rect.top), rect.top, 'v']
142
- else if rect.vertex.y > rect.bottom
143
- [rect.vertex.x, rect.vertex.y, rect.vertex.direction] = [y2x(rect.bottom), rect.bottom, 'v']
144
- else
145
- from.vertex.direction = 'h'
230
+ [model_id, model_name] = [parent.attr('id'), parent.data('model_name')]
231
+ upsert_change 'remove_model', model_name, '', '', ''
232
+ parent.hide()
233
+
234
+ $.each @edges, (i, edge) =>
235
+ @edges.splice i, 1 if (edge.from == model_id) || (edge.to == model_id)
236
+ @paper.clear()
237
+ @connect_arrows(@edges)
146
238
 
147
- if from.vertex.direction == 'h'
148
- path = "M#{parseInt(from.vertex.x)} #{parseInt(from.vertex.y)}H#{parseInt((from.vertex.x + to.vertex.x) / 2)} V#{parseInt(to.vertex.y)} H#{parseInt(to.vertex.x)}"
149
- else
150
- path = "M#{parseInt(from.vertex.x)} #{parseInt(from.vertex.y)}V#{parseInt((from.vertex.y + to.vertex.y) / 2)} H#{parseInt(to.vertex.x)} V#{parseInt(to.vertex.y)}"
239
+ $ ->
240
+ window.erd = new ERD('erd', $('#erd'), window.raw_edges)
151
241
 
152
- window.paper.path(path).attr({'stroke-width': 2, opacity: 0.5, 'arrow-end': 'classic-wide-long'})
@@ -2,5 +2,5 @@
2
2
  <%= render :partial => 'erd/erd/model', :collection => models -%>
3
3
  <svg width="<%= width %>pt" height="<%= height %>pt" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
4
4
  </svg>
5
- <script>$(function() { window.edges = <%= edges.to_json.html_safe %>; connect_arrows(window.edges)})</script>
5
+ <script>window.raw_edges = <%= edges.to_json.html_safe %>;</script>
6
6
  </div>
data/lib/erd/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Erd
2
- VERSION = '0.1.0'
2
+ VERSION = '0.1.1'
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: erd
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.1.1
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,11 +9,11 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-04-28 00:00:00.000000000 Z
12
+ date: 2012-04-30 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rails-erd
16
- requirement: &70264677495520 !ruby/object:Gem::Requirement
16
+ requirement: &70208383601640 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ! '>='
@@ -21,10 +21,10 @@ dependencies:
21
21
  version: 0.4.5
22
22
  type: :runtime
23
23
  prerelease: false
24
- version_requirements: *70264677495520
24
+ version_requirements: *70208383601640
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: nokogiri
27
- requirement: &70264677495100 !ruby/object:Gem::Requirement
27
+ requirement: &70208383631860 !ruby/object:Gem::Requirement
28
28
  none: false
29
29
  requirements:
30
30
  - - ! '>='
@@ -32,7 +32,7 @@ dependencies:
32
32
  version: '0'
33
33
  type: :runtime
34
34
  prerelease: false
35
- version_requirements: *70264677495100
35
+ version_requirements: *70208383631860
36
36
  description: erd engine on Rails
37
37
  email:
38
38
  - ronnie@dio.jp