mirror of
https://github.com/getrebuild/rebuild.git
synced 2024-09-20 23:45:55 +08:00
comp spinner/indeterminate
This commit is contained in:
parent
d11fb94920
commit
ccc10985aa
|
@ -32,7 +32,7 @@ if (currentUser != null) {
|
|||
<meta name="rb.isAdminVerified" content="<%=AppUtils.isAdminVerified(request)%>">
|
||||
<%}}%>
|
||||
<%if (AppUtils.isIE(request)) {%>
|
||||
<script src="${baseUrl}/assets/lib/react/polyfill.min.js?v=7.6.0"></script>
|
||||
<script id="ie-polyfill" src="${baseUrl}/assets/lib/react/polyfill.min.js?v=7.6.0"></script>
|
||||
<!--[if lt IE 10]><script>location.href='${baseUrl}/error/unsupported-browser'</script><![endif]-->
|
||||
<%}%>
|
||||
<c:if test="${markWatermark}"><script src="${baseUrl}/assets/lib/watermark.js?v=2.3.2"></script></c:if>
|
|
@ -25796,4 +25796,56 @@ div.table-responsive>div.dataTables_wrapper>div.row>div[class^="col-"]:last-chil
|
|||
.file-icon[data-type=gif],
|
||||
.file-icon[data-type=png] {
|
||||
background: #f4b400;
|
||||
}
|
||||
|
||||
/* BS v4.4 */
|
||||
|
||||
/* https://getbootstrap.com/docs/4.4/components/spinners/ */
|
||||
|
||||
.spinner-border,
|
||||
.spinner-grow {
|
||||
display: inline-block;
|
||||
width: 2rem;
|
||||
height: 2rem;
|
||||
vertical-align: text-bottom;
|
||||
}
|
||||
|
||||
.spinner-border-sm,
|
||||
.spinner-grow-sm {
|
||||
width: 1rem;
|
||||
height: 1rem;
|
||||
}
|
||||
|
||||
@keyframes spinner-border {
|
||||
to {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
|
||||
.spinner-border {
|
||||
border: 3px solid currentColor;
|
||||
border-right-color: transparent;
|
||||
border-radius: 50%;
|
||||
animation: spinner-border .75s linear infinite;
|
||||
}
|
||||
|
||||
.spinner-border-sm {
|
||||
border-width: 2px;
|
||||
}
|
||||
|
||||
@keyframes spinner-grow {
|
||||
0% {
|
||||
transform: scale(0);
|
||||
}
|
||||
|
||||
50% {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.spinner-grow {
|
||||
background-color: currentColor;
|
||||
border-radius: 50%;
|
||||
opacity: 0;
|
||||
animation: spinner-grow .75s linear infinite;
|
||||
}
|
|
@ -1146,6 +1146,7 @@ i.split.ui-draggable-dragging {
|
|||
right: 0;
|
||||
color: #4285f4;
|
||||
padding-top: 1px;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.data-list .table thead th>div>i.zmdi.sort-asc::before {
|
||||
|
@ -3254,4 +3255,51 @@ a.icon-link>.zmdi {
|
|||
.popover {
|
||||
border-radius: 2px;
|
||||
border-width: 0;
|
||||
}
|
||||
|
||||
.btn .spinner-border,
|
||||
.btn .spinner-grow {
|
||||
width: 1rem;
|
||||
height: 1rem;
|
||||
}
|
||||
|
||||
.btn.btn-xl .spinner-border,
|
||||
.btn.btn-xl .spinner-grow {
|
||||
width: 1.5rem;
|
||||
height: 1.5rem;
|
||||
}
|
||||
|
||||
.custom-checkbox.indeterminate .custom-control-label::after {
|
||||
background-color: #4285f4;
|
||||
border: 0;
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
margin-top: 5px;
|
||||
margin-left: 5px !important;
|
||||
}
|
||||
|
||||
.custom-checkbox.indeterminate .custom-control-label::before {
|
||||
border-color: #4285f4;
|
||||
}
|
||||
|
||||
.custom-checkbox.custom-control-sm.indeterminate .custom-control-label::after {
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
}
|
||||
|
||||
.custom-radio .custom-control-input:checked~.custom-control-label::after {
|
||||
font-size: 0 !important;
|
||||
width: 11px;
|
||||
height: 11px;
|
||||
background-color: #4285f4;
|
||||
border-radius: 50%;
|
||||
margin-top: 6px;
|
||||
margin-left: 6px;
|
||||
}
|
||||
|
||||
.custom-radio.custom-control-sm .custom-control-input:checked~.custom-control-label::after {
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
margin-top: 5px;
|
||||
margin-left: 5px;
|
||||
}
|
|
@ -4,8 +4,8 @@ Copyright (c) REBUILD <https://getrebuild.com/> and its owners. All rights reser
|
|||
rebuild is dual-licensed under commercial and open source licenses (GPLv3).
|
||||
See LICENSE and COMMERCIAL in the project root for license information.
|
||||
*/
|
||||
|
||||
/* eslint-disable no-unused-vars */
|
||||
|
||||
/*! https://github.com/carhartl/jquery-cookie */
|
||||
// eslint-disable-next-line
|
||||
(function (factory) { if (typeof define === "function" && define.amd) { define(["jquery"], factory) } else { if (typeof exports === "object") { factory(require("jquery")) } else { factory(jQuery) } } }(function ($) { var pluses = /\+/g; function encode(s) { return config.raw ? s : encodeURIComponent(s) } function decode(s) { return config.raw ? s : decodeURIComponent(s) } function stringifyCookieValue(value) { return encode(config.json ? JSON.stringify(value) : String(value)) } function parseCookieValue(s) { if (s.indexOf('"') === 0) { s = s.slice(1, -1).replace(/\\"/g, '"').replace(/\\\\/g, "\\") } try { s = decodeURIComponent(s.replace(pluses, " ")); return config.json ? JSON.parse(s) : s } catch (e) { } } function read(s, converter) { var value = config.raw ? s : parseCookieValue(s); return $.isFunction(converter) ? converter(value) : value } var config = $.cookie = function (key, value, options) { if (value !== undefined && !$.isFunction(value)) { options = $.extend({}, config.defaults, options); if (typeof options.expires === "number") { var days = options.expires, t = options.expires = new Date(); t.setTime(+t + days * 86400000) } return (document.cookie = [encode(key), "=", stringifyCookieValue(value), options.expires ? "; expires=" + options.expires.toUTCString() : "", options.path ? "; path=" + options.path : "", options.domain ? "; domain=" + options.domain : "", options.secure ? "; secure" : ""].join("")) } var result = key ? undefined : {}; var cookies = document.cookie ? document.cookie.split("; ") : []; for (var i = 0, l = cookies.length; i < l; i++) { var parts = cookies[i].split("="); var name = decode(parts.shift()); var cookie = parts.join("="); if (key && key === name) { result = read(cookie, value); break } if (!key && (cookie = read(cookie)) !== undefined) { result[name] = cookie } } return result }; config.defaults = {}; $.removeCookie = function (key, options) { if ($.cookie(key) === undefined) { return false } $.cookie(key, "", $.extend({}, options, { expires: -1 })); return !$.cookie(key) } }));
|
||||
|
@ -17,24 +17,28 @@ See LICENSE and COMMERCIAL in the project root for license information.
|
|||
$.fn.extend({
|
||||
'button': function (state) {
|
||||
return this.each(function () {
|
||||
var el = $(this)
|
||||
if (!(el.prop('nodeName') === 'BUTTON' || el.prop('nodeName') === 'A')) return
|
||||
var $el = $(this)
|
||||
if (!($el.prop('nodeName') === 'BUTTON' || $el.prop('nodeName') === 'A')) return
|
||||
if (state === 'loading') {
|
||||
el.attr('disabled', true)
|
||||
var loadingText = el.data('loading-text')
|
||||
$el.attr('disabled', true)
|
||||
|
||||
var spinner = $el.data('spinner')
|
||||
if ($('#ie-polyfill').length > 0) spinner = undefined
|
||||
var loadingText = $el.data('loading-text')
|
||||
this.__textHold = $el.html()
|
||||
|
||||
var _this = this
|
||||
if (loadingText) {
|
||||
var _this = this
|
||||
this.__loadingTextTimer = setTimeout(function () {
|
||||
_this.__textHold = el.html()
|
||||
el.text(loadingText)
|
||||
}, 200)
|
||||
this.__loadingTimer = setTimeout(function () { $el.text(loadingText) }, 200)
|
||||
} else if (spinner !== undefined) {
|
||||
this.__loadingTimer = setTimeout(function () { $el.html('<span class="spinner-' + (spinner === 'grow' ? 'grow' : 'border') + '"></span>') }, 200)
|
||||
}
|
||||
} else if (state === 'reset') {
|
||||
el.attr('disabled', false)
|
||||
if (this.__loadingTextTimer) {
|
||||
clearTimeout(this.__loadingTextTimer)
|
||||
this.__loadingTextTimer = null
|
||||
if (this.__textHold) el.html(this.__textHold)
|
||||
$el.attr('disabled', false)
|
||||
if (this.__loadingTimer) {
|
||||
clearTimeout(this.__loadingTimer)
|
||||
this.__loadingTimer = null
|
||||
if (this.__textHold) $el.html(this.__textHold)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
@ -60,7 +64,6 @@ See LICENSE and COMMERCIAL in the project root for license information.
|
|||
beforeSend: function (xhr, settings) {
|
||||
// URL prefix
|
||||
if (settings.url.substr(0, 1) === '/' && rb.baseUrl) settings.url = rb.baseUrl + settings.url
|
||||
console.log(settings)
|
||||
return settings
|
||||
}
|
||||
})
|
||||
|
|
|
@ -50,12 +50,12 @@ class RbList extends React.Component {
|
|||
<div className="col-sm-12">
|
||||
<div className="rb-scroller" ref={(c) => this._rblistScroller = c}>
|
||||
<table className="table table-hover table-striped">
|
||||
<thead ref={(c) => this._rblistHead = c}>
|
||||
<thead>
|
||||
<tr>
|
||||
{this.props.uncheckbox !== true && <th className="column-checkbox">
|
||||
<div>
|
||||
<label className="custom-control custom-control-sm custom-checkbox">
|
||||
<input className="custom-control-input" type="checkbox" onChange={(e) => this.toggleRows(e)} />
|
||||
<input className="custom-control-input" type="checkbox" onChange={(e) => this._toggleRows(e)} ref={(c) => this._checkAll = c} />
|
||||
<span className="custom-control-label"></span>
|
||||
</label>
|
||||
</div>
|
||||
|
@ -64,7 +64,7 @@ class RbList extends React.Component {
|
|||
const cWidth = item.width || that.__defaultColumnWidth
|
||||
const styles = { width: cWidth + 'px' }
|
||||
return <th key={'column-' + item.field} style={styles} className={`unselect ${item.unsort ? '' : 'sortable'}`} data-field={item.field}
|
||||
onClick={item.unsort ? null : this.sortField.bind(this, item.field)}>
|
||||
onClick={item.unsort ? null : this._sortField.bind(this, item.field)}>
|
||||
<div style={styles}>
|
||||
<span style={{ width: (cWidth - 8) + 'px' }}>{item.label}</span>
|
||||
<i className={'zmdi ' + (item.sort || '')} />
|
||||
|
@ -79,11 +79,11 @@ class RbList extends React.Component {
|
|||
{this.state.rowsData.map((item) => {
|
||||
const lastPrimary = item[lastIndex]
|
||||
const rowKey = 'row-' + lastPrimary.id
|
||||
return <tr key={rowKey} data-id={lastPrimary.id} onClick={(e) => this.clickRow(e, true)}>
|
||||
return <tr key={rowKey} data-id={lastPrimary.id} onClick={(e) => this._clickRow(e, true)}>
|
||||
{this.props.uncheckbox !== true && <td key={rowKey + '-checkbox'} className="column-checkbox">
|
||||
<div>
|
||||
<label className="custom-control custom-control-sm custom-checkbox">
|
||||
<input className="custom-control-input" type="checkbox" onChange={(e) => this.clickRow(e)} />
|
||||
<input className="custom-control-input" type="checkbox" onChange={(e) => this._clickRow(e)} />
|
||||
<span className="custom-control-label"></span>
|
||||
</label>
|
||||
</div>
|
||||
|
@ -146,16 +146,6 @@ class RbList extends React.Component {
|
|||
if (wpc.advFilter !== true) this.fetchList(this.__buildQuick())
|
||||
}
|
||||
|
||||
componentDidUpdate() {
|
||||
// 按钮状态
|
||||
const $oper = $('.dataTables_oper')
|
||||
$oper.find('.J_delete, .J_view, .J_edit, .J_assign, .J_share, .J_unshare').attr('disabled', true)
|
||||
const selected = this.getSelectedIds(true).length
|
||||
if (selected > 0) $oper.find('.J_delete, .J_assign, .J_share, .J_unshare').attr('disabled', false)
|
||||
else $(this._rblistHead).find('.custom-control-input').prop('checked', false)
|
||||
if (selected === 1) $oper.find('.J_view, .J_edit').attr('disabled', false)
|
||||
}
|
||||
|
||||
fetchList(filter) {
|
||||
const fields = []
|
||||
let field_sort = null
|
||||
|
@ -184,7 +174,10 @@ class RbList extends React.Component {
|
|||
}, 400)
|
||||
$.post(`/app/${entity}/data-list`, JSON.stringify(query), (res) => {
|
||||
if (res.error_code === 0) {
|
||||
this.setState({ rowsData: res.data.data || [], inLoad: false }, () => RbList.renderAfter())
|
||||
this.setState({ rowsData: res.data.data || [], inLoad: false }, () => {
|
||||
RbList.renderAfter()
|
||||
this._clearSelected()
|
||||
})
|
||||
if (res.data.total > 0) this._pagination.setState({ rowsTotal: res.data.total, pageNo: this.pageNo })
|
||||
} else {
|
||||
RbHighbar.error(res.error_msg)
|
||||
|
@ -218,33 +211,69 @@ class RbList extends React.Component {
|
|||
}
|
||||
|
||||
// 全选
|
||||
toggleRows(e, noUpdate) {
|
||||
_toggleRows(e, uncheck) {
|
||||
const $body = $(this._rblistBody)
|
||||
if (e.target.checked) $body.find('>tr').addClass('active').find('.custom-control-input').prop('checked', true)
|
||||
else $body.find('>tr').removeClass('active').find('.custom-control-input').prop('checked', false)
|
||||
// this.setState({ checkedChanged: true })
|
||||
if (!noUpdate) this.componentDidUpdate() // perform
|
||||
if (e.target.checked) {
|
||||
$body.find('>tr').addClass('active').find('.custom-control-input').prop('checked', true)
|
||||
} else {
|
||||
$body.find('>tr').removeClass('active').find('.custom-control-input').prop('checked', false)
|
||||
}
|
||||
if (!uncheck) this._checkSelected()
|
||||
}
|
||||
|
||||
// 单选
|
||||
clickRow(e, unhold) {
|
||||
_clickRow(e, unhold) {
|
||||
const $target = $(e.target)
|
||||
if ($target.hasClass('custom-control-label')) return
|
||||
if ($target.hasClass('custom-control-input') && unhold) return
|
||||
|
||||
const $tr = $target.parents('tr')
|
||||
if (unhold) {
|
||||
this.toggleRows({ target: { checked: false } }, true)
|
||||
this._toggleRows({ target: { checked: false } }, true)
|
||||
$tr.addClass('active').find('.custom-control-input').prop('checked', true)
|
||||
} else {
|
||||
if (e.target.checked) $tr.addClass('active')
|
||||
else $tr.removeClass('active')
|
||||
}
|
||||
// this.setState({ checkedChanged: true })
|
||||
this.componentDidUpdate() // for perform
|
||||
|
||||
this._checkSelected()
|
||||
}
|
||||
|
||||
sortField(field, e) {
|
||||
_checkSelected() {
|
||||
const chkSelected = $(this._rblistBody).find('>tr .custom-control-input:checked').length
|
||||
console.log('_checkSelected', chkSelected)
|
||||
|
||||
// 全选/半选/全清
|
||||
const chkAll = this.state.rowsData.length
|
||||
if (chkSelected === 0) {
|
||||
$(this._checkAll).prop('checked', false).parent().removeClass('indeterminate')
|
||||
} else if (chkSelected !== chkAll) {
|
||||
$(this._checkAll).prop('checked', false).parent().addClass('indeterminate')
|
||||
}
|
||||
|
||||
if (chkSelected > 0 && chkSelected === chkAll) {
|
||||
$(this._checkAll).prop('checked', true).parent().removeClass('indeterminate')
|
||||
}
|
||||
|
||||
// 操作按钮状态
|
||||
const $oper = $('.dataTables_oper')
|
||||
$oper.find('.J_delete, .J_view, .J_edit, .J_assign, .J_share, .J_unshare').attr('disabled', true)
|
||||
if (chkSelected > 0) {
|
||||
$oper.find('.J_delete, .J_assign, .J_share, .J_unshare').attr('disabled', false)
|
||||
if (chkSelected === 1) $oper.find('.J_view, .J_edit').attr('disabled', false)
|
||||
}
|
||||
|
||||
// 分页组件
|
||||
this._pagination && this._pagination.setState({ selectedTotal: chkSelected })
|
||||
}
|
||||
|
||||
_clearSelected() {
|
||||
$(this._checkAll).prop('checked', false)
|
||||
this._toggleRows({ target: { checked: false } })
|
||||
}
|
||||
|
||||
// 排序
|
||||
_sortField(field, e) {
|
||||
const fields = this.state.fields
|
||||
for (let i = 0; i < fields.length; i++) {
|
||||
if (fields[i].field === field) {
|
||||
|
@ -319,9 +348,8 @@ class RbList extends React.Component {
|
|||
*/
|
||||
getSelectedIds(noWarn) {
|
||||
const selected = []
|
||||
$(this._rblistBody).find('>tr .custom-control-input').each(function () {
|
||||
const $this = $(this)
|
||||
if ($this.prop('checked')) selected.push($this.parents('tr').data('id'))
|
||||
$(this._rblistBody).find('>tr .custom-control-input:checked').each(function () {
|
||||
selected.push($(this).parents('tr').data('id'))
|
||||
})
|
||||
if (selected.length === 0 && noWarn !== true) RbHighbar.create('未选中任何记录')
|
||||
return selected
|
||||
|
@ -477,7 +505,10 @@ class RbListPagination extends React.Component {
|
|||
return (
|
||||
<div className="row rb-datatable-footer">
|
||||
<div className="col-12 col-md-4">
|
||||
<div className="dataTables_info" key="page-rowsTotal">{this.state.rowsTotal > 0 ? `共 ${this.state.rowsTotal} 条数据` : ''}</div>
|
||||
<div className="dataTables_info" key="page-rowsTotal">
|
||||
{this.state.selectedTotal > 0 && <span className="mr-2">已选中 {this.state.selectedTotal} 条.</span>}
|
||||
{this.state.rowsTotal > 0 && <span>共 {this.state.rowsTotal} 条数据</span>}
|
||||
</div>
|
||||
</div>
|
||||
<div className="col-12 col-md-8">
|
||||
<div className="float-right paging_sizes">
|
||||
|
|
|
@ -93,8 +93,8 @@
|
|||
<a href="forgot-passwd">${bundle.lang('ForgotPassword')}</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group login-submit" style="margin-bottom:1.15rem">
|
||||
<button class="btn btn-primary btn-xl" type="submit">${bundle.lang('Login')}</button>
|
||||
<div class="form-group login-submit mb-2">
|
||||
<button class="btn btn-primary btn-xl" type="submit" data-spinner>${bundle.lang('Login')}</button>
|
||||
<div class="mt-4 text-center">${bundle.lang('NoAccountYet')} <a href="signup">${bundle.lang('SignupNow')}</a></div>
|
||||
</div>
|
||||
<div class="select-lang text-center mb-2">
|
||||
|
|
Loading…
Reference in a new issue