kindred 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/.gitignore +15 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +316 -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 +153 -0
- data/app/assets/javascripts/models/setup.coffee +97 -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 +59 -0
- data/kindred.gemspec +26 -0
- data/lib/kindred/engine.rb +8 -0
- data/lib/kindred/version.rb +3 -0
- data/lib/kindred.rb +5 -0
- metadata +123 -0
@@ -0,0 +1,97 @@
|
|
1
|
+
class App.Setup
|
2
|
+
constructor: (@opts) ->
|
3
|
+
@_set_name_properties()
|
4
|
+
@_set_self()
|
5
|
+
|
6
|
+
@opts ||= {}
|
7
|
+
|
8
|
+
@attributes = {}
|
9
|
+
template = @opts.template || App[@constructor.name].template
|
10
|
+
|
11
|
+
@_set_opts_to_attributes()
|
12
|
+
|
13
|
+
@_setup_route()
|
14
|
+
|
15
|
+
@uuid = @opts.uuid || @attributes.uuid || App.UUID.generate()
|
16
|
+
@id = @opts.id || @attributes.id
|
17
|
+
@target_uuid = @opts.target_uuid || @attributes.target_uuid
|
18
|
+
|
19
|
+
@attributes["uuid"] = @uuid
|
20
|
+
|
21
|
+
if template?
|
22
|
+
@template = template.replace(/\b(data-k-uuid)\.?[^\s|>]+/g, "data-k-uuid=" + @uuid)
|
23
|
+
@template = @template.replace(/\b(data-id)\.?[^\s|>]+/g, "data-id=" + @id)
|
24
|
+
@_build_attrs_template()
|
25
|
+
@_setup_interpolated_vars()
|
26
|
+
|
27
|
+
@set_class_name: (class_name) ->
|
28
|
+
@class_name = class_name
|
29
|
+
@dash_name = @_get_dash_name(class_name)
|
30
|
+
@snake_name = @_get_snake_name(class_name)
|
31
|
+
|
32
|
+
@_get_class_name: ->
|
33
|
+
@name
|
34
|
+
|
35
|
+
@_get_dash_name: (name) ->
|
36
|
+
dash_str = name.replace /([A-Z])/g, ($1) ->
|
37
|
+
"-" + $1.toLowerCase()
|
38
|
+
dash_str[1 .. dash_str.length - 1]
|
39
|
+
|
40
|
+
@_get_snake_name: (name) ->
|
41
|
+
under_str = name.replace /([A-Z])/g, ($1) ->
|
42
|
+
"_" + $1.toLowerCase()
|
43
|
+
under_str[1 .. under_str.length - 1]
|
44
|
+
|
45
|
+
_set_self: ->
|
46
|
+
@_self = @
|
47
|
+
|
48
|
+
_set_name_properties: =>
|
49
|
+
@class_name ||= App[@constructor.name].class_name
|
50
|
+
@dash_name = App[@constructor.name]._get_dash_name(@class_name)
|
51
|
+
@snake_name = App[@constructor.name].snake_name
|
52
|
+
|
53
|
+
_build_attrs_template: ->
|
54
|
+
$.each @attributes, (attr, val) =>
|
55
|
+
j_attr = $(@template).find("[data-k-uuid='" + @uuid + "'][data-attr='" + attr + "']")
|
56
|
+
clone = j_attr.clone()
|
57
|
+
|
58
|
+
replace_string = clone.wrap('<span/>').parent().html()
|
59
|
+
|
60
|
+
cloned_template = $(@template).clone()
|
61
|
+
updated_template = $("<div />").append($(@template).clone()).html()
|
62
|
+
|
63
|
+
if replace_string? && replace_string.length
|
64
|
+
replace_regex = new RegExp(replace_string)
|
65
|
+
|
66
|
+
new_attr_string = replace_string.replace(/\b(data-val)\.?[^\s]+/g, "data-val='" + val + "'")
|
67
|
+
|
68
|
+
@template = updated_template.replace(replace_regex, new_attr_string)
|
69
|
+
|
70
|
+
_setup_interpolated_vars: =>
|
71
|
+
template_match = new RegExp(/{{([^{}]+)}}/g)
|
72
|
+
|
73
|
+
new_template = @template.replace(template_match, (match, p1) =>
|
74
|
+
class_name = match.split(".")[0].substr(2)
|
75
|
+
attribute = match.split(".")[1].slice(0, - 2)
|
76
|
+
|
77
|
+
if class_name == @snake_name && (typeof @get(attribute) != 'undefined')
|
78
|
+
@get(attribute)
|
79
|
+
else
|
80
|
+
match
|
81
|
+
)
|
82
|
+
|
83
|
+
@template = new_template
|
84
|
+
|
85
|
+
_set_opts_to_attributes: ->
|
86
|
+
if @opts?
|
87
|
+
$.each @opts, (key, val) =>
|
88
|
+
@set key, val
|
89
|
+
|
90
|
+
_setup_route: =>
|
91
|
+
url_match = new RegExp(/{{([^{}]+)}}/g)
|
92
|
+
@route ||= App[@constructor.name].route
|
93
|
+
@route ||= "/" + @snake_name + "s"
|
94
|
+
@route = @route.replace(url_match, (match, p1) =>
|
95
|
+
attribute = match.slice(2, - 2)
|
96
|
+
@get(attribute)
|
97
|
+
)
|
@@ -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
|