Show More
@@ -0,0 +1,91 b'' | |||||
|
1 | .deform { | |||
|
2 | ||||
|
3 | * { | |||
|
4 | box-sizing: border-box; | |||
|
5 | } | |||
|
6 | ||||
|
7 | .required:after { | |||
|
8 | color: #e32; | |||
|
9 | content: '*'; | |||
|
10 | display:inline; | |||
|
11 | } | |||
|
12 | ||||
|
13 | .control-label { | |||
|
14 | width: 200px; | |||
|
15 | float: left; | |||
|
16 | } | |||
|
17 | .control-inputs { | |||
|
18 | width: 400px; | |||
|
19 | float: left; | |||
|
20 | } | |||
|
21 | .form-group .radio, .form-group .checkbox { | |||
|
22 | position: relative; | |||
|
23 | display: block; | |||
|
24 | /* margin-bottom: 10px; */ | |||
|
25 | } | |||
|
26 | ||||
|
27 | .form-group { | |||
|
28 | clear: left; | |||
|
29 | } | |||
|
30 | ||||
|
31 | .form-control { | |||
|
32 | width: 100%; | |||
|
33 | } | |||
|
34 | ||||
|
35 | .error-block { | |||
|
36 | color: red; | |||
|
37 | } | |||
|
38 | ||||
|
39 | .deform-seq-container .control-inputs { | |||
|
40 | width: 100%; | |||
|
41 | } | |||
|
42 | ||||
|
43 | .deform-seq-container .deform-seq-item-handle { | |||
|
44 | width: 8.3%; | |||
|
45 | float: left; | |||
|
46 | } | |||
|
47 | ||||
|
48 | .deform-seq-container .deform-seq-item-group { | |||
|
49 | width: 91.6%; | |||
|
50 | float: left; | |||
|
51 | } | |||
|
52 | ||||
|
53 | .form-control { | |||
|
54 | input { | |||
|
55 | height: 40px; | |||
|
56 | } | |||
|
57 | input[type=checkbox], input[type=radio] { | |||
|
58 | height: auto; | |||
|
59 | } | |||
|
60 | select { | |||
|
61 | height: 40px; | |||
|
62 | } | |||
|
63 | } | |||
|
64 | ||||
|
65 | .form-control.select2-container { height: 40px; } | |||
|
66 | ||||
|
67 | .deform-two-field-sequence .deform-seq-container .deform-seq-item label { | |||
|
68 | display: none; | |||
|
69 | } | |||
|
70 | .deform-two-field-sequence .deform-seq-container .deform-seq-item:first-child label { | |||
|
71 | display: block; | |||
|
72 | } | |||
|
73 | .deform-two-field-sequence .deform-seq-container .deform-seq-item .panel-heading { | |||
|
74 | display: none; | |||
|
75 | } | |||
|
76 | .deform-two-field-sequence .deform-seq-container .deform-seq-item.form-group { | |||
|
77 | background: red; | |||
|
78 | } | |||
|
79 | .deform-two-field-sequence .deform-seq-container .deform-seq-item .deform-seq-item-group .form-group { | |||
|
80 | width: 45%; padding: 0 2px; float: left; clear: none; | |||
|
81 | } | |||
|
82 | .deform-two-field-sequence .deform-seq-container .deform-seq-item .deform-seq-item-group > .panel { | |||
|
83 | padding: 0; | |||
|
84 | margin: 5px 0; | |||
|
85 | border: none; | |||
|
86 | } | |||
|
87 | .deform-two-field-sequence .deform-seq-container .deform-seq-item .deform-seq-item-group > .panel > .panel-body { | |||
|
88 | padding: 0; | |||
|
89 | } | |||
|
90 | ||||
|
91 | } |
@@ -0,0 +1,20 b'' | |||||
|
1 | <div class="checkbox"> | |||
|
2 | <input tal:define="name name|field.name; | |||
|
3 | true_val true_val|field.widget.true_val; | |||
|
4 | css_class css_class|field.widget.css_class; | |||
|
5 | style style|field.widget.style; | |||
|
6 | oid oid|field.oid" | |||
|
7 | type="checkbox" | |||
|
8 | name="${name}" value="${true_val}" | |||
|
9 | id="${oid}" | |||
|
10 | tal:attributes="checked cstruct == true_val; | |||
|
11 | class css_class; | |||
|
12 | style style;" /> | |||
|
13 | ||||
|
14 | <label for="${field.oid}"> | |||
|
15 | <span tal:condition="hasattr(field, 'schema') and hasattr(field.schema, 'label')" | |||
|
16 | tal:replace="field.schema.label" class="checkbox-label" > | |||
|
17 | </span> | |||
|
18 | ||||
|
19 | </label> | |||
|
20 | </div> No newline at end of file |
@@ -0,0 +1,25 b'' | |||||
|
1 | <div tal:define="css_class css_class|field.widget.css_class; | |||
|
2 | style style|field.widget.style; | |||
|
3 | oid oid|field.oid; | |||
|
4 | inline getattr(field.widget, 'inline', False)" | |||
|
5 | tal:omit-tag="not inline"> | |||
|
6 | ${field.start_sequence()} | |||
|
7 | <div tal:repeat="choice values | field.widget.values" | |||
|
8 | tal:omit-tag="inline" | |||
|
9 | class="checkbox"> | |||
|
10 | <div tal:define="(value, title) choice"> | |||
|
11 | <input tal:attributes="checked value in cstruct; | |||
|
12 | class css_class; | |||
|
13 | style style" | |||
|
14 | type="checkbox" | |||
|
15 | name="checkbox" | |||
|
16 | value="${value}" | |||
|
17 | id="${oid}-${repeat.choice.index}"/> | |||
|
18 | <label for="${oid}-${repeat.choice.index}" | |||
|
19 | tal:attributes="class inline and 'checkbox-inline'"> | |||
|
20 | ${title} | |||
|
21 | </label> | |||
|
22 | </div> | |||
|
23 | </div> | |||
|
24 | ${field.end_sequence()} | |||
|
25 | </div> No newline at end of file |
@@ -0,0 +1,100 b'' | |||||
|
1 | <form | |||
|
2 | tal:define="style style|field.widget.style; | |||
|
3 | css_class css_class|string:${field.widget.css_class or field.css_class or ''}; | |||
|
4 | item_template item_template|field.widget.item_template; | |||
|
5 | autocomplete autocomplete|field.autocomplete; | |||
|
6 | title title|field.title; | |||
|
7 | errormsg errormsg|field.errormsg; | |||
|
8 | description description|field.description; | |||
|
9 | buttons buttons|field.buttons; | |||
|
10 | use_ajax use_ajax|field.use_ajax; | |||
|
11 | ajax_options ajax_options|field.ajax_options; | |||
|
12 | formid formid|field.formid; | |||
|
13 | action action|field.action or None; | |||
|
14 | method method|field.method;" | |||
|
15 | tal:attributes="autocomplete autocomplete; | |||
|
16 | style style; | |||
|
17 | class css_class; | |||
|
18 | action action;" | |||
|
19 | id="${formid}" | |||
|
20 | method="${method}" | |||
|
21 | enctype="multipart/form-data" | |||
|
22 | accept-charset="utf-8" | |||
|
23 | i18n:domain="deform" | |||
|
24 | > | |||
|
25 | ||||
|
26 | <fieldset class="deform-form-fieldset"> | |||
|
27 | ||||
|
28 | <legend tal:condition="title">${title}</legend> | |||
|
29 | ||||
|
30 | <input type="hidden" name="${h.csrf_token_key}" value="${h.get_csrf_token()}" /> | |||
|
31 | <input type="hidden" name="_charset_" /> | |||
|
32 | <input type="hidden" name="__formid__" value="${formid}"/> | |||
|
33 | ||||
|
34 | <!-- | |||
|
35 | <div class="alert alert-danger" tal:condition="field.error"> | |||
|
36 | <div class="error-msg-lbl" i18n:translate="" | |||
|
37 | >There was a problem with your submission</div> | |||
|
38 | <div class="error-msg-detail" i18n:translate="" | |||
|
39 | >Errors have been highlighted below</div> | |||
|
40 | <p class="error-msg">${field.errormsg}</p> | |||
|
41 | </div> | |||
|
42 | --> | |||
|
43 | ||||
|
44 | <p class="section first" tal:condition="description"> | |||
|
45 | ${description} | |||
|
46 | </p> | |||
|
47 | ||||
|
48 | <div tal:repeat="child field" | |||
|
49 | tal:replace="structure child.render_template(item_template)"/> | |||
|
50 | ||||
|
51 | <div class="form-group"> | |||
|
52 | <tal:loop tal:repeat="button buttons"> | |||
|
53 | <button | |||
|
54 | tal:define="btn_disposition repeat.button.start and 'btn-primary' or (button.name == 'delete' and 'btn-danger' or 'btn-default'); | |||
|
55 | btn_icon button.icon|None" | |||
|
56 | tal:attributes="disabled button.disabled if button.disabled else None" | |||
|
57 | id="${formid+button.name}" | |||
|
58 | name="${button.name}" | |||
|
59 | type="${button.type}" | |||
|
60 | class="btn ${button.css_class or btn_disposition}" | |||
|
61 | value="${button.value}"> | |||
|
62 | <i tal:condition="btn_icon" class="${btn_icon}"> </i> | |||
|
63 | ${button.title} | |||
|
64 | </button> | |||
|
65 | </tal:loop> | |||
|
66 | </div> | |||
|
67 | ||||
|
68 | </fieldset> | |||
|
69 | ||||
|
70 | <script type="text/javascript" tal:condition="use_ajax"> | |||
|
71 | deform.addCallback( | |||
|
72 | '${formid}', | |||
|
73 | function(oid) { | |||
|
74 | var target = '#' + oid; | |||
|
75 | var options = { | |||
|
76 | target: target, | |||
|
77 | replaceTarget: true, | |||
|
78 | success: function() { | |||
|
79 | deform.processCallbacks(); | |||
|
80 | deform.focusFirstInput(target); | |||
|
81 | }, | |||
|
82 | beforeSerialize: function() { | |||
|
83 | // See http://bit.ly/1agBs9Z (hack to fix tinymce-related ajax bug) | |||
|
84 | if ('tinymce' in window) { | |||
|
85 | $(tinymce.get()).each( | |||
|
86 | function(i, el) { | |||
|
87 | var content = el.getContent(); | |||
|
88 | var editor_input = document.getElementById(el.id); | |||
|
89 | editor_input.value = content; | |||
|
90 | }); | |||
|
91 | } | |||
|
92 | } | |||
|
93 | }; | |||
|
94 | var extra_options = ${ajax_options} || {}; | |||
|
95 | $('#' + oid).ajaxForm($.extend(options, extra_options)); | |||
|
96 | } | |||
|
97 | ); | |||
|
98 | </script> | |||
|
99 | ||||
|
100 | </form> No newline at end of file |
@@ -0,0 +1,33 b'' | |||||
|
1 | <tal:def tal:define="title title|field.title; | |||
|
2 | description description|field.description; | |||
|
3 | errormsg errormsg|field.errormsg; | |||
|
4 | item_template item_template|field.widget.item_template" | |||
|
5 | i18n:domain="deform"> | |||
|
6 | ||||
|
7 | <div class="panel panel-default"> | |||
|
8 | <div class="panel-heading">${title}</div> | |||
|
9 | <div class="panel-body"> | |||
|
10 | ||||
|
11 | <div tal:condition="errormsg" | |||
|
12 | class="clearfix alert alert-danger"> | |||
|
13 | <p i18n:translate=""> | |||
|
14 | There was a problem with this section | |||
|
15 | </p> | |||
|
16 | <p>${errormsg}</p> | |||
|
17 | </div> | |||
|
18 | ||||
|
19 | <div tal:condition="description"> | |||
|
20 | ${description} | |||
|
21 | </div> | |||
|
22 | ||||
|
23 | ${field.start_mapping()} | |||
|
24 | <div tal:repeat="child field.children" | |||
|
25 | tal:replace="structure child.render_template(item_template)" > | |||
|
26 | </div> | |||
|
27 | ${field.end_mapping()} | |||
|
28 | ||||
|
29 | <div style="clear: both"></div> | |||
|
30 | </div> | |||
|
31 | </div> | |||
|
32 | ||||
|
33 | </tal:def> No newline at end of file |
@@ -0,0 +1,47 b'' | |||||
|
1 | <div tal:define="error_class error_class|field.widget.error_class; | |||
|
2 | description description|field.description; | |||
|
3 | title title|field.title; | |||
|
4 | oid oid|field.oid; | |||
|
5 | hidden hidden|field.widget.hidden; | |||
|
6 | category category|field.widget.category; | |||
|
7 | structural hidden or category == 'structural'; | |||
|
8 | required required|field.required;" | |||
|
9 | class="form-group ${field.error and 'has-error' or ''} ${field.widget.item_css_class or ''}" | |||
|
10 | id="item-${oid}" | |||
|
11 | tal:omit-tag="structural" | |||
|
12 | i18n:domain="deform"> | |||
|
13 | ||||
|
14 | <label for="${oid}" | |||
|
15 | class="control-label ${required and 'required' or ''}" | |||
|
16 | tal:condition="not structural" | |||
|
17 | id="req-${oid}" | |||
|
18 | > | |||
|
19 | ${title} | |||
|
20 | </label> | |||
|
21 | <div class="control-inputs"> | |||
|
22 | <div tal:define="input_prepend field.widget.input_prepend | None; | |||
|
23 | input_append field.widget.input_append | None" | |||
|
24 | tal:omit-tag="not (input_prepend or input_append)" | |||
|
25 | class="input-group"> | |||
|
26 | <span class="input-group-addon" | |||
|
27 | tal:condition="input_prepend">${input_prepend}</span | |||
|
28 | ><span tal:replace="structure field.serialize(cstruct).strip()" | |||
|
29 | /><span class="input-group-addon" | |||
|
30 | tal:condition="input_append">${input_append}</span> | |||
|
31 | </div> | |||
|
32 | <p class="help-block error-block" | |||
|
33 | tal:define="errstr 'error-%s' % field.oid" | |||
|
34 | tal:repeat="msg field.error.messages()" | |||
|
35 | i18n:translate="" | |||
|
36 | tal:attributes="id repeat.msg.index==0 and errstr or | |||
|
37 | ('%s-%s' % (errstr, repeat.msg.index))" | |||
|
38 | tal:condition="field.error and not field.widget.hidden and not field.typ.__class__.__name__=='Mapping'"> | |||
|
39 | ${msg} | |||
|
40 | </p> | |||
|
41 | ||||
|
42 | <p tal:condition="field.description and not field.widget.hidden" | |||
|
43 | class="help-block" > | |||
|
44 | ${field.description} | |||
|
45 | </p> | |||
|
46 | </div> | |||
|
47 | </div> No newline at end of file |
@@ -0,0 +1,24 b'' | |||||
|
1 | <div tal:define=" | |||
|
2 | item_tmpl item_template|field.widget.readonly_item_template; | |||
|
3 | oid oid|field.oid; | |||
|
4 | name name|field.name; | |||
|
5 | title title|field.title;" | |||
|
6 | class="deform-seq" | |||
|
7 | id="${oid}"> | |||
|
8 | ||||
|
9 | <div class="panel panel-default"> | |||
|
10 | <div class="panel-heading">${title}</div> | |||
|
11 | <div class="panel-body"> | |||
|
12 | ||||
|
13 | <div class="deform-seq-container"> | |||
|
14 | <div tal:define="subfields [ x[1] for x in subfields ]" | |||
|
15 | tal:repeat="subfield subfields" | |||
|
16 | tal:replace="structure subfield.render_template(item_tmpl, | |||
|
17 | parent=field)" /> | |||
|
18 | </div> | |||
|
19 | ||||
|
20 | <div style="clear: both"></div> | |||
|
21 | </div> | |||
|
22 | ||||
|
23 | </div> | |||
|
24 | </div> No newline at end of file |
@@ -0,0 +1,11 b'' | |||||
|
1 | <div tal:omit-tag="field.widget.hidden" | |||
|
2 | tal:define=" | |||
|
3 | hidden hidden|field.widget.hidden; | |||
|
4 | description description|field.description;" | |||
|
5 | title="${description}" | |||
|
6 | class="form-group row deform-seq-item ${field.error and error_class or ''} ${field.widget.item_css_class or ''}" | |||
|
7 | i18n:domain="deform"> | |||
|
8 | <div class="deform-seq-item-group"> | |||
|
9 | <span tal:replace="structure field.serialize(cstruct, readonly=True)"/> | |||
|
10 | </div> | |||
|
11 | </div> |
@@ -0,0 +1,55 b'' | |||||
|
1 | <div tal:define=" | |||
|
2 | name name|field.name; | |||
|
3 | style field.widget.style; | |||
|
4 | oid oid|field.oid; | |||
|
5 | css_class css_class|field.widget.css_class; | |||
|
6 | optgroup_class optgroup_class|field.widget.optgroup_class; | |||
|
7 | multiple multiple|field.widget.multiple;" | |||
|
8 | tal:omit-tag=""> | |||
|
9 | <input type="hidden" name="__start__" value="${name}:sequence" | |||
|
10 | tal:condition="multiple" /> | |||
|
11 | ||||
|
12 | <select tal:attributes=" | |||
|
13 | name name; | |||
|
14 | id oid; | |||
|
15 | class string: form-control ${css_class or ''}; | |||
|
16 | data-placeholder field.widget.placeholder|None; | |||
|
17 | multiple multiple; | |||
|
18 | style style;"> | |||
|
19 | <tal:loop tal:repeat="item values"> | |||
|
20 | <optgroup tal:condition="isinstance(item, optgroup_class)" | |||
|
21 | tal:attributes="label item.label"> | |||
|
22 | <option tal:repeat="(value, description) item.options" | |||
|
23 | tal:attributes=" | |||
|
24 | selected (multiple and value in list(map(unicode, cstruct)) or value == list(map(unicode, cstruct))) and 'selected'; | |||
|
25 | class css_class; | |||
|
26 | label field.widget.long_label_generator and description; | |||
|
27 | value value" | |||
|
28 | tal:content="field.widget.long_label_generator and field.widget.long_label_generator(item.label, description) or description"/> | |||
|
29 | </optgroup> | |||
|
30 | <option tal:condition="not isinstance(item, optgroup_class)" | |||
|
31 | tal:attributes=" | |||
|
32 | selected (multiple and item[0] in list(map(unicode, cstruct)) or item[0] == unicode(cstruct)) and 'selected'; | |||
|
33 | class css_class; | |||
|
34 | value item[0]">${item[1]}</option> | |||
|
35 | </tal:loop> | |||
|
36 | </select> | |||
|
37 | ||||
|
38 | <script type="text/javascript"> | |||
|
39 | deform.addCallback( | |||
|
40 | '${field.oid}', | |||
|
41 | function(oid) { | |||
|
42 | $('#' + oid).select2({ | |||
|
43 | containerCssClass: 'form-control drop-menu', | |||
|
44 | dropdownCssClass: 'drop-menu-dropdown', | |||
|
45 | dropdownAutoWidth: true, | |||
|
46 | placeholder: "${str(field.widget.placeholder).replace('"','\\"')|""}", | |||
|
47 | allowClear: true | |||
|
48 | }); | |||
|
49 | } | |||
|
50 | ); | |||
|
51 | </script> | |||
|
52 | ||||
|
53 | <input type="hidden" name="__end__" value="${name}:sequence" | |||
|
54 | tal:condition="multiple" /> | |||
|
55 | </div> No newline at end of file |
@@ -0,0 +1,105 b'' | |||||
|
1 | <div tal:define="item_tmpl item_template|field.widget.item_template; | |||
|
2 | oid oid|field.oid; | |||
|
3 | name name|field.name; | |||
|
4 | min_len min_len|field.widget.min_len; | |||
|
5 | min_len min_len or 0; | |||
|
6 | max_len max_len|field.widget.max_len; | |||
|
7 | max_len max_len or 100000; | |||
|
8 | now_len len(subfields); | |||
|
9 | orderable orderable|field.widget.orderable; | |||
|
10 | orderable orderable and 1 or 0; | |||
|
11 | prototype field.widget.prototype(field); | |||
|
12 | title title|field.title;" | |||
|
13 | class="deform-seq" | |||
|
14 | id="${oid}"> | |||
|
15 | ||||
|
16 | <style> | |||
|
17 | body.dragging, body.dragging * { | |||
|
18 | cursor: move !important; | |||
|
19 | } | |||
|
20 | ||||
|
21 | .dragged { | |||
|
22 | position: absolute; | |||
|
23 | opacity: 0.5; | |||
|
24 | z-index: 2000; | |||
|
25 | } | |||
|
26 | </style> | |||
|
27 | ||||
|
28 | <!-- sequence --> | |||
|
29 | <input type="hidden" name="__start__" | |||
|
30 | value="${field.name}:sequence" | |||
|
31 | class="deform-proto" | |||
|
32 | tal:attributes="prototype prototype"/> | |||
|
33 | ||||
|
34 | <div class="panel panel-default"> | |||
|
35 | <div class="panel-heading">${title}</div> | |||
|
36 | <div class="panel-body"> | |||
|
37 | ||||
|
38 | <div class="deform-seq-container" | |||
|
39 | id="${oid}-orderable"> | |||
|
40 | <div tal:define="subfields [ x[1] for x in subfields ]" | |||
|
41 | tal:repeat="subfield subfields" | |||
|
42 | tal:replace="structure subfield.render_template(item_tmpl, | |||
|
43 | parent=field)" /> | |||
|
44 | <span class="deform-insert-before" | |||
|
45 | tal:attributes=" | |||
|
46 | min_len min_len; | |||
|
47 | max_len max_len; | |||
|
48 | now_len now_len; | |||
|
49 | orderable orderable;"></span> | |||
|
50 | </div> | |||
|
51 | ||||
|
52 | <div style="clear: both"></div> | |||
|
53 | </div> | |||
|
54 | ||||
|
55 | <div class="panel-footer"> | |||
|
56 | <a href="#" | |||
|
57 | class="btn deform-seq-add" | |||
|
58 | id="${field.oid}-seqAdd" | |||
|
59 | onclick="javascript: return deform.appendSequenceItem(this);"> | |||
|
60 | <small id="${field.oid}-addtext">${add_subitem_text}</small> | |||
|
61 | </a> | |||
|
62 | ||||
|
63 | <script type="text/javascript"> | |||
|
64 | deform.addCallback( | |||
|
65 | '${field.oid}', | |||
|
66 | function(oid) { | |||
|
67 | oid_node = $('#'+ oid); | |||
|
68 | deform.processSequenceButtons(oid_node, ${min_len}, | |||
|
69 | ${max_len}, ${now_len}, | |||
|
70 | ${orderable}); | |||
|
71 | } | |||
|
72 | ) | |||
|
73 | <tal:block condition="orderable"> | |||
|
74 | $( "#${oid}-orderable" ).sortable({ | |||
|
75 | handle: ".deform-order-button, .panel-heading", | |||
|
76 | containerSelector: "#${oid}-orderable", | |||
|
77 | itemSelector: ".deform-seq-item", | |||
|
78 | placeholder: '<span class="glyphicon glyphicon-arrow-right placeholder"></span>', | |||
|
79 | onDragStart: function ($item, container, _super) { | |||
|
80 | var offset = $item.offset(), | |||
|
81 | pointer = container.rootGroup.pointer | |||
|
82 | ||||
|
83 | adjustment = { | |||
|
84 | left: pointer.left - offset.left, | |||
|
85 | top: pointer.top - offset.top | |||
|
86 | } | |||
|
87 | ||||
|
88 | _super($item, container) | |||
|
89 | }, | |||
|
90 | onDrag: function ($item, position) { | |||
|
91 | $item.css({ | |||
|
92 | left: position.left - adjustment.left, | |||
|
93 | top: position.top - adjustment.top | |||
|
94 | }) | |||
|
95 | } | |||
|
96 | }); | |||
|
97 | </tal:block> | |||
|
98 | </script> | |||
|
99 | ||||
|
100 | <input type="hidden" name="__end__" value="${field.name}:sequence"/> | |||
|
101 | <!-- /sequence --> | |||
|
102 | </div> | |||
|
103 | ||||
|
104 | </div> | |||
|
105 | </div> No newline at end of file |
@@ -0,0 +1,35 b'' | |||||
|
1 | <div tal:omit-tag="field.widget.hidden" | |||
|
2 | tal:define="hidden hidden|field.widget.hidden; | |||
|
3 | error_class error_class|field.widget.error_class; | |||
|
4 | description description|field.description; | |||
|
5 | title title|field.title; | |||
|
6 | oid oid|field.oid" | |||
|
7 | class="form-group row deform-seq-item ${field.error and error_class or ''} ${field.widget.item_css_class or ''}" | |||
|
8 | i18n:domain="deform"> | |||
|
9 | <div class="deform-seq-item-group"> | |||
|
10 | <span tal:replace="structure field.serialize(cstruct)"/> | |||
|
11 | <tal:errors condition="field.error and not hidden" | |||
|
12 | define="errstr 'error-%s' % oid" | |||
|
13 | repeat="msg field.error.messages()"> | |||
|
14 | <p tal:condition="msg" | |||
|
15 | id="${errstr if repeat.msg.index==0 else '%s-%s' % (errstr, repeat.msg.index)}" | |||
|
16 | class="${error_class} help-block" | |||
|
17 | i18n:translate="">${msg}</p> | |||
|
18 | </tal:errors> | |||
|
19 | </div> | |||
|
20 | <div class="deform-seq-item-handle" style="padding:0"> | |||
|
21 | <!-- sequence_item --> | |||
|
22 | <span class="deform-order-button close glyphicon glyphicon-resize-vertical" | |||
|
23 | id="${oid}-order" | |||
|
24 | tal:condition="not hidden" | |||
|
25 | title="Reorder (via drag and drop)" | |||
|
26 | i18n:attributes="title"></span> | |||
|
27 | <a class="deform-close-button close" | |||
|
28 | id="${oid}-close" | |||
|
29 | tal:condition="not field.widget.hidden" | |||
|
30 | title="Remove" | |||
|
31 | i18n:attributes="title" | |||
|
32 | onclick="javascript:deform.removeSequenceItem(this);">×</a> | |||
|
33 | </div> | |||
|
34 | <!-- /sequence_item --> | |||
|
35 | </div> |
@@ -0,0 +1,23 b'' | |||||
|
1 | <span tal:define="name name|field.name; | |||
|
2 | css_class css_class|field.widget.css_class; | |||
|
3 | oid oid|field.oid; | |||
|
4 | mask mask|field.widget.mask; | |||
|
5 | placeholder placeholder|field.widget.placeholder|field.placeholder|''; | |||
|
6 | mask_placeholder mask_placeholder|field.widget.mask_placeholder; | |||
|
7 | style style|field.widget.style; | |||
|
8 | " | |||
|
9 | tal:omit-tag=""> | |||
|
10 | <input type="text" name="${name}" value="${cstruct}" | |||
|
11 | tal:attributes="class string: form-control ${css_class or ''}; | |||
|
12 | style style" | |||
|
13 | placeholder="${placeholder}" | |||
|
14 | id="${oid}"/> | |||
|
15 | <script tal:condition="mask" type="text/javascript"> | |||
|
16 | deform.addCallback( | |||
|
17 | '${oid}', | |||
|
18 | function (oid) { | |||
|
19 | $("#" + oid).mask("${mask}", | |||
|
20 | {placeholder:"${mask_placeholder}"}); | |||
|
21 | }); | |||
|
22 | </script> | |||
|
23 | </span> No newline at end of file |
@@ -38,6 +38,19 b'' | |||||
38 | license = [ pkgs.lib.licenses.mit ]; |
|
38 | license = [ pkgs.lib.licenses.mit ]; | |
39 | }; |
|
39 | }; | |
40 | }; |
|
40 | }; | |
|
41 | Chameleon = super.buildPythonPackage { | |||
|
42 | name = "Chameleon-2.24"; | |||
|
43 | buildInputs = with self; []; | |||
|
44 | doCheck = false; | |||
|
45 | propagatedBuildInputs = with self; []; | |||
|
46 | src = fetchurl { | |||
|
47 | url = "https://pypi.python.org/packages/5a/9e/637379ffa13c5172b5c0e704833ffea6bf51cec7567f93fd6e903d53ed74/Chameleon-2.24.tar.gz"; | |||
|
48 | md5 = "1b01f1f6533a8a11d0d2f2366dec5342"; | |||
|
49 | }; | |||
|
50 | meta = { | |||
|
51 | license = [ { fullName = "BSD-derived (http://www.repoze.org/LICENSE.txt)"; } ]; | |||
|
52 | }; | |||
|
53 | }; | |||
41 | Fabric = super.buildPythonPackage { |
|
54 | Fabric = super.buildPythonPackage { | |
42 | name = "Fabric-1.10.0"; |
|
55 | name = "Fabric-1.10.0"; | |
43 | buildInputs = with self; []; |
|
56 | buildInputs = with self; []; | |
@@ -558,6 +571,20 b'' | |||||
558 | license = [ pkgs.lib.licenses.bsdOriginal ]; |
|
571 | license = [ pkgs.lib.licenses.bsdOriginal ]; | |
559 | }; |
|
572 | }; | |
560 | }; |
|
573 | }; | |
|
574 | deform = super.buildPythonPackage { | |||
|
575 | name = "deform-2.0a3.dev0"; | |||
|
576 | buildInputs = with self; []; | |||
|
577 | doCheck = false; | |||
|
578 | propagatedBuildInputs = with self; [Chameleon colander iso8601 peppercorn translationstring zope.deprecation]; | |||
|
579 | src = fetchgit { | |||
|
580 | url = "https://github.com/Pylons/deform"; | |||
|
581 | rev = "08fb9de077c76951f6e70e28d4bf060a209d3d39"; | |||
|
582 | sha256 = "0nmhajc4pfgp4lbwhs5szqfzswpij1qyr69m7qkyhncl2g2d759r"; | |||
|
583 | }; | |||
|
584 | meta = { | |||
|
585 | license = [ { fullName = "BSD-derived (http://www.repoze.org/LICENSE.txt)"; } ]; | |||
|
586 | }; | |||
|
587 | }; | |||
561 | docutils = super.buildPythonPackage { |
|
588 | docutils = super.buildPythonPackage { | |
562 | name = "docutils-0.12"; |
|
589 | name = "docutils-0.12"; | |
563 | buildInputs = with self; []; |
|
590 | buildInputs = with self; []; | |
@@ -1355,7 +1382,7 b'' | |||||
1355 | name = "rhodecode-enterprise-ce-4.3.0"; |
|
1382 | name = "rhodecode-enterprise-ce-4.3.0"; | |
1356 | buildInputs = with self; [WebTest configobj cssselect flake8 lxml mock pytest pytest-cov pytest-runner]; |
|
1383 | buildInputs = with self; [WebTest configobj cssselect flake8 lxml mock pytest pytest-cov pytest-runner]; | |
1357 | doCheck = true; |
|
1384 | doCheck = true; | |
1358 | propagatedBuildInputs = with self; [Babel Beaker FormEncode Mako Markdown MarkupSafe MySQL-python Paste PasteDeploy PasteScript Pygments Pylons Pyro4 Routes SQLAlchemy Tempita URLObject WebError WebHelpers WebHelpers2 WebOb WebTest Whoosh alembic amqplib anyjson appenlight-client authomatic backport-ipaddress celery colander decorator docutils gunicorn infrae.cache ipython iso8601 kombu msgpack-python packaging psycopg2 py-gfm pycrypto pycurl pyparsing pyramid pyramid-debugtoolbar pyramid-mako pyramid-beaker pysqlite python-dateutil python-ldap python-memcached python-pam recaptcha-client repoze.lru requests simplejson waitress zope.cachedescriptors dogpile.cache dogpile.core psutil py-bcrypt]; |
|
1385 | propagatedBuildInputs = with self; [Babel Beaker FormEncode Mako Markdown MarkupSafe MySQL-python Paste PasteDeploy PasteScript Pygments Pylons Pyro4 Routes SQLAlchemy Tempita URLObject WebError WebHelpers WebHelpers2 WebOb WebTest Whoosh alembic amqplib anyjson appenlight-client authomatic backport-ipaddress celery colander decorator deform docutils gunicorn infrae.cache ipython iso8601 kombu msgpack-python packaging psycopg2 py-gfm pycrypto pycurl pyparsing pyramid pyramid-debugtoolbar pyramid-mako pyramid-beaker pysqlite python-dateutil python-ldap python-memcached python-pam recaptcha-client repoze.lru requests simplejson waitress zope.cachedescriptors dogpile.cache dogpile.core psutil py-bcrypt]; | |
1359 | src = ./.; |
|
1386 | src = ./.; | |
1360 | meta = { |
|
1387 | meta = { | |
1361 | license = [ { fullName = "AGPLv3, and Commercial License"; } ]; |
|
1388 | license = [ { fullName = "AGPLv3, and Commercial License"; } ]; |
@@ -60,6 +60,7 b' cov-core==1.15.0' | |||||
60 | coverage==3.7.1 |
|
60 | coverage==3.7.1 | |
61 | cssselect==0.9.1 |
|
61 | cssselect==0.9.1 | |
62 | decorator==3.4.2 |
|
62 | decorator==3.4.2 | |
|
63 | git+https://github.com/Pylons/deform@08fb9de077c76951f6e70e28d4bf060a209d3d39#egg=deform | |||
63 | docutils==0.12 |
|
64 | docutils==0.12 | |
64 | dogpile.cache==0.6.1 |
|
65 | dogpile.cache==0.6.1 | |
65 | dogpile.core==0.4.1 |
|
66 | dogpile.core==0.4.1 |
@@ -316,9 +316,10 b' def includeme_first(config):' | |||||
316 | config.add_route('favicon', '/favicon.ico') |
|
316 | config.add_route('favicon', '/favicon.ico') | |
317 |
|
317 | |||
318 | config.add_static_view( |
|
318 | config.add_static_view( | |
|
319 | '_static/deform', 'deform:static') | |||
|
320 | config.add_static_view( | |||
319 | '_static', path='rhodecode:public', cache_max_age=3600 * 24) |
|
321 | '_static', path='rhodecode:public', cache_max_age=3600 * 24) | |
320 |
|
322 | |||
321 |
|
||||
322 | def wrap_app_in_wsgi_middlewares(pyramid_app, config): |
|
323 | def wrap_app_in_wsgi_middlewares(pyramid_app, config): | |
323 | """ |
|
324 | """ | |
324 | Apply outer WSGI middlewares around the application. |
|
325 | Apply outer WSGI middlewares around the application. |
@@ -19,6 +19,7 b'' | |||||
19 | # and proprietary license terms, please see https://rhodecode.com/licenses/ |
|
19 | # and proprietary license terms, please see https://rhodecode.com/licenses/ | |
20 |
|
20 | |||
21 | import logging |
|
21 | import logging | |
|
22 | ||||
22 | from rhodecode.integrations.registry import IntegrationTypeRegistry |
|
23 | from rhodecode.integrations.registry import IntegrationTypeRegistry | |
23 | from rhodecode.integrations.types import webhook, slack |
|
24 | from rhodecode.integrations.types import webhook, slack | |
24 |
|
25 |
@@ -35,7 +35,6 b' class IntegrationSettingsSchemaBase(cola' | |||||
35 | description=lazy_ugettext('Enable or disable this integration.'), |
|
35 | description=lazy_ugettext('Enable or disable this integration.'), | |
36 | missing=False, |
|
36 | missing=False, | |
37 | title=lazy_ugettext('Enabled'), |
|
37 | title=lazy_ugettext('Enabled'), | |
38 | widget='bool', |
|
|||
39 | ) |
|
38 | ) | |
40 |
|
39 | |||
41 | name = colander.SchemaNode( |
|
40 | name = colander.SchemaNode( | |
@@ -43,6 +42,4 b' class IntegrationSettingsSchemaBase(cola' | |||||
43 | description=lazy_ugettext('Short name for this integration.'), |
|
42 | description=lazy_ugettext('Short name for this integration.'), | |
44 | missing=colander.required, |
|
43 | missing=colander.required, | |
45 | title=lazy_ugettext('Integration name'), |
|
44 | title=lazy_ugettext('Integration name'), | |
46 | widget='string', |
|
|||
47 | ) |
|
45 | ) | |
48 |
|
@@ -31,8 +31,7 b' class IntegrationTypeBase(object):' | |||||
31 | self.settings = settings |
|
31 | self.settings = settings | |
32 |
|
32 | |||
33 |
|
33 | |||
34 | @classmethod |
|
34 | def settings_schema(self): | |
35 | def settings_schema(cls): |
|
|||
36 | """ |
|
35 | """ | |
37 | A colander schema of settings for the integration type |
|
36 | A colander schema of settings for the integration type | |
38 |
|
37 |
@@ -19,7 +19,7 b'' | |||||
19 | # and proprietary license terms, please see https://rhodecode.com/licenses/ |
|
19 | # and proprietary license terms, please see https://rhodecode.com/licenses/ | |
20 |
|
20 | |||
21 | from __future__ import unicode_literals |
|
21 | from __future__ import unicode_literals | |
22 |
|
22 | import deform | ||
23 | import re |
|
23 | import re | |
24 | import logging |
|
24 | import logging | |
25 | import requests |
|
25 | import requests | |
@@ -48,10 +48,11 b' class SlackSettingsSchema(IntegrationSet' | |||||
48 | '<a href="https://my.slack.com/services/new/incoming-webhook/">' |
|
48 | '<a href="https://my.slack.com/services/new/incoming-webhook/">' | |
49 | 'slack app manager</a>')), |
|
49 | 'slack app manager</a>')), | |
50 | default='', |
|
50 | default='', | |
51 | placeholder='https://hooks.slack.com/services/...', |
|
|||
52 | preparer=strip_whitespace, |
|
51 | preparer=strip_whitespace, | |
53 | validator=colander.url, |
|
52 | validator=colander.url, | |
54 | widget='string' |
|
53 | widget=deform.widget.TextInputWidget( | |
|
54 | placeholder='https://hooks.slack.com/services/...', | |||
|
55 | ), | |||
55 | ) |
|
56 | ) | |
56 | username = colander.SchemaNode( |
|
57 | username = colander.SchemaNode( | |
57 | colander.String(), |
|
58 | colander.String(), | |
@@ -59,8 +60,9 b' class SlackSettingsSchema(IntegrationSet' | |||||
59 | description=lazy_ugettext('Username to show notifications coming from.'), |
|
60 | description=lazy_ugettext('Username to show notifications coming from.'), | |
60 | missing='Rhodecode', |
|
61 | missing='Rhodecode', | |
61 | preparer=strip_whitespace, |
|
62 | preparer=strip_whitespace, | |
62 | widget='string', |
|
63 | widget=deform.widget.TextInputWidget( | |
63 | placeholder='Rhodecode' |
|
64 | placeholder='Rhodecode' | |
|
65 | ), | |||
64 | ) |
|
66 | ) | |
65 | channel = colander.SchemaNode( |
|
67 | channel = colander.SchemaNode( | |
66 | colander.String(), |
|
68 | colander.String(), | |
@@ -68,8 +70,9 b' class SlackSettingsSchema(IntegrationSet' | |||||
68 | description=lazy_ugettext('Channel to send notifications to.'), |
|
70 | description=lazy_ugettext('Channel to send notifications to.'), | |
69 | missing='', |
|
71 | missing='', | |
70 | preparer=strip_whitespace, |
|
72 | preparer=strip_whitespace, | |
71 | widget='string', |
|
73 | widget=deform.widget.TextInputWidget( | |
72 | placeholder='#general' |
|
74 | placeholder='#general' | |
|
75 | ), | |||
73 | ) |
|
76 | ) | |
74 | icon_emoji = colander.SchemaNode( |
|
77 | icon_emoji = colander.SchemaNode( | |
75 | colander.String(), |
|
78 | colander.String(), | |
@@ -77,8 +80,9 b' class SlackSettingsSchema(IntegrationSet' | |||||
77 | description=lazy_ugettext('Emoji to use eg. :studio_microphone:'), |
|
80 | description=lazy_ugettext('Emoji to use eg. :studio_microphone:'), | |
78 | missing='', |
|
81 | missing='', | |
79 | preparer=strip_whitespace, |
|
82 | preparer=strip_whitespace, | |
80 | widget='string', |
|
83 | widget=deform.widget.TextInputWidget( | |
81 | placeholder=':studio_microphone:' |
|
84 | placeholder=':studio_microphone:' | |
|
85 | ), | |||
82 | ) |
|
86 | ) | |
83 |
|
87 | |||
84 |
|
88 | |||
@@ -144,16 +148,19 b' class SlackIntegrationType(IntegrationTy' | |||||
144 |
|
148 | |||
145 | run_task(post_text_to_slack, self.settings, text) |
|
149 | run_task(post_text_to_slack, self.settings, text) | |
146 |
|
150 | |||
147 | @classmethod |
|
151 | def settings_schema(self): | |
148 | def settings_schema(cls): |
|
|||
149 | schema = SlackSettingsSchema() |
|
152 | schema = SlackSettingsSchema() | |
150 | schema.add(colander.SchemaNode( |
|
153 | schema.add(colander.SchemaNode( | |
151 | colander.Set(), |
|
154 | colander.Set(), | |
152 |
widget= |
|
155 | widget=deform.widget.CheckboxChoiceWidget( | |
153 | choices=sorted([e.name for e in cls.valid_events]), |
|
156 | values=sorted( | |
|
157 | [(e.name, e.display_name) for e in self.valid_events] | |||
|
158 | ) | |||
|
159 | ), | |||
154 | description="Events activated for this integration", |
|
160 | description="Events activated for this integration", | |
155 | name='events' |
|
161 | name='events' | |
156 | )) |
|
162 | )) | |
|
163 | ||||
157 | return schema |
|
164 | return schema | |
158 |
|
165 | |||
159 | def format_pull_request_comment_event(self, event, data): |
|
166 | def format_pull_request_comment_event(self, event, data): |
@@ -20,6 +20,7 b'' | |||||
20 |
|
20 | |||
21 | from __future__ import unicode_literals |
|
21 | from __future__ import unicode_literals | |
22 |
|
22 | |||
|
23 | import deform | |||
23 | import logging |
|
24 | import logging | |
24 | import requests |
|
25 | import requests | |
25 | import colander |
|
26 | import colander | |
@@ -41,16 +42,18 b' class WebhookSettingsSchema(IntegrationS' | |||||
41 | description=lazy_ugettext('URL of the webhook to receive POST event.'), |
|
42 | description=lazy_ugettext('URL of the webhook to receive POST event.'), | |
42 | default='', |
|
43 | default='', | |
43 | validator=colander.url, |
|
44 | validator=colander.url, | |
44 | placeholder='https://www.example.com/webhook', |
|
45 | widget=deform.widget.TextInputWidget( | |
45 | widget='string' |
|
46 | placeholder='https://www.example.com/webhook' | |
|
47 | ), | |||
46 | ) |
|
48 | ) | |
47 | secret_token = colander.SchemaNode( |
|
49 | secret_token = colander.SchemaNode( | |
48 | colander.String(), |
|
50 | colander.String(), | |
49 | title=lazy_ugettext('Secret Token'), |
|
51 | title=lazy_ugettext('Secret Token'), | |
50 | description=lazy_ugettext('String used to validate received payloads.'), |
|
52 | description=lazy_ugettext('String used to validate received payloads.'), | |
51 | default='', |
|
53 | default='', | |
52 | placeholder='secret_token', |
|
54 | widget=deform.widget.TextInputWidget( | |
53 | widget='string' |
|
55 | placeholder='secret_token' | |
|
56 | ), | |||
54 | ) |
|
57 | ) | |
55 |
|
58 | |||
56 |
|
59 | |||
@@ -68,13 +71,15 b' class WebhookIntegrationType(Integration' | |||||
68 | events.RepoCreateEvent, |
|
71 | events.RepoCreateEvent, | |
69 | ] |
|
72 | ] | |
70 |
|
73 | |||
71 | @classmethod |
|
74 | def settings_schema(self): | |
72 | def settings_schema(cls): |
|
|||
73 | schema = WebhookSettingsSchema() |
|
75 | schema = WebhookSettingsSchema() | |
74 | schema.add(colander.SchemaNode( |
|
76 | schema.add(colander.SchemaNode( | |
75 | colander.Set(), |
|
77 | colander.Set(), | |
76 |
widget= |
|
78 | widget=deform.widget.CheckboxChoiceWidget( | |
77 | choices=sorted([e.name for e in cls.valid_events]), |
|
79 | values=sorted( | |
|
80 | [(e.name, e.display_name) for e in self.valid_events] | |||
|
81 | ) | |||
|
82 | ), | |||
78 | description="Events activated for this integration", |
|
83 | description="Events activated for this integration", | |
79 | name='events' |
|
84 | name='events' | |
80 | )) |
|
85 | )) |
@@ -21,6 +21,7 b'' | |||||
21 | import colander |
|
21 | import colander | |
22 | import logging |
|
22 | import logging | |
23 | import pylons |
|
23 | import pylons | |
|
24 | import deform | |||
24 |
|
25 | |||
25 | from pyramid.httpexceptions import HTTPFound, HTTPForbidden |
|
26 | from pyramid.httpexceptions import HTTPFound, HTTPForbidden | |
26 | from pyramid.renderers import render |
|
27 | from pyramid.renderers import render | |
@@ -101,30 +102,41 b' class IntegrationSettingsViewBase(object' | |||||
101 | return c |
|
102 | return c | |
102 |
|
103 | |||
103 | def _form_schema(self): |
|
104 | def _form_schema(self): | |
104 | return self.IntegrationType.settings_schema() |
|
105 | if self.integration: | |
|
106 | settings = self.integration.settings | |||
|
107 | else: | |||
|
108 | settings = {} | |||
|
109 | return self.IntegrationType(settings=settings).settings_schema() | |||
105 |
|
110 | |||
106 | def settings_get(self, defaults=None, errors=None): |
|
111 | def settings_get(self, defaults=None, errors=None, form=None): | |
107 | """ |
|
112 | """ | |
108 | View that displays the plugin settings as a form. |
|
113 | View that displays the plugin settings as a form. | |
109 | """ |
|
114 | """ | |
110 | defaults = defaults or {} |
|
115 | defaults = defaults or {} | |
111 | errors = errors or {} |
|
116 | errors = errors or {} | |
112 |
|
117 | |||
113 | schema = self._form_schema() |
|
118 | if self.integration: | |
114 |
|
119 | defaults = self.integration.settings or {} | ||
115 | if not defaults: |
|
120 | defaults['name'] = self.integration.name | |
116 |
|
|
121 | defaults['enabled'] = self.integration.enabled | |
117 | defaults['enabled'] = self.integration.enabled |
|
122 | else: | |
118 | defaults['name'] = self.integration.name |
|
123 | if self.repo: | |
|
124 | scope = self.repo.repo_name | |||
119 | else: |
|
125 | else: | |
120 | if self.repo: |
|
126 | scope = _('Global') | |
121 | scope = self.repo.repo_name |
|
127 | ||
122 | else: |
|
128 | defaults['name'] = '{} {} integration'.format(scope, | |
123 | scope = _('Global') |
|
129 | self.IntegrationType.display_name) | |
|
130 | defaults['enabled'] = True | |||
124 |
|
131 | |||
125 | defaults['name'] = '{} {} integration'.format(scope, |
|
132 | schema = self._form_schema().bind(request=self.request) | |
126 | self.IntegrationType.display_name) |
|
133 | ||
127 | defaults['enabled'] = True |
|
134 | if self.integration: | |
|
135 | buttons = ('submit', 'delete') | |||
|
136 | else: | |||
|
137 | buttons = ('submit',) | |||
|
138 | ||||
|
139 | form = form or deform.Form(schema, appstruct=defaults, buttons=buttons) | |||
128 |
|
140 | |||
129 | for node in schema: |
|
141 | for node in schema: | |
130 | setting = self.settings.get(node.name) |
|
142 | setting = self.settings.get(node.name) | |
@@ -135,6 +147,7 b' class IntegrationSettingsViewBase(object' | |||||
135 | defaults.setdefault(node.name, node.default) |
|
147 | defaults.setdefault(node.name, node.default) | |
136 |
|
148 | |||
137 | template_context = { |
|
149 | template_context = { | |
|
150 | 'form': form, | |||
138 | 'defaults': defaults, |
|
151 | 'defaults': defaults, | |
139 | 'errors': errors, |
|
152 | 'errors': errors, | |
140 | 'schema': schema, |
|
153 | 'schema': schema, | |
@@ -166,7 +179,9 b' class IntegrationSettingsViewBase(object' | |||||
166 | redirect_to = self.request.route_url('global_integrations_home') |
|
179 | redirect_to = self.request.route_url('global_integrations_home') | |
167 | raise HTTPFound(redirect_to) |
|
180 | raise HTTPFound(redirect_to) | |
168 |
|
181 | |||
169 | schema = self._form_schema() |
|
182 | schema = self._form_schema().bind(request=self.request) | |
|
183 | ||||
|
184 | form = deform.Form(schema, buttons=('submit', 'delete')) | |||
170 |
|
185 | |||
171 | params = {} |
|
186 | params = {} | |
172 | for node in schema.children: |
|
187 | for node in schema.children: | |
@@ -177,15 +192,15 b' class IntegrationSettingsViewBase(object' | |||||
177 | if val: |
|
192 | if val: | |
178 | params[node.name] = val |
|
193 | params[node.name] = val | |
179 |
|
194 | |||
|
195 | controls = self.request.POST.items() | |||
180 | try: |
|
196 | try: | |
181 |
valid_data = |
|
197 | valid_data = form.validate(controls) | |
182 |
except |
|
198 | except deform.ValidationFailure as e: | |
183 | # Display error message and display form again. |
|
|||
184 | self.request.session.flash( |
|
199 | self.request.session.flash( | |
185 |
_('Errors exist when saving |
|
200 | _('Errors exist when saving integration settings. ' | |
186 | 'Please check the form inputs.'), |
|
201 | 'Please check the form inputs.'), | |
187 | queue='error') |
|
202 | queue='error') | |
188 |
return self.settings_get(errors= |
|
203 | return self.settings_get(errors={}, defaults=params, form=e) | |
189 |
|
204 | |||
190 | if not self.integration: |
|
205 | if not self.integration: | |
191 | self.integration = Integration() |
|
206 | self.integration = Integration() | |
@@ -230,7 +245,6 b' class IntegrationSettingsViewBase(object' | |||||
230 | template_context = { |
|
245 | template_context = { | |
231 | 'current_IntegrationType': self.IntegrationType, |
|
246 | 'current_IntegrationType': self.IntegrationType, | |
232 | 'current_integrations': current_integrations, |
|
247 | 'current_integrations': current_integrations, | |
233 | 'current_integration': 'none', |
|
|||
234 | 'available_integrations': integration_type_registry, |
|
248 | 'available_integrations': integration_type_registry, | |
235 | 'c': self._template_c_context() |
|
249 | 'c': self._template_c_context() | |
236 | } |
|
250 | } |
@@ -950,7 +950,8 b' def bool2icon(value):' | |||||
950 | #============================================================================== |
|
950 | #============================================================================== | |
951 | from rhodecode.lib.auth import HasPermissionAny, HasPermissionAll, \ |
|
951 | from rhodecode.lib.auth import HasPermissionAny, HasPermissionAll, \ | |
952 | HasRepoPermissionAny, HasRepoPermissionAll, HasRepoGroupPermissionAll, \ |
|
952 | HasRepoPermissionAny, HasRepoPermissionAll, HasRepoGroupPermissionAll, \ | |
953 | HasRepoGroupPermissionAny, HasRepoPermissionAnyApi, get_csrf_token |
|
953 | HasRepoGroupPermissionAny, HasRepoPermissionAnyApi, get_csrf_token, \ | |
|
954 | csrf_token_key | |||
954 |
|
955 | |||
955 |
|
956 | |||
956 | #============================================================================== |
|
957 | #============================================================================== | |
@@ -1877,11 +1878,15 b' def secure_form(url, method="POST", mult' | |||||
1877 |
|
1878 | |||
1878 | """ |
|
1879 | """ | |
1879 | from webhelpers.pylonslib.secure_form import insecure_form |
|
1880 | from webhelpers.pylonslib.secure_form import insecure_form | |
1880 | from rhodecode.lib.auth import get_csrf_token, csrf_token_key |
|
|||
1881 | form = insecure_form(url, method, multipart, **attrs) |
|
1881 | form = insecure_form(url, method, multipart, **attrs) | |
1882 | token = HTML.div(hidden(csrf_token_key, get_csrf_token()), style="display: none;") |
|
1882 | token = csrf_input() | |
1883 | return literal("%s\n%s" % (form, token)) |
|
1883 | return literal("%s\n%s" % (form, token)) | |
1884 |
|
1884 | |||
|
1885 | def csrf_input(): | |||
|
1886 | return literal( | |||
|
1887 | '<input type="hidden" id="{}" name="{}" value="{}">'.format( | |||
|
1888 | csrf_token_key, csrf_token_key, get_csrf_token())) | |||
|
1889 | ||||
1885 | def dropdownmenu(name, selected, options, enable_filter=False, **attrs): |
|
1890 | def dropdownmenu(name, selected, options, enable_filter=False, **attrs): | |
1886 | select_html = select(name, selected, options, **attrs) |
|
1891 | select_html = select(name, selected, options, **attrs) | |
1887 | select2 = """ |
|
1892 | select2 = """ | |
@@ -1937,6 +1942,16 b' def route_path(*args, **kwds):' | |||||
1937 | return req.route_path(*args, **kwds) |
|
1942 | return req.route_path(*args, **kwds) | |
1938 |
|
1943 | |||
1939 |
|
1944 | |||
|
1945 | def static_url(*args, **kwds): | |||
|
1946 | """ | |||
|
1947 | Wrapper around pyramids `route_path` function. It is used to generate | |||
|
1948 | URLs from within pylons views or templates. This will be removed when | |||
|
1949 | pyramid migration if finished. | |||
|
1950 | """ | |||
|
1951 | req = get_current_request() | |||
|
1952 | return req.static_url(*args, **kwds) | |||
|
1953 | ||||
|
1954 | ||||
1940 | def resource_path(*args, **kwds): |
|
1955 | def resource_path(*args, **kwds): | |
1941 | """ |
|
1956 | """ | |
1942 | Wrapper around pyramids `route_path` function. It is used to generate |
|
1957 | Wrapper around pyramids `route_path` function. It is used to generate |
@@ -41,6 +41,16 b' for SELECT use formencode.All(OneOf(list' | |||||
41 |
|
41 | |||
42 | """ |
|
42 | """ | |
43 |
|
43 | |||
|
44 | import deform | |||
|
45 | from pkg_resources import resource_filename | |||
|
46 | ||||
|
47 | deform_templates = resource_filename('deform', 'templates') | |||
|
48 | rhodecode_templates = resource_filename('rhodecode', 'templates/forms') | |||
|
49 | search_path = (rhodecode_templates, deform_templates) | |||
|
50 | ||||
|
51 | deform.Form.set_zpt_renderer(search_path) | |||
|
52 | ||||
|
53 | ||||
44 | import logging |
|
54 | import logging | |
45 |
|
55 | |||
46 | import formencode |
|
56 | import formencode |
@@ -25,6 +25,7 b'' | |||||
25 | @import 'comments'; |
|
25 | @import 'comments'; | |
26 | @import 'panels-bootstrap'; |
|
26 | @import 'panels-bootstrap'; | |
27 | @import 'panels'; |
|
27 | @import 'panels'; | |
|
28 | @import 'deform'; | |||
28 |
|
29 | |||
29 |
|
30 | |||
30 | //--- BASE ------------------// |
|
31 | //--- BASE ------------------// | |
@@ -141,7 +142,7 b' input.inline[type="file"] {' | |||||
141 | h1 { |
|
142 | h1 { | |
142 | color: @grey2; |
|
143 | color: @grey2; | |
143 | } |
|
144 | } | |
144 |
|
145 | |||
145 | .error-branding { |
|
146 | .error-branding { | |
146 | font-family: @text-semibold; |
|
147 | font-family: @text-semibold; | |
147 | color: @grey4; |
|
148 | color: @grey4; | |
@@ -1022,9 +1023,9 b' label {' | |||||
1022 | padding: .9em; |
|
1023 | padding: .9em; | |
1023 | color: @grey3; |
|
1024 | color: @grey3; | |
1024 | background-color: @grey7; |
|
1025 | background-color: @grey7; | |
1025 |
border-right: @border-thickness solid @border-default-color; |
|
1026 | border-right: @border-thickness solid @border-default-color; | |
1026 |
border-bottom: @border-thickness solid @border-default-color; |
|
1027 | border-bottom: @border-thickness solid @border-default-color; | |
1027 |
border-left: @border-thickness solid @border-default-color; |
|
1028 | border-left: @border-thickness solid @border-default-color; | |
1028 | } |
|
1029 | } | |
1029 |
|
1030 | |||
1030 | #repo_vcs_settings { |
|
1031 | #repo_vcs_settings { | |
@@ -1953,7 +1954,7 b' div.search-feedback-items {' | |||||
1953 | padding:0px 0px 0px 96px; |
|
1954 | padding:0px 0px 0px 96px; | |
1954 | } |
|
1955 | } | |
1955 |
|
1956 | |||
1956 |
div.search-code-body { |
|
1957 | div.search-code-body { | |
1957 | background-color: #ffffff; padding: 5px 0 5px 10px; |
|
1958 | background-color: #ffffff; padding: 5px 0 5px 10px; | |
1958 | pre { |
|
1959 | pre { | |
1959 | .match { background-color: #faffa6;} |
|
1960 | .match { background-color: #faffa6;} |
@@ -27,8 +27,6 b'' | |||||
27 | ${integration.name} |
|
27 | ${integration.name} | |
28 | %endif |
|
28 | %endif | |
29 | </%def> |
|
29 | </%def> | |
30 |
|
||||
31 |
|
||||
32 | <div class="panel panel-default"> |
|
30 | <div class="panel panel-default"> | |
33 | <div class="panel-heading"> |
|
31 | <div class="panel-heading"> | |
34 | <h2 class="panel-title"> |
|
32 | <h2 class="panel-title"> | |
@@ -39,70 +37,8 b'' | |||||
39 | %endif |
|
37 | %endif | |
40 | </h2> |
|
38 | </h2> | |
41 | </div> |
|
39 | </div> | |
42 |
<div class=" |
|
40 | <div class="panel-body"> | |
43 | ${h.secure_form(request.url)} |
|
41 | ## TODO: dan: find way to put h in the deform context properly | |
44 | <div class="form"> |
|
42 | ${form.render(h=h) | n} | |
45 | %for node in schema: |
|
|||
46 | <% label_css_class = ("label-checkbox" if (node.widget == "bool") else "") %> |
|
|||
47 | <div class="field"> |
|
|||
48 | <div class="label ${label_css_class}"><label for="${node.name}">${node.title}</label></div> |
|
|||
49 | <div class="input"> |
|
|||
50 | %if node.widget in ["string", "int", "unicode"]: |
|
|||
51 | ${h.text(node.name, defaults.get(node.name), class_="medium", placeholder=hasattr(node, 'placeholder') and node.placeholder or '')} |
|
|||
52 | %elif node.widget in ["text"]: |
|
|||
53 | ${h.textarea(node.name, defaults.get(node.name), class_="medium", placeholder=hasattr(node, 'placeholder') and node.placeholder or '')} |
|
|||
54 | %elif node.widget == "password": |
|
|||
55 | ${h.password(node.name, defaults.get(node.name), class_="medium")} |
|
|||
56 | %elif node.widget == "bool": |
|
|||
57 | <div class="checkbox">${h.checkbox(node.name, True, checked=defaults.get(node.name))}</div> |
|
|||
58 | %elif node.widget == "select": |
|
|||
59 | ${h.select(node.name, defaults.get(node.name), node.choices)} |
|
|||
60 | %elif node.widget == "checkbox_list": |
|
|||
61 | %for i, choice in enumerate(node.choices): |
|
|||
62 | <% |
|
|||
63 | name, value = choice, choice |
|
|||
64 | if isinstance(choice, tuple): |
|
|||
65 | choice, name = choice |
|
|||
66 | %> |
|
|||
67 | <div> |
|
|||
68 | <input id="${node.name}-${choice}" |
|
|||
69 | name="${node.name}" |
|
|||
70 | value="${value}" |
|
|||
71 | type="checkbox" |
|
|||
72 | ${value in defaults.get(node.name, []) and 'checked' or ''}> |
|
|||
73 | <label for="${node.name}-${value}"> |
|
|||
74 | ${name} |
|
|||
75 | </label> |
|
|||
76 | </div> |
|
|||
77 | %endfor |
|
|||
78 | %elif node.widget == "readonly": |
|
|||
79 | ${node.default} |
|
|||
80 | %else: |
|
|||
81 | This field is of type ${node.typ}, which cannot be displayed. Must be one of [string|int|bool|select|password|text|checkbox_list]. |
|
|||
82 | %endif |
|
|||
83 | %if node.name in errors: |
|
|||
84 | <span class="error-message">${errors.get(node.name)}</span> |
|
|||
85 | <br /> |
|
|||
86 | %endif |
|
|||
87 | <p class="help-block">${node.description}</p> |
|
|||
88 | </div> |
|
|||
89 | </div> |
|
|||
90 | %endfor |
|
|||
91 |
|
||||
92 | ## Allow derived templates to add something below the form |
|
|||
93 | ## input fields |
|
|||
94 | %if hasattr(next, 'below_form_fields'): |
|
|||
95 | ${next.below_form_fields()} |
|
|||
96 | %endif |
|
|||
97 |
|
||||
98 | <div class="buttons"> |
|
|||
99 | ${h.submit('save',_('Save'),class_="btn")} |
|
|||
100 | %if integration: |
|
|||
101 | ${h.submit('delete',_('Delete'),class_="btn btn-danger")} |
|
|||
102 | %endif |
|
|||
103 | </div> |
|
|||
104 |
|
||||
105 | </div> |
|
|||
106 | ${h.end_form()} |
|
|||
107 | </div> |
|
43 | </div> | |
108 | </div> No newline at end of file |
|
44 | </div> |
@@ -83,9 +83,11 b" c.template_context['visual']['default_re" | |||||
83 | <![endif]--> |
|
83 | <![endif]--> | |
84 | <script language="javascript" type="text/javascript" src="${h.asset('js/rhodecode/routes.js', ver=c.rhodecode_version_hash)}"></script> |
|
84 | <script language="javascript" type="text/javascript" src="${h.asset('js/rhodecode/routes.js', ver=c.rhodecode_version_hash)}"></script> | |
85 | <script language="javascript" type="text/javascript" src="${h.asset('js/scripts.js', ver=c.rhodecode_version_hash)}"></script> |
|
85 | <script language="javascript" type="text/javascript" src="${h.asset('js/scripts.js', ver=c.rhodecode_version_hash)}"></script> | |
|
86 | <script language="javascript" type="text/javascript" src="${h.static_url('deform:static/scripts/deform.js')}"></script> | |||
86 | ## avoide esaping the %N |
|
87 | ## avoide esaping the %N | |
87 | <script>CodeMirror.modeURL = "${h.asset('') + 'js/mode/%N/%N.js'}";</script> |
|
88 | <script>CodeMirror.modeURL = "${h.asset('') + 'js/mode/%N/%N.js'}";</script> | |
88 |
|
89 | |||
|
90 | ||||
89 | ## JAVASCRIPT EXTRA - optionally inject some extra JS for specificed templates |
|
91 | ## JAVASCRIPT EXTRA - optionally inject some extra JS for specificed templates | |
90 | ${self.js_extra()} |
|
92 | ${self.js_extra()} | |
91 |
|
93 |
General Comments 0
You need to be logged in to leave comments.
Login now