Merge branch 'develop' into builder-ui
Conflicts: modules/backend/assets/css/october.css
This commit is contained in:
commit
3851ae68cd
File diff suppressed because it is too large
Load Diff
Binary file not shown.
|
Before Width: | Height: | Size: 188 B |
File diff suppressed because one or more lines are too long
|
|
@ -33,7 +33,7 @@
|
|||
}
|
||||
|
||||
.control-tabs, &.control-tabs {
|
||||
&.master {
|
||||
&.master-tabs {
|
||||
overflow: hidden;
|
||||
|
||||
&:before, &:after {
|
||||
|
|
@ -178,7 +178,7 @@
|
|||
}
|
||||
}
|
||||
|
||||
&.secondary {
|
||||
&.secondary-tabs {
|
||||
> div > ul.nav-tabs {
|
||||
background: @color-fancy-secondary-tabs-bg;
|
||||
> li {
|
||||
|
|
@ -215,7 +215,7 @@
|
|||
}
|
||||
}
|
||||
|
||||
&.content-tabs {
|
||||
&.secondary-content-tabs {
|
||||
> div > ul.nav-tabs {
|
||||
background: @body-bg;
|
||||
|
||||
|
|
@ -308,7 +308,7 @@
|
|||
}
|
||||
}
|
||||
|
||||
&.primary {
|
||||
&.primary-tabs {
|
||||
> div > ul.nav-tabs {
|
||||
background: @color-fancy-primary-tabs-bg;
|
||||
margin-left: 0!important;
|
||||
|
|
@ -559,7 +559,7 @@
|
|||
}
|
||||
}
|
||||
|
||||
.content-tabs .field-richeditor {
|
||||
.secondary-content-tabs .field-richeditor {
|
||||
.redactor-box .redactor-toolbar {
|
||||
margin: 20px 20px 0 20px!important;
|
||||
.border-radius(3px)!important;
|
||||
|
|
|
|||
|
|
@ -42,6 +42,25 @@ body {
|
|||
height: 100%;
|
||||
}
|
||||
|
||||
//
|
||||
// Tabs override for Layout
|
||||
// Primary tabs should use inset by default, unless otherwise specified
|
||||
// --------------------------------------------------
|
||||
|
||||
.control-tabs.primary-tabs {
|
||||
> ul.nav-tabs, > div > ul.nav-tabs, > div > div > ul.nav-tabs {
|
||||
margin-left: -20px;
|
||||
margin-right: -20px;
|
||||
}
|
||||
|
||||
&.tabs-no-inset {
|
||||
> ul.nav-tabs, > div > ul.nav-tabs, > div > div > ul.nav-tabs {
|
||||
margin-left: 0;
|
||||
margin-right: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Flexible layout system
|
||||
// --------------------------------------------------
|
||||
|
|
|
|||
|
|
@ -3,21 +3,16 @@
|
|||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1, user-scalable=0">
|
||||
<meta name="apple-mobile-web-app-capable" content="yes">
|
||||
<meta name="backend-base-path" content="<?= Backend::baseUrl() ?>">
|
||||
<meta name="csrf-token" content="<?= csrf_token() ?>">
|
||||
<title><?= e(trans('backend::lang.auth.title')) ?></title>
|
||||
<link href="<?= URL::to('modules/backend/assets/css/october.css') ?>" rel="stylesheet">
|
||||
|
||||
<script src="<?= URL::to('modules/backend/assets/js/vendor/jquery.min.js') ?>"></script>
|
||||
<script src="<?= URL::to('modules/system/assets/js/framework.js') ?>"></script>
|
||||
<script src="<?= URL::to('modules/system/assets/ui/js/flashmessage.js') ?>"></script>
|
||||
<script src="<?= URL::to('modules/system/assets/ui/vendor/modernizr/modernizr.js') ?>"></script>
|
||||
<script src="<?= URL::to('modules/backend/assets/js/october.utils.js') ?>"></script>
|
||||
<script src="<?= URL::to('modules/backend/assets/js/october-min.js') ?>"></script>
|
||||
<script src="<?= URL::to('modules/backend/assets/js/auth/auth.js') ?>"></script>
|
||||
|
||||
<script>
|
||||
<!--
|
||||
backendBasePath = '<?= Backend::baseUrl() ?>';
|
||||
// -->
|
||||
</script>
|
||||
<?= $this->makeAssets() ?>
|
||||
<?= Block::placeholder('head') ?>
|
||||
<?= $this->makeLayoutPartial('custom_styles') ?>
|
||||
|
|
|
|||
|
|
@ -172,10 +172,10 @@ class BrandSettings extends Model
|
|||
* Compile CSS
|
||||
*/
|
||||
$css = '';
|
||||
$css .= '.fancy-layout .control-tabs.master > div > div.tabs-container > ul.nav-tabs > li a > span.title:before,';
|
||||
$css .= '.fancy-layout.control-tabs.master > div > div.tabs-container > ul.nav-tabs > li a > span.title:before,';
|
||||
$css .= '.fancy-layout .control-tabs.master > div > div.tabs-container > ul.nav-tabs > li a > span.title:after,';
|
||||
$css .= '.fancy-layout.control-tabs.master > div > div.tabs-container > ul.nav-tabs > li a > span.title:after {';
|
||||
$css .= '.fancy-layout .control-tabs.master-tabs > div > div.tabs-container > ul.nav-tabs > li a > span.title:before,';
|
||||
$css .= '.fancy-layout.control-tabs.master-tabs > div > div.tabs-container > ul.nav-tabs > li a > span.title:before,';
|
||||
$css .= '.fancy-layout .control-tabs.master-tabs > div > div.tabs-container > ul.nav-tabs > li a > span.title:after,';
|
||||
$css .= '.fancy-layout.control-tabs.master-tabs > div > div.tabs-container > ul.nav-tabs > li a > span.title:after {';
|
||||
$css .= "background-image: url('".$svg."')}";
|
||||
|
||||
return $css;
|
||||
|
|
|
|||
|
|
@ -116,13 +116,13 @@ table.table.data {
|
|||
|
||||
.fancy-layout {
|
||||
.control-tabs, &.control-tabs {
|
||||
&.master {
|
||||
&.master-tabs {
|
||||
> div > div.tabs-container {
|
||||
background: @color-fancy-master-tabs-bg;
|
||||
}
|
||||
}
|
||||
|
||||
&.secondary {
|
||||
&.secondary-tabs {
|
||||
&.content-tabs {
|
||||
&.primary-collapsed {
|
||||
> div > ul.nav-tabs {
|
||||
|
|
@ -132,7 +132,7 @@ table.table.data {
|
|||
}
|
||||
}
|
||||
|
||||
&.primary {
|
||||
&.primary-tabs {
|
||||
> div > ul.nav-tabs {
|
||||
&.master-area {
|
||||
background: @color-fancy-form-tabless-fields-bg;
|
||||
|
|
@ -140,7 +140,7 @@ table.table.data {
|
|||
}
|
||||
}
|
||||
|
||||
&.master {
|
||||
&.master-tabs {
|
||||
> div > div.tabs-container > ul.nav-tabs > li {
|
||||
a > span.title {
|
||||
background-color: @color-fancy-form-inactive-tab;
|
||||
|
|
@ -184,7 +184,7 @@ div.control-componentlist {
|
|||
|
||||
.fancy-layout {
|
||||
.control-tabs, &.control-tabs {
|
||||
&.primary {
|
||||
&.primary-tabs {
|
||||
> div > ul.nav-tabs {
|
||||
&.component-area {
|
||||
background: @color-component-list-bg;
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@
|
|||
|
||||
<div
|
||||
id="<?= $this->getId($type.'Tabs') ?>"
|
||||
class="control-tabs <?= $type ?> layout <?= $tabs->cssClass ?>"
|
||||
class="control-tabs <?= $type ?>-tabs layout <?= $tabs->cssClass ?>"
|
||||
data-control="tab"
|
||||
data-slidable>
|
||||
<?= $this->makePartial('form_tabs', ['tabs' => $tabs]) ?>
|
||||
|
|
|
|||
|
|
@ -106,9 +106,21 @@
|
|||
return this
|
||||
}
|
||||
|
||||
// LIST WIDGET HELPERS
|
||||
// =================
|
||||
|
||||
if ($.oc === undefined)
|
||||
$.oc = {}
|
||||
|
||||
$.oc.listToggleChecked = function(el) {
|
||||
$(el)
|
||||
.closest('[data-control="listwidget"]')
|
||||
.listWidget('toggleChecked', el)
|
||||
}
|
||||
|
||||
// LIST WIDGET DATA-API
|
||||
// ==============
|
||||
|
||||
|
||||
$(document).render(function(){
|
||||
$('[data-control="listwidget"]').listWidget();
|
||||
})
|
||||
|
|
|
|||
|
|
@ -326,8 +326,8 @@ div.control-componentlist div.components div.layout-cell.adding > div {
|
|||
text-shadow: 0 0 1px #475354 !important;
|
||||
color: #ffffff !important;
|
||||
}
|
||||
.fancy-layout .control-tabs.primary > div > ul.nav-tabs.component-area,
|
||||
.fancy-layout.control-tabs.primary > div > ul.nav-tabs.component-area {
|
||||
.fancy-layout .control-tabs.primary-tabs > div > ul.nav-tabs.component-area,
|
||||
.fancy-layout.control-tabs.primary-tabs > div > ul.nav-tabs.component-area {
|
||||
background: #2c3e50;
|
||||
}
|
||||
body.drag div.control-componentlist div.components div.layout-cell > div,
|
||||
|
|
|
|||
|
|
@ -120,7 +120,7 @@
|
|||
|
||||
var $el = $(element),
|
||||
$panel = $el.closest('.form-tabless-fields.collapsed'),
|
||||
$primaryPanel = $el.closest('.control-tabs.primary.collapsed')
|
||||
$primaryPanel = $el.closest('.control-tabs.primary-tabs.collapsed')
|
||||
|
||||
if ($panel.length > 0)
|
||||
$panel.removeClass('collapsed')
|
||||
|
|
@ -129,7 +129,7 @@
|
|||
$primaryPanel.removeClass('collapsed')
|
||||
|
||||
var pane = $primaryPanel.closest('.tab-pane'),
|
||||
$secondaryPanel = $('.control-tabs.secondary', pane)
|
||||
$secondaryPanel = $('.control-tabs.secondary-tabs', pane)
|
||||
|
||||
$secondaryPanel.removeClass('primary-collapsed')
|
||||
}
|
||||
|
|
@ -208,8 +208,8 @@
|
|||
})
|
||||
|
||||
var $primaryCollapseIcon = $('<a href="javascript:;" class="tab-collapse-icon primary"><i class="icon-chevron-down"></i></a>'),
|
||||
$primaryPanel = $('.control-tabs.primary', data.pane),
|
||||
$secondaryPanel = $('.control-tabs.secondary', data.pane),
|
||||
$primaryPanel = $('.control-tabs.primary-tabs', data.pane),
|
||||
$secondaryPanel = $('.control-tabs.secondary-tabs', data.pane),
|
||||
$primaryTabContainer = $('.nav-tabs', $primaryPanel)
|
||||
|
||||
$primaryTabContainer.addClass('master-area')
|
||||
|
|
@ -511,7 +511,7 @@
|
|||
|
||||
CmsPage.prototype.updateComponentListClass = function(pane) {
|
||||
var $componentList = $('.control-componentlist', pane),
|
||||
$primaryPanel = $('.control-tabs.primary', pane),
|
||||
$primaryPanel = $('.control-tabs.primary-tabs', pane),
|
||||
$primaryTabContainer = $('.nav-tabs', $primaryPanel),
|
||||
hasComponents = $('.layout', $componentList).children(':not(.hidden)').length > 0
|
||||
|
||||
|
|
@ -554,11 +554,11 @@
|
|||
|
||||
CmsPage.prototype.updateModifiedCounter = function() {
|
||||
var counters = {
|
||||
page: {menu: 'pages', count: 0},
|
||||
partial: {menu: 'partials', count: 0},
|
||||
layout: {menu: 'layouts', count: 0},
|
||||
content: {menu: 'content', count: 0},
|
||||
asset:{menu: 'assets', count: 0}
|
||||
page: { menu: 'pages', count: 0 },
|
||||
partial: { menu: 'partials', count: 0 },
|
||||
layout: { menu: 'layouts', count: 0 },
|
||||
content: { menu: 'content', count: 0 },
|
||||
asset: { menu: 'assets', count: 0}
|
||||
}
|
||||
|
||||
$('> div.tab-content > div.tab-pane[data-modified]', '#cms-master-tabs').each(function(){
|
||||
|
|
|
|||
|
|
@ -354,7 +354,7 @@ div.control-componentlist {
|
|||
|
||||
.fancy-layout {
|
||||
.control-tabs, &.control-tabs {
|
||||
&.primary {
|
||||
&.primary-tabs {
|
||||
> div > ul.nav-tabs {
|
||||
&.component-area {
|
||||
background: @color-component-list-bg;
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@
|
|||
data-pane-classes="layout-cell"
|
||||
data-max-title-symbols="15"
|
||||
data-title-as-file-names="true"
|
||||
class="layout control-tabs master fancy-layout oc-bg-logo"
|
||||
class="layout control-tabs master-tabs fancy-layout oc-bg-logo"
|
||||
id="cms-master-tabs">
|
||||
|
||||
<div class="layout-row min-size">
|
||||
|
|
|
|||
|
|
@ -0,0 +1,53 @@
|
|||
.plugin-details-content {
|
||||
padding: 0 0;
|
||||
}
|
||||
.plugin-details-content > *:first-child {
|
||||
margin-top: 0;
|
||||
}
|
||||
.plugin-details-content h1 {
|
||||
font-size: 28px;
|
||||
}
|
||||
.plugin-details-content h2 {
|
||||
font-size: 24px;
|
||||
}
|
||||
.plugin-details-content h3 {
|
||||
font-size: 20px;
|
||||
}
|
||||
.plugin-details-content h4 {
|
||||
font-size: 17px;
|
||||
}
|
||||
.plugin-details-content h1,
|
||||
.plugin-details-content h2 {
|
||||
padding-bottom: 10px;
|
||||
border-bottom: 1px solid #ccc;
|
||||
}
|
||||
.plugin-details-content ul,
|
||||
.plugin-details-content ol {
|
||||
padding-left: 20px;
|
||||
}
|
||||
.plugin-details-content pre {
|
||||
display: block;
|
||||
padding: 10px 10px 10px 20px;
|
||||
font-size: 13px;
|
||||
word-break: break-all;
|
||||
word-wrap: break-word;
|
||||
color: #fff;
|
||||
background-color: #333;
|
||||
margin-top: 10px;
|
||||
margin-bottom: 20px;
|
||||
margin-left: -20px;
|
||||
margin-right: -20px;
|
||||
}
|
||||
.plugin-details-content pre code {
|
||||
padding: 0;
|
||||
font-size: inherit;
|
||||
color: inherit;
|
||||
white-space: pre-wrap;
|
||||
background-color: transparent;
|
||||
border-radius: 0;
|
||||
}
|
||||
.plugin-details-content ul pre,
|
||||
.plugin-details-content ol pre {
|
||||
margin-left: -40px;
|
||||
padding-left: 40px;
|
||||
}
|
||||
|
|
@ -196,7 +196,7 @@
|
|||
display: block;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
background-image: url(../../../../system/assets/ui/images/loader-transparent.svg);
|
||||
background-image: url('../../../../system/assets/ui/images/loader-transparent.svg');
|
||||
background-size: 24px 24px;
|
||||
background-position: 50% 50%;
|
||||
-webkit-animation: spin 1s linear infinite;
|
||||
|
|
|
|||
|
|
@ -1,3 +1,6 @@
|
|||
.important-update-label {
|
||||
margin: 7px 0;
|
||||
}
|
||||
.control-updatelist {
|
||||
border: 1px solid #ccc;
|
||||
margin-bottom: 20px;
|
||||
|
|
@ -8,11 +11,11 @@
|
|||
.control-updatelist .update-item .item-header {
|
||||
background-color: #f5f5f5;
|
||||
border-bottom: 1px solid #ccc;
|
||||
padding: 15px 10px;
|
||||
padding: 0 10px;
|
||||
}
|
||||
.control-updatelist .update-item .item-header h5 {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
padding: 15px 0;
|
||||
text-transform: uppercase;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
|
@ -26,10 +29,13 @@
|
|||
line-height: 13px;
|
||||
margin-right: 5px;
|
||||
}
|
||||
.control-updatelist .update-item .item-header .important-update {
|
||||
padding: 7px 0 0 0;
|
||||
float: right;
|
||||
}
|
||||
.control-updatelist .update-item dl {
|
||||
padding: 10px;
|
||||
margin-bottom: 0;
|
||||
font-size: 12px;
|
||||
}
|
||||
.control-updatelist .update-item dl:before,
|
||||
.control-updatelist .update-item dl:after {
|
||||
|
|
@ -43,12 +49,37 @@
|
|||
.control-updatelist .update-item dl dd {
|
||||
float: left;
|
||||
padding: 5px 0;
|
||||
line-height: 20px;
|
||||
}
|
||||
.control-updatelist .update-item dl dt.text-muted,
|
||||
.control-updatelist .update-item dl dd.text-muted {
|
||||
color: #999 !important;
|
||||
}
|
||||
.control-updatelist .update-item dl dt {
|
||||
width: 15%;
|
||||
clear: left;
|
||||
font-size: 14px;
|
||||
font-weight: 400;
|
||||
color: #2b3e50;
|
||||
}
|
||||
.control-updatelist .update-item dl dd {
|
||||
width: 85%;
|
||||
font-size: 12px;
|
||||
color: #455152;
|
||||
}
|
||||
.control-updatelist .update-item dl .important-update-label {
|
||||
position: relative;
|
||||
top: -1px;
|
||||
background-color: #ab2a1c;
|
||||
color: #fff;
|
||||
display: inline-block;
|
||||
padding: .2em .6em .3em;
|
||||
font-size: 75%;
|
||||
line-height: 1;
|
||||
text-align: center;
|
||||
white-space: nowrap;
|
||||
vertical-align: baseline;
|
||||
border-radius: .25em;
|
||||
}
|
||||
.control-updatelist .update-item:last-child {
|
||||
border-bottom: none;
|
||||
|
|
@ -56,6 +87,27 @@
|
|||
.control-updatelist .update-item.item-danger .item-header {
|
||||
background-color: #f2dede;
|
||||
}
|
||||
.control-updatelist .update-item.item-danger dl {
|
||||
.control-updatelist .update-item.item-danger .item-header h5,
|
||||
.control-updatelist .update-item.item-danger .item-header i,
|
||||
.control-updatelist .update-item.item-danger .item-header {
|
||||
color: #a94442;
|
||||
}
|
||||
.control-updatelist .update-item.item-success .item-header {
|
||||
background-color: #dff0d8;
|
||||
}
|
||||
.control-updatelist .update-item.item-success .item-header h5,
|
||||
.control-updatelist .update-item.item-success .item-header i,
|
||||
.control-updatelist .update-item.item-success .item-header {
|
||||
color: #3c763d;
|
||||
}
|
||||
.control-updatelist .update-item.item-muted {
|
||||
border-bottom: none;
|
||||
}
|
||||
.control-updatelist .update-item.item-muted .item-header h5,
|
||||
.control-updatelist .update-item.item-muted .item-header i,
|
||||
.control-updatelist .update-item.item-muted .item-header {
|
||||
color: rgba(0, 0, 0, 0.35);
|
||||
}
|
||||
.control-updatelist .update-item.item-muted dl {
|
||||
display: none;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,6 +19,55 @@
|
|||
this.updateSteps = null
|
||||
}
|
||||
|
||||
UpdateProcess.prototype.check = function() {
|
||||
var $form = $('#updateForm'),
|
||||
self = this
|
||||
|
||||
$form.request('onCheckForUpdates').done(function() {
|
||||
self.evalConfirmedUpdates()
|
||||
})
|
||||
|
||||
$form.on('change', '[data-important-update-select]', function() {
|
||||
var $el = $(this),
|
||||
selectedValue = $el.val(),
|
||||
$updateItem = $el.closest('.update-item')
|
||||
|
||||
$updateItem.removeClass('item-danger item-muted item-success')
|
||||
|
||||
if (selectedValue == 'confirm') {
|
||||
$updateItem.addClass('item-success')
|
||||
}
|
||||
else if (selectedValue == 'ignore' || selectedValue == 'skip') {
|
||||
$updateItem.addClass('item-muted')
|
||||
}
|
||||
else {
|
||||
$updateItem.addClass('item-danger')
|
||||
}
|
||||
|
||||
self.evalConfirmedUpdates()
|
||||
})
|
||||
}
|
||||
|
||||
UpdateProcess.prototype.evalConfirmedUpdates = function() {
|
||||
var $form = $('#updateForm'),
|
||||
hasConfirmed = false
|
||||
|
||||
$('[data-important-update-select]', $form).each(function() {
|
||||
if ($(this).val() == '') {
|
||||
hasConfirmed = true
|
||||
}
|
||||
})
|
||||
|
||||
if (hasConfirmed) {
|
||||
$('#updateListUpdateButton').prop('disabled', true)
|
||||
$('#updateListImportantLabel').show()
|
||||
}
|
||||
else {
|
||||
$('#updateListUpdateButton').prop('disabled', false)
|
||||
$('#updateListImportantLabel').hide()
|
||||
}
|
||||
}
|
||||
|
||||
UpdateProcess.prototype.execute = function(steps) {
|
||||
this.updateSteps = steps
|
||||
this.runUpdate()
|
||||
|
|
|
|||
|
|
@ -0,0 +1,51 @@
|
|||
@import "../../../../backend/assets/less/core/boot.less";
|
||||
|
||||
@padding-standard: 20px;
|
||||
@padding-container: 0;
|
||||
|
||||
.plugin-details-content {
|
||||
padding: 0 @padding-container;
|
||||
|
||||
> *:first-child {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
h1 { font-size: @font-size-h1 - 8; }
|
||||
h2 { font-size: @font-size-h2 - 6; }
|
||||
h3 { font-size: @font-size-h3 - 4; }
|
||||
h4 { font-size: @font-size-h4 - 1; }
|
||||
|
||||
h1, h2 { padding-bottom: 10px; border-bottom: 1px solid #ccc; }
|
||||
|
||||
ul, ol {
|
||||
padding-left: @padding-standard;
|
||||
}
|
||||
|
||||
pre {
|
||||
display: block;
|
||||
padding: 10px 10px 10px (@padding-standard + @padding-container);
|
||||
font-size: 13px;
|
||||
word-break: break-all;
|
||||
word-wrap: break-word;
|
||||
color: #fff;
|
||||
background-color: #333;
|
||||
margin-top: 10px;
|
||||
margin-bottom: 20px;
|
||||
margin-left: -(@padding-standard + @padding-container);
|
||||
margin-right: -(@padding-standard + @padding-container);
|
||||
code {
|
||||
padding: 0;
|
||||
font-size: inherit;
|
||||
color: inherit;
|
||||
white-space: pre-wrap;
|
||||
background-color: transparent;
|
||||
border-radius: 0;
|
||||
}
|
||||
}
|
||||
|
||||
ul pre,
|
||||
ol pre {
|
||||
margin-left: -((@padding-standard * 2) + @padding-container);
|
||||
padding-left: ((@padding-standard * 2) + @padding-container);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,5 +1,9 @@
|
|||
@import "../../../../backend/assets/less/core/boot.less";
|
||||
|
||||
.important-update-label {
|
||||
margin: 7px 0;
|
||||
}
|
||||
|
||||
.control-updatelist {
|
||||
|
||||
border: 1px solid #ccc;
|
||||
|
|
@ -12,11 +16,11 @@
|
|||
.item-header {
|
||||
background-color: #f5f5f5;
|
||||
border-bottom: 1px solid #ccc;
|
||||
padding: 15px 10px;
|
||||
padding: 0 10px;
|
||||
|
||||
h5 {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
padding: 15px 0;
|
||||
text-transform: uppercase;
|
||||
font-size: 13px;
|
||||
|
||||
|
|
@ -32,23 +36,53 @@
|
|||
margin-right: 5px;
|
||||
}
|
||||
}
|
||||
|
||||
.important-update {
|
||||
padding: 7px 0 0 0;
|
||||
float: right;
|
||||
}
|
||||
}
|
||||
|
||||
dl {
|
||||
padding: 10px;
|
||||
margin-bottom: 0;
|
||||
font-size: 12px;
|
||||
.clearfix;
|
||||
|
||||
dt, dd {
|
||||
float: left;
|
||||
padding: 5px 0;
|
||||
line-height: 20px;
|
||||
&.text-muted {
|
||||
color: #999 !important;
|
||||
}
|
||||
}
|
||||
|
||||
dt {
|
||||
width: 15%;
|
||||
clear: left;
|
||||
font-size: 14px;
|
||||
font-weight: 400;
|
||||
color: #2b3e50;
|
||||
}
|
||||
dd {
|
||||
width: 85%;
|
||||
font-size: 12px;
|
||||
color: #455152;
|
||||
}
|
||||
|
||||
.important-update-label {
|
||||
position: relative;
|
||||
top: -1px;
|
||||
background-color: #ab2a1c;
|
||||
color: #fff;
|
||||
display: inline-block;
|
||||
padding: .2em .6em .3em;
|
||||
font-size: 75%;
|
||||
line-height: 1;
|
||||
text-align: center;
|
||||
white-space: nowrap;
|
||||
vertical-align: baseline;
|
||||
border-radius: .25em;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -59,11 +93,28 @@
|
|||
&.item-danger {
|
||||
.item-header {
|
||||
background-color: @state-danger-bg;
|
||||
}
|
||||
dl {
|
||||
color: @state-danger-text;
|
||||
h5, i, & { color: @state-danger-text; }
|
||||
}
|
||||
}
|
||||
|
||||
&.item-success {
|
||||
.item-header {
|
||||
background-color: @state-success-bg;
|
||||
h5, i, & { color: @state-success-text; }
|
||||
}
|
||||
}
|
||||
|
||||
&.item-muted {
|
||||
border-bottom: none;
|
||||
|
||||
.item-header {
|
||||
h5, i, & { color: rgba(0,0,0,.35); }
|
||||
}
|
||||
dl {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -4,7 +4,6 @@ Scoreboard
|
|||
|
||||
# Example
|
||||
|
||||
|
||||
<script src="/assets/js/october.goalmeter.js"></script>
|
||||
<script src="/assets/js/vendor/raphael-min.js"></script>
|
||||
<script src="/assets/js/october.chartutils.js"></script>
|
||||
|
|
|
|||
|
|
@ -1,32 +1,159 @@
|
|||
# Tabs
|
||||
# Tab control
|
||||
|
||||
## Content tabs
|
||||
This plugin is a wrapper for the Twitter Bootstrap Tab component. It provides the following features:
|
||||
|
||||
Content tabs are heavier tabs designed for displaying content.
|
||||
- Adding tabs
|
||||
- Optional close icons with 2 states (modified / unmodified). The icon state can be changed by triggering the modified.oc.tab/unmodified.oc.tab events on any element within tab, or on the tab itself.
|
||||
- Removing tabs with the Close icon, or with triggering an event from inside a tab pane or tab. The removing can be canceled if the confirm.oc.tab event handler returns false.
|
||||
- Scrolling tabs if they do not fit the screen
|
||||
- Collapsible tabs
|
||||
|
||||
### Supported data attributes:
|
||||
|
||||
- data-control="tab" - creates the tab control from an element
|
||||
- data-closable - enables the Close Tab feature
|
||||
- data-pane-classes - a list of CSS classes to apply new pane elements
|
||||
|
||||
Example with data attributes (data-control="tab"):
|
||||
|
||||
<div class="control-tabs master" data-control="tab" data-closable>
|
||||
<ul class="nav nav-tabs">
|
||||
<li class="active"><a href="#home">Home</a></li>
|
||||
</ul>
|
||||
<div class="tab-content">
|
||||
<div class="tab-pane active">Home</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
### JavaScript API:
|
||||
|
||||
- $('#mytabs').ocTab({closable: true, closeConfirmation: 'Do you really want to close this tab? Unsaved data will be lost.'})
|
||||
- $('#mytabs').ocTab('addTab', 'Tab title', 'Tab content', identifier) - adds tab. The optional identifier parameter allows to associate a identifier with a tab. The identifier can be used with the goTo() method to find and open a tab by it's identifier.
|
||||
- $('#mytabs').ocTab('closeTab', '.nav-tabs > li.active', true) - closes a tab. The second argument can point to a tab or tab pane. The thrid argument determines whether the tab should be closed without the user confirmation. The default value is false.
|
||||
- $('.nav-tabs > li.active').trigger('close.oc.tab') - another way to close a tab. The event can be triggered on a tab, tab pane or any element inside a tab or tab pane.
|
||||
- $('#mytabs').ocTab('modifyTab', '.nav-tabs > li.active') - marks a tab as modified. Use the 'unmodifyTab' to mark a tab as unmodified.
|
||||
- $('.nav-tabs > li.active').trigger('modified.oc.tab') - another way to mark a tab as modified. The event can be triggered on a tab, tab pane or any element inside a tab or tab pane. Use the 'unmodified.oc.tab' to mark a tab as unmodified.
|
||||
- $('#mytabs').ocTab('goTo', 'someidentifier') - Finds a tab by it's identifier and opens it.
|
||||
- $('#mytabs').ocTab('goToPane', '.tab-content .tab-pane:first') - Opens a tab in context of it's content (pane element)
|
||||
|
||||
### Supported options:
|
||||
|
||||
- closable - adds the "close" icon to the tab and lets users to close tabs. Corresponds the data-closable attribute.
|
||||
- closeConfirmation - a confirmation to show when a user tries to close a modified tab. Corresponds the data-close-confirmation
|
||||
attribute. The confirmation is displayed only if the tab was modified.
|
||||
- slidable - allows the tabs to be switched with the swipe gesture on touch devices. Corresponds the data-slidable attribute.
|
||||
- paneClasses - a list of CSS classes to apply new pane elements. Corresponds to the data-pane-classes attribute.
|
||||
- maxTitleSymbols - the maximum number of characters in tab titles.
|
||||
- titleAsFileNames - treat tab titles as file names. In this mode only the file name part is displayed in the tab, and the directory part
|
||||
is hidden.
|
||||
|
||||
### Supported events:
|
||||
|
||||
- beforeClose.oc.tab - triggered on a tab pane element before tab is closed by the user. Call the event's
|
||||
preventDefault() method to cancel the action.
|
||||
- afterAllClosed.oc.tab - triggered after all tabs have been closed
|
||||
|
||||
# Example
|
||||
|
||||
<div class="control-tabs content-tabs" data-control="tab">
|
||||
<h5>Master</h5>
|
||||
|
||||
<div class="control-tabs master-tabs" data-control="tab">
|
||||
<ul class="nav nav-tabs">
|
||||
<li class="active"><a href="#tabOne">One</a></li>
|
||||
<li><a href="#tabTwo">Two</a></li>
|
||||
<li><a href="#tabThree">Three</a></li>
|
||||
<li class="active"><a href="#primaryTabOne">One</a></li>
|
||||
<li><a href="#primaryTabTwo">Two</a></li>
|
||||
<li><a href="#primaryTabThree">Three</a></li>
|
||||
</ul>
|
||||
<div class="tab-content">
|
||||
<div class="tab-pane active">
|
||||
<div class="padded-container">
|
||||
Tab one content
|
||||
</div>
|
||||
Tab one content
|
||||
</div>
|
||||
<div class="tab-pane">
|
||||
<div class="padded-container">
|
||||
Tab two content
|
||||
</div>
|
||||
Tab two content
|
||||
</div>
|
||||
<div class="tab-pane">
|
||||
<div class="padded-container">
|
||||
Tab three content
|
||||
</div>
|
||||
Tab three content
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<hr />
|
||||
|
||||
|
||||
|
||||
<h5>Primary</h5>
|
||||
|
||||
<div class="control-tabs primary-tabs" data-control="tab">
|
||||
<ul class="nav nav-tabs">
|
||||
<li class="active"><a href="#primaryTabOne">One</a></li>
|
||||
<li><a href="#primaryTabTwo">Two</a></li>
|
||||
<li><a href="#primaryTabThree">Three</a></li>
|
||||
</ul>
|
||||
<div class="tab-content">
|
||||
<div class="tab-pane active">
|
||||
Tab one content
|
||||
</div>
|
||||
<div class="tab-pane">
|
||||
Tab two content
|
||||
</div>
|
||||
<div class="tab-pane">
|
||||
Tab three content
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<hr />
|
||||
|
||||
|
||||
|
||||
<h5>Secondary</h5>
|
||||
|
||||
<div class="control-tabs secondary-tabs" data-control="tab">
|
||||
<ul class="nav nav-tabs">
|
||||
<li class="active"><a href="#secondaryTabOne">One</a></li>
|
||||
<li><a href="#secondaryTabTwo">Two</a></li>
|
||||
<li><a href="#secondaryTabThree">Three</a></li>
|
||||
</ul>
|
||||
<div class="tab-content">
|
||||
<div class="tab-pane active">
|
||||
Tab one content
|
||||
</div>
|
||||
<div class="tab-pane">
|
||||
Tab two content
|
||||
</div>
|
||||
<div class="tab-pane">
|
||||
Tab three content
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<hr />
|
||||
|
||||
|
||||
|
||||
<h5>Content</h5>
|
||||
|
||||
<div class="control-tabs content-tabs" data-control="tab">
|
||||
<ul class="nav nav-tabs">
|
||||
<li class="active"><a href="#contentTabOne">One</a></li>
|
||||
<li><a href="#contentTabTwo">Two</a></li>
|
||||
<li><a href="#contentTabThree">Three</a></li>
|
||||
</ul>
|
||||
<div class="tab-content">
|
||||
<div class="tab-pane active">
|
||||
Tab one content
|
||||
</div>
|
||||
<div class="tab-pane">
|
||||
Tab two content
|
||||
</div>
|
||||
<div class="tab-pane">
|
||||
Tab three content
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 1.6 KiB |
|
|
@ -1,71 +1,13 @@
|
|||
/*
|
||||
=require ../vendor/bootstrap/js/transition.js
|
||||
=require ../vendor/bootstrap/js/tab.js
|
||||
=require toolbar.js
|
||||
*/
|
||||
|
||||
/*
|
||||
* Tab control.
|
||||
* Tab control
|
||||
*
|
||||
* This plugin is a wrapper for the Twitter Bootstrap Tab component. It provides the following features:
|
||||
* - Adding tabs
|
||||
* - Optional close icons with 2 states (modified / unmodified). The icon state can be changed by
|
||||
* triggering the modified.oc.tab/unmodified.oc.tab events on any element within tab, or on the tab itself.
|
||||
* - Removing tabs with the Close icon, or with triggering an event from inside a tab pane or tab.
|
||||
* The removing can be canceled if the confirm.oc.tab event handler returns false.
|
||||
* - Scrolling tabs if they do not fit the screen
|
||||
* - Collapsible tabs
|
||||
*
|
||||
* Data attributes:
|
||||
* - data-control="tab" - creates the tab control from an element
|
||||
* - data-closable - enables the Close Tab feature
|
||||
* - data-pane-classes - a list of CSS classes to apply new pane elements
|
||||
*
|
||||
* Example with data attributes (data-control="tab"):
|
||||
*
|
||||
* <div class="control-tabs master" data-control="tab" data-closable>
|
||||
* <ul class="nav nav-tabs">
|
||||
* <li class="active"><a href="#home">Home</a></li>
|
||||
* </ul>
|
||||
* <div class="tab-content">
|
||||
* <div class="tab-pane active">Home</div>
|
||||
* </div>
|
||||
* </div>
|
||||
*
|
||||
* JavaScript methods:
|
||||
* - $('#mytabs').ocTab({closable: true, closeConfirmation: 'Do you really want to close this tab? Unsaved data will be lost.'})
|
||||
* - $('#mytabs').ocTab('addTab', 'Tab title', 'Tab content', identifier) - adds tab. The optional identifier parameter allows to
|
||||
associate a identifier with a tab. The identifier can be used with the goTo() method to find and open a tab by it's identifier.
|
||||
* - $('#mytabs').ocTab('closeTab', '.nav-tabs > li.active', true) - closes a tab. The second argument can point to a tab or tab pane.
|
||||
The thrid argument determines whether the tab should be closed without the user confirmation. The default value is false.
|
||||
* - $('.nav-tabs > li.active').trigger('close.oc.tab') - another way to close a tab. The event can be triggered on a tab, tab pane
|
||||
* or any element inside a tab or tab pane.
|
||||
* - $('#mytabs').ocTab('modifyTab', '.nav-tabs > li.active') - marks a tab as modified. Use the 'unmodifyTab' to mark a tab as unmodified.
|
||||
* - $('.nav-tabs > li.active').trigger('modified.oc.tab') - another way to mark a tab as modified. The event can be triggered on a tab, tab pane
|
||||
* or any element inside a tab or tab pane. Use the 'unmodified.oc.tab' to mark a tab as unmodified.
|
||||
* - $('#mytabs').ocTab('goTo', 'someidentifier') - Finds a tab by it's identifier and opens it.
|
||||
* - $('#mytabs').ocTab('goToPane', '.tab-content .tab-pane:first') - Opens a tab in context of it's content (pane element)
|
||||
*
|
||||
* Supported options:
|
||||
* - closable - adds the "close" icon to the tab and lets users to close tabs. Corresponds the data-closable attribute.
|
||||
* - closeConfirmation - a confirmation to show when a user tries to close a modified tab. Corresponds the data-close-confirmation
|
||||
* attribute. The confirmation is displayed only if the tab was modified.
|
||||
* - slidable - allows the tabs to be switched with the swipe gesture on touch devices. Corresponds the data-slidable attribute.
|
||||
* - paneClasses - a list of CSS classes to apply new pane elements. Corresponds to the data-pane-classes attribute.
|
||||
* - maxTitleSymbols - the maximum number of characters in tab titles.
|
||||
* - titleAsFileNames - treat tab titles as file names. In this mode only the file name part is displayed in the tab, and the directory part
|
||||
* is hidden.
|
||||
*
|
||||
* Events:
|
||||
* - beforeClose.oc.tab - triggered on a tab pane element before tab is closed by the user. Call the event's
|
||||
* preventDefault() method to cancel the action.
|
||||
* - afterAllClosed.oc.tab - triggered after all tabs have been closed
|
||||
*
|
||||
* Dependences:
|
||||
* - DragScroll (october.dragscroll.js)
|
||||
* - Toolbar (october.toolbar.js)
|
||||
* - Touchwipe (jquery.touchwipe.min.js)
|
||||
* - Documentation: ../docs/tab.md
|
||||
*/
|
||||
|
||||
+function ($) { "use strict";
|
||||
|
||||
var Tab = function (element, options) {
|
||||
|
|
|
|||
|
|
@ -150,6 +150,12 @@ table.table.data {
|
|||
}
|
||||
}
|
||||
|
||||
tr.frozen {
|
||||
td, th, td a, th a {
|
||||
color: #337ab7;
|
||||
}
|
||||
}
|
||||
|
||||
tr.processing {
|
||||
td, th, td a, th a {
|
||||
color: #666666;
|
||||
|
|
|
|||
|
|
@ -46,6 +46,7 @@
|
|||
@nav-pills-active-link-hover-bg: @component-active-bg;
|
||||
@nav-pills-active-link-hover-color: @component-active-color;
|
||||
|
||||
@tab-image-path: @image-path;
|
||||
|
||||
.control-tabs {
|
||||
position: relative;
|
||||
|
|
@ -206,7 +207,12 @@
|
|||
}
|
||||
}
|
||||
|
||||
&.master {
|
||||
//
|
||||
// Master tabs
|
||||
//
|
||||
|
||||
&.master, // Deprecated
|
||||
&.master-tabs {
|
||||
> ul.nav-tabs, > div > ul.nav-tabs, > div > div > ul.nav-tabs {
|
||||
> li {
|
||||
a {
|
||||
|
|
@ -224,13 +230,18 @@
|
|||
}
|
||||
}
|
||||
|
||||
&.primary {
|
||||
//
|
||||
// Primary tabs
|
||||
//
|
||||
|
||||
&.primary, // Deprecated
|
||||
&.primary-tabs {
|
||||
margin-bottom: 5px;
|
||||
|
||||
> ul.nav-tabs, > div > ul.nav-tabs, > div > div > ul.nav-tabs {
|
||||
position: relative;
|
||||
margin-left: -20px;
|
||||
margin-right: -20px;
|
||||
margin-left: 0;
|
||||
margin-right: 0;
|
||||
|
||||
&:before {
|
||||
position: absolute;
|
||||
|
|
@ -250,9 +261,9 @@
|
|||
|
||||
&:first-child {
|
||||
margin-left: 0;
|
||||
padding-left: 15px!important;
|
||||
padding-left: 15px !important;
|
||||
}
|
||||
|
||||
|
||||
a {
|
||||
font-size: 12px;
|
||||
padding-bottom: 3px;
|
||||
|
|
@ -274,7 +285,7 @@
|
|||
&:before, &:after {
|
||||
content: ' ';
|
||||
position: absolute;
|
||||
background: transparent url(../images/primary-tab-shape.png?v2) no-repeat left -31px;
|
||||
background: transparent url('@{tab-image-path}/primary-tab-shape.png') no-repeat left -31px;
|
||||
width: 16px;
|
||||
height: 26px;
|
||||
display: block;
|
||||
|
|
@ -337,16 +348,21 @@
|
|||
> div.tab-content {
|
||||
}
|
||||
|
||||
// Tabs to sit in by the standard offset (0px)
|
||||
&.tabs-offset {
|
||||
// Tab divider to sit inset the standard padding (20px)
|
||||
&.tabs-inset {
|
||||
> ul.nav-tabs, > div > ul.nav-tabs, > div > div > ul.nav-tabs {
|
||||
margin-left: 0;
|
||||
margin-right: 0;
|
||||
margin-left: -20px;
|
||||
margin-right: -20px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.secondary {
|
||||
//
|
||||
// Secondary tabs
|
||||
//
|
||||
|
||||
&.secondary, // Deprecated
|
||||
&.secondary-tabs {
|
||||
> ul.nav-tabs, > div > ul.nav-tabs, > div > div > ul.nav-tabs {
|
||||
> li {
|
||||
padding-right: 10px;
|
||||
|
|
@ -368,6 +384,10 @@
|
|||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Content tabs
|
||||
//
|
||||
|
||||
&.content-tabs {
|
||||
|
||||
> ul.nav-tabs {
|
||||
|
|
@ -425,6 +445,17 @@
|
|||
}
|
||||
}
|
||||
|
||||
// Tab divider to sit inset the standard padding (20px)
|
||||
&.tabs-inset {
|
||||
> ul.nav-tabs, > div > ul.nav-tabs, > div > div > ul.nav-tabs {
|
||||
margin-left: -20px;
|
||||
margin-right: -20px;
|
||||
li:first-child {
|
||||
margin-left: 20px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Tabs to sit in by the standard offset (20px)
|
||||
&.tabs-offset {
|
||||
> ul.nav-tabs {
|
||||
|
|
|
|||
|
|
@ -1319,7 +1319,7 @@ S2.define('select2/selection/base',[
|
|||
});
|
||||
|
||||
this.$selection.on('blur', function (evt) {
|
||||
self.trigger('blur', evt);
|
||||
self._handleBlur(evt);
|
||||
});
|
||||
|
||||
this.$selection.on('keydown', function (evt) {
|
||||
|
|
@ -1366,6 +1366,24 @@ S2.define('select2/selection/base',[
|
|||
});
|
||||
};
|
||||
|
||||
BaseSelection.prototype._handleBlur = function (evt) {
|
||||
var self = this;
|
||||
|
||||
// This needs to be delayed as the actve element is the body when the tab
|
||||
// key is pressed, possibly along with others.
|
||||
window.setTimeout(function () {
|
||||
// Don't trigger `blur` if the focus is still in the selection
|
||||
if (
|
||||
(document.activeElement == self.$selection[0]) ||
|
||||
($.contains(self.$selection[0], document.activeElement))
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
self.trigger('blur', evt);
|
||||
}, 1);
|
||||
};
|
||||
|
||||
BaseSelection.prototype._attachCloseHandler = function (container) {
|
||||
var self = this;
|
||||
|
||||
|
|
@ -1475,11 +1493,11 @@ S2.define('select2/selection/single',[
|
|||
this.$selection.find('.select2-selection__rendered').empty();
|
||||
};
|
||||
|
||||
SingleSelection.prototype.display = function (data) {
|
||||
SingleSelection.prototype.display = function (data, container) {
|
||||
var template = this.options.get('templateSelection');
|
||||
var escapeMarkup = this.options.get('escapeMarkup');
|
||||
|
||||
return escapeMarkup(template(data));
|
||||
return escapeMarkup(template(data, container));
|
||||
};
|
||||
|
||||
SingleSelection.prototype.selectionContainer = function () {
|
||||
|
|
@ -1494,9 +1512,9 @@ S2.define('select2/selection/single',[
|
|||
|
||||
var selection = data[0];
|
||||
|
||||
var formatted = this.display(selection);
|
||||
|
||||
var $rendered = this.$selection.find('.select2-selection__rendered');
|
||||
var formatted = this.display(selection, $rendered);
|
||||
|
||||
$rendered.empty().append(formatted);
|
||||
$rendered.prop('title', selection.title || selection.text);
|
||||
};
|
||||
|
|
@ -1556,11 +1574,11 @@ S2.define('select2/selection/multiple',[
|
|||
this.$selection.find('.select2-selection__rendered').empty();
|
||||
};
|
||||
|
||||
MultipleSelection.prototype.display = function (data) {
|
||||
MultipleSelection.prototype.display = function (data, container) {
|
||||
var template = this.options.get('templateSelection');
|
||||
var escapeMarkup = this.options.get('escapeMarkup');
|
||||
|
||||
return escapeMarkup(template(data));
|
||||
return escapeMarkup(template(data, container));
|
||||
};
|
||||
|
||||
MultipleSelection.prototype.selectionContainer = function () {
|
||||
|
|
@ -1587,8 +1605,8 @@ S2.define('select2/selection/multiple',[
|
|||
for (var d = 0; d < data.length; d++) {
|
||||
var selection = data[d];
|
||||
|
||||
var formatted = this.display(selection);
|
||||
var $selection = this.selectionContainer();
|
||||
var formatted = this.display(selection, $selection);
|
||||
|
||||
$selection.append(formatted);
|
||||
$selection.prop('title', selection.title || selection.text);
|
||||
|
|
@ -1777,6 +1795,8 @@ S2.define('select2/selection/search',[
|
|||
|
||||
var $rendered = decorated.call(this);
|
||||
|
||||
this._transferTabIndex();
|
||||
|
||||
return $rendered;
|
||||
};
|
||||
|
||||
|
|
@ -1786,32 +1806,34 @@ S2.define('select2/selection/search',[
|
|||
decorated.call(this, container, $container);
|
||||
|
||||
container.on('open', function () {
|
||||
self.$search.attr('tabindex', 0);
|
||||
|
||||
self.$search.focus();
|
||||
self.$search.trigger('focus');
|
||||
});
|
||||
|
||||
container.on('close', function () {
|
||||
self.$search.attr('tabindex', -1);
|
||||
|
||||
self.$search.val('');
|
||||
self.$search.focus();
|
||||
self.$search.trigger('focus');
|
||||
});
|
||||
|
||||
container.on('enable', function () {
|
||||
self.$search.prop('disabled', false);
|
||||
|
||||
self._transferTabIndex();
|
||||
});
|
||||
|
||||
container.on('disable', function () {
|
||||
self.$search.prop('disabled', true);
|
||||
});
|
||||
|
||||
container.on('focus', function (evt) {
|
||||
self.$search.trigger('focus');
|
||||
});
|
||||
|
||||
this.$selection.on('focusin', '.select2-search--inline', function (evt) {
|
||||
self.trigger('focus', evt);
|
||||
});
|
||||
|
||||
this.$selection.on('focusout', '.select2-search--inline', function (evt) {
|
||||
self.trigger('blur', evt);
|
||||
self._handleBlur(evt);
|
||||
});
|
||||
|
||||
this.$selection.on('keydown', '.select2-search--inline', function (evt) {
|
||||
|
|
@ -1819,7 +1841,7 @@ S2.define('select2/selection/search',[
|
|||
|
||||
self.trigger('keypress', evt);
|
||||
|
||||
self._keyUpPrevented = evt.isDefaultPrevented();
|
||||
self._keyUpPrevented = false; //evt.isDefaultPrevented();
|
||||
|
||||
var key = evt.which;
|
||||
|
||||
|
|
@ -1847,15 +1869,41 @@ S2.define('select2/selection/search',[
|
|||
|
||||
this.$selection.on('keyup.search input', '.select2-search--inline',
|
||||
function (evt) {
|
||||
var key = evt.which;
|
||||
|
||||
// We can freely ignore events from modifier keys
|
||||
if (key == KEYS.SHIFT || key == KEYS.CTRL || key == KEYS.ALT) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Tabbing will be handled during the `keydown` phase
|
||||
if (key == KEYS.TAB) {
|
||||
return;
|
||||
}
|
||||
|
||||
self.handleSearch(evt);
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* This method will transfer the tabindex attribute from the rendered
|
||||
* selection to the search box. This allows for the search box to be used as
|
||||
* the primary focus instead of the selection container.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
Search.prototype._transferTabIndex = function (decorated) {
|
||||
this.$search.attr('tabindex', this.$selection.attr('tabindex'));
|
||||
this.$selection.attr('tabindex', '-1');
|
||||
};
|
||||
|
||||
Search.prototype.createPlaceholder = function (decorated, placeholder) {
|
||||
this.$search.attr('placeholder', placeholder.text);
|
||||
};
|
||||
|
||||
Search.prototype.update = function (decorated, data) {
|
||||
var searchHadFocus = this.$search[0] == document.activeElement;
|
||||
|
||||
this.$search.attr('placeholder', '');
|
||||
|
||||
decorated.call(this, data);
|
||||
|
|
@ -1864,6 +1912,9 @@ S2.define('select2/selection/search',[
|
|||
.append(this.$searchContainer);
|
||||
|
||||
this.resizeSearch();
|
||||
if (searchHadFocus) {
|
||||
this.$search.focus();
|
||||
}
|
||||
};
|
||||
|
||||
Search.prototype.handleSearch = function () {
|
||||
|
|
@ -1948,7 +1999,7 @@ S2.define('select2/selection/eventRelay',[
|
|||
return;
|
||||
}
|
||||
|
||||
params.prevented = evt.isDefaultPrevented();
|
||||
params.prevented = false; //evt.isDefaultPrevented();
|
||||
});
|
||||
};
|
||||
|
||||
|
|
@ -3259,7 +3310,7 @@ S2.define('select2/data/ajax',[
|
|||
this.processResults = this.ajaxOptions.processResults;
|
||||
}
|
||||
|
||||
ArrayAdapter.__super__.constructor.call(this, $element, options);
|
||||
AjaxAdapter.__super__.constructor.call(this, $element, options);
|
||||
}
|
||||
|
||||
Utils.Extend(AjaxAdapter, ArrayAdapter);
|
||||
|
|
@ -3723,7 +3774,7 @@ S2.define('select2/dropdown/search',[
|
|||
this.$search.on('keydown', function (evt) {
|
||||
self.trigger('keypress', evt);
|
||||
|
||||
self._keyUpPrevented = evt.isDefaultPrevented();
|
||||
self._keyUpPrevented = false; //evt.isDefaultPrevented();
|
||||
});
|
||||
|
||||
// Workaround for browsers which do not support the `input` event
|
||||
|
|
@ -4868,8 +4919,8 @@ S2.define('select2/core',[
|
|||
|
||||
// Hide the original select
|
||||
$element.addClass('select2-hidden-accessible');
|
||||
$element.attr('aria-hidden', 'true');
|
||||
|
||||
$element.attr('aria-hidden', 'true');
|
||||
|
||||
// Synchronize any monitored attributes
|
||||
this._syncAttributes();
|
||||
|
||||
|
|
@ -5004,12 +5055,16 @@ S2.define('select2/core',[
|
|||
|
||||
Select2.prototype._registerSelectionEvents = function () {
|
||||
var self = this;
|
||||
var nonRelayEvents = ['toggle'];
|
||||
var nonRelayEvents = ['toggle', 'focus'];
|
||||
|
||||
this.selection.on('toggle', function () {
|
||||
self.toggleDropdown();
|
||||
});
|
||||
|
||||
this.selection.on('focus', function (params) {
|
||||
self.focus(params);
|
||||
});
|
||||
|
||||
this.selection.on('*', function (name, params) {
|
||||
if ($.inArray(name, nonRelayEvents) !== -1) {
|
||||
return;
|
||||
|
|
@ -5054,10 +5109,6 @@ S2.define('select2/core',[
|
|||
self.$container.addClass('select2-container--disabled');
|
||||
});
|
||||
|
||||
this.on('focus', function () {
|
||||
self.$container.addClass('select2-container--focus');
|
||||
});
|
||||
|
||||
this.on('blur', function () {
|
||||
self.$container.removeClass('select2-container--focus');
|
||||
});
|
||||
|
|
@ -5088,7 +5139,12 @@ S2.define('select2/core',[
|
|||
var key = evt.which;
|
||||
|
||||
if (self.isOpen()) {
|
||||
if (key === KEYS.ENTER) {
|
||||
if (key === KEYS.ESC || key === KEYS.TAB ||
|
||||
(key === KEYS.UP && evt.altKey)) {
|
||||
self.close();
|
||||
|
||||
evt.preventDefault();
|
||||
} else if (key === KEYS.ENTER) {
|
||||
self.trigger('results:select');
|
||||
|
||||
evt.preventDefault();
|
||||
|
|
@ -5103,15 +5159,11 @@ S2.define('select2/core',[
|
|||
} else if (key === KEYS.DOWN) {
|
||||
self.trigger('results:next');
|
||||
|
||||
evt.preventDefault();
|
||||
} else if (key === KEYS.ESC || key === KEYS.TAB) {
|
||||
self.close();
|
||||
|
||||
evt.preventDefault();
|
||||
}
|
||||
} else {
|
||||
if (key === KEYS.ENTER || key === KEYS.SPACE ||
|
||||
((key === KEYS.DOWN || key === KEYS.UP) && evt.altKey)) {
|
||||
(key === KEYS.DOWN && evt.altKey)) {
|
||||
self.open();
|
||||
|
||||
evt.preventDefault();
|
||||
|
|
@ -5201,6 +5253,20 @@ S2.define('select2/core',[
|
|||
return this.$container.hasClass('select2-container--open');
|
||||
};
|
||||
|
||||
Select2.prototype.hasFocus = function () {
|
||||
return this.$container.hasClass('select2-container--focus');
|
||||
};
|
||||
|
||||
Select2.prototype.focus = function (data) {
|
||||
// No need to re-trigger focus events if we are already focused
|
||||
if (this.hasFocus()) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.$container.addClass('select2-container--focus');
|
||||
this.trigger('focus');
|
||||
};
|
||||
|
||||
Select2.prototype.enable = function (args) {
|
||||
if (this.options.get('debug') && window.console && console.warn) {
|
||||
console.warn(
|
||||
|
|
@ -5281,7 +5347,7 @@ S2.define('select2/core',[
|
|||
this.$element.attr('tabindex', this.$element.data('old-tabindex'));
|
||||
|
||||
this.$element.removeClass('select2-hidden-accessible');
|
||||
this.$element.attr('aria-hidden', 'false');
|
||||
this.$element.attr('aria-hidden', 'false');
|
||||
this.$element.removeData('select2');
|
||||
|
||||
this.dataAdapter.destroy();
|
||||
|
|
@ -5385,7 +5451,7 @@ S2.define('select2/compat/containerCss',[
|
|||
containerCssAdapter = containerCssAdapter || _containerAdapter;
|
||||
|
||||
if (containerCssClass.indexOf(':all:') !== -1) {
|
||||
containerCssClass = containerCssClass.replace(':all', '');
|
||||
containerCssClass = containerCssClass.replace(':all:', '');
|
||||
|
||||
var _cssAdapter = containerCssAdapter;
|
||||
|
||||
|
|
@ -5442,7 +5508,7 @@ S2.define('select2/compat/dropdownCss',[
|
|||
dropdownCssAdapter = dropdownCssAdapter || _dropdownAdapter;
|
||||
|
||||
if (dropdownCssClass.indexOf(':all:') !== -1) {
|
||||
dropdownCssClass = dropdownCssClass.replace(':all', '');
|
||||
dropdownCssClass = dropdownCssClass.replace(':all:', '');
|
||||
|
||||
var _cssAdapter = dropdownCssAdapter;
|
||||
|
||||
|
|
@ -6111,4 +6177,4 @@ S2.define('jquery.select2',[
|
|||
|
||||
// Return the Select2 instance for anyone who is importing it.
|
||||
return select2;
|
||||
}));
|
||||
}));
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -209,6 +209,7 @@ class UpdateManager
|
|||
$versions = $installed->lists('version', 'code');
|
||||
$names = $installed->lists('name', 'code');
|
||||
$icons = $installed->lists('icon', 'code');
|
||||
$frozen = $installed->lists('is_frozen', 'code');
|
||||
$build = Parameters::get('system::core.build');
|
||||
|
||||
$params = [
|
||||
|
|
@ -241,7 +242,17 @@ class UpdateManager
|
|||
$info['name'] = isset($names[$code]) ? $names[$code] : $code;
|
||||
$info['old_version'] = isset($versions[$code]) ? $versions[$code] : false;
|
||||
$info['icon'] = isset($icons[$code]) ? $icons[$code] : false;
|
||||
$plugins[$code] = $info;
|
||||
|
||||
/*
|
||||
* If plugin has updates frozen, do not add it to the list
|
||||
* and discount an update unit.
|
||||
*/
|
||||
if (isset($frozen[$code]) && $frozen[$code]) {
|
||||
$updateCount = max(0, --$updateCount);
|
||||
}
|
||||
else {
|
||||
$plugins[$code] = $info;
|
||||
}
|
||||
}
|
||||
$result['plugins'] = $plugins;
|
||||
|
||||
|
|
|
|||
|
|
@ -2,10 +2,12 @@
|
|||
|
||||
use Str;
|
||||
use Lang;
|
||||
use Html;
|
||||
use File;
|
||||
use Flash;
|
||||
use Config;
|
||||
use Backend;
|
||||
use Markdown;
|
||||
use Redirect;
|
||||
use Response;
|
||||
use BackendMenu;
|
||||
|
|
@ -98,6 +100,71 @@ class Updates extends Controller
|
|||
}
|
||||
}
|
||||
|
||||
public function details($urlCode = null, $tab = null)
|
||||
{
|
||||
try {
|
||||
$this->pageTitle = 'Plugin details';
|
||||
$this->addCss('/modules/system/assets/css/updates/details.css', 'core');
|
||||
|
||||
$readmeFiles = ['README.md', 'readme.md'];
|
||||
$upgradeFiles = ['UPGRADE.md', 'upgrade.md'];
|
||||
|
||||
$upgrades = $readme = $name = null;
|
||||
$code = str_replace('-', '.', $urlCode);
|
||||
|
||||
/*
|
||||
* Lookup the plugin
|
||||
*/
|
||||
$manager = PluginManager::instance();
|
||||
$plugin = $manager->findByIdentifier($code);
|
||||
$code = $manager->getIdentifier($plugin);
|
||||
$path = $manager->getPluginPath($plugin);
|
||||
|
||||
if ($path && $plugin) {
|
||||
$details = $plugin->pluginDetails();
|
||||
$readme = $this->getPluginMarkdownFile($path, $readmeFiles);
|
||||
$upgrades = $this->getPluginMarkdownFile($path, $upgradeFiles);
|
||||
|
||||
$pluginVersion = PluginVersion::whereCode($code)->first();
|
||||
$this->vars['pluginName'] = array_get($details, 'name', 'system::lang.plugin.unnamed');
|
||||
$this->vars['pluginVersion'] = $pluginVersion->version;
|
||||
$this->vars['pluginAuthor'] = array_get($details, 'author');
|
||||
$this->vars['pluginIcon'] = array_get($details, 'icon', 'icon-leaf');
|
||||
$this->vars['pluginHomepage'] = array_get($details, 'homepage');
|
||||
}
|
||||
else {
|
||||
throw new ApplicationException('Plugin not found');
|
||||
}
|
||||
|
||||
$this->vars['activeTab'] = $tab ?: 'readme';
|
||||
$this->vars['urlCode'] = $urlCode;
|
||||
$this->vars['upgrades'] = $upgrades;
|
||||
$this->vars['readme'] = $readme;
|
||||
}
|
||||
catch (Exception $ex) {
|
||||
$this->handleError($ex);
|
||||
}
|
||||
}
|
||||
|
||||
protected function getPluginMarkdownFile($path, $filenames)
|
||||
{
|
||||
$contents = null;
|
||||
foreach ($filenames as $file) {
|
||||
if (!File::exists($path . '/'.$file)) continue;
|
||||
|
||||
$contents = File::get($path . '/'.$file);
|
||||
|
||||
/*
|
||||
* Parse markdown, clean HTML, remove first H1 tag
|
||||
*/
|
||||
$contents = Markdown::parse($contents);
|
||||
$contents = Html::clean($contents);
|
||||
$contents = preg_replace('@<h1[^>]*?>.*?<\/h1>@si', '', $contents, 1);
|
||||
}
|
||||
|
||||
return $contents;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
|
|
@ -119,6 +186,10 @@ class Updates extends Controller
|
|||
return 'negative';
|
||||
}
|
||||
|
||||
if ($record->is_frozen) {
|
||||
return 'frozen';
|
||||
}
|
||||
|
||||
return 'positive';
|
||||
}
|
||||
|
||||
|
|
@ -193,8 +264,11 @@ class Updates extends Controller
|
|||
$manager = UpdateManager::instance();
|
||||
$result = $manager->requestUpdateList();
|
||||
|
||||
$result = $this->processImportantUpdates($result);
|
||||
|
||||
$this->vars['core'] = array_get($result, 'core', false);
|
||||
$this->vars['hasUpdates'] = array_get($result, 'hasUpdates', false);
|
||||
$this->vars['hasImportantUpdates'] = array_get($result, 'hasImportantUpdates', false);
|
||||
$this->vars['pluginList'] = array_get($result, 'plugins', []);
|
||||
$this->vars['themeList'] = array_get($result, 'themes', []);
|
||||
}
|
||||
|
|
@ -205,6 +279,31 @@ class Updates extends Controller
|
|||
return ['#updateContainer' => $this->makePartial('update_list')];
|
||||
}
|
||||
|
||||
/**
|
||||
* Loops the update list and checks for actionable updates.
|
||||
*/
|
||||
protected function processImportantUpdates($result)
|
||||
{
|
||||
$hasImportantUpdates = false;
|
||||
foreach (array_get($result, 'plugins', []) as $code => $plugin) {
|
||||
$isImportant = false;
|
||||
|
||||
foreach (array_get($plugin, 'updates', []) as $version => $description) {
|
||||
if (strpos($description, '!!!') === false) continue;
|
||||
|
||||
$isImportant = $hasImportantUpdates = true;
|
||||
$detailsUrl = Backend::url('system/updates/details/'.strtolower(str_replace('.', '-', $code)).'/upgrades');
|
||||
$description = str_replace('!!!', '', $description);
|
||||
$result['plugins'][$code]['updates'][$version] = [$description, $detailsUrl];
|
||||
}
|
||||
|
||||
$result['plugins'][$code]['isImportant'] = $isImportant ? '1' : '0';
|
||||
}
|
||||
|
||||
$result['hasImportantUpdates'] = $hasImportantUpdates;
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Contacts the update server for a list of necessary updates.
|
||||
*/
|
||||
|
|
@ -258,20 +357,69 @@ class Updates extends Controller
|
|||
public function onApplyUpdates()
|
||||
{
|
||||
try {
|
||||
/*
|
||||
* Process core
|
||||
*/
|
||||
$coreHash = post('hash');
|
||||
$coreBuild = post('build');
|
||||
$core = [$coreHash, $coreBuild];
|
||||
|
||||
$plugins = post('plugins', []);
|
||||
if (!is_array($plugins)) {
|
||||
/*
|
||||
* Process plugins
|
||||
*/
|
||||
$plugins = post('plugins');
|
||||
if (is_array($plugins)) {
|
||||
$pluginCodes = [];
|
||||
foreach ($plugins as $code => $hash) {
|
||||
$pluginCodes[] = $this->decodeCode($code);
|
||||
}
|
||||
|
||||
$plugins = array_combine($pluginCodes, $plugins);
|
||||
}
|
||||
else {
|
||||
$plugins = [];
|
||||
}
|
||||
|
||||
$themes = post('themes', []);
|
||||
if (!is_array($themes)) {
|
||||
/*
|
||||
* Process themes
|
||||
*/
|
||||
$themes = post('themes');
|
||||
if (is_array($themes)) {
|
||||
$themeCodes = [];
|
||||
foreach ($themes as $code => $hash) {
|
||||
$themeCodes[] = $this->decodeCode($code);
|
||||
}
|
||||
|
||||
$themes = array_combine($themeCodes, $themes);
|
||||
}
|
||||
else {
|
||||
$themes = [];
|
||||
}
|
||||
|
||||
/*
|
||||
* Process important update actions
|
||||
*/
|
||||
$pluginActions = (array) post('plugin_actions');
|
||||
foreach ($plugins as $code => $hash) {
|
||||
$_code = $this->encodeCode($code);
|
||||
if (!array_key_exists($_code, $pluginActions)) continue;
|
||||
$pluginAction = $pluginActions[$_code];
|
||||
|
||||
if (!$pluginAction) {
|
||||
throw new ApplicationException('Please select an action for plugin '. $code);
|
||||
}
|
||||
|
||||
if ($pluginAction != 'confirm') {
|
||||
unset($plugins[$code]);
|
||||
}
|
||||
|
||||
if ($pluginAction == 'ignore') {
|
||||
PluginVersion::whereCode($code)->update([
|
||||
'is_frozen' => true
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Update steps
|
||||
*/
|
||||
|
|
@ -546,6 +694,7 @@ class Updates extends Controller
|
|||
public function onDisablePlugins()
|
||||
{
|
||||
$disable = post('disable', false);
|
||||
$freeze = post('freeze', false);
|
||||
if (($checkedIds = post('checked')) && is_array($checkedIds) && count($checkedIds)) {
|
||||
|
||||
$manager = PluginManager::instance();
|
||||
|
|
@ -563,6 +712,7 @@ class Updates extends Controller
|
|||
}
|
||||
|
||||
$object->is_disabled = $disable;
|
||||
$object->is_frozen = $freeze;
|
||||
$object->save();
|
||||
}
|
||||
|
||||
|
|
@ -727,4 +877,23 @@ class Updates extends Controller
|
|||
return array_values($popular);
|
||||
}
|
||||
|
||||
//
|
||||
// Helpers
|
||||
//
|
||||
|
||||
/**
|
||||
* Encode HTML safe product code.
|
||||
*/
|
||||
protected function encodeCode($code)
|
||||
{
|
||||
return str_replace('.', '_', $code);
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode HTML safe product code.
|
||||
*/
|
||||
protected function decodeCode($code)
|
||||
{
|
||||
return str_replace('_', '.', $code);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,4 +12,3 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,19 @@
|
|||
<?php
|
||||
$icon = null;
|
||||
|
||||
if ($record->is_disabled) {
|
||||
$icon = 'eye-slash';
|
||||
}
|
||||
elseif ($record->disabledBySystem) {
|
||||
$icon = 'exclamation';
|
||||
}
|
||||
elseif ($record->orphaned) {
|
||||
$icon = 'question';
|
||||
}
|
||||
elseif ($record->is_frozen) {
|
||||
$icon = 'lock';
|
||||
}
|
||||
?>
|
||||
<span class="<?= $icon ? 'oc-icon-'.$icon : '' ?>">
|
||||
<?= $value ?>
|
||||
</span>
|
||||
|
|
@ -28,6 +28,21 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<!-- Checkbox -->
|
||||
<div class="checkbox custom-checkbox">
|
||||
<input
|
||||
type="checkbox"
|
||||
name="freeze"
|
||||
value="1"
|
||||
id="pluginFreeze">
|
||||
<label for="pluginFreeze">
|
||||
<?= e(trans('system::lang.plugins.frozen_label')) ?>
|
||||
</label>
|
||||
<p class="help-block"><?= e(trans('system::lang.plugins.frozen_help')) ?></p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<?php foreach ($checked as $id): ?>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,7 @@
|
|||
<div data-control="toolbar">
|
||||
<a href="<?= Backend::url('system/updates') ?>" class="btn btn-default oc-icon-chevron-left">
|
||||
<?= e(trans('system::lang.updates.return_link')) ?>
|
||||
</a>
|
||||
<div class="btn-group">
|
||||
<button
|
||||
class="btn btn-default oc-icon-magic"
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@
|
|||
</div>
|
||||
|
||||
<script>
|
||||
$('#checkUpdatesPopup').on('popupComplete', function(){
|
||||
$('#updateForm').request('onCheckForUpdates')
|
||||
$('#checkUpdatesPopup').on('popupComplete', function() {
|
||||
$.oc.updateProcess.check()
|
||||
})
|
||||
</script>
|
||||
|
|
@ -9,21 +9,22 @@
|
|||
</p>
|
||||
|
||||
<div class="control-updatelist">
|
||||
<div class="control-scrollbar" style="height:300px" data-control="scrollbar">
|
||||
<div class="control-scrollbar" style="height:400px" data-control="scrollbar">
|
||||
<?php if ($core): ?>
|
||||
<div class="update-item">
|
||||
<div class="item-header">
|
||||
<h5>
|
||||
<i class="icon-cube"></i>
|
||||
<?= e(trans('system::lang.system.name')) ?>
|
||||
<?php if ($core['old_build']): ?>
|
||||
<small><?= e(trans('system::lang.updates.core_build_old', ['build'=>$core['old_build']])) ?></small>
|
||||
<?php endif ?>
|
||||
</h5>
|
||||
</div>
|
||||
<dl>
|
||||
<dt><?= e(trans('system::lang.updates.core_build_new', ['build'=>$core['build']])) ?></dt>
|
||||
<dd><?= e(trans('system::lang.updates.core_build_new_help')) ?></dd>
|
||||
<?php if ($core['old_build']): ?>
|
||||
<dt class="text-muted"><?= e(trans('system::lang.updates.core_build_new', ['build'=>$core['old_build']])) ?></dt>
|
||||
<dd class="text-muted"><?= e(trans('system::lang.updates.core_build')) ?></dd>
|
||||
<?php endif ?>
|
||||
</dl>
|
||||
<input type="hidden" name="hash" value="<?= e($core['hash']) ?>" />
|
||||
<input type="hidden" name="build" value="<?= e($core['build']) ?>" />
|
||||
|
|
@ -36,7 +37,6 @@
|
|||
<h5>
|
||||
<i class="icon-picture-o"></i>
|
||||
<?= e(array_get($theme, 'name', 'Unknown')) ?>
|
||||
<small><?= e(trans('system::lang.updates.theme_label')) ?></small>
|
||||
</h5>
|
||||
</div>
|
||||
<dl>
|
||||
|
|
@ -44,32 +44,66 @@
|
|||
<dd><?= e(trans('system::lang.updates.theme_new_install')) ?></dd>
|
||||
</dl>
|
||||
|
||||
<input type="hidden" name="themes[<?= e($code) ?>]" value="<?= e($theme['hash']) ?>" />
|
||||
<input type="hidden" name="themes[<?= e($this->encodeCode($code)) ?>]" value="<?= e($theme['hash']) ?>" />
|
||||
</div>
|
||||
<?php endforeach ?>
|
||||
|
||||
<?php foreach ($pluginList as $code => $plugin): ?>
|
||||
<div class="update-item">
|
||||
<div class="update-item <?= $plugin['isImportant'] ? 'item-danger' : '' ?>">
|
||||
<div class="item-header">
|
||||
<?php if ($plugin['isImportant']): ?>
|
||||
<div class="important-update form-group form-group-sm">
|
||||
<select
|
||||
name="plugin_actions[<?= e($this->encodeCode($code)) ?>]"
|
||||
class="form-control custom-select select-no-search"
|
||||
data-important-update-select>
|
||||
<option value="">-- Select action --</option>
|
||||
<option value="confirm">Confirm update</option>
|
||||
<option value="skip">Skip this plugin (once only)</option>
|
||||
<option value="ignore">Skip this plugin (always)</option>
|
||||
</select>
|
||||
</div>
|
||||
<?php endif ?>
|
||||
<h5>
|
||||
<i class="<?= e($plugin['icon'] ?: 'icon-puzzle-piece') ?>"></i>
|
||||
<?= e($plugin['name']) ?>
|
||||
|
||||
<?php if ($plugin['old_version']): ?>
|
||||
<small><?= e(trans('system::lang.updates.plugin_version_old', ['version'=>$plugin['old_version']])) ?></small>
|
||||
<?php else: ?>
|
||||
<small><?= e(trans('system::lang.updates.plugin_version_none')) ?></small>
|
||||
<?php endif ?>
|
||||
</h5>
|
||||
</div>
|
||||
<dl>
|
||||
<?php foreach ($plugin['updates'] as $version => $description): ?>
|
||||
<dt><?= e(trans('system::lang.updates.plugin_version_new', compact('version'))) ?></dt>
|
||||
<dd><?= e($description) ?></dd>
|
||||
<?php endforeach ?>
|
||||
|
||||
<?php if (!$plugin['old_version']): ?>
|
||||
<dt>
|
||||
<?= $plugin['version'] ?>
|
||||
</dt>
|
||||
<dd>
|
||||
<?= e(trans('system::lang.updates.plugin_version_none')) ?>
|
||||
</dd>
|
||||
<?php else: ?>
|
||||
<?php foreach (array_reverse($plugin['updates']) as $version => $description): ?>
|
||||
<dt><?= e($version) ?></dt>
|
||||
<?php if (is_array($description)): ?>
|
||||
<dd>
|
||||
<span class="important-update-label">Action required</span>
|
||||
<?= e($description[0]) ?>
|
||||
<a href="<?= $description[1] ?>" target="_blank">
|
||||
View upgrade guide <i class="icon-external-link"></i>
|
||||
</a>
|
||||
</dd>
|
||||
<?php else: ?>
|
||||
<dd><?= e($description) ?></dd>
|
||||
<?php endif ?>
|
||||
<?php endforeach ?>
|
||||
|
||||
<dt class="text-muted">
|
||||
<?= e($plugin['old_version']) ?>
|
||||
</dt>
|
||||
<dd class="text-muted">
|
||||
Current version
|
||||
</dd>
|
||||
<?php endif ?>
|
||||
</dl>
|
||||
|
||||
<input type="hidden" name="plugins[<?= e($code) ?>]" value="<?= e($plugin['hash']) ?>" />
|
||||
<input type="hidden" name="plugins[<?= e($this->encodeCode($code)) ?>]" value="<?= e($plugin['hash']) ?>" />
|
||||
</div>
|
||||
<?php endforeach ?>
|
||||
|
||||
|
|
@ -79,8 +113,14 @@
|
|||
</div>
|
||||
|
||||
<div class="modal-footer">
|
||||
<?php if ($hasImportantUpdates): ?>
|
||||
<p class="text-danger pull-left oc-icon-exclamation important-update-label" id="updateListImportantLabel">
|
||||
Some updates need your attention.
|
||||
</p>
|
||||
<?php endif ?>
|
||||
<button
|
||||
type="button"
|
||||
id="updateListUpdateButton"
|
||||
class="btn btn-primary"
|
||||
data-dismiss="popup"
|
||||
data-control="popup"
|
||||
|
|
|
|||
|
|
@ -2,11 +2,12 @@
|
|||
# List Behavior Config
|
||||
# ===================================
|
||||
|
||||
list: ~/modules/system/models/pluginversion/columns.yaml
|
||||
list: ~/modules/system/models/pluginversion/columns_manage.yaml
|
||||
modelClass: System\Models\PluginVersion
|
||||
noRecordsMessage: backend::lang.list.no_records
|
||||
showSetup: false
|
||||
showCheckboxes: true
|
||||
recordOnClick: $.oc.listToggleChecked(this)
|
||||
|
||||
toolbar:
|
||||
buttons: list_manage_toolbar
|
||||
|
|
|
|||
|
|
@ -0,0 +1,76 @@
|
|||
<?php Block::put('breadcrumb') ?>
|
||||
<ul>
|
||||
<li><a href="<?= Backend::url('system/updates') ?>"><?= e(trans('system::lang.updates.menu_label')) ?></a></li>
|
||||
<li><?= e(trans($this->pageTitle)) ?></li>
|
||||
</ul>
|
||||
<?php Block::endPut() ?>
|
||||
|
||||
<?php if (!$this->fatalError): ?>
|
||||
|
||||
<div class="scoreboard">
|
||||
<div data-control="toolbar">
|
||||
<div class="scoreboard-item title-value">
|
||||
<h4>Plugin</h4>
|
||||
<p class="oc-<?= $pluginIcon ?>"><?= e(trans($pluginName)) ?></p>
|
||||
<?php if ($pluginHomepage): ?>
|
||||
<p class="description">
|
||||
<a href="<?= e($pluginHomepage) ?>">View homepage</a>
|
||||
</p>
|
||||
<?php endif ?>
|
||||
</div>
|
||||
<div class="scoreboard-item title-value">
|
||||
<h4>Current version</h4>
|
||||
<p><?= e($pluginVersion) ?></p>
|
||||
</div>
|
||||
<div class="scoreboard-item title-value">
|
||||
<h4>Author</h4>
|
||||
<p><?= e($pluginAuthor) ?></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="control-tabs primary-tabs" data-control="tab">
|
||||
<ul class="nav nav-tabs">
|
||||
<li class="<?= $activeTab == 'readme' ? 'active' : '' ?>">
|
||||
<a
|
||||
href="#readme"
|
||||
data-tab-url="<?= Backend::url('system/updates/details/'.$urlCode.'/readme') ?>">
|
||||
Documentation
|
||||
</a>
|
||||
</li>
|
||||
<li class="<?= $activeTab == 'upgrades' ? 'active' : '' ?>">
|
||||
<a
|
||||
href="#upgrades"
|
||||
data-tab-url="<?= Backend::url('system/updates/details/'.$urlCode.'/upgrades') ?>">
|
||||
Upgrade Guide
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
<div class="tab-content">
|
||||
<div class="tab-pane <?= $activeTab == 'readme' ? 'active' : '' ?>">
|
||||
<div class="plugin-details-content">
|
||||
<?php if ($readme): ?>
|
||||
<?= $readme ?>
|
||||
<?php else: ?>
|
||||
<p>Plugin does not provide any documentation.</p>
|
||||
<?php endif ?>
|
||||
</div>
|
||||
</div>
|
||||
<div class="tab-pane <?= $activeTab == 'upgrades' ? 'active' : '' ?>">
|
||||
<div class="plugin-details-content">
|
||||
<?php if ($upgrades): ?>
|
||||
<?= $upgrades ?>
|
||||
<?php else: ?>
|
||||
<p>Plugin does not provide any upgrade instructions.</p>
|
||||
<?php endif ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php else: ?>
|
||||
|
||||
<p class="flash-message static error"><?= e($this->fatalError) ?></p>
|
||||
<p><a href="<?= Backend::url('system/updates') ?>" class="btn btn-default"><?= e(trans('system::lang.settings.return')) ?></a></p>
|
||||
|
||||
<?php endif ?>
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
class DbSystemAddFrozenFlag extends Migration
|
||||
{
|
||||
public function up()
|
||||
{
|
||||
Schema::table('system_plugin_versions', function (Blueprint $table) {
|
||||
$table->boolean('is_frozen')->default(0);
|
||||
});
|
||||
}
|
||||
|
||||
public function down()
|
||||
{
|
||||
Schema::table('system_plugin_versions', function (Blueprint $table) {
|
||||
$table->dropColumn('is_frozen');
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -91,6 +91,8 @@ return [
|
|||
'refresh' => 'Refresh',
|
||||
'disabled_label' => 'Disabled',
|
||||
'disabled_help' => 'Plugins that are disabled are ignored by the application.',
|
||||
'frozen_label' => 'Freeze updates',
|
||||
'frozen_help' => 'Plugins that are frozen will be ignored by the update process.',
|
||||
'selected_amount' => 'Plugins selected: :amount',
|
||||
'remove_confirm' => 'Are you sure you want to remove this plugin?',
|
||||
'remove_success' => 'Successfully removed those plugins from the system.',
|
||||
|
|
@ -195,6 +197,7 @@ return [
|
|||
'check_label' => 'Check for updates',
|
||||
'retry_label' => 'Try again',
|
||||
'plugin_name' => 'Name',
|
||||
'plugin_code' => 'Code',
|
||||
'plugin_description' => 'Description',
|
||||
'plugin_version' => 'Version',
|
||||
'plugin_author' => 'Author',
|
||||
|
|
@ -210,8 +213,8 @@ return [
|
|||
'plugin_downloading' => 'Downloading plugin: :name',
|
||||
'plugin_extracting' => 'Unpacking plugin: :name',
|
||||
'plugin_version_none' => 'New plugin',
|
||||
'plugin_version_old' => 'Current v:version',
|
||||
'plugin_version_new' => 'v:version',
|
||||
// 'plugin_version_old' => 'Current v:version',
|
||||
// 'plugin_version_new' => 'v:version',
|
||||
'theme_label' => 'Theme',
|
||||
'theme_new_install' => 'New theme installation.',
|
||||
'theme_downloading' => 'Downloading theme: :name',
|
||||
|
|
@ -229,7 +232,8 @@ return [
|
|||
'none' => [
|
||||
'label' => 'No updates',
|
||||
'help' => 'No new updates were found.'
|
||||
]
|
||||
],
|
||||
'return_link' => 'Return to system updates'
|
||||
],
|
||||
'server' => [
|
||||
'connect_error' => 'Error connecting to the server.',
|
||||
|
|
|
|||
|
|
@ -49,7 +49,6 @@ class PluginVersion extends Model
|
|||
$manager = PluginManager::instance();
|
||||
$pluginObj = $manager->findByIdentifier($this->code);
|
||||
|
||||
|
||||
if ($pluginObj) {
|
||||
$pluginInfo = $pluginObj->pluginDetails();
|
||||
foreach ($pluginInfo as $attribute => $info) {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,15 @@
|
|||
# ===================================
|
||||
# Column Definitions
|
||||
# ===================================
|
||||
|
||||
columns:
|
||||
|
||||
code:
|
||||
label: system::lang.updates.plugin_code
|
||||
sortable: false
|
||||
type: partial
|
||||
path: column_code
|
||||
|
||||
version:
|
||||
label: system::lang.updates.plugin_version
|
||||
sortable: false
|
||||
Loading…
Reference in New Issue