fae-rails 2.0.0 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +3 -1
- data/app/assets/javascripts/fae/form/_ajax.js +21 -1
- data/app/assets/javascripts/fae/form/_cancel.js +1 -0
- data/app/assets/javascripts/fae/form/_validator.js +22 -12
- data/app/assets/javascripts/fae/form/inputs/_color.js +2 -1
- data/app/assets/javascripts/fae/vendor/jqColorPicker.min.js +0 -1
- data/app/controllers/fae/application_controller.rb +15 -1
- data/app/controllers/fae/users_controller.rb +8 -0
- data/app/helpers/fae/form_helper.rb +13 -4
- data/app/helpers/fae/view_helper.rb +76 -31
- data/app/models/concerns/fae/user_concern.rb +10 -1
- data/app/models/fae/static_page.rb +7 -2
- data/app/models/fae/user.rb +2 -3
- data/app/uploaders/fae/file_uploader.rb +1 -1
- data/app/uploaders/fae/image_uploader.rb +1 -1
- data/app/views/fae/application/_file_uploader.html.slim +4 -1
- data/app/views/fae/application/_global_search_results.html.slim +1 -1
- data/app/views/fae/application/_header.slim +8 -8
- data/app/views/fae/application/_markdown_helper.slim +17 -17
- data/app/views/fae/application/_mobilenav.slim +6 -6
- data/app/views/fae/application/_user_log.html.slim +2 -2
- data/app/views/fae/images/_image_uploader.html.slim +1 -1
- data/app/views/fae/options/_form.html.slim +6 -6
- data/app/views/fae/pages/activity_log.html.slim +11 -11
- data/app/views/fae/pages/disabled_environment.html.slim +2 -2
- data/app/views/fae/pages/error404.html.slim +5 -3
- data/app/views/fae/pages/home.html.slim +9 -8
- data/app/views/fae/setup/first_user.html.slim +3 -3
- data/app/views/fae/shared/_form_header.html.slim +3 -3
- data/app/views/fae/shared/_index_header.html.slim +3 -2
- data/app/views/fae/shared/_nested_table.html.slim +1 -1
- data/app/views/fae/shared/_recent_changes.html.slim +6 -6
- data/app/views/fae/shared/_shared_nested_table.html.slim +1 -1
- data/app/views/fae/static_pages/index.html.slim +2 -2
- data/app/views/fae/users/_form.html.slim +8 -12
- data/app/views/fae/users/index.html.slim +6 -6
- data/config/locales/devise.cs.yml +59 -0
- data/config/locales/fae.cs.yml +125 -0
- data/config/locales/fae.en.yml +109 -0
- data/config/locales/fae.zh-CN.yml +109 -0
- data/lib/fae/version.rb +1 -1
- data/lib/generators/fae/base_generator.rb +46 -3
- data/lib/generators/fae/nested_index_scaffold_generator.rb +1 -0
- data/lib/generators/fae/nested_scaffold_generator.rb +1 -0
- data/lib/generators/fae/page_generator.rb +8 -0
- data/lib/generators/fae/scaffold_generator.rb +1 -0
- data/lib/generators/fae/templates/graphql/graphql_page_type.rb +17 -0
- data/lib/generators/fae/templates/graphql/graphql_type.rb +13 -0
- metadata +9 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 64efa885d567372d041fc98081e6074e37adb03a
|
4
|
+
data.tar.gz: 9945edf6077be0c1ef698a593da299c422baeb60
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ab50aeecbc77980ccb20b73c742ef4043b74319b658a4e01f5a88432f538f95896e18bdf87cfdfee55331026d03283315e4b6ff1f1f8738274bc869a458f3bc9
|
7
|
+
data.tar.gz: 48c3aae1f2cde1deb1405161f4942328c417733bf2832bac73fc4ca6967d96c30a0a8dfe994121c19e14631bdaabad28f721c9d4be82bdb099343bfff04f1947
|
data/README.md
CHANGED
@@ -7,7 +7,7 @@
|
|
7
7
|
|
8
8
|
Like many Rails CMS engines, Fae delivers all the basics to get you up and running quickly: authentication, authorization, a sleek UI, form helpers, image processing and workflows. But unlike other engines, Fae's generated models, controllers, and views are built to customize and scale.
|
9
9
|
|
10
|
-
Fae supports Rails
|
10
|
+
Fae 2.0 supports Rails 5.0 to 5.2, support for Rails 4.x is deprecated as of Fae 2.0.
|
11
11
|
|
12
12
|
## Installation
|
13
13
|
|
@@ -61,6 +61,7 @@ https://www.faecms.com/documentation
|
|
61
61
|
|
62
62
|
### Tutorials
|
63
63
|
|
64
|
+
* [Setting Up GraphQL with Fae](docs/tutorials/graphql_support.md)
|
64
65
|
* [Setting Up Images and Files](docs/tutorials/image_and_files.md)
|
65
66
|
* [Adding Dynamic Relationships to Pages](docs/tutorials/dynamic_relationships_to_pages.md)
|
66
67
|
* [Adding Conditional Validations](docs/tutorials/conditional_validations.md)
|
@@ -84,6 +85,7 @@ https://www.faecms.com/documentation
|
|
84
85
|
|
85
86
|
* [Running Fae Locally](docs/contributing/local_setup.md)
|
86
87
|
* [Fae Standards](docs/contributing/standards.md)
|
88
|
+
* [Share Your Creation](docs/contributing/share_your_creation.md)
|
87
89
|
|
88
90
|
## [Upgrading](docs/upgrading/index.md)
|
89
91
|
|
@@ -10,6 +10,7 @@ Fae.form.ajax = {
|
|
10
10
|
init: function() {
|
11
11
|
this.$addedit_form = $('.js-addedit-form, .js-index-addedit-form');
|
12
12
|
this.$filter_form = $('.js-filter-form');
|
13
|
+
this.$nested_form = $('.nested-form');
|
13
14
|
|
14
15
|
this.addEditLinks();
|
15
16
|
this.addEditSubmission();
|
@@ -66,6 +67,9 @@ Fae.form.ajax = {
|
|
66
67
|
$wrapper.find('.input.file').fileinputer();
|
67
68
|
}
|
68
69
|
|
70
|
+
// Bind validation to nested form fields added by AJAX
|
71
|
+
Fae.form.validator.bindValidationEvents(this.$nested_form);
|
72
|
+
|
69
73
|
// Reinitialize form elements
|
70
74
|
Fae.form.dates.initDatepicker();
|
71
75
|
Fae.form.dates.initDateRangePicker();
|
@@ -73,7 +77,12 @@ Fae.form.ajax = {
|
|
73
77
|
Fae.form.slugger.addListener();
|
74
78
|
Fae.form.validator.length_counter.init();
|
75
79
|
Fae.form.text.initMarkdown();
|
80
|
+
Fae.form.text.initHTML();
|
76
81
|
Fae.form.checkbox.setCheckboxAsActive();
|
82
|
+
Fae.form.select.init();
|
83
|
+
|
84
|
+
// validate nested form fields on submit
|
85
|
+
Fae.form.validator.formValidate(this.$nested_form);
|
77
86
|
|
78
87
|
$wrapper.find('.hint').hinter();
|
79
88
|
});
|
@@ -126,7 +135,7 @@ Fae.form.ajax = {
|
|
126
135
|
} else if ($html.hasClass('nested-form')) {
|
127
136
|
|
128
137
|
// we're returning the form due to an error, just replace the form
|
129
|
-
$this.find(
|
138
|
+
$this.find('.nested-form' ).replaceWith($html);
|
130
139
|
$this.find('.select select').fae_chosen();
|
131
140
|
$this.find('.input.file').fileinputer();
|
132
141
|
|
@@ -136,6 +145,7 @@ Fae.form.ajax = {
|
|
136
145
|
Fae.form.validator.length_counter.init();
|
137
146
|
Fae.form.checkbox.setCheckboxAsActive();
|
138
147
|
Fae.form.text.initMarkdown();
|
148
|
+
Fae.form.text.initHTML();
|
139
149
|
|
140
150
|
FCH.smoothScroll($this.find('.js-addedit-form-wrapper'), 500, 100, 120);
|
141
151
|
}
|
@@ -289,6 +299,16 @@ Fae.form.ajax = {
|
|
289
299
|
htmlListeners: function() {
|
290
300
|
$('#js-main-content, .login-form > form')
|
291
301
|
|
302
|
+
/**
|
303
|
+
* For the delete button on file input
|
304
|
+
*/
|
305
|
+
.on('click', '.js-file-clear', function(e) {
|
306
|
+
e.preventDefault();
|
307
|
+
var $parent = $(this).parent();
|
308
|
+
$parent.next().show();
|
309
|
+
$parent.hide();
|
310
|
+
})
|
311
|
+
|
292
312
|
/**
|
293
313
|
* For the yes/no slider
|
294
314
|
*/
|
@@ -26,10 +26,13 @@ Fae.form.validator = {
|
|
26
26
|
/**
|
27
27
|
* Validate the entire form on submit and stop it if the form is invalid
|
28
28
|
*/
|
29
|
-
formValidate: function () {
|
29
|
+
formValidate: function ($scope) {
|
30
30
|
var _this = this;
|
31
31
|
|
32
|
-
|
32
|
+
if (typeof($scope) === 'undefined'){
|
33
|
+
$scope = FCH.$document;
|
34
|
+
}
|
35
|
+
$scope.on('submit', 'form:not([data-remote=true])', function (e) {
|
33
36
|
var $this = $(this);
|
34
37
|
|
35
38
|
if ($this.data('passed_validation') !== 'true') {
|
@@ -58,7 +61,7 @@ Fae.form.validator = {
|
|
58
61
|
}
|
59
62
|
});
|
60
63
|
|
61
|
-
_this.testValidation($this);
|
64
|
+
_this.testValidation($this, $scope);
|
62
65
|
|
63
66
|
}
|
64
67
|
|
@@ -69,7 +72,7 @@ Fae.form.validator = {
|
|
69
72
|
* Tests a forms validation after all validation checks have responded
|
70
73
|
* Polls validations responses every 50ms to allow uniqueness AJAX calls to complete
|
71
74
|
*/
|
72
|
-
testValidation: function($this) {
|
75
|
+
testValidation: function($this, $scope) {
|
73
76
|
var _this = this;
|
74
77
|
_this.validation_test_count++;
|
75
78
|
|
@@ -84,9 +87,11 @@ Fae.form.validator = {
|
|
84
87
|
|
85
88
|
$this.submit();
|
86
89
|
} else {
|
87
|
-
// otherwise scroll to the top to display alerts
|
90
|
+
// otherwise scroll to the top to display alerts (unless in a nested form scope)
|
88
91
|
Fae.navigation.language.checkForHiddenErrors();
|
89
|
-
|
92
|
+
if (typeof($scope) === 'undefined') {
|
93
|
+
FCH.smoothScroll($('#js-main-header'), 500, 100, 0);
|
94
|
+
}
|
90
95
|
|
91
96
|
if ($(".field_with_errors").length) {
|
92
97
|
$('.alert').slideDown('fast').delay(3000).slideUp('fast');
|
@@ -108,10 +113,14 @@ Fae.form.validator = {
|
|
108
113
|
/**
|
109
114
|
* Bind validation events based on input type
|
110
115
|
*/
|
111
|
-
bindValidationEvents: function () {
|
116
|
+
bindValidationEvents: function ($scope) {
|
112
117
|
var _this = this;
|
113
118
|
|
114
|
-
$
|
119
|
+
if (typeof($scope) === 'undefined'){
|
120
|
+
$scope = $('body');
|
121
|
+
}
|
122
|
+
|
123
|
+
$scope.find('[data-validate]').each(function () {
|
115
124
|
var $this = $(this);
|
116
125
|
|
117
126
|
if ($this.data('validate').length) {
|
@@ -264,12 +273,13 @@ Fae.form.validator = {
|
|
264
273
|
// if the kind matches, remove it from the array
|
265
274
|
if (validations[i]['kind'] === kind) {
|
266
275
|
validations.splice(i, 1);
|
276
|
+
i--;
|
277
|
+
} else {
|
278
|
+
// otherwise convert JSON back to a string
|
279
|
+
validations[i] = JSON.stringify(validations[i]);
|
267
280
|
}
|
268
|
-
|
269
|
-
// convert JSON back to a string
|
270
|
-
validations[i] = JSON.stringify(validations[i]);
|
271
281
|
}
|
272
|
-
$field.
|
282
|
+
$field.data('validate', '[' + validations + ']');
|
273
283
|
},
|
274
284
|
|
275
285
|
/**
|
@@ -23,8 +23,9 @@ Fae.form.color = {
|
|
23
23
|
var inputOffset = $elm.offset().top;
|
24
24
|
var distanceToBottom = $(document).height() - inputOffset;
|
25
25
|
var top = distanceToBottom <= this.$UI._height ? 414 : inputOffset + $elm.innerHeight();
|
26
|
+
var left = $elm.offset().left;
|
26
27
|
|
27
|
-
return { left:
|
28
|
+
return { left: left, top: top }
|
28
29
|
},
|
29
30
|
renderCallback: function($elm, toggled) {
|
30
31
|
var colors = this.color.colors;
|
@@ -1,4 +1,3 @@
|
|
1
1
|
/*! tinyColorPicker - v1.1.1 2016-07-15 */
|
2
2
|
|
3
3
|
!function(a,b){"object"==typeof exports?module.exports=b(a):"function"==typeof define&&define.amd?define("colors",[],function(){return b(a)}):a.Colors=b(a)}(this,function(a,b){"use strict";function c(a,c,d,f,g){if("string"==typeof c){var c=v.txt2color(c);d=c.type,p[d]=c[d],g=g!==b?g:c.alpha}else if(c)for(var h in c)a[d][h]=k(c[h]/l[d][h][1],0,1);return g!==b&&(a.alpha=k(+g,0,1)),e(d,f?a:b)}function d(a,b,c){var d=o.options.grey,e={};return e.RGB={r:a.r,g:a.g,b:a.b},e.rgb={r:b.r,g:b.g,b:b.b},e.alpha=c,e.equivalentGrey=n(d.r*a.r+d.g*a.g+d.b*a.b),e.rgbaMixBlack=i(b,{r:0,g:0,b:0},c,1),e.rgbaMixWhite=i(b,{r:1,g:1,b:1},c,1),e.rgbaMixBlack.luminance=h(e.rgbaMixBlack,!0),e.rgbaMixWhite.luminance=h(e.rgbaMixWhite,!0),o.options.customBG&&(e.rgbaMixCustom=i(b,o.options.customBG,c,1),e.rgbaMixCustom.luminance=h(e.rgbaMixCustom,!0),o.options.customBG.luminance=h(o.options.customBG,!0)),e}function e(a,b){var c,e,k,q=b||p,r=v,s=o.options,t=l,u=q.RND,w="",x="",y={hsl:"hsv",rgb:a},z=u.rgb;if("alpha"!==a){for(var A in t)if(!t[A][A]){a!==A&&(x=y[A]||"rgb",q[A]=r[x+"2"+A](q[x])),u[A]||(u[A]={}),c=q[A];for(w in c)u[A][w]=n(c[w]*t[A][w][1])}z=u.rgb,q.HEX=r.RGB2HEX(z),q.equivalentGrey=s.grey.r*q.rgb.r+s.grey.g*q.rgb.g+s.grey.b*q.rgb.b,q.webSave=e=f(z,51),q.webSmart=k=f(z,17),q.saveColor=z.r===e.r&&z.g===e.g&&z.b===e.b?"web save":z.r===k.r&&z.g===k.g&&z.b===k.b?"web smart":"",q.hueRGB=v.hue2RGB(q.hsv.h),b&&(q.background=d(z,q.rgb,q.alpha))}var B,C,D,E=q.rgb,F=q.alpha,G="luminance",H=q.background;return B=i(E,{r:0,g:0,b:0},F,1),B[G]=h(B,!0),q.rgbaMixBlack=B,C=i(E,{r:1,g:1,b:1},F,1),C[G]=h(C,!0),q.rgbaMixWhite=C,s.customBG&&(D=i(E,H.rgbaMixCustom,F,1),D[G]=h(D,!0),D.WCAG2Ratio=j(D[G],H.rgbaMixCustom[G]),q.rgbaMixBGMixCustom=D,D.luminanceDelta=m.abs(D[G]-H.rgbaMixCustom[G]),D.hueDelta=g(H.rgbaMixCustom,D,!0)),q.RGBLuminance=h(z),q.HUELuminance=h(q.hueRGB),s.convertCallback&&s.convertCallback(q,a),q}function f(a,b){var c={},d=0,e=b/2;for(var f in a)d=a[f]%b,c[f]=a[f]+(d>e?b-d:-d);return c}function g(a,b,c){return(m.max(a.r-b.r,b.r-a.r)+m.max(a.g-b.g,b.g-a.g)+m.max(a.b-b.b,b.b-a.b))*(c?255:1)/765}function h(a,b){for(var c=b?1:255,d=[a.r/c,a.g/c,a.b/c],e=o.options.luminance,f=d.length;f--;)d[f]=d[f]<=.03928?d[f]/12.92:m.pow((d[f]+.055)/1.055,2.4);return e.r*d[0]+e.g*d[1]+e.b*d[2]}function i(a,c,d,e){var f={},g=d!==b?d:1,h=e!==b?e:1,i=g+h*(1-g);for(var j in a)f[j]=(a[j]*g+c[j]*h*(1-g))/i;return f.a=i,f}function j(a,b){var c=1;return c=a>=b?(a+.05)/(b+.05):(b+.05)/(a+.05),n(100*c)/100}function k(a,b,c){return a>c?c:b>a?b:a}var l={rgb:{r:[0,255],g:[0,255],b:[0,255]},hsv:{h:[0,360],s:[0,100],v:[0,100]},hsl:{h:[0,360],s:[0,100],l:[0,100]},alpha:{alpha:[0,1]},HEX:{HEX:[0,16777215]}},m=a.Math,n=m.round,o={},p={},q={r:.298954,g:.586434,b:.114612},r={r:.2126,g:.7152,b:.0722},s=function(a){this.colors={RND:{}},this.options={color:"rgba(0,0,0,0)",grey:q,luminance:r,valueRanges:l},t(this,a||{})},t=function(a,d){var e,f=a.options;u(a);for(var g in d)d[g]!==b&&(f[g]=d[g]);e=f.customBG,f.customBG="string"==typeof e?v.txt2color(e).rgb:e,p=c(a.colors,f.color,b,!0)},u=function(a){o!==a&&(o=a,p=a.colors)};s.prototype.setColor=function(a,d,f){return u(this),a?c(this.colors,a,d,b,f):(f!==b&&(this.colors.alpha=k(f,0,1)),e(d))},s.prototype.setCustomBackground=function(a){return u(this),this.options.customBG="string"==typeof a?v.txt2color(a).rgb:a,c(this.colors,b,"rgb")},s.prototype.saveAsBackground=function(){return u(this),c(this.colors,b,"rgb",!0)},s.prototype.toString=function(a,b){return v.color2text((a||"rgb").toLowerCase(),this.colors,b)};var v={txt2color:function(a){var b={},c=a.replace(/(?:#|\)|%)/g,"").split("("),d=(c[1]||"").split(/,\s*/),e=c[1]?c[0].substr(0,3):"rgb",f="";if(b.type=e,b[e]={},c[1])for(var g=3;g--;)f=e[g]||e.charAt(g),b[e][f]=+d[g]/l[e][f][1];else b.rgb=v.HEX2rgb(c[0]);return b.alpha=d[3]?+d[3]:1,b},color2text:function(a,b,c){var d=c!==!1&&n(100*b.alpha)/100,e="number"==typeof d&&c!==!1&&(c||1!==d),f=b.RND.rgb,g=b.RND.hsl,h="hex"===a&&e,i="hex"===a&&!h,j="rgb"===a||h,k=j?f.r+", "+f.g+", "+f.b:i?"#"+b.HEX:g.h+", "+g.s+"%, "+g.l+"%";return i?k:(h?"rgb":a)+(e?"a":"")+"("+k+(e?", "+d:"")+")"},RGB2HEX:function(a){return((a.r<16?"0":"")+a.r.toString(16)+(a.g<16?"0":"")+a.g.toString(16)+(a.b<16?"0":"")+a.b.toString(16)).toUpperCase()},HEX2rgb:function(a){return a=a.split(""),{r:+("0x"+a[0]+a[a[3]?1:0])/255,g:+("0x"+a[a[3]?2:1]+(a[3]||a[1]))/255,b:+("0x"+(a[4]||a[2])+(a[5]||a[2]))/255}},hue2RGB:function(a){var b=6*a,c=~~b%6,d=6===b?0:b-c;return{r:n(255*[1,1-d,0,0,d,1][c]),g:n(255*[d,1,1,1-d,0,0][c]),b:n(255*[0,0,d,1,1,1-d][c])}},rgb2hsv:function(a){var b,c,d,e=a.r,f=a.g,g=a.b,h=0;return g>f&&(f=g+(g=f,0),h=-1),c=g,f>e&&(e=f+(f=e,0),h=-2/6-h,c=m.min(f,g)),b=e-c,d=e?b/e:0,{h:1e-15>d?p&&p.hsl&&p.hsl.h||0:b?m.abs(h+(f-g)/(6*b)):0,s:e?b/e:p&&p.hsv&&p.hsv.s||0,v:e}},hsv2rgb:function(a){var b=6*a.h,c=a.s,d=a.v,e=~~b,f=b-e,g=d*(1-c),h=d*(1-f*c),i=d*(1-(1-f)*c),j=e%6;return{r:[d,h,g,g,i,d][j],g:[i,d,d,h,g,g][j],b:[g,g,i,d,d,h][j]}},hsv2hsl:function(a){var b=(2-a.s)*a.v,c=a.s*a.v;return c=a.s?1>b?b?c/b:0:c/(2-b):0,{h:a.h,s:a.v||c?c:p&&p.hsl&&p.hsl.s||0,l:b/2}},rgb2hsl:function(a,b){var c=v.rgb2hsv(a);return v.hsv2hsl(b?c:p.hsv=c)},hsl2rgb:function(a){var b=6*a.h,c=a.s,d=a.l,e=.5>d?d*(1+c):d+c-c*d,f=d+d-e,g=e?(e-f)/e:0,h=~~b,i=b-h,j=e*g*i,k=f+j,l=e-j,m=h%6;return{r:[e,l,f,f,k,e][m],g:[k,e,e,l,f,f][m],b:[f,f,k,e,e,l][m]}}};return s}),function(a,b){"object"==typeof exports?module.exports=b(a,require("jquery"),require("colors")):"function"==typeof define&&define.amd?define(["jquery","colors"],function(c,d){return b(a,c,d)}):b(a,a.jQuery,a.Colors)}(this,function(a,b,c,d){"use strict";function e(a){return a.value||a.getAttribute("value")||b(a).css("background-color")||"#FFF"}function f(a){return a=a.originalEvent&&a.originalEvent.touches?a.originalEvent.touches[0]:a,a.originalEvent?a.originalEvent:a}function g(a){return b(a.find(r.doRender)[0]||a[0])}function h(c){var d=b(this),f=d.offset(),h=b(a),k=r.gap;c?(s=g(d),s._colorMode=s.data("colorMode"),p.$trigger=d,(t||i()).css(r.positionCallback.call(p,d)||{left:(t._left=f.left)-((t._left+=t._width-(h.scrollLeft()+h.width()))+k>0?t._left+k:0),top:(t._top=f.top+d.outerHeight())-((t._top+=t._height-(h.scrollTop()+h.height()))+k>0?t._top+k:0)}).show(r.animationSpeed,function(){c!==!0&&(y.toggle(!!r.opacity)._width=y.width(),v._width=v.width(),v._height=v.height(),u._height=u.height(),q.setColor(e(s[0])),n(!0))}).off(".tcp").on(D,".cp-xy-slider,.cp-z-slider,.cp-alpha",j)):p.$trigger&&b(t).hide(r.animationSpeed,function(){n(!1),p.$trigger=null}).off(".tcp")}function i(){return b("head").append('<style type="text/css" id="tinyColorPickerStyles">'+(r.css||I)+(r.cssAddon||"")+"</style>"),b(H).css({margin:r.margin}).appendTo("body").show(0,function(){p.$UI=t=b(this),F=r.GPU&&t.css("perspective")!==d,u=b(".cp-z-slider",this),v=b(".cp-xy-slider",this),w=b(".cp-xy-cursor",this),x=b(".cp-z-cursor",this),y=b(".cp-alpha",this),z=b(".cp-alpha-cursor",this),r.buildCallback.call(p,t),t.prepend("<div>").children().eq(0).css("width",t.children().eq(0).width()),t._width=this.offsetWidth,t._height=this.offsetHeight}).hide()}function j(a){var c=this.className.replace(/cp-(.*?)(?:\s*|$)/,"$1").replace("-","_");(a.button||a.which)>1||(a.preventDefault&&a.preventDefault(),a.returnValue=!1,s._offset=b(this).offset(),(c="xy_slider"===c?k:"z_slider"===c?l:m)(a),n(),A.on(E,function(){A.off(".tcp")}).on(C,function(a){c(a),n()}))}function k(a){var b=f(a),c=b.pageX-s._offset.left,d=b.pageY-s._offset.top;q.setColor({s:c/v._width*100,v:100-d/v._height*100},"hsv")}function l(a){var b=f(a).pageY-s._offset.top;q.setColor({h:360-b/u._height*360},"hsv")}function m(a){var b=f(a).pageX-s._offset.left,c=b/y._width;q.setColor({},"rgb",c)}function n(a){var b=q.colors,c=b.hueRGB,e=(b.RND.rgb,b.RND.hsl,r.dark),f=r.light,g=q.toString(s._colorMode,r.forceAlpha),h=b.HUELuminance>.22?e:f,i=b.rgbaMixBlack.luminance>.22?e:f,j=(1-b.hsv.h)*u._height,k=b.hsv.s*v._width,l=(1-b.hsv.v)*v._height,m=b.alpha*y._width,n=F?"translate3d":"",p=s[0].value,t=s[0].hasAttribute("value")&&""===p&&a!==d;v._css={backgroundColor:"rgb("+c.r+","+c.g+","+c.b+")"},w._css={transform:n+"("+k+"px, "+l+"px, 0)",left:F?"":k,top:F?"":l,borderColor:b.RGBLuminance>.22?e:f},x._css={transform:n+"(0, "+j+"px, 0)",top:F?"":j,borderColor:"transparent "+h},y._css={backgroundColor:"#"+b.HEX},z._css={transform:n+"("+m+"px, 0, 0)",left:F?"":m,borderColor:i+" transparent"},s._css={backgroundColor:t?"":g,color:t?"":b.rgbaMixBGMixCustom.luminance>.22?e:f},s.text=t?"":p!==g?g:"",a!==d?o(a):G(o)}function o(a){v.css(v._css),w.css(w._css),x.css(x._css),y.css(y._css),z.css(z._css),r.doRender&&s.css(s._css),s.text&&s.val(s.text),r.renderCallback.call(p,s,"boolean"==typeof a?a:d)}var p,q,r,s,t,u,v,w,x,y,z,A=b(document),B=b(),C="touchmove.tcp mousemove.tcp pointermove.tcp",D="touchstart.tcp mousedown.tcp pointerdown.tcp",E="touchend.tcp mouseup.tcp pointerup.tcp",F=!1,G=a.requestAnimationFrame||a.webkitRequestAnimationFrame||function(a){a()},H='<div class="cp-color-picker"><div class="cp-z-slider"><div class="cp-z-cursor"></div></div><div class="cp-xy-slider"><div class="cp-white"></div><div class="cp-xy-cursor"></div></div><div class="cp-alpha"><div class="cp-alpha-cursor"></div></div></div>',I=".cp-color-picker{position:absolute;overflow:hidden;padding:6px 6px 0;background-color:#444;color:#bbb;font-family:Arial,Helvetica,sans-serif;font-size:12px;font-weight:400;cursor:default;border-radius:5px}.cp-color-picker>div{position:relative;overflow:hidden}.cp-xy-slider{float:left;height:128px;width:128px;margin-bottom:6px;background:linear-gradient(to right,#FFF,rgba(255,255,255,0))}.cp-white{height:100%;width:100%;background:linear-gradient(rgba(0,0,0,0),#000)}.cp-xy-cursor{position:absolute;top:0;width:10px;height:10px;margin:-5px;border:1px solid #fff;border-radius:100%;box-sizing:border-box}.cp-z-slider{float:right;margin-left:6px;height:128px;width:20px;background:linear-gradient(red 0,#f0f 17%,#00f 33%,#0ff 50%,#0f0 67%,#ff0 83%,red 100%)}.cp-z-cursor{position:absolute;margin-top:-4px;width:100%;border:4px solid #fff;border-color:transparent #fff;box-sizing:border-box}.cp-alpha{clear:both;width:100%;height:16px;margin:6px 0;background:linear-gradient(to right,#444,rgba(0,0,0,0))}.cp-alpha-cursor{position:absolute;margin-left:-4px;height:100%;border:4px solid #fff;border-color:#fff transparent;box-sizing:border-box}",J=function(a){q=this.color=new c(a),r=q.options,p=this};J.prototype={render:n,toggle:h},b.fn.colorPicker=function(c){var d=this,f=function(){};return c=b.extend({animationSpeed:150,GPU:!0,doRender:!0,customBG:"#FFF",opacity:!0,renderCallback:f,buildCallback:f,positionCallback:f,body:document.body,scrollResize:!0,gap:4,dark:"#222",light:"#DDD"},c),!p&&c.scrollResize&&b(a).on("resize.tcp scroll.tcp",function(){p.$trigger&&p.toggle.call(p.$trigger[0],!0)}),B=B.add(this),this.colorPicker=p||new J(c),this.options=c,b(c.body).off(".tcp").on(D,function(a){-1===B.add(t).add(b(t).find(a.target)).index(a.target)&&h()}),this.on("focusin.tcp click.tcp",function(a){p.color.options=b.extend(p.color.options,r=d.options),h.call(this,a)}).on("change.tcp",function(){q.setColor(this.value||"#FFF"),d.colorPicker.render(!0)}).each(function(){var a=e(this),d=a.split("("),f=g(b(this));f.data("colorMode",d[1]?d[0].substr(0,3):"HEX").attr("readonly",r.preventFocus),c.doRender&&f.css({"background-color":a,color:function(){return q.setColor(a).rgbaMixBGMixCustom.luminance>.22?c.dark:c.light}})})},b.fn.colorPicker.destroy=function(){b("*").off(".tcp"),p.toggle(!1),B=b()}});
|
4
|
-
//# sourceMappingURL=jqColorPicker.js.map
|
@@ -20,8 +20,22 @@ module Fae
|
|
20
20
|
|
21
21
|
private
|
22
22
|
|
23
|
+
# defines the locale used to translate the Fae interface
|
23
24
|
def set_locale
|
24
|
-
I18n.
|
25
|
+
if I18n.available_locales.include?(language_from_browser)
|
26
|
+
language_from_browser
|
27
|
+
else
|
28
|
+
:en
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
# parse HTTP_ACCEPT_LANGUAGE and return an array of language codes
|
33
|
+
# ex: ["en-US", "en", "zh-CN", "zh", "cs"]
|
34
|
+
# then grab the first and convert to symbol
|
35
|
+
def language_from_browser
|
36
|
+
if request.env['HTTP_ACCEPT_LANGUAGE'].present?
|
37
|
+
request.env['HTTP_ACCEPT_LANGUAGE'].scan(/[a-z-]{2,5}/i).first.try(:to_sym)
|
38
|
+
end
|
25
39
|
end
|
26
40
|
|
27
41
|
def check_disabled_environment
|
@@ -3,6 +3,7 @@ module Fae
|
|
3
3
|
before_action :admin_only, except: [:settings, :update]
|
4
4
|
before_action :set_user, only: [:show, :edit, :update, :destroy]
|
5
5
|
before_action :set_role_collection, except: [:index, :destroy]
|
6
|
+
before_action :set_index_path, only: [:settings, :new, :edit]
|
6
7
|
|
7
8
|
def index
|
8
9
|
@users = current_user.super_admin? ? Fae::User.all : Fae::User.public_users
|
@@ -17,6 +18,8 @@ module Fae
|
|
17
18
|
|
18
19
|
def settings
|
19
20
|
@user = current_user
|
21
|
+
# set index path to dashboard
|
22
|
+
@index_path = root_path
|
20
23
|
end
|
21
24
|
|
22
25
|
def create
|
@@ -67,5 +70,10 @@ module Fae
|
|
67
70
|
params.require(:user).permit(:email, :first_name, :last_name, :password, :password_confirmation)
|
68
71
|
end
|
69
72
|
end
|
73
|
+
|
74
|
+
def set_index_path
|
75
|
+
# @index_path determines form's cancel btn path
|
76
|
+
@index_path = users_path
|
77
|
+
end
|
70
78
|
end
|
71
79
|
end
|
@@ -122,7 +122,7 @@ module Fae
|
|
122
122
|
options[:helper_text] = attempt_common_helper_text(attribute) if options[:helper_text].blank?
|
123
123
|
|
124
124
|
attribute_name = options[:as].to_s == 'hidden' ? '' : attribute.to_s.titleize
|
125
|
-
label = options[:label] || attribute_name
|
125
|
+
label = options[:label] || label_translation(attribute) || attribute_name
|
126
126
|
if options[:markdown_supported].present? || options[:helper_text].present?
|
127
127
|
label += content_tag :h6, class: 'helper_text' do
|
128
128
|
concat(options[:helper_text]) if options[:helper_text].present?
|
@@ -134,6 +134,15 @@ module Fae
|
|
134
134
|
options[:hint] = hint.html_safe if hint.present?
|
135
135
|
end
|
136
136
|
|
137
|
+
def label_translation(attribute)
|
138
|
+
try_translation attribute, 'fae.form.attribute'
|
139
|
+
end
|
140
|
+
|
141
|
+
def try_translation(item, translation_path)
|
142
|
+
translation = t("#{translation_path}.#{item}")
|
143
|
+
translation =~ /translation_missing/ ? nil : translation
|
144
|
+
end
|
145
|
+
|
137
146
|
def is_attribute_or_association?(f, attribute)
|
138
147
|
f.object.has_attribute?(attribute) || is_association?(f, attribute)
|
139
148
|
end
|
@@ -192,7 +201,7 @@ module Fae
|
|
192
201
|
|
193
202
|
# sets default prompt for pulldowns
|
194
203
|
def set_prompt(f, attribute, options)
|
195
|
-
options[:prompt] = '
|
204
|
+
options[:prompt] = 'None' if is_association?(f, attribute) && f.object.class.reflect_on_association(attribute).macro == :belongs_to && options[:prompt].nil? && !options[:two_pane]
|
196
205
|
end
|
197
206
|
|
198
207
|
# removes language suffix from label and adds data attr for languange nav
|
@@ -228,9 +237,9 @@ module Fae
|
|
228
237
|
def attempt_common_helper_text(attribute)
|
229
238
|
case attribute
|
230
239
|
when :seo_title
|
231
|
-
return '
|
240
|
+
return t('fae.seo_title')
|
232
241
|
when :seo_description
|
233
|
-
return '
|
242
|
+
return t('fae.seo_description')
|
234
243
|
else
|
235
244
|
''
|
236
245
|
end
|
@@ -1,5 +1,5 @@
|
|
1
1
|
module Fae
|
2
|
-
module
|
2
|
+
module ViewHelper
|
3
3
|
|
4
4
|
def fae_date_format(datetime, timezone = @option.time_zone)
|
5
5
|
datetime.in_time_zone(timezone).strftime('%m/%d/%y') if is_date_or_time?(datetime)
|
@@ -71,47 +71,34 @@ module Fae
|
|
71
71
|
end
|
72
72
|
|
73
73
|
def fae_filter_form(options = {}, &block)
|
74
|
-
options
|
75
|
-
options[:action] ||= "#{@index_path}/filter"
|
76
|
-
options[:title] ||= "Search #{@klass_humanized.pluralize.titleize}"
|
77
|
-
options[:search] = true if options[:search].nil?
|
78
|
-
options[:cookie_key] ||= false
|
79
|
-
|
74
|
+
options = prepare_options_for_filter_form options
|
80
75
|
return if options[:collection].blank?
|
81
76
|
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
filter_header = content_tag(:div, class: 'table-filter-header') do
|
86
|
-
concat content_tag :h4, options[:title]
|
87
|
-
concat filter_search_field if options[:search]
|
88
|
-
end
|
89
|
-
|
90
|
-
form_tag(options[:action], form_hash) do
|
91
|
-
concat filter_header
|
77
|
+
form_tag(options[:action], prepare_form_filter_hash(options)) do
|
78
|
+
concat prepare_filter_header(options)
|
92
79
|
|
93
80
|
if block_given?
|
94
81
|
filter_group_wrapper = content_tag(:div, class: 'table-filter-group-wrapper') do
|
82
|
+
link_tag = content_tag(:a,
|
83
|
+
t('fae.reset_search'),
|
84
|
+
class: 'js-reset-btn button -small hidden',
|
85
|
+
href: '#')
|
95
86
|
concat capture(&block)
|
96
|
-
concat content_tag(:div,
|
87
|
+
concat content_tag(:div,
|
88
|
+
link_tag,
|
89
|
+
class: 'table-filter-group')
|
97
90
|
end
|
98
91
|
end
|
99
|
-
|
100
92
|
concat filter_group_wrapper
|
101
93
|
# I know this `unless !` looks like it should be an `if` but it's definitely supposed to be `unless !`
|
102
|
-
|
94
|
+
unless !options[:search]
|
95
|
+
concat submit_tag t('fae.apply_filters'), class: 'hidden'
|
96
|
+
end
|
103
97
|
end
|
104
98
|
end
|
105
99
|
|
106
|
-
def fae_filter_select(attribute,
|
107
|
-
options
|
108
|
-
options[:collection] ||= default_collection_from_attribute(attribute)
|
109
|
-
options[:label_method] ||= :fae_display_field
|
110
|
-
options[:placeholder] = "All #{options[:label].pluralize}" if options[:placeholder].nil?
|
111
|
-
options[:options] ||= []
|
112
|
-
options[:grouped_by] ||= nil
|
113
|
-
options[:grouped_options] ||= []
|
114
|
-
|
100
|
+
def fae_filter_select(attribute, opts = {})
|
101
|
+
options = prepare_options_for_filter_select(attribute, opts)
|
115
102
|
# grouped_by takes priority over grouped_options
|
116
103
|
if options[:grouped_by].present?
|
117
104
|
select_options = filter_generate_select_group(options[:collection], options[:grouped_by], options[:label_method])
|
@@ -122,7 +109,6 @@ module Fae
|
|
122
109
|
select_options = options_for_select(options[:options]) if options[:options].present?
|
123
110
|
end
|
124
111
|
|
125
|
-
|
126
112
|
content_tag :div, class: 'table-filter-group' do
|
127
113
|
concat label_tag "filter[#{attribute}]", options[:label]
|
128
114
|
concat select_tag "filter[#{attribute}]", select_options, prompt: options[:placeholder]
|
@@ -144,7 +130,9 @@ module Fae
|
|
144
130
|
|
145
131
|
def filter_search_field
|
146
132
|
content_tag :div, class: 'table-filter-keyword-wrapper' do
|
147
|
-
concat text_field_tag
|
133
|
+
concat text_field_tag('filter[search]',
|
134
|
+
nil,
|
135
|
+
placeholder: t('fae.keyword_search'))
|
148
136
|
concat content_tag(:i, '', class: 'icon-search')
|
149
137
|
end
|
150
138
|
end
|
@@ -171,5 +159,62 @@ module Fae
|
|
171
159
|
datetime.present? && ( datetime.kind_of?(Date) || datetime.kind_of?(Time) || datetime.kind_of?(ActiveSupport::TimeWithZone) )
|
172
160
|
end
|
173
161
|
|
162
|
+
def try_placeholder_translation(attribute, path, label)
|
163
|
+
items = try_translation(attribute, path) || label
|
164
|
+
t('fae.all_items', items: items)
|
165
|
+
end
|
166
|
+
|
167
|
+
def prepare_options_for_filter_select(attribute, options)
|
168
|
+
options = preprare_label_for_filter_select attribute, options
|
169
|
+
options = prepare_placeholder_for_filter_select attribute, options
|
170
|
+
options[:collection] ||= default_collection_from_attribute(attribute)
|
171
|
+
options[:label_method] ||= :fae_display_field
|
172
|
+
options[:options] ||= []
|
173
|
+
options[:grouped_by] ||= nil
|
174
|
+
options[:grouped_options] ||= []
|
175
|
+
options
|
176
|
+
end
|
177
|
+
|
178
|
+
def preprare_label_for_filter_select(attribute, options)
|
179
|
+
options[:label] ||= try_translation(attribute.to_s,
|
180
|
+
options[:translation_path]) ||
|
181
|
+
attribute.to_s.titleize
|
182
|
+
options
|
183
|
+
end
|
184
|
+
|
185
|
+
def prepare_placeholder_for_filter_select(attribute, options)
|
186
|
+
if options[:placeholder].nil?
|
187
|
+
options[:placeholder] = try_placeholder_translation(
|
188
|
+
attribute.to_s.pluralize,
|
189
|
+
options[:translation_path],
|
190
|
+
options[:label].pluralize
|
191
|
+
)
|
192
|
+
end
|
193
|
+
options
|
194
|
+
end
|
195
|
+
|
196
|
+
def prepare_options_for_filter_form(options)
|
197
|
+
options[:collection] ||= @items
|
198
|
+
options[:action] ||= "#{@index_path}/filter"
|
199
|
+
options[:title] ||= t('fae.search',
|
200
|
+
search: @klass_humanized.pluralize.titleize)
|
201
|
+
|
202
|
+
options[:search] = true if options[:search].nil?
|
203
|
+
options[:cookie_key] ||= false
|
204
|
+
options
|
205
|
+
end
|
206
|
+
|
207
|
+
def prepare_filter_header(options)
|
208
|
+
content_tag(:div, class: 'table-filter-header') do
|
209
|
+
concat content_tag :h4, options[:title]
|
210
|
+
concat filter_search_field if options[:search]
|
211
|
+
end
|
212
|
+
end
|
213
|
+
|
214
|
+
def prepare_form_filter_hash(options)
|
215
|
+
form_hash = { class: 'js-filter-form table-filter-area' }
|
216
|
+
form_hash['data-cookie-key'] = options[:cookie_key] if options[:cookie_key].present?
|
217
|
+
form_hash
|
218
|
+
end
|
174
219
|
end
|
175
220
|
end
|