Knockot JS 数字输入插件
我将它放在了在GitHub上面,希望有高手一起来帮助完善它,这里附上网址:
https://github测试数据/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://HdhCmsTestcnblogs测试数据/Leo_wl/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
版权信息查看更多关于Knockot JS 数字输入插件的详细内容...