Anonymous avatar Anonymous committed 18ff05e

Some first (working) sketches for data layer components in record, rest and control. Improved route to also do a mapping upon start-up.

Comments (0)

Files changed (9)

+<!DOCTYPE html>
+<html lang="en" class="no-js">
+
+	<head>
+		<meta http-equiv="X-UA-Compatible" content="IE=Edge">
+		<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+		
+		<title>
+			CSS
+		</title>
+		
+	    <script type="text/javascript" src="../lib/modernizr-1.5.min.js"></script>
+		<style type="text/css">
+			
+			div {
+				position: absolute;
+				top: 0;
+				right: 0;
+				bottom: 0;
+				left: 0;
+				background-color: red;
+				-webkit-transition: opacity 1s;
+			}
+			div.no-display {
+				bottom: 100%;
+				opacity: 0;
+				-webkit-transition: opacity 1s, bottom 0s 1s;
+			}
+			
+		</style>
+	</head>
+	
+	<body>
+		
+		<div class="no-display">
+			blaaa
+		</div>
+		
+		<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.js"></script>
+		<script type="text/javascript">
+			
+			$('html').click(function() {
+				$('div').toggleClass('display no-display');
+			});
+			
+		</script>
+		
+	</body>
+
+</html>

demo/pre.html

-<!DOCTYPE html>
-<html lang="en" class="no-js">
-
-	<head>
-		<meta http-equiv="X-UA-Compatible" content="IE=Edge">
-		<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
-		
-		<title>
-			pre-wrap
-		</title>
-		
-	    <script type="text/javascript" src="../lib/modernizr-1.5.min.js"></script>
-		<style type="text/css">
-			
-			div {
-				white-space: pre-wrap;
-				border: 1px solid red;
-			}
-			
-		</style>
-	</head>
-	
-	<body>
-		
-<div>line1
-	
-line3</div>
-<div>line1\n\nline3</div>
-		
-	</body>
-
-</html>

lib/jshashset_src.js

+/**
+ * Copyright 2010 Tim Down.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * HashSet
+ *
+ * This is a JavaScript implementation of HashSet, similar in concept to those found in Java or C#'s standard libraries.
+ * It is distributed as part of jshashtable and depends on jshashtable.js. It creates a single constructor function
+ * called HashSet in the global scope.
+ *
+ * Author: Tim Down <tim@timdown.co.uk>
+ * Version: 2.1
+ * Build date: 27 March 2010
+ * Website: http://www.timdown.co.uk/jshashtable/
+ */
+
+function HashSet(hashingFunction, equalityFunction) {
+    var hashTable = new Hashtable(hashingFunction, equalityFunction);
+
+    this.add = function(o) {
+        hashTable.put(o, true);
+    };
+
+    this.addAll = function(arr) {
+        var i = arr.length;
+        while (i--) {
+            hashTable.put(arr[i], true);
+        }
+    };
+
+    this.values = function() {
+        return hashTable.keys();
+    };
+
+    this.remove = function(o) {
+        return hashTable.remove(o) ? o : null;
+    };
+
+    this.contains = function(o) {
+        return hashTable.containsKey(o);
+    };
+
+    this.clear = function() {
+        hashTable.clear();
+    };
+
+    this.size = function() {
+        return hashTable.size();
+    };
+
+    this.isEmpty = function() {
+        return hashTable.isEmpty();
+    };
+
+    this.clone = function() {
+        var h = new HashSet(hashingFunction, equalityFunction);
+        h.addAll(hashTable.keys());
+        return h;
+    };
+
+    this.intersection = function(hashSet) {
+        var intersection = new HashSet(hashingFunction, equalityFunction);
+        var values = hashSet.values(), i = values.length, val;
+        while (i--) {
+            val = values[i];
+            if (hashTable.containsKey(val)) {
+                intersection.add(val);
+            }
+        }
+        return intersection;
+    };
+
+    this.union = function(hashSet) {
+        var union = this.clone();
+        var values = hashSet.values(), i = values.length, val;
+        while (i--) {
+            val = values[i];
+            if (!hashTable.containsKey(val)) {
+                union.add(val);
+            }
+        }
+        return union;
+    };
+
+    this.isSubsetOf = function(hashSet) {
+        var values = hashTable.keys(), i = values.length;
+        while (i--) {
+            if (!hashSet.contains(values[i])) {
+                return false;
+            }
+        }
+        return true;
+    };
+}

src/jquery.al.control.js

 		
 	},
 	
+	awake: function() {
+		for (member in this) {
+			if (this[member] instanceof $.al.Field) {
+				this[member].sleep(false);
+			}
+		}
+	},
+	
 	displayInit: $.noop,
 	
 	observeDisplay: function(value) {
-		this.element[value ? 'show' : 'hide']();
+		if (value) {
+			this.element.removeClass('no-display').addClass('display');
+		} else {
+			this.element.removeClass('display').addClass('no-display');
+		}
 		if (value && this.displayed !== true) {
 			this.displayed = true;
 			this.displayInit();
 
 		if (action === 'init') {
 			var instance = new Class(this);
-			for (member in instance) {
-				if (instance[member] instanceof $.al.Field) {
-					instance[member].sleep(false);
-				}
-			}
+			instance.awake();
 			$this.store('control', 'instance', instance);
 			return true;
 		}

src/jquery.al.dataview.js

 					return true;
 				}
 				
-				$this.flirt('templateNode', templateName).store('dataview', 'data', new Record(data));
+				var $template = $this.flirt('templateNode', templateName);
 				
-				if (data instanceof $.al.List) {
+				var savedList = $template.fetch('dataview', 'data');
+				if (data instanceof $.al.List && (!savedList || savedList.gettt() !== data)) {
 					data.observe(function() {
 						// TODO: Note that templateName can be undefined, in
 						// which case all views contained by $this will be
 					});
 				}
 				
+				$template.store('dataview', 'data', new Record(data));
+				
 				var trigger = [];
 				$this.flirt('set', data instanceof $.al.List ? data.val() : data, templateName, function(d) {
 					var $nodes = this;

src/jquery.al.flirt.js

 // TODO: Add a function to the flirt run-time environment which can tell us if
 // we are at the first or last item of a list. Use case: allow for easy
-// generation of comma-separated lists.
+// generation of comma-separated lists. ==> think we should solve this in a
+// more generic way; by providing access to a shared/static scope in which you
+// can store variables that live throughout the entire parse iteration.
 
 // TODO: Find out why it does not work on <title />, and if we can change
 // this situation.
 
+// TODO: Provide a prettify template function (in addition to safe and esc).
+
 (function($) {
 
 var settings = {

src/jquery.al.record.js

 
 (function($) {
 
+$.al.Record = $.al.Field.extend(function() {
+	
+	this.equals = function(record) {
+		return this.toString() === record.toString() && this.val() === record.val();
+	};
+	
+	this.toString = function() {
+		return "[object $.al.Record]";
+	};
+	
+});
+
+// TODO: store does not have to be global i guess...
+var store = $.store = new Hashtable();
+$.al.Record.instantiate = function(data, type) {
+	if (!$.isFunction(type) || !((new type) instanceof $.al.Record)) {
+		type = $.al.Record;
+	}
+	
+	var singularity = false;
+	if (!$.isArray(data)) {
+		data = [data];
+		singularity = true;
+	}
+	
+	var records = [],
+		record, existingRecord;
+	for (var i = 0, l = data.length; i < l; i++) {
+		record = type().val(data[i]);
+		if (store.containsKey(record)) {
+			existingRecord = store.remove(record);
+			record = existingRecord.val(record.val());
+		}
+		store.put(record, record);
+		records.push(record);
+	}
+	
+	return records.length === 1 && singularity ? records[0] : records;
+};
+
+$.al.Record.del = function(records) {
+	if (records === undefined) {
+		return;
+	}
+	
+	if (!$.isArray(records)) {
+		records = [records];
+	}
+	
+	for (var i = 0, l = records.length; i < l; i++) {
+		// TODO: can't this remove call be done by an observer that is attached
+		// to the fielddelete event at the moment the record is added to the store?
+		store.remove(records[i]);
+		// records[i].remove();
+		// $(records[i]).trigger('fielddelete');
+	}
+};
+
+}(jQuery));
+
+
+
+
+/*
+(function($) {
+
 var Record = function(data) {
 	if (!(this instanceof Record)) {
 		return new Record(data);
 };
 
 }(jQuery));
+*/

src/jquery.al.rest.js

 // of jsonp requested and html retrieved -- not sure about behavior in other
 // scenarios).
 
-$.Rest = function(url, dataType, error) {
+$.Rest = function(url, dataType, error, validate) {
 	if (!(this instanceof $.Rest)) {
-		return new $.Rest(url, dataType, error);
+		return new $.Rest(url, dataType, error, validate);
 	}
 	
 	if (!$.isFunction(error)) {
 				'application/json' :
 				'application/x-www-form-urlencoded';
 			
-			$.ajax({
+			var fullUrl = url + handler;
+			if (verb === 'DELETE' && data && !$.isEmptyObject(data)) {
+				fullUrl += '?' + $.param(data, true);
+			}
+			
+			var ajaxObj = {
 				type: verb,
-				url: url + handler,
+				url: fullUrl,
 				dataType: dataType,
 				contentType: contentType,
 				processData: contentType === 'application/x-www-form-urlencoded',
 				complete: function(xhr, textStatus) {
 					// console.log('$.ajax complete:');
 					// console.log(textStatus);
+					
+					// TODO: We probably want to cancel the request as soon
+					// as the xhr does not validate...
+					if ($.isFunction(validate)) {
+						validate(xhr);
+					}
 				},
 				dataFilter: function(data, type) {
 					// console.log('$.ajax dataFilter:');
 				},
 				error: function(xhr, textStatus, errorThrown) {
 					// console.log('$.ajax error:');
+					// console.log(xhr);
 					// console.log(textStatus);
-					// console.log(error);
-					error.call(this, $.httpData(xhr));
+					// console.log(errorThrown);
+					error.call(this, xhr, $.httpData(xhr));
 				}
-			});
+			};
+			// console.log(ajaxObj);
+			$.ajax(ajaxObj);
 		}, 0);
 	};
 };
 	},
 	put: function(handler, data, success) {
 		this.request('PUT', handler, data, success);
+	},
+	del: function(handler, data, success) {
+		this.request('DELETE', handler, data, success);
 	}
 	
 };

src/jquery.al.route.js

 	
 	var routes = $.makeArray(arguments);
 	
-	$(window).bind('hashchange', function() {
+	var map = function() {
 		var $this = $(this),
 			hash = location.hash,
 			oldMatch = $this.fetch('route', 'match'),	// TODO: Use $.fetch(?)
 		}
 		$this.trigger('routechange', eventData);
 		
-	});
+	};
+	
+	$(window).bind('hashchange', map);
+	
+	map();
 	
 };
 
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.