| | |
| | | url: `/webapi/dostars${param.func ? '/' + param.func : ''}`, |
| | | data: param |
| | | }).then(res => { |
| | | if (!res.status) { |
| | | reject() |
| | | return |
| | | } |
| | | let version = res.app_version || '1.00' |
| | | appVersion.newVersion = version |
| | | appVersion.oldVersion = appVersion.oldVersion || version |
| | |
| | | } |
| | | |
| | | /** |
| | | * @description 删除某个菜单配置信息 |
| | | */ |
| | | deleteMenuStorage (menuId) { |
| | | return new Promise(resolve => { |
| | | if (!mkDataBase) { |
| | | resolve() |
| | | return |
| | | } |
| | | mkDataBase.transaction(tx => { |
| | | tx.executeSql(`DELETE FROM CONFIGS where menuid='${menuId}'`, [], () => { |
| | | resolve() |
| | | }, () => { |
| | | mkDataBase = null |
| | | }) |
| | | }) |
| | | }) |
| | | } |
| | | |
| | | /** |
| | | * @description 获取或修改云端配置 |
| | | */ |
| | | getCloudConfig (param) { |
| | |
| | | |
| | | if (this.props.menuType === 'HS') { // 云端数据验证 |
| | | param.open_key = Utils.encrypt(param.secretkey, param.timestamp, true) |
| | | } else if (window.GLOB.systemType !== 'production') { |
| | | isSSO = false |
| | | } |
| | | |
| | | let defer = new Promise(resolve => { |
| | |
| | | const workbook = XLSX.read(result, { type: 'binary' }) |
| | | |
| | | let errors = null |
| | | let sheetName = btn.verify.sheet |
| | | |
| | | if (!workbook.Sheets.hasOwnProperty(btn.verify.sheet)) { |
| | | if (Object.keys(workbook.Sheets).length === 1) { |
| | | sheetName = Object.keys(workbook.Sheets)[0] |
| | | } |
| | | |
| | | if (!workbook.Sheets.hasOwnProperty(sheetName)) { |
| | | errors = 'notexit' |
| | | } else if (range === 1) { |
| | | let header = XLSX.utils.sheet_to_json(workbook.Sheets[btn.verify.sheet], {header: columns})[0] |
| | | let header = XLSX.utils.sheet_to_json(workbook.Sheets[sheetName], {header: columns})[0] |
| | | |
| | | if (!header) { |
| | | errors = 'empty' |
| | |
| | | let data = [] |
| | | |
| | | if (!errors) { |
| | | data = XLSX.utils.sheet_to_json(workbook.Sheets[btn.verify.sheet], {header: columns, range: (range)}) |
| | | data = XLSX.utils.sheet_to_json(workbook.Sheets[sheetName], {header: columns, range: (range)}) |
| | | } |
| | | |
| | | // 最终获取到并且格式化后的 json 数据 |
| | | this.props.returndata(data, errors) |
| | | this.props.returndata(data, errors, sheetName) |
| | | this.setState({ |
| | | excelId: '', |
| | | }, () => { |
| | |
| | | /** |
| | | * @description Excel 导入 |
| | | */ |
| | | getexceldata = (data, errors) => { |
| | | getexceldata = (data, errors, sheetName) => { |
| | | const { btn } = this.props |
| | | |
| | | if (errors) { |
| | | if (errors === 'notexit') { |
| | | notification.warning({ |
| | | top: 92, |
| | | message: '工作表《' + btn.verify.sheet + '》不存在!', |
| | | message: '工作表《' + sheetName + '》不存在!', |
| | | duration: 5 |
| | | }) |
| | | } else if (errors === 'empty') { |
| | | notification.warning({ |
| | | top: 92, |
| | | message: '工作表《' + btn.verify.sheet + '》为空!', |
| | | message: '工作表《' + sheetName + '》为空!', |
| | | duration: 5 |
| | | }) |
| | | } else if (errors === 'headerError') { |
| | | notification.warning({ |
| | | top: 92, |
| | | message: '工作表《' + btn.verify.sheet + '》表头设置错误,请检查表头中的名称及顺序,与按钮Excel列信息是否一致!', |
| | | message: '工作表《' + sheetName + '》表头设置错误,请检查表头中的名称及顺序,与按钮Excel列信息是否一致!', |
| | | duration: 5 |
| | | }) |
| | | } |
| | |
| | | if (!data || data.length === 0) { |
| | | notification.warning({ |
| | | top: 92, |
| | | message: '未获取到工作表《' + btn.verify.sheet + '》数据!', |
| | | message: '未获取到工作表《' + sheetName + '》数据!', |
| | | duration: 5 |
| | | }) |
| | | this.updateStatus('over') |
New file |
| | |
| | | import React, {Component} from 'react' |
| | | import PropTypes from 'prop-types' |
| | | import { is, fromJS } from 'immutable' |
| | | import { Select, Radio, Row, Col, Popover, Badge } from 'antd' |
| | | import moment from 'moment' |
| | | |
| | | // import Utils from '@/utils/utils.js' |
| | | import './index.scss' |
| | | |
| | | const { Option } = Select |
| | | |
| | | class Calendar extends Component { |
| | | static propTpyes = { |
| | | data: PropTypes.any, // 事件数据 |
| | | levels: PropTypes.any |
| | | } |
| | | |
| | | state = { |
| | | level: 'day', |
| | | levels: null, |
| | | yearlist: null, |
| | | selectYear: moment().format('YYYY'), |
| | | selectMonth: moment().format('MM'), |
| | | datelist: null, |
| | | monthlist: null, |
| | | } |
| | | |
| | | UNSAFE_componentWillMount() { |
| | | const { levels } = this.props |
| | | |
| | | let yearlist = [] |
| | | let _selectYear = +this.state.selectYear |
| | | yearlist.push(`${_selectYear}`) |
| | | |
| | | for (let i = 1; i <= 50; i++) { |
| | | yearlist.unshift(`${_selectYear - i}`) |
| | | yearlist.push(`${_selectYear + i}`) |
| | | } |
| | | |
| | | let datelist = this.getDateList(this.state.selectYear) |
| | | let _levels = null |
| | | |
| | | if (!levels) { |
| | | _levels = ['day', 'month', 'year'] |
| | | } else { |
| | | _levels = levels |
| | | } |
| | | |
| | | let level = _levels[0] |
| | | let monthlist = null |
| | | level = 'month' |
| | | |
| | | if (_levels.includes('month')) { |
| | | monthlist = datelist.filter(item => item.month === moment().format('MM'))[0] |
| | | } |
| | | |
| | | this.setState({ |
| | | yearlist, |
| | | datelist, |
| | | monthlist, |
| | | level, |
| | | levels: _levels |
| | | }) |
| | | } |
| | | |
| | | UNSAFE_componentWillReceiveProps(nextProps) { |
| | | if (!is(fromJS(this.props.data), fromJS(nextProps.data))) { |
| | | |
| | | } |
| | | } |
| | | |
| | | shouldComponentUpdate (nextProps, nextState) { |
| | | return !is(fromJS(this.state), fromJS(nextState)) |
| | | } |
| | | |
| | | getDateList = (selectYear) => { |
| | | let datelist = [] |
| | | let months = ['01', '02', '03', '04', '05', '06', '07', '08', '09', '10', '11', '12'] |
| | | let monthName = { |
| | | '01': '一月', '02': '二月', '03': '三月', '04': '四月', '05': '五月', '06': '六月', |
| | | '07': '七月', '08': '八月', '09': '九月', '10': '十月', '11': '十一月', '12': '十二月' |
| | | } |
| | | |
| | | months.forEach(month => { |
| | | let _weeklist = [{week: 1, sublist: []}] |
| | | let _week = moment(`${selectYear}${month}01`, 'YYYYMMDD').weekday() |
| | | let end = +moment(`${selectYear}${month}`, 'YYYYMM').endOf('month').format('DD') |
| | | |
| | | for (let i = 0; i < _week; i++) { |
| | | _weeklist[0].sublist.push(null) |
| | | } |
| | | |
| | | for (let i = 1; i <= end; i++) { |
| | | if (_weeklist[_weeklist.length - 1].sublist.length < 7) { |
| | | _weeklist[_weeklist.length - 1].sublist.push({day: i < 10 ? `0${i}` : `${i}`, label: i}) |
| | | } else { |
| | | let _week = {week: _weeklist.length + 1, sublist: [{day: i < 10 ? `0${i}` : `${i}`, label: i}]} |
| | | _weeklist.push(_week) |
| | | } |
| | | } |
| | | |
| | | let re = 7 - _weeklist[_weeklist.length - 1].sublist.length |
| | | for (let i = 0; i < re; i++) { |
| | | _weeklist[_weeklist.length - 1].sublist.push(null) |
| | | } |
| | | |
| | | datelist.push({ |
| | | month: month, |
| | | label: monthName[month], |
| | | sublist: _weeklist |
| | | }) |
| | | }) |
| | | |
| | | return datelist |
| | | } |
| | | |
| | | levelChange = (e) => { |
| | | this.setState({ level: e.target.value }) |
| | | } |
| | | |
| | | yearChange = (value) => { |
| | | const { levels, selectMonth } = this.state |
| | | let datelist = this.getDateList(value) |
| | | let monthlist = null |
| | | |
| | | if (levels.includes('month')) { |
| | | monthlist = datelist.filter(item => item.month === selectMonth)[0] |
| | | } |
| | | |
| | | this.setState({ selectYear: value, datelist, monthlist }) |
| | | } |
| | | |
| | | monthChange = (value) => { |
| | | const { datelist } = this.state |
| | | |
| | | this.setState({ |
| | | selectMonth: value, |
| | | monthlist: datelist.filter(item => item.month === value)[0] |
| | | }) |
| | | } |
| | | |
| | | triggerDay = (item) => { |
| | | |
| | | } |
| | | |
| | | render() { |
| | | const { level, selectMonth, selectYear, yearlist, levels, datelist, monthlist } = this.state |
| | | const _levelName = {day: '日', month: '月', year: '年'} |
| | | const listData = [ |
| | | { type: 'orange', content: 'This is error event 2.' }, |
| | | { type: 'cyan', content: 'This is error event 3.' }, |
| | | { type: 'green', content: 'This is error event 4.' }, |
| | | ] |
| | | |
| | | return ( |
| | | <div className="mk-calendar"> |
| | | <div className="mk-calendar-control"> |
| | | <Select value={selectYear} onChange={this.yearChange}> |
| | | {yearlist.map(item => (<Option key={item} value={item}>{item}年</Option>))} |
| | | </Select> |
| | | {level === 'month' ? <Select value={selectMonth} onChange={this.monthChange}> |
| | | <Option value="01">1月</Option> |
| | | <Option value="02">2月</Option> |
| | | <Option value="03">3月</Option> |
| | | <Option value="04">4月</Option> |
| | | <Option value="05">5月</Option> |
| | | <Option value="06">6月</Option> |
| | | <Option value="07">7月</Option> |
| | | <Option value="08">8月</Option> |
| | | <Option value="09">9月</Option> |
| | | <Option value="10">10月</Option> |
| | | <Option value="11">11月</Option> |
| | | <Option value="12">12月</Option> |
| | | </Select> : null} |
| | | {levels.length > 1 ? <Radio.Group value={level} onChange={this.levelChange}> |
| | | {levels.map(item => (<Radio.Button key={item} value={item}>{_levelName[item]}</Radio.Button>))} |
| | | </Radio.Group> : null} |
| | | </div> |
| | | <div className="mk-calendar-content"> |
| | | {level === 'day' ? <Row className="day-calendar" gutter={16}> |
| | | {datelist.map(item => ( |
| | | <Col span={4} key={item.month}> |
| | | <table> |
| | | <thead> |
| | | <tr> |
| | | <th colSpan="7">{item.label}</th> |
| | | </tr> |
| | | <tr> |
| | | <th>一</th><th>二</th><th>三</th><th>四</th><th>五</th><th>六</th><th>日</th> |
| | | </tr> |
| | | </thead> |
| | | <tbody> |
| | | {item.sublist.map(cell => ( |
| | | <tr key={cell.week}> |
| | | {cell.sublist.map((d, i) => ( |
| | | <td key={i}> |
| | | {d ? <div className={'day-wrap ' + d.class} onClick={() => this.triggerDay(d)}> |
| | | {d.label ? <Popover mouseEnterDelay={0.3} overlayClassName="calendar-day-pop" content={ |
| | | <div> |
| | | {listData.map((data, index) => ( |
| | | <div key={index} className="message"> |
| | | <Badge color={data.type} text={data.content} /> |
| | | </div> |
| | | ))} |
| | | </div> |
| | | } trigger="hover"> |
| | | {d.label} |
| | | </Popover> : d.label} |
| | | </div> : null } |
| | | </td> |
| | | ))} |
| | | </tr> |
| | | ))} |
| | | </tbody> |
| | | </table> |
| | | </Col> |
| | | ))} |
| | | </Row> : null} |
| | | {level === 'month' && monthlist ? <div className="month-calendar"> |
| | | <table> |
| | | <thead> |
| | | <tr> |
| | | <th>一</th><th>二</th><th>三</th><th>四</th><th>五</th><th>六</th><th>日</th> |
| | | </tr> |
| | | </thead> |
| | | <tbody> |
| | | {monthlist.sublist.map(cell => ( |
| | | <tr key={cell.week}> |
| | | {cell.sublist.map((d, i) => ( |
| | | <td key={i}> |
| | | {d ? <div className="month-wrap" onClick={() => this.triggerDay(d)}> |
| | | <div className="header"> |
| | | {d.label} |
| | | </div> |
| | | <ul className="content"> |
| | | {[1,3,7,18,22].includes(d.label) && listData.map((data, index) => ( |
| | | <li key={index} className="message" title={data.content}> |
| | | <Badge color={data.type} text={data.content} /> |
| | | </li> |
| | | ))} |
| | | </ul> |
| | | </div> : null } |
| | | </td> |
| | | ))} |
| | | </tr> |
| | | ))} |
| | | </tbody> |
| | | </table> |
| | | </div>: null} |
| | | {level === 'year' && monthlist ? <Row className="year-calendar"> |
| | | {datelist.map(item => ( |
| | | <Col span={8} key={item.month}> |
| | | <div className="year-wrap"> |
| | | <div className="header"> |
| | | {item.label} |
| | | </div> |
| | | <ul className="content"> |
| | | {['01', '05', '10'].includes(item.month) && listData.map((data, index) => ( |
| | | <li key={index} className="message" title={data.content}> |
| | | <Badge color={data.type} text={data.content} /> |
| | | </li> |
| | | ))} |
| | | </ul> |
| | | </div> |
| | | </Col> |
| | | ))} |
| | | </Row>: null} |
| | | </div> |
| | | </div> |
| | | ) |
| | | } |
| | | } |
| | | |
| | | export default Calendar |
New file |
| | |
| | | .mk-calendar { |
| | | width: 100%; |
| | | padding: 10px; |
| | | |
| | | .mk-calendar-control { |
| | | text-align: right; |
| | | .ant-select { |
| | | width: 90px; |
| | | margin-right: 15px; |
| | | } |
| | | } |
| | | .mk-calendar-content { |
| | | margin-top: 10px; |
| | | .day-calendar .ant-col { |
| | | min-height: 235px; |
| | | table { |
| | | width: 100%; |
| | | thead { |
| | | text-align: center; |
| | | color: #1890ff; |
| | | tr { |
| | | height: 30px; |
| | | } |
| | | tr:first-child { |
| | | th { |
| | | font-weight: 600; |
| | | font-size: 16px; |
| | | } |
| | | } |
| | | } |
| | | tbody { |
| | | text-align: center; |
| | | tr { |
| | | height: 28px; |
| | | td { |
| | | .day-wrap { |
| | | cursor: pointer; |
| | | transition: background 0.1s; |
| | | span { |
| | | display: inline-block; |
| | | width: 100%; |
| | | height: 100%; |
| | | } |
| | | } |
| | | .day-wrap:hover { |
| | | background: #bae7ff; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | } |
| | | } |
| | | .month-calendar { |
| | | table { |
| | | width: 100%; |
| | | thead { |
| | | text-align: center; |
| | | color: #1890ff; |
| | | font-size: 16px; |
| | | tr { |
| | | height: 35px; |
| | | } |
| | | } |
| | | tbody { |
| | | tr { |
| | | td { |
| | | position: relative; |
| | | width: 14.2%; |
| | | .month-wrap { |
| | | cursor: pointer; |
| | | height: 120px; |
| | | width: 100%; |
| | | transition: background 0.1s; |
| | | .header { |
| | | text-align: center; |
| | | font-size: 16px; |
| | | } |
| | | .content { |
| | | padding: 0 10px 10px; |
| | | height: 90px; |
| | | overflow-y: auto; |
| | | position: absolute; |
| | | left: 0; |
| | | right: 0; |
| | | .message { |
| | | width: 100%; |
| | | white-space: nowrap; |
| | | overflow: hidden; |
| | | text-overflow: ellipsis; |
| | | } |
| | | } |
| | | .content::-webkit-scrollbar { |
| | | width: 5px; |
| | | } |
| | | .content::-webkit-scrollbar-thumb { |
| | | border-radius: 5px; |
| | | box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.09); |
| | | background: rgba(0, 0, 0, 0.09); |
| | | } |
| | | .content::-webkit-scrollbar-track { |
| | | box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.05); |
| | | border-radius: 3px; |
| | | border: 1px solid rgba(0, 0, 0, 0.07); |
| | | background: rgba(0, 0, 0, 0); |
| | | } |
| | | } |
| | | .month-wrap:hover { |
| | | background: #e6f7ff; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | } |
| | | } |
| | | .year-calendar { |
| | | .year-wrap { |
| | | cursor: pointer; |
| | | transition: background 0.1s; |
| | | .header { |
| | | text-align: center; |
| | | font-size: 16px; |
| | | color: #1890ff; |
| | | } |
| | | .content { |
| | | padding: 5px 15px 10px; |
| | | height: 110px; |
| | | overflow-y: auto; |
| | | .message { |
| | | width: 100%; |
| | | white-space: nowrap; |
| | | overflow: hidden; |
| | | text-overflow: ellipsis; |
| | | } |
| | | } |
| | | .content::-webkit-scrollbar { |
| | | width: 5px; |
| | | } |
| | | .content::-webkit-scrollbar-thumb { |
| | | border-radius: 5px; |
| | | box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.09); |
| | | background: rgba(0, 0, 0, 0.09); |
| | | } |
| | | .content::-webkit-scrollbar-track { |
| | | box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.05); |
| | | border-radius: 3px; |
| | | border: 1px solid rgba(0, 0, 0, 0.07); |
| | | background: rgba(0, 0, 0, 0); |
| | | } |
| | | } |
| | | .year-wrap:hover { |
| | | background: #e6f7ff; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | .calendar-day-pop { |
| | | .message { |
| | | .ant-badge-status-text { |
| | | display: inline-block; |
| | | min-width: 100px; |
| | | max-width: 200px; |
| | | white-space: nowrap; |
| | | vertical-align: middle; |
| | | overflow: hidden; |
| | | text-overflow: ellipsis; |
| | | } |
| | | } |
| | | .ant-popover-inner-content { |
| | | min-height: 100px; |
| | | max-height: 200px; |
| | | overflow-y: auto; |
| | | } |
| | | .ant-popover-inner-content::-webkit-scrollbar { |
| | | width: 5px; |
| | | } |
| | | .ant-popover-inner-content::-webkit-scrollbar-thumb { |
| | | border-radius: 5px; |
| | | box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.09); |
| | | background: rgba(0, 0, 0, 0.09); |
| | | } |
| | | .ant-popover-inner-content::-webkit-scrollbar-track { |
| | | box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.05); |
| | | border-radius: 3px; |
| | | border: 1px solid rgba(0, 0, 0, 0.07); |
| | | background: rgba(0, 0, 0, 0); |
| | | } |
| | | } |
| | |
| | | obj_name: 'data', |
| | | arr_field: item.arr_field |
| | | } |
| | | let isSSO = item.database === 'sso' |
| | | |
| | | if (this.props.BID) { |
| | | param.BID = this.props.BID |
| | |
| | | |
| | | if (this.props.menuType === 'HS') { // 云端数据验证 |
| | | param.open_key = Utils.encrypt(param.secretkey, param.timestamp, true) |
| | | } else if (window.GLOB.systemType !== 'production') { |
| | | isSSO = false |
| | | } |
| | | |
| | | deffers.push( |
| | | new Promise(resolve => { |
| | | Api.getSystemCacheConfig(param, item.database === 'sso').then(res => { |
| | | Api.getSystemCacheConfig(param, isSSO).then(res => { |
| | | res.$search = item |
| | | resolve(res) |
| | | }) |
| | |
| | | }) |
| | | return |
| | | } |
| | | |
| | | Api.deleteMenuStorage(this.props.MenuID).then(() => { |
| | | this.setState({ |
| | | visible: false, |
| | | confirmLoading: false |
| | |
| | | this.props.reloadview() |
| | | }) |
| | | }) |
| | | }) |
| | | } |
| | | |
| | | render() { |
| | |
| | | |
| | | if (this.props.menuType === 'HS') { // 云端数据验证 |
| | | param.open_key = Utils.encrypt(param.secretkey, param.timestamp, true) |
| | | } else if (window.GLOB.systemType !== 'production') { |
| | | isSSO = false |
| | | } |
| | | |
| | | let defer = new Promise(resolve => { |
| | |
| | | }, |
| | | { |
| | | type: 'form', |
| | | label: CommonDict['model.form.color'], |
| | | subType: 'color', |
| | | url: '' |
| | | }, |
| | | { |
| | | type: 'form', |
| | | label: CommonDict['header.form.funcvar'], |
| | | subType: 'funcvar', |
| | | url: '' |
| | |
| | | value: '', // 实时内容 |
| | | options: null, // mode : text/javascript、text/x-mysql ; theme : cobalt - 黑底 |
| | | fullScreen: false, |
| | | style: null, |
| | | style: {fontSize: '18px', lineHeight: '32px'}, |
| | | display: true |
| | | } |
| | | |
| | |
| | | _style = {fontSize: '18px', lineHeight: '32px'} |
| | | } else if (size === 20) { |
| | | _style = {fontSize: '20px', lineHeight: '34px'} |
| | | } else if (size === 22) { |
| | | _style = {fontSize: '22px', lineHeight: '36px'} |
| | | } else if (size === 24) { |
| | | _style = {fontSize: '24px', lineHeight: '40px'} |
| | | } |
| | | |
| | | // 切换字体大小,刷新编辑器窗口,解决调整后的选择区域错乱问题 |
| | |
| | | > |
| | | <span style={{padding: '0 10px 0px 5px'}}>20px</span> |
| | | </Menu.Item> |
| | | <Menu.Item |
| | | style={style && style.fontSize === '22px' ? {backgroundColor: '#bae7ff'} : ''} |
| | | onClick={() => {this.changeSize(22)}} |
| | | > |
| | | <span style={{padding: '0 10px 0px 5px'}}>22px</span> |
| | | </Menu.Item> |
| | | <Menu.Item |
| | | style={style && style.fontSize === '24px' ? {backgroundColor: '#bae7ff'} : ''} |
| | | onClick={() => {this.changeSize(24)}} |
| | | > |
| | | <span style={{padding: '0 10px 0px 5px'}}>24px</span> |
| | | </Menu.Item> |
| | | </Menu> |
| | | ) |
| | | |
| | |
| | | value: 'textarea', |
| | | text: Formdict['model.form.textarea'] |
| | | }, { |
| | | value: 'color', |
| | | text: Formdict['model.form.color'] |
| | | }, { |
| | | value: 'funcvar', |
| | | text: Formdict['header.form.funcvar'] |
| | | }, |
| | |
| | | datemonth: ['label', 'field', 'initval', 'type', 'readonly', 'required', 'hidden', 'readin', 'blacklist'], |
| | | datetime: ['label', 'field', 'initval', 'type', 'readonly', 'required', 'hidden', 'readin', 'blacklist'], |
| | | textarea: ['label', 'field', 'initval', 'type', 'readonly', 'required', 'hidden', 'readin', 'blacklist', 'fieldlength', 'maxRows', 'encryption', 'interception'], |
| | | color: ['label', 'field', 'type', 'blacklist', 'required', 'hidden', 'readin'], |
| | | funcvar: ['label', 'field', 'type', 'blacklist', 'hidden'], |
| | | linkMain: ['label', 'field', 'type', 'readonly', 'required', 'hidden', 'fieldlength', 'blacklist'] |
| | | } |