nisetegami 0.4.0 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (30) hide show
  1. data/app/assets/javascripts/nisetegami/application.js +15 -0
  2. data/app/assets/javascripts/nisetegami/nisetegami.bootstrap.min.js +7 -0
  3. data/app/assets/javascripts/nisetegami/templates.js.coffee +18 -0
  4. data/app/assets/stylesheets/nisetegami/application.css.scss +4 -0
  5. data/app/assets/stylesheets/nisetegami/nisetegami.bootstrap.min.css +363 -0
  6. data/app/assets/stylesheets/nisetegami/templates.css.scss +19 -0
  7. data/app/controllers/nisetegami/application_controller.rb +4 -0
  8. data/app/controllers/nisetegami/templates_controller.rb +52 -0
  9. data/app/models/nisetegami/template.rb +15 -6
  10. data/app/views/layouts/nisetegami/application.html.erb +27 -0
  11. data/app/views/nisetegami/templates/_delete_button.html.erb +5 -0
  12. data/app/views/nisetegami/templates/_edit_form_buttons.html.erb +3 -0
  13. data/app/views/nisetegami/templates/_field.html.erb +6 -0
  14. data/app/views/nisetegami/templates/_filters.html.erb +35 -0
  15. data/app/views/nisetegami/templates/_test_mail.html.erb +26 -0
  16. data/app/views/nisetegami/templates/_var.html.erb +4 -0
  17. data/app/views/nisetegami/templates/edit.html.erb +36 -0
  18. data/app/views/nisetegami/templates/index.html.erb +42 -0
  19. data/config/locales/nisetegami.en.yml +56 -0
  20. data/config/locales/nisetegami.ru.yml +56 -0
  21. data/config/routes.rb +6 -0
  22. data/lib/nisetegami.rb +5 -0
  23. data/lib/nisetegami/action_mailer_extensions.rb +4 -6
  24. data/lib/nisetegami/engine.rb +0 -2
  25. data/lib/nisetegami/mapping.rb +8 -8
  26. data/lib/nisetegami/railtie.rb +9 -0
  27. data/lib/nisetegami/template_presenter.rb +34 -0
  28. data/lib/nisetegami/version.rb +1 -1
  29. data/lib/tasks/nisetegami_tasks.rake +8 -4
  30. metadata +24 -18
@@ -0,0 +1,15 @@
1
+ // This is a manifest file that'll be compiled into application.js, which will include all the files
2
+ // listed below.
3
+ //
4
+ // Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
5
+ // or vendor/assets/javascripts of plugins, if any, can be referenced here using a relative path.
6
+ //
7
+ // It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
8
+ // the compiled file.
9
+ //
10
+ // WARNING: THE FIRST BLANK LINE MARKS THE END OF WHAT'S TO BE PROCESSED, ANY BLANK LINE SHOULD
11
+ // GO AFTER THE REQUIRES BELOW.
12
+ //
13
+ //= require jquery
14
+ //= require jquery_ujs
15
+ //= require_tree .
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Bootstrap.js by @fat & @mdo
3
+ * plugins: bootstrap-alert.js
4
+ * Copyright 2012 Twitter, Inc.
5
+ * http://www.apache.org/licenses/LICENSE-2.0.txt
6
+ */
7
+ !function(a){var b='[data-dismiss="alert"]',c=function(c){a(c).on("click",b,this.close)};c.prototype.close=function(b){function f(){e.trigger("closed").remove()}var c=a(this),d=c.attr("data-target"),e;d||(d=c.attr("href"),d=d&&d.replace(/.*(?=#[^\s]*$)/,"")),e=a(d),b&&b.preventDefault(),e.length||(e=c.hasClass("alert")?c:c.parent()),e.trigger(b=a.Event("close"));if(b.isDefaultPrevented())return;e.removeClass("in"),a.support.transition&&e.hasClass("fade")?e.on(a.support.transition.end,f):f()},a.fn.alert=function(b){return this.each(function(){var d=a(this),e=d.data("alert");e||d.data("alert",e=new c(this)),typeof b=="string"&&e[b].call(d)})},a.fn.alert.Constructor=c,a(document).on("click.alert.data-api",b,c.prototype.close)}(window.jQuery)
@@ -0,0 +1,18 @@
1
+ jQuery ->
2
+ $('button.reset').on 'click', (event) ->
3
+ event.preventDefault()
4
+ $(@).closest('form').find('input, select').not(':input[type=submit]').val('')
5
+ $('#mailer_action').text('')
6
+
7
+ $('#mailer').on 'change', (event) ->
8
+ mailer = $(@).val()
9
+ actionSelect = $('#mailer_action')
10
+ if mailer != ''
11
+ loc = window.location
12
+ port = unless loc.port == 80 then ":#{loc.port}" else ''
13
+ $.post "#{loc.protocol}//#{loc.hostname}#{port}#{loc.pathname}actions", mailer: mailer, (data) ->
14
+ console.log data
15
+ actionSelect.append($('<option></option>').val(action).text(action)) for action in data
16
+ else
17
+ actionSelect.text('')
18
+
@@ -0,0 +1,4 @@
1
+ /*
2
+ *= require_self
3
+ *= require_tree .
4
+ */
@@ -0,0 +1,363 @@
1
+ /*!
2
+ * Bootstrap v2.2.1
3
+ *
4
+ * Copyright 2012 Twitter, Inc
5
+ * Licensed under the Apache License v2.0
6
+ * http://www.apache.org/licenses/LICENSE-2.0
7
+ *
8
+ * Designed and built with all the love in the world @twitter by @mdo and @fat.
9
+ */
10
+ .clearfix{*zoom:1;}.clearfix:before,.clearfix:after{display:table;content:"";line-height:0;}
11
+ .clearfix:after{clear:both;}
12
+ .hide-text{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0;}
13
+ .input-block-level{display:block;width:100%;min-height:30px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;}
14
+ article,aside,details,figcaption,figure,footer,header,hgroup,nav,section{display:block;}
15
+ audio,canvas,video{display:inline-block;*display:inline;*zoom:1;}
16
+ audio:not([controls]){display:none;}
17
+ html{font-size:100%;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%;}
18
+ a:focus{outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px;}
19
+ a:hover,a:active{outline:0;}
20
+ sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline;}
21
+ sup{top:-0.5em;}
22
+ sub{bottom:-0.25em;}
23
+ img{max-width:100%;width:auto\9;height:auto;vertical-align:middle;border:0;-ms-interpolation-mode:bicubic;}
24
+ #map_canvas img,.google-maps img{max-width:none;}
25
+ button,input,select,textarea{margin:0;font-size:100%;vertical-align:middle;}
26
+ button,input{*overflow:visible;line-height:normal;}
27
+ button::-moz-focus-inner,input::-moz-focus-inner{padding:0;border:0;}
28
+ button,html input[type="button"],input[type="reset"],input[type="submit"]{-webkit-appearance:button;cursor:pointer;}
29
+ input[type="search"]{-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;-webkit-appearance:textfield;}
30
+ input[type="search"]::-webkit-search-decoration,input[type="search"]::-webkit-search-cancel-button{-webkit-appearance:none;}
31
+ textarea{overflow:auto;vertical-align:top;}
32
+ body{margin:0;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:14px;line-height:20px;color:#333333;background-color:#ffffff;}
33
+ a{color:#0088cc;text-decoration:none;}
34
+ a:hover{color:#005580;text-decoration:underline;}
35
+ .img-rounded{-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;}
36
+ .img-polaroid{padding:4px;background-color:#fff;border:1px solid #ccc;border:1px solid rgba(0, 0, 0, 0.2);-webkit-box-shadow:0 1px 3px rgba(0, 0, 0, 0.1);-moz-box-shadow:0 1px 3px rgba(0, 0, 0, 0.1);box-shadow:0 1px 3px rgba(0, 0, 0, 0.1);}
37
+ .img-circle{-webkit-border-radius:500px;-moz-border-radius:500px;border-radius:500px;}
38
+ .row{margin-left:-20px;*zoom:1;}.row:before,.row:after{display:table;content:"";line-height:0;}
39
+ .row:after{clear:both;}
40
+ [class*="span"]{float:left;min-height:1px;margin-left:20px;}
41
+ .container,.navbar-static-top .container,.navbar-fixed-top .container,.navbar-fixed-bottom .container{width:940px;}
42
+ .span12{width:940px;}
43
+ .span11{width:860px;}
44
+ .span10{width:780px;}
45
+ .span9{width:700px;}
46
+ .span8{width:620px;}
47
+ .span7{width:540px;}
48
+ .span6{width:460px;}
49
+ .span5{width:380px;}
50
+ .span4{width:300px;}
51
+ .span3{width:220px;}
52
+ .span2{width:140px;}
53
+ .span1{width:60px;}
54
+ .offset12{margin-left:980px;}
55
+ .offset11{margin-left:900px;}
56
+ .offset10{margin-left:820px;}
57
+ .offset9{margin-left:740px;}
58
+ .offset8{margin-left:660px;}
59
+ .offset7{margin-left:580px;}
60
+ .offset6{margin-left:500px;}
61
+ .offset5{margin-left:420px;}
62
+ .offset4{margin-left:340px;}
63
+ .offset3{margin-left:260px;}
64
+ .offset2{margin-left:180px;}
65
+ .offset1{margin-left:100px;}
66
+ .row-fluid{width:100%;*zoom:1;}.row-fluid:before,.row-fluid:after{display:table;content:"";line-height:0;}
67
+ .row-fluid:after{clear:both;}
68
+ .row-fluid [class*="span"]{display:block;width:100%;min-height:30px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;float:left;margin-left:2.127659574468085%;*margin-left:2.074468085106383%;}
69
+ .row-fluid [class*="span"]:first-child{margin-left:0;}
70
+ .row-fluid .controls-row [class*="span"]+[class*="span"]{margin-left:2.127659574468085%;}
71
+ .row-fluid .span12{width:100%;*width:99.94680851063829%;}
72
+ .row-fluid .span11{width:91.48936170212765%;*width:91.43617021276594%;}
73
+ .row-fluid .span10{width:82.97872340425532%;*width:82.92553191489361%;}
74
+ .row-fluid .span9{width:74.46808510638297%;*width:74.41489361702126%;}
75
+ .row-fluid .span8{width:65.95744680851064%;*width:65.90425531914893%;}
76
+ .row-fluid .span7{width:57.44680851063829%;*width:57.39361702127659%;}
77
+ .row-fluid .span6{width:48.93617021276595%;*width:48.88297872340425%;}
78
+ .row-fluid .span5{width:40.42553191489362%;*width:40.37234042553192%;}
79
+ .row-fluid .span4{width:31.914893617021278%;*width:31.861702127659576%;}
80
+ .row-fluid .span3{width:23.404255319148934%;*width:23.351063829787233%;}
81
+ .row-fluid .span2{width:14.893617021276595%;*width:14.840425531914894%;}
82
+ .row-fluid .span1{width:6.382978723404255%;*width:6.329787234042553%;}
83
+ .row-fluid .offset12{margin-left:104.25531914893617%;*margin-left:104.14893617021275%;}
84
+ .row-fluid .offset12:first-child{margin-left:102.12765957446808%;*margin-left:102.02127659574467%;}
85
+ .row-fluid .offset11{margin-left:95.74468085106382%;*margin-left:95.6382978723404%;}
86
+ .row-fluid .offset11:first-child{margin-left:93.61702127659574%;*margin-left:93.51063829787232%;}
87
+ .row-fluid .offset10{margin-left:87.23404255319149%;*margin-left:87.12765957446807%;}
88
+ .row-fluid .offset10:first-child{margin-left:85.1063829787234%;*margin-left:84.99999999999999%;}
89
+ .row-fluid .offset9{margin-left:78.72340425531914%;*margin-left:78.61702127659572%;}
90
+ .row-fluid .offset9:first-child{margin-left:76.59574468085106%;*margin-left:76.48936170212764%;}
91
+ .row-fluid .offset8{margin-left:70.2127659574468%;*margin-left:70.10638297872339%;}
92
+ .row-fluid .offset8:first-child{margin-left:68.08510638297872%;*margin-left:67.9787234042553%;}
93
+ .row-fluid .offset7{margin-left:61.70212765957446%;*margin-left:61.59574468085106%;}
94
+ .row-fluid .offset7:first-child{margin-left:59.574468085106375%;*margin-left:59.46808510638297%;}
95
+ .row-fluid .offset6{margin-left:53.191489361702125%;*margin-left:53.085106382978715%;}
96
+ .row-fluid .offset6:first-child{margin-left:51.063829787234035%;*margin-left:50.95744680851063%;}
97
+ .row-fluid .offset5{margin-left:44.68085106382979%;*margin-left:44.57446808510638%;}
98
+ .row-fluid .offset5:first-child{margin-left:42.5531914893617%;*margin-left:42.4468085106383%;}
99
+ .row-fluid .offset4{margin-left:36.170212765957444%;*margin-left:36.06382978723405%;}
100
+ .row-fluid .offset4:first-child{margin-left:34.04255319148936%;*margin-left:33.93617021276596%;}
101
+ .row-fluid .offset3{margin-left:27.659574468085104%;*margin-left:27.5531914893617%;}
102
+ .row-fluid .offset3:first-child{margin-left:25.53191489361702%;*margin-left:25.425531914893618%;}
103
+ .row-fluid .offset2{margin-left:19.148936170212764%;*margin-left:19.04255319148936%;}
104
+ .row-fluid .offset2:first-child{margin-left:17.02127659574468%;*margin-left:16.914893617021278%;}
105
+ .row-fluid .offset1{margin-left:10.638297872340425%;*margin-left:10.53191489361702%;}
106
+ .row-fluid .offset1:first-child{margin-left:8.51063829787234%;*margin-left:8.404255319148938%;}
107
+ [class*="span"].hide,.row-fluid [class*="span"].hide{display:none;}
108
+ [class*="span"].pull-right,.row-fluid [class*="span"].pull-right{float:right;}
109
+ .container{margin-right:auto;margin-left:auto;*zoom:1;}.container:before,.container:after{display:table;content:"";line-height:0;}
110
+ .container:after{clear:both;}
111
+ .container-fluid{padding-right:20px;padding-left:20px;*zoom:1;}.container-fluid:before,.container-fluid:after{display:table;content:"";line-height:0;}
112
+ .container-fluid:after{clear:both;}
113
+ p{margin:0 0 10px;}
114
+ .lead{margin-bottom:20px;font-size:21px;font-weight:200;line-height:30px;}
115
+ small{font-size:85%;}
116
+ strong{font-weight:bold;}
117
+ em{font-style:italic;}
118
+ cite{font-style:normal;}
119
+ .muted{color:#999999;}
120
+ .text-warning{color:#c09853;}
121
+ a.text-warning:hover{color:#a47e3c;}
122
+ .text-error{color:#b94a48;}
123
+ a.text-error:hover{color:#953b39;}
124
+ .text-info{color:#3a87ad;}
125
+ a.text-info:hover{color:#2d6987;}
126
+ .text-success{color:#468847;}
127
+ a.text-success:hover{color:#356635;}
128
+ h1,h2,h3,h4,h5,h6{margin:10px 0;font-family:inherit;font-weight:bold;line-height:20px;color:inherit;text-rendering:optimizelegibility;}h1 small,h2 small,h3 small,h4 small,h5 small,h6 small{font-weight:normal;line-height:1;color:#999999;}
129
+ h1,h2,h3{line-height:40px;}
130
+ h1{font-size:38.5px;}
131
+ h2{font-size:31.5px;}
132
+ h3{font-size:24.5px;}
133
+ h4{font-size:17.5px;}
134
+ h5{font-size:14px;}
135
+ h6{font-size:11.9px;}
136
+ h1 small{font-size:24.5px;}
137
+ h2 small{font-size:17.5px;}
138
+ h3 small{font-size:14px;}
139
+ h4 small{font-size:14px;}
140
+ .page-header{padding-bottom:9px;margin:20px 0 30px;border-bottom:1px solid #eeeeee;}
141
+ ul,ol{padding:0;margin:0 0 10px 25px;}
142
+ ul ul,ul ol,ol ol,ol ul{margin-bottom:0;}
143
+ li{line-height:20px;}
144
+ ul.unstyled,ol.unstyled{margin-left:0;list-style:none;}
145
+ dl{margin-bottom:20px;}
146
+ dt,dd{line-height:20px;}
147
+ dt{font-weight:bold;}
148
+ dd{margin-left:10px;}
149
+ .dl-horizontal{*zoom:1;}.dl-horizontal:before,.dl-horizontal:after{display:table;content:"";line-height:0;}
150
+ .dl-horizontal:after{clear:both;}
151
+ .dl-horizontal dt{float:left;width:160px;clear:left;text-align:right;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}
152
+ .dl-horizontal dd{margin-left:180px;}
153
+ hr{margin:20px 0;border:0;border-top:1px solid #eeeeee;border-bottom:1px solid #ffffff;}
154
+ abbr[title],abbr[data-original-title]{cursor:help;border-bottom:1px dotted #999999;}
155
+ abbr.initialism{font-size:90%;text-transform:uppercase;}
156
+ blockquote{padding:0 0 0 15px;margin:0 0 20px;border-left:5px solid #eeeeee;}blockquote p{margin-bottom:0;font-size:16px;font-weight:300;line-height:25px;}
157
+ blockquote small{display:block;line-height:20px;color:#999999;}blockquote small:before{content:'\2014 \00A0';}
158
+ blockquote.pull-right{float:right;padding-right:15px;padding-left:0;border-right:5px solid #eeeeee;border-left:0;}blockquote.pull-right p,blockquote.pull-right small{text-align:right;}
159
+ blockquote.pull-right small:before{content:'';}
160
+ blockquote.pull-right small:after{content:'\00A0 \2014';}
161
+ q:before,q:after,blockquote:before,blockquote:after{content:"";}
162
+ address{display:block;margin-bottom:20px;font-style:normal;line-height:20px;}
163
+ table{max-width:100%;background-color:transparent;border-collapse:collapse;border-spacing:0;}
164
+ .table{width:100%;margin-bottom:20px;}.table th,.table td{padding:8px;line-height:20px;text-align:left;vertical-align:top;border-top:1px solid #dddddd;}
165
+ .table th{font-weight:bold;}
166
+ .table thead th{vertical-align:bottom;}
167
+ .table caption+thead tr:first-child th,.table caption+thead tr:first-child td,.table colgroup+thead tr:first-child th,.table colgroup+thead tr:first-child td,.table thead:first-child tr:first-child th,.table thead:first-child tr:first-child td{border-top:0;}
168
+ .table tbody+tbody{border-top:2px solid #dddddd;}
169
+ .table-condensed th,.table-condensed td{padding:4px 5px;}
170
+ .table-bordered{border:1px solid #dddddd;border-collapse:separate;*border-collapse:collapse;border-left:0;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;}.table-bordered th,.table-bordered td{border-left:1px solid #dddddd;}
171
+ .table-bordered caption+thead tr:first-child th,.table-bordered caption+tbody tr:first-child th,.table-bordered caption+tbody tr:first-child td,.table-bordered colgroup+thead tr:first-child th,.table-bordered colgroup+tbody tr:first-child th,.table-bordered colgroup+tbody tr:first-child td,.table-bordered thead:first-child tr:first-child th,.table-bordered tbody:first-child tr:first-child th,.table-bordered tbody:first-child tr:first-child td{border-top:0;}
172
+ .table-bordered thead:first-child tr:first-child th:first-child,.table-bordered tbody:first-child tr:first-child td:first-child{-webkit-border-top-left-radius:4px;border-top-left-radius:4px;-moz-border-radius-topleft:4px;}
173
+ .table-bordered thead:first-child tr:first-child th:last-child,.table-bordered tbody:first-child tr:first-child td:last-child{-webkit-border-top-right-radius:4px;border-top-right-radius:4px;-moz-border-radius-topright:4px;}
174
+ .table-bordered thead:last-child tr:last-child th:first-child,.table-bordered tbody:last-child tr:last-child td:first-child,.table-bordered tfoot:last-child tr:last-child td:first-child{-webkit-border-radius:0 0 0 4px;-moz-border-radius:0 0 0 4px;border-radius:0 0 0 4px;-webkit-border-bottom-left-radius:4px;border-bottom-left-radius:4px;-moz-border-radius-bottomleft:4px;}
175
+ .table-bordered thead:last-child tr:last-child th:last-child,.table-bordered tbody:last-child tr:last-child td:last-child,.table-bordered tfoot:last-child tr:last-child td:last-child{-webkit-border-bottom-right-radius:4px;border-bottom-right-radius:4px;-moz-border-radius-bottomright:4px;}
176
+ .table-bordered caption+thead tr:first-child th:first-child,.table-bordered caption+tbody tr:first-child td:first-child,.table-bordered colgroup+thead tr:first-child th:first-child,.table-bordered colgroup+tbody tr:first-child td:first-child{-webkit-border-top-left-radius:4px;border-top-left-radius:4px;-moz-border-radius-topleft:4px;}
177
+ .table-bordered caption+thead tr:first-child th:last-child,.table-bordered caption+tbody tr:first-child td:last-child,.table-bordered colgroup+thead tr:first-child th:last-child,.table-bordered colgroup+tbody tr:first-child td:last-child{-webkit-border-top-right-radius:4px;border-top-right-radius:4px;-moz-border-radius-topright:4px;}
178
+ .table-striped tbody tr:nth-child(odd) td,.table-striped tbody tr:nth-child(odd) th{background-color:#f9f9f9;}
179
+ .table-hover tbody tr:hover td,.table-hover tbody tr:hover th{background-color:#f5f5f5;}
180
+ table td[class*="span"],table th[class*="span"],.row-fluid table td[class*="span"],.row-fluid table th[class*="span"]{display:table-cell;float:none;margin-left:0;}
181
+ .table td.span1,.table th.span1{float:none;width:44px;margin-left:0;}
182
+ .table td.span2,.table th.span2{float:none;width:124px;margin-left:0;}
183
+ .table td.span3,.table th.span3{float:none;width:204px;margin-left:0;}
184
+ .table td.span4,.table th.span4{float:none;width:284px;margin-left:0;}
185
+ .table td.span5,.table th.span5{float:none;width:364px;margin-left:0;}
186
+ .table td.span6,.table th.span6{float:none;width:444px;margin-left:0;}
187
+ .table td.span7,.table th.span7{float:none;width:524px;margin-left:0;}
188
+ .table td.span8,.table th.span8{float:none;width:604px;margin-left:0;}
189
+ .table td.span9,.table th.span9{float:none;width:684px;margin-left:0;}
190
+ .table td.span10,.table th.span10{float:none;width:764px;margin-left:0;}
191
+ .table td.span11,.table th.span11{float:none;width:844px;margin-left:0;}
192
+ .table td.span12,.table th.span12{float:none;width:924px;margin-left:0;}
193
+ .table tbody tr.success td{background-color:#dff0d8;}
194
+ .table tbody tr.error td{background-color:#f2dede;}
195
+ .table tbody tr.warning td{background-color:#fcf8e3;}
196
+ .table tbody tr.info td{background-color:#d9edf7;}
197
+ .table-hover tbody tr.success:hover td{background-color:#d0e9c6;}
198
+ .table-hover tbody tr.error:hover td{background-color:#ebcccc;}
199
+ .table-hover tbody tr.warning:hover td{background-color:#faf2cc;}
200
+ .table-hover tbody tr.info:hover td{background-color:#c4e3f3;}
201
+ form{margin:0 0 20px;}
202
+ fieldset{padding:0;margin:0;border:0;}
203
+ legend{display:block;width:100%;padding:0;margin-bottom:20px;font-size:21px;line-height:40px;color:#333333;border:0;border-bottom:1px solid #e5e5e5;}legend small{font-size:15px;color:#999999;}
204
+ label,input,button,select,textarea{font-size:14px;font-weight:normal;line-height:20px;}
205
+ input,button,select,textarea{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;}
206
+ label{display:block;margin-bottom:5px;}
207
+ select,textarea,input[type="text"],input[type="password"],input[type="datetime"],input[type="datetime-local"],input[type="date"],input[type="month"],input[type="time"],input[type="week"],input[type="number"],input[type="email"],input[type="url"],input[type="search"],input[type="tel"],input[type="color"],.uneditable-input{display:inline-block;height:20px;padding:4px 6px;margin-bottom:10px;font-size:14px;line-height:20px;color:#555555;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;vertical-align:middle;}
208
+ input,textarea,.uneditable-input{width:206px;}
209
+ textarea{height:auto;}
210
+ textarea,input[type="text"],input[type="password"],input[type="datetime"],input[type="datetime-local"],input[type="date"],input[type="month"],input[type="time"],input[type="week"],input[type="number"],input[type="email"],input[type="url"],input[type="search"],input[type="tel"],input[type="color"],.uneditable-input{background-color:#ffffff;border:1px solid #cccccc;-webkit-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075);-moz-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075);box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075);-webkit-transition:border linear .2s, box-shadow linear .2s;-moz-transition:border linear .2s, box-shadow linear .2s;-o-transition:border linear .2s, box-shadow linear .2s;transition:border linear .2s, box-shadow linear .2s;}textarea:focus,input[type="text"]:focus,input[type="password"]:focus,input[type="datetime"]:focus,input[type="datetime-local"]:focus,input[type="date"]:focus,input[type="month"]:focus,input[type="time"]:focus,input[type="week"]:focus,input[type="number"]:focus,input[type="email"]:focus,input[type="url"]:focus,input[type="search"]:focus,input[type="tel"]:focus,input[type="color"]:focus,.uneditable-input:focus{border-color:rgba(82, 168, 236, 0.8);outline:0;outline:thin dotted \9;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(82,168,236,.6);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(82,168,236,.6);box-shadow:inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(82,168,236,.6);}
211
+ input[type="radio"],input[type="checkbox"]{margin:4px 0 0;*margin-top:0;margin-top:1px \9;line-height:normal;cursor:pointer;}
212
+ input[type="file"],input[type="image"],input[type="submit"],input[type="reset"],input[type="button"],input[type="radio"],input[type="checkbox"]{width:auto;}
213
+ select,input[type="file"]{height:30px;*margin-top:4px;line-height:30px;}
214
+ select{width:220px;border:1px solid #cccccc;background-color:#ffffff;}
215
+ select[multiple],select[size]{height:auto;}
216
+ select:focus,input[type="file"]:focus,input[type="radio"]:focus,input[type="checkbox"]:focus{outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px;}
217
+ .uneditable-input,.uneditable-textarea{color:#999999;background-color:#fcfcfc;border-color:#cccccc;-webkit-box-shadow:inset 0 1px 2px rgba(0, 0, 0, 0.025);-moz-box-shadow:inset 0 1px 2px rgba(0, 0, 0, 0.025);box-shadow:inset 0 1px 2px rgba(0, 0, 0, 0.025);cursor:not-allowed;}
218
+ .uneditable-input{overflow:hidden;white-space:nowrap;}
219
+ .uneditable-textarea{width:auto;height:auto;}
220
+ input:-moz-placeholder,textarea:-moz-placeholder{color:#999999;}
221
+ input:-ms-input-placeholder,textarea:-ms-input-placeholder{color:#999999;}
222
+ input::-webkit-input-placeholder,textarea::-webkit-input-placeholder{color:#999999;}
223
+ .radio,.checkbox{min-height:20px;padding-left:20px;}
224
+ .radio input[type="radio"],.checkbox input[type="checkbox"]{float:left;margin-left:-20px;}
225
+ .controls>.radio:first-child,.controls>.checkbox:first-child{padding-top:5px;}
226
+ .radio.inline,.checkbox.inline{display:inline-block;padding-top:5px;margin-bottom:0;vertical-align:middle;}
227
+ .radio.inline+.radio.inline,.checkbox.inline+.checkbox.inline{margin-left:10px;}
228
+ .input-mini{width:60px;}
229
+ .input-small{width:90px;}
230
+ .input-medium{width:150px;}
231
+ .input-large{width:210px;}
232
+ .input-xlarge{width:270px;}
233
+ .input-xxlarge{width:530px;}
234
+ input[class*="span"],select[class*="span"],textarea[class*="span"],.uneditable-input[class*="span"],.row-fluid input[class*="span"],.row-fluid select[class*="span"],.row-fluid textarea[class*="span"],.row-fluid .uneditable-input[class*="span"]{float:none;margin-left:0;}
235
+ .input-append input[class*="span"],.input-append .uneditable-input[class*="span"],.input-prepend input[class*="span"],.input-prepend .uneditable-input[class*="span"],.row-fluid input[class*="span"],.row-fluid select[class*="span"],.row-fluid textarea[class*="span"],.row-fluid .uneditable-input[class*="span"],.row-fluid .input-prepend [class*="span"],.row-fluid .input-append [class*="span"]{display:inline-block;}
236
+ input,textarea,.uneditable-input{margin-left:0;}
237
+ .controls-row [class*="span"]+[class*="span"]{margin-left:20px;}
238
+ input.span12, textarea.span12, .uneditable-input.span12{width:926px;}
239
+ input.span11, textarea.span11, .uneditable-input.span11{width:846px;}
240
+ input.span10, textarea.span10, .uneditable-input.span10{width:766px;}
241
+ input.span9, textarea.span9, .uneditable-input.span9{width:686px;}
242
+ input.span8, textarea.span8, .uneditable-input.span8{width:606px;}
243
+ input.span7, textarea.span7, .uneditable-input.span7{width:526px;}
244
+ input.span6, textarea.span6, .uneditable-input.span6{width:446px;}
245
+ input.span5, textarea.span5, .uneditable-input.span5{width:366px;}
246
+ input.span4, textarea.span4, .uneditable-input.span4{width:286px;}
247
+ input.span3, textarea.span3, .uneditable-input.span3{width:206px;}
248
+ input.span2, textarea.span2, .uneditable-input.span2{width:126px;}
249
+ input.span1, textarea.span1, .uneditable-input.span1{width:46px;}
250
+ .controls-row{*zoom:1;}.controls-row:before,.controls-row:after{display:table;content:"";line-height:0;}
251
+ .controls-row:after{clear:both;}
252
+ .controls-row [class*="span"],.row-fluid .controls-row [class*="span"]{float:left;}
253
+ .controls-row .checkbox[class*="span"],.controls-row .radio[class*="span"]{padding-top:5px;}
254
+ input[disabled],select[disabled],textarea[disabled],input[readonly],select[readonly],textarea[readonly]{cursor:not-allowed;background-color:#eeeeee;}
255
+ input[type="radio"][disabled],input[type="checkbox"][disabled],input[type="radio"][readonly],input[type="checkbox"][readonly]{background-color:transparent;}
256
+ .control-group.warning>label,.control-group.warning .help-block,.control-group.warning .help-inline{color:#c09853;}
257
+ .control-group.warning .checkbox,.control-group.warning .radio,.control-group.warning input,.control-group.warning select,.control-group.warning textarea{color:#c09853;}
258
+ .control-group.warning input,.control-group.warning select,.control-group.warning textarea{border-color:#c09853;-webkit-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075);-moz-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075);box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075);}.control-group.warning input:focus,.control-group.warning select:focus,.control-group.warning textarea:focus{border-color:#a47e3c;-webkit-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075),0 0 6px #dbc59e;-moz-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075),0 0 6px #dbc59e;box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075),0 0 6px #dbc59e;}
259
+ .control-group.warning .input-prepend .add-on,.control-group.warning .input-append .add-on{color:#c09853;background-color:#fcf8e3;border-color:#c09853;}
260
+ .control-group.error>label,.control-group.error .help-block,.control-group.error .help-inline{color:#b94a48;}
261
+ .control-group.error .checkbox,.control-group.error .radio,.control-group.error input,.control-group.error select,.control-group.error textarea{color:#b94a48;}
262
+ .control-group.error input,.control-group.error select,.control-group.error textarea{border-color:#b94a48;-webkit-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075);-moz-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075);box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075);}.control-group.error input:focus,.control-group.error select:focus,.control-group.error textarea:focus{border-color:#953b39;-webkit-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075),0 0 6px #d59392;-moz-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075),0 0 6px #d59392;box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075),0 0 6px #d59392;}
263
+ .control-group.error .input-prepend .add-on,.control-group.error .input-append .add-on{color:#b94a48;background-color:#f2dede;border-color:#b94a48;}
264
+ .control-group.success>label,.control-group.success .help-block,.control-group.success .help-inline{color:#468847;}
265
+ .control-group.success .checkbox,.control-group.success .radio,.control-group.success input,.control-group.success select,.control-group.success textarea{color:#468847;}
266
+ .control-group.success input,.control-group.success select,.control-group.success textarea{border-color:#468847;-webkit-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075);-moz-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075);box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075);}.control-group.success input:focus,.control-group.success select:focus,.control-group.success textarea:focus{border-color:#356635;-webkit-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075),0 0 6px #7aba7b;-moz-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075),0 0 6px #7aba7b;box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075),0 0 6px #7aba7b;}
267
+ .control-group.success .input-prepend .add-on,.control-group.success .input-append .add-on{color:#468847;background-color:#dff0d8;border-color:#468847;}
268
+ .control-group.info>label,.control-group.info .help-block,.control-group.info .help-inline{color:#3a87ad;}
269
+ .control-group.info .checkbox,.control-group.info .radio,.control-group.info input,.control-group.info select,.control-group.info textarea{color:#3a87ad;}
270
+ .control-group.info input,.control-group.info select,.control-group.info textarea{border-color:#3a87ad;-webkit-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075);-moz-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075);box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075);}.control-group.info input:focus,.control-group.info select:focus,.control-group.info textarea:focus{border-color:#2d6987;-webkit-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075),0 0 6px #7ab5d3;-moz-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075),0 0 6px #7ab5d3;box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075),0 0 6px #7ab5d3;}
271
+ .control-group.info .input-prepend .add-on,.control-group.info .input-append .add-on{color:#3a87ad;background-color:#d9edf7;border-color:#3a87ad;}
272
+ input:focus:required:invalid,textarea:focus:required:invalid,select:focus:required:invalid{color:#b94a48;border-color:#ee5f5b;}input:focus:required:invalid:focus,textarea:focus:required:invalid:focus,select:focus:required:invalid:focus{border-color:#e9322d;-webkit-box-shadow:0 0 6px #f8b9b7;-moz-box-shadow:0 0 6px #f8b9b7;box-shadow:0 0 6px #f8b9b7;}
273
+ .form-actions{padding:19px 20px 20px;margin-top:20px;margin-bottom:20px;background-color:#f5f5f5;border-top:1px solid #e5e5e5;*zoom:1;}.form-actions:before,.form-actions:after{display:table;content:"";line-height:0;}
274
+ .form-actions:after{clear:both;}
275
+ .help-block,.help-inline{color:#595959;}
276
+ .help-block{display:block;margin-bottom:10px;}
277
+ .help-inline{display:inline-block;*display:inline;*zoom:1;vertical-align:middle;padding-left:5px;}
278
+ .input-append,.input-prepend{margin-bottom:5px;font-size:0;white-space:nowrap;}.input-append input,.input-prepend input,.input-append select,.input-prepend select,.input-append .uneditable-input,.input-prepend .uneditable-input,.input-append .dropdown-menu,.input-prepend .dropdown-menu{font-size:14px;}
279
+ .input-append input,.input-prepend input,.input-append select,.input-prepend select,.input-append .uneditable-input,.input-prepend .uneditable-input{position:relative;margin-bottom:0;*margin-left:0;vertical-align:top;-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0;}.input-append input:focus,.input-prepend input:focus,.input-append select:focus,.input-prepend select:focus,.input-append .uneditable-input:focus,.input-prepend .uneditable-input:focus{z-index:2;}
280
+ .input-append .add-on,.input-prepend .add-on{display:inline-block;width:auto;height:20px;min-width:16px;padding:4px 5px;font-size:14px;font-weight:normal;line-height:20px;text-align:center;text-shadow:0 1px 0 #ffffff;background-color:#eeeeee;border:1px solid #ccc;}
281
+ .input-append .add-on,.input-prepend .add-on,.input-append .btn,.input-prepend .btn{vertical-align:top;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;}
282
+ .input-append .active,.input-prepend .active{background-color:#a9dba9;border-color:#46a546;}
283
+ .input-prepend .add-on,.input-prepend .btn{margin-right:-1px;}
284
+ .input-prepend .add-on:first-child,.input-prepend .btn:first-child{-webkit-border-radius:4px 0 0 4px;-moz-border-radius:4px 0 0 4px;border-radius:4px 0 0 4px;}
285
+ .input-append input,.input-append select,.input-append .uneditable-input{-webkit-border-radius:4px 0 0 4px;-moz-border-radius:4px 0 0 4px;border-radius:4px 0 0 4px;}.input-append input+.btn-group .btn,.input-append select+.btn-group .btn,.input-append .uneditable-input+.btn-group .btn{-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0;}
286
+ .input-append .add-on,.input-append .btn,.input-append .btn-group{margin-left:-1px;}
287
+ .input-append .add-on:last-child,.input-append .btn:last-child{-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0;}
288
+ .input-prepend.input-append input,.input-prepend.input-append select,.input-prepend.input-append .uneditable-input{-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;}.input-prepend.input-append input+.btn-group .btn,.input-prepend.input-append select+.btn-group .btn,.input-prepend.input-append .uneditable-input+.btn-group .btn{-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0;}
289
+ .input-prepend.input-append .add-on:first-child,.input-prepend.input-append .btn:first-child{margin-right:-1px;-webkit-border-radius:4px 0 0 4px;-moz-border-radius:4px 0 0 4px;border-radius:4px 0 0 4px;}
290
+ .input-prepend.input-append .add-on:last-child,.input-prepend.input-append .btn:last-child{margin-left:-1px;-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0;}
291
+ .input-prepend.input-append .btn-group:first-child{margin-left:0;}
292
+ input.search-query{padding-right:14px;padding-right:4px \9;padding-left:14px;padding-left:4px \9;margin-bottom:0;-webkit-border-radius:15px;-moz-border-radius:15px;border-radius:15px;}
293
+ .form-search .input-append .search-query,.form-search .input-prepend .search-query{-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;}
294
+ .form-search .input-append .search-query{-webkit-border-radius:14px 0 0 14px;-moz-border-radius:14px 0 0 14px;border-radius:14px 0 0 14px;}
295
+ .form-search .input-append .btn{-webkit-border-radius:0 14px 14px 0;-moz-border-radius:0 14px 14px 0;border-radius:0 14px 14px 0;}
296
+ .form-search .input-prepend .search-query{-webkit-border-radius:0 14px 14px 0;-moz-border-radius:0 14px 14px 0;border-radius:0 14px 14px 0;}
297
+ .form-search .input-prepend .btn{-webkit-border-radius:14px 0 0 14px;-moz-border-radius:14px 0 0 14px;border-radius:14px 0 0 14px;}
298
+ .form-search input,.form-inline input,.form-horizontal input,.form-search textarea,.form-inline textarea,.form-horizontal textarea,.form-search select,.form-inline select,.form-horizontal select,.form-search .help-inline,.form-inline .help-inline,.form-horizontal .help-inline,.form-search .uneditable-input,.form-inline .uneditable-input,.form-horizontal .uneditable-input,.form-search .input-prepend,.form-inline .input-prepend,.form-horizontal .input-prepend,.form-search .input-append,.form-inline .input-append,.form-horizontal .input-append{display:inline-block;*display:inline;*zoom:1;margin-bottom:0;vertical-align:middle;}
299
+ .form-search .hide,.form-inline .hide,.form-horizontal .hide{display:none;}
300
+ .form-search label,.form-inline label,.form-search .btn-group,.form-inline .btn-group{display:inline-block;}
301
+ .form-search .input-append,.form-inline .input-append,.form-search .input-prepend,.form-inline .input-prepend{margin-bottom:0;}
302
+ .form-search .radio,.form-search .checkbox,.form-inline .radio,.form-inline .checkbox{padding-left:0;margin-bottom:0;vertical-align:middle;}
303
+ .form-search .radio input[type="radio"],.form-search .checkbox input[type="checkbox"],.form-inline .radio input[type="radio"],.form-inline .checkbox input[type="checkbox"]{float:left;margin-right:3px;margin-left:0;}
304
+ .control-group{margin-bottom:10px;}
305
+ legend+.control-group{margin-top:20px;-webkit-margin-top-collapse:separate;}
306
+ .form-horizontal .control-group{margin-bottom:20px;*zoom:1;}.form-horizontal .control-group:before,.form-horizontal .control-group:after{display:table;content:"";line-height:0;}
307
+ .form-horizontal .control-group:after{clear:both;}
308
+ .form-horizontal .control-label{float:left;width:160px;padding-top:5px;text-align:right;}
309
+ .form-horizontal .controls{*display:inline-block;*padding-left:20px;margin-left:180px;*margin-left:0;}.form-horizontal .controls:first-child{*padding-left:180px;}
310
+ .form-horizontal .help-block{margin-bottom:0;}
311
+ .form-horizontal input+.help-block,.form-horizontal select+.help-block,.form-horizontal textarea+.help-block{margin-top:10px;}
312
+ .form-horizontal .form-actions{padding-left:180px;}
313
+ .btn{display:inline-block;*display:inline;*zoom:1;padding:4px 12px;margin-bottom:0;font-size:14px;line-height:20px;*line-height:20px;text-align:center;vertical-align:middle;cursor:pointer;color:#333333;text-shadow:0 1px 1px rgba(255, 255, 255, 0.75);background-color:#f5f5f5;background-image:-moz-linear-gradient(top, #ffffff, #e6e6e6);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), to(#e6e6e6));background-image:-webkit-linear-gradient(top, #ffffff, #e6e6e6);background-image:-o-linear-gradient(top, #ffffff, #e6e6e6);background-image:linear-gradient(to bottom, #ffffff, #e6e6e6);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#ffe6e6e6', GradientType=0);border-color:#e6e6e6 #e6e6e6 #bfbfbf;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);*background-color:#e6e6e6;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);border:1px solid #bbbbbb;*border:0;border-bottom-color:#a2a2a2;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;*margin-left:.3em;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.2), 0 1px 2px rgba(0,0,0,.05);-moz-box-shadow:inset 0 1px 0 rgba(255,255,255,.2), 0 1px 2px rgba(0,0,0,.05);box-shadow:inset 0 1px 0 rgba(255,255,255,.2), 0 1px 2px rgba(0,0,0,.05);}.btn:hover,.btn:active,.btn.active,.btn.disabled,.btn[disabled]{color:#333333;background-color:#e6e6e6;*background-color:#d9d9d9;}
314
+ .btn:active,.btn.active{background-color:#cccccc \9;}
315
+ .btn:first-child{*margin-left:0;}
316
+ .btn:hover{color:#333333;text-decoration:none;background-color:#e6e6e6;*background-color:#d9d9d9;background-position:0 -15px;-webkit-transition:background-position 0.1s linear;-moz-transition:background-position 0.1s linear;-o-transition:background-position 0.1s linear;transition:background-position 0.1s linear;}
317
+ .btn:focus{outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px;}
318
+ .btn.active,.btn:active{background-color:#e6e6e6;background-color:#d9d9d9 \9;background-image:none;outline:0;-webkit-box-shadow:inset 0 2px 4px rgba(0,0,0,.15), 0 1px 2px rgba(0,0,0,.05);-moz-box-shadow:inset 0 2px 4px rgba(0,0,0,.15), 0 1px 2px rgba(0,0,0,.05);box-shadow:inset 0 2px 4px rgba(0,0,0,.15), 0 1px 2px rgba(0,0,0,.05);}
319
+ .btn.disabled,.btn[disabled]{cursor:default;background-color:#e6e6e6;background-image:none;opacity:0.65;filter:alpha(opacity=65);-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none;}
320
+ .btn-large{padding:11px 19px;font-size:17.5px;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;}
321
+ .btn-large [class^="icon-"],.btn-large [class*=" icon-"]{margin-top:2px;}
322
+ .btn-small{padding:2px 10px;font-size:11.9px;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;}
323
+ .btn-small [class^="icon-"],.btn-small [class*=" icon-"]{margin-top:0;}
324
+ .btn-mini{padding:1px 6px;font-size:10.5px;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;}
325
+ .btn-block{display:block;width:100%;padding-left:0;padding-right:0;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;}
326
+ .btn-block+.btn-block{margin-top:5px;}
327
+ input[type="submit"].btn-block,input[type="reset"].btn-block,input[type="button"].btn-block{width:100%;}
328
+ .btn-primary.active,.btn-warning.active,.btn-danger.active,.btn-success.active,.btn-info.active,.btn-inverse.active{color:rgba(255, 255, 255, 0.75);}
329
+ .btn{border-color:#c5c5c5;border-color:rgba(0, 0, 0, 0.15) rgba(0, 0, 0, 0.15) rgba(0, 0, 0, 0.25);}
330
+ .btn-primary{color:#ffffff;text-shadow:0 -1px 0 rgba(0, 0, 0, 0.25);background-color:#006dcc;background-image:-moz-linear-gradient(top, #0088cc, #0044cc);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0044cc));background-image:-webkit-linear-gradient(top, #0088cc, #0044cc);background-image:-o-linear-gradient(top, #0088cc, #0044cc);background-image:linear-gradient(to bottom, #0088cc, #0044cc);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0088cc', endColorstr='#ff0044cc', GradientType=0);border-color:#0044cc #0044cc #002a80;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);*background-color:#0044cc;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);}.btn-primary:hover,.btn-primary:active,.btn-primary.active,.btn-primary.disabled,.btn-primary[disabled]{color:#ffffff;background-color:#0044cc;*background-color:#003bb3;}
331
+ .btn-primary:active,.btn-primary.active{background-color:#003399 \9;}
332
+ .btn-warning{color:#ffffff;text-shadow:0 -1px 0 rgba(0, 0, 0, 0.25);background-color:#faa732;background-image:-moz-linear-gradient(top, #fbb450, #f89406);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#fbb450), to(#f89406));background-image:-webkit-linear-gradient(top, #fbb450, #f89406);background-image:-o-linear-gradient(top, #fbb450, #f89406);background-image:linear-gradient(to bottom, #fbb450, #f89406);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffbb450', endColorstr='#fff89406', GradientType=0);border-color:#f89406 #f89406 #ad6704;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);*background-color:#f89406;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);}.btn-warning:hover,.btn-warning:active,.btn-warning.active,.btn-warning.disabled,.btn-warning[disabled]{color:#ffffff;background-color:#f89406;*background-color:#df8505;}
333
+ .btn-warning:active,.btn-warning.active{background-color:#c67605 \9;}
334
+ .btn-danger{color:#ffffff;text-shadow:0 -1px 0 rgba(0, 0, 0, 0.25);background-color:#da4f49;background-image:-moz-linear-gradient(top, #ee5f5b, #bd362f);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#ee5f5b), to(#bd362f));background-image:-webkit-linear-gradient(top, #ee5f5b, #bd362f);background-image:-o-linear-gradient(top, #ee5f5b, #bd362f);background-image:linear-gradient(to bottom, #ee5f5b, #bd362f);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffee5f5b', endColorstr='#ffbd362f', GradientType=0);border-color:#bd362f #bd362f #802420;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);*background-color:#bd362f;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);}.btn-danger:hover,.btn-danger:active,.btn-danger.active,.btn-danger.disabled,.btn-danger[disabled]{color:#ffffff;background-color:#bd362f;*background-color:#a9302a;}
335
+ .btn-danger:active,.btn-danger.active{background-color:#942a25 \9;}
336
+ .btn-success{color:#ffffff;text-shadow:0 -1px 0 rgba(0, 0, 0, 0.25);background-color:#5bb75b;background-image:-moz-linear-gradient(top, #62c462, #51a351);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#62c462), to(#51a351));background-image:-webkit-linear-gradient(top, #62c462, #51a351);background-image:-o-linear-gradient(top, #62c462, #51a351);background-image:linear-gradient(to bottom, #62c462, #51a351);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff62c462', endColorstr='#ff51a351', GradientType=0);border-color:#51a351 #51a351 #387038;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);*background-color:#51a351;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);}.btn-success:hover,.btn-success:active,.btn-success.active,.btn-success.disabled,.btn-success[disabled]{color:#ffffff;background-color:#51a351;*background-color:#499249;}
337
+ .btn-success:active,.btn-success.active{background-color:#408140 \9;}
338
+ .btn-info{color:#ffffff;text-shadow:0 -1px 0 rgba(0, 0, 0, 0.25);background-color:#49afcd;background-image:-moz-linear-gradient(top, #5bc0de, #2f96b4);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#5bc0de), to(#2f96b4));background-image:-webkit-linear-gradient(top, #5bc0de, #2f96b4);background-image:-o-linear-gradient(top, #5bc0de, #2f96b4);background-image:linear-gradient(to bottom, #5bc0de, #2f96b4);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff2f96b4', GradientType=0);border-color:#2f96b4 #2f96b4 #1f6377;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);*background-color:#2f96b4;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);}.btn-info:hover,.btn-info:active,.btn-info.active,.btn-info.disabled,.btn-info[disabled]{color:#ffffff;background-color:#2f96b4;*background-color:#2a85a0;}
339
+ .btn-info:active,.btn-info.active{background-color:#24748c \9;}
340
+ .btn-inverse{color:#ffffff;text-shadow:0 -1px 0 rgba(0, 0, 0, 0.25);background-color:#363636;background-image:-moz-linear-gradient(top, #444444, #222222);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#444444), to(#222222));background-image:-webkit-linear-gradient(top, #444444, #222222);background-image:-o-linear-gradient(top, #444444, #222222);background-image:linear-gradient(to bottom, #444444, #222222);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff444444', endColorstr='#ff222222', GradientType=0);border-color:#222222 #222222 #000000;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);*background-color:#222222;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);}.btn-inverse:hover,.btn-inverse:active,.btn-inverse.active,.btn-inverse.disabled,.btn-inverse[disabled]{color:#ffffff;background-color:#222222;*background-color:#151515;}
341
+ .btn-inverse:active,.btn-inverse.active{background-color:#080808 \9;}
342
+ button.btn,input[type="submit"].btn{*padding-top:3px;*padding-bottom:3px;}button.btn::-moz-focus-inner,input[type="submit"].btn::-moz-focus-inner{padding:0;border:0;}
343
+ button.btn.btn-large,input[type="submit"].btn.btn-large{*padding-top:7px;*padding-bottom:7px;}
344
+ button.btn.btn-small,input[type="submit"].btn.btn-small{*padding-top:3px;*padding-bottom:3px;}
345
+ button.btn.btn-mini,input[type="submit"].btn.btn-mini{*padding-top:1px;*padding-bottom:1px;}
346
+ .btn-link,.btn-link:active,.btn-link[disabled]{background-color:transparent;background-image:none;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none;}
347
+ .btn-link{border-color:transparent;cursor:pointer;color:#0088cc;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;}
348
+ .btn-link:hover{color:#005580;text-decoration:underline;background-color:transparent;}
349
+ .btn-link[disabled]:hover{color:#333333;text-decoration:none;}
350
+ .alert{padding:8px 35px 8px 14px;margin-bottom:20px;text-shadow:0 1px 0 rgba(255, 255, 255, 0.5);background-color:#fcf8e3;border:1px solid #fbeed5;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;color:#c09853;}
351
+ .alert h4{margin:0;}
352
+ .alert .close{position:relative;top:-2px;right:-21px;line-height:20px;}
353
+ .alert-success{background-color:#dff0d8;border-color:#d6e9c6;color:#468847;}
354
+ .alert-danger,.alert-error{background-color:#f2dede;border-color:#eed3d7;color:#b94a48;}
355
+ .alert-info{background-color:#d9edf7;border-color:#bce8f1;color:#3a87ad;}
356
+ .alert-block{padding-top:14px;padding-bottom:14px;}
357
+ .alert-block>p,.alert-block>ul{margin-bottom:0;}
358
+ .alert-block p+p{margin-top:5px;}
359
+ .well{min-height:20px;padding:19px;margin-bottom:20px;background-color:#f5f5f5;border:1px solid #e3e3e3;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.05);-moz-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.05);box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.05);}.well blockquote{border-color:#ddd;border-color:rgba(0, 0, 0, 0.15);}
360
+ .well-large{padding:24px;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;}
361
+ .well-small{padding:9px;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;}
362
+ .close{float:right;font-size:20px;font-weight:bold;line-height:20px;color:#000000;text-shadow:0 1px 0 #ffffff;opacity:0.2;filter:alpha(opacity=20);}.close:hover{color:#000000;text-decoration:none;cursor:pointer;opacity:0.4;filter:alpha(opacity=40);}
363
+ button.close{padding:0;cursor:pointer;background:transparent;border:0;-webkit-appearance:none;}
@@ -0,0 +1,19 @@
1
+ div.alert {
2
+ margin-top: 20px;
3
+ }
4
+
5
+ form.filters {
6
+ margin-top: 40px;
7
+ }
8
+
9
+ .bottom20 {
10
+ margin-bottom: 10px;
11
+ }
12
+
13
+ table {
14
+ white-space: nowrap;
15
+ }
16
+
17
+ form.filters table {
18
+ text-align: left;
19
+ }
@@ -0,0 +1,4 @@
1
+ module Nisetegami
2
+ class ApplicationController < ActionController::Base
3
+ end
4
+ end
@@ -0,0 +1,52 @@
1
+ require_dependency "nisetegami/application_controller"
2
+
3
+ module Nisetegami
4
+ class TemplatesController < ApplicationController
5
+ def index
6
+ @templates = Template.recent
7
+ params[:enabled] = params[:enabled] == 'true' ? true : false unless params[:enabled].blank?
8
+ %w(enabled mailer mailer_action).each do |attr|
9
+ @templates = @templates.where((attr == 'mailer_action' ? 'action' : attr) => params[attr]) unless params[attr].blank?
10
+ end
11
+ %w(name subject from reply_to cc bcc).each do |attr|
12
+ @templates = @templates.where(["#{attr} LIKE ?", "%#{params[attr]}%"]) unless params[attr].blank?
13
+ end
14
+ @templates = @templates.all
15
+ end
16
+
17
+ def actions
18
+ render json: [''] + Nisetegami.mapping.actions(params[:mailer])
19
+ end
20
+
21
+ def edit
22
+ @template = Template.find(params[:id])
23
+ end
24
+
25
+ def update
26
+ @template = Template.find(params[:id])
27
+ if @template.update_attributes(params[:template])
28
+ redirect_to templates_path, notice: t('nisetegami.templates.updated', template: @template.name)
29
+ else
30
+ render action: :edit
31
+ end
32
+ end
33
+
34
+ def destroy
35
+ templates = Template.where(id: params[:template_ids])
36
+ template_names = templates.map(&:name).join(', ')
37
+ templates.destroy_all
38
+ redirect_to templates_path, notice: t('nisetegami.templates.destroyed', templates: template_names)
39
+ end
40
+
41
+ def test
42
+ template = Template.find(params[:id])
43
+ message = unless params[:recipient] =~ Nisetegami.email_re
44
+ {alert: t('nisetegami.templates.wrong_email')}
45
+ else
46
+ template.message(params[:recipient], params[:template]).deliver
47
+ {notice: t('nisetegami.templates.test_email_delivered')}
48
+ end
49
+ redirect_to edit_template_path(template), message
50
+ end
51
+ end
52
+ end
@@ -1,6 +1,8 @@
1
1
  class Nisetegami::Template < ActiveRecord::Base
2
2
 
3
- self.table_name = :nisetegami_templates
3
+ attr_accessible :name, :mailer, :action, :subject, :from,
4
+ :reply_to, :cc, :bcc, :enabled, :only_text,
5
+ :layout_text, :body_text, :layout_html, :body_html
4
6
 
5
7
  ## constants
6
8
 
@@ -9,6 +11,7 @@ class Nisetegami::Template < ActiveRecord::Base
9
11
 
10
12
  ## scopes
11
13
 
14
+ scope :recent, order('id DESC')
12
15
  scope :by_mailer, ->(mailer){ where(mailer: mailer.respond_to?(:name) ? mailer.name : mailer) }
13
16
  scope :by_action, ->(action){ where(action: action) }
14
17
  scope :by_layout, ->(layout){ where(layout: layout) }
@@ -18,15 +21,19 @@ class Nisetegami::Template < ActiveRecord::Base
18
21
  scope :text, where(only_text: true)
19
22
 
20
23
  ## validations
21
- email_re = '[-a-z0-9_+\.]+@([-a-z0-9]+\.)+[a-z0-9]{2,}'
22
- address_re = "(?:[^<@]+\\s+<#{email_re}>|#{email_re})"
24
+
25
+ address_re = "(?:[^<@]+\\s+<#{Nisetegami.email_re}>|#{Nisetegami.email_re})"
23
26
  addresses_re = /^#{address_re}(?:\s*,\s*#{address_re})*$/i
24
27
  validates_format_of :from, :reply_to, :cc, :bcc, with: addresses_re, allow_blank: true
25
- validate :subject, :body_text, :layout_text, :name, presence: true
28
+ validate :name, :subject, :body_text, :layout_text, presence: true
26
29
  validate :body_html, :layout_html, presence: true, unless: :only_text?
27
30
  validate :check_template_syntax
28
31
  validate :check_mailer
29
32
 
33
+ ## callbacks
34
+
35
+ before_validation :set_name_if_necessary
36
+
30
37
  ## class-methods
31
38
 
32
39
  # Accepts an instance of the ActionMailer::Base subclass
@@ -36,8 +43,6 @@ class Nisetegami::Template < ActiveRecord::Base
36
43
  relation.where(mailer: mailer_instance.class.name, action: mailer_instance.action_name).first
37
44
  end
38
45
 
39
- public
40
-
41
46
  def layout_html_path
42
47
  layout_html && File.join(Nisetegami.layouts_path, layout_html)
43
48
  end
@@ -127,6 +132,10 @@ class Nisetegami::Template < ActiveRecord::Base
127
132
  false
128
133
  end
129
134
 
135
+ def set_name_if_necessary
136
+ self.name = "#{mailer}##{action}" unless name.present?
137
+ end
138
+
130
139
  end
131
140
 
132
141
  # == Schema Information
@@ -0,0 +1,27 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title><%= t('nisetegami.admin.title') %></title>
5
+ <%= stylesheet_link_tag "nisetegami/application", :media => "all" %>
6
+ <%= javascript_include_tag "nisetegami/application" %>
7
+ <%= csrf_meta_tags %>
8
+ </head>
9
+ <body>
10
+
11
+ <div class="container-fluid">
12
+ <% flash.each do |kind, value| %>
13
+ <div class="alert alert-<%= kind == :alert ? 'error' : 'success' %>">
14
+ <button type="button" class="close" data-dismiss="alert">×</button>
15
+ <% if kind == :alert %>
16
+ <strong><%= t('nisetegami.flash.alert') %>:</strong> <%= value %>
17
+ <% else %>
18
+ <%= value %>
19
+ <% end %>
20
+ </div>
21
+ <% end %>
22
+
23
+ <%= yield %>
24
+ </div>
25
+
26
+ </body>
27
+ </html>
@@ -0,0 +1,5 @@
1
+ <tr>
2
+ <th colspan="10" align="left">
3
+ <%= submit_tag t('.label'), class: 'btn btn-danger', confirm: t('nisetegami.are_you_sure') %>
4
+ </th>
5
+ </tr>
@@ -0,0 +1,3 @@
1
+ <% margin_class = defined?(bottom_margin) && bottom_margin ? 'bottom20' : '' %>
2
+ <%= f.submit t('.update'), class: "btn btn-primary #{margin_class}" %>
3
+ <%= link_to t('.cancel'), templates_path, class: "btn #{margin_class}" %>
@@ -0,0 +1,6 @@
1
+ <div class="control-group">
2
+ <%= f.label attr, class: 'control-label' %>
3
+ <div class="controls">
4
+ <%= (input = yield).present? ? input : f.text_field(attr) %>
5
+ </div>
6
+ </div>
@@ -0,0 +1,35 @@
1
+ <%= form_tag '', method: :get, class: 'filters well' do %>
2
+ <table>
3
+ <tr>
4
+ <th colspan="2"><h3><%= t('.title') %></h3></th>
5
+ </tr>
6
+ <tr>
7
+ <th><%= Nisetegami::Template.human_attribute_name :name %></th>
8
+ <td><%= text_field_tag :name, params[:name] %></td>
9
+ </tr>
10
+ <tr>
11
+ <th><%= t('.state') %></th>
12
+ <td><%= select_tag :enabled, options_for_select([[''], [t('.enabled'), true], [t('.disabled'), false]], params[:enabled]) %></td>
13
+ </tr>
14
+ <tr>
15
+ <th><%= Nisetegami::Template.human_attribute_name :mailer %></th>
16
+ <td><%= select_tag :mailer, options_for_select(([''] + Nisetegami.mapping.mailers.to_a), params[:mailer]) %></td>
17
+ </tr>
18
+ <tr>
19
+ <th><%= Nisetegami::Template.human_attribute_name :action %></th>
20
+ <td><%= select_tag :mailer_action, options_for_select(params[:mailer].blank? ? '' : ([''] + Nisetegami.mapping.actions(params[:mailer]).to_a), params[:mailer_action]) %></td>
21
+ </tr>
22
+ <% %w(subject from reply_to cc bcc).each do |attr| %>
23
+ <tr>
24
+ <th><%= Nisetegami::Template.human_attribute_name attr %></th>
25
+ <td><%= text_field_tag attr, params[attr] %></td>
26
+ </tr>
27
+ <% end %>
28
+ <tr>
29
+ <th colspan="2" align="left">
30
+ <%= submit_tag t('.filter'), class: 'btn btn-primary' %>
31
+ <%= content_tag :button, t('.reset'), class: 'reset btn btn-inverse' %>
32
+ </th>
33
+ </tr>
34
+ </table>
35
+ <% end %>
@@ -0,0 +1,26 @@
1
+ <%= form_tag test_template_path(template), class: 'well' do %>
2
+ <h3><%= t('.title') %></h3>
3
+
4
+ <%= label_tag :recipient, t('.recipient') %>
5
+ <%= text_field_tag :recipient %>
6
+
7
+ <%- if template.variable_mapping.present? %>
8
+ <h5><%= t('.variables') %></h5>
9
+ <% end %>
10
+
11
+ <% template.variable_mapping.each do |var| %>
12
+ <% unless var.respond_to?(:keys) %>
13
+ <%= render 'var', var: "[#{var}]", label: var, i18n_label: "#{template.translate_variable(var)}" %>
14
+ <% else %>
15
+ <% var.each do |klass, attributes| %>
16
+ <% attributes.each do |attr| %>
17
+ <%= render 'var', var: "[#{klass}][#{attr}]", label: "#{klass}.#{attr}", i18n_label: "#{template.translate_variable(klass, attr)}" %>
18
+ <% end %>
19
+ <% end %>
20
+ <% end %>
21
+ <% end %>
22
+ <div class="buttons">
23
+ <%= submit_tag t('.send'), class: 'btn btn-primary' %>
24
+ <%= content_tag :button, t('.reset'), class: 'reset btn btn-inverse' %>
25
+ </div>
26
+ <% end %>
@@ -0,0 +1,4 @@
1
+ <%= label_tag "template#{var}", label %>
2
+ <%= label_tag "template#{var}", i18n_label %>
3
+ <%= text_field_tag "template#{var}" %>
4
+
@@ -0,0 +1,36 @@
1
+ <h1><%= t('.title', title: @template.name) %></h1>
2
+
3
+ <div class="row-fluid">
4
+ <div class="span9">
5
+ <%= form_for @template, html: {class: 'well'} do |f| %>
6
+ <fieldset>
7
+ <%= render 'edit_form_buttons', f: f, bottom_margin: true %>
8
+
9
+ <% %w(name subject from reply_to cc bcc).each do |attr| %>
10
+ <%= render 'field', f: f, attr: attr %>
11
+ <% end %>
12
+
13
+ <% %w(enabled only_text).each do |attr| %>
14
+ <%= render layout: 'field', locals: {f: f, attr: attr} do %>
15
+ <%= f.check_box attr %>
16
+ <% end %>
17
+ <% end %>
18
+
19
+ <% %w(text html).each do |format| %>
20
+ <%= render layout: 'field', locals: {f: f, attr: "layout_#{format}"} do %>
21
+ <%= f.select "layout_#{format}", options_for_select([''] + Nisetegami.send("#{format}_layouts")) %>
22
+ <% end %>
23
+ <%= render layout: 'field', locals: {f: f, attr: "body_#{format}"} do %>
24
+ <%= f.text_area "body_#{format}", class: 'span12', rows: 10 %>
25
+ <% end %>
26
+ <% end %>
27
+
28
+ <%= render 'edit_form_buttons', f: f %>
29
+ </fieldset>
30
+ <% end %>
31
+ </div>
32
+
33
+ <div class="span3">
34
+ <%= render 'test_mail', template: Nisetegami::TemplatePresenter.new(@template) %>
35
+ </div>
36
+ </div>
@@ -0,0 +1,42 @@
1
+ <h1><%= t('.title') %></h1>
2
+
3
+ <div class="row-fluid">
4
+ <div class="span8">
5
+ <%= form_tag do %>
6
+ <table class="table table-striped">
7
+ <%- if @templates.empty? %>
8
+ <tr>
9
+ <th><%= t('.no_templates_found') %></th>
10
+ </tr>
11
+ <%- else %>
12
+ <thead>
13
+ <%= render "delete_button" %>
14
+ <tr>
15
+ <%- %w(name mailer action subject from reply_to enabled only_text).each do |attr| %>
16
+ <th><%= Nisetegami::Template.human_attribute_name(attr) %></th>
17
+ <% end %>
18
+ <th><%= t('.edit') %></th>
19
+ <th><%= t('.delete') %></th>
20
+ </tr>
21
+ </thead>
22
+ <tbody>
23
+ <%- @templates.map { |t| Nisetegami::TemplatePresenter.new(t) }.each do |t| %>
24
+ <tr>
25
+ <%- %w(name mailer action subject from reply_to enabled only_text).each do |attr| %>
26
+ <td><%= t.send(attr) %></td>
27
+ <% end %>
28
+ <td><%= link_to t('.edit'), edit_template_path(t) %></td>
29
+ <td><%= check_box_tag 'template_ids[]', t.id %></td>
30
+ </tr>
31
+ <% end %>
32
+ <%= render "delete_button" %>
33
+ </tbody>
34
+ <% end %>
35
+ </table>
36
+ <% end %>
37
+ </div>
38
+
39
+ <div class="span4">
40
+ <%= render 'filters' %>
41
+ </div>
42
+ </div>
@@ -0,0 +1,56 @@
1
+ en:
2
+ activerecord:
3
+ models:
4
+ nisetegami/template: "Mail Template"
5
+ attributes:
6
+ nisetegami/template:
7
+ name: "Name"
8
+ mailer: "Mailer"
9
+ action: "Action"
10
+ subject: "Subject"
11
+ from: "From"
12
+ reply_to: "Reply to"
13
+ cc: "CC"
14
+ bcc: "BCC"
15
+ body_text: "Body text"
16
+ body_html: "Body html"
17
+ layout_text: "Layout text"
18
+ layout_html: "Layout html"
19
+ enabled: "Enabled"
20
+ only_text: "Only text"
21
+ nisetegami:
22
+ flash:
23
+ alert: "Error"
24
+ are_you_sure: "Are you sure?"
25
+ admin:
26
+ title: "Nisetegami Admin"
27
+ templates:
28
+ wrong_email: "Wrong email address"
29
+ test_email_delivered: "Test email delivered"
30
+ destroyed: "Templates %{templates} have been destroyed"
31
+ updated: "Template %{template} has been updated"
32
+ index:
33
+ title: "Mail Templates"
34
+ delete: "Delete"
35
+ edit: "Edit"
36
+ no_templates_found: "There are no templates found"
37
+ delete_button:
38
+ label: "Delete selected"
39
+ edit:
40
+ title: "Mail Template %{title}"
41
+ edit_form_buttons:
42
+ cancel: "Cancel"
43
+ update: "Update"
44
+ filters:
45
+ title: "Filters"
46
+ enabled: "enabled"
47
+ disabled: "disabled"
48
+ filter: "Filter"
49
+ state: "State"
50
+ reset: "Reset"
51
+ test_mail:
52
+ title: "Test Mail"
53
+ variables: "Variables"
54
+ recipient: "Recipient"
55
+ send: "Send"
56
+ reset: "Reset"
@@ -0,0 +1,56 @@
1
+ en:
2
+ activerecord:
3
+ models:
4
+ nisetegami/template: "Шаблон письма"
5
+ attributes:
6
+ nisetegami/template:
7
+ name: "Название"
8
+ mailer: "Мэйлер"
9
+ action: "Экшн"
10
+ subject: "Тема"
11
+ from: "От"
12
+ reply_to: "Ответить"
13
+ cc: "Копия"
14
+ bcc: "Скрытая копия"
15
+ body_text: "Содержание (текст)"
16
+ body_html: "Содержание (html)"
17
+ layout_text: "Лэйаут (текст)"
18
+ layout_html: "Лэйаут (html)"
19
+ enabled: "Включен"
20
+ only_text: "Только текст"
21
+ nisetegami:
22
+ flash:
23
+ alert: "Ошибка"
24
+ are_you_sure: "Вы уверены?"
25
+ admin:
26
+ title: "Админка Nisetegami"
27
+ templates:
28
+ wrong_email: "Неправильный адрес email"
29
+ test_email_delivered: "Тестовое сообщение отправлено"
30
+ destroyed: "Шаблоны %{templates} удалены"
31
+ updated: "Шаблоны %{template} обновлены"
32
+ index:
33
+ title: "Шаблоны писем"
34
+ delete: "Удалить"
35
+ edit: "Редактировать"
36
+ no_templates_found: "Шаблоны не найдены"
37
+ delete_button:
38
+ label: "Удалить выбранное"
39
+ edit:
40
+ title: "Шаблон %{title}"
41
+ edit_form_buttons:
42
+ cancel: "Отмена"
43
+ update: "Обновить"
44
+ filters:
45
+ title: "Фильтры"
46
+ enabled: "включен"
47
+ disabled: "выключен"
48
+ filter: "Отфильтровать"
49
+ state: "Состояние"
50
+ reset: "Сбросить"
51
+ test_mail:
52
+ title: "Тестовое сообщение"
53
+ variables: "Переменные"
54
+ recipient: "Получатель"
55
+ send: "Отправить"
56
+ reset: "Сбросить"
@@ -0,0 +1,6 @@
1
+ Nisetegami::Engine.routes.draw do
2
+ resources :templates, path: '', only: [:index, :edit, :update] do
3
+ post :test, on: :member
4
+ post :actions, :destroy, on: :collection
5
+ end
6
+ end
@@ -8,7 +8,9 @@ require 'nisetegami/asset_provider'
8
8
  require 'nisetegami/exceptions'
9
9
  require 'nisetegami/mapping'
10
10
  require 'nisetegami/utils'
11
+ require 'nisetegami/template_presenter'
11
12
  require 'nisetegami/engine'
13
+ require 'nisetegami/railtie'
12
14
 
13
15
  module Nisetegami
14
16
 
@@ -17,6 +19,9 @@ module Nisetegami
17
19
  mattr_reader :mapping
18
20
  @@mapping = Nisetegami::Mapping.new
19
21
 
22
+ mattr_accessor :email_re
23
+ @@email_re = /[-a-z0-9_+\.]+@([-a-z0-9]+\.)+[a-z0-9]{2,}/
24
+
20
25
  def self.configure
21
26
  yield self
22
27
  end
@@ -14,7 +14,7 @@ module Nisetegami
14
14
  def testing(action, recipient, variables)
15
15
  new.testing do |instance|
16
16
  instance.action_name = action.to_s
17
- variables.each { |k, v| instance.instance_variable_set("@#{k}", v) }
17
+ variables.each { |k, v| instance.instance_variable_set("@#{k}", v) } if variables
18
18
  instance.mail to: recipient
19
19
  end
20
20
  end
@@ -38,11 +38,9 @@ module Nisetegami
38
38
  vars = instance_variables.inject({}) do |hsh, var|
39
39
  unless var =~ /@_/
40
40
  template_var = instance_variable_get(var)
41
- template_var = begin
42
- instance_variable_set(var, "#{template_var.class}Decorator".constantize.decorate(template_var))
43
- rescue NameError
44
- template_var
45
- end
41
+ if template_var.class != (casted = Nisetegami.cast[template_var.class])
42
+ template_var = instance_variable_set(var, casted.new(template_var))
43
+ end
46
44
  hsh[var[1..-1].to_sym] = template_var
47
45
  end
48
46
  hsh
@@ -1,5 +1,3 @@
1
- require 'nisetegami'
2
-
3
1
  module Nisetegami
4
2
  class Engine < Rails::Engine
5
3
  isolate_namespace Nisetegami
@@ -32,9 +32,8 @@ module Nisetegami
32
32
 
33
33
  Nisetegami::Template.create!(
34
34
  subject: "Subject",
35
- body_text: "You can use following variables: #{variables}. Format: text.",
36
- body_html: "You can use following variables: #{variables}. Format: html.",
37
- name: route,
35
+ body_text: "You can use the following variables: #{variables}. Format: text.",
36
+ body_html: "You can use the following variables: #{variables}. Format: html.",
38
37
  mailer: mailer,
39
38
  action: action,
40
39
  enabled: false
@@ -42,6 +41,11 @@ module Nisetegami
42
41
  end
43
42
  end
44
43
 
44
+ def actions(mailer)
45
+ klass = mailer.constantize
46
+ klass.ancestors.include?(ActionMailer::Base) && klass.action_methods
47
+ end
48
+
45
49
  private
46
50
 
47
51
  def expand_locals(*locals)
@@ -62,11 +66,7 @@ module Nisetegami
62
66
  end
63
67
 
64
68
  def action_exists?(mailer, action)
65
- klass = mailer.constantize
66
- klass.ancestors.include?(ActionMailer::Base) &&
67
- klass.action_methods.include?(action.to_s)
68
- rescue NameError
69
- false
69
+ actions(mailer).include?(action.to_s)
70
70
  end
71
71
 
72
72
  end
@@ -0,0 +1,9 @@
1
+ require 'rails/railtie'
2
+
3
+ module Nisetegami
4
+ class Railtie < Rails::Railtie
5
+ rake_tasks do
6
+ load 'tasks/nisetegami_tasks.rake'
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,34 @@
1
+ # encoding: utf-8
2
+
3
+ module Nisetegami
4
+ class TemplatePresenter
5
+ def initialize(template)
6
+ @template = template
7
+ end
8
+
9
+ def mailer
10
+ I18n.t("nisetegami.mailers.#{@template[:mailer].underscore}", default: @template.mailer)
11
+ end
12
+
13
+ def action
14
+ I18n.t("nisetegami.actions.#{@template[:mailer].underscore}.#{@template.action}", default: @template.action.humanize)
15
+ end
16
+
17
+ def translate_variable(*args)
18
+ '(' + I18n.t!("nisetegami.variables.#{@template[:mailer].underscore}.#{@template.action}." << args.join('.')) + ')'
19
+ rescue I18n::MissingTranslationData
20
+ end
21
+
22
+ %w(enabled only_text).each do |attr|
23
+ define_method(attr) { @template.send(attr) ? '√' : '' }
24
+ end
25
+
26
+ def to_param
27
+ @template.id
28
+ end
29
+
30
+ def method_missing(method, *args, &block)
31
+ @template.send(method, *args, &block)
32
+ end
33
+ end
34
+ end
@@ -1,3 +1,3 @@
1
1
  module Nisetegami
2
- VERSION = "0.4.0"
2
+ VERSION = "0.5.0"
3
3
  end
@@ -1,4 +1,8 @@
1
- # desc "Explaining what the task does"
2
- # task :nisetegami do
3
- # # Task goes here
4
- # end
1
+ namespace :nisetegami do
2
+ namespace :templates do
3
+ desc "Populate nisetegami templates with sample data"
4
+ task :populate => :environment do
5
+ Nisetegami.populate!
6
+ end
7
+ end
8
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: nisetegami
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.0
4
+ version: 0.5.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2012-11-05 00:00:00.000000000 Z
13
+ date: 2012-11-09 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: rails
@@ -92,22 +92,6 @@ dependencies:
92
92
  - - ~>
93
93
  - !ruby/object:Gem::Version
94
94
  version: '3.2'
95
- - !ruby/object:Gem::Dependency
96
- name: rspec
97
- requirement: !ruby/object:Gem::Requirement
98
- none: false
99
- requirements:
100
- - - ! '>='
101
- - !ruby/object:Gem::Version
102
- version: '0'
103
- type: :development
104
- prerelease: false
105
- version_requirements: !ruby/object:Gem::Requirement
106
- none: false
107
- requirements:
108
- - - ! '>='
109
- - !ruby/object:Gem::Version
110
- version: '0'
111
95
  - !ruby/object:Gem::Dependency
112
96
  name: rspec-rails
113
97
  requirement: !ruby/object:Gem::Requirement
@@ -164,7 +148,27 @@ executables: []
164
148
  extensions: []
165
149
  extra_rdoc_files: []
166
150
  files:
151
+ - app/assets/javascripts/nisetegami/application.js
152
+ - app/assets/javascripts/nisetegami/nisetegami.bootstrap.min.js
153
+ - app/assets/javascripts/nisetegami/templates.js.coffee
154
+ - app/assets/stylesheets/nisetegami/application.css.scss
155
+ - app/assets/stylesheets/nisetegami/nisetegami.bootstrap.min.css
156
+ - app/assets/stylesheets/nisetegami/templates.css.scss
157
+ - app/controllers/nisetegami/application_controller.rb
158
+ - app/controllers/nisetegami/templates_controller.rb
167
159
  - app/models/nisetegami/template.rb
160
+ - app/views/layouts/nisetegami/application.html.erb
161
+ - app/views/nisetegami/templates/_delete_button.html.erb
162
+ - app/views/nisetegami/templates/_edit_form_buttons.html.erb
163
+ - app/views/nisetegami/templates/_field.html.erb
164
+ - app/views/nisetegami/templates/_filters.html.erb
165
+ - app/views/nisetegami/templates/_test_mail.html.erb
166
+ - app/views/nisetegami/templates/_var.html.erb
167
+ - app/views/nisetegami/templates/edit.html.erb
168
+ - app/views/nisetegami/templates/index.html.erb
169
+ - config/locales/nisetegami.en.yml
170
+ - config/locales/nisetegami.ru.yml
171
+ - config/routes.rb
168
172
  - lib/generators/nisetegami/templates/migrations/001_create_nisetegami_templates.rb
169
173
  - lib/generators/nisetegami/templates_generator.rb
170
174
  - lib/nisetegami/action_mailer_extensions.rb
@@ -174,6 +178,8 @@ files:
174
178
  - lib/nisetegami/exceptions.rb
175
179
  - lib/nisetegami/liquid_template_handler.rb
176
180
  - lib/nisetegami/mapping.rb
181
+ - lib/nisetegami/railtie.rb
182
+ - lib/nisetegami/template_presenter.rb
177
183
  - lib/nisetegami/test/factories.rb
178
184
  - lib/nisetegami/test/test_mailer.rb
179
185
  - lib/nisetegami/test.rb