view.getRenderer = function (tpl) { var target = this.getTarget(tpl) || tpl; var renderer = etplEngine.getRenderer(target); if (!renderer) { renderer = etplEngine.compile(tpl); } return renderer; };
/** * 编译模版 * * @public * @param {View} view 视图对象 * @param {string|Array.<string>} str 模版 */ function compileTemplate(view, str) { if (Array.isArray(str)) { str = str.join(''); } var config = extend({}, view.templateConfig || {}); var filters = {}; if (config.filters) { filters = config.filters; delete config.filters; } // 新建模版引擎 var tplEngine = new etpl.Engine(config); Object.keys(filters).forEach(function (key) { tplEngine.addFilter(key, filters[key]); }); // 保存默认render var defaultRender = tplEngine.compile(str); // 如果没有默认render就是模版编译失败了 if (!defaultRender) { throw new Error('compile template fail'); } // 保存原始的render var orgRender = tplEngine.render; view.template = tplEngine; // 重载render以支持无target的情况 view.template.render = function (name, data) { // 扩展通用模版数据 data = extend({}, view.templateData, data); var res = ''; // 如果只有一个参数 或者target为null // 则使用默认render if (arguments.length < 2 || !name) { res = defaultRender(name || data); } else { res = orgRender.call(this, name, data); } return res; }; }
/** * 渲染 esui.Select 组件并绑定 change 事件 * * @param {Object} componentsConf 组件的配置,就是 json 中的配置 * @param {er.View} view 当前 View 实例 */ function renderElem(componentsConf, view) { formSubmitData.submitName = componentsConf.submitName || ''; var containerId = componentsConf.containerId; var containerDom = $('#' + containerId); var etplEngine = new etpl.Engine(); etplEngine.compile(tpl); var componentList = componentsConf.list; var etplRenderOpts = { componentList: componentList, submitName: formSubmitData.submitName }; containerDom.html( etplEngine.render('selectAddr', etplRenderOpts) ); esui.init( containerDom[0], { viewContext: view.viewContext } ); // data 只有在修改表单的时候才会有 var editData = componentsConf.data; for (var i = 0, len = componentList.length; i < len; i++) { var component = componentList[i]; view.get('prov' + formSubmitData.submitName + component.index).updateDatasource(povince.getAll()); // 默认选中北京,如果是修改,那么回填之前的值 view.get('prov' + formSubmitData.submitName + component.index).setValue( (editData && editData[i]) ? editData[i].prov : 0 ); view.get('prov' + formSubmitData.submitName + component.index).on( 'change', lib.bind( changeProv, { view: view, index: component.index, formSubmitData: formSubmitData } ) ); view.get('city' + formSubmitData.submitName + component.index).updateDatasource( city.getCityByProvince(view.get('prov' + formSubmitData.submitName + component.index).getValue()) ); view.get('city' + formSubmitData.submitName + component.index).setValue( (editData && editData[i]) ? editData[i].city : 0 ); view.get('city' + formSubmitData.submitName + component.index).on( 'change', lib.bind( changeCity, { view: view, index: component.index, formSubmitData: formSubmitData } ) ); view.get('addr' + formSubmitData.submitName + component.index).setValue( (editData && editData[i]) ? editData[i].addr : '' ); view.get('addr' + formSubmitData.submitName + component.index).on( 'change', lib.bind( changeAddr, { view: view, index: component.index, formSubmitData: formSubmitData } ) ); formSubmitData.dataList.push({ prov: view.get('prov' + formSubmitData.submitName + component.index).getValue(), city: view.get('city' + formSubmitData.submitName + component.index).getValue(), addr: view.get('addr' + formSubmitData.submitName + component.index).getValue() || '' }); } // 初始化的时候也需要 fire // 因为可能编辑 form 的时候,不改动这个组件的值 exports.fire( formSubmitData.submitName + 'formSubmitDataChange', { curFormData: formSubmitData, componentCallback: submitDataFilter } ); return formSubmitData; }
function createBlogPages(env) { var etplEngin = new etpl.Engine(); etplEngin.compile(fs.readFileSync(path.join(__dirname, 'site/template.tpl.html')).toString()); etplEngin.addFilter('md', function (mdCode) { return marked(mdCode) .replace(/url\(\.\/imgs\//g, 'url(../../imgs/') .replace(/src="\.\/imgs\//g, 'src="../../imgs/'); }); var config = JSON.parse(fs.readFileSync('./site/' + env + '.conf')); var mdFiles = fs.readdirSync(path.join(__dirname, 'blogs')); mdFiles = mdFiles.filter(function (fileName) { return /\.md$/.test(fileName); }).map(function (fileName) { var fullPath = path.join(__dirname, 'blogs', fileName); var content = fs.readFileSync(fullPath).toString(); var time = getBlogTime(content); return { fileName: fileName, path: fullPath, content: content, time: time, timeText: moment(time).format('YYYY-MM-DD HH:mm:ss'), brief: getBlogBrief(content), title: fileName.slice(0, -3) }; }); var blogs = mdFiles.sort(function (a, b) { return b.time.getTime() - a.time.getTime(); }); blogs.forEach(function (blog) { fs.writeFileSync( path.join(__dirname, '/site/blogs', blog.fileName.slice(0, -3) + '.html'), etplEngin.getRenderer('blogPage')(getData({blog: blog})) ); }); fs.writeFileSync( path.join(__dirname, 'site/index.html'), etplEngin.getRenderer('indexPage')(getData({blogs: blogs})) ); fs.writeFileSync( path.join(__dirname, '/README.md'), etplEngin.getRenderer('readmeTitleList')(getData({blogs: blogs})) ); function getData(local) { return u.extend({}, config, local); } function getBlogBrief(mdStr) { var briefMatch = mdStr.match(/<!--\s*config.brief:(.+)-->/); if (briefMatch && briefMatch.length >= 2) { return briefMatch[1].replace(/^\s|\s$/g, ''); } return ''; } // 拿到 blog 发布时间 function getBlogTime(mdStr) { var timeMatch = mdStr.match(/<!--\s*config.time:\s*([0-9\-:\s]+)\s*-->/); if (timeMatch && timeMatch.length >= 2) { return new Date(timeMatch[1]); } return new Date(); } }
define(function (require) { var dynamicAddFormTpl = require('er/tpl!./dynamicForm.tpl.html'); var $ = require('jquery'); var _ = require('underscore'); var util = require('er/util'); var etpl = require('etpl'); var esui = require('esui'); var Deferred = require('er/Deferred'); var FormView = require('./FormView'); var dynamicUtil = require('./dynamicUtil'); var LANG_PKG = require('../lang').getLangPkg(); var etplEngine = new etpl.Engine(); etplEngine.compile(dynamicAddFormTpl); /** * 动态 Form View 基类 * * @extends FormView * @constructor */ function DynamicFormView() { FormView.apply(this, arguments); } DynamicFormView.prototype.template = 'dynamicForm'; /** * form 提交成功后的回调函数 */ DynamicFormView.prototype.successFunc = function () {}; /** * form 提交成功后的回调函数 * 常规的错误处理函数已经在 ejson 中封装,会弹出错误信息 * 这里的 errorFunc 是为了做一些自定义的错误处理 */ DynamicFormView.prototype.errorFunc = function () {}; /** * 容器渲染完毕后做一些准备工作 * 例如控制元素可见性及绑定事件等DOM操作 * * @override */ DynamicFormView.prototype.enterDocument = function () { var me = this; var model = me.model; var formItemConfigs = model.get('formItemConfigs'); if (_.isArray(formItemConfigs)) { buildUIProperties( formItemConfigs, model ).then( function (ret) { // 触发 submit 事件的参数 var submitEvtArgs = { componentData: {} }; var properties = ret.properties; // DynamicFormView.prototype.uiProperties = properties; me.uiProperties = properties; // 要挂载在 me 上,这样子类才能生效 // 设置 uiEvents 要在执行父类的 enterDocument 之前 me.uiEvents = _.extend( {}, me.uiEvents, { 'form:submit': function (e) { submitEvtArgs = _.extend( submitEvtArgs, { form: me.getFormInstance(), ideaInfo: model.get('ideaInfo') // 修改才有的 } ); me.fire('submit', submitEvtArgs); } } ); FormView.prototype.enterDocument.apply(me, arguments); initTip(me, properties); // 对 components 做处理 var components = properties.components; if (components.length) { dealComponents(components, submitEvtArgs, me); } var dynamicItems = properties.dynamicItems; if (dynamicItems) { dealDynamicItems(dynamicItems, me); } } ); } }; /** * 动态添加表单项的处理 * * @param {Object} dynamicItems 要添加的表单项的配置 * @param {View} view 当前的 View 对象 */ function dealDynamicItems(dynamicItems, view) { $('.add-items').each( function (i, v) { v = $(v); var refIdentify = v.data('refIdentify'); var maxCount = dynamicItems[refIdentify].maxCount; var candidateAddItemsConfig = dynamicItems[refIdentify].list; var alreadyAddItemsConfig = dynamicItems[refIdentify].alreadyAddItemsConfig; var len; if (alreadyAddItemsConfig && (len = alreadyAddItemsConfig.length)) { v.attr('data-already-addcount', len); for (var j = 0, l = alreadyAddItemsConfig.length; j < l; j++) { var addItemContainer = $('<div class="add-items-container"></div>'); var html = ''; html += etplEngine.render('dynamicForm', { formItemConfigs: alreadyAddItemsConfig[j], i18n: { 'QXZ': LANG_PKG.QXZ, 'ZDXZ': LANG_PKG.ZDXZ, 'Ge': LANG_PKG.Ge, 'BT': LANG_PKG.BT } }); addItemContainer.attr('data-index', alreadyAddItemsConfig[j].index).html(html); v.parents('.form-row').append(addItemContainer); esui.init( addItemContainer[0], { viewContext: view.viewContext } ); } } var alreadyAddcount = v.attr('data-already-addcount') || 0; alreadyAddcount = parseInt(alreadyAddcount, 10); if (alreadyAddcount >= maxCount) { v.attr('disabled', 'disabled'); } var maxCountArr = []; for (var q = 1; q <= maxCount; q++) { maxCountArr.push(q); } v.on( 'click', { view: view, itemsConfig: candidateAddItemsConfig, maxCount: maxCount, maxCountArr: maxCountArr, alreadyAddItemsConfig: alreadyAddItemsConfig, dynamicItems: dynamicItems, refIdentify: refIdentify }, addItemFunc ); // if (alreadyAddcount < maxCount) { // var maxCountArr = []; // for (var q = 1; q <= maxCount; q++) { // maxCountArr.push(q); // } // v.on( // 'click', // { // view: view, // itemsConfig: candidateAddItemsConfig, // maxCount: maxCount, // maxCountArr: maxCountArr, // alreadyAddItemsConfig: alreadyAddItemsConfig, // dynamicItems: dynamicItems, // refIdentify: refIdentify // }, // addItemFunc // ); // } // else { // v.attr('disabled', 'disabled'); // } $('.form-data-body').delegate( '.del-items', 'click', { addNode: v, view: view, maxCount: maxCount, refIdentify: refIdentify }, delItemFunc ); } ); } /** * 删除之前动态添加的 formItem * * @param {jQuery.Element} e jQuery 事件对象 */ function delItemFunc(e) { e.stopPropagation(); e.preventDefault(); var target = $(e.currentTarget); var data = e.data; var refIdentify = data.refIdentify; if (refIdentify == target.attr('data-ref-identify')) { $(target.parents('.add-items-container')).remove(); e.data.view.get(target.attr('data-del-identify')).dispose(); // 这个删除按钮对应的添加按钮 var addNode = data.addNode; var alreadyAddcount = +addNode.attr('data-already-addcount'); alreadyAddcount--; addNode.attr('data-already-addcount', alreadyAddcount); if (alreadyAddcount >= e.data.maxCount) { addNode.attr('disabled', 'disabled'); } else { addNode.removeAttr('disabled'); } } } /** * 动态添加 formItem * * @param {jQuery.Element} e jQuery 事件对象 */ function addItemFunc(e) { e.stopPropagation(); e.preventDefault(); var target = $(e.currentTarget); // 当前添加按钮所在的这一行的 form-row 节点 var curFormRowNode = target.parents('.form-row'); var alreadyAddNode = curFormRowNode.find('.add-items-container'); var alreadyIndexArr = []; alreadyAddNode.each( function (i, v) { v = $(v); alreadyIndexArr.push(+v.attr('data-index')); } ); var maxCountArr = e.data.maxCountArr; var differenceArr = _.difference(maxCountArr, alreadyIndexArr).sort(); var alreadyAddcount = +target.attr('data-already-addcount') || 0; alreadyAddcount++; var flag = 0; if (!_.contains(differenceArr, alreadyAddcount)) { flag = alreadyAddcount; alreadyAddcount = differenceArr[0]; } // 要添加的表单项的配置 var itemsConfig = $.extend(true, [], e.data.itemsConfig); for (var i = 0, l = itemsConfig.length; i < l; i++) { itemsConfig[i].id += alreadyAddcount; itemsConfig[i].title += alreadyAddcount; itemsConfig[i].properties.value = ''; } // 设置删除按钮,只需要在添加出来的一组元素的第一个设置 // 如果添加的多行元素,在每一行添加的元素后面加上删除按钮是不合理的 itemsConfig[0].properties.delItems = e.data.refIdentify; itemsConfig[0].properties.delIdentify = itemsConfig[0].id; var addItemContainer = $('<div class="add-items-container"></div>'); var html = ''; html += etplEngine.render('dynamicForm', { formItemConfigs: itemsConfig, i18n: { 'QXZ': LANG_PKG.QXZ, 'ZDXZ': LANG_PKG.ZDXZ, 'Ge': LANG_PKG.Ge, 'BT': LANG_PKG.BT } }); addItemContainer.attr('data-index', alreadyAddcount).html(html); curFormRowNode.append(addItemContainer); esui.init( addItemContainer[0], { viewContext: e.data.view.viewContext } ); // debugger target.attr('data-already-addcount', flag ? flag : alreadyAddcount); var maxCount = e.data.maxCount; if (+target.attr('data-already-addcount') >= maxCount) { target.attr('disabled', 'disabled'); } } /** * 对 components 的处理 * * @param {Array} components component 集合 * @param {Object} submitEvtArgs form 提交时的参数,需要在 component 的值改变后修改参数中的值 * @param {View} view 当前 View 对象 */ function dealComponents(components, submitEvtArgs, view) { Deferred.all( (function () { return _.map( components, function (component, index) { return dynamicUtil.loadConfig( './component/' + component.type + '/main', component ); } ); })() ).then( function (d) { var args = Array.prototype.slice.call(arguments); var componentDataTmp = {}; var componentCallbackTmp = {}; /* jshint loopfunc:true */ for (var i = 0, len = args.length; i < len; i++) { args[i].modExport.on( args[i].component.submitName + 'formSubmitDataChange', function (changedData) { // debugger componentDataTmp[changedData.curFormData.submitName] = changedData.curFormData; componentCallbackTmp[changedData.curFormData.submitName] = changedData.componentCallback; submitEvtArgs = _.extend( submitEvtArgs, { componentData: componentDataTmp, componentCallback: componentCallbackTmp } ); } ); args[i].modExport.init(args[i].component, view); } } ); } /** * 设置 formItem 的 tip * * @param {View} view 当前的 View 对象 * @param {Object} properties 每一个 formItem 的配置属性对象 */ function initTip(view, properties) { // 设置 ideaName 的 tip,ideaName 不属于动态 form,它是一个固定的 formItem view.initTip( LANG_PKG.YZXWG, view.get('ideaName') ); // 遍历 properties // 初始化 formItem 的 tip // 如果是修改的话,那么设置 Uploader 的值 _.forEach( properties, function (property, key) { if (property.tip) { view.initTip( property.tip, view.get(key) ); } // 说明是 Uploader if (property.uploaderVal) { view.get(key).setRawValue(property.uploaderVal); } } ); } /** * 根据 formItemConfigs 配置获取 properties ,便于之后渲染 esui 控件 * * @param {Array.<Object>} formItemConfigs formItem 配置 * @param {Model} model 当前的 Model 对象 * * @return {Promise} */ function buildUIProperties(formItemConfigs, model) { var formType = model.get('formType'); var defer = new Deferred(); var len = formItemConfigs.length; var ret = {}; ret.components = []; ret.dynamicItems = {}; _.forEach( formItemConfigs, function (formItemConfig, index) { if (formItemConfig.type === 'TextBoxs') { for (var i = 0, itemsLen = formItemConfig.items.length; i < itemsLen; i++) { var fc = formItemConfig.items[i]; var p = fc.properties; if (p) { ret[fc.id] = p; // 把 Uploader 类型的 formItem 的值直接放入到 p 中, // 便于不用循环就可以回填 Uploader 的值 if (formType === 'edit' && fc.type === 'Uploader' ) { var uploaderData = model.get(fc.id); // 如果 uploaderData 不存在,说明这个 Uploader 组件不是必填项 if (uploaderData) { ret[fc.id].uploaderVal = { width: uploaderData.width || 50, height: uploaderData.height || 50, previewUrl: decodeURIComponent(uploaderData) }; } } var subItems = p.subItems; // 存在 subItems,即当前这个 fc.id 的 formItem 后面有添加按钮 // 添加按钮添加的元素配置就是 subItems.list 里的配置 // 把 subItems 直接挂在 properties.dynamicItems 上,便于之后操作 if (subItems) { ret.dynamicItems[fc.id] = subItems; // console.log(model.get('alreadyAddItemsConfigNew')); // console.log(model.get('alreadyAddItemsConfig')); // console.log(fc.id); // var alreadyAddItemsConfig = model.get('alreadyAddItemsConfig'); // if (alreadyAddItemsConfig) { // ret.dynamicItems[fc.id].alreadyAddItemsConfig = alreadyAddItemsConfig; // } var alreadyAddItemsConfigNew = model.get('alreadyAddItemsConfigNew'); if (alreadyAddItemsConfigNew) { for (var i = 0, l = alreadyAddItemsConfigNew.length; i < l; i++) { if (fc.id == alreadyAddItemsConfigNew[i].refId) { var curAlreadyAddItemsConfig = alreadyAddItemsConfigNew[i].alreadyAddItemsConfig; if (curAlreadyAddItemsConfig && curAlreadyAddItemsConfig.length) { ret.dynamicItems[fc.id].alreadyAddItemsConfig = curAlreadyAddItemsConfig; } } } // ret.dynamicItems[fc.id].alreadyAddItemsConfig = alreadyAddItemsConfig; } } } var components = fc.components; if (components) { if (!_.isArray(components)) { ret.components.push(components); } else { Array.prototype.push.apply(ret.components, components); } } } } else { var properties = formItemConfig.properties; if (properties) { ret[formItemConfig.id] = properties; // 把 Uploader 类型的 formItem 的值直接放入到 properties 中, // 便于不用循环就可以回填 Uploader 的值 if (formType === 'edit' && formItemConfig.type === 'Uploader' ) { var uploaderData = model.get(formItemConfig.id); // 如果 uploaderData 不存在,说明这个 Uploader 组件不是必填项 if (uploaderData) { ret[formItemConfig.id].uploaderVal = { width: uploaderData.width || 50, height: uploaderData.height || 50, previewUrl: decodeURIComponent(uploaderData) }; } } var subItems = properties.subItems; // 存在 subItems,即当前这个 formItemConfig.id 的 formItem 后面有添加按钮 // 添加按钮添加的元素配置就是 subItems.list 里的配置 // 把 subItems 直接挂在 properties.dynamicItems 上,便于之后操作 if (subItems) { ret.dynamicItems[formItemConfig.id] = subItems; // console.log(model.get('alreadyAddItemsConfigNew')); // console.log(model.get('alreadyAddItemsConfig')); // console.log(formItemConfig.id); // var alreadyAddItemsConfig = model.get('alreadyAddItemsConfig'); // if (alreadyAddItemsConfig) { // ret.dynamicItems[formItemConfig.id].alreadyAddItemsConfig = alreadyAddItemsConfig; // } var alreadyAddItemsConfigNew = model.get('alreadyAddItemsConfigNew'); if (alreadyAddItemsConfigNew) { for (var i = 0, l = alreadyAddItemsConfigNew.length; i < l; i++) { if (formItemConfig.id == alreadyAddItemsConfigNew[i].refId) { var curAlreadyAddItemsConfig = alreadyAddItemsConfigNew[i].alreadyAddItemsConfig; if (curAlreadyAddItemsConfig && curAlreadyAddItemsConfig.length) { ret.dynamicItems[formItemConfig.id].alreadyAddItemsConfig = curAlreadyAddItemsConfig; } } } // ret.dynamicItems[formItemConfig.id].alreadyAddItemsConfig = alreadyAddItemsConfig; } } } var components = formItemConfig.components; if (components) { if (!_.isArray(components)) { ret.components.push(components); } else { Array.prototype.push.apply(ret.components, components); } } } if (index === len - 1) { defer.resolve({ properties: ret }); } } ); return defer.promise; } util.inherits(DynamicFormView, FormView); return DynamicFormView; });
/** * 动态添加 formItem * * @param {jQuery.Element} e jQuery 事件对象 */ function addItemFunc(e) { e.stopPropagation(); e.preventDefault(); var target = $(e.currentTarget); // 当前添加按钮所在的这一行的 form-row 节点 var curFormRowNode = target.parents('.form-row'); var alreadyAddNode = curFormRowNode.find('.add-items-container'); var alreadyIndexArr = []; alreadyAddNode.each( function (i, v) { v = $(v); alreadyIndexArr.push(+v.attr('data-index')); } ); var maxCountArr = e.data.maxCountArr; var differenceArr = _.difference(maxCountArr, alreadyIndexArr).sort(); var alreadyAddcount = +target.attr('data-already-addcount') || 0; alreadyAddcount++; var flag = 0; if (!_.contains(differenceArr, alreadyAddcount)) { flag = alreadyAddcount; alreadyAddcount = differenceArr[0]; } // 要添加的表单项的配置 var itemsConfig = $.extend(true, [], e.data.itemsConfig); for (var i = 0, l = itemsConfig.length; i < l; i++) { itemsConfig[i].id += alreadyAddcount; itemsConfig[i].title += alreadyAddcount; itemsConfig[i].properties.value = ''; } // 设置删除按钮,只需要在添加出来的一组元素的第一个设置 // 如果添加的多行元素,在每一行添加的元素后面加上删除按钮是不合理的 itemsConfig[0].properties.delItems = e.data.refIdentify; itemsConfig[0].properties.delIdentify = itemsConfig[0].id; var addItemContainer = $('<div class="add-items-container"></div>'); var html = ''; html += etplEngine.render('dynamicForm', { formItemConfigs: itemsConfig, i18n: { 'QXZ': LANG_PKG.QXZ, 'ZDXZ': LANG_PKG.ZDXZ, 'Ge': LANG_PKG.Ge, 'BT': LANG_PKG.BT } }); addItemContainer.attr('data-index', alreadyAddcount).html(html); curFormRowNode.append(addItemContainer); esui.init( addItemContainer[0], { viewContext: e.data.view.viewContext } ); // debugger target.attr('data-already-addcount', flag ? flag : alreadyAddcount); var maxCount = e.data.maxCount; if (+target.attr('data-already-addcount') >= maxCount) { target.attr('disabled', 'disabled'); } }
function (i, v) { v = $(v); var refIdentify = v.data('refIdentify'); var maxCount = dynamicItems[refIdentify].maxCount; var candidateAddItemsConfig = dynamicItems[refIdentify].list; var alreadyAddItemsConfig = dynamicItems[refIdentify].alreadyAddItemsConfig; var len; if (alreadyAddItemsConfig && (len = alreadyAddItemsConfig.length)) { v.attr('data-already-addcount', len); for (var j = 0, l = alreadyAddItemsConfig.length; j < l; j++) { var addItemContainer = $('<div class="add-items-container"></div>'); var html = ''; html += etplEngine.render('dynamicForm', { formItemConfigs: alreadyAddItemsConfig[j], i18n: { 'QXZ': LANG_PKG.QXZ, 'ZDXZ': LANG_PKG.ZDXZ, 'Ge': LANG_PKG.Ge, 'BT': LANG_PKG.BT } }); addItemContainer.attr('data-index', alreadyAddItemsConfig[j].index).html(html); v.parents('.form-row').append(addItemContainer); esui.init( addItemContainer[0], { viewContext: view.viewContext } ); } } var alreadyAddcount = v.attr('data-already-addcount') || 0; alreadyAddcount = parseInt(alreadyAddcount, 10); if (alreadyAddcount >= maxCount) { v.attr('disabled', 'disabled'); } var maxCountArr = []; for (var q = 1; q <= maxCount; q++) { maxCountArr.push(q); } v.on( 'click', { view: view, itemsConfig: candidateAddItemsConfig, maxCount: maxCount, maxCountArr: maxCountArr, alreadyAddItemsConfig: alreadyAddItemsConfig, dynamicItems: dynamicItems, refIdentify: refIdentify }, addItemFunc ); // if (alreadyAddcount < maxCount) { // var maxCountArr = []; // for (var q = 1; q <= maxCount; q++) { // maxCountArr.push(q); // } // v.on( // 'click', // { // view: view, // itemsConfig: candidateAddItemsConfig, // maxCount: maxCount, // maxCountArr: maxCountArr, // alreadyAddItemsConfig: alreadyAddItemsConfig, // dynamicItems: dynamicItems, // refIdentify: refIdentify // }, // addItemFunc // ); // } // else { // v.attr('disabled', 'disabled'); // } $('.form-data-body').delegate( '.del-items', 'click', { addNode: v, view: view, maxCount: maxCount, refIdentify: refIdentify }, delItemFunc ); }
define(function (require) { var etpl = require('etpl'); var smallImgWidth = 106; // 缩略图宽度 var tpl = '' + '<div class="${expandPrefix}-action">' + '<a href="" class="${expandPrefix}-original" target="_blank" title="查看原图"><i></i>查看原图</a>' + '<a href="#" onclick="return false;" class="${expandPrefix}-rotate-right" title="向右旋转"><i></i>向右旋转</a>' + '</div>' + '<div class="${expandPrefix}-main-img">' + '<img src="" />' + '</div>' + '<div class="${expandPrefix}-small-img-container">' + '<% if: ${sUrls.length} %>' + '<div class="${expandPrefix}-switch-left ${expandPrefix}-switch"><i data-switch="left"></i></div>' + '<% /if %>' + '<% if: ${sUrls.length} %>' + '<div class="${expandPrefix}-switch-right ${expandPrefix}-switch"><i data-switch="right"></i></div>' + '<% /if %>' + '<% var: smallImgUlWidth = ${sUrls.length} * ${smallImgWidth} %>' + '<% var: smallImgWrapWidth = ${smallImgNum} * ${smallImgWidth} %>' + '<div class="${expandPrefix}-small-img-wrap <% if: !${sUrls.length} %>hidden<%/if%>" ' + 'style="width:${smallImgWrapWidth}px" data-a="${smallImgUlWidth} - ${smallImgWrapWidth}">' + '<ul class="${expandPrefix}-small-img" style="width:${smallImgUlWidth}px">' + '<% for: ${sUrls} as ${sUrl}, ${i} %>' + '<li>' + '<a href="" data-index="${i}"><img src="${sUrl}" /></a>' + '</li>' + '<% /for %>' + '</ul>' + '</div>' + '</div>'; var etplEngine = new etpl.Engine({ commandOpen: '<%', commandClose: '%>' }); // 共用一个render即可 var render = etplEngine.compile(tpl); /** * 是否支持css3的transition * * @private * @return {boolean} 支持状态 */ var supportTransition = (function () { var s = document.createElement('p').style; var r = 'transition' in s || 'WebkitTransition' in s || 'MozTransition' in s || 'msTransition' in s || 'OTransition' in s; s = null; return r; })(); /** * 旋转 * * @private * @param {(string | HTMLElement)} target 目标元素 * @param {number} deg 角度 */ function rotate(target, deg) { if (supportTransition) { var degStr = 'rotate(' + deg + 'deg)'; $(target).css({ '-webkit-transform': degStr, '-mos-transform': degStr, '-o-transform': degStr, 'transform': degStr }); } else { var ieRotate = ~~((deg / 90) % 4 + 4) % 4; $(target).css('filter', 'progid:DXImageTransform.Microsoft.BasicImage(rotation=' + ieRotate +')'); } } /** * 图片展开放大 * * @constructor * @exports * @param {Object} options 配置项 */ function ImgAmplify(options) { $.extend(this, options); $(this.source).unbind('click').bind('click', this.getExpandImgHandler()); } /** * ImgAmplify新增prototype属性 * * @type {Object} */ var proto = { /** * 获取展开图片的处理函数 * * @private * @return {Function} */ getExpandImgHandler: function () { var me = this; return function (e) { // console.log(111); e.preventDefault(); var target = e.target; var targetTagName = target.tagName.toLowerCase(); // modify by liulangyu // if (targetTagName !== 'a' && targetTagName !== 'img' && targetTagName !== 'div') { if (targetTagName !== 'a' && targetTagName !== 'img') { return; } target = $(target).parents('a').eq(0)[0]; // 若第一次展开,则插入节点,绑定事件 if (!me.expanded) { me.expandInit(); // 插入节点 me.bindEvent(); // 渲染事件 me.index = -1; } var index = me.originImgLinks.index(target); me.expand(index); // 打开缩略图 }; }, /** * 展开图片初始化操作 * * @private */ expandInit: function () { // 生成图片展开节点 var src = $(this.source); src.after('<div class="' + this.expandPrefix + '-container" style="display:none;"></div>'); this.expandEle = src.next()[0]; // 生成一个临时img节点 var tempImg = $('<img>', {style: 'position:absolute; left: -10000px; top:0;'})[0]; // FIXME no need to append // document.body.appendChild(tempImg); this.tempImg = tempImg; // 抽取缩略图和大图url数据 var src = $(this.source); var originImgLinks = src.find('a'); var sUrls = []; // 缩略图列表 var bUrls = []; // 原图列表 var fileInfos = {}; $.each(originImgLinks, function (index, imgLink) { var img = $(imgLink).find('img')[0]; sUrls.push($(img).attr('src')); bUrls.push($(imgLink).attr('href') || $(img).attr('src')); fileInfos[index] = fileInfos[index] || {}; fileInfos[index].rotate = parseInt($(imgLink).attr('data-rotate') || 0, 10); }); this.originImgLinks = originImgLinks; this.sUrls = sUrls; this.bUrls = bUrls; this.fileInfos = fileInfos; this.smallImgNum = this.smallImgNum || 6; // 插入图片展开DOM var data = { 'sUrls': this.sUrls, 'expandPrefix': this.expandPrefix, 'smallImgWidth': smallImgWidth, 'smallImgNum': this.smallImgNum }; // modify 如果只有一张,不显示缩略图 if (this.sUrls.length <= 1) { data.sUrls = []; } // var render = etpl.compile(tpl); var html = render(data); this.expandEle.innerHTML = html; this.expandImgWrapper = $(this.expandEle).find('.' + this.expandPrefix + '-main-img')[0]; this.expandImg = $(this.expandImgWrapper).find('img')[0]; this.expandOriginal = $(this.expandEle).find('.' + this.expandPrefix + '-original')[0]; this.expandSwitch = $(this.expandEle).find('.' + this.expandPrefix + '-switch i'); this.expanded = true; }, /** * 绑定事件 * * @private */ bindEvent: function () { $(this.tempImg).bind('load', this.getImgLoadedHandler()); // 为展开后的缩略图绑定事件 $(this.expandEle).find('.' + this.expandPrefix + '-small-img a').bind( 'click', this.getSImgClickHandler() ); // 为展开后的缩略图的左右绑定事件 $(this.expandSwitch).bind('click', this.getSwitchClickHandler()); // 为展开图片区域绑定mousemove事件 $(this.expandImgWrapper).bind('mousemove', this.getExpandWrapperMvHandler()); // 为展开图片区域绑定click事件 $(this.expandImgWrapper).bind('click', this.getExpandWrapperClickHandler()); // action $(this.expandEle).find('.' + this.expandPrefix + '-action').bind('click', this.getActionClickHandler()); }, /** * 获取临时图片加载成功后的事件处理函数 * * @private * @return {Function} */ getImgLoadedHandler: function () { var me = this; return function () { $(me.expandImgWrapper).removeClass('loading'); if (me.imgLoading) { me.show(); $($(me.source).find('img')[me.index]).css({ 'opacity': 1, 'filter': 'alpha(opacity=100)' }); } me.resizeImg(); var bUrl = me.bUrls[me.index]; me.expandImg.src = bUrl; $(me.expandOriginal).attr('href', bUrl); // 初始化角度 var deg = me.fileInfos[me.index].rotate; if (deg) { me.rotateImage(deg, true); } if (!me.imgLoading) { $(me.expandImg).animate({ opacity: '1' }, 500); } if (me.imgLoading) { me.imgLoading = false; } me.scrollPos(me.expandEle); }; }, /** * 根据临时图片的尺寸调整展开图片大小,限制宽度,保持宽高比 * * @private */ resizeImg: function () { var tempImg = this.tempImg; var originWidth = tempImg.width; var wrapperWidth = this.expandImgWrapper.offsetWidth; this.fileInfos[this.index] = this.fileInfos[this.index] || {}; this.fileInfos[this.index].width = originWidth; this.fileInfos[this.index].height = tempImg.height; // 原图宽度小于wrapper宽度 if (originWidth < wrapperWidth) { $(this.expandImg).css('width', originWidth + 'px'); } else { $(this.expandImg).css('width', wrapperWidth + 'px'); } }, /** * 获取展开后缩略图部分点击事件处理函数 * * @private * @return {Function} */ getSImgClickHandler: function () { var me = this; return function (e) { e.preventDefault(); var index = parseInt($(this).attr('data-index'), 10); me.turnTo(index); }; }, /** * 获取展开后缩略图左右箭头点击事件处理函数 * * @private * @return {Function} */ getSwitchClickHandler: function () { var me = this; return function (e) { e.preventDefault(); var isFirstImg = (me.index === 0); var isLastImg = (me.index === me.sUrls.length - 1); var target = $(e.target); if (target.attr('data-switch') === 'left' && !isFirstImg) { me.turnTo(me.index - 1); } else if (target.attr('data-switch') === 'right' && !isLastImg) { me.turnTo(me.index + 1); } }; }, /** * 更新缩略图列表 * * @private */ updataThumbList: function () { var thumbList = $(this.expandEle).find('.' + this.expandPrefix + '-small-img'); var thumbLen = this.sUrls.length; if (thumbLen > this.smallImgNum) { // 溢出 if (this.index < 2) { thumbList.css({ left: 0 }); } else if (this.index < thumbLen - this.smallImgNum + 3) { thumbList.animate( { left: -smallImgWidth * this.index + smallImgWidth * 2 }, 300 ); } else { thumbList.animate( { left: -smallImgWidth * (thumbLen - this.smallImgNum) }, 300 ); } } // 更新switch $(this.expandSwitch).removeClass('disable'); if (this.index === 0) { $(this.expandSwitch).filter('[data-switch=left]').addClass('disable'); } else if (this.index === this.sUrls.length - 1) { $(this.expandSwitch).filter('[data-switch=right]').addClass('disable'); } }, /** * 转到指定索引的某张图片 * * @param {number} index 目标图片的索引 */ turnTo: function (index) { var prevIndex = this.index; if (prevIndex === index) { return; } if (index < 0 || index > this.bUrls.length - 1) { this.hide(); return; } if (!this.imgLoading) { $(this.expandImg).css({ 'opacity': 0, 'filter': 'alpha(opacity=0)' }); $(this.expandImgWrapper).addClass('loading'); } this.index = index; // 重置 this.resetStyles(); // 重置图片大小 this.resizeImg(); if (this.tempImg.src === this.bUrls[index]) { if (!this.imgLoading) { $(this.expandImg).css({ opacity: '1' }); } $(this.expandImgWrapper).removeClass('loading'); } this.tempImg.src = this.bUrls[index]; var sLinkList = $(this.expandEle).find('.' + this.expandPrefix + '-small-img a'); $(sLinkList[prevIndex]).parent().removeClass('current'); $(sLinkList[index]).parent().addClass('current'); // 更新缩略图列表 this.updataThumbList(); }, /** * 获取图片展开区域mouseover事件处理函数 * * @private * @return {Function} */ getExpandWrapperMvHandler: function () { var me = this; return function (e) { // original // if ( // $(e.target) // .add($(e.target).parents('.' + me.expandPrefix + '-original')) // .hasClass(me.expandPrefix + '-original') // ) { // return; // } var offsetGap = e.pageX - $(this).offset().left; var wrapperWidth = $(this).width(); var wrapper = $(me.expandImgWrapper); // 若鼠标在图片左边1/3区域,并且当前不为第一张图片,则可向前翻页 if (offsetGap < wrapperWidth / 3 && me.index > 0) { wrapper.removeClass('next'); wrapper.addClass('prev'); } // 若鼠标在图片右边1/3区域,且当前不为最后一张图片,则可向后翻页 else if (offsetGap > wrapperWidth * 2 / 3 && me.index < me.sUrls.length - 1) { wrapper.removeClass('prev'); wrapper.addClass('next'); } // 其他情况为缩小指针 else { wrapper.removeClass('prev'); wrapper.removeClass('next'); } }; }, /** * 获取图片展开区域click事件处理函数 * * @private * @return {Function} */ getExpandWrapperClickHandler: function () { var me = this; return function (e) { if ($(this).hasClass('prev')) { me.turnTo(me.index - 1); } else if ($(this).hasClass('next')) { me.turnTo(me.index + 1); } else { me.hide(); } }; }, /** * action区域点击 */ getActionClickHandler: function () { var self = this; return function (e) { if ( $(e.target) .add($(e.target).parents('.' + self.expandPrefix + '-rotate-right')) .hasClass(self.expandPrefix + '-rotate-right') ) { self.rotateImage(); } }; }, /** * 旋转 * * @private * @param {number=} deg 需要顺时针旋转角度 * @param {boolean=} isNoAnimation 是否不需要动画 */ rotateImage: function(deg, isNoAnimation) { deg = deg || (parseInt(this.currentRotate || 0, 10) + 90); this.currentRotate = deg; var target = $(this.expandImg); rotate(target, deg); if (!isNoAnimation) { $(this.expandImg).addClass('rotate'); } // resize,简单处理,只处理90°倍数的问题,其它的可以通过getBoundClientRect var wrapperWidth = this.expandImgWrapper.offsetWidth; var isHorizontal = deg % 180 === 0; var info = this.fileInfos[this.index]; var afterWidth = info[isHorizontal ? 'width' : 'height']; var afterHeight = info[isHorizontal ? 'height' : 'width']; // 原图宽度小于wrapper宽度 if (afterWidth < wrapperWidth) { target.css({ width: info.width, height: info.height }); } else { if (isHorizontal) { target.css({ width: wrapperWidth, height: 'auto' }); } else { target.css({ height: wrapperWidth, width: 'auto' }); } } if (isHorizontal) { $(this.expandImgWrapper).css({ height: 'auto' }); $(this.expandImg).css({ position: 'static', left: 'auto', top:' auto' }); } else { var w = parseInt(target.css('width').replace('px', ''), 10); var h = parseInt(target.css('height').replace('px', ''), 10); $(this.expandImgWrapper).css({ height: w }); $(this.expandImg).css({ position: 'absolute', left: (wrapperWidth - h) / 2 - (w - h) / 2, top: (w - h) / 2 }); } }, /** * 重置样式 */ resetStyles: function () { this.currentRotate = 0; $(this.expandImgWrapper).css({ height: 'auto' }); $(this.expandImg).css({ position: 'static', left: 'auto', top:' auto', width: 'auto', height: 'auto' }).removeClass('rotate'); rotate($(this.expandImg), 0); }, /** * 展开大图 * * @param {number} index 展开大图的索引 */ expand: function (index) { // 需要加载图片 if (index !== this.index) { $($(this.source).find('img')[index]).css({ 'opacity': '0.5', 'filter': 'alpha(opacity=50)' }); this.imgLoading = true; this.turnTo(index); } // 直接展开 else { this.show(); } }, show: function () { $(this.source).hide(); $(this.expandEle).show(); }, /** * 收起大图 * * @private */ hide: function () { $(this.expandEle).hide(); $(this.source).show(); // this.scrollPos(this.source); }, /** * 若目标节点的起始位置在视觉范围之外,将页面滚动到目标元素的位置 * * @param {HTMLElement} target 目标节点 */ scrollPos: function (target) { // TODO 简单处理下,后期改为事件处理 var offsetTopFix = this.offsetTop || 0; var offsetTop = $(target).offset().top; if (this.scrollElem && $(this.scrollElem).size()) { var scrollElem = $(this.scrollElem); var scrollElemOffsetTop = scrollElem.offset().top; var scrollTop = scrollElem.scrollTop(); if (offsetTop < scrollElemOffsetTop) { scrollElem.scrollTop(scrollTop - scrollElemOffsetTop + offsetTop - offsetTopFix); } } else { if ($(document).scrollTop() > offsetTop - offsetTopFix) { $(document).scrollTop(offsetTop - offsetTopFix); } } } }; $.extend(ImgAmplify.prototype, proto); return ImgAmplify; });
/** * 简易Table控件 * Copyright 2016 Baidu Inc. All rights reserved. * * @file 控件用的模板引擎 * @author otakustay */ import {Engine} from 'etpl'; import TEMPLATE from 'text!./LightTable.tpl.html'; let engine = new Engine(); engine.parse(TEMPLATE); engine.addFilter('camelize', str => str.replace(/[A-Z]/g, char => '-' + char.toLowerCase())); export default engine;
view.addFilter = function (name, fn) { etplEngine.addFilter(name, fn); };
view.getRendererByTarget = function (target) { return etplEngine.getRenderer(target); };