diff --git a/CHANGELOG.md b/CHANGELOG.md index e419ff0b0..ed00ab737 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,7 @@ -* **Build 15x** (2014-10-x) +* **Build 155** (2014-10-16) + - Back-end area can now be customized with colors and logo, via System > Customize Back-end. - Added twig filters `|trans` for `Lang::get(...)` and `|transchoice` for `Lang::choice(...)`. + - `SettingsModel` behavior now uses a cached database query. * **Build 153** (2014-10-09) - Plugins are now updated in order of their dependency definitions. diff --git a/README.md b/README.md index 78ba95dd7..184b46a4d 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -[October](http://octobercms.com) is a Content Management System (CMS) and web platform whose sole purpose is to make your development workflow simple again.We feel building websites has become a convoluted and confusing process that leaves developers unsatisfied, we want to turn you around to the simpler side and get back to basics. +[October](http://octobercms.com) is a Content Management System (CMS) and web platform whose sole purpose is to make your development workflow simple again. We feel building websites has become a convoluted and confusing process that leaves developers unsatisfied, we want to turn you around to the simpler side and get back to basics. October's mission is to show the world that web development is not rocket science. @@ -42,7 +42,7 @@ You can communicate with us using the following mediums: * [Follow us on Facebook](http://facebook.com/octobercms) for announcements and updates. * [Join us on IRC](https://kiwiirc.com/client/irc.freenode.net/?nick=Octonaut|?#october) to chat with us. -### Licence +### License The OctoberCMS platform is open-sourced software licensed under the [MIT license](http://opensource.org/licenses/MIT). diff --git a/modules/backend/ServiceProvider.php b/modules/backend/ServiceProvider.php index 0ee23b327..565513ce7 100644 --- a/modules/backend/ServiceProvider.php +++ b/modules/backend/ServiceProvider.php @@ -37,15 +37,18 @@ class ServiceProvider extends ModuleServiceProvider 'label' => 'File uploader', 'alias' => 'fileupload' ]); - $manager->registerFormWidget('Backend\FormWidgets\Relation', [ 'label' => 'Relationship', 'alias' => 'relation' ]); - $manager->registerFormWidget('Backend\FormWidgets\Datepicker', [ + $manager->registerFormWidget('Backend\FormWidgets\DatePicker', [ 'label' => 'Date picker', 'alias' => 'datepicker' ]); + $manager->registerFormWidget('Backend\FormWidgets\ColorPicker', [ + 'label' => 'Color picker', + 'alias' => 'colorpicker' + ]); $manager->registerFormWidget('Backend\FormWidgets\DataGrid', [ 'label' => 'Data Grid', 'alias' => 'datagrid' @@ -76,6 +79,14 @@ class ServiceProvider extends ModuleServiceProvider */ SettingsManager::instance()->registerCallback(function($manager){ $manager->registerSettingItems('October.Backend', [ + 'branding' => [ + 'label' => 'backend::lang.branding.menu_label', + 'description' => 'backend::lang.branding.menu_description', + 'category' => SettingsManager::CATEGORY_SYSTEM, + 'icon' => 'icon-paint-brush', + 'class' => 'Backend\Models\BrandSettings', + 'order' => 500, + ], 'editor' => [ 'label' => 'backend::lang.editor.menu_label', 'description' => 'backend::lang.editor.menu_description', diff --git a/modules/backend/assets/css/october.css b/modules/backend/assets/css/october.css index 26d3ed5f7..d255d107f 100644 --- a/modules/backend/assets/css/october.css +++ b/modules/backend/assets/css/october.css @@ -8257,7 +8257,7 @@ body.mainmenu-open .mainmenu-collapsed ul { padding: 13px; display: block; font-size: 12px; - color: #808b93; + color: rgba(255, 255, 255, 0.35); font-weight: normal; } #layout-sidenav ul li a:hover { @@ -8268,7 +8268,7 @@ body.mainmenu-open .mainmenu-collapsed ul { background: transparent; } #layout-sidenav ul li a i { - color: #808b93; + color: rgba(255, 255, 255, 0.35); display: block; margin-bottom: 5px; font-size: 28px; @@ -8331,7 +8331,7 @@ body.mainmenu-open .mainmenu-collapsed ul { top: 0; height: 9px; font-size: 10px; - color: #808b93; + color: rgba(255, 255, 255, 0.35); } #layout-sidenav .scroll-marker.before { top: 0; @@ -8350,11 +8350,11 @@ body.mainmenu-open .mainmenu-collapsed ul { } #layout-sidenav.layout-sidenav ul.drag li:not(.active) a:hover, .touch #layout-sidenav.layout-sidenav li:not(.active) a:hover { - color: #808b93 !important; + color: rgba(255, 255, 255, 0.35) !important; } #layout-sidenav.layout-sidenav ul.drag li:not(.active) a:hover i, .touch #layout-sidenav.layout-sidenav li:not(.active) a:hover i { - color: #808b93 !important; + color: rgba(255, 255, 255, 0.35) !important; } #layout-sidenav.layout-sidenav ul.drag li:not(.active) a:hover:after, .touch #layout-sidenav.layout-sidenav li:not(.active) a:hover:after { @@ -8418,7 +8418,7 @@ body.side-panel-fix-shadow #layout-side-panel { border-top: 1px solid #dfdfdf; } #layout-footer .brand, -#layout-footer .motto { +#layout-footer .tagline { margin: 10px; height: 40px; line-height: 40px; @@ -8430,10 +8430,10 @@ body.side-panel-fix-shadow #layout-side-panel { #layout-footer .brand .logo { margin: 0 10px; } -#layout-footer .motto { +#layout-footer .tagline { float: right; } -#layout-footer .motto p { +#layout-footer .tagline p { color: #999999; } body.outer { @@ -8451,16 +8451,16 @@ body.outer .layout > .layout-row.layout-head > .layout-cell { box-sizing: border-box; vertical-align: middle; } -body.outer .layout > .layout-row.layout-head > .layout-cell h1 { +body.outer .layout > .layout-row.layout-head > .layout-cell h1.oc-logo-white { font: 0/0 a; color: transparent; text-shadow: none; background-color: transparent; border: 0; display: inline-block; - background: transparent url(../images/october-logo-text.png) no-repeat left top; - width: 404px; - height: 65px; + width: 100%; + max-width: 410px; + height: 72px; } body.outer .layout > .layout-row > .layout-cell { vertical-align: middle; @@ -8513,10 +8513,10 @@ body.outer .layout > .layout-row > .layout-cell .outer-form-container .forgot-pa top: 8px; } body.outer .layout > .layout-row > .layout-cell .outer-form-container .forgot-password a { - color: #8d969d; + color: rgba(255, 255, 255, 0.44); } body.outer .layout > .layout-row > .layout-cell .outer-form-container .forgot-password:before { - color: #8d969d; + color: rgba(255, 255, 255, 0.44); font-size: 14px; position: relative; margin-right: 5px; @@ -11150,11 +11150,17 @@ html.cssanimations .cursor-loading-indicator.hide { opacity: 1; filter: alpha(opacity=100); } +.oc-logo-white { + background-image: url(../images/october-logo-white.svg); + background-position: 50% 50%; + background-repeat: no-repeat; + background-size: contain; +} .oc-bg-logo { background-image: url(../images/october-logo-transparent.svg); background-position: 50% 50%; background-repeat: no-repeat; - background-size: 50% auto; + background-size: 50% contain; } .dropdown-menu { padding: 0; @@ -12664,7 +12670,7 @@ div.popover-overlay { .fancy-layout.control-tabs.master:after { top: 7px; font-size: 14px; - color: #e39664; + color: rgba(255, 255, 255, 0.35); } .fancy-layout .control-tabs.master:before, .fancy-layout.control-tabs.master:before { @@ -12708,7 +12714,7 @@ div.popover-overlay { top: 4px; right: 1px; color: rgba(255, 255, 255, 0.3) !important; - font: 14px bold "Helvetica Neue", Helvetica, Arial, sans-seri8; + font: 14px bold "Helvetica Neue", Helvetica, Arial, sans-serif; } .fancy-layout .control-tabs.master > div > div.tabs-container > ul.nav-tabs > li span.tab-close i:hover, .fancy-layout.control-tabs.master > div > div.tabs-container > ul.nav-tabs > li span.tab-close i:hover { @@ -12719,7 +12725,7 @@ div.popover-overlay { border-bottom: none; background: transparent; font-size: 14px; - color: #e39664; + color: rgba(255, 255, 255, 0.35); padding: 6px 0 0 0; overflow: visible; } @@ -13114,7 +13120,7 @@ div.popover-overlay { } .fancy-layout .form-tabless-fields label { text-transform: uppercase; - color: #f4c69e; + color: rgba(255, 255, 255, 0.5); margin-bottom: 0; } .fancy-layout .form-tabless-fields input[type=text] { @@ -13200,7 +13206,7 @@ div.popover-overlay { .fancy-layout .form-tabless-fields .loading-indicator-container .loading-indicator { background-color: #e67e22; padding: 0 0 0 30px; - color: #f4c69e; + color: rgba(255, 255, 255, 0.5); margin-top: 1px; height: 90%; font-size: 12px; @@ -13237,7 +13243,7 @@ div.popover-overlay { filter: alpha(opacity=100); } .fancy-layout .field-codeeditor { - border: none!important; + border: none !important; -webkit-border-radius: 0; -moz-border-radius: 0; border-radius: 0; @@ -14551,7 +14557,7 @@ div[data-control="balloon-selector"]:not(.control-disabled) ul li:hover { padding: 15px 15px 15px 40px; background: #3d5265; margin-bottom: 1px; - color: #808c8d; + color: rgba(255, 255, 255, 0.26); text-decoration: none!important; } .sidenav-tree ul.top-level > li > ul li a:hover { @@ -14568,24 +14574,24 @@ div[data-control="balloon-selector"]:not(.control-disabled) ul li:hover { line-height: 150%; } .sidenav-tree ul.top-level > li > ul li a span.header { - color: #cad5d8; + color: rgba(255, 255, 255, 0.74); font-size: 14px; margin-bottom: 5px; } .sidenav-tree ul.top-level > li > ul li a span.description { - color: #bdc3c7; + color: rgba(255, 255, 255, 0.64); font-size: 12px; font-weight: 100; } .sidenav-tree ul.top-level > li > ul li.active a { background: #34495e; - color: #ecf0f1; + color: rgba(255, 255, 255, 0.91); } .sidenav-tree ul.top-level > li > ul li.active a:before { content: ' '; position: absolute; width: 4px; - background: #e6802b; + background: #e67e22; left: 0; top: 0; height: 100%; @@ -14594,7 +14600,7 @@ div[data-control="balloon-selector"]:not(.control-disabled) ul li:hover { color: #ffffff; } .sidenav-tree ul.top-level > li > ul li.active a span.description { - color: #ecf0f1; + color: rgba(255, 255, 255, 0.91); } .sidenav-tree ul.top-level > li > ul li:last-child a { margin-bottom: 0; @@ -14608,34 +14614,34 @@ div[data-control="balloon-selector"]:not(.control-disabled) ul li:hover { @media (max-width: 768px) { .sidenav-tree { width: 100%; - height: auto!important; - display: block!important; + height: auto !important; + display: block !important; } .sidenav-tree > .layout { display: none; } .sidenav-tree-root .sidenav-tree { - width: 100%!important; - height: 100%!important; + width: 100% !important; + height: 100% !important; display: table-cell !important; } .sidenav-tree-root .sidenav-tree .back-link { - display: none!important; + display: none !important; } .sidenav-tree-root .sidenav-tree > .layout { - display: table!important; + display: table !important; } .sidenav-tree-root #layout-body { display: none; } body.has-sidenav-tree .sidenav-tree .back-link { display: block; - background: #2b3e50; padding: 13px 15px; + background: #2b3e50; color: #bdc3c7; font-size: 14px; - text-transform: uppercase; line-height: 14px; + text-transform: uppercase; } body.has-sidenav-tree .sidenav-tree .back-link i { display: inline-block; @@ -14645,6 +14651,6 @@ div[data-control="balloon-selector"]:not(.control-disabled) ul li:hover { text-decoration: none; } body.has-sidenav-tree #layout-body { - display: block!important; + display: block !important; } } diff --git a/modules/backend/assets/images/october-logo-white.svg b/modules/backend/assets/images/october-logo-white.svg new file mode 100644 index 000000000..122438598 --- /dev/null +++ b/modules/backend/assets/images/october-logo-white.svg @@ -0,0 +1,75 @@ + + + +]> + + + + + + + + + + + diff --git a/modules/backend/assets/images/october-logo.svg b/modules/backend/assets/images/october-logo.svg new file mode 100644 index 000000000..b4121e44f --- /dev/null +++ b/modules/backend/assets/images/october-logo.svg @@ -0,0 +1,75 @@ + + + +]> + + + + + + + + + + + diff --git a/modules/backend/assets/less/controls/common.less b/modules/backend/assets/less/controls/common.less index 6f901fb1b..faab59d23 100644 --- a/modules/backend/assets/less/controls/common.less +++ b/modules/backend/assets/less/controls/common.less @@ -26,9 +26,20 @@ } } +// +// Logos +// + +.oc-logo-white { + background-image: url(../images/october-logo-white.svg); + background-position: 50% 50%; + background-repeat: no-repeat; + background-size: contain; +} + .oc-bg-logo { background-image: url(../images/october-logo-transparent.svg); background-position: 50% 50%; background-repeat: no-repeat; - background-size: 50% auto; + background-size: 50% contain; } diff --git a/modules/backend/assets/less/controls/fancylayout.less b/modules/backend/assets/less/controls/fancylayout.less index 52b01a3a3..e8fc91eb0 100644 --- a/modules/backend/assets/less/controls/fancylayout.less +++ b/modules/backend/assets/less/controls/fancylayout.less @@ -41,10 +41,10 @@ font-size: 14px; color: @color-fancy-master-tabs-inactive-text; } - &:before {left: 8px;} - &:after {right: 8px;} - &.scroll-before:before {color: @color-fancy-master-tabs-active-text;} - &.scroll-after:after {color: @color-fancy-master-tabs-active-text;} + &:before { left: 8px; } + &:after { right: 8px; } + &.scroll-before:before { color: @color-fancy-master-tabs-active-text; } + &.scroll-after:after { color: @color-fancy-master-tabs-active-text; } > div > div.tabs-container { background: @color-fancy-master-tabs-bg; @@ -65,12 +65,12 @@ i { top: 4px; right: 1px; - color: rgba(255, 255, 255, 0.3)!important; - font: 14px bold "Helvetica Neue", Helvetica, Arial, sans-seri8; - - &:hover {color: @color-fancy-master-tabs-active-text!important;} + color: rgba(255, 255, 255, 0.3) !important; + font: 14px bold "Helvetica Neue", Helvetica, Arial, sans-serif; + + &:hover { color: @color-fancy-master-tabs-active-text !important; } } - + } a { @@ -126,7 +126,7 @@ z-index: 107; color: @color-fancy-master-tabs-active-text; } - span.tab-close i {color: @color-fancy-master-tabs-active-text;} + span.tab-close i { color: @color-fancy-master-tabs-active-text; } a > span.title { background-color: @color-fancy-form-tabless-fields-bg; @@ -142,17 +142,17 @@ } } - &[data-modified] { - span.tab-close i { - top: 4px; - .hide-text(); + &[data-modified] { + span.tab-close i { + top: 4px; + .hide-text(); - &:before { - .icon(@circle); - font-size: 9px; - } + &:before { + .icon(@circle); + font-size: 9px; } } + } &:first-child { margin-left: 0; @@ -529,8 +529,8 @@ // Code editor // - .field-codeeditor { - border: none!important; + .field-codeeditor { + border: none !important; .border-radius(0); .editor-code { diff --git a/modules/backend/assets/less/controls/filelist.less b/modules/backend/assets/less/controls/filelist.less index 31e82171b..697a1a442 100644 --- a/modules/backend/assets/less/controls/filelist.less +++ b/modules/backend/assets/less/controls/filelist.less @@ -40,6 +40,7 @@ a:hover { background: @color-list-hover; } + &.active a { background: @color-list-active; position: relative; @@ -98,7 +99,7 @@ position: relative; outline: none; - &:hover {background: transparent;} + &:hover { background: transparent; } &:before, &:after { width: 10px; @@ -132,14 +133,16 @@ padding-left: 52px; } - > li.group {padding-left: 20px;} + > li.group { + padding-left: 20px; + } .listPaddings(10, 27px); } &[data-status=collapsed] { > h4 a:before, > div.group > h4 a:before { - .transform( ~'rotate(0deg) translate(3px, 0)' ); + .transform(~'rotate(0deg) translate(3px, 0)'); } & > ul, & > div.subitems { diff --git a/modules/backend/assets/less/controls/sidenav-tree.less b/modules/backend/assets/less/controls/sidenav-tree.less index 3e5ba2973..7b63e0bfb 100644 --- a/modules/backend/assets/less/controls/sidenav-tree.less +++ b/modules/backend/assets/less/controls/sidenav-tree.less @@ -20,10 +20,10 @@ background: #2b3e50!important; } - ul.top-level > li { + ul.top-level > li { &[data-status=collapsed] { > div.group h3:before { - .transform( ~'rotate(0deg) translate(3px, 0)' ); + .transform(~'rotate(0deg) translate(3px, 0)'); } ul { @@ -55,7 +55,7 @@ top: 15px; color: @color-list-arrow; .icon(@caret-right); - .transform( ~'rotate(90deg) translate(5px, 0)' ); + .transform(~'rotate(90deg) translate(5px, 0)'); .transition(all 0.1s ease); } } @@ -137,16 +137,14 @@ .back-link { display: none; - - } } @media (max-width: @screen-sm) { .sidenav-tree { width: 100%; - height: auto!important; - display: block!important; + height: auto !important; + display: block !important; > .layout { display: none; @@ -155,16 +153,16 @@ .sidenav-tree-root { .sidenav-tree { - width: 100%!important; - height: 100%!important; - display: table-cell!important; + width: 100% !important; + height: 100% !important; + display: table-cell !important; .back-link { - display: none!important; + display: none !important; } > .layout { - display: table!important; + display: table !important; } } @@ -177,12 +175,12 @@ .sidenav-tree { .back-link { display: block; - background: @color-sidebarnav-back-link-bg; padding: 13px 15px; + background: @color-sidebarnav-back-link-bg; color: @color-sidebarnav-back-link-text; font-size: 14px; - text-transform: uppercase; line-height: 14px; + text-transform: uppercase; i { display: inline-block; margin-right: 10px; @@ -194,7 +192,7 @@ } #layout-body { - display: block!important; + display: block !important; } } } \ No newline at end of file diff --git a/modules/backend/assets/less/core/variables.less b/modules/backend/assets/less/core/variables.less index 355a56f7d..3575c99e9 100644 --- a/modules/backend/assets/less/core/variables.less +++ b/modules/backend/assets/less/core/variables.less @@ -15,7 +15,7 @@ @btn-default-bg: #e3e3e3; @btn-default-border: #e3e3e3; -@tooltip-bg: #34495E; +@tooltip-bg: #34495e; @link-color: darken(@brand-primary, 15%); @link-hover-color: darken(@link-color, 30%); @@ -68,24 +68,24 @@ @color-footer-border: #dfdfdf; @color-footer-text: #666666; -@color-sidebarnav-bg: #34495E; -@color-sidebarnav-inactive-text: #808b93; -@color-sidebarnav-inactive-icon: #808b93; +@color-sidebarnav-bg: #34495e; @color-sidebarnav-active-text: #ffffff; @color-sidebarnav-active-icon: #ffffff; +@color-sidebarnav-inactive-text: rgba(255,255,255,.35); +@color-sidebarnav-inactive-icon: rgba(255,255,255,.35); @color-sidebarnav-counter-bg: #d9350f; @color-sidebarnav-counter-text: #ffffff; @color-sidebarnav-tree-group: #ecf0f1; @color-sidebarnav-tree-group-bg: #2b3e50; -@color-sidebarnav-tree-inactive-header: #CAD5D8; -@color-sidebarnav-tree-inactive-desc: #bdc3c7; -@color-sidebarnav-tree-inactive-text: #808c8d; +@color-sidebarnav-tree-inactive-header: rgba(255,255,255,.74); +@color-sidebarnav-tree-inactive-desc: rgba(255,255,255,.64); +@color-sidebarnav-tree-inactive-text: rgba(255,255,255,.26); @color-sidebarnav-tree-active-header: #ffffff; @color-sidebarnav-tree-inactive-bg: #3d5265; @color-sidebarnav-tree-active-bg: #34495e; -@color-sidebarnav-tree-active-text: #ecf0f1; -@color-sidebarnav-tree-active-marker: #e6802b; +@color-sidebarnav-tree-active-text: rgba(255,255,255,.91); +@color-sidebarnav-tree-active-marker: #e67e22; @color-sidebarnav-back-link-bg: #2b3e50; @color-sidebarnav-back-link-text: #bdc3c7; @@ -95,7 +95,7 @@ @color-list-arrow: #cfcfcf; @color-list-icon: #a1aab1; @color-list-parent-bg: #ffffff; -@color-list-nav-arrow: #34495E; +@color-list-nav-arrow: #34495e; @color-list-header-bg: transparent; @color-list-head-bg: #ffffff; @color-list-progress-bg: #0181b9; @@ -156,7 +156,7 @@ @color-ui-border: #d7d7d7; -@color-outer-muted-text: #8d969d; +@color-outer-muted-text: rgba(255,255,255,.44); @color-outer-heading: #feffff; @color-outer-description: #999999; @color-outer-bg: #2b3e50; @@ -229,7 +229,7 @@ @color-fancy-master-tabs-bg: #d35400; @color-fancy-master-tabs-active-text: #ffffff; -@color-fancy-master-tabs-inactive-text: #e39664; +@color-fancy-master-tabs-inactive-text: rgba(255, 255, 255, .35); @color-fancy-master-panel-bg: #d35400; @color-fancy-secondary-tabs-bg: #475354; @@ -243,7 +243,7 @@ @color-fancy-primary-tabs-inactive-bg: #d5d9d8; @color-fancy-form-tabless-fields-bg: #e67e22; -@color-fancy-form-label: #f4c69e; +@color-fancy-form-label: rgba(255, 255, 255, .5); @color-fancy-form-text: #ffffff; @color-fancy-form-text-selection: #d35400; @color-fancy-form-placeholder: #f4c69e; diff --git a/modules/backend/assets/less/layout/footer.less b/modules/backend/assets/less/layout/footer.less index 5ff344059..f3ae25f73 100644 --- a/modules/backend/assets/less/layout/footer.less +++ b/modules/backend/assets/less/layout/footer.less @@ -11,7 +11,7 @@ background-color: @color-footer; border-top: 1px solid @color-footer-border; - .brand, .motto { + .brand, .tagline { margin: 10px; height: (@footer-height - 20) + 0px; line-height: (@footer-height - 20) + 0px; @@ -24,7 +24,7 @@ .name { } } - .motto { + .tagline { float: right; p { color: lighten(@color-footer-text, 20%); } } diff --git a/modules/backend/assets/less/layout/outerlayout.less b/modules/backend/assets/less/layout/outerlayout.less index 281da987c..99db0e702 100644 --- a/modules/backend/assets/less/layout/outerlayout.less +++ b/modules/backend/assets/less/layout/outerlayout.less @@ -17,17 +17,16 @@ body.outer { .box-sizing(border-box); vertical-align: middle; - h1 { + h1.oc-logo-white { .hide-text(); display: inline-block; - background: transparent url(../images/october-logo-text.png) no-repeat left top; - width: 404px; - height: 65px; + width: 100%; + max-width: 410px; + height: 72px; } } } - > .layout-cell { vertical-align: middle; diff --git a/modules/backend/assets/less/layout/sidenav.less b/modules/backend/assets/less/layout/sidenav.less index 240e7a60a..8e14fd412 100644 --- a/modules/backend/assets/less/layout/sidenav.less +++ b/modules/backend/assets/less/layout/sidenav.less @@ -56,7 +56,7 @@ &.active a, a:hover { color: @color-sidebarnav-active-text; - i {color: @color-sidebarnav-active-icon;} + i { color: @color-sidebarnav-active-icon; } } span.counter { diff --git a/modules/backend/behaviors/ListController.php b/modules/backend/behaviors/ListController.php index 608d166dc..20da01854 100644 --- a/modules/backend/behaviors/ListController.php +++ b/modules/backend/behaviors/ListController.php @@ -260,6 +260,18 @@ class ListController extends ControllerBehavior return $this->listWidgets[$definition]->onRefresh(); } + /** + * Returns the widget used by this behavior. + * @return Backend\Classes\WidgetBase + */ + public function listGetWidget($definition = null) + { + if (!$definition) + $definition = $this->primaryDefinition; + + return array_get($this->listWidgets, $definition); + } + // // Overrides // diff --git a/modules/backend/behaviors/RelationController.php b/modules/backend/behaviors/RelationController.php index a53fff7a5..6c3aa1de4 100644 --- a/modules/backend/behaviors/RelationController.php +++ b/modules/backend/behaviors/RelationController.php @@ -414,7 +414,7 @@ class RelationController extends ControllerBehavior */ protected function findExistingRelationIds($checkIds = null) { - $foreignKeyName = $this->relationModel->getKeyName(); + $foreignKeyName = $this->relationModel->getQualifiedKeyName(); $results = $this->relationObject ->getBaseQuery() @@ -818,4 +818,4 @@ class RelationController extends ControllerBehavior return $this->sessionKey = FormHelper::getSessionKey(); } -} \ No newline at end of file +} diff --git a/modules/backend/behaviors/UserPreferencesModel.php b/modules/backend/behaviors/UserPreferencesModel.php index c88e61afa..de4b6e69b 100644 --- a/modules/backend/behaviors/UserPreferencesModel.php +++ b/modules/backend/behaviors/UserPreferencesModel.php @@ -38,18 +38,8 @@ class UserPreferencesModel extends SettingsModel if (isset(self::$instances[$this->recordCode])) return self::$instances[$this->recordCode]; - $item = UserPreferences::forUser(); - $item = $item->scopeFindRecord($this->model, $this->recordCode, $item->userContext)->first(); - - if (!$item) { + if (!$item = $this->getSettingsRecord()) { $this->model->initSettingsData(); - - if (method_exists($this->model, 'forceSave')) - $this->model->forceSave(); - else - $this->model->save(); - - $this->model->reload(); $item = $this->model; } @@ -61,7 +51,21 @@ class UserPreferencesModel extends SettingsModel */ public function isConfigured() { - return UserPreferences::forUser()->findRecord($this->recordCode, $item->userContext)->count() > 0; + return $this->getSettingsRecord() !== null; + } + + /** + * Returns the raw Model record that stores the settings. + * @return Model + */ + public function getSettingsRecord() + { + $item = UserPreferences::forUser(); + $record = $item->scopeFindRecord($this->model, $this->recordCode, $item->userContext) + ->remember(1440, $this->getCacheKey()) + ->first(); + + return $record ?: null; } /** @@ -95,4 +99,12 @@ class UserPreferencesModel extends SettingsModel return parent::isKeyAllowed($key); } -} \ No newline at end of file + + /** + * Returns a cache key for this record. + */ + protected function getCacheKey() + { + return 'backend::userpreferences.'.$this->recordCode; + } +} \ No newline at end of file diff --git a/modules/backend/classes/Controller.php b/modules/backend/classes/Controller.php index 88d6557df..4c214048d 100644 --- a/modules/backend/classes/Controller.php +++ b/modules/backend/classes/Controller.php @@ -276,10 +276,9 @@ class Controller extends Extendable if ($result instanceof RedirectResponse) return $result; - // Translate the page title - $this->pageTitle = $this->pageTitle - ? Lang::get($this->pageTitle) - : Lang::get('backend::lang.page.untitled'); + // No page title + if (!$this->pageTitle) + $this->pageTitle = 'backend::lang.page.untitled'; // Load the view if (!$this->suppressView && is_null($result)) diff --git a/modules/backend/controllers/EditorPreferences.php b/modules/backend/controllers/EditorPreferences.php index e73c695de..6969673cb 100644 --- a/modules/backend/controllers/EditorPreferences.php +++ b/modules/backend/controllers/EditorPreferences.php @@ -1,6 +1,5 @@ vars['margin'] = 0; $this->asExtension('FormController')->update(); - $this->pageTitle = Lang::get('backend::lang.editor.menu_label'); + $this->pageTitle = 'backend::lang.editor.menu_label'; } public function index_onSave() diff --git a/modules/backend/controllers/Index.php b/modules/backend/controllers/Index.php index 8f422c1f3..499bd6013 100644 --- a/modules/backend/controllers/Index.php +++ b/modules/backend/controllers/Index.php @@ -37,7 +37,7 @@ class Index extends Controller public function index() { - $this->pageTitle = trans('backend::lang.dashboard.menu_label'); + $this->pageTitle = 'backend::lang.dashboard.menu_label'; BackendMenu::setContextMainMenu('dashboard'); } } \ No newline at end of file diff --git a/modules/backend/controllers/Users.php b/modules/backend/controllers/Users.php index 5db153b3d..2839cfbef 100644 --- a/modules/backend/controllers/Users.php +++ b/modules/backend/controllers/Users.php @@ -1,6 +1,5 @@ pageTitle = Lang::get('backend::lang.myaccount.menu_label'); + $this->pageTitle = 'backend::lang.myaccount.menu_label'; return $this->update($this->user->id, 'myaccount'); } diff --git a/modules/backend/controllers/auth/signin.htm b/modules/backend/controllers/auth/signin.htm index 82ce38808..f5ddccf52 100644 --- a/modules/backend/controllers/auth/signin.htm +++ b/modules/backend/controllers/auth/signin.htm @@ -1,4 +1,4 @@ -

+

diff --git a/modules/backend/controllers/editorpreferences/index.htm b/modules/backend/controllers/editorpreferences/index.htm index 25be31fb9..948d944ef 100644 --- a/modules/backend/controllers/editorpreferences/index.htm +++ b/modules/backend/controllers/editorpreferences/index.htm @@ -52,6 +52,6 @@ -

fatalError) ?>

+

fatalError)) ?>

\ No newline at end of file diff --git a/modules/backend/controllers/groups/create.htm b/modules/backend/controllers/groups/create.htm index 62f852781..3000b0d79 100644 --- a/modules/backend/controllers/groups/create.htm +++ b/modules/backend/controllers/groups/create.htm @@ -2,7 +2,7 @@ @@ -37,6 +37,6 @@ -

fatalError) ?>

+

fatalError)) ?>

\ No newline at end of file diff --git a/modules/backend/controllers/groups/index.htm b/modules/backend/controllers/groups/index.htm index c3dccaf27..ee75b8527 100644 --- a/modules/backend/controllers/groups/index.htm +++ b/modules/backend/controllers/groups/index.htm @@ -1,7 +1,7 @@ diff --git a/modules/backend/controllers/groups/update.htm b/modules/backend/controllers/groups/update.htm index b5d8e4019..ca4184f1e 100644 --- a/modules/backend/controllers/groups/update.htm +++ b/modules/backend/controllers/groups/update.htm @@ -2,7 +2,7 @@ @@ -46,6 +46,6 @@ -

fatalError) ?>

+

fatalError)) ?>

\ No newline at end of file diff --git a/modules/backend/controllers/users/create.htm b/modules/backend/controllers/users/create.htm index 828987baa..bbbb4c83b 100644 --- a/modules/backend/controllers/users/create.htm +++ b/modules/backend/controllers/users/create.htm @@ -1,7 +1,7 @@ @@ -54,7 +54,7 @@
-

fatalError) ?>

+

fatalError)) ?>

\ No newline at end of file diff --git a/modules/backend/controllers/users/myaccount.htm b/modules/backend/controllers/users/myaccount.htm index 32578229e..fe9641d1d 100644 --- a/modules/backend/controllers/users/myaccount.htm +++ b/modules/backend/controllers/users/myaccount.htm @@ -44,7 +44,7 @@
-

fatalError) ?>

+

fatalError)) ?>

\ No newline at end of file diff --git a/modules/backend/controllers/users/update.htm b/modules/backend/controllers/users/update.htm index aa3a486a9..54bb51a6f 100644 --- a/modules/backend/controllers/users/update.htm +++ b/modules/backend/controllers/users/update.htm @@ -1,7 +1,7 @@ @@ -62,7 +62,7 @@
-

fatalError) ?>

+

fatalError)) ?>

\ No newline at end of file diff --git a/modules/backend/formwidgets/ColorPicker.php b/modules/backend/formwidgets/ColorPicker.php new file mode 100644 index 000000000..05b3a93f9 --- /dev/null +++ b/modules/backend/formwidgets/ColorPicker.php @@ -0,0 +1,81 @@ +availableColors = $this->getConfig('availableColors', $this->availableColors); + } + + /** + * {@inheritDoc} + */ + public function render() + { + $this->prepareVars(); + return $this->makePartial('colorpicker'); + } + + /** + * Prepares the list data + */ + public function prepareVars() + { + $this->vars['name'] = $this->formField->getName(); + $this->vars['value'] = $value = $this->getLoadData(); + $this->vars['availableColors'] = $this->availableColors; + $this->vars['isCustomColor'] = !in_array($value, $this->availableColors); + } + + /** + * {@inheritDoc} + */ + public function loadAssets() + { + $this->addCss('vendor/colpick/css/colpick.css', 'core'); + $this->addJs('vendor/colpick/js/colpick.js', 'core'); + $this->addCss('css/colorpicker.css', 'core'); + $this->addJs('js/colorpicker.js', 'core'); + } + + /** + * {@inheritDoc} + */ + public function getSaveData($value) + { + return strlen($value) ? $value : null; + } +} \ No newline at end of file diff --git a/modules/backend/formwidgets/Datepicker.php b/modules/backend/formwidgets/DatePicker.php similarity index 98% rename from modules/backend/formwidgets/Datepicker.php rename to modules/backend/formwidgets/DatePicker.php index b443542cf..2774eb5d0 100644 --- a/modules/backend/formwidgets/Datepicker.php +++ b/modules/backend/formwidgets/DatePicker.php @@ -9,7 +9,7 @@ use Backend\Classes\FormWidgetBase; * @package october\backend * @author Alexey Bobkov, Samuel Georges */ -class Datepicker extends FormWidgetBase +class DatePicker extends FormWidgetBase { /** * {@inheritDoc} @@ -92,4 +92,4 @@ class Datepicker extends FormWidgetBase { return strlen($value) ? $value : null; } -} \ No newline at end of file +} diff --git a/modules/backend/formwidgets/colorpicker/assets/css/colorpicker.css b/modules/backend/formwidgets/colorpicker/assets/css/colorpicker.css new file mode 100644 index 000000000..3c70325a7 --- /dev/null +++ b/modules/backend/formwidgets/colorpicker/assets/css/colorpicker.css @@ -0,0 +1,59 @@ +.field-colorpicker > ul { + list-style-type: none; + padding: 0; + margin: 0; + margin-top: -8px; +} +.field-colorpicker > ul li { + float: left; + text-indent: -9999px; + padding: 3px; + margin: 14px 14px 0 0; + cursor: pointer; + border-radius: 2px; +} +.field-colorpicker > ul li span { + display: block; + width: 25px; + height: 25px; + border: 1px solid #cecece; +} +.field-colorpicker > ul li:hover, +.field-colorpicker > ul li.active { + background-color: #cecece; +} +.field-colorpicker > ul li:hover span, +.field-colorpicker > ul li.active span { + border: 1px solid #ffffff; +} +.field-colorpicker > ul li.custom-color { + position: relative; +} +.field-colorpicker > ul li.custom-color span { + border-style: dashed; +} +.field-colorpicker > ul li.custom-color:hover span, +.field-colorpicker > ul li.custom-color.active span { + border-style: solid; +} +.field-colorpicker > ul li.custom-color:before { + text-indent: 0; + font-family: FontAwesome; + font-weight: normal; + font-style: normal; + text-decoration: inherit; + -webkit-font-smoothing: antialiased; + *margin-right: .3em; + content: "\f0d8"; + display: block; + text-align: center; + color: #000; + background: #e0e0e0; + font-size: 9px; + height: 9px; + line-height: 9px; + width: 9px; + position: absolute; + bottom: 3px; + right: 3px; +} diff --git a/modules/backend/formwidgets/colorpicker/assets/js/colorpicker.js b/modules/backend/formwidgets/colorpicker/assets/js/colorpicker.js new file mode 100644 index 000000000..e281c214e --- /dev/null +++ b/modules/backend/formwidgets/colorpicker/assets/js/colorpicker.js @@ -0,0 +1,114 @@ +/* + * ColorPicker plugin + * + * Data attributes: + * - data-control="colorpicker" - enables the plugin on an element + * - data-data-locker="input#locker" - Input element to store and restore the chosen color + * + * JavaScript API: + * $('div#someElement').colorPicker({ dataLocker: 'input#locker' }) + * + * Dependences: + * - Some other plugin (filename.js) + */ + ++function ($) { "use strict"; + + // COLORPICKER CLASS DEFINITION + // ============================ + + var ColorPicker = function(element, options) { + this.options = options + this.$el = $(element) + + // Init + this.init() + } + + ColorPicker.DEFAULTS = { + dataLocker: null + } + + ColorPicker.prototype.init = function() { + var self = this + this.$dataLocker = $(this.options.dataLocker, this.$el) + this.$colorList = $('>ul', this.$el) + this.$customColor = $('[data-custom-color]', this.$el) + + this.$colorList.on('click', '>li', function(){ + self.selectColor(this) + }) + + /* + * Custom color + */ + if (this.$customColor.length) { + this.$customColor.colpick({ + layout: 'hex', + submit: 0, + color: this.$customColor.data('hexColor'), + onShow: function(cal) { + var el = $(cal).data('colpick').el + self.selectColor(el) + }, + onChange: function(hsb, hex, rgb, el, bySetColor) { + $('>span', el).css('background', '#'+hex) + $(el).data('hexColor', '#'+hex) + self.setColor('#'+hex) + } + }) + } + + } + + ColorPicker.prototype.setColor = function(hexColor) { + this.$dataLocker.val(hexColor) + } + + ColorPicker.prototype.selectColor = function(el) { + var $item = $(el) + + $item + .addClass('active') + .siblings().removeClass('active') + + this.setColor($item.data('hexColor')) + } + + // COLORPICKER PLUGIN DEFINITION + // ============================ + + var old = $.fn.colorPicker + + $.fn.colorPicker = function (option) { + var args = Array.prototype.slice.call(arguments, 1), result + this.each(function () { + var $this = $(this) + var data = $this.data('oc.colorpicker') + var options = $.extend({}, ColorPicker.DEFAULTS, $this.data(), typeof option == 'object' && option) + if (!data) $this.data('oc.colorpicker', (data = new ColorPicker(this, options))) + if (typeof option == 'string') result = data[option].apply(data, args) + if (typeof result != 'undefined') return false + }) + + return result ? result : this + } + + $.fn.colorPicker.Constructor = ColorPicker + + // COLORPICKER NO CONFLICT + // ================= + + $.fn.colorPicker.noConflict = function () { + $.fn.colorPicker = old + return this + } + + // COLORPICKER DATA-API + // =============== + + $(document).render(function() { + $('[data-control="colorpicker"]').colorPicker() + }) + +}(window.jQuery); \ No newline at end of file diff --git a/modules/backend/formwidgets/colorpicker/assets/less/colorpicker.less b/modules/backend/formwidgets/colorpicker/assets/less/colorpicker.less new file mode 100644 index 000000000..51a9a6233 --- /dev/null +++ b/modules/backend/formwidgets/colorpicker/assets/less/colorpicker.less @@ -0,0 +1,72 @@ +@import "../../../../assets/less/core/boot.less"; + + +@color-colorpicker-border: #cecece; +@color-colorpicker-active-border: #fff; +@color-colorpicker-active: #5fb6f5; + +.field-colorpicker { + + > ul { + list-style-type: none; + padding: 0; + margin: 0; + margin-top: -8px; + + li { + float: left; + text-indent: -9999px; + padding: 3px; + margin: 14px 14px 0 0; + cursor: pointer; + border-radius: @border-radius-base; + + span { + display: block; + width: 25px; + height: 25px; + border: 1px solid @color-colorpicker-border; + } + + &:hover, + &.active { + background-color: @color-colorpicker-border; + span { + border: 1px solid @color-colorpicker-active-border; + } + } + + &.custom-color { + position: relative; + span { + border-style: dashed; + } + &:hover, + &.active { + span { + border-style: solid; + } + } + + &:before { + text-indent: 0; + .icon-FontAutumn(); + content: @caret-up; + display: block; + text-align: center; + color: #000; + background: #e0e0e0; + font-size: 9px; + height: 9px; + line-height: 9px; + width: 9px; + position: absolute; + bottom: 3px; + right: 3px; + } + } + } + + } + +} diff --git a/modules/backend/formwidgets/colorpicker/assets/vendor/colpick/LICENSE b/modules/backend/formwidgets/colorpicker/assets/vendor/colpick/LICENSE new file mode 100644 index 000000000..70d53ac30 --- /dev/null +++ b/modules/backend/formwidgets/colorpicker/assets/vendor/colpick/LICENSE @@ -0,0 +1,339 @@ +GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + jQuery Color Picker with RGB, HSB and HEX fields, several skins and layouts + Copyright (C) 2013 Jose Vargas + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + {signature of Ty Coon}, 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. diff --git a/modules/backend/formwidgets/colorpicker/assets/vendor/colpick/README.md b/modules/backend/formwidgets/colorpicker/assets/vendor/colpick/README.md new file mode 100644 index 000000000..594e7c01d --- /dev/null +++ b/modules/backend/formwidgets/colorpicker/assets/vendor/colpick/README.md @@ -0,0 +1,36 @@ +colpick Color Picker +==================== + +colpick is a simple Photoshop-style color picker jQuery plugin. Its interface is familiar for most users and it's also very lightweight loading less than 30 KB to the browser. + +For instructions and examples see: http://colpick.com/plugin + + + +

Layouts

+ + + + + + + + + + + + + +
full:colpick full layout
rgbhex:colpick rgbhex layout
hex:colpick hex layout
+ + +Dual licensed under the MIT and GPL licenses. + +Based on Stefan Petre's color picker diff --git a/modules/backend/formwidgets/colorpicker/assets/vendor/colpick/css/colpick.css b/modules/backend/formwidgets/colorpicker/assets/vendor/colpick/css/colpick.css new file mode 100644 index 000000000..564f60cb3 --- /dev/null +++ b/modules/backend/formwidgets/colorpicker/assets/vendor/colpick/css/colpick.css @@ -0,0 +1,420 @@ +/* +colpick Color Picker / colpick.com +*/ + +/*Main container*/ +.colpick { + position: absolute; + width: 346px; + height: 170px; + overflow: hidden; + display: none; + font-family: Arial, Helvetica, sans-serif; + background:#ebebeb; + border: 1px solid #bbb; + -webkit-border-radius: 5px; + -moz-border-radius: 5px; + border-radius: 5px; + + /*Prevents selecting text when dragging the selectors*/ + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + -o-user-select: none; + user-select: none; +} +/*Color selection box with gradients*/ +.colpick_color { + position: absolute; + left: 7px; + top: 7px; + width: 156px; + height: 156px; + overflow: hidden; + outline: 1px solid #aaa; + cursor: crosshair; +} +.colpick_color_overlay1 { + position: absolute; + left:0; + top:0; + width: 156px; + height: 156px; + -ms-filter: "progid:DXImageTransform.Microsoft.gradient(GradientType=1,startColorstr='#ffffff', endColorstr='#00ffffff')"; /* IE8 */ + background: -moz-linear-gradient(left, rgba(255,255,255,1) 0%, rgba(255,255,255,0) 100%); /* FF3.6+ */ + background: -webkit-gradient(linear, left top, right top, color-stop(0%,rgba(255,255,255,1)), color-stop(100%,rgba(255,255,255,0))); /* Chrome,Safari4+ */ + background: -webkit-linear-gradient(left, rgba(255,255,255,1) 0%,rgba(255,255,255,0) 100%); /* Chrome10+,Safari5.1+ */ + background: -o-linear-gradient(left, rgba(255,255,255,1) 0%,rgba(255,255,255,0) 100%); /* Opera 11.10+ */ + background: -ms-linear-gradient(left, rgba(255,255,255,1) 0%,rgba(255,255,255,0) 100%); /* IE10+ */ + background: linear-gradient(to right, rgba(255,255,255,1) 0%, rgba(255,255,255,0) 100%); + filter: progid:DXImageTransform.Microsoft.gradient(GradientType=1,startColorstr='#ffffff', endColorstr='#00ffffff'); /* IE6 & IE7 */ +} +.colpick_color_overlay2 { + position: absolute; + left:0; + top:0; + width: 156px; + height: 156px; + -ms-filter: "progid:DXImageTransform.Microsoft.gradient(GradientType=0,startColorstr='#00000000', endColorstr='#000000')"; /* IE8 */ + background: -moz-linear-gradient(top, rgba(0,0,0,0) 0%, rgba(0,0,0,1) 100%); /* FF3.6+ */ + background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,rgba(0,0,0,0)), color-stop(100%,rgba(0,0,0,1))); /* Chrome,Safari4+ */ + background: -webkit-linear-gradient(top, rgba(0,0,0,0) 0%,rgba(0,0,0,1) 100%); /* Chrome10+,Safari5.1+ */ + background: -o-linear-gradient(top, rgba(0,0,0,0) 0%,rgba(0,0,0,1) 100%); /* Opera 11.10+ */ + background: -ms-linear-gradient(top, rgba(0,0,0,0) 0%,rgba(0,0,0,1) 100%); /* IE10+ */ + background: linear-gradient(to bottom, rgba(0,0,0,0) 0%,rgba(0,0,0,1) 100%); /* W3C */ + filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#00000000', endColorstr='#000000',GradientType=0 ); /* IE6-9 */ +} +/*Circular color selector*/ +.colpick_selector_outer { + background:none; + position: absolute; + width: 11px; + height: 11px; + margin: -6px 0 0 -6px; + border: 1px solid black; + border-radius: 50%; +} +.colpick_selector_inner{ + position: absolute; + width: 9px; + height: 9px; + border: 1px solid white; + border-radius: 50%; +} +/*Vertical hue bar*/ +.colpick_hue { + position: absolute; + top: 6px; + left: 175px; + width: 19px; + height: 156px; + border: 1px solid #aaa; + cursor: n-resize; +} +/*Hue bar sliding indicator*/ +.colpick_hue_arrs { + position: absolute; + left: -8px; + width: 35px; + height: 7px; + margin: -7px 0 0 0; +} +.colpick_hue_larr { + position:absolute; + width: 0; + height: 0; + border-top: 6px solid transparent; + border-bottom: 6px solid transparent; + border-left: 7px solid #858585; +} +.colpick_hue_rarr { + position:absolute; + right:0; + width: 0; + height: 0; + border-top: 6px solid transparent; + border-bottom: 6px solid transparent; + border-right: 7px solid #858585; +} +/*New color box*/ +.colpick_new_color { + position: absolute; + left: 207px; + top: 6px; + width: 60px; + height: 27px; + background: #f00; + border: 1px solid #8f8f8f; +} +/*Current color box*/ +.colpick_current_color { + position: absolute; + left: 277px; + top: 6px; + width: 60px; + height: 27px; + background: #f00; + border: 1px solid #8f8f8f; +} +/*Input field containers*/ +.colpick_field, .colpick_hex_field { + position: absolute; + height: 20px; + width: 60px; + overflow:hidden; + background:#f3f3f3; + color:#b8b8b8; + font-size:12px; + border:1px solid #bdbdbd; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; +} +.colpick_rgb_r { + top: 40px; + left: 207px; +} +.colpick_rgb_g { + top: 67px; + left: 207px; +} +.colpick_rgb_b { + top: 94px; + left: 207px; +} +.colpick_hsb_h { + top: 40px; + left: 277px; +} +.colpick_hsb_s { + top: 67px; + left: 277px; +} +.colpick_hsb_b { + top: 94px; + left: 277px; +} +.colpick_hex_field { + width: 68px; + left: 207px; + top: 121px; +} +/*Text field container on focus*/ +.colpick_focus { + border-color: #999; +} +/*Field label container*/ +.colpick_field_letter { + position: absolute; + width: 12px; + height: 20px; + line-height: 20px; + padding-left: 4px; + background: #efefef; + border-right: 1px solid #bdbdbd; + font-weight: bold; + color:#777; +} +/*Text inputs*/ +.colpick_field input, .colpick_hex_field input { + position: absolute; + right: 11px; + margin: 0; + padding: 0; + height: 20px; + line-height: 20px; + background: transparent; + border: none; + font-size: 12px; + font-family: Arial, Helvetica, sans-serif; + color: #555; + text-align: right; + outline: none; +} +.colpick_hex_field input { + right: 4px; +} +/*Field up/down arrows*/ +.colpick_field_arrs { + position: absolute; + top: 0; + right: 0; + width: 9px; + height: 21px; + cursor: n-resize; +} +.colpick_field_uarr { + position: absolute; + top: 5px; + width: 0; + height: 0; + border-left: 4px solid transparent; + border-right: 4px solid transparent; + border-bottom: 4px solid #959595; +} +.colpick_field_darr { + position: absolute; + bottom:5px; + width: 0; + height: 0; + border-left: 4px solid transparent; + border-right: 4px solid transparent; + border-top: 4px solid #959595; +} +/*Submit/Select button*/ +.colpick_submit { + position: absolute; + left: 207px; + top: 149px; + width: 130px; + height: 22px; + line-height:22px; + background: #efefef; + text-align: center; + color: #555; + font-size: 12px; + font-weight:bold; + border: 1px solid #bdbdbd; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; +} +.colpick_submit:hover { + background:#f3f3f3; + border-color:#999; + cursor: pointer; +} + +/*full layout with no submit button*/ +.colpick_full_ns .colpick_submit, .colpick_full_ns .colpick_current_color{ + display:none; +} +.colpick_full_ns .colpick_new_color { + width: 130px; + height: 25px; +} +.colpick_full_ns .colpick_rgb_r, .colpick_full_ns .colpick_hsb_h { + top: 42px; +} +.colpick_full_ns .colpick_rgb_g, .colpick_full_ns .colpick_hsb_s { + top: 73px; +} +.colpick_full_ns .colpick_rgb_b, .colpick_full_ns .colpick_hsb_b { + top: 104px; +} +.colpick_full_ns .colpick_hex_field { + top: 135px; +} + +/*rgbhex layout*/ +.colpick_rgbhex .colpick_hsb_h, .colpick_rgbhex .colpick_hsb_s, .colpick_rgbhex .colpick_hsb_b { + display:none; +} +.colpick_rgbhex { + width:282px; +} +.colpick_rgbhex .colpick_field, .colpick_rgbhex .colpick_submit { + width:68px; +} +.colpick_rgbhex .colpick_new_color { + width:34px; + border-right:none; +} +.colpick_rgbhex .colpick_current_color { + width:34px; + left:240px; + border-left:none; +} + +/*rgbhex layout, no submit button*/ +.colpick_rgbhex_ns .colpick_submit, .colpick_rgbhex_ns .colpick_current_color{ + display:none; +} +.colpick_rgbhex_ns .colpick_new_color{ + width:68px; + border: 1px solid #8f8f8f; +} +.colpick_rgbhex_ns .colpick_rgb_r { + top: 42px; +} +.colpick_rgbhex_ns .colpick_rgb_g { + top: 73px; +} +.colpick_rgbhex_ns .colpick_rgb_b { + top: 104px; +} +.colpick_rgbhex_ns .colpick_hex_field { + top: 135px; +} + +/*hex layout*/ +.colpick_hex .colpick_hsb_h, .colpick_hex .colpick_hsb_s, .colpick_hex .colpick_hsb_b, .colpick_hex .colpick_rgb_r, .colpick_hex .colpick_rgb_g, .colpick_hex .colpick_rgb_b { + display:none; +} +.colpick_hex { + width:206px; + height:201px; +} +.colpick_hex .colpick_hex_field { + width:72px; + height:25px; + top:168px; + left:80px; +} +.colpick_hex .colpick_hex_field div, .colpick_hex .colpick_hex_field input { + height: 25px; + line-height: 25px; +} +.colpick_hex .colpick_new_color { + left:9px; + top:168px; + width:30px; + border-right:none; +} +.colpick_hex .colpick_current_color { + left:39px; + top:168px; + width:30px; + border-left:none; +} +.colpick_hex .colpick_submit { + left:164px; + top: 168px; + width:30px; + height:25px; + line-height: 25px; +} + +/*hex layout, no submit button*/ +.colpick_hex_ns .colpick_submit, .colpick_hex_ns .colpick_current_color { + display:none; +} +.colpick_hex_ns .colpick_hex_field { + width:80px; +} +.colpick_hex_ns .colpick_new_color{ + width:60px; + border: 1px solid #8f8f8f; +} + +/*Dark color scheme*/ +.colpick_dark { + background: #161616; + border-color: #2a2a2a; +} +.colpick_dark .colpick_color { + outline-color: #333; +} +.colpick_dark .colpick_hue { + border-color: #555; +} +.colpick_dark .colpick_field, .colpick_dark .colpick_hex_field { + background: #101010; + border-color: #2d2d2d; +} +.colpick_dark .colpick_field_letter { + background: #131313; + border-color: #2d2d2d; + color: #696969; +} +.colpick_dark .colpick_field input, .colpick_dark .colpick_hex_field input { + color: #7a7a7a; +} +.colpick_dark .colpick_field_uarr { + border-bottom-color:#696969; +} +.colpick_dark .colpick_field_darr { + border-top-color:#696969; +} +.colpick_dark .colpick_focus { + border-color:#444; +} +.colpick_dark .colpick_submit { + background: #131313; + border-color:#2d2d2d; + color:#7a7a7a; +} +.colpick_dark .colpick_submit:hover { + background-color:#101010; + border-color:#444; +} \ No newline at end of file diff --git a/modules/backend/formwidgets/colorpicker/assets/vendor/colpick/js/colpick.js b/modules/backend/formwidgets/colorpicker/assets/vendor/colpick/js/colpick.js new file mode 100644 index 000000000..d77432a34 --- /dev/null +++ b/modules/backend/formwidgets/colorpicker/assets/vendor/colpick/js/colpick.js @@ -0,0 +1,520 @@ +/* +colpick Color Picker +Copyright 2013 Jose Vargas. Licensed under GPL license. Based on Stefan Petre's Color Picker www.eyecon.ro, dual licensed under the MIT and GPL licenses + +For usage and examples: colpick.com/plugin + */ + +(function ($) { + var colpick = function () { + var + tpl = '
#
R
G
B
H
S
B
', + defaults = { + showEvent: 'click', + onShow: function () {}, + onBeforeShow: function(){}, + onHide: function () {}, + onChange: function () {}, + onSubmit: function () {}, + colorScheme: 'light', + color: '3289c7', + livePreview: true, + flat: false, + layout: 'full', + submit: 1, + submitText: 'OK', + height: 156 + }, + //Fill the inputs of the plugin + fillRGBFields = function (hsb, cal) { + var rgb = hsbToRgb(hsb); + $(cal).data('colpick').fields + .eq(1).val(rgb.r).end() + .eq(2).val(rgb.g).end() + .eq(3).val(rgb.b).end(); + }, + fillHSBFields = function (hsb, cal) { + $(cal).data('colpick').fields + .eq(4).val(Math.round(hsb.h)).end() + .eq(5).val(Math.round(hsb.s)).end() + .eq(6).val(Math.round(hsb.b)).end(); + }, + fillHexFields = function (hsb, cal) { + $(cal).data('colpick').fields.eq(0).val(hsbToHex(hsb)); + }, + //Set the round selector position + setSelector = function (hsb, cal) { + $(cal).data('colpick').selector.css('backgroundColor', '#' + hsbToHex({h: hsb.h, s: 100, b: 100})); + $(cal).data('colpick').selectorIndic.css({ + left: parseInt($(cal).data('colpick').height * hsb.s/100, 10), + top: parseInt($(cal).data('colpick').height * (100-hsb.b)/100, 10) + }); + }, + //Set the hue selector position + setHue = function (hsb, cal) { + $(cal).data('colpick').hue.css('top', parseInt($(cal).data('colpick').height - $(cal).data('colpick').height * hsb.h/360, 10)); + }, + //Set current and new colors + setCurrentColor = function (hsb, cal) { + $(cal).data('colpick').currentColor.css('backgroundColor', '#' + hsbToHex(hsb)); + }, + setNewColor = function (hsb, cal) { + $(cal).data('colpick').newColor.css('backgroundColor', '#' + hsbToHex(hsb)); + }, + //Called when the new color is changed + change = function (ev) { + var cal = $(this).parent().parent(), col; + if (this.parentNode.className.indexOf('_hex') > 0) { + cal.data('colpick').color = col = hexToHsb(fixHex(this.value)); + fillRGBFields(col, cal.get(0)); + fillHSBFields(col, cal.get(0)); + } else if (this.parentNode.className.indexOf('_hsb') > 0) { + cal.data('colpick').color = col = fixHSB({ + h: parseInt(cal.data('colpick').fields.eq(4).val(), 10), + s: parseInt(cal.data('colpick').fields.eq(5).val(), 10), + b: parseInt(cal.data('colpick').fields.eq(6).val(), 10) + }); + fillRGBFields(col, cal.get(0)); + fillHexFields(col, cal.get(0)); + } else { + cal.data('colpick').color = col = rgbToHsb(fixRGB({ + r: parseInt(cal.data('colpick').fields.eq(1).val(), 10), + g: parseInt(cal.data('colpick').fields.eq(2).val(), 10), + b: parseInt(cal.data('colpick').fields.eq(3).val(), 10) + })); + fillHexFields(col, cal.get(0)); + fillHSBFields(col, cal.get(0)); + } + setSelector(col, cal.get(0)); + setHue(col, cal.get(0)); + setNewColor(col, cal.get(0)); + cal.data('colpick').onChange.apply(cal.parent(), [col, hsbToHex(col), hsbToRgb(col), cal.data('colpick').el, 0]); + }, + //Change style on blur and on focus of inputs + blur = function (ev) { + $(this).parent().removeClass('colpick_focus'); + }, + focus = function () { + $(this).parent().parent().data('colpick').fields.parent().removeClass('colpick_focus'); + $(this).parent().addClass('colpick_focus'); + }, + //Increment/decrement arrows functions + downIncrement = function (ev) { + ev.preventDefault ? ev.preventDefault() : ev.returnValue = false; + var field = $(this).parent().find('input').focus(); + var current = { + el: $(this).parent().addClass('colpick_slider'), + max: this.parentNode.className.indexOf('_hsb_h') > 0 ? 360 : (this.parentNode.className.indexOf('_hsb') > 0 ? 100 : 255), + y: ev.pageY, + field: field, + val: parseInt(field.val(), 10), + preview: $(this).parent().parent().data('colpick').livePreview + }; + $(document).mouseup(current, upIncrement); + $(document).mousemove(current, moveIncrement); + }, + moveIncrement = function (ev) { + ev.data.field.val(Math.max(0, Math.min(ev.data.max, parseInt(ev.data.val - ev.pageY + ev.data.y, 10)))); + if (ev.data.preview) { + change.apply(ev.data.field.get(0), [true]); + } + return false; + }, + upIncrement = function (ev) { + change.apply(ev.data.field.get(0), [true]); + ev.data.el.removeClass('colpick_slider').find('input').focus(); + $(document).off('mouseup', upIncrement); + $(document).off('mousemove', moveIncrement); + return false; + }, + //Hue slider functions + downHue = function (ev) { + ev.preventDefault ? ev.preventDefault() : ev.returnValue = false; + var current = { + cal: $(this).parent(), + y: $(this).offset().top + }; + $(document).on('mouseup touchend',current,upHue); + $(document).on('mousemove touchmove',current,moveHue); + + var pageY = ((ev.type == 'touchstart') ? ev.originalEvent.changedTouches[0].pageY : ev.pageY ); + change.apply( + current.cal.data('colpick') + .fields.eq(4).val(parseInt(360*(current.cal.data('colpick').height - (pageY - current.y))/current.cal.data('colpick').height, 10)) + .get(0), + [current.cal.data('colpick').livePreview] + ); + return false; + }, + moveHue = function (ev) { + var pageY = ((ev.type == 'touchmove') ? ev.originalEvent.changedTouches[0].pageY : ev.pageY ); + change.apply( + ev.data.cal.data('colpick') + .fields.eq(4).val(parseInt(360*(ev.data.cal.data('colpick').height - Math.max(0,Math.min(ev.data.cal.data('colpick').height,(pageY - ev.data.y))))/ev.data.cal.data('colpick').height, 10)) + .get(0), + [ev.data.preview] + ); + return false; + }, + upHue = function (ev) { + fillRGBFields(ev.data.cal.data('colpick').color, ev.data.cal.get(0)); + fillHexFields(ev.data.cal.data('colpick').color, ev.data.cal.get(0)); + $(document).off('mouseup touchend',upHue); + $(document).off('mousemove touchmove',moveHue); + return false; + }, + //Color selector functions + downSelector = function (ev) { + ev.preventDefault ? ev.preventDefault() : ev.returnValue = false; + var current = { + cal: $(this).parent(), + pos: $(this).offset() + }; + current.preview = current.cal.data('colpick').livePreview; + + $(document).on('mouseup touchend',current,upSelector); + $(document).on('mousemove touchmove',current,moveSelector); + + var payeX,pageY; + if(ev.type == 'touchstart') { + pageX = ev.originalEvent.changedTouches[0].pageX, + pageY = ev.originalEvent.changedTouches[0].pageY; + } else { + pageX = ev.pageX; + pageY = ev.pageY; + } + + change.apply( + current.cal.data('colpick').fields + .eq(6).val(parseInt(100*(current.cal.data('colpick').height - (pageY - current.pos.top))/current.cal.data('colpick').height, 10)).end() + .eq(5).val(parseInt(100*(pageX - current.pos.left)/current.cal.data('colpick').height, 10)) + .get(0), + [current.preview] + ); + return false; + }, + moveSelector = function (ev) { + var payeX,pageY; + if(ev.type == 'touchmove') { + pageX = ev.originalEvent.changedTouches[0].pageX, + pageY = ev.originalEvent.changedTouches[0].pageY; + } else { + pageX = ev.pageX; + pageY = ev.pageY; + } + + change.apply( + ev.data.cal.data('colpick').fields + .eq(6).val(parseInt(100*(ev.data.cal.data('colpick').height - Math.max(0,Math.min(ev.data.cal.data('colpick').height,(pageY - ev.data.pos.top))))/ev.data.cal.data('colpick').height, 10)).end() + .eq(5).val(parseInt(100*(Math.max(0,Math.min(ev.data.cal.data('colpick').height,(pageX - ev.data.pos.left))))/ev.data.cal.data('colpick').height, 10)) + .get(0), + [ev.data.preview] + ); + return false; + }, + upSelector = function (ev) { + fillRGBFields(ev.data.cal.data('colpick').color, ev.data.cal.get(0)); + fillHexFields(ev.data.cal.data('colpick').color, ev.data.cal.get(0)); + $(document).off('mouseup touchend',upSelector); + $(document).off('mousemove touchmove',moveSelector); + return false; + }, + //Submit button + clickSubmit = function (ev) { + var cal = $(this).parent(); + var col = cal.data('colpick').color; + cal.data('colpick').origColor = col; + setCurrentColor(col, cal.get(0)); + cal.data('colpick').onSubmit(col, hsbToHex(col), hsbToRgb(col), cal.data('colpick').el); + }, + //Show/hide the color picker + show = function (ev) { + // Prevent the trigger of any direct parent + ev.stopPropagation(); + var cal = $('#' + $(this).data('colpickId')); + cal.data('colpick').onBeforeShow.apply(this, [cal.get(0)]); + var pos = $(this).offset(); + var top = pos.top + this.offsetHeight; + var left = pos.left; + var viewPort = getViewport(); + var calW = cal.width(); + if (left + calW > viewPort.l + viewPort.w) { + left -= calW; + } + cal.css({left: left + 'px', top: top + 'px'}); + if (cal.data('colpick').onShow.apply(this, [cal.get(0)]) != false) { + cal.show(); + } + //Hide when user clicks outside + $('html').mousedown({cal:cal}, hide); + cal.mousedown(function(ev){ev.stopPropagation();}) + }, + hide = function (ev) { + if (ev.data.cal.data('colpick').onHide.apply(this, [ev.data.cal.get(0)]) != false) { + ev.data.cal.hide(); + } + $('html').off('mousedown', hide); + }, + getViewport = function () { + var m = document.compatMode == 'CSS1Compat'; + return { + l : window.pageXOffset || (m ? document.documentElement.scrollLeft : document.body.scrollLeft), + w : window.innerWidth || (m ? document.documentElement.clientWidth : document.body.clientWidth) + }; + }, + //Fix the values if the user enters a negative or high value + fixHSB = function (hsb) { + return { + h: Math.min(360, Math.max(0, hsb.h)), + s: Math.min(100, Math.max(0, hsb.s)), + b: Math.min(100, Math.max(0, hsb.b)) + }; + }, + fixRGB = function (rgb) { + return { + r: Math.min(255, Math.max(0, rgb.r)), + g: Math.min(255, Math.max(0, rgb.g)), + b: Math.min(255, Math.max(0, rgb.b)) + }; + }, + fixHex = function (hex) { + var len = 6 - hex.length; + if (len > 0) { + var o = []; + for (var i=0; i').attr('style','height:8.333333%; filter:progid:DXImageTransform.Microsoft.gradient(GradientType=0,startColorstr='+stops[i]+', endColorstr='+stops[i+1]+'); -ms-filter: "progid:DXImageTransform.Microsoft.gradient(GradientType=0,startColorstr='+stops[i]+', endColorstr='+stops[i+1]+')";'); + huebar.append(div); + } + } else { + stopList = stops.join(','); + huebar.attr('style','background:-webkit-linear-gradient(top,'+stopList+'); background: -o-linear-gradient(top,'+stopList+'); background: -ms-linear-gradient(top,'+stopList+'); background:-moz-linear-gradient(top,'+stopList+'); -webkit-linear-gradient(top,'+stopList+'); background:linear-gradient(to bottom,'+stopList+'); '); + } + cal.find('div.colpick_hue').on('mousedown touchstart',downHue); + options.newColor = cal.find('div.colpick_new_color'); + options.currentColor = cal.find('div.colpick_current_color'); + //Store options and fill with default color + cal.data('colpick', options); + fillRGBFields(options.color, cal.get(0)); + fillHSBFields(options.color, cal.get(0)); + fillHexFields(options.color, cal.get(0)); + setHue(options.color, cal.get(0)); + setSelector(options.color, cal.get(0)); + setCurrentColor(options.color, cal.get(0)); + setNewColor(options.color, cal.get(0)); + //Append to body if flat=false, else show in place + if (options.flat) { + cal.appendTo(this).show(); + cal.css({ + position: 'relative', + display: 'block' + }); + } else { + cal.appendTo(document.body); + $(this).on(options.showEvent, show); + cal.css({ + position:'absolute' + }); + } + } + }); + }, + //Shows the picker + showPicker: function() { + return this.each( function () { + if ($(this).data('colpickId')) { + show.apply(this); + } + }); + }, + //Hides the picker + hidePicker: function() { + return this.each( function () { + if ($(this).data('colpickId')) { + $('#' + $(this).data('colpickId')).hide(); + } + }); + }, + //Sets a color as new and current (default) + setColor: function(col, setCurrent) { + setCurrent = (typeof setCurrent === "undefined") ? 1 : setCurrent; + if (typeof col == 'string') { + col = hexToHsb(col); + } else if (col.r != undefined && col.g != undefined && col.b != undefined) { + col = rgbToHsb(col); + } else if (col.h != undefined && col.s != undefined && col.b != undefined) { + col = fixHSB(col); + } else { + return this; + } + return this.each(function(){ + if ($(this).data('colpickId')) { + var cal = $('#' + $(this).data('colpickId')); + cal.data('colpick').color = col; + cal.data('colpick').origColor = col; + fillRGBFields(col, cal.get(0)); + fillHSBFields(col, cal.get(0)); + fillHexFields(col, cal.get(0)); + setHue(col, cal.get(0)); + setSelector(col, cal.get(0)); + + setNewColor(col, cal.get(0)); + cal.data('colpick').onChange.apply(cal.parent(), [col, hsbToHex(col), hsbToRgb(col), cal.data('colpick').el, 1]); + if(setCurrent) { + setCurrentColor(col, cal.get(0)); + } + } + }); + } + }; + }(); + //Color space convertions + var hexToRgb = function (hex) { + var hex = parseInt(((hex.indexOf('#') > -1) ? hex.substring(1) : hex), 16); + return {r: hex >> 16, g: (hex & 0x00FF00) >> 8, b: (hex & 0x0000FF)}; + }; + var hexToHsb = function (hex) { + return rgbToHsb(hexToRgb(hex)); + }; + var rgbToHsb = function (rgb) { + var hsb = {h: 0, s: 0, b: 0}; + var min = Math.min(rgb.r, rgb.g, rgb.b); + var max = Math.max(rgb.r, rgb.g, rgb.b); + var delta = max - min; + hsb.b = max; + hsb.s = max != 0 ? 255 * delta / max : 0; + if (hsb.s != 0) { + if (rgb.r == max) hsb.h = (rgb.g - rgb.b) / delta; + else if (rgb.g == max) hsb.h = 2 + (rgb.b - rgb.r) / delta; + else hsb.h = 4 + (rgb.r - rgb.g) / delta; + } else hsb.h = -1; + hsb.h *= 60; + if (hsb.h < 0) hsb.h += 360; + hsb.s *= 100/255; + hsb.b *= 100/255; + return hsb; + }; + var hsbToRgb = function (hsb) { + var rgb = {}; + var h = hsb.h; + var s = hsb.s*255/100; + var v = hsb.b*255/100; + if(s == 0) { + rgb.r = rgb.g = rgb.b = v; + } else { + var t1 = v; + var t2 = (255-s)*v/255; + var t3 = (t1-t2)*(h%60)/60; + if(h==360) h = 0; + if(h<60) {rgb.r=t1; rgb.b=t2; rgb.g=t2+t3} + else if(h<120) {rgb.g=t1; rgb.b=t2; rgb.r=t1-t3} + else if(h<180) {rgb.g=t1; rgb.r=t2; rgb.b=t2+t3} + else if(h<240) {rgb.b=t1; rgb.r=t2; rgb.g=t1-t3} + else if(h<300) {rgb.b=t1; rgb.g=t2; rgb.r=t2+t3} + else if(h<360) {rgb.r=t1; rgb.g=t2; rgb.b=t1-t3} + else {rgb.r=0; rgb.g=0; rgb.b=0} + } + return {r:Math.round(rgb.r), g:Math.round(rgb.g), b:Math.round(rgb.b)}; + }; + var rgbToHex = function (rgb) { + var hex = [ + rgb.r.toString(16), + rgb.g.toString(16), + rgb.b.toString(16) + ]; + $.each(hex, function (nr, val) { + if (val.length == 1) { + hex[nr] = '0' + val; + } + }); + return hex.join(''); + }; + var hsbToHex = function (hsb) { + return rgbToHex(hsbToRgb(hsb)); + }; + $.fn.extend({ + colpick: colpick.init, + colpickHide: colpick.hidePicker, + colpickShow: colpick.showPicker, + colpickSetColor: colpick.setColor + }); + $.extend({ + colpick:{ + rgbToHex: rgbToHex, + rgbToHsb: rgbToHsb, + hsbToHex: hsbToHex, + hsbToRgb: hsbToRgb, + hexToHsb: hexToHsb, + hexToRgb: hexToRgb + } + }); +})(jQuery); diff --git a/modules/backend/formwidgets/colorpicker/partials/_colorpicker.htm b/modules/backend/formwidgets/colorpicker/partials/_colorpicker.htm new file mode 100644 index 000000000..18ad301bc --- /dev/null +++ b/modules/backend/formwidgets/colorpicker/partials/_colorpicker.htm @@ -0,0 +1,34 @@ +previewMode): ?> +
+ +
+ + + + +
+ + \ No newline at end of file diff --git a/modules/backend/lang/en/lang.php b/modules/backend/lang/en/lang.php index 2243df5f3..b9e39b434 100644 --- a/modules/backend/lang/en/lang.php +++ b/modules/backend/lang/en/lang.php @@ -1,6 +1,9 @@ [ + 'title' => 'Administration Area', + ], 'field' => [ 'invalid_type' => 'Invalid field type used :type.', 'options_method_not_exists' => 'The model class :model must define a method :method() returning options for the ":field" form field.', @@ -14,7 +17,7 @@ return [ 'access_denied' => [ 'label' => "Access denied", 'help' => "You don't have the required permissions to view this page.", - 'cms_link' => "Return to the backend", + 'cms_link' => "Return to the back-end", ], ], 'partial' => [ @@ -211,8 +214,8 @@ return [ 'extension' => 'The PHP extension :name is not installed. Please install this library and activate the extension.' ], 'editor' => [ - 'menu_label' => 'Code Editor Preferences', - 'menu_description' => 'Customize the code editor preferences, such as font size and color scheme.', + 'menu_label' => 'Code editor preferences', + 'menu_description' => 'Customize your code editor preferences, such as font size and color scheme.', 'font_size' => 'Font size', 'tab_size' => 'Tab size', 'use_hard_tabs' => 'Indent using tabs', @@ -231,19 +234,23 @@ return [ 'menu_description' => 'Settings relate to your administration account', ], 'myaccount' => [ - 'menu_label' => 'My Account', + 'menu_label' => 'My account', 'menu_description' => 'Update your account details such as name, email address and password.', 'menu_keywords' => 'security login' ], + 'branding' => [ + 'menu_label' => 'Customize back-end', + 'menu_description' => 'Customize the administration area such as name, colors and logo.', + ], 'backend_preferences' => [ - 'menu_label' => 'Backend Preferences', - 'menu_description' => 'Manage language preference and the appearance of the backend.', + 'menu_label' => 'Back-end preferences', + 'menu_description' => 'Manage your account preferences such as desired language.', 'locale' => 'Language', 'locale_comment' => 'Select your desired locale for language use.', ], 'access_log' => [ 'hint' => 'This log displays a list of successful sign in attempts by administrators. Records are kept for a total of :days days.', - 'menu_label' => 'Access Log', + 'menu_label' => 'Access log', 'menu_description' => 'View a list of successful back-end user sign ins.', 'created_at' => 'Date & Time', 'login' => 'Login', diff --git a/modules/backend/lang/es-ar/lang.php b/modules/backend/lang/es-ar/lang.php new file mode 100644 index 000000000..2577371be --- /dev/null +++ b/modules/backend/lang/es-ar/lang.php @@ -0,0 +1,254 @@ + [ + 'invalid_type' => 'El tipo de campo utilizado es inválido :type.', + 'options_method_not_exists' => 'El modelo clase: model debe definir un método: method() opciones recurrentes para el ":field" desde campo.', + ], + 'widget' => [ + 'not_registered' => "La clase del modulo ':name' no ha sido registrada", + 'not_bound' => "El módulo con la clase ':name' no se ha unido al controlador", + ], + 'page' => [ + 'untitled' => "Sin título", + 'access_denied' => [ + 'label' => "Acceso denegado", + 'help' => "Usted no tiene los permisos necesarios para ver esta página.", + 'cms_link' => "Regresar al Back-end", + ], + ], + 'partial' => [ + 'not_found' => "El parcial ':name' no se encuentra.", + ], + 'account' => [ + 'sign_out' => 'Salir', + 'login' => 'Entrar', + 'reset' => 'Reiniciar', + 'restore' => 'Restaurar', + 'login_placeholder' => 'Usuario', + 'password_placeholder' => 'Contraseña', + 'forgot_password' => "Olvido su contraseña?", + 'enter_email' => "Ingrese su email", + 'enter_login' => "Ingrese su usuario", + 'email_placeholder' => "email", + 'enter_new_password' => "Ingrese una nueva contraseña", + 'password_reset' => "Reiniciar contraseña", + 'restore_success' => "Le hemos enviado un email con la nueva contraseña.", + 'restore_error' => "El usuario no es válido ':login'", + 'reset_success' => "Su contraseña fue correctamente reseteada.", + 'reset_error' => "La contraseña es inválida. Por favor, intente otra vez!", + 'reset_fail' => "No se puede reiniciar su contraseña!", + 'apply' => 'Aplicar', + 'cancel' => 'Cancelar', + 'delete' => 'Borrar', + 'ok' => 'OK', + ], + 'dashboard' => [ + 'menu_label' => 'Tablero', + 'widget_label' => 'Modulo', + 'widget_width' => 'Ancho', + 'full_width' => 'Ancho completo', + 'add_widget' => 'Agregar módulo', + 'widget_inspector_title' => 'Configurar módulo', + 'widget_inspector_description' => 'Configure el módulo de informe', + 'widget_columns_label' => 'Ancho :columnas', + 'widget_columns_description' => 'El ancho del módulo, un número entre 1 y 10.', + 'widget_columns_error' => 'Por favor introduce el ancho del modulo, un número entre 1 y 10.', + 'columns' => '{1} columna|[2,Inf] columnas', + 'widget_new_row_label' => 'Forzar nueva fila', + 'widget_new_row_description' => 'Coloca el módulo en una nueva fila.', + 'widget_title_label' => 'Título del módulo', + 'widget_title_error' => 'El título del módulo es requerido.', + 'status' => [ + 'widget_title_default' => 'Estado del sistema', + 'online' => 'online', + 'update_available' => '{0} actualizaciones disponibles!|{1} actualizaciones disponibles!|[2,Inf] actualizaciones disponibles!', + ] + ], + 'user' => [ + 'name' => 'Administrador', + 'menu_label' => 'Administradores', + 'menu_description' => 'Gestionar back-end de administrador de usuarios, grupos y permisos.', + 'list_title' => 'Gestionar Administradores', + 'new' => 'Nuevo Administrador', + 'login' => "Acceso", + 'first_name' => "Nombre", + 'last_name' => "Apellido", + 'full_name' => "Nombre completo", + 'email' => "Email", + 'groups' => "Grupos", + 'groups_comment' => "Especifique a qué grupos pertenece esta persona.", + 'avatar' => "Avatar", + 'password' => "Contraseña", + 'password_confirmation' => "Confirmar contraseña", + 'superuser' => "Super Administrador", + 'superuser_comment' => "Marque esta casilla para permitir que esta persona tenga acceso a todas las áreas.", + 'send_invite' => 'Enviar invitación por email', + 'send_invite_comment' => 'Utilice esta casilla de verificación para enviar una invitación al usuario por emai', + 'delete_confirm' => '¿Realmente desea eliminar este administrador?', + 'return' => 'Regresar a la lista de administradorest', + 'allow' => 'Permitir', + 'inherit' => 'Heredar', + 'deny' => 'Denegar', + 'group' => [ + 'name' => 'Grupo', + 'name_field' => 'Nombre', + 'menu_label' => 'Grupos', + 'list_title' => 'Gestionar Grupos', + 'new' => 'Nuevo Grupo', + 'delete_confirm' => '¿Realmente desea eliminar este grupo de administradores?', + 'return' => 'Regresar a la lista de grupos', + ], + 'preferences' => [ + 'not_authenticated' => 'No existe un usuario autenticado para cargar o guardar las preferencias para.' + ] + ], + 'list' => [ + 'default_title' => 'Lista', + 'search_prompt' => 'Buscar...', + 'no_records' => 'No hay registros en esta lista', + 'missing_model' => 'El comportamiento de lista utilizado en :class no tiene un modelo definido.', + 'missing_column' => 'No hay definiciones de columna para :columns.', + 'missing_columns' => 'Lista utilizada en :class no tiene lista de columnas definidas.', + 'missing_definition' => "Comportamiento de lista no contiene una columna para ':field'.", + 'behavior_not_ready' => 'Comportamiento de lista no se ha inicializado, compruebe que ha llamado makeLists() en el controlador.', + 'invalid_column_datetime' => "Columna valor ':column' no es un objeto DateTime, has perdido la referencia \$dates en el Modelo?", + 'pagination' => 'Registros que se muestran: :from-:to de :total', + 'prev_page' => 'Página anterior', + 'next_page' => 'Página siguiente', + 'loading' => 'Cargando...', + 'setup_title' => 'Configuración de la lista', + 'setup_help' => 'Utilice las casillas de verificación para seleccionar las columnas que desea ver en la lista. Usted puede cambiar la posición de las columnas arrastrándolas hacia arriba o hacia abajo.', + 'records_per_page' => 'Registros por página', + 'records_per_page_help' => 'Seleccione el número de registros por página para mostrar. Tenga en cuenta que un alto número de registros en una sola página puede reducir el rendimiento.', + ], + 'fileupload' => [ + 'attachment' => 'Adjunto', + 'help' => 'Añadir un título y una descripción para este Adjunto..', + 'title_label' => 'Título', + 'description_label' => 'Descripción' + ], + + 'form' => [ + 'create_title' => "Nuevo :name", + 'update_title' => "Editar :name", + 'preview_title' => "Vista previa :name", + 'create_success' => ':name ha sido creado con éxito', + 'update_success' => ':name se ha actualizado correctamente', + 'delete_success' => ':name se ha eliminado correctamente', + 'missing_id' => "El formulario de registro de identificación no se ha especificado.", + 'missing_model' => 'El comportamiento del formulario utilizado en :class no tiene un modelo definido.', + 'missing_definition' => "El comportamiento de formulario no contiene un campo para':field'.", + 'not_found' => 'El registro de formulario con el ID :id no se pudo encontrar.', + 'create' => 'Crear', + 'create_and_close' => 'Crear y cerrar', + 'creating' => 'Creando...', + 'save' => 'Guardar', + 'save_and_close' => 'Guardar y cerrar', + 'saving' => 'Guardando...', + 'delete' => 'Borrar', + 'deleting' => 'Borrando...', + 'undefined_tab' => 'Misc', + 'field_off' => 'Off', + 'field_on' => 'On', + 'add' => 'Agregar', + 'apply' => 'Aplicar', + 'cancel' => 'Cancelar', + 'close' => 'Cerrar', + 'ok' => 'OK', + 'or' => 'o', + 'confirm_tab_close' => '¿Realmente desea cerrar la cuenta? Se perderán los cambios no guardados.', + 'behavior_not_ready' => 'Favor compruebe que ha llamado a la funcion initForm() en el controlador.', + 'preview_no_files_message' => 'Los archivos no fueron cargados', + 'select' => 'Seleccionar', + 'select_all' => 'Todo', + 'select_none' => 'Nada', + 'select_placeholder' => 'Seleccione', + 'insert_row' => 'Insertar fila', + 'delete_row' => 'Eliminar fila', + 'concurrency-file-changed-title' => 'El archivo fue cambiado', + 'concurrency-file-changed-description' => 'El archivo que usted se encuentra editando fue cambiado editado por otro usuario. Usted puede recargar el archivo y perder los cambios o sobreescribir el archivo en el disco.', + 'reload' => 'Recargar', + ], + 'relation' => [ + 'missing_definition' => "Relación comportamiento no contiene una definición para ':field'.", + 'missing_model' => "Relación comportamiento utilizado en :class no tiene un modelo definido.", + 'invalid_action_single' => "Esta acción no se puede realizar en una relación singular.", + 'invalid_action_multi' => "Esta acción no se puede realizar en una relación múltiple.", + 'help' => "Haga clic en un elemento para añadir.", + 'related_data' => "Relacionar :name datos", + 'add' => "Agregar", + 'add_selected' => "Agregar seleccionado", + 'add_a_new' => "Agregar un nuevo :name", + 'cancel' => "Cancelar", + 'add_name' => "Agregar :name", + 'create' => "Crear", + 'create_name' => "Crear :name", + 'update' => "Actualizar", + 'update_name' => "Actualizar :name", + 'remove' => "Remover", + 'remove_name' => "Remover :name", + 'delete' => "Borrar", + 'delete_name' => "Borrar :name", + 'delete_confirm' => "¿Está usted seguro?", + ], + 'model' => [ + 'name' => "Modelo", + 'not_found' => "Modelo ':class' con el ID :id no se pudo encontrar", + 'missing_id' => "No se ha especificado un ID para encontrar el modelo guardado.", + 'missing_relation' => "Modelo ':class' no contiene una definición para ':relation'.", + 'invalid_class' => "Modelo :model utilizado en :class no es váildo, este debería heredar la clase del \Model.", + 'mass_assignment_failed' => "Asignación masiva falló para el atributo del Modelo ':attribute'.", + ], + 'warnings' => [ + 'tips' => 'Consejos de configuración del sistema', + 'tips_description' => 'Hay problemas que necesitan de su atención para configurar el sistema correctamente.', + 'permissions' => 'Directorio :name o los subdirectorios no se puede escribir por PHP. Por favor establecer los permisos correctos para el servidor web en este directorio.', + 'extension' => 'La extensión PHP :name no está instalada. Por favor instalar esta librería y activar la extensión.' + ], + 'editor' => [ + 'menu_label' => 'Preferencias del Editor de Código', + 'menu_description' => 'Configurar las preferencias del editor de código, como el tamaño de la letra y el color del esquema.', + 'font_size' => 'Tamaño de la letra', + 'tab_size' => '>Tamaño de la Solapa', + 'use_hard_tabs' => 'Espacio entre solapas', + 'code_folding' => 'Código Plegable', + 'word_wrap' => 'Ajuste de línea', + 'highlight_active_line' => 'Resaltar línea activa', + 'show_invisibles' => 'Mostrar caracteres invisibles', + 'show_gutter' => 'Mostrar canal', + 'theme' => 'Color del esquema', + ], + 'tooltips' => [ + 'preview_website' => 'Vista previa de la página web' + ], + 'mysettings' => [ + 'menu_label' => 'Mi configuración', + 'menu_description' => 'Ajustes relacionados con su cuenta de administración', + ], + 'myaccount' => [ + 'menu_label' => 'Mi cuenta', + 'menu_description' => 'Actualice la información de su cuenta, tales como nombre, dirección de correo electrónico y contraseña.', + 'menu_keywords' => 'Inicio seguro' + ], + 'backend_preferences' => [ + 'menu_label' => 'Preferencias de Back-end', + 'menu_description' => 'Gestionar preferencia de idioma y la apariencia del Back-end.', + 'locale' => 'Idioma', + 'locale_comment' => 'Seleccione la localización para el uso del lenguaje.', + ], + 'access_log' => [ + 'hint' => 'Este registro muestra la lista de ingresos al panel de administración. Los registros se mantienen por un total de :days días.', + 'menu_label' => 'Registro de acceso', + 'menu_description' => 'Ver registro de ingresos al panel de administracion.', + 'created_at' => 'Fecha y hora', + 'login' => 'Acceso', + 'ip_address' => 'IP', + 'first_name' => 'Nombre', + 'last_name' => 'Apellido', + 'email' => 'Email', + ], + 'filter' => [ + 'all' => 'Todo' + ] +]; \ No newline at end of file diff --git a/modules/backend/layouts/_custom_styles.htm b/modules/backend/layouts/_custom_styles.htm new file mode 100644 index 000000000..643d16010 --- /dev/null +++ b/modules/backend/layouts/_custom_styles.htm @@ -0,0 +1,8 @@ + + + + diff --git a/modules/backend/layouts/_footer.htm b/modules/backend/layouts/_footer.htm index 97a3a97e8..870fac32c 100644 --- a/modules/backend/layouts/_footer.htm +++ b/modules/backend/layouts/_footer.htm @@ -3,7 +3,7 @@ -
-

+
+

\ No newline at end of file diff --git a/modules/backend/layouts/_head.htm b/modules/backend/layouts/_head.htm index e224d731e..21215f8c1 100644 --- a/modules/backend/layouts/_head.htm +++ b/modules/backend/layouts/_head.htm @@ -2,8 +2,8 @@ - - <?= $this->pageTitle ?> | October CMS +<title data-title-template="<?= empty($this->pageTitleTemplate) ? '%s' : e($this->pageTitleTemplate) ?> | <?= e(Backend\Models\BrandSettings::get('app_name')) ?>"> + <?= e(trans($this->pageTitle)) ?> | <?= e(Backend\Models\BrandSettings::get('app_name')) ?> @@ -80,4 +80,5 @@ // --> makeAssets() ?> - \ No newline at end of file + +makeLayoutPartial('custom_styles') ?> \ No newline at end of file diff --git a/modules/backend/layouts/auth.htm b/modules/backend/layouts/auth.htm index 331cb34de..57040a8bb 100644 --- a/modules/backend/layouts/auth.htm +++ b/modules/backend/layouts/auth.htm @@ -3,7 +3,7 @@ - Administration Area + <?= e(trans('backend::lang.auth.title')) ?> @@ -12,7 +12,7 @@ - + makeAssets() ?> + makeLayoutPartial('custom_styles') ?>
+
-

+

diff --git a/modules/backend/models/BackendPreferences.php b/modules/backend/models/BackendPreferences.php index 1d2fbdf06..d747047f2 100644 --- a/modules/backend/models/BackendPreferences.php +++ b/modules/backend/models/BackendPreferences.php @@ -48,6 +48,7 @@ class BackendPreferences extends Model 'fr' => [Lang::get('system::lang.locale.fr'), 'flag-fr'], 'it' => [Lang::get('system::lang.locale.it'), 'flag-it'], 'ro' => [Lang::get('system::lang.locale.ro'), 'flag-ro'], + 'es-ar' => [Lang::get('system::lang.locale.es-ar'), 'flag-ar'], 'pt-br' => [Lang::get('system::lang.locale.pt-br'), 'flag-br'], 'fa' => [Lang::get('system::lang.locale.fa'), 'flag-ir'], ]; diff --git a/modules/backend/models/BrandSettings.php b/modules/backend/models/BrandSettings.php new file mode 100644 index 000000000..961491a51 --- /dev/null +++ b/modules/backend/models/BrandSettings.php @@ -0,0 +1,92 @@ + ['System\Models\File'] + ]; + + // Pumpkin + const PRIMARY_LIGHT = '#e67e22'; + + // Carrot + const PRIMARY_DARK = '#d35400'; + + // Wet Asphalt + const SECONDARY_LIGHT = '#34495e'; + + // Midnight Blue + const SECONDARY_DARK = '#2b3e50'; + + /** + * Validation rules + */ + public $rules = [ + 'app_name' => 'required', + 'app_tagline' => 'required', + ]; + + public function initSettingsData() + { + $this->app_name = Lang::get('system::lang.app.name'); + $this->app_tagline = Lang::get('system::lang.app.tagline'); + + $this->primary_color_light = self::PRIMARY_LIGHT; + $this->primary_color_dark = self::PRIMARY_DARK; + $this->secondary_color_light = self::SECONDARY_LIGHT; + $this->secondary_color_dark = self::SECONDARY_DARK; + } + + public function beforeValidate() + { + $this->rendered_css = self::renderCss(); + } + + public static function getLogo() + { + $settings = self::instance(); + if (!$settings->logo) + return null; + + return $settings->logo->getPath(); + } + + public static function renderCss() + { + $parser = new Less_Parser(['compress' => true]); + + $parser->ModifyVars([ + 'logo-image' => "'".self::getLogo()."'", + 'primary-color-light' => self::get('primary_color_light', self::PRIMARY_LIGHT), + 'primary-color-dark' => self::get('primary_color_dark', self::PRIMARY_DARK), + 'secondary-color-light' => self::get('secondary_color_light', self::SECONDARY_LIGHT), + 'secondary-color-dark' => self::get('secondary_color_dark', self::SECONDARY_DARK), + ]); + + $parser->parse(File::get(__DIR__.'/brandsettings/custom.less').self::get('custom_css')); + $css = $parser->getCss(); + + return $css; + } + +} \ No newline at end of file diff --git a/modules/backend/models/brandsettings/custom.less b/modules/backend/models/brandsettings/custom.less new file mode 100644 index 000000000..ad62d9387 --- /dev/null +++ b/modules/backend/models/brandsettings/custom.less @@ -0,0 +1,166 @@ +// +// Coded variables +// +// @logo-image +// @primary-color-light - #e67e22 +// @primary-color-dark - #d35400 +// @secondary-color-light - #34495e +// @secondary-color-dark - #2b3e50 +// + +// +// Logos +// + +.oc-bg-logo { + background-image: linear-gradient(to bottom, rgba(249,249,249,0.7) 0%,rgba(249,249,249,0.7) 100%), url('@{logo-image}'); +} +.oc-logo-white { + background-image: url('@{logo-image}'); + height: 170px !important; +} + +// +// Outside Layout +// + +@color-outer-bg: @secondary-color-dark; +@color-outer-header: mix(black, saturate(@secondary-color-dark, 5%), 27%); + +body.outer { + background: @color-outer-bg; +} + +body.outer .layout > .layout-row.layout-head { + background: @color-outer-header; +} + +// +// Side navigation bar +// + +@color-sidebarnav-bg: @secondary-color-light; + +#layout-sidenav { + background-color: @color-sidebarnav-bg; +} + +// +// Breadcrumb +// + +@color-breadcrumb-background: mix(rgb(43,43,43), @secondary-color-dark, 50%); + +.control-breadcrumb { + background-color: @color-breadcrumb-background; +} + +// +// Fancy layout +// + +@color-fancy-form-tabless-fields-bg: @primary-color-light; +@color-fancy-master-tabs-bg: @primary-color-dark; +@color-fancy-form-inactive-tab: mix(black, desaturate(@primary-color-dark, 14.5%), 5%); +@tab-svg: escape(''); + +.fancy-layout { + .control-tabs, &.control-tabs { + &.master { + > div > div.tabs-container { + background: @color-fancy-master-tabs-bg; + } + } + + &.primary { + > div > ul.nav-tabs { + &.master-area { + background: @color-fancy-form-tabless-fields-bg; + } + } + } + + &.master { + > div > div.tabs-container > ul.nav-tabs > li { + a > span.title { + background-color: @color-fancy-form-inactive-tab; + &:before, &:after { + background-image: url(~'data:image/svg+xml;charset=UTF-8,@{tab-svg}'); + } + } + &.active { + a > span.title { + background-color: @color-fancy-form-tabless-fields-bg; + } + } + } + } + } + + .form-tabless-fields { + background: @color-fancy-form-tabless-fields-bg; + } +} + +// +// Component List +// + +@color-component-list-bg: @secondary-color-dark; + +div.control-componentlist { + background-color: @color-component-list-bg; + + &.droppable { + background-color: lighten(@color-component-list-bg, 20%); + } +} + +// +// File List +// + +@color-list-active-border: @primary-color-light; + +.control-filelist { + ul li.active a:after { + background: @color-list-active-border; + } +} + +// +// Sidenav Tree +// + +@color-sidebarnav-bg: @secondary-color-light; +@color-sidebarnav-tree-group-bg: @secondary-color-dark; +@color-sidebarnav-tree-inactive-bg: mix(white, @secondary-color-light, 7%); +@color-sidebarnav-tree-active-bg: @secondary-color-light; +@color-sidebarnav-tree-active-marker: @primary-color-light; + +.sidenav-tree { + background: @color-sidebarnav-bg; + + ul.top-level > li { + > div.group h3 { + background: @color-sidebarnav-tree-group-bg; + } + + > ul li { + a { + background: @color-sidebarnav-tree-inactive-bg; + } + &.active a { + background: @color-sidebarnav-tree-active-bg; + + &:before { + background: @color-sidebarnav-tree-active-marker; + } + } + + &:hover a { + background: @color-sidebarnav-tree-active-bg; + } + } + } +} \ No newline at end of file diff --git a/modules/backend/models/brandsettings/fields.yaml b/modules/backend/models/brandsettings/fields.yaml new file mode 100644 index 000000000..558f1cd04 --- /dev/null +++ b/modules/backend/models/brandsettings/fields.yaml @@ -0,0 +1,59 @@ +# =================================== +# Field Definitions +# =================================== + + +tabs: + fields: + + logo: + label: Logo + type: fileupload + commentAbove: Upload a custom logo to use in the back-end. + mode: image + imageHeight: 170 + imageWidth: 170 + tab: Brand + + app_name: + label: App Name + commentAbove: This name is shown in the title area of the back-end. + tab: Brand + + app_tagline: + label: App Tagline + commentAbove: This name is shown on the sign in screen for the back-end. + tab: Brand + + primary_color_light: + label: Primary (Light) + type: colorpicker + tab: Colors + availableColors: [#1abc9c, #2ecc71, #3498db, #9b59b6, #34495e, #f1c40f, #e67e22, #e74c3c, #ecf0f1, #95a5a6] + + primary_color_dark: + label: Primary (Dark) + type: colorpicker + tab: Colors + availableColors: [#16a085, #27ae60, #2980b9, #8e44ad, #2b3e50, #f39c12, #d35400, #c0392b, #bdc3c7, #7f8c8d] + + secondary_color_light: + label: Secondary (Light) + type: colorpicker + tab: Colors + availableColors: [#1abc9c, #2ecc71, #3498db, #9b59b6, #34495e, #f1c40f, #e67e22, #e74c3c, #ecf0f1, #95a5a6] + + secondary_color_dark: + label: Secondary (Dark) + type: colorpicker + tab: Colors + availableColors: [#16a085, #27ae60, #2980b9, #8e44ad, #2b3e50, #f39c12, #d35400, #c0392b, #bdc3c7, #7f8c8d] + + custom_css: + label: Custom stylesheet + type: codeeditor + tab: Styles + size: giant + language: css + + diff --git a/modules/backend/widgets/Lists.php b/modules/backend/widgets/Lists.php index 463ca2dff..81b6be4d7 100644 --- a/modules/backend/widgets/Lists.php +++ b/modules/backend/widgets/Lists.php @@ -562,7 +562,9 @@ class Lists extends WidgetBase if ($columnOrder = $this->getSession('order', null)) { $orderedDefinitions = []; foreach ($columnOrder as $column) { - $orderedDefinitions[$column] = $this->columns[$column]; + if (isset($this->columns[$column])) { + $orderedDefinitions[$column] = $this->columns[$column]; + } } $this->columns = array_merge($orderedDefinitions, $this->columns); diff --git a/modules/backend/widgets/filter/partials/_scope_checkbox.htm b/modules/backend/widgets/filter/partials/_scope_checkbox.htm index d9ce4fe87..3b618af87 100644 --- a/modules/backend/widgets/filter/partials/_scope_checkbox.htm +++ b/modules/backend/widgets/filter/partials/_scope_checkbox.htm @@ -3,5 +3,5 @@ class="filter-scope checkbox custom-checkbox" data-scope-name="scopeName ?>"> value ? 'checked' : '' ?> /> - +
diff --git a/modules/backend/widgets/filter/partials/_scope_group.htm b/modules/backend/widgets/filter/partials/_scope_group.htm index bec8604fe..e5628d359 100644 --- a/modules/backend/widgets/filter/partials/_scope_group.htm +++ b/modules/backend/widgets/filter/partials/_scope_group.htm @@ -3,6 +3,6 @@ class="filter-scope value ? 'active' : '' ?>" href="javascript:;" data-scope-name="scopeName ?>"> - label) ?>: + label)) ?>: value ? count($scope->value) : e(trans('backend::lang.filter.all')) ?> diff --git a/modules/cms/classes/Controller.php b/modules/cms/classes/Controller.php index df4555bc7..8c75fe544 100644 --- a/modules/cms/classes/Controller.php +++ b/modules/cms/classes/Controller.php @@ -20,6 +20,7 @@ use Cms\Twig\Extension as CmsTwigExtension; use Cms\Classes\FileHelper as CmsFileHelper; use System\Models\RequestLog; use System\Classes\ErrorHandler; +use System\Classes\CombineAssets; use System\Classes\ApplicationException; use System\Twig\Extension as SystemTwigExtension; use October\Rain\Support\ValidationException; @@ -893,28 +894,6 @@ class Controller extends BaseController return $this->router->getParameter($name, $default); } - /** - * Combines JavaScript and StyleSheet assets. - * @param string $name Combined file code - * @return string Combined content. - */ - public function combine($name) - { - try { - if (!strpos($name, '-')) - throw new CmsException(Lang::get('cms::lang.combiner.not_found', ['name'=>$name])); - - $parts = explode('-', $name); - $cacheId = $parts[0]; - - $combiner = new CombineAssets; - return $combiner->getContents($cacheId); - } - catch (Exception $ex) { - return '/* '.$ex->getMessage().' */'; - } - } - /** * Searches the layout and page components by an alias * @return ComponentBase The component object, if found diff --git a/modules/cms/controllers/Index.php b/modules/cms/controllers/Index.php index 8800f20e1..311cfb096 100644 --- a/modules/cms/controllers/Index.php +++ b/modules/cms/controllers/Index.php @@ -101,8 +101,8 @@ class Index extends Controller $this->addJs('/modules/backend/formwidgets/codeeditor/assets/vendor/ace/mode-'.$mode.'.js', 'core'); $this->bodyClass = 'compact-container side-panel-not-fixed'; - $this->pageTitle = Lang::get('cms::lang.cms.menu_label'); - $this->pageTitleTemplate = '%s CMS | October'; + $this->pageTitle = 'cms::lang.cms.menu_label'; + $this->pageTitleTemplate = '%s CMS'; } public function index_onOpenTemplate() diff --git a/modules/cms/controllers/Themes.php b/modules/cms/controllers/Themes.php index a1c0b98fa..6e3e117a7 100644 --- a/modules/cms/controllers/Themes.php +++ b/modules/cms/controllers/Themes.php @@ -1,6 +1,5 @@ addCss('/modules/cms/assets/css/october.theme-selector.css', 'core'); - $this->pageTitle = Lang::get('cms::lang.theme.settings_menu'); + $this->pageTitle = 'cms::lang.theme.settings_menu'; BackendMenu::setContext('October.System', 'system', 'settings'); SettingsManager::setContext('October.Cms', 'theme'); } diff --git a/modules/cms/controllers/index/index.htm b/modules/cms/controllers/index/index.htm index 08c9e7ac1..56aa5368d 100644 --- a/modules/cms/controllers/index/index.htm +++ b/modules/cms/controllers/index/index.htm @@ -28,6 +28,6 @@
-

fatalError) ?>

+

fatalError)) ?>

\ No newline at end of file diff --git a/modules/cms/lang/de/lang.php b/modules/cms/lang/de/lang.php index 4bbabe6a3..52e59f2a7 100644 --- a/modules/cms/lang/de/lang.php +++ b/modules/cms/lang/de/lang.php @@ -68,9 +68,6 @@ return [ 'invalid_name' => "Ungültiger Name für AJAX Handler: :name.", 'not_found' => "AJAX Handler ':name' wurde nicht gefunden.", ], - 'combiner' => [ - 'not_found' => "Die combiner Datei ':name' wurde nicht gefunden.", - ], 'cms' => [ 'menu_label' => "CMS" ], diff --git a/modules/cms/lang/en/lang.php b/modules/cms/lang/en/lang.php index f29007641..a92ff49e0 100644 --- a/modules/cms/lang/en/lang.php +++ b/modules/cms/lang/en/lang.php @@ -74,9 +74,6 @@ return [ 'invalid_name' => "Invalid AJAX handler name: :name.", 'not_found' => "AJAX handler ':name' was not found.", ], - 'combiner' => [ - 'not_found' => "The combiner file ':name' is not found.", - ], 'cms' => [ 'menu_label' => "CMS" ], diff --git a/modules/cms/lang/es-ar/lang.php b/modules/cms/lang/es-ar/lang.php new file mode 100644 index 000000000..de2148777 --- /dev/null +++ b/modules/cms/lang/es-ar/lang.php @@ -0,0 +1,170 @@ + [ + 'invalid_file' => 'Nombre inválido del archivo: :name. El nombre del archivo debe contener solamente caracteres alfanuméricos, guiones bajos, barras y puntos. Algunos ejemplos de nombres correctos son: archivo.htm, archivo, subdirectorio/archivo', + 'invalid_property' => 'La propiedad ":name" no puede establecerse', + 'file_already_exists' => 'Archivo ":name" ya existe.', + 'error_saving' => 'Error guardando archivo ":name". Por favor revisar los permisos de escritura.', + 'error_creating_directory' => 'Error creando el directorio :name. Por favor revisar los permisos de escritura.', + 'invalid_file_extension'=>'Extensión de archivo inválida: :invalid. Las extensiones permitidas son: :allowed.', + 'error_deleting' => 'Error borrando el archivo template ":name". Por favor revisar los permisos de escritura.', + 'delete_success' => 'Los templates fueron borrados exitosamente: :count.', + 'file_name_required' => 'Falta el nombre del campo del archivo.' + ], + 'theme' => [ + 'active' => [ + 'not_set' => "El tema activo no se ha establecido.", + 'not_found' => "El tema activo no se encuentra.", + ], + 'edit' => [ + 'not_set' => "El tema de edición no se ha establecido.", + 'not_found' => "El tema de edición no se encuentra.", + 'not_match' => "El objeto que está intentando acceder no pertenece al tema que se está editando. Vuelve a cargar la página." + ], + 'settings_menu' => 'Plantilla', + 'settings_menu_description' => 'Vista previa de la lista de las plantillas instaladas.', + 'find_more_themes' => 'Busque más Plantillas', + 'activate_button' => 'Activar', + 'active_button' => 'Activar', + ], + 'page' => [ + 'not_found' => [ + 'label' => "Página no encontrada", + 'help' => "La página solicitada no se puede encontrar.", + ], + 'custom_error' => [ + 'label' => "Error de página", + 'help' => "Lo sentimos, ha ocurrido un error y la página no se puede mostrar.", + ], + 'menu_label' => 'Páginas', + 'no_list_records' => 'No se encontraron páginas', + 'new' => 'Nueva página', + 'invalid_url' => 'Formato de URL inválido. El URL debe comenzar con el símbolo de barra diagonal y puede contener dígitos, letras latinas y los siguientes símbolos: _-[]:?|/+*', + 'delete_confirm_multiple' => '¿Realmente quiere eliminar las páginas seleccionadas?', + 'delete_confirm_single' => '¿Realmente quieres eliminar esta página?', + 'no_layout' => '-- ninguna disposición --' + ], + 'layout' => [ + 'not_found' => "El diseño ':name' no se encuentra", + 'menu_label' => 'Diseños', + 'no_list_records' => 'No se ecnontraron diseños', + 'new' => 'Nuevo diseño', + 'delete_confirm_multiple' => 'Realmente quiere borrar los diseños seleccionados?', + 'delete_confirm_single' => 'Realmente quiere borrar este diseño?' + ], + 'partial' => [ + 'invalid_name' => "Nombre parcial inválido: :name.", + 'not_found' => "El nombre parcial ':name' no se encuentra.", + 'menu_label' => 'Parciales', + 'no_list_records' => 'No se encontraron parciales', + 'delete_confirm_multiple' => 'Realmente quiere borrar los parciales seleccionados?', + 'delete_confirm_single' => 'Realmente quiere borrar este parcial?', + 'new' => 'Nuevo parcial' + ], + 'content' => [ + 'not_found' => "El contenido del archivo ':name' no se encuentra.", + 'menu_label' => 'Contenido', + 'no_list_records' => 'No se encuentra el conteinod de los archivos', + 'delete_confirm_multiple' => 'Realmente desea borrar los contenidos seleccionados de los archivos o directorios?', + 'delete_confirm_single' => 'Realmente desea borrar el contenido de este archivo?', + 'new' => 'Nuevo contenido de archivo' + ], + 'ajax_handler' => [ + 'invalid_name' => "Manejador de AJAX inválido: :name.", + 'not_found' => "El manejador de AJAX ':name' no se encuentra.", + ], + 'cms' => [ + 'menu_label' => "Gestión" + ], + 'sidebar' => [ + 'add' => 'Agregar', + 'search' => 'Buscar...' + ], + 'editor' => [ + 'settings' => 'Configuración', + 'title' => 'Título', + 'new_title' => 'Nuevo título de la página', + 'url' => 'URL', + 'filename' => 'Nombre del archivo', + 'layout' => 'Disposición', + 'description' => 'Descripción', + 'preview' => 'Vista previa', + 'meta' => 'Meta', + 'meta_title' => 'Meta Título', + 'meta_description' => 'Meta Descripción', + 'markup' => 'Marcado', + 'code' => 'Código', + 'content' => 'Contenido', + 'hidden' => 'Oculto', + 'hidden_comment' => 'A las páginas ocultas solamente pueden acceder los usuarios del back-end que se encuentren logueados.', + 'enter_fullscreen' => 'Ingresar en el modo pantalla completa', + 'exit_fullscreen' => 'Salir de pantalla completa' + ], + 'asset' => [ + 'menu_label' => "Assets", + 'drop_down_add_title' => 'Add...', + 'drop_down_operation_title' => 'Action...', + 'upload_files' => 'Upload file(s)', + 'create_file' => 'Create file', + 'create_directory' => 'Create directory', + 'directory_popup_title' => 'Nuevo directorio', + 'directory_name' => 'Nombre del directorio', + 'rename' => 'Renombrar', + 'delete' => 'Borrar', + 'move' => 'Mover', + 'select' => 'Seleccionar', + 'new' => 'Nuevo archivo', + 'rename_popup_title' => 'Renombrar', + 'rename_new_name' => 'Nuevo nombre', + 'invalid_path' => 'El path solamente puede contener dígitos, letras, espacios y los símbolos siguientes: ._-/', + 'error_deleting_file' => 'Error al borrar el archivo :name.', + 'error_deleting_dir_not_empty' => 'Error borrando el directorio :name. El directorio no está vacío.', + 'error_deleting_dir' => 'Error borrando el archivo :name.', + 'invalid_name' => 'El nombre solamente puede contener dígitos, letras, espacios y los símbolos siguientes: ._-', + 'original_not_found' => 'El archivo o directorio original no se encuentra', + 'already_exists' => 'Un archivo o directorio con este nombre ya existe', + 'error_renaming' => 'Error renombrando el archivo o directorio', + 'name_cant_be_empty' => 'El nombre no puede estar vacío', + 'too_large' => 'El archivo subido es demasiado pesado. El tamaño máximo permitido es :max_size', + 'type_not_allowed' => 'Solamente los siguientes tipos de archivos están permitidos: :allowed_types', + 'file_not_valid' => 'El archivo no es válido', + 'error_uploading_file' => 'Error subiendo el archivo ":name": :error', + 'move_please_select' => 'por favor seleccionar', + 'move_destination' => 'Directorio destino', + 'move_popup_title' => 'Mover los títulos emergentes', + 'move_button' => 'Mover', + 'selected_files_not_found' => 'Los archivos seleccionados no se encuentran', + 'select_destination_dir' => 'Por favor seleccione un directorio destino', + 'destination_not_found' => 'El directorio destino no se encuentra', + 'error_moving_file' => 'Error moviendo archivo :file', + 'error_moving_directory' => 'Error moviendo el directorio :dir', + 'error_deleting_directory' => 'Error borrando el directorio original :dir', + 'path' => 'Path' + ], + 'component' => [ + 'menu_label' => "Componentes", + 'unnamed' => "Sin nombre", + 'no_description' => "No se proporciona descripción", + 'alias' => "Alias", + 'alias_description' => "Se le ha asignado un nombre único a este componente cuando se lo utilizaba en la página o en el código de disposición.", + 'validation_message' => "El componente alias es requerido y puede contener solamente letras, números y guión bajo. El alias debe empezar con una letra.", + 'invalid_request' => "La plantilla no puede ser guardada porque tiene datos inválidos.", + 'no_records' => 'No se encontraron componentes', + 'not_found' => "El componente ':name' no se encuentra.", + 'method_not_found' => "El componente ':name' no contiene un método ':method'.", + ], + 'template' => [ + 'invalid_type' => "Tipo de plantilla Desconocido.", + 'not_found' => "No se encontró la plantilla solicitada.", + 'saved'=> "La plantilla se ha guardado correctamente." + ], + 'permissions' => [ + 'manage_content' => 'Gestionar contenido', + 'manage_assets' => 'Gestionar archivos', + 'manage_pages' => 'Gestionar páginas', + 'manage_layouts' => 'Gestionar diseños', + 'manage_partials' => 'Gestionar parciales', + 'manage_themes' => 'Gestionar plantilla' + ] +]; \ No newline at end of file diff --git a/modules/cms/lang/fa/lang.php b/modules/cms/lang/fa/lang.php index 2645b8e12..6f3b87a0e 100644 --- a/modules/cms/lang/fa/lang.php +++ b/modules/cms/lang/fa/lang.php @@ -74,9 +74,6 @@ return [ 'invalid_name' => "نام کنترل کننده آژاکس نا معتبر است: :name.", 'not_found' => "کنترل کننده آژاکس ':name' یافت نشد.", ], - 'combiner' => [ - 'not_found' => "فایل ترکیب کننده ':name' یافت نشد.", - ], 'cms' => [ 'menu_label' => "مدیریت محتوی" ], diff --git a/modules/cms/lang/fr/lang.php b/modules/cms/lang/fr/lang.php index 21edf845a..ce9e51e81 100644 --- a/modules/cms/lang/fr/lang.php +++ b/modules/cms/lang/fr/lang.php @@ -74,9 +74,6 @@ return [ 'invalid_name' => "Nom de gestionnaire AJAX invalide: :name.", 'not_found' => "Le gestionnaire AJAX ':name' est introuvable.", ], - 'combiner' => [ - 'not_found' => "Le fichier combiner ':name' est introuvable.", - ], 'cms' => [ 'menu_label' => "CMS" ], diff --git a/modules/cms/lang/it/lang.php b/modules/cms/lang/it/lang.php index 406d4ca30..006c749e8 100644 --- a/modules/cms/lang/it/lang.php +++ b/modules/cms/lang/it/lang.php @@ -74,9 +74,6 @@ return [ 'invalid_name' => "Nome del gestore AJAX non valido: :name.", 'not_found' => "Il gestore AJAX ':name' non è stato trovato.", ], - 'combiner' => [ - 'not_found' => "Il file combinatore ':name' non è stato trovato.", - ], 'cms' => [ 'menu_label' => "CMS" ], diff --git a/modules/cms/lang/ja/lang.php b/modules/cms/lang/ja/lang.php index 8a087e347..18b50238a 100644 --- a/modules/cms/lang/ja/lang.php +++ b/modules/cms/lang/ja/lang.php @@ -68,9 +68,6 @@ return [ 'invalid_name' => "正しくないAJAXハンドラー名::name。", 'not_found' => "':name' AJAXハンドラーが見つかりません。", ], - 'combiner' => [ - 'not_found' => "':name'コンバイナーファイルが見つかりません。", - ], 'cms' => [ 'menu_label' => "CMS" ], diff --git a/modules/cms/lang/nl/lang.php b/modules/cms/lang/nl/lang.php index dbe4a82cd..07147ab93 100644 --- a/modules/cms/lang/nl/lang.php +++ b/modules/cms/lang/nl/lang.php @@ -74,9 +74,6 @@ return [ 'invalid_name' => "Ongeldige AJAX handlernaam: :name.", 'not_found' => "AJAX handler ':name' is niet gevonden.", ], - 'combiner' => [ - 'not_found' => "Het samenvoegbestand ':name' is niet gevonden.", - ], 'cms' => [ 'menu_label' => "CMS" ], diff --git a/modules/cms/lang/pt-br/lang.php b/modules/cms/lang/pt-br/lang.php index a4cb9cdaa..7e4aade3b 100644 --- a/modules/cms/lang/pt-br/lang.php +++ b/modules/cms/lang/pt-br/lang.php @@ -74,9 +74,6 @@ return [ 'invalid_name' => "O nome do Manipulador AJAX é inválido: :name.", 'not_found' => "Manipulador AJAX ':name' não foi encontrado.", ], - 'combiner' => [ - 'not_found' => "O arquivo combinador ':name' não foi encontrado.", - ], 'cms' => [ 'menu_label' => "Design" ], diff --git a/modules/cms/lang/ro/lang.php b/modules/cms/lang/ro/lang.php index 2af6f1c6c..a55731b35 100644 --- a/modules/cms/lang/ro/lang.php +++ b/modules/cms/lang/ro/lang.php @@ -74,9 +74,6 @@ return [ 'invalid_name' => "Nume Functie AJAX invalid: :name.", 'not_found' => "Functia AJAX ':name' nu a fost gasita.", ], - 'combiner' => [ - 'not_found' => "Fisierul compus ':name' nu a fost gasit.", - ], 'cms' => [ 'menu_label' => "CMS" ], diff --git a/modules/cms/lang/ru/lang.php b/modules/cms/lang/ru/lang.php index 68aab92fd..1ad311ea0 100644 --- a/modules/cms/lang/ru/lang.php +++ b/modules/cms/lang/ru/lang.php @@ -74,9 +74,6 @@ return [ 'invalid_name' => "Ошибка в имени обработчика AJAX: :name.", 'not_found' => "Обработчик AJAX не найден: ':name'.", ], - 'combiner' => [ - 'not_found' => "Сборщик ресурсов не может найти файл ':name'.", - ], 'cms' => [ 'menu_label' => "CMS" ], diff --git a/modules/cms/lang/sv/lang.php b/modules/cms/lang/sv/lang.php index b8dab98a1..f51d60b98 100644 --- a/modules/cms/lang/sv/lang.php +++ b/modules/cms/lang/sv/lang.php @@ -68,9 +68,6 @@ return [ 'invalid_name' => "Felaktig AJAX-hanterare: :name", 'not_found' => "AJAX-hanterare ':name' kunde ej hittas", ], - 'combiner' => [ - 'not_found' => "Kombinationsfilen ':name' kunde ej hittas", - ], 'cms' => [ 'menu_label' => "CMS" ], diff --git a/modules/cms/lang/tr/lang.php b/modules/cms/lang/tr/lang.php index 7aa0d65ae..d88cef5d5 100644 --- a/modules/cms/lang/tr/lang.php +++ b/modules/cms/lang/tr/lang.php @@ -68,9 +68,6 @@ return [ 'invalid_name' => "Hatalı AJAX işleyici adı: :name.", 'not_found' => "':name' isimli AJAX işleyici bulunamadı.", ], - 'combiner' => [ - 'not_found' => "The combiner file ':name' is not found.", - ], 'cms' => [ 'menu_label' => "CMS" ], diff --git a/modules/cms/routes.php b/modules/cms/routes.php index 45a8295ff..bc04921dc 100644 --- a/modules/cms/routes.php +++ b/modules/cms/routes.php @@ -5,11 +5,6 @@ */ App::before(function($request) { - /* - * Combine JavaScript and StyleSheet assets - */ - Route::any('combine/{file}', 'Cms\Classes\Controller@combine'); - /* * The CMS module intercepts all URLs that were not * handled by the back-end modules. diff --git a/modules/system/ServiceProvider.php b/modules/system/ServiceProvider.php index 88c6c64af..89275e896 100644 --- a/modules/system/ServiceProvider.php +++ b/modules/system/ServiceProvider.php @@ -5,6 +5,7 @@ use Lang; use Event; use Config; use Backend; +use Request; use DbDongle; use BackendMenu; use BackendAuth; @@ -66,7 +67,11 @@ class ServiceProvider extends ModuleServiceProvider */ $requestPath = \October\Rain\Router\Helper::normalizeUrl(\Request::path()); $systemPath = \October\Rain\Router\Helper::normalizeUrl(Config::get('cms.backendUri') . '/system/updates'); - if (App::runningInConsole() || stripos($requestPath, $systemPath) === 0) + if (stripos($requestPath, $systemPath) === 0) + PluginManager::$noInit = true; + + $updateCommands = ['october:up', 'october:update']; + if (App::runningInConsole() && count(array_intersect($updateCommands, Request::server('argv'))) > 0) PluginManager::$noInit = true; /* diff --git a/modules/system/behaviors/SettingsModel.php b/modules/system/behaviors/SettingsModel.php index f4c7c30a8..c3228c1f1 100644 --- a/modules/system/behaviors/SettingsModel.php +++ b/modules/system/behaviors/SettingsModel.php @@ -1,5 +1,6 @@ model->bindEvent('model.afterFetch', [$this, 'afterModelFetch']); $this->model->bindEvent('model.beforeSave', [$this, 'beforeModelSave']); + $this->model->bindEvent('model.afterSave', [$this, 'afterModelSave']); $this->model->bindEvent('model.setAttribute', [$this, 'setModelAttribute']); $this->model->bindEvent('model.saveInternal', [$this, 'saveModelInternal']); @@ -72,17 +74,8 @@ class SettingsModel extends ModelBehavior if (isset(self::$instances[$this->recordCode])) return self::$instances[$this->recordCode]; - $item = $this->model->where('item', $this->recordCode)->first(); - - if (!$item) { + if (!$item = $this->getSettingsRecord()) { $this->model->initSettingsData(); - - if (method_exists($this->model, 'forceSave')) - $this->model->forceSave(); - else - $this->model->save(); - - $this->model->reload(); $item = $this->model; } @@ -94,7 +87,21 @@ class SettingsModel extends ModelBehavior */ public function isConfigured() { - return $this->model->where('item', $this->recordCode)->count() > 0; + return $this->getSettingsRecord() !== null; + } + + /** + * Returns the raw Model record that stores the settings. + * @return Model + */ + public function getSettingsRecord() + { + $record = $this->model + ->where('item', $this->recordCode) + ->remember(1440, $this->getCacheKey()) + ->first(); + + return $record ?: null; } /** @@ -108,17 +115,17 @@ class SettingsModel extends ModelBehavior } /** - * Helper for getValue, intended as a static method + * Helper for getSettingsValue, intended as a static method */ public function get($key, $default = null) { - return $this->instance()->getValue($key, $default); + return $this->instance()->getSettingsValue($key, $default); } /** * Get a single setting value, or return a default value */ - public function getValue($key, $default = null) + public function getSettingsValue($key, $default = null) { if (array_key_exists($key, $this->fieldValues)) return $this->fieldValues[$key]; @@ -161,6 +168,15 @@ class SettingsModel extends ModelBehavior $this->model->value = $this->fieldValues; } + /** + * After the model is saved, clear the cached query entry. + * @return void + */ + public function afterModelSave() + { + Cache::forget($this->getCacheKey()); + } + /** * Adulterate the model setter to use our field values instead. */ @@ -200,4 +216,12 @@ class SettingsModel extends ModelBehavior { return $this->fieldConfig; } + + /** + * Returns a cache key for this record. + */ + protected function getCacheKey() + { + return 'system::settings.'.$this->recordCode; + } } diff --git a/modules/cms/classes/CombineAssets.php b/modules/system/classes/CombineAssets.php similarity index 97% rename from modules/cms/classes/CombineAssets.php rename to modules/system/classes/CombineAssets.php index 952b1e049..f460cafc6 100644 --- a/modules/cms/classes/CombineAssets.php +++ b/modules/system/classes/CombineAssets.php @@ -1,4 +1,4 @@ -getCache($cacheId); if (!$cacheInfo) - throw new CmsException(Lang::get('cms::lang.combiner.not_found', ['name'=>$cacheId])); + throw new ApplicationException(Lang::get('cms::lang.combiner.not_found', ['name'=>$cacheId])); $this->path = $cacheInfo['path']; $this->storagePath = storage_path().'/combiner/cms'; @@ -355,7 +356,7 @@ class CombineAssets */ protected function getCombinedUrl($outputFilename = 'undefined.css') { - $combineAction = 'Cms\Classes\Controller@combine'; + $combineAction = 'System\Classes\Controller@combine'; $actionExists = Route::getRoutes()->getByAction($combineAction) !== null; if ($actionExists) diff --git a/modules/system/classes/Controller.php b/modules/system/classes/Controller.php new file mode 100644 index 000000000..a49caa6f9 --- /dev/null +++ b/modules/system/classes/Controller.php @@ -0,0 +1,39 @@ +$name])); + + $parts = explode('-', $name); + $cacheId = $parts[0]; + + $combiner = new CombineAssets; + return $combiner->getContents($cacheId); + } + catch (Exception $ex) { + return '/* '.$ex->getMessage().' */'; + } + } + +} \ No newline at end of file diff --git a/modules/system/classes/PluginManager.php b/modules/system/classes/PluginManager.php index 2da124526..9d5616105 100644 --- a/modules/system/classes/PluginManager.php +++ b/modules/system/classes/PluginManager.php @@ -116,14 +116,16 @@ class PluginManager */ public function registerAll() { - if ($this->registered || self::$noInit) + if ($this->registered) return; foreach ($this->plugins as $pluginId => $plugin) { if ($plugin->disabled) continue; - $plugin->register(); + if (!self::$noInit) + $plugin->register(); + $pluginPath = $this->getPluginPath($plugin); $pluginNamespace = strtolower($pluginId); @@ -171,14 +173,15 @@ class PluginManager */ public function bootAll() { - if ($this->booted || self::$noInit) + if ($this->booted) return; foreach ($this->plugins as $plugin) { if ($plugin->disabled) continue; - $plugin->boot(); + if (!self::$noInit) + $plugin->boot(); } $this->booted = true; diff --git a/modules/system/controllers/Settings.php b/modules/system/controllers/Settings.php index 2db37def9..0e5e98601 100644 --- a/modules/system/controllers/Settings.php +++ b/modules/system/controllers/Settings.php @@ -37,7 +37,7 @@ class Settings extends Controller public function index() { - $this->pageTitle = Lang::get('system::lang.settings.menu_label'); + $this->pageTitle = 'system::lang.settings.menu_label'; $this->vars['items'] = SettingsManager::instance()->listItems('system'); $this->bodyClass = 'compact-container sidenav-tree-root'; } @@ -45,7 +45,7 @@ class Settings extends Controller public function mysettings() { BackendMenu::setContextSideMenu('mysettings'); - $this->pageTitle = Lang::get('backend::lang.mysettings.menu_label'); + $this->pageTitle = 'backend::lang.mysettings.menu_label'; $this->vars['items'] = SettingsManager::instance()->listItems('mysettings'); $this->bodyClass = 'compact-container'; } @@ -58,18 +58,19 @@ class Settings extends Controller { SettingsManager::setContext($author.'.'.$plugin, $code); + $this->vars['parentLink'] = Backend::url('system/settings'); + $this->vars['parentLabel'] = Lang::get('system::lang.settings.menu_label'); + try { - $item = $this->findSettingItem($author, $plugin, $code); + if (!$item = $this->findSettingItem($author, $plugin, $code)) + throw new ApplicationException(Lang::get('system::lang.settings.not_found')); + $this->pageTitle = $item->label; if ($item->context == 'mysettings') { $this->vars['parentLink'] = Backend::url('system/settings/mysettings'); $this->vars['parentLabel'] = Lang::get('backend::lang.mysettings.menu_label'); } - else { - $this->vars['parentLink'] = Backend::url('system/settings'); - $this->vars['parentLabel'] = Lang::get('system::lang.settings.menu_label'); - } $model = $this->createModel($item); $this->initWidgets($model); diff --git a/modules/system/controllers/Updates.php b/modules/system/controllers/Updates.php index 37890c3d5..a0996ab9b 100644 --- a/modules/system/controllers/Updates.php +++ b/modules/system/controllers/Updates.php @@ -67,7 +67,7 @@ class Updates extends Controller */ public function manage() { - $this->pageTitle = Lang::get('system::lang.plugins.manage'); + $this->pageTitle = 'system::lang.plugins.manage'; PluginManager::instance()->clearDisabledCache(); return $this->asExtension('ListController')->index(); } diff --git a/modules/system/controllers/eventlogs/preview.htm b/modules/system/controllers/eventlogs/preview.htm index 82d865062..e44db1bc7 100644 --- a/modules/system/controllers/eventlogs/preview.htm +++ b/modules/system/controllers/eventlogs/preview.htm @@ -1,7 +1,7 @@
  • -
  • pageTitle) ?>
  • +
  • pageTitle)) ?>
@@ -30,7 +30,7 @@ -

fatalError) ?>

+

fatalError)) ?>

diff --git a/modules/system/controllers/maillayouts/create.htm b/modules/system/controllers/maillayouts/create.htm index 4347511fa..f8e64df4b 100644 --- a/modules/system/controllers/maillayouts/create.htm +++ b/modules/system/controllers/maillayouts/create.htm @@ -1,7 +1,7 @@
  • -
  • pageTitle) ?>
  • +
  • pageTitle)) ?>
@@ -40,7 +40,7 @@ -

fatalError) ?>

+

fatalError)) ?>

diff --git a/modules/system/controllers/maillayouts/update.htm b/modules/system/controllers/maillayouts/update.htm index 52599fddb..d21fa821a 100644 --- a/modules/system/controllers/maillayouts/update.htm +++ b/modules/system/controllers/maillayouts/update.htm @@ -1,7 +1,7 @@
  • -
  • pageTitle) ?>
  • +
  • pageTitle)) ?>
@@ -59,7 +59,7 @@ -

fatalError) ?>

+

fatalError)) ?>

diff --git a/modules/system/controllers/mailtemplates/create.htm b/modules/system/controllers/mailtemplates/create.htm index db42fd5c4..05b11f3fa 100644 --- a/modules/system/controllers/mailtemplates/create.htm +++ b/modules/system/controllers/mailtemplates/create.htm @@ -1,7 +1,7 @@
  • -
  • pageTitle) ?>
  • +
  • pageTitle)) ?>
@@ -40,7 +40,7 @@ -

fatalError) ?>

+

fatalError)) ?>

diff --git a/modules/system/controllers/mailtemplates/update.htm b/modules/system/controllers/mailtemplates/update.htm index 61a06871c..e812f8639 100644 --- a/modules/system/controllers/mailtemplates/update.htm +++ b/modules/system/controllers/mailtemplates/update.htm @@ -1,7 +1,7 @@
  • -
  • pageTitle) ?>
  • +
  • pageTitle)) ?>
@@ -65,7 +65,7 @@ -

fatalError) ?>

+

fatalError)) ?>

diff --git a/modules/system/controllers/requestlogs/preview.htm b/modules/system/controllers/requestlogs/preview.htm index b690986af..fe9b83583 100644 --- a/modules/system/controllers/requestlogs/preview.htm +++ b/modules/system/controllers/requestlogs/preview.htm @@ -1,7 +1,7 @@
  • -
  • pageTitle) ?>
  • +
  • pageTitle)) ?>
@@ -34,7 +34,7 @@ -

fatalError) ?>

+

fatalError)) ?>

diff --git a/modules/system/controllers/settings/update.htm b/modules/system/controllers/settings/update.htm index 1232d9320..5d357c5d6 100644 --- a/modules/system/controllers/settings/update.htm +++ b/modules/system/controllers/settings/update.htm @@ -32,6 +32,6 @@ -

fatalError) ?>

+

fatalError)) ?>

\ No newline at end of file diff --git a/modules/system/controllers/updates/_disable_form.htm b/modules/system/controllers/updates/_disable_form.htm index 5f116dfda..1bb8fd4e1 100644 --- a/modules/system/controllers/updates/_disable_form.htm +++ b/modules/system/controllers/updates/_disable_form.htm @@ -41,7 +41,7 @@ type="submit" class="btn btn-primary" data-request="onDisablePlugins" - data-request-confirm="" + data-request-confirm="" data-stripe-load-indicator> @@ -52,4 +52,4 @@
- \ No newline at end of file + diff --git a/modules/system/controllers/updates/_execute.htm b/modules/system/controllers/updates/_execute.htm index a1fa35d08..91a14471b 100644 --- a/modules/system/controllers/updates/_execute.htm +++ b/modules/system/controllers/updates/_execute.htm @@ -136,7 +136,7 @@