kindred-rails 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +15 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +310 -0
- data/Rakefile +2 -0
- data/app/assets/javascripts/app.coffee +1 -0
- data/app/assets/javascripts/kindred.js +13 -0
- data/app/assets/javascripts/models/active_page.coffee +97 -0
- data/app/assets/javascripts/models/base.coffee +162 -0
- data/app/assets/javascripts/models/setup.coffee +115 -0
- data/app/assets/javascripts/utilities/binder.coffee +29 -0
- data/app/assets/javascripts/utilities/listener.coffee +74 -0
- data/app/assets/javascripts/utilities/logger.coffee +12 -0
- data/app/assets/javascripts/utilities/stack_trace.js +511 -0
- data/app/assets/javascripts/utilities/template.coffee +3 -0
- data/app/assets/javascripts/utilities/uuid.coffee +9 -0
- data/app/assets/javascripts/utilities/virtual_class.coffee +25 -0
- data/app/helpers/template_helper.rb +53 -0
- data/kindred.gemspec +23 -0
- data/lib/kindred/engine.rb +4 -0
- data/lib/kindred/version.rb +3 -0
- data/lib/kindred.rb +5 -0
- metadata +95 -0
@@ -0,0 +1,115 @@
|
|
1
|
+
class App.Setup
|
2
|
+
constructor: (@opts) ->
|
3
|
+
@_set_name_properties()
|
4
|
+
@_set_self()
|
5
|
+
@route ||= App[@constructor.name].route
|
6
|
+
@route ||= "/" + @snake_name + "s"
|
7
|
+
|
8
|
+
@opts ||= {}
|
9
|
+
|
10
|
+
if App[@constructor.name].relations?
|
11
|
+
@_setup_relationships()
|
12
|
+
|
13
|
+
@attributes = {}
|
14
|
+
template = @opts.template || App[@constructor.name].template
|
15
|
+
|
16
|
+
@_set_opts_to_attributes()
|
17
|
+
|
18
|
+
@uuid = @opts.uuid || @attributes.uuid || App.UUID.generate()
|
19
|
+
@id = @opts.id || @attributes.id
|
20
|
+
@target_uuid = @opts.target_uuid || @attributes.target_uuid
|
21
|
+
|
22
|
+
@attributes["uuid"] = @uuid
|
23
|
+
|
24
|
+
if template?
|
25
|
+
@template = template.replace(/\b(data-k-uuid)\.?[^\s|>]+/g, "data-k-uuid=" + @uuid)
|
26
|
+
@template = @template.replace(/\b(data-id)\.?[^\s|>]+/g, "data-id=" + @id)
|
27
|
+
@_build_attrs_template()
|
28
|
+
@_setup_interpolated_vars()
|
29
|
+
|
30
|
+
@has_many: (relation) ->
|
31
|
+
@relations ||= []
|
32
|
+
@relations.push({has_many: relation})
|
33
|
+
|
34
|
+
@set_class_name: (class_name) ->
|
35
|
+
@class_name = class_name
|
36
|
+
@dash_name = @_get_dash_name(class_name)
|
37
|
+
@snake_name = @_get_snake_name(class_name)
|
38
|
+
|
39
|
+
@_get_class_name: ->
|
40
|
+
@name
|
41
|
+
|
42
|
+
@_get_dash_name: (name) ->
|
43
|
+
dash_str = name.replace /([A-Z])/g, ($1) ->
|
44
|
+
"-" + $1.toLowerCase()
|
45
|
+
dash_str[1 .. dash_str.length - 1]
|
46
|
+
|
47
|
+
@_get_snake_name: (name) ->
|
48
|
+
under_str = name.replace /([A-Z])/g, ($1) ->
|
49
|
+
"_" + $1.toLowerCase()
|
50
|
+
under_str[1 .. under_str.length - 1]
|
51
|
+
|
52
|
+
_setup_relationships: =>
|
53
|
+
if App[@constructor.name].relations.length > 0
|
54
|
+
$.each App[@constructor.name].relations, (i, relation) =>
|
55
|
+
@[relation["has_many"]] = ->
|
56
|
+
$.ajax
|
57
|
+
type: "get"
|
58
|
+
url: "/kindred.json"
|
59
|
+
dataType: "json"
|
60
|
+
data: {
|
61
|
+
class_name: @class_name
|
62
|
+
id: @id
|
63
|
+
relation: relation["has_many"]
|
64
|
+
}
|
65
|
+
success: (data, textStatus, xhr) =>
|
66
|
+
console.log "success"
|
67
|
+
console.log data
|
68
|
+
error: (xhr) =>
|
69
|
+
console.log "error"
|
70
|
+
console.log xhr
|
71
|
+
|
72
|
+
_set_self: ->
|
73
|
+
@_self = @
|
74
|
+
|
75
|
+
_set_name_properties: =>
|
76
|
+
@class_name ||= App[@constructor.name].class_name
|
77
|
+
@dash_name = App[@constructor.name]._get_dash_name(@class_name)
|
78
|
+
@snake_name = App[@constructor.name].snake_name
|
79
|
+
|
80
|
+
_build_attrs_template: ->
|
81
|
+
$.each @attributes, (attr, val) =>
|
82
|
+
j_attr = $(@template).find("[data-k-uuid='" + @uuid + "'][data-attr='" + attr + "']")
|
83
|
+
clone = j_attr.clone()
|
84
|
+
|
85
|
+
replace_string = clone.wrap('<span/>').parent().html()
|
86
|
+
|
87
|
+
cloned_template = $(@template).clone()
|
88
|
+
updated_template = $("<div />").append($(@template).clone()).html()
|
89
|
+
|
90
|
+
if replace_string? && replace_string.length
|
91
|
+
replace_regex = new RegExp(replace_string)
|
92
|
+
|
93
|
+
new_attr_string = replace_string.replace(/\b(data-val)\.?[^\s]+/g, "data-val='" + val + "'")
|
94
|
+
|
95
|
+
@template = updated_template.replace(replace_regex, new_attr_string)
|
96
|
+
|
97
|
+
_setup_interpolated_vars: =>
|
98
|
+
template_match = new RegExp(/{{([^{}]+)}}/g)
|
99
|
+
|
100
|
+
new_template = @template.replace(template_match, (match, p1) =>
|
101
|
+
class_name = match.split(".")[0].substr(2)
|
102
|
+
attribute = match.split(".")[1].slice(0, - 2)
|
103
|
+
|
104
|
+
if class_name == @snake_name && (typeof @get(attribute) != 'undefined')
|
105
|
+
@get(attribute)
|
106
|
+
else
|
107
|
+
match
|
108
|
+
)
|
109
|
+
|
110
|
+
@template = new_template
|
111
|
+
|
112
|
+
_set_opts_to_attributes: ->
|
113
|
+
if @opts?
|
114
|
+
$.each @opts, (key, val) =>
|
115
|
+
@set key, val
|
@@ -0,0 +1,29 @@
|
|
1
|
+
App.DataBinder = (object_id, model_name) ->
|
2
|
+
# Use a jQuery object as simple PubSub
|
3
|
+
pubSub = jQuery({})
|
4
|
+
|
5
|
+
# We expect a `data` element specifying the binding
|
6
|
+
# in the form: data-bind-<object_id>="<property_name>"
|
7
|
+
data_attr = "input"
|
8
|
+
message = object_id + ":change"
|
9
|
+
|
10
|
+
jQuery(document).on "keydown", "[data-input]", (evt) ->
|
11
|
+
$input = jQuery(this)
|
12
|
+
pubSub.trigger message, [
|
13
|
+
$input.data(data_attr)
|
14
|
+
$input.val()
|
15
|
+
]
|
16
|
+
|
17
|
+
# PubSub propagates changes to all bound elements, setting value of
|
18
|
+
# input tags or HTML content of other tags
|
19
|
+
pubSub.on message, (evt, prop_name, new_val, id) ->
|
20
|
+
# model_name = "purchase-order"
|
21
|
+
model_elem = jQuery("[data-model-" + model_name + "=" + object_id + "]")
|
22
|
+
|
23
|
+
attr_elm = model_elem.find("[data-attr=" + prop_name + "]")
|
24
|
+
input_elm = $("[data-input=" + prop_name + "]")
|
25
|
+
|
26
|
+
input_elm.val new_val
|
27
|
+
attr_elm.html new_val
|
28
|
+
|
29
|
+
pubSub
|
@@ -0,0 +1,74 @@
|
|
1
|
+
class App.Listener
|
2
|
+
# Create a closure so that we can define intermediary
|
3
|
+
# method pointers that don't collide with other items
|
4
|
+
# in the global name space.
|
5
|
+
(->
|
6
|
+
# Store a reference to the original remove method.
|
7
|
+
originalOnMethod = jQuery.fn.on
|
8
|
+
|
9
|
+
# Define overriding method.
|
10
|
+
jQuery.fn.on = ->
|
11
|
+
if (jQuery.type( arguments[0] ) == "string")
|
12
|
+
listener_function = arguments[2]
|
13
|
+
element = arguments[1]
|
14
|
+
|
15
|
+
listener_namespace = arguments[0].split(".")
|
16
|
+
event_trigger = listener_namespace[0]
|
17
|
+
listener_name = listener_namespace[listener_namespace.length - 1]
|
18
|
+
namespaces = listener_namespace.slice(1, -1)
|
19
|
+
|
20
|
+
listener_info = {
|
21
|
+
trigger: event_trigger,
|
22
|
+
element: element,
|
23
|
+
name: listener_name,
|
24
|
+
funct: listener_function
|
25
|
+
}
|
26
|
+
|
27
|
+
App.Listener.createNestedObject(App, namespaces, listener_info)
|
28
|
+
|
29
|
+
# Execute the original method.
|
30
|
+
originalOnMethod.apply this, arguments
|
31
|
+
|
32
|
+
else
|
33
|
+
originalOnMethod.apply this, arguments
|
34
|
+
)()
|
35
|
+
|
36
|
+
@createNestedObject = (base, names, value) ->
|
37
|
+
|
38
|
+
# If a value is given, remove the last name and keep it for later:
|
39
|
+
lastName = (if arguments.length is 3 then names.pop() else false)
|
40
|
+
|
41
|
+
# Walk the hierarchy, creating new objects where needed.
|
42
|
+
# If the lastName was removed, then the last object is not set yet:
|
43
|
+
i = 0
|
44
|
+
|
45
|
+
while i < names.length
|
46
|
+
base = base[names[i]] = base[names[i]] or {}
|
47
|
+
i++
|
48
|
+
|
49
|
+
# If a value was given, set it to the last name:
|
50
|
+
if Array.isArray(base[lastName])
|
51
|
+
base[lastName].push(value)
|
52
|
+
else
|
53
|
+
base[lastName] = [value]
|
54
|
+
|
55
|
+
# Return the last object in the hierarchy:
|
56
|
+
base
|
57
|
+
|
58
|
+
@params: (obj) ->
|
59
|
+
# Stupid hack because jQuery converts data to camelCase
|
60
|
+
keys = Object.keys(obj)
|
61
|
+
n = keys.length
|
62
|
+
newobj = {}
|
63
|
+
while n--
|
64
|
+
key = keys[n]
|
65
|
+
|
66
|
+
if keys[n] == "kUuid"
|
67
|
+
snake_key = "uuid"
|
68
|
+
else
|
69
|
+
snake_key = key.replace(/([A-Z])/g, ($1) ->
|
70
|
+
"_" + $1.toLowerCase()
|
71
|
+
)
|
72
|
+
newobj[snake_key] = obj[key]
|
73
|
+
|
74
|
+
newobj
|
@@ -0,0 +1,12 @@
|
|
1
|
+
class App.Logger
|
2
|
+
@add_error: (error_object) ->
|
3
|
+
@errors ||= []
|
4
|
+
@errors.push(error_object)
|
5
|
+
|
6
|
+
jQueryInit = $.fn.init
|
7
|
+
$.fn.init = (selector, context) ->
|
8
|
+
element = new jQueryInit(selector, context)
|
9
|
+
if selector and element.length is 0
|
10
|
+
App.Logger.add_error({selector_not_found: selector, stack_trace: printStackTrace()})
|
11
|
+
|
12
|
+
element
|