| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930 |
- /**
- * @typedef {'list'|'form'|'detail'} ZinPageLayout
- */
- /**
- * @typedef {Object} ZinItemProps
- * @property {string} type
- * @property {string} text
- * @property {string} icon
- */
- /**
- * @typedef {Object} ZinFeatureBar
- * @property {ZinItemProps[]} [items]
- * @property {string} [current]
- * @property {string} [linkParams]
- */
- /**
- * @typedef {Object} ZinDtableProps
- * @property {Object[]} [cols]
- * @property {Object[]} [data]
- * @property {string[]} [plugins]
- * @property {boolean} [footPager]
- * @property {{items: Object[]}} [footToolbar]
- * @property {string[]} [footer]
- */
- /**
- * @typedef {Object} ZinFormGroup
- * @property {string} type
- * @property {string} [label]
- * @property {string} [labelClass]
- * @property {string|number} [labelWidth]
- * @property {string} [tip]
- * @property {string} [tipClass]
- * @property {string} [value]
- * @property {string} [placeholder]
- * @property {string} [class]
- * @property {string|ZinFormControl} [control]
- * @property {string} [name]
- * @property {string} [readonly]
- * @property {string} [disabled]
- * @property {string} [required]
- */
- /**
- * @typedef {Object} ZinFormRow
- * @property {ZinFormGroup[]} items
- * @property {string} [width]
- */
- /**
- * @typedef {Object} ZinPageInfo
- * @property {string} url
- * @property {string} title
- * @property {ZinPageLayout} layout
- * @property {string} moduleName
- * @property {string} methodName
- * @property {ZinFeatureBar} featureBar
- * @property {ZinItemProps[]} toolbar
- * @property {ZinDtableProps} dtable
- * @property {boolean} tableCustomCols
- * @property {{type: string}} sidebar
- * @property {{title: string, toolbar: ZinItemProps[]}} mainHeader
- * @property {{submitBtnText?: string, rows: ZinFormRow[]}} form
- */
- function getIconName(iconClass)
- {
- const names = iconClass.split(' ');
- const excludeSet = new Set(['sm', 'lg', '2x', '3x', '4x', 'xs', 'xl']);
- for(const name of names)
- {
- if(!name.length || !name.startsWith('icon-') || name.startsWith('icon-common-')) continue;
- const icon = name.replace('icon-', '');
- if(excludeSet.has(icon)) continue;
- return icon;
- }
- return '';
- }
- function convertClassName(className, exclude = 'dropdown-toggle input-group-btn')
- {
- const excludeSet = new Set(exclude.split(' '));
- return className.split(' ').reduce((list, name) =>
- {
- if(!name.length || excludeSet.has(name)) return list;
- if(name.endsWith('-primary')) list.push('primary');
- else if(name.endsWith('-secondary')) list.push('secondary');
- else if(name.endsWith('-warning')) list.push('warning');
- else if(name.endsWith('-success')) list.push('success');
- else if(name.endsWith('-danger')) list.push('danger');
- else if(name === 'btn-link') list.push('ghost');
- else list.push(name);
- return list;
- }, []).join(' ');
- }
- function getZinItemProps($item, props)
- {
- if($item.hasClass('dropdown-menu')) return;
- if($item.is('.btn-group,.dropdown'))
- {
- const items = [];
- $item.children().each(function()
- {
- const $this = $(this);
- if(!$this.is('a,.btn')) return;
- items.push(getZinItemProps($this));
- });
- return {type: 'btnGroup', items, ...props};
- }
- const $icon = $item.find('.icon,i');
- const item = {
- icon: $icon.length ? getIconName($icon.attr('class')) : undefined,
- text: $item.text().trim(),
- class: convertClassName($item.attr('class'), 'btn'),
- ...props
- };
- if($item.data('toggle') === 'dropdown')
- {
- item.type = 'dropdown';
- item.items = [];
- const $menu = $item.next('.dropdown-menu');
- if($menu.length)
- {
- const $listGroup = $menu.children('.list-group');
- if($listGroup.length)
- {
- $listGroup.children('a').each(function()
- {
- item.items.push($(this).text().trim());
- });
- }
- else
- {
- $menu.children('li').each(function()
- {
- item.items.push($(this).text().trim());
- });
- }
- }
- }
- return item;
- }
- function getFeatureBarInfo($)
- {
- const $featureBar = $('#mainMenu .btn-toolbar.pull-left,#mainMenu .btn-toolBar.pull-left');
- if(!$featureBar.length) return;
- const featureBar = {items: []};
- $featureBar.children().each(function()
- {
- const $this = $(this);
- const id = $this.attr('id') || '';
- if($this.is('.querybox-toggle'))
- {
- featureBar.items.push({type: 'searchToggle'});
- return;
- }
- if($this.is('.checkbox-primary'))
- {
- featureBar.items.push({type: 'checkbox', text: $this.find('label').text().trim() || $this.text().trim()});
- return;
- }
- if($this.is('a.btn'))
- {
- if($this.hasClass('btn-active-text')) featureBar.current = id ? id.replace('Tab', '') : ($this.find('.text').text().trim() || $this.text().trim());
- return;
- }
- });
- if(!featureBar.items.length) return;
- return featureBar;
- }
- function getToolbarInfo($)
- {
- const $toolbar = $('#mainMenu .btn-toolbar.pull-right');
- if(!$toolbar.length) return;
- const toolbar = [];
- $toolbar.children().each(function()
- {
- toolbar.push(getZinItemProps($(this)));
- });
- return toolbar.length ? toolbar : null;
- }
- function getTableInfo($)
- {
- const info = {};
- const $table = $('#mainContent .table:not(.table-form)').first();
- if(!$table.length) return;
- if($('#mainContent .datatable').length)
- {
- return alert('zin: Please switch the table to simple table mode.');
- }
- const colTypesMap =
- {
- name: 'link',
- pri: 'pri',
- id: 'id',
- status: 'status',
- actions: 'actions',
- progress: 'circleProgress',
- assignedTo: 'avatarBtn',
- };
- const getColName = ($cell) => ($cell.attr('class').toLowerCase().split(' ').find(x => x.startsWith('c-')) || '').replace('c-', '');
- /**
- * @type {ZinDtableProps}
- */
- const setting = {cols: [], data: [], plugins: [], footer: []};
- let flexed = false;
- $table.find('thead>tr:first>th').each(function()
- {
- const $this = $(this);
- const data = $this.data();
- const title = $this.attr('title') || $this.text().trim();
- const name = getColName($this) || title;
- if(!flexed && data.flex) flexed = true;
- const col =
- {
- title,
- name,
- width: data.width.endsWith('px') ? Number.parseInt(data.width, 10) : 200,
- flex: data.width === 'auto' ? 1 : 0,
- fixed: data.flex ? false : (flexed ? 'right' : 'left'),
- type: colTypesMap[name],
- sortType: !!$this.find('a.sort-up,a.sort-down,a.header').length
- };
- setting.cols.push(col);
- });
- $table.find('tbody>tr').each(function(idx)
- {
- const $this = $(this);
- const rowData = $this.data();
- $this.children('td').each(function()
- {
- $td = $(this);
- const name = getColName($td);
- if(name && rowData[name] === undefined)
- {
- rowData[name] = $td.text().trim();
- if(name === 'progress' && rowData[name]) rowData[name] = rowData[name].replace('%', 0);
- }
- });
- if(rowData.id === undefined) rowData.id = idx;
- rowData.id = String(rowData.id);
- setting.data.push(rowData);
- if(setting.data.length > 5) return;
- });
- const tableJs = $('#mainContent [data-ride="table"]').data('zui.table');
- if(tableJs)
- {
- if(tableJs.options.checkable) setting.plugins.push('checkable');
- if(tableJs.options.sortable) setting.plugins.push('sortable');
- if(tableJs.options.nested || $table.find('tbody>tr.table-parent,tbody>tr.has-child').length) setting.plugins.push('nested');
- }
- else
- {
- if($table.find('td .checkbox-primary').length) setting.plugins.push('checkable');
- if($table.hasClass('has-sort-head')) setting.plugins.push('sortable');
- if($table.find('tbody>tr.table-parent,tbody>tr.has-child').length) setting.plugins.push('nested');
- }
- if(setting.plugins.includes('checkable'))
- {
- const idCol = setting.cols.find(x => x.name === 'id');
- if(idCol) idCol.checkbox = true;
- }
- if(setting.plugins.includes('nested') && !setting.cols.find(x => x.nestedToggle))
- {
- const nameCol = setting.cols.find(x => x.name === 'name');
- if(nameCol) nameCol.nestedToggle = true;
- }
- const $footer = $('#mainContent .table-footer');
- if($footer.length)
- {
- if(setting.plugins.includes('checkable')) setting.footer.push('checkbox', 'divider');
- const $actions = $footer.find('.table-actions,.btn-toolbar');
- if($actions.length)
- {
- const actions = [];
- $actions.children().each(function()
- {
- actions.push(getZinItemProps($(this)));
- });
- if(actions.length) setting.footer.push('toolbar');
- setting.footToolbar = {items: actions.filter(Boolean)};
- setting.footer.push('toolbar');
- }
- const $statistic = $footer.find('.table-statistic');
- if($statistic.length) setting.footer.push($statistic.text().trim());
- const $pager = $footer.find('.pager');
- if($pager.length)
- {
- setting.footer.push('flex', 'pager');
- setting.footPager = true;
- }
- }
- info.dtable = setting;
- info.layout = 'list';
- info.sidebar = $('#sidebar').length ? {type: 'moduleMenu'} : undefined;
- if($('#tableCustomBtn').length) info.tableCustomCols = true;
- return info;
- }
- function getMainHeaderInfo($)
- {
- const $mainHeader = $('#mainContent .main-header');
- if(!$mainHeader.length) return;
- const mainHeader = {title: $mainHeader.find('h2').text().trim()};
- const $toolbar = $mainHeader.find('.btn-toolbar');
- if($toolbar.length)
- {
- const toolbar = [];
- $toolbar.children().each(function()
- {
- toolbar.push(getZinItemProps($(this)));
- });
- mainHeader.toolbar = toolbar.filter(Boolean);
- }
- return mainHeader;
- }
- function getFormGroupProps($control)
- {
- if($control.hasClass('input-group'))
- {
- const info = {type: 'inputGroup', items: []};
- $control.children('.form-control,.input-group-addon,.input-group-btn').each(function()
- {
- const $this = $(this);
- if($this.hasClass('form-control')) info.items.push(getFormGroupProps($this));
- else if($this.hasClass('input-group-addon')) info.items.push({type: 'addon', text: $this.text().trim()});
- else if($this.hasClass('input-group-btn')) info.items.push({type: 'btn', ...getZinItemProps($this)});
- });
- return info;
- }
- if($control.hasClass('file-input-list'))
- {
- const $file = $control.find('input[type="file"]');
- return {type: 'file', name: $control.attr('name') || $file.attr('name'), multiple: $file.prop('multiple')};
- }
- if($control.hasClass('checkbox-primary'))
- {
- const $checkboxes = $control.find('input[type="checkbox"]');
- const info = {type: 'checkList', name: $control.attr('name') || $checkboxes.attr('name'), items: [], inline: true};
- $checkboxes.each(function()
- {
- const $checkbox = $(this);
- info.items.push({checked: $checkbox.prop('checked'), value: $checkbox.val(), disabled: $checkbox.prop('disabled'), text: $checkbox.parent().find('label').text().trim()});
- if(info.items.length > 5) return;
- });
- if($checkboxes.closest('td').prev('td').length) info.class = 'ml-4';
- return info;
- }
- if($control.hasClass('radio') || $control.hasClass('radio-inline'))
- {
- const $radioes = $control.closest('td').find('input[type="radio"]');
- const info = {type: 'radioList', inline: $control.hasClass('radio-inline'), name: $radioes.attr('name'), items: []};
- $radioes.each(function()
- {
- const $radio = $(this);
- info.items.push({checked: $radio.prop('checked'), value: $radio.val(), disabled: $radio.prop('disabled'), text: $radio.parent().text().trim()});
- if(info.items.length > 5) return;
- });
- return info;
- }
- const info = {name: $control.attr('name'), id: $control.attr('id'), placeholder: $control.attr('placeholder'), value: $control.val(), disabled: $control.prop('disabled'), type: $control.is('input') ? $control.attr('type') : null};
- if($control.attr('onchange')) info.onchange = $control.attr('onchange').split('(').shift().trim();
- if($control.is('textarea'))
- {
- info.rows = +$control.attr('rows') || null;
- info.type = $control.data('keditor') ? 'editor' : 'textarea';
- return info;
- }
- if($control.is('select'))
- {
- info.items = [];
- info.type = $control.prop('multiple') ? {type: 'picker', multiple: true} : 'picker';
- $control.children().each(function()
- {
- const $option = $(this);
- info.items.push({value: $option.attr('value'), text: $option.text().trim()});
- if(info.items.length > 5) return;
- });
- return info;
- }
- if($control.is('.form-date,.form-time,.form-datetime'))
- {
- info.type = $control.hasClass('form-date') ? 'date' : $control.hasClass('form-time') ? 'time' : 'datetime';
- }
- return info;
- }
- function getFormInfo($)
- {
- const $form = $('#mainContent').find('.table-form,.main-form>.table');
- if(!$form.length) return;
- const form = {items: [], grid: 4, vars: [], hiddens: []};
- const $submit = $form.find('#submit');
- if($submit.length)
- {
- form.grid = +$submit.closest('td').attr('colspan') || 1;
- form.submitBtnText = $submit.text().trim();
- if(form.submitBtnText === '保存') form.submitBtnText = null;
- }
- $form.find('tbody>tr').each(function()
- {
- const $tr = $(this);
- if($tr.find('#submit').length) return;
- let label = '';
- const formRow = {items: [], hidden: $tr.is(':hidden')};
- $tr.children().each(function()
- {
- const $thd = $(this);
- if($thd.is('th'))
- {
- label = $thd.text().trim();
- }
- else
- {
- const $control = $thd.find('.form-control,.input-group,textarea.kindeditor,.file-input-list,.checkbox-primary,.radio,.radio-inline').first();
- if(!$control.length) return;
- const colspan = +$thd.attr('colspan') || 1;
- const width = colspan !== form.grid ? `${colspan}/${form.grid}` : null;
- const formGroup = {label: label, required: $thd.hasClass('required'), width: width, value: ''};
- $.extend(formGroup, getFormGroupProps($control));
- if(!formGroup.name && formGroup.type !== 'inputGroup') return;
- if(formGroup.items)
- {
- if(formGroup.name)
- {
- form.vars.push({name: `${formGroup.name.replace('[]', '')}Options`, value: formGroup.items.slice(0, Math.min(formGroup.items.length, 5))});
- }
- else if(formGroup.type === 'inputGroup')
- {
- formGroup.items.forEach(item =>
- {
- if(item.items && item.name) form.vars.push({name: `${item.name.replace('[]', '')}Options`, value: item.items.slice(0, Math.min(item.items.length, 5))});
- });
- }
- }
- formRow.items.push(formGroup);
- label = '';
- }
- });
- if(formRow.items.length) form.items.push(formRow);
- });
- $form.find('input[type="hidden"]').each(function()
- {
- const $input = $(this);
- form.hiddens.push({name: $input.attr('name'), value: $input.val()});
- });
- return {form, layout: 'form'};
- }
- /**
- * Get page info for zin
- * @param {Window} win
- * @returns {ZinPageInfo}
- */
- function getPageInfo(win)
- {
- const {document, config, $, pageVars} = win;
- return $.extend(
- {
- url: win.location.href,
- title: document.title.replace(' - 禅道', ''),
- moduleName: config.currentModule,
- methodName: config.currentMethod,
- featureBar: getFeatureBarInfo($),
- toolbar: getToolbarInfo($),
- mainHeader: getMainHeaderInfo($),
- vars: pageVars,
- }, getTableInfo($), getFormInfo($));
- }
- /**
- * Indent string lines
- * @param {string[]|string} lines
- * @param {number} [indent=0]
- * @returns {string[]|string}
- */
- function indentLines(lines, indent = 0)
- {
- const isArray = Array.isArray(lines);
- if(!isArray) lines = lines.split('\n');
- const indentStr = ' '.repeat(indent * 4);
- lines = lines.map(x => x.includes('\n') ? indentLines(x, indent) : (indentStr + x));
- return isArray ? lines : lines.join('\n');
- }
- /**
- * Generate item statement
- * @param {ZinItemProps} name
- * @param {any} value
- * @param {number} [indent=0]
- * @returns {string}
- */
- function genSetStatement(name, value, indent = 0)
- {
- return indentLines(`set::${name}(${JSON.stringify(value)})`, indent);
- }
- /**
- * Find dotted var name from an object
- */
- function findVarName(val, vars, preName = '')
- {
- if(vars === val) return preName;
- if(!vars || typeof vars !== 'object') return '';
- const props = Object.keys(vars);
- for(const prop of props)
- {
- if(!Number.isNaN(+prop)) return (preName.length && val === vars[prop]) ? `${preName}[${prop}]` : '';
- const name = findVarName(val, vars[prop], preName.length ? `${preName}->${prop}` : prop);
- if(name.length) return name;
- }
- return '';
- }
- /**
- * Get var name matches the given value
- */
- function getVarName(val)
- {
- if(!pageInfo || !pageInfo.vars || typeof val === 'object') return;
- return findVarName(val, pageInfo.vars);
- }
- /**
- * Gen value to php statement
- * @param {any} value
- * @param {number} indent
- * @returns {string}
- */
- function genValueStatement(value, indent = 0, join = '\n')
- {
- if(value === undefined) return;
- if(value === null) return indentLines('NULL', indent);
- if(Array.isArray(value))
- {
- return indentLines(`array(${value.map(val => genValueStatement(val, indent, join)).join(', ')})`, indent);
- }
- if(typeof value === 'object')
- {
- return genArrayStatement(value, null, indent, '', '', join);
- }
- if(typeof value === 'string' && value.startsWith('RAW_PHP<')) return indentLines(value.substring(8, value.length - 8), indent);
- if(typeof value !== 'object' && value !== '')
- {
- const varName = getVarName(value);
- if(varName.length) return `$${varName}`;
- }
- return indentLines(JSON.stringify(value), indent);
- }
- /**
- * Generate php array statement
- * @param {Reacord<string, any>} array Php array object
- * @param {string|string[]} props Prop names list
- * @param {number} [indent=0]
- * @returns {string}
- */
- function genArrayStatement(array, props = null, indent = 0, prefix = '', suffix = '', join = '\n')
- {
- if(typeof props === 'string') props = props.split(',');
- else if(props === null) props = Object.keys(array);
- const propLines = props.reduce((lines, prop) =>
- {
- const value = genValueStatement(array[prop], 0, join);
- if(typeof value === 'string' && value.length)
- {
- lines.push(`'${prop}' => ${value}`);
- }
- return lines;
- }, []);
- if(!propLines.length) return [indentLines('array()', indent)];
- return indentLines(
- [
- `${prefix}array`,
- '(',
- indentLines(propLines.join(`,${join === '' ? ' ' : join}`), join === '' ? 0 : (1 + indent)),
- `)${suffix}`
- ], indent).join(join);
- }
- /**
- * Generate item statement
- * @param {ZinItemProps} item
- * @param {number} [indent=0]
- * @returns {string}
- */
- function genItemStatement(item, indent = 0)
- {
- if(item.type === 'searchToggle') return indentLines('li(searchToggle())', indent);
- return genArrayStatement(item, null, indent, 'item(set(', '))');
- }
- /**
- * Generate php variable statement
- * @param {string} name
- * @param {any} value
- * @param {number} indent
- * @param {string} join
- */
- function genVarStatement(name, value, indent = 0, join = '')
- {
- return indentLines(`$${name} = ${genValueStatement(value, indent, join)};`, indent);
- }
- function genInputGroupItemStatement(item, indent = 0)
- {
- if(item.type === 'addon') return indentLines(genValueStatement(item.text), indent);
- if(item.type === 'btn') return indentLines(genArrayStatement(item, null, 0, 'btn(set(', '))'), indent);
- item = $.extend({}, item);
- if(typeof item.type === 'object') item = $.extend(item, item.type);
- if(item.items) item.items = `RAW_PHP<$${item.name.replace('[]', '')}Options>RAW_PHP`;
- return indentLines(genArrayStatement(item, null, 0, 'control(set(', '))'), indent);
- }
- function genInputGroupStatement(items, indent = 0)
- {
- return indentLines(
- [
- 'inputGroup',
- '(',
- items.map(item => genInputGroupItemStatement(item, 1)).join(',\n'),
- ')'
- ], indent).join('\n');
- }
- function genFormGroupStatement(formGroup, indent = 0)
- {
- return indentLines(
- [
- 'formGroup',
- '(',
- indentLines(
- [
- formGroup.width ? `set::width(${JSON.stringify(formGroup.width)})` : null,
- formGroup.name ? `set::name(${JSON.stringify(formGroup.name)})` : null,
- formGroup.label ? `set::label(${genValueStatement(formGroup.label)})` : null,
- formGroup.class ? `set::className(${JSON.stringify(formGroup.class)})` : null,
- formGroup.disabled ? 'set::disabled(true)' : null,
- formGroup.required ? 'set::required(true)' : null,
- formGroup.value ? `set::value(${JSON.stringify(formGroup.value)})` : null,
- formGroup.type && formGroup.type !== 'inputGroup' ? `set::control(${JSON.stringify(formGroup.type)})` : null,
- formGroup.id && formGroup.id !== formGroup.name ? `set::id(${JSON.stringify(formGroup.id)})` : null,
- formGroup.items && formGroup.type !== 'inputGroup' ? `set::items($${formGroup.name.replace('[]', '')}Options)` : null,
- formGroup.type === 'inputGroup' ? genInputGroupStatement(formGroup.items) : null,
- ].filter(x => typeof x === 'string'), 1).join(',\n'),
- ')'
- ].filter(x => typeof x === 'string'), indent).join('\n');
- }
- function getFormRowStatement(formRow, indent = 0)
- {
- return indentLines(
- [
- 'formRow',
- '(',
- formRow.hidden ? ' set::hidden(true),' : null,
- formRow.items.map(item => genFormGroupStatement(item, 1)).join(',\n'),
- ')'
- ].filter(Boolean), indent).join('\n');
- }
- /**
- * Get page template
- * @param {ZinPageInfo} info
- * @returns {string}
- */
- function getPageTemplate(info)
- {
- /** @type {string[]} */
- const lines = [];
- const {featureBar = {}, toolbar, dtable, form, mainHeader = {}} = info;
- const variables = [];
- const widgets = [];
- if(featureBar && featureBar.current && !info.vars.browseType)
- {
- lines.push
- (
- '/* zin: Set variable $browseType to store the current active item in feature bar. */',
- `${genVarStatement('browseType', featureBar.current)} // the variable may already defined in control method.`,
- ''
- );
- }
- if(dtable)
- {
- lines.push('/* zin: Set variables to define columns and rows data for dtable. */');
- lines.push(genVarStatement('dtableCols', dtable.cols));
- lines.push(genVarStatement('dtableRows', dtable.data));
- variables.push('dtableCols', 'dtableRows');
- if(dtable.footToolbar)
- {
- variables.push('dtableToolbar');
- lines.push(genVarStatement('dtableToolbar', dtable.footToolbar));
- }
- }
- if(form && form.vars.length)
- {
- lines.push('/* zin: Set variables to define picker options for form. */');
- if(mainHeader.title !== info.title) lines.push(genVarStatement('formTitle', mainHeader.title));
- form.vars.forEach(item => lines.push(genVarStatement(item.name, item.value)));
- variables.push(...form.vars.map(item => item.name));
- }
- lines.push('\n\n/* ====== Define the page structure with zin widgets ====== */\n');
- if(featureBar && featureBar.items)
- {
- widgets.push('featureBar');
- lines.push
- (
- '/* zin: Define the feature bar on main menu. */',
- 'featureBar',
- '(',
- indentLines(
- [
- featureBar.current ? 'set::current($browseType)' : null,
- featureBar.linkParams ? `set::linkParams(${JSON.stringify(featureBar.linkParams)}),` : null,
- ...featureBar.items.map(item => genItemStatement(item))
- ].filter(x => typeof x === 'string'), 1).join(',\n'),
- ');',
- ''
- );
- }
- if(toolbar && toolbar.length)
- {
- lines.push
- (
- '/* zin: Define the toolbar on main menu. */',
- 'toolbar',
- '(',
- indentLines(toolbar.map(item => genItemStatement(item)).filter(x => typeof x === 'string'), 1).join(',\n'),
- ');',
- ''
- );
- }
- if(info.sidebar)
- {
- widgets.push('sidebar');
- lines.push
- (
- '/* zin: Define the sidebar in main content. */',
- 'sidebar',
- '(',
- ` ${info.sidebar.type}()`,
- ');',
- ''
- );
- }
- if(dtable)
- {
- widgets.push('dtable');
- lines.push
- (
- '/* zin: Define the dtable in main content. */',
- 'dtable',
- '(',
- indentLines(
- [
- "set::className('shadow rounded')",
- 'set::cols($dtableCols)',
- 'set::data($dtableRows)',
- dtable.plugins ? `set::plugins(array(${dtable.plugins.map(x => JSON.stringify(x)).join(', ')}))` : null,
- (dtable.plugins && dtable.plugins.includes('checkable')) ? 'set::checkable(true)' : null,
- (dtable.plugins && dtable.plugins.includes('nested')) ? 'set::nested(true)' : null,
- dtable.footToolbar ? 'set::toolbar($dtableToolbar)' : null,
- dtable.footPager ? 'set::footPager(usePager())' : null,
- dtable.footer ? `set::footer(array(${dtable.footer.map(x => JSON.stringify(x)).join(', ')}))` : null,
- ].filter(x => typeof x === 'string'), 1).join(',\n'),
- ');',
- ''
- );
- }
- else if(form)
- {
- widgets.push('formPanel', 'formRow', 'inputGroup', 'input', 'control');
- const mainHeader = info.mainHeader || {};
- lines.push
- (
- '/* zin: Define the form in main content. */',
- 'formPanel',
- '(',
- indentLines
- ([
- mainHeader.title !== info.title ? "set::title($formTitle), // The form title is diffrent from the page title" : null,
- form.items.map((formRow) =>
- {
- if(!formRow.hidden && formRow.items.length === 1)
- {
- return genFormGroupStatement(formRow.items[0]);
- }
- return getFormRowStatement(formRow);
- }).join(',\n'),
- ].filter(x => typeof x === 'string'), 1).join(',\n'),
- ');',
- ''
- );
- }
- lines.push
- (
- '\n/* ====== Render page ====== */\n',
- 'render();'
- );
- lines.unshift(
- '<?php',
- 'declare(strict_types=1);',
- '/**',
- ` * The ${info.methodName} view file of ${info.moduleName} module of ZenTaoPMS.`,
- ' *',
- ' * @copyright Copyright 2009-2023 禅道软件(青岛)有限公司(ZenTao Software (Qingdao) Co., Ltd. www.zentao.net)',
- ' * @license ZPL(https://zpl.pub/page/zplv12.html) or AGPL(https://www.gnu.org/licenses/agpl-3.0.en.html)',
- ' * @author yourname<yourname@easycorp.ltd>',
- ` * @package ${info.moduleName}`,
- ' * @link http://www.zentao.net',
- ' */',
- '',
- '/*',
- ' ======= Attention ======',
- '',
- ' This file is generated by zin-tool, you should check the following to-do list.',
- '',
- ` + Familiar with the use of these widgets in zin: ${widgets.join(', ')}.`,
- variables.length ? ` + Check the following variables which used in widgets: ${variables.map(x => `$${x}`).join(', ')}.` : null,
- featureBar.items && featureBar.items.length ? ` + Check the ${featureBar.items.length} items definition in featureBar widget.` : null,
- toolbar && toolbar.length ? ` + Check the ${toolbar.length} items definition in toolbar widget.` : null,
- ` + Check the origin code in module/${info.moduleName}/view/${info.methodName}.html.php, and ensure that all features have been implemented.`,
- ` + Check the origin js code in module/${info.moduleName}/js/common.js and module/${info.moduleName}/js/${info.methodName}.js.`,
- ` + Check the origin css code in module/${info.moduleName}/css/common.css and module/${info.moduleName}/css/${info.methodName}.css.`,
- ' + Remove the comments which start with "zin:".',
- ' + Test according to the new design draft and the original implementation.',
- ' */',
- '',
- 'namespace zin;',
- '',
- '/* ====== Preparing and processing page data ====== */',
- '',
- );
- return lines.filter(x => typeof x === 'string').join('\n');
- }
- function zin(win)
- {
- if(!win)
- {
- if(config.currentModule === 'index' && config.currentMethod === 'index') win = $.apps.getLastApp().$iframe[0].contentWindow;
- else win = window;
- }
- if(!win.config) return $.zui.messager.danger('zin: Current page is not supported yet, may be it rendered by zin already!');
- const pageInfo = window.pageInfo = getPageInfo(win);
- if(!pageInfo) return $.zui.messager.danger('zin: Current page is not supported temporarily.');
- const template = getPageTemplate(pageInfo);
- console.log('> [ZIN-TOOL] pageInfo', pageInfo);
- console.log('> [ZIN-TOOL] template', template);
- const $dialog = bootbox.dialog(
- {
- title: '<strong><i class="icon icon-magic"></i> zin view file</strong>',
- message: `<div class="strong">module/${pageInfo.moduleName}/ui/${pageInfo.methodName}.html.php</div><pre class="prettyprint"><code></code></pre>`,
- size: 'large',
- buttons:
- {
- copy:
- {
- label: 'Copy to clipboard',
- className: 'btn-primary',
- callback: () =>
- {
- navigator.clipboard.writeText(template);
- $.zui.messager.success(`zin view file copied to clipboard, you can create file module/${pageInfo.moduleName}/ui/${pageInfo.methodName}.html.php and paste to it.`);
- }
- },
- close:
- {
- label: 'Close',
- className: 'btn-default',
- callback: () => {}
- },
- }
- });
- $dialog.find('.modal-dialog').width(1200).find('pre>code').text(template);
- if(!window.prettyPrint) $.getScript(config.webRoot + 'js/kindeditor/plugins/code/prettify.js', () => window.prettyPrint());
- else window.prettyPrint();
- }
- $(function()
- {
- if(!config) return;
- if(config.currentModule === 'index' && config.currentMethod === 'index')
- {
- $('<button type="button" class="btn btn-danger code">zin()</button>').prependTo('#globalBarLogo').on('click', () =>
- {
- const app = $.apps.getLastApp();
- if(!app) return;
- zin(app.$iframe[0].contentWindow);
- });
- }
- });
|