radiant-fabulator_exhibit-extension 0.0.3 → 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
@@ -104,7 +104,87 @@ Fabulator.namespace('Exhibit');
104
104
  return div.firstChild;
105
105
  };
106
106
 
107
- var createDOMFromTemplate = function(rootID, templateNode, result, parentElmt) {
107
+ var itemList = function(view, parentElmt, templateNode, list) {
108
+ var separator = ", ",
109
+ last_separator = ", and ",
110
+ pair_separator = " and ",
111
+ values, value, lens,
112
+ valueType, lensElmt, lensRender,
113
+ i, n;
114
+
115
+ if( "separator" in templateNode ) {
116
+ separator = templateNode.separator;
117
+ }
118
+ if( "last_separator" in templateNode ) {
119
+ last_separator = templateNode.last_separator;
120
+ }
121
+ if( "pair_separator" in templateNode ) {
122
+ pair_separator = templateNode.pair_separator;
123
+ }
124
+
125
+ if(separator && separator.substr(0,1) != "<") {
126
+ separator = "<span>" + separator + "</span>";
127
+ }
128
+ if(last_separator && last_separator.substr(0,1) != "<") {
129
+ last_separator = "<span>" + last_separator + "</span>";
130
+ }
131
+ if(pair_separator && pair_separator.substr(0,1) != "<") {
132
+ pair_separator = "<span>" + pair_separator + "</span>";
133
+ }
134
+
135
+ valueType = list.valueType || "text";
136
+ values = list.values.items();
137
+
138
+ $(parentElmt).empty();
139
+
140
+ /* we want a popup that will show the lens for this item type */
141
+ for( i = 0, n = values.length; i < n; i += 1 ) {
142
+ if( valueType == 'item' ) {
143
+ value = that.getItem(values[i]);
144
+ lens = view.getLens(value);
145
+ if( lens == null ) {
146
+ value = value.label[0];
147
+ /* we should escape this value so it's just text */
148
+ $(value).appendTo($(parentElmt));
149
+ }
150
+ else {
151
+ /* construct a clickable link that will pop up the lens content */
152
+ lensElmt = $("<div></div>");
153
+ lensRender = lens.render(view, model, values[i]);
154
+ /* TODO: make id more universally unique */
155
+ $(lensRender).attr('id', 'facet-item-lens-' + values[i]);
156
+ $(lensRender).addClass('facets-overlay');
157
+ $("<a class='close ui-icon ui-icon-circle-close'></a>").prependTo($(lensRender));
158
+ $(lensRender).addClass('ui-corner-all');
159
+ trigger = $("<span rel='#facet-item-lens-'" + values[i] + "'>" + value.label[0] + "</span>")
160
+ trigger.appendTo(lensElmt);
161
+ $(lensRender).appendTo(lensElmt);
162
+ lensElmt.appendTo($(parentElmt));
163
+ $(lensRender).hide();
164
+ trigger.overlay();
165
+ }
166
+ }
167
+ else {
168
+ $("<span>" + values[i] + "</span>").appendTo($(parentElmt));
169
+ }
170
+
171
+ if( n > 1 ) {
172
+ if( i == n-2 ) {
173
+ if( n > 2 ) {
174
+ $(last_separator).appendTo($(parentElmt));
175
+ }
176
+ else {
177
+ $(pair_separator).appendTo($(parentElmt));
178
+ }
179
+ }
180
+ else if( i < n-1 ){
181
+ $(separator).appendTo($(parentElmt));
182
+ }
183
+ }
184
+ }
185
+ };
186
+
187
+ var createDOMFromTemplate = function(view, rootID, templateNode, result, parentElmt) {
108
188
  var node, elmt, tag, attribute, value, v, n, i, items;
109
189
 
110
190
  if(templateNode == null) {
@@ -199,12 +279,10 @@ Fabulator.namespace('Exhibit');
199
279
  }
200
280
  else if( attribute == "content" ) {
201
281
  if( value != null ) {
202
- items = value.evaluateOneItem(rootID, that.dataSource);
203
- if( items.values.size() > 1 ) {
282
+ items = value.evaluateOnItem(rootID, that.dataSource);
283
+ if( items.values.size() > 0 ) {
204
284
  // we have a list of items
205
- }
206
- else if( items.values.size() == 1 ) {
207
- elmt.innerText = (items.values.items())[0];
285
+ itemList(view, elmt, templateNode, items);
208
286
  }
209
287
  }
210
288
  }
@@ -219,7 +297,7 @@ Fabulator.namespace('Exhibit');
219
297
  setting += e;
220
298
  }
221
299
  else {
222
- r = e.evaluateOneItem(rootID, that.dataSource);
300
+ r = e.evaluateOnItem(rootID, that.dataSource);
223
301
  setting += (r.values.items()).join("");
224
302
  }
225
303
  });
@@ -230,7 +308,7 @@ Fabulator.namespace('Exhibit');
230
308
  else if( attribute == "children" ) {
231
309
  if( value != null ) {
232
310
  for(i = 0, n = value.length; i < n; i++) {
233
- createDOMFromTemplate(rootID, value[i], result, elmt);
311
+ createDOMFromTemplate(view, rootID, value[i], result, elmt);
234
312
  }
235
313
  }
236
314
  }
@@ -242,9 +320,9 @@ Fabulator.namespace('Exhibit');
242
320
  }
243
321
  };
244
322
 
245
- that.renderTemplate = function(rootID, template) {
323
+ that.renderTemplate = function(view, rootID, template) {
246
324
  var result = {};
247
- result.elmt = createDOMFromTemplate(rootID, template, result, null);
325
+ result.elmt = createDOMFromTemplate(view, rootID, template, result, null);
248
326
 
249
327
  return result;
250
328
  };
@@ -155,6 +155,7 @@ jQuery(document).ready(function($){
155
155
  var options = {
156
156
  };
157
157
 
158
- Fabulator.Exhibit.ViewPanel('#' + $(el).attr('id'), options);
158
+ //Fabulator.Exhibit.ViewPanel('#' + $(el).attr('id'), options);
159
+ Fabulator.Exhibit.ViewPanel(el, options);
159
160
  });
160
161
  });
@@ -110,7 +110,7 @@
110
110
  };
111
111
  };
112
112
 
113
- that.evaluateOneItem = function( itemID, database ) {
113
+ that.evaluateOnItem = function( itemID, database ) {
114
114
  return this.evaluate(
115
115
  { "value" : itemID },
116
116
  { "value" : "item" },
@@ -156,159 +156,9 @@ Fabulator.namespace('Exhibit');
156
156
  return that;
157
157
  };
158
158
 
159
- Exhibit.Facets.Base = function(type, container, options) {
159
+ Exhibit.Facets.initView = function(type, container, options) {
160
160
  var that = fluid.initView("Fabulator.Exhibit.Facets." + type, container, options);
161
161
 
162
- var parseSetting = function(s, type, spec) {
163
- var sType = typeof s, f, i, n, choices;
164
-
165
- if(type == "text") {
166
- return s;
167
- }
168
- else if( type == "float" ) {
169
- if( sType == "number" ) {
170
- return s;
171
- }
172
- else if( sType == "string" ) {
173
- f = parseFloat(s);
174
- if( !isNaN(f) ) {
175
- return f;
176
- }
177
- }
178
- throw new Error("Expected a floating point number but got " + s);
179
- }
180
- else if( type == "int" ) {
181
- if( sType == "number" ) {
182
- return Math.round(s);
183
- }
184
- else if( sType == "string" ) {
185
- n = parseInt(s);
186
- if( !isNaN(n) ) {
187
- return n;
188
- }
189
- }
190
- throw new Error("Expected an integer but got " + s);
191
- }
192
- else if(type == "boolean" ) {
193
- if( sType == "boolean" ) {
194
- return s;
195
- }
196
- else if( sType == "string" ) {
197
- s = s.toLowerCase();
198
- if( s == "true" || s == "on" || s == "yes" ) {
199
- return true;
200
- }
201
- else if( s == "false" || s == "off" || s == "no" ) {
202
- return false;
203
- }
204
- }
205
- throw new Error("Expected either 'true' or 'false' but got " + s);
206
- }
207
- else if( type == "function" ) {
208
- if( sType == "function" ) {
209
- return s;
210
- }
211
- else if( sType == "string" ) {
212
- try {
213
- f = eval(s);
214
- if( typeof f == "function") {
215
- return f;
216
- }
217
- }
218
- catch(e) {
219
- // silent
220
- }
221
- }
222
- throw new Error("Expected a function or the name of a function but got " + s);
223
- }
224
- else if( type == "enum" ) {
225
- choices = spec.choices;
226
- for(i = 0, n = choices.length; i < n; i += 1 ) {
227
- if(choices[i] == s) {
228
- return s;
229
- }
230
- }
231
- throw new Error("Expected one of " + choices.join(", ") + " but got " + s);
232
- }
233
- else if( type == "expression" ) {
234
- return Exhibit.ExpressionParser().parse(s);
235
- }
236
- else {
237
- throw new Error("Unknown setting type " + type);
238
- }
239
- };
240
-
241
- that.collectSettingsFromDOM = function(specs) {
242
- var field, spec, name, settings, type, value, dimensions,
243
- separator, a, i, n;
244
-
245
- that.options.facet = that.options.facet || { };
246
-
247
- settings = that.options.facet;
248
-
249
- for(field in specs) {
250
- spec = specs[field];
251
- name = field;
252
- if( "name" in spec ) {
253
- name = spec.name;
254
- }
255
- if( !(name in settings) && "defaultValue" in spec) {
256
- settings[name] = spec.defaultValue;
257
- }
258
-
259
- value = $(container).attr("ex:" + field);
260
- if( value == null ) {
261
- continue;
262
- }
263
-
264
- if( typeof value == "string") {
265
- value = value.trim();
266
- if( value.length == 0 ) {
267
- continue;
268
- }
269
- }
270
-
271
- type = "text";
272
- if( "type" in spec ) {
273
- type = spec.type;
274
- }
275
-
276
- dimensions = 1;
277
- if( "dimensions" in spec ) {
278
- dimensions = spec.dimensions;
279
- }
280
-
281
- try {
282
- if( dimensions > 1 || dimensions == '*') {
283
- separator = ",";
284
- if( "separator" in spec ) {
285
- separator = spec.separator;
286
- }
287
-
288
- a = value.split(separator);
289
- if( dimensions != '*' && a.length != dimensions ) {
290
- throw new Error("Expected a tuple of " + dimensions + " dimensions separated with " + separator + " but got " + value);
291
- }
292
- else {
293
- for(i = 0, n = a.length; i < n; i += 1 ) {
294
- a[i] = parseSetting(a[i].trim(), type, spec);
295
- }
296
-
297
- settings[name] = a;
298
- }
299
- }
300
- else {
301
- settings[name] = parseSetting(value, type, spec);
302
- }
303
- }
304
- catch(e) {
305
- Exhibit.debug(e);
306
- }
307
- }
308
-
309
- that.options.facet = settings;
310
- };
311
-
312
162
  options = that.options;
313
163
 
314
164
  that.events = { };
@@ -317,14 +167,14 @@ Fabulator.namespace('Exhibit');
317
167
  options.viewPanel.registerFilter(that);
318
168
 
319
169
  if( "settingSpec" in options ) {
320
- that.collectSettingsFromDOM(options.settingSpec);
170
+ that.options.facet = Exhibit.Util.collectSettingsFromDOM(container, options.settingSpec);
321
171
  }
322
172
 
323
173
  return that;
324
174
  };
325
175
 
326
176
  Exhibit.Facets.TextSearch = function(container, options) {
327
- var that = Exhibit.Facets.Base("TextSearch", container, options),
177
+ var that = Exhibit.Facets.initView("TextSearch", container, options),
328
178
  dom, input_id;
329
179
  options = that.options;
330
180
 
@@ -342,7 +192,7 @@ Fabulator.namespace('Exhibit');
342
192
  if( that.text && that.options.facet.expression ) {
343
193
  values = [ ];
344
194
  $(that.options.facet.expression).each(function(idx, ex) {
345
- var items = ex.evaluateOneItem(id, dataSource);
195
+ var items = ex.evaluateOnItem(id, dataSource);
346
196
  values = values.concat(items.values.items());
347
197
  });
348
198
  n = values.length;
@@ -366,7 +216,7 @@ Fabulator.namespace('Exhibit');
366
216
  $("<input type='text' id='" + input_id + "'>").appendTo($(dom.valuesContainer));
367
217
 
368
218
  $("#" + input_id).keyup(function() {
369
- that.text = $("#" + input_id).val().toLowerCase().trim();
219
+ that.text = $.trim($("#" + input_id).val().toLowerCase());
370
220
  that.events.onFilterChange.fire();
371
221
  });
372
222
 
@@ -374,7 +224,7 @@ Fabulator.namespace('Exhibit');
374
224
  };
375
225
 
376
226
  Exhibit.Facets.List = function(container, options) {
377
- var that = Exhibit.Facets.Base("List", container, options),
227
+ var that = Exhibit.Facets.initView("List", container, options),
378
228
  valueSet = Exhibit.Set(),
379
229
  counts = { },
380
230
  entries = [ ],
@@ -539,7 +389,7 @@ Fabulator.namespace('Exhibit');
539
389
  // that.eventModelChange(that.viewPanel.dataView);
540
390
 
541
391
  that.eventFilterItem = function(dataSource, id) {
542
- var values = options.facet.expression.evaluateOneItem(id, dataSource),
392
+ var values = options.facet.expression.evaluateOnItem(id, dataSource),
543
393
  i, n;
544
394
 
545
395
 
@@ -0,0 +1,473 @@
1
+ /*
2
+ * (c) Copyright Texas A&M University 2010. All rights reserved.
3
+ *
4
+ * Portions of this code are copied from The SIMILE Project:
5
+ * (c) Copyright The SIMILE Project 2006. All rights reserved.
6
+ *
7
+ * Redistribution and use in source and binary forms, with or without
8
+ * modification, are permitted provided that the following conditions
9
+ * are met:
10
+ *
11
+ * 1. Redistributions of source code must retain the above copyright
12
+ * notice, this list of conditions and the following disclaimer.
13
+ *
14
+ * 2. Redistributions in binary form must reproduce the above copyright
15
+ * notice, this list of conditions and the following disclaimer in the
16
+ * documentation and/or other materials provided with the distribution.
17
+ *
18
+ * 3. The name of the author may not be used to endorse or promote products
19
+ * derived from this software without specific prior written permission.
20
+ *
21
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31
+ *
32
+ */
33
+
34
+ Fabulator.namespace('Exhibit');
35
+
36
+ (function($, Exhibit) {
37
+
38
+ Exhibit.Util = { };
39
+
40
+ var parseSetting = function(s, type, spec) {
41
+ var sType = typeof s, f, i, n, choices;
42
+
43
+ if(type == "text") {
44
+ return s;
45
+ }
46
+ else if( type == "float" ) {
47
+ if( sType == "number" ) {
48
+ return s;
49
+ }
50
+ else if( sType == "string" ) {
51
+ f = parseFloat(s);
52
+ if( !isNaN(f) ) {
53
+ return f;
54
+ }
55
+ }
56
+ throw new Error("Expected a floating point number but got " + s);
57
+ }
58
+ else if( type == "int" ) {
59
+ if( sType == "number" ) {
60
+ return Math.round(s);
61
+ }
62
+ else if( sType == "string" ) {
63
+ n = parseInt(s);
64
+ if( !isNaN(n) ) {
65
+ return n;
66
+ }
67
+ }
68
+ throw new Error("Expected an integer but got " + s);
69
+ }
70
+ else if(type == "boolean" ) {
71
+ if( sType == "boolean" ) {
72
+ return s;
73
+ }
74
+ else if( sType == "string" ) {
75
+ s = s.toLowerCase();
76
+ if( s == "true" || s == "on" || s == "yes" ) {
77
+ return true;
78
+ }
79
+ else if( s == "false" || s == "off" || s == "no" ) {
80
+ return false;
81
+ }
82
+ }
83
+ throw new Error("Expected either 'true' or 'false' but got " + s);
84
+ }
85
+ else if( type == "function" ) {
86
+ if( sType == "function" ) {
87
+ return s;
88
+ }
89
+ else if( sType == "string" ) {
90
+ try {
91
+ f = eval(s);
92
+ if( typeof f == "function") {
93
+ return f;
94
+ }
95
+ }
96
+ catch(e) {
97
+ // silent
98
+ }
99
+ }
100
+ throw new Error("Expected a function or the name of a function but got " + s);
101
+ }
102
+ else if( type == "enum" ) {
103
+ choices = spec.choices;
104
+ for(i = 0, n = choices.length; i < n; i += 1 ) {
105
+ if(choices[i] == s) {
106
+ return s;
107
+ }
108
+ }
109
+ throw new Error("Expected one of " + choices.join(", ") + " but got " + s);
110
+ }
111
+ else if( type == "expression" ) {
112
+ return Exhibit.ExpressionParser().parse(s);
113
+ }
114
+ else {
115
+ throw new Error("Unknown setting type " + type);
116
+ }
117
+ };
118
+
119
+ Exhibit.Util.collectSettingsFromDOM = function(container, specs) {
120
+ var field, spec, name, settings, type, value, dimensions,
121
+ separator, a, i, n;
122
+
123
+ settings = { };
124
+
125
+ for(field in specs) {
126
+ spec = specs[field];
127
+ name = field;
128
+ if( "name" in spec ) {
129
+ name = spec.name;
130
+ }
131
+ if( !(name in settings) && "defaultValue" in spec) {
132
+ settings[name] = spec.defaultValue;
133
+ }
134
+
135
+ value = $(container).attr("ex:" + field);
136
+ if( value == null ) {
137
+ continue;
138
+ }
139
+
140
+ if( typeof value == "string") {
141
+ value = $.trim(value);
142
+ if( value.length == 0 ) {
143
+ continue;
144
+ }
145
+ }
146
+
147
+ type = "text";
148
+ if( "type" in spec ) {
149
+ type = spec.type;
150
+ }
151
+
152
+ dimensions = 1;
153
+ if( "dimensions" in spec ) {
154
+ dimensions = spec.dimensions;
155
+ }
156
+
157
+ try {
158
+ if( dimensions > 1 || dimensions == '*') {
159
+ separator = ",";
160
+ if( "separator" in spec ) {
161
+ separator = spec.separator;
162
+ }
163
+
164
+ a = value.split(separator);
165
+ if( dimensions != '*' && a.length != dimensions ) {
166
+ throw new Error("Expected a tuple of " + dimensions + " dimensions separated with " + separator + " but got " + value);
167
+ }
168
+ else {
169
+ for(i = 0, n = a.length; i < n; i += 1 ) {
170
+ a[i] = parseSetting($.trim(a[i]), type, spec);
171
+ }
172
+
173
+ settings[name] = a;
174
+ }
175
+ }
176
+ else {
177
+ settings[name] = parseSetting(value, type, spec);
178
+ }
179
+ }
180
+ catch(e) {
181
+ Exhibit.debug(e);
182
+ }
183
+ }
184
+
185
+ return settings;
186
+ };
187
+
188
+ Exhibit.Util.TypeParsers = {
189
+ text: function(v, f) {
190
+ return f(v);
191
+ },
192
+ float: function(v, f) {
193
+ var n = parseFloat(v);
194
+ if(!isNaN(n)) {
195
+ return f(n);
196
+ }
197
+ return false;
198
+ },
199
+
200
+ int: function(v, f) {
201
+ var n = parseInt(v);
202
+ if(!isNaN(n)) {
203
+ return f(n);
204
+ }
205
+ return false;
206
+ },
207
+
208
+ date: function(v, f) {
209
+ var d;
210
+
211
+ if( v instanceof Date ) {
212
+ return f(v);
213
+ }
214
+ else if( typeof(v) == "number" ) {
215
+ d = new Date(0);
216
+ d.setUTCFullYear(v);
217
+ return f(d);
218
+ }
219
+ else {
220
+ d = Exhibit.DateTime.parseIso8601DateTime(v.toString());
221
+ if( d != null ) {
222
+ return f(d);
223
+ }
224
+ }
225
+ return false;
226
+ },
227
+ url: function(v, f) {
228
+ return f(Exhibit.Persistence.resolveURL(v.toString()));
229
+ },
230
+ boolean: function(v, f) {
231
+ v = v.toString().toLowerCase();
232
+ if( v == "true" ) {
233
+ return f(true);
234
+ }
235
+ else if( v == "false" ) {
236
+ return f(false);
237
+ }
238
+ return false;
239
+ }
240
+ };
241
+
242
+ var typeToParser = function(type) {
243
+ if( type in Exhibit.Util.TypeParsers ) {
244
+ return Exhibit.Util.TypeParsers[type];
245
+ }
246
+ throw new Error("Unknown setting type " + type);
247
+ };
248
+
249
+ var createTupleAccessor = function(f, spec) {
250
+ var value = f(spec.attributeName),
251
+ expression, parsers, i, n, bindingNames, separator;
252
+
253
+ if( value == null ) {
254
+ return null;
255
+ }
256
+
257
+ if( typeof(value) == "string" ) {
258
+ value = $.trim(value);
259
+ if( value.length == 0 ) {
260
+ return null;
261
+ }
262
+ }
263
+
264
+ try {
265
+ expression = Exhibit.ExpressionParser().parse(value);
266
+ parsers = [ ];
267
+ bindingTypes = spec.types;
268
+
269
+ for( i = 0, n = bindingTypes.length; i < n; i += 1 ) {
270
+ parsers.push(typeToParser(bindingTypes[i]));
271
+ }
272
+
273
+ bindingNames = spec.bindingNames;
274
+ separator = ",";
275
+
276
+ if( "separator" in spec ) {
277
+ separator = spec.separator;
278
+ }
279
+
280
+ return function(itemID, database, visitor, tuple) {
281
+ expression.evaluateOnItem(itemID, database).values.visit(
282
+ function(v) {
283
+ var a = v.split(separator),
284
+ tuple2 = { },
285
+ i, n;
286
+
287
+ if( a.length == parsers.length ) {
288
+ if( tuple ) {
289
+ for(n in tuple) {
290
+ tuple2[n] = tuple[n];
291
+ }
292
+ }
293
+
294
+ for(i = 0, n = bindingNames.length; i < n; i += 1) {
295
+ tuple2[bindingNames[i]] = null;
296
+ parsers[i](a[i], function(v) { tuple2[bindingNames[i]] = v; });
297
+ }
298
+ visitor(tuple2);
299
+ }
300
+ }
301
+ );
302
+ };
303
+ }
304
+ catch(e) {
305
+ Exhibit.debug(e);
306
+ return null;
307
+ }
308
+ };
309
+
310
+ var createElementalAccessor = function(f, spec) {
311
+ var value = f(spec.attributeName),
312
+ bindingType = "text",
313
+ expression, parser;
314
+
315
+ if( value == null ) {
316
+ return null;
317
+ }
318
+
319
+ if( typeof(value) == "string" ) {
320
+ value = $.trim(value);
321
+ if( value.length == 0 ) {
322
+ return null;
323
+ }
324
+ }
325
+
326
+ if( "type" in spec ) {
327
+ bindingType = spec.type;
328
+ }
329
+
330
+ try {
331
+ expression = Exhibit.ExpressionParser().parse(value);
332
+ parser = typeToParser(bindingType);
333
+
334
+ return function(itemID, database, visitor) {
335
+ expression.evaluateOnItem(itemID, database).values.visit(
336
+ function(v) { return parser(v, visitor); }
337
+ );
338
+ };
339
+ }
340
+ catch(e) {
341
+ Exhibit.debug(e);
342
+ return null;
343
+ }
344
+ };
345
+
346
+ var evaluateBindings = function(value, database, visitor, bindings) {
347
+ var maxIndex = bindings.length - 1,
348
+ f = function(tuple, index) {
349
+ var binding = bindings[index],
350
+ visited = false,
351
+ recurse = index == maxIndex ? function() { visitor(tuple); } : function() { f(tuple, index + 1); },
352
+ bindingName;
353
+
354
+ /*
355
+ The tuple accessor will copy existing fields out of "tuple" into a new
356
+ object and then injects new fields into it before calling the visitor.
357
+ This is so that the same tuple object is not reused for different
358
+ tuple values, which would cause old tuples to be overwritten by new ones.
359
+ */
360
+ if( binding.isTuple ) {
361
+ binding.accessor(
362
+ value,
363
+ database,
364
+ function(tuple2) { visited = true; tuple = tuple2; recurse(); },
365
+ tuple
366
+ );
367
+ }
368
+ else {
369
+ bindingName = binding.bindingName;
370
+ binding.accessor(
371
+ value,
372
+ database,
373
+ function(v) { visited = true; tuple[bindingName] = v; recurse(); }
374
+ );
375
+ }
376
+
377
+ if( !visited ) { recurse(); }
378
+ };
379
+
380
+ f({}, 0);
381
+ };
382
+
383
+ var createBindingsAccessor = function(f, bineingSpecs) {
384
+ var bindings = [ ],
385
+ i, n, accessor, bindingSpec, accessor, isTuple;
386
+
387
+ for( i = 0, n = bindingSpecs.length; i < n; i += 1 ) {
388
+ bindingSpec = bindingSpecs[i];
389
+ accessor = null;
390
+ isTuple = false;
391
+
392
+ if( "bindingNames" in bindingSpec ) {
393
+ isTuple = true;
394
+ accessor = createTupleAccessor(f, bindingSpec);
395
+ }
396
+ else {
397
+ accessor = createElementalAccessor(f, bindingSpec);
398
+ }
399
+
400
+ if( accessor = null ) {
401
+ if( !("optional" in bindingSpec) || !bindingSpec.optional ) {
402
+ return null;
403
+ }
404
+ }
405
+ else {
406
+ bindings.push({
407
+ bindingName: bindingSpec.bindingName,
408
+ accessor: accessor,
409
+ isTuple: isTuple
410
+ });
411
+ }
412
+ }
413
+
414
+ return function(value, database, visitor) {
415
+ evaluateBindings(value, database, visitor, bindings);
416
+ };
417
+ };
418
+
419
+ var createAccessors = function(f, specs, accessors) {
420
+ var field, spec, accessorName, accessor, isTuple,
421
+ createOneAccessor, alternatives, i, n;
422
+
423
+ for(field in specs) {
424
+ spec = specs[field];
425
+ accessorName = spec.accessorName;
426
+ accessor = null;
427
+ isTuple = false;
428
+
429
+ createOneAccessor = function(spec2) {
430
+ isTuple = false;
431
+ if( "bindings" in specs ) {
432
+ return createBindingsAccessor(f, spec2.bindings);
433
+ }
434
+ else if( "bindingNames" in spec2 ) {
435
+ isTuple = true;
436
+ return createTupleAccessor(f, spec2);
437
+ }
438
+ else {
439
+ return createElementalAccessor(f, spec2);
440
+ }
441
+ };
442
+
443
+ if( "alternatives" in spec ) {
444
+ alternatives = spec.alternatives;
445
+ for( i = 0, n = alternatives.length; i < n; i += 1 ) {
446
+ accessor = createOneAccessor(alternatives[i]);
447
+ if( accessor != null ) {
448
+ break;
449
+ }
450
+ }
451
+ }
452
+ else {
453
+ accessor = createOneAccessor(spec);
454
+ }
455
+
456
+ if( accessor != null ) {
457
+ accessors[accessorName] = accessor;
458
+ }
459
+ else if( !(accessorName in accessors) ) {
460
+ accessors[accessorName] = function(value, database, visitor) {};
461
+ }
462
+ }
463
+ };
464
+
465
+ Exhibit.Util.createAccessorsFromDOM = function(container, specs, accessors) {
466
+ createAccessors(
467
+ function(field) { return $(container).attr("ex:" + field); },
468
+ specs,
469
+ accessors
470
+ );
471
+ };
472
+
473
+ })(jQuery, Fabulator.Exhibit);