Knockot JS 数字输入插件
我将它放在了在GitHub上面,希望有高手一起来帮助完善它,这里附上网址:
https://github.com/dragonrhyme/KnockotNumeric
之前写过 XML技术在界面生成中的简单应用 的文章,后来由于一直很忙,就没有再写。但是东西已经可以用了, 附上截图给大家预览下,等自己不那么紧张的时候,再接着跟大家分享,这里先行道歉!
再附上一TabPanel为例子的XML代码:
1 < Tab ID ="tab1" Cols ="12" Offset ="0" > 2 < TabItem Key ="tabitem1" LabelText ="选项卡一" > 3 < TextBox ID ="tabitemtextbox1" LabelWidth ="10" Cols ="3" Offset ="0" LabelText ="文字输入一:" Value ="$root.text" /> 4 < TextBox ID ="tabitemtextbox2" LabelWidth ="100" Cols ="3" Offset ="0" LabelText ="文字输入二:" Value ="$root.text" NotWripRow ="true" /> 5 < TextBox ID ="tabitemtextbox3" LabelWidth ="100" Cols ="3" Offset ="0" LabelText ="文字输入三:" Value ="$root.text" NotWripRow ="true" /> 6 < TextBox ID ="tabitemtextbox4" LabelWidth ="100" Cols ="3" Offset ="0" LabelText ="文字输入四:" Value ="$root.text" NotWripRow ="true" /> 7 </ TabItem > 8 </ Tab >
然后这里是关于操作的定义方式,分为服务器端和客户端操作,其中客户端操作不需要额外手写代码,服务器端也是ajax交互的。也贴出来给大家探讨下(注释部分表示可以那样嵌套定义操作):
1 < Operations > 2 < Operation ID ="saveData" > 3 < ServerOperation Handler ="SaveChanges" FinishAlert ="'保存数据'" > 4 <!-- <ServerOperation Handler="SaveChanges" FinishAlert="'Second'"></ServerOperation> 5 <ClientOperation Handler="Confirm" Para="'From client'"></ClientOperation> 6 <ClientOperation Handler="Information" Para="'From client'"></ClientOperation> 7 <FailbackOperation> 8 <ClientOperation Handler="Error" Para="'From client'"></ClientOperation> 9 </FailbackOperation> --> 10 </ ServerOperation > 11 </ Operation > 12 < Operation ID ="changeValue" > 13 < ClientOperation Handler ="ChangeValue" Para ="'$root.mCourseList[0].Name', $root.mCourseList()[0].Desc" /> 14 </ Operation > 15 < Operation ID ="changeValue1" > 16 < ClientOperation Handler ="ChangeValue" Para ="'$root.mCourseList[*].Name', $root.mCourseList()[1].Desc" /> 17 </ Operation > 18 < Operation ID ="openWindow" > 19 < ClientOperation Handler ="OpenWindow" Para ="'window1'" /> 20 </ Operation > 21 </ Operations >
当然,OpenWindow有关于Window的定义,如下:
1 < PopWindow Height ="100" Width ="100" IsEnable ="true" IsVisible ="true" ID ="window1" Title ="这是个窗口" > 2 < TableContainer > 3 < DataGrid Rows ="6" SelectColumnName ="isSelected" SelectMode ="multi" ID ="datagrid1" DataSource ="$root.mCourseList" > 4 < Column BindFieldKey ="Name" Header ="名称" Tip ="This is tip" /> 5 < Column BindFieldKey ="Desc" Header ="描述" Tip ="This is tip" /> 6 </ DataGrid > 7 </ TableContainer > 8 </ PopWindow >
看看Rhyme定义的客户端操作类库, 例如ChangeValue,解析'$root.mCourseList[*].Name'这个表达式的代码还算有些价值, 当然,还不太完善:
1 ChangeValue: function (args, successCallBack, failureCallBack) { 2 var _$root, _$data, _event, _target, _assignTo, _from, _dataContext, _statements, _assignmentInContextByStatementsWithValue; 3 4 // Context params. 5 _$root = args.$root; // Root context of view model. 6 _$data = args.$data; // Current context of view model. 7 _event = args.event; // Event from dom or jQuery . 8 _target = args.target; // Source element of event. 9 10 // The change where target. 11 _assignTo = args.params[0 ]; 12 // The new value. 13 _from = ko.utils.unwrapObservable(args.params[1 ]); 14 15 // When the target was observable object, Assignment new value to it. 16 if ( typeof (_assignTo) === 'function' ) { 17 _assignTo(_from); 18 } else if ( typeof (_assignTo) === 'string' ) { 19 // The list of statements need to parse. 20 _statements = _assignTo.replace(/\[\*\]/g, '.*').replace(/\[\d\]/g, function (s, t) { return '.' + s.replace(/[^\d]/g, ''); }).split('.' ); 21 _assignmentInContextByStatementsWithValue = function (dataContext, statements, newValue, currentStatementIndex) { 22 var _currentContext = dataContext, 23 _currentContextLength, 24 _currentStatementIndex = currentStatementIndex, 25 _currentStatement, 26 _indexStatement, 27 _totalStatements = statements.length; 28 29 // Syntactic analysis. 30 for ( var i = _currentStatementIndex; i < _totalStatements; i++ ) { 31 _currentStatement = statements[i]; 32 33 if (_currentStatement === '$root' || _currentStatement === '$data' ) { 34 continue ; 35 } else if (/^\d+$/.test(_currentStatement)) { // Match index statement. 36 _indexStatement = parseInt(statements[i]); 37 38 if (i === _totalStatements - 1 ) { 39 _currentContext[_indexStatement](newValue); 40 } else { 41 _assignmentInContextByStatementsWithValue(_currentContext[_indexStatement], statements, newValue, i + 1 ); 42 } 43 } else if (_currentStatement === '*') { // Match every item. 44 _currentContextLength = ko.utils.unwrapObservable(_currentContext).length; 45 for ( var j = 0; j < _currentContextLength; j++ ) { 46 debugger ; 47 if (i === _totalStatements - 1 ) { 48 _currentContext[j](newValue); 49 } else { 50 _assignmentInContextByStatementsWithValue(_currentContext[j], statements, newValue, i + 1 ); 51 } 52 } 53 } else { // In normal case. 54 if (i === _totalStatements - 1 ) { 55 dataContext[_currentStatement.replace(/\(\)/g, '' )](newValue); 56 } else { 57 _currentContext = ko.utils.unwrapObservable(dataContext[_currentStatement.replace(/\(\)/g, '' )]); 58 } 59 } 60 } 61 }; 62 63 if (_statements[0].search("\\u0024data") != -1 ) { 64 _dataContext = _$data; 65 } else { 66 _dataContext = _$root; 67 } 68 69 _assignmentInContextByStatementsWithValue(_dataContext, _statements, _from, 0 ); 70 } 71 }
还有Rhyme 为操作的定义自动生成了相应的操作代码:
1 ( function (){ $( function (){initViewModel('PageLoaded', 'Evaluation' );}); })(); 2 3 var saveData = function ($root, $data, event, target){window.appViewModel.doAction('SaveChanges','保存数据' , function (viewModel, response) { }, function (xhr) { });} 4 5 var changeValue = function ($root, $data, event, target){ 6 ClientEventHandlers.ChangeValue({ $root: $root, $data: $data, event: event, target: target, params: ['$root.mCourseList[0].Name', $root.mCourseList()[0].Desc] }, function (){ }, function (){ }); 7 } 8 9 var changeValue1 = function ($root, $data, event, target){ 10 ClientEventHandlers.ChangeValue({ $root: $root, $data: $data, event: event, target: target, params: ['$root.mCourseList[*].Name', $root.mCourseList()[1].Desc] }, function (){ }, function (){ }); 11 } 12 13 var openWindow = function ($root, $data, event, target){ 14 ClientEventHandlers.OpenWindow({ $root: $root, $data: $data, event: event, target: target, params: ['window1'] }, function (){ }, function (){ }); 15 }
由于Rhyme比较懒惰,所以ViewModel定义了个通用的,当然,如果你不懒惰,定义N个慢慢玩玩后再决定是否也会学Rhyme偷懒吧。(:以后会慢慢完善:
1 var ViewModel = function (url, pageCode, initAction) { 2 3 var self = this ; 4 5 self.url = url; 6 self.pageCode = ko.observable(pageCode); 7 8 self.loadData = function (dataHandler, successMsg, successCallBack, failureCallBack) { 9 var _data = {}; 10 debugger ; 11 12 if ( typeof (dataHandler) === 'function' ) { 13 _data = dataHandler(ko.toJS(self)); 14 } 15 16 $.ajax({ 17 url: self.url, 18 data: { pageCode: _data.pageCode, actionName: _data.actionName, "datasource" : ko.toJSON(_data) }, 19 type: "POST" , 20 dataType: 'json' , 21 error: function (xhr) { 22 if ( typeof (failureCallBack) === 'function' ) { 23 try { 24 failureCallBack(self, xhr); 25 MessageCenter.fromXhr(e); 26 } catch (e) { 27 MessageCenter.fromException(e); 28 } 29 } 30 }, 31 success: function (response) { 32 if (successMsg) { 33 MessageCenter.success(successMsg); 34 } 35 36 if ( typeof (successCallBack) === 'function' ) { 37 try { 38 successCallBack(self, response); 39 } catch (e) { 40 MessageCenter.fromException(e); 41 } 42 } 43 } 44 }); 45 46 return self; 47 }; 48 49 // Call service. 50 self.doAction = function (actionName, successMsg, successCallBack, failureCallBack) { 51 debugger ; 52 self.loadData( function (model) { 53 model.actionName = actionName; 54 55 return model; 56 }, successMsg, successCallBack, failureCallBack); 57 }; 58 59 // self.saveChanges = function () { 60 // self.doAction("SaveChanges", successMsg, function (viewModel, response) { 61 // debugger; 62 // ko.mapping.fromJS(response, {}, viewModel); 63 // }); 64 // }; 65 66 self.bind = function (element) { 67 if (element) { 68 ko.applyBindings(self); 69 } else { 70 ko.applyBindings(self); 71 } 72 }; 73 74 ( function (){ 75 if ( typeof (initAction) === 'function' ) { 76 try { 77 initAction(self); 78 } catch (ex) { 79 // init error 80 } 81 } 82 })(); 83 };
还有为了兼容万恶的IE, 不得不用JS来调整组件大小。Rhyme的布局是支持响应式布局的。当然,也是基于Bootstrap的。
1 ( function () { 2 $( function () { 3 var resizeControls = function (forVisible, containerSelector) { 4 var selectorTemplate = 'input[type="text"]{forVisible},input[type="password"]{forVisible},select{forVisible},textarea{forVisible}' ; 5 var selector = '' ; 6 7 if (forVisible === true ) { 8 selector = selectorTemplate.replace(/{forVisible}/g, ':visible' ); 9 } else { 10 selector = selectorTemplate.replace(/{forVisible}/g, '' ); 11 } 12 13 var $resizeControl = $(selector, containerSelector); 14 var totalControlForResize = $resizeControl.length; 15 for ( var i = 0; i < totalControlForResize; i++ ) { 16 17 var currentControl = $resizeControl.get(i), 18 $currentControl = $(currentControl), 19 $parent = $currentControl.parents('.control-group' ), 20 $label = $parent.children('.control-label' ); 21 if ($label && $label.get(0)) { $currentControl.width($parent.get(0).offsetWidth - $label.get(0).offsetWidth - 15 ); } 22 else { 23 $currentControl.width($parent.get(0).offsetWidth - 15 ); 24 } 25 } 26 }; 27 28 resizeControls( true , '.controls' ); 29 30 window.onresize = function () { 31 resizeControls( true , '.controls' ); 32 }; 33 34 $('[data-toggle="tab"]').live('click', function () { 35 var container = $( this ).attr('href' ); 36 resizeControls( false , container); 37 }); 38 39 $('[data-toggle="details"]').live('click', function () { 40 var container = $( this ).attr('data-toggle-target' ); 41 window.setTimeout( function () { resizeControls( false , container); }, 10 ) 42 }); 43 }); 44 })();
Rhyme 也为布局提供了模版,类似母版页,当然,用的是HTML,生成后的也是纯HTML,由于服务于企业内部系统,所以没有对SEO做任何考虑。
View Code
Rhyme由于工作比较忙,所以难得抽出时间整理东西,接下来要是再有时间,会把那个语法解析的完善下,争取让Knockout中让人头疼的括号语法消失。Rhyme初步的想法是在绑定数据前对原有表达式语法重新解析,这样需要括号的地方就可以解析的时候在用代码插入了。有哪位有更好的想法请求分享一下。(:
Rhyme接下来的源代码会托管到GitHub,也会在博客园放下载,大家共同学习,也多帮我找找Bug,提点不足,在这里先行谢过了。
标签: XSL , XSLT , 代码生成 , Javascript MVVM , Javascript MVC , 数字输入 , 语法分析
作者: Leo_wl
出处: http://www.cnblogs.com/Leo_wl/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
版权信息查看更多关于Knockot JS 数字输入插件的详细内容...