Skip to content

Commit 283d9a8

Browse files
committed
Add Object support and repeat nest
1 parent 843bc63 commit 283d9a8

File tree

7 files changed

+469
-143
lines changed

7 files changed

+469
-143
lines changed

README.md

Lines changed: 54 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,29 +2,72 @@
22

33
A simple, lightweight jQuery plugin for model binding
44

5-
## Getting Started
5+
## Download
66
Download the [production version][min] or the [development version][max].
77

8-
[min]: https://raw.github.com/zengohm/jquery-ctrl/master/dist/ctrl.min.js
9-
[max]: https://raw.github.com/zengohm/jquery-ctrl/master/dist/ctrl.js
8+
[min]: https://raw.github.com/zengohm/jquery-ctrl/master/dist/jquery.ctrl.min.js
9+
[max]: https://raw.github.com/zengohm/jquery-ctrl/master/dist/jquery.ctrl.js
10+
11+
## Getting Started
1012

1113
In your web page:
1214

1315
```html
16+
<div jq-ctrl="myCtrl">
17+
Hello, {{demo}}!
18+
</div>
1419
<script src="jquery.js"></script>
15-
<script src="dist/ctrl.min.js"></script>
20+
<script src="dist/jquery.ctrl.min.js"></script>
1621
<script>
1722
jQuery(function($) {
18-
$.awesome(); // "awesome"
23+
$.ctrl('myCtrl',function(model){
24+
model.demo = 'World';
25+
});
1926
});
2027
</script>
2128
```
2229

23-
## Documentation
24-
_(Coming soon)_
30+
You will see
31+
32+
```html
33+
<div jq-ctrl="myCtrl">
34+
Hello, world!
35+
</div>
36+
```
37+
38+
## Installation
39+
Include script after the jQuery library (unless you are packaging scripts somehow else):
40+
```html
41+
<script src="dist/jquery.ctrl.min.js"></script>
42+
```
43+
The plugin can also be loaded as AMD or CommonJS module.
44+
45+
## Usage
46+
47+
### String
48+
```html
49+
<div jq-ctrl="myCtrl">
50+
Hello, {{demo}}!
51+
<button title="{{btnTitle}}">Button</button>
52+
</div>
53+
<script>
54+
jQuery(function($) {
55+
$.ctrl('myCtrl',function(model){
56+
model.demo = 'World';
57+
model.btnTitle = 'Click Me!';
58+
});
59+
});
60+
</script>
61+
```
62+
63+
### If
64+
65+
### Repeat
66+
67+
### Options
68+
69+
### Src and href
2570

26-
## Examples
27-
_(Coming soon)_
71+
### Style
2872

29-
## Release History
30-
_(Nothing yet)_
73+
### Disabled

dist/jquery.ctrl.js

Lines changed: 124 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,36 @@
1-
/*! jQuery Ctrl - v0.1.0 - 2014-07-21
1+
/*! jQuery Ctrl - v0.1.0 - 2014-07-23
22
* https://github.com/zengohm/jquery-ctrl
33
* Copyright (c) 2014 Zeng Ohm; Licensed MIT */
4-
(function ($) {
4+
(function (factory) {
5+
if (typeof define === 'function' && define.amd) {
6+
// AMD
7+
define(['jquery'], factory);
8+
} else if (typeof exports === 'object') {
9+
// CommonJS
10+
factory(require('jquery'));
11+
} else {
12+
// Browser globals
13+
factory(jQuery);
14+
}
15+
}(function ($) {
516
var NODE_STATUS_NORMAL = 0;
617
var NODE_STATUS_COVER = 1;
718
var NODE_STATUS_LAST = 2;
819

9-
var modules = {};
10-
1120
var bindingTypes = {};
1221

22+
var createCtrl = function(modelData,$element){
23+
return {
24+
model:new ModelObject(modelData),
25+
ctrl: $element
26+
};
27+
};
28+
1329
// Static method.
1430
$.ctrl = function (ctrlName, init) {
15-
var thisCtrl = {
16-
model: {},
17-
init: init,
18-
ctrl: $('[jq-ctrl="' + ctrlName + '"]')
19-
};
20-
modules[ctrlName] = thisCtrl;
21-
thisCtrl.init(thisCtrl.model);
31+
var modelData = {};
32+
init(modelData);
33+
var thisCtrl = createCtrl(modelData,$('[jq-ctrl="' + ctrlName + '"]'));
2234
bindingInit(thisCtrl);
2335
};
2436

@@ -37,7 +49,9 @@
3749
break;
3850
}
3951
}
40-
initElement($(this));
52+
if(!(node_status & NODE_STATUS_COVER)) {
53+
initElement($(this));
54+
}
4155
}
4256
});
4357
};
@@ -46,11 +60,11 @@
4660

4761

4862
bindingTypes.text = function(node,model,onChangeTasks){
49-
if(node.nodeName.substr(0,1)==='#' && node.data.match(/\{\{\w+\}\}/)){
63+
if(node.nodeName.substr(0,1)==='#' && node.data.match(/\{\{[\w\.]+\}\}/)){
5064
var template = node.data;
5165
onChangeTasks.push(function(){
52-
node.data = template.replace(/\{\{(\w+)\}\}/g, function (match, key) {
53-
return model[key];
66+
node.data = template.replace(/\{\{([\w\.]+)\}\}/g, function (match, key) {
67+
return model.get(key);
5468
});
5569
});
5670
onChangeTasks[onChangeTasks.length-1]();
@@ -65,11 +79,11 @@
6579
if(element === srcElement){
6680
return false;
6781
}
68-
$(element).val(model[modelName]);
82+
$(element).val(model.get(modelName));
6983
});
7084
onChangeTasks[onChangeTasks.length-1]();
7185
$(element).bind('keypress change keyup',function(){
72-
model[modelName] = $(this).val();
86+
model.set(modelName,$(this).val());
7387
for(var i in onChangeTasks){
7488
onChangeTasks[i](this);
7589
}
@@ -85,8 +99,8 @@
8599
var allowAttributes = ['jq-src','jq-href'];
86100
var onChangeDelegate = function(element,attribute,template) {
87101
onChangeTasks.push(function(){
88-
element.setAttribute(attribute.substr(3),template.replace(/\{\{(\w+)\}\}/g, function (match, key) {
89-
return model[key];
102+
element.setAttribute(attribute.substr(3),template.replace(/\{\{([\w\.]+)\}\}/g, function (match, key) {
103+
return model.get(key);
90104
}));
91105
});
92106
};
@@ -108,8 +122,8 @@
108122

109123
var onChangeDelegate = function(element,attribute,template) {
110124
onChangeTasks.push(function () {
111-
element.setAttribute(attribute, template.replace(/\{\{(\w+)\}\}/g, function (match, key) {
112-
return model[key];
125+
element.setAttribute(attribute, template.replace(/\{\{([\w\.]+)\}\}/g, function (match, key) {
126+
return model.get(key);
113127
}));
114128
});
115129
};
@@ -120,7 +134,7 @@
120134
}
121135
var template = attributes[i].value;
122136
var attribute = attributes[i].name;
123-
if(template.match(/\{\{(\w+)\}\}/)){
137+
if(template.match(/\{\{([\w\.]+)\}\}/)){
124138
onChangeDelegate(element,attribute,template);
125139
onChangeTasks[onChangeTasks.length-1](null);
126140
}
@@ -133,7 +147,7 @@
133147
return NODE_STATUS_NORMAL;
134148
}
135149
onChangeTasks.push(function () {
136-
$(element).css(model[modelName]);
150+
$(element).css(model.get(modelName));
137151
});
138152
onChangeTasks[onChangeTasks.length-1](null);
139153
return NODE_STATUS_NORMAL;
@@ -144,7 +158,7 @@
144158
return NODE_STATUS_NORMAL;
145159
}
146160
onChangeTasks.push(function () {
147-
$(element).attr('disabled',model[modelName]);
161+
$(element).attr('disabled',model.get(modelName));
148162
});
149163
onChangeTasks[onChangeTasks.length-1](null);
150164
return NODE_STATUS_NORMAL;
@@ -171,18 +185,39 @@
171185
onChangeTasks.push(function(){
172186
$(element).empty();
173187
var modelName = element.getAttribute('jq-model');
174-
if(keyName === null){
175-
for(var i in model[listName]){
176-
$(element).append('<option>' + model[listName][i] + '</option>');
188+
var list = model.get(listName);
189+
if(list && typeof(list[0])==='object' && Object.keys(list[0]).length===1 && list[0][Object.keys(list[0])[0]] instanceof Array ) {
190+
for (var g in list){
191+
var $group = $('<optgroup></optgroup>');
192+
var groupKey = Object.keys(list[g])[0];
193+
$group.attr('label',groupKey);
194+
var subList = list[g][groupKey];
195+
if(keyName === null){
196+
for(var gi in subList){
197+
$group.append('<option value="'+subList[gi]+'">' + subList[gi] + '</option>');
198+
}
199+
}else{
200+
for (var gk in subList) {
201+
$group.append('<option value="' + subList[gk][keyName] + '">' + subList[gk]['valueName'] + '</option>');
202+
}
203+
}
204+
$(element).append($group);
177205
}
178206
}else{
179-
for(var k in model[listName]){
180-
$(element).append('<option value="' + model[listName][k][keyName] + '">' + model[listName][k]['valueName'] + '</option>');
207+
if(keyName === null) {
208+
for(var i in list){
209+
$(element).append('<option>' + list[i] + '</option>');
210+
}
211+
}else{
212+
for (var k in list) {
213+
$(element).append('<option value="' + list[k][keyName] + '">' + list[k]['valueName'] + '</option>');
214+
}
181215
}
182216
}
183-
$(element).val(model[modelName]);
217+
$(element).val(model.get(modelName));
184218
});
185219
onChangeTasks[onChangeTasks.length-1](null);
220+
$(element).removeAttr('jq-options');
186221
return NODE_STATUS_COVER;
187222
};
188223
bindingTypes.jqIf = function(element,model,onChangeTasks){
@@ -202,7 +237,7 @@
202237
}
203238
onChangeTasks.push(function(){
204239
$(element).remove();
205-
if(model[query]){
240+
if(model.get(query)){
206241
$(element).insertAfter(startComment);
207242
}
208243
});
@@ -212,7 +247,7 @@
212247

213248
bindingTypes.jqRepeat = function(element,model,onChangeTasks){
214249
var query, match;
215-
if(typeof(element.getAttribute)!=='function' || !(query = element.getAttribute('jq-repeat')) || !(match = query.match(/(\w+)\s+in\s+(\w+)/))){
250+
if(typeof(element.getAttribute)!=='function' || !(query = element.getAttribute('jq-repeat')) || !(match = query.match(/(\w+)\s+in\s+([\w\.]+)/))){
216251
return NODE_STATUS_NORMAL;
217252
}
218253
var modelName = match[2];
@@ -228,12 +263,14 @@
228263
parent.appendChild(endComment);
229264
}
230265

231-
var repeatRowDelegate = function(row){
232-
return template.replace(/\{\{([\w\.]+)\}\}/g,function(match,key){
233-
if(key.substr(0,rowName.length+1) === (rowName+'.')){
234-
return row[key.substr(rowName.length+1)];
235-
}
236-
});
266+
var repeatRowDelegate = function(subModel){
267+
var $row = $(template.replace(/\{\{([\w\.]+)\}\}/g,function(match,key){
268+
return subModel.get(key)?subModel.get(key):match;
269+
}));
270+
$row.removeAttr('jq-repeat');
271+
var subCtrl = createCtrl(subModel.getData(),$row);
272+
bindingInit(subCtrl);
273+
return $row;
237274
};
238275

239276

@@ -243,16 +280,60 @@
243280
currentNode = currentNode.nextSibling;
244281
$(currentNode).prev().remove();
245282
}
246-
var html = '';
247-
var list = model[modelName];
283+
var list = model.get(modelName);
248284
for(var i in list){
249-
html+= repeatRowDelegate(list[i]);
285+
var subModel = model.clone();
286+
subModel.getData()[rowName] = list[i];
287+
repeatRowDelegate(subModel).insertAfter(startComment);
250288
}
251-
$(html).insertAfter(startComment);
252289

253290
});
254291
onChangeTasks[onChangeTasks.length-1](null);
255292
return NODE_STATUS_COVER;
256293
};
257294

258-
}(jQuery));
295+
var ModelObject = function(data){
296+
if(typeof(data) === 'undefined' || !data){
297+
data = {};
298+
}
299+
var model = data;
300+
301+
this.set = function(key,value){
302+
var keys = key.split('.');
303+
var lastKey = keys.pop();
304+
var current = model;
305+
for(var i in keys){
306+
if(typeof(current[keys[i]]) === 'undefined'){
307+
current[keys[i]] = {};
308+
}
309+
current = current[keys[i]];
310+
}
311+
current[lastKey] = value;
312+
return value;
313+
};
314+
315+
this.get = function(key){
316+
var keys = key.split('.');
317+
var current = model;
318+
for(var i in keys){
319+
current = current[keys[i]];
320+
if(!current){
321+
return null;
322+
}
323+
}
324+
return current;
325+
};
326+
327+
this.subModel = function(key){
328+
return new ModelObject(this.get(key));
329+
};
330+
331+
this.getData = function(){
332+
return model;
333+
};
334+
335+
this.clone = function(){
336+
return new ModelObject($.extend(true,{},model));
337+
};
338+
};
339+
}));

0 commit comments

Comments
 (0)