fae-rails 2.0.0 → 2.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|