chr 0.2.1 → 0.2.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +0 -1
- data/Gruntfile.coffee +50 -16
- data/app/assets/javascripts/chr.coffee +9 -16
- data/app/assets/javascripts/chr/core/chr.coffee +38 -20
- data/app/assets/javascripts/chr/core/item.coffee +30 -24
- data/app/assets/javascripts/chr/core/list.coffee +30 -60
- data/app/assets/javascripts/chr/core/list_config.coffee +65 -0
- data/app/assets/javascripts/chr/core/list_pagination.coffee +27 -0
- data/app/assets/javascripts/chr/core/list_reorder.coffee +75 -0
- data/app/assets/javascripts/chr/core/list_search.coffee +41 -0
- data/app/assets/javascripts/chr/core/module.coffee +55 -32
- data/app/assets/javascripts/chr/core/utils.coffee +34 -13
- data/app/assets/javascripts/chr/core/view.coffee +70 -97
- data/app/assets/javascripts/chr/form/form.coffee +63 -49
- data/app/assets/javascripts/chr/form/input-checkbox.coffee +40 -27
- data/app/assets/javascripts/chr/form/input-color.coffee +26 -8
- data/app/assets/javascripts/chr/form/input-date.coffee +0 -0
- data/app/assets/javascripts/chr/form/input-file.coffee +81 -46
- data/app/assets/javascripts/chr/form/input-form.coffee +162 -0
- data/app/assets/javascripts/chr/form/input-form_reorder.coffee +67 -0
- data/app/assets/javascripts/chr/form/input-hidden.coffee +27 -11
- data/app/assets/javascripts/chr/form/input-list.coffee +60 -56
- data/app/assets/javascripts/chr/form/input-list_reorder.coffee +37 -0
- data/app/assets/javascripts/chr/form/input-password.coffee +31 -0
- data/app/assets/javascripts/chr/form/input-select.coffee +61 -35
- data/app/assets/javascripts/chr/form/input-string.coffee +55 -25
- data/app/assets/javascripts/chr/form/input-text.coffee +22 -5
- data/app/assets/javascripts/chr/store/mongosteen-array-store.coffee +1 -1
- data/app/assets/javascripts/chr/vendor/ace.js +18280 -0
- data/app/assets/javascripts/chr/vendor/marked.js +1272 -0
- data/app/assets/javascripts/chr/vendor/mode-html.js +2436 -0
- data/app/assets/javascripts/chr/vendor/mode-markdown.js +2820 -0
- data/app/assets/javascripts/chr/vendor/redactor.fixedtoolbar.js +110 -0
- data/app/assets/javascripts/input-html.coffee +78 -0
- data/app/assets/javascripts/input-markdown.coffee +88 -0
- data/app/assets/javascripts/input-redactor.coffee +66 -0
- data/app/assets/stylesheets/_chr.scss +6 -6
- data/app/assets/stylesheets/_input-redactor.scss +34 -0
- data/app/assets/stylesheets/core/_mixins.scss +75 -0
- data/app/assets/stylesheets/form/_input-checkbox.scss +18 -0
- data/app/assets/stylesheets/form/{_input_color.scss → _input-color.scss} +0 -0
- data/app/assets/stylesheets/form/{_input_file.scss → _input-file.scss} +1 -0
- data/app/assets/stylesheets/form/{_nested_form.scss → _input-form.scss} +0 -0
- data/app/assets/stylesheets/form/{_input_list.scss → _input-list.scss} +0 -0
- data/app/assets/stylesheets/form/_input-string.scss +8 -0
- data/bower.json +3 -2
- data/{app/assets/javascripts/chr-dist.js → dist/chr.js} +1472 -1337
- data/dist/input-ace.js +24936 -0
- data/dist/input-redactor.js +156 -0
- data/lib/chr/version.rb +1 -1
- data/package.json +2 -2
- metadata +29 -13
- data/app/assets/javascripts/chr/core/list-pagination.coffee +0 -26
- data/app/assets/javascripts/chr/core/list-reorder.coffee +0 -70
- data/app/assets/javascripts/chr/core/list-search.coffee +0 -37
- data/app/assets/javascripts/chr/form/nested-form.coffee +0 -164
- data/app/assets/stylesheets/form/_input_checkbox.scss +0 -91
- data/app/assets/stylesheets/form/_input_string.scss +0 -8
@@ -0,0 +1,156 @@
|
|
1
|
+
/*
|
2
|
+
* webhook-redactor
|
3
|
+
*
|
4
|
+
*
|
5
|
+
* Copyright (c) 2014 Webhook
|
6
|
+
* Licensed under the MIT license.
|
7
|
+
*/
|
8
|
+
|
9
|
+
(function ($) {
|
10
|
+
"use strict";
|
11
|
+
|
12
|
+
// namespacing
|
13
|
+
var Fixedtoolbar = function (redactor) {
|
14
|
+
this.redactor = redactor;
|
15
|
+
this.$window = $('.view > form'); //$(window);
|
16
|
+
this.viewHeaderHeight = 40;
|
17
|
+
|
18
|
+
this.$window.on('scroll', $.proxy(this.checkOffset, this));
|
19
|
+
redactor.$box.on('scroll', $.proxy(this.checkOffset, this));
|
20
|
+
|
21
|
+
this.redactor.$editor.on('focus', $.proxy(function () {
|
22
|
+
this.isFocused = true;
|
23
|
+
}, this));
|
24
|
+
|
25
|
+
this.redactor.$editor.on('blur', $.proxy(function () {
|
26
|
+
this.isFocused = false;
|
27
|
+
}, this));
|
28
|
+
};
|
29
|
+
Fixedtoolbar.prototype = {
|
30
|
+
isFixed: false,
|
31
|
+
isFocused: false,
|
32
|
+
|
33
|
+
checkOffset: function () {
|
34
|
+
if ( !this.redactor.fullscreen.isOpen )
|
35
|
+
{
|
36
|
+
var boxOffset = this.redactor.$box.offset();
|
37
|
+
|
38
|
+
var isBelowBoxTop = boxOffset.top - this.viewHeaderHeight <= 0;
|
39
|
+
//var isAboveBoxBottom = boxOffset.top + this.redactor.$box.outerHeight() - this.redactor.$toolbar.outerHeight() - this.$window.scrollTop() >= 0;
|
40
|
+
var isAboveBoxBottom = this.redactor.$box.outerHeight() + boxOffset.top - this.viewHeaderHeight - this.redactor.$toolbar.outerHeight() >= 0;
|
41
|
+
|
42
|
+
if (isBelowBoxTop && isAboveBoxBottom) {
|
43
|
+
this.fix();
|
44
|
+
} else {
|
45
|
+
this.unfix();
|
46
|
+
}
|
47
|
+
}
|
48
|
+
},
|
49
|
+
|
50
|
+
fix: function () {
|
51
|
+
|
52
|
+
if (this.isFixed) {
|
53
|
+
|
54
|
+
// webkit does not recalc top: 0 when focused on contenteditable
|
55
|
+
if (this.redactor.utils.isMobile() && this.isFocused) {
|
56
|
+
this.redactor.$toolbar.css({
|
57
|
+
position: 'absolute',
|
58
|
+
top : this.$window.scrollTop() - this.redactor.$box.offset().top,
|
59
|
+
left : this.redactor.$box.offset().left
|
60
|
+
});
|
61
|
+
}
|
62
|
+
|
63
|
+
return;
|
64
|
+
}
|
65
|
+
|
66
|
+
var border_left = parseInt(this.redactor.$box.css('border-left-width').replace('px', ''), 10);
|
67
|
+
|
68
|
+
this.redactor.$toolbar.css({
|
69
|
+
position: 'fixed',
|
70
|
+
top : this.viewHeaderHeight,
|
71
|
+
left : this.redactor.$box.offset().left + border_left,
|
72
|
+
width : this.redactor.$box.width(),
|
73
|
+
zIndex : 300
|
74
|
+
});
|
75
|
+
|
76
|
+
this.redactor.$editor.css('padding-top', this.redactor.$toolbar.height() + 10);
|
77
|
+
|
78
|
+
this.isFixed = true;
|
79
|
+
|
80
|
+
},
|
81
|
+
|
82
|
+
unfix: function () {
|
83
|
+
if (!this.isFixed) {
|
84
|
+
return;
|
85
|
+
}
|
86
|
+
|
87
|
+
this.redactor.$toolbar.css({
|
88
|
+
position: 'relative',
|
89
|
+
left : '',
|
90
|
+
width : '',
|
91
|
+
top : ''
|
92
|
+
});
|
93
|
+
|
94
|
+
this.redactor.$editor.css('padding-top', 10);
|
95
|
+
|
96
|
+
this.isFixed = false;
|
97
|
+
}
|
98
|
+
};
|
99
|
+
|
100
|
+
// Hook up plugin to Redactor.
|
101
|
+
window.RedactorPlugins = window.RedactorPlugins || {};
|
102
|
+
window.RedactorPlugins.fixedtoolbar = function() {
|
103
|
+
return {
|
104
|
+
init: function () {
|
105
|
+
this.fixedtoolbar = new Fixedtoolbar(this);
|
106
|
+
}
|
107
|
+
};
|
108
|
+
};
|
109
|
+
|
110
|
+
}(jQuery));
|
111
|
+
|
112
|
+
var extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
|
113
|
+
hasProp = {}.hasOwnProperty;
|
114
|
+
|
115
|
+
this.InputRedactor = (function(superClass) {
|
116
|
+
extend(InputRedactor, superClass);
|
117
|
+
|
118
|
+
function InputRedactor() {
|
119
|
+
return InputRedactor.__super__.constructor.apply(this, arguments);
|
120
|
+
}
|
121
|
+
|
122
|
+
InputRedactor.prototype._add_input = function() {
|
123
|
+
this.$el.css('opacity', 0);
|
124
|
+
this.$input = $("<textarea class='redactor' name='" + this.name + "' rows=1>" + (this._safe_value()) + "</textarea>");
|
125
|
+
return this.$el.append(this.$input);
|
126
|
+
};
|
127
|
+
|
128
|
+
InputRedactor.prototype.initialize = function() {
|
129
|
+
var base, base1, redactor_options;
|
130
|
+
redactor_options = {
|
131
|
+
focus: false,
|
132
|
+
imageFloatMargin: '20px',
|
133
|
+
buttonSource: true,
|
134
|
+
pastePlainText: true,
|
135
|
+
plugins: ['fixedtoolbar', 'loft'],
|
136
|
+
buttons: ['html', 'formatting', 'bold', 'italic', 'deleted', 'alignment', 'unorderedlist', 'orderedlist', 'link']
|
137
|
+
};
|
138
|
+
if ((base = this.config).redactorOptions == null) {
|
139
|
+
base.redactorOptions = {};
|
140
|
+
}
|
141
|
+
$.extend(redactor_options, this.config.redactorOptions);
|
142
|
+
this.$input.redactor(redactor_options);
|
143
|
+
this.$el.css('opacity', 1);
|
144
|
+
return typeof (base1 = this.config).onInitialize === "function" ? base1.onInitialize(this) : void 0;
|
145
|
+
};
|
146
|
+
|
147
|
+
InputRedactor.prototype.updateValue = function(value) {
|
148
|
+
this.value = value;
|
149
|
+
return this.$input.redactor('insert.set', this._safe_value());
|
150
|
+
};
|
151
|
+
|
152
|
+
return InputRedactor;
|
153
|
+
|
154
|
+
})(InputString);
|
155
|
+
|
156
|
+
chr.formInputs['redactor'] = InputRedactor;
|
data/lib/chr/version.rb
CHANGED
data/package.json
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: chr
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Alexander Kravets
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-
|
11
|
+
date: 2015-04-05 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bourbon
|
@@ -68,38 +68,51 @@ files:
|
|
68
68
|
- LICENSE.md
|
69
69
|
- README.md
|
70
70
|
- Rakefile
|
71
|
-
- app/assets/javascripts/chr-dist.js
|
72
71
|
- app/assets/javascripts/chr.coffee
|
73
72
|
- app/assets/javascripts/chr/core/chr.coffee
|
74
73
|
- app/assets/javascripts/chr/core/item.coffee
|
75
|
-
- app/assets/javascripts/chr/core/list-pagination.coffee
|
76
|
-
- app/assets/javascripts/chr/core/list-reorder.coffee
|
77
|
-
- app/assets/javascripts/chr/core/list-search.coffee
|
78
74
|
- app/assets/javascripts/chr/core/list.coffee
|
75
|
+
- app/assets/javascripts/chr/core/list_config.coffee
|
76
|
+
- app/assets/javascripts/chr/core/list_pagination.coffee
|
77
|
+
- app/assets/javascripts/chr/core/list_reorder.coffee
|
78
|
+
- app/assets/javascripts/chr/core/list_search.coffee
|
79
79
|
- app/assets/javascripts/chr/core/module.coffee
|
80
80
|
- app/assets/javascripts/chr/core/utils.coffee
|
81
81
|
- app/assets/javascripts/chr/core/view.coffee
|
82
82
|
- app/assets/javascripts/chr/form/form.coffee
|
83
83
|
- app/assets/javascripts/chr/form/input-checkbox.coffee
|
84
84
|
- app/assets/javascripts/chr/form/input-color.coffee
|
85
|
+
- app/assets/javascripts/chr/form/input-date.coffee
|
85
86
|
- app/assets/javascripts/chr/form/input-file.coffee
|
87
|
+
- app/assets/javascripts/chr/form/input-form.coffee
|
88
|
+
- app/assets/javascripts/chr/form/input-form_reorder.coffee
|
86
89
|
- app/assets/javascripts/chr/form/input-hidden.coffee
|
87
90
|
- app/assets/javascripts/chr/form/input-list.coffee
|
91
|
+
- app/assets/javascripts/chr/form/input-list_reorder.coffee
|
92
|
+
- app/assets/javascripts/chr/form/input-password.coffee
|
88
93
|
- app/assets/javascripts/chr/form/input-select.coffee
|
89
94
|
- app/assets/javascripts/chr/form/input-string.coffee
|
90
95
|
- app/assets/javascripts/chr/form/input-text.coffee
|
91
|
-
- app/assets/javascripts/chr/form/nested-form.coffee
|
92
96
|
- app/assets/javascripts/chr/store/_array-store.coffee
|
93
97
|
- app/assets/javascripts/chr/store/_object-store.coffee
|
94
98
|
- app/assets/javascripts/chr/store/mongosteen-array-store.coffee
|
95
99
|
- app/assets/javascripts/chr/store/mongosteen-object-store.coffee
|
96
100
|
- app/assets/javascripts/chr/store/rest-array-store.coffee
|
97
101
|
- app/assets/javascripts/chr/store/rest-object-store.coffee
|
102
|
+
- app/assets/javascripts/chr/vendor/ace.js
|
98
103
|
- app/assets/javascripts/chr/vendor/jquery.scrollparent.js
|
99
104
|
- app/assets/javascripts/chr/vendor/jquery.textarea_autosize.js
|
100
105
|
- app/assets/javascripts/chr/vendor/jquery.typeahead.js
|
106
|
+
- app/assets/javascripts/chr/vendor/marked.js
|
107
|
+
- app/assets/javascripts/chr/vendor/mode-html.js
|
108
|
+
- app/assets/javascripts/chr/vendor/mode-markdown.js
|
109
|
+
- app/assets/javascripts/chr/vendor/redactor.fixedtoolbar.js
|
101
110
|
- app/assets/javascripts/chr/vendor/slip.js
|
111
|
+
- app/assets/javascripts/input-html.coffee
|
112
|
+
- app/assets/javascripts/input-markdown.coffee
|
113
|
+
- app/assets/javascripts/input-redactor.coffee
|
102
114
|
- app/assets/stylesheets/_chr.scss
|
115
|
+
- app/assets/stylesheets/_input-redactor.scss
|
103
116
|
- app/assets/stylesheets/core/_icons.scss
|
104
117
|
- app/assets/stylesheets/core/_list.scss
|
105
118
|
- app/assets/stylesheets/core/_main.scss
|
@@ -107,14 +120,17 @@ files:
|
|
107
120
|
- app/assets/stylesheets/core/_responsive.scss
|
108
121
|
- app/assets/stylesheets/core/_settings.scss
|
109
122
|
- app/assets/stylesheets/form/_form.scss
|
110
|
-
- app/assets/stylesheets/form/
|
111
|
-
- app/assets/stylesheets/form/
|
112
|
-
- app/assets/stylesheets/form/
|
113
|
-
- app/assets/stylesheets/form/
|
114
|
-
- app/assets/stylesheets/form/
|
115
|
-
- app/assets/stylesheets/form/
|
123
|
+
- app/assets/stylesheets/form/_input-checkbox.scss
|
124
|
+
- app/assets/stylesheets/form/_input-color.scss
|
125
|
+
- app/assets/stylesheets/form/_input-file.scss
|
126
|
+
- app/assets/stylesheets/form/_input-form.scss
|
127
|
+
- app/assets/stylesheets/form/_input-list.scss
|
128
|
+
- app/assets/stylesheets/form/_input-string.scss
|
116
129
|
- bower.json
|
117
130
|
- chr.gemspec
|
131
|
+
- dist/chr.js
|
132
|
+
- dist/input-ace.js
|
133
|
+
- dist/input-redactor.js
|
118
134
|
- docs/assets.md
|
119
135
|
- docs/basics.md
|
120
136
|
- docs/bootstrap-data.md
|
@@ -1,26 +0,0 @@
|
|
1
|
-
# -----------------------------------------------------------------------------
|
2
|
-
# LIST SCROLL
|
3
|
-
# todo:
|
4
|
-
# - trigger onScroll event only when scrolling down
|
5
|
-
# -----------------------------------------------------------------------------
|
6
|
-
@_listBindPagination = (listEl) ->
|
7
|
-
$container = listEl.$el
|
8
|
-
$list = listEl.$items
|
9
|
-
arrayStore = listEl.config.arrayStore
|
10
|
-
|
11
|
-
$list.scroll (e) =>
|
12
|
-
if ! arrayStore.dataFetchLock
|
13
|
-
$listChildren = $list.children()
|
14
|
-
listChildrenCount = $listChildren.length
|
15
|
-
listFirstChildHeight = $listChildren.first().outerHeight()
|
16
|
-
listHeight = listChildrenCount * listFirstChildHeight
|
17
|
-
viewHeight = $container.height()
|
18
|
-
|
19
|
-
if listHeight < (viewHeight + e.target.scrollTop + 100)
|
20
|
-
listEl._show_spinner()
|
21
|
-
arrayStore.load()
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
@@ -1,70 +0,0 @@
|
|
1
|
-
# -----------------------------------------------------------------------------
|
2
|
-
# LIST REORDER
|
3
|
-
# -----------------------------------------------------------------------------
|
4
|
-
# Dependencies:
|
5
|
-
# - slip
|
6
|
-
# -----------------------------------------------------------------------------
|
7
|
-
|
8
|
-
@_listBindReorder = (listEl) ->
|
9
|
-
items = listEl.items
|
10
|
-
list = listEl.$items.get(0)
|
11
|
-
arrayStore = listEl.config.arrayStore
|
12
|
-
|
13
|
-
config = arrayStore.reorderable
|
14
|
-
|
15
|
-
# this is optimistic scenario when assumes that all positions are different
|
16
|
-
_getObjectNewPosition = (el) ->
|
17
|
-
$el =$ el
|
18
|
-
|
19
|
-
nextObjectId = $el.next().attr('data-id')
|
20
|
-
prevObjectId = $el.prev().attr('data-id')
|
21
|
-
nextObjectPosition = 0
|
22
|
-
prevObjectPosition = 0
|
23
|
-
|
24
|
-
if prevObjectId
|
25
|
-
prevObjectPosition = items[prevObjectId].position()
|
26
|
-
|
27
|
-
if nextObjectId
|
28
|
-
nextObjectPosition = items[nextObjectId].position()
|
29
|
-
|
30
|
-
if arrayStore.sortReverse
|
31
|
-
newPosition = nextObjectPosition + Math.abs(nextObjectPosition - prevObjectPosition) / 2.0
|
32
|
-
else
|
33
|
-
newPosition = prevObjectPosition + Math.abs(nextObjectPosition - prevObjectPosition) / 2.0
|
34
|
-
|
35
|
-
return newPosition
|
36
|
-
|
37
|
-
new Slip(list)
|
38
|
-
|
39
|
-
list.addEventListener 'slip:beforeswipe', (e) -> e.preventDefault()
|
40
|
-
|
41
|
-
list.addEventListener 'slip:beforewait', ((e) ->
|
42
|
-
if $(e.target).hasClass("icon-reorder") then e.preventDefault()
|
43
|
-
), false
|
44
|
-
|
45
|
-
list.addEventListener 'slip:beforereorder', ((e) ->
|
46
|
-
if not $(e.target).hasClass("icon-reorder") then e.preventDefault()
|
47
|
-
), false
|
48
|
-
|
49
|
-
list.addEventListener 'slip:reorder', ((e) =>
|
50
|
-
# when `e.detail.insertBefore` is null, item put to the end of the list.
|
51
|
-
e.target.parentNode.insertBefore(e.target, e.detail.insertBefore)
|
52
|
-
|
53
|
-
objectPositionValue = _getObjectNewPosition(e.target)
|
54
|
-
objectId = $(e.target).attr('data-id')
|
55
|
-
value = {}
|
56
|
-
value["[#{arrayStore.sortBy}"] = "#{ objectPositionValue }"
|
57
|
-
|
58
|
-
arrayStore.update objectId, value,
|
59
|
-
# error handling
|
60
|
-
onSuccess: (object) => ;
|
61
|
-
onError: (errors) => ;
|
62
|
-
|
63
|
-
return false
|
64
|
-
), false
|
65
|
-
|
66
|
-
$(list).addClass 'reorderable'
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
@@ -1,37 +0,0 @@
|
|
1
|
-
# -----------------------------------------------------------------------------
|
2
|
-
# LIST SEARCH
|
3
|
-
# -----------------------------------------------------------------------------
|
4
|
-
@_listBindSearch = (listEl) ->
|
5
|
-
$input = listEl.$search
|
6
|
-
arrayStore = listEl.config.arrayStore
|
7
|
-
|
8
|
-
runSearch = (input) ->
|
9
|
-
query = $(input).val()
|
10
|
-
listEl._show_spinner()
|
11
|
-
arrayStore.search(query)
|
12
|
-
|
13
|
-
showSearch = ->
|
14
|
-
listEl.$el.addClass 'list-search'
|
15
|
-
$input.find('input').focus()
|
16
|
-
|
17
|
-
cancelSearch = ->
|
18
|
-
listEl.$el.removeClass 'list-search'
|
19
|
-
$input.find('input').val('')
|
20
|
-
listEl._show_spinner()
|
21
|
-
arrayStore.reset()
|
22
|
-
|
23
|
-
$input.show()
|
24
|
-
|
25
|
-
$input.on 'keyup', 'input', (e) =>
|
26
|
-
if e.keyCode == 27 # esc
|
27
|
-
return cancelSearch()
|
28
|
-
|
29
|
-
if e.keyCode == 13 # enter
|
30
|
-
return runSearch(e.target)
|
31
|
-
|
32
|
-
$input.on 'click', '.icon', (e) => e.preventDefault() ; showSearch()
|
33
|
-
$input.on 'click', '.cancel', (e) => e.preventDefault() ; cancelSearch()
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
@@ -1,164 +0,0 @@
|
|
1
|
-
# -----------------------------------------------------------------------------
|
2
|
-
# NESTED FORM
|
3
|
-
# -----------------------------------------------------------------------------
|
4
|
-
class @NestedForm
|
5
|
-
constructor: (@name, @nestedObjects, @config, @object) ->
|
6
|
-
@forms = []
|
7
|
-
|
8
|
-
@config.namePrefix ||= name
|
9
|
-
@config.removeButton = true
|
10
|
-
@config.formSchema.id = { type: 'hidden' }
|
11
|
-
@reorderContainerClass = "nested-forms-#{@config.klassName}"
|
12
|
-
|
13
|
-
if @config.sortBy
|
14
|
-
@config.formSchema[@config.sortBy] = { type: 'hidden' }
|
15
|
-
if @nestedObjects
|
16
|
-
# NOTE: this is not required but make things a bit easier on the backend
|
17
|
-
# as object don't have to be in a specific order.
|
18
|
-
@nestedObjects.sort (a, b) => parseFloat(a[@config.sortBy]) - parseFloat(b[@config.sortBy])
|
19
|
-
# NOTE: normalizes nested objects positions
|
20
|
-
(o[@config.sortBy] = parseInt(i) + 1) for i, o of @nestedObjects
|
21
|
-
|
22
|
-
@$el =$ "<div class='input-stacked nested-forms #{ @config.klassName }'>"
|
23
|
-
|
24
|
-
@_addLabel()
|
25
|
-
@_addForms()
|
26
|
-
@_addFormsReorder()
|
27
|
-
@_addNewButton()
|
28
|
-
|
29
|
-
return this
|
30
|
-
|
31
|
-
_addLabel: ->
|
32
|
-
if @config.klass in [ 'inline', 'stacked' ]
|
33
|
-
@$label =$ "<span class='label'>#{ @config.label }</span>"
|
34
|
-
@$el.append @$label
|
35
|
-
|
36
|
-
@$errorMessage =$ "<span class='error-message'></span>"
|
37
|
-
@$label.append @$errorMessage
|
38
|
-
|
39
|
-
_addForms: ->
|
40
|
-
@$forms =$ "<ul>"
|
41
|
-
@$el.append @$forms
|
42
|
-
|
43
|
-
# if not default value which means no objects
|
44
|
-
if @nestedObjects != ''
|
45
|
-
for i, object of @nestedObjects
|
46
|
-
namePrefix = "#{ @config.namePrefix }[#{ i }]"
|
47
|
-
@forms.push @_renderForm(object, namePrefix, @config)
|
48
|
-
|
49
|
-
_renderForm: (object, namePrefix, config) ->
|
50
|
-
formConfig = $.extend {}, config,
|
51
|
-
namePrefix: namePrefix
|
52
|
-
rootEl: "<li>"
|
53
|
-
|
54
|
-
form = new Form(object, formConfig)
|
55
|
-
@$forms.append form.$el
|
56
|
-
|
57
|
-
return form
|
58
|
-
|
59
|
-
_addFormsReorder: ->
|
60
|
-
if @config.sortBy
|
61
|
-
list = @$forms.addClass(@reorderContainerClass).get(0)
|
62
|
-
|
63
|
-
new Slip(list)
|
64
|
-
|
65
|
-
list.addEventListener 'slip:beforeswipe', (e) -> e.preventDefault()
|
66
|
-
|
67
|
-
list.addEventListener 'slip:beforewait', ((e) ->
|
68
|
-
if $(e.target).hasClass("icon-reorder") then e.preventDefault()
|
69
|
-
), false
|
70
|
-
|
71
|
-
list.addEventListener 'slip:beforereorder', ((e) ->
|
72
|
-
if not $(e.target).hasClass("icon-reorder") then e.preventDefault()
|
73
|
-
), false
|
74
|
-
|
75
|
-
list.addEventListener 'slip:reorder', ((e) =>
|
76
|
-
# NOTE: this event called for all parent lists, add a check for context:
|
77
|
-
# process this event only if target form is in the @forms list.
|
78
|
-
targetForm = @_findFormByTarget(e.target)
|
79
|
-
if targetForm
|
80
|
-
# NOTE: when `e.detail.insertBefore` is null, item put to the end of the list.
|
81
|
-
e.target.parentNode.insertBefore(e.target, e.detail.insertBefore)
|
82
|
-
|
83
|
-
$targetForm =$ e.target
|
84
|
-
prevForm = @_findFormByTarget($targetForm.prev().get(0))
|
85
|
-
nextForm = @_findFormByTarget($targetForm.next().get(0))
|
86
|
-
|
87
|
-
prevFormPosition = if prevForm then prevForm.inputs[@config.sortBy].value else 0
|
88
|
-
nextFormPosition = if nextForm then nextForm.inputs[@config.sortBy].value else 0
|
89
|
-
newTargetFormPosition = prevFormPosition + Math.abs(nextFormPosition - prevFormPosition) / 2.0
|
90
|
-
|
91
|
-
targetForm.inputs[@config.sortBy].updateValue(newTargetFormPosition)
|
92
|
-
|
93
|
-
return false
|
94
|
-
), false
|
95
|
-
|
96
|
-
@_addFormReorderButton(form) for form in @forms
|
97
|
-
|
98
|
-
_addFormReorderButton: (form) ->
|
99
|
-
form.$el.append("""<div class='icon-reorder' data-container-class='#{@reorderContainerClass}'></div>""").addClass('reorderable')
|
100
|
-
|
101
|
-
_findFormByTarget: (el) ->
|
102
|
-
if el
|
103
|
-
for form in @forms
|
104
|
-
if form.$el.get(0) == el then return form
|
105
|
-
return null
|
106
|
-
|
107
|
-
_addNewButton: ->
|
108
|
-
label = @config.newButtonLabel || "Add"
|
109
|
-
@$newButton =$ """<a href='#' class='nested-form-new'>#{ label }</a>"""
|
110
|
-
@$el.append @$newButton
|
111
|
-
@$newButton.on 'click', (e) => e.preventDefault() ; @addNewForm()
|
112
|
-
|
113
|
-
#
|
114
|
-
# PUBLIC
|
115
|
-
#
|
116
|
-
|
117
|
-
addNewForm: (object=null) ->
|
118
|
-
namePrefix = "#{ @config.namePrefix }[#{ Date.now() }]"
|
119
|
-
newFormConfig = $.extend({}, @config)
|
120
|
-
|
121
|
-
delete newFormConfig.formSchema.id
|
122
|
-
|
123
|
-
form = @_renderForm(object, namePrefix, newFormConfig)
|
124
|
-
form.initializePlugins()
|
125
|
-
|
126
|
-
if @config.sortBy
|
127
|
-
@_addFormReorderButton(form)
|
128
|
-
prevForm = _last(@forms)
|
129
|
-
position = if prevForm then prevForm.inputs[@config.sortBy].value + 1 else 1
|
130
|
-
form.inputs[@config.sortBy].updateValue(position)
|
131
|
-
|
132
|
-
@forms.push(form)
|
133
|
-
|
134
|
-
@config.onNew?(form)
|
135
|
-
|
136
|
-
return form
|
137
|
-
|
138
|
-
initialize: ->
|
139
|
-
for nestedForm in @forms
|
140
|
-
nestedForm.initializePlugins()
|
141
|
-
@config.onInitialize?(this)
|
142
|
-
|
143
|
-
showErrorMessage: (message) ->
|
144
|
-
@$el.addClass 'error'
|
145
|
-
@$errorMessage.html(message)
|
146
|
-
|
147
|
-
hideErrorMessage: ->
|
148
|
-
@$el.removeClass 'error'
|
149
|
-
@$errorMessage.html('')
|
150
|
-
|
151
|
-
updateValue: (@value) ->
|
152
|
-
# TODO: update
|
153
|
-
|
154
|
-
hash: (hash={})->
|
155
|
-
hash[@config.klassName] = []
|
156
|
-
for form in @forms
|
157
|
-
hash[@config.klassName].push form.hash()
|
158
|
-
return hash
|
159
|
-
|
160
|
-
_chrFormInputs['form'] = NestedForm
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|