Przeglądaj źródła

The http/javascript interface for the "OurBiz" application

mingodad 13 lat temu
rodzic
commit
f0be39d212
51 zmienionych plików z 9491 dodań i 0 usunięć
  1. 0 0
      ourbiz/s/codemirror-compressed.js
  2. 174 0
      ourbiz/s/codemirror.css
  3. 27 0
      ourbiz/s/dialogs.css
  4. 56 0
      ourbiz/s/ourbiz/ajax-data-table.js
  5. 1739 0
      ourbiz/s/ourbiz/app-base.js
  6. 445 0
      ourbiz/s/ourbiz/barchart.js
  7. 211 0
      ourbiz/s/ourbiz/calendar-chooser.js
  8. 258 0
      ourbiz/s/ourbiz/css/styles.css
  9. BIN
      ourbiz/s/ourbiz/dadbiz_120.png
  10. 137 0
      ourbiz/s/ourbiz/dadlib.js
  11. 150 0
      ourbiz/s/ourbiz/editor.html
  12. 297 0
      ourbiz/s/ourbiz/entities.js
  13. 114 0
      ourbiz/s/ourbiz/etnetstrings.js
  14. 1416 0
      ourbiz/s/ourbiz/excanvas.js
  15. BIN
      ourbiz/s/ourbiz/favicon.ico
  16. 151 0
      ourbiz/s/ourbiz/gl-chart.js
  17. 93 0
      ourbiz/s/ourbiz/gl-groups.js
  18. 248 0
      ourbiz/s/ourbiz/gl-transactions.js
  19. 191 0
      ourbiz/s/ourbiz/groups.js
  20. BIN
      ourbiz/s/ourbiz/images/bar.png
  21. BIN
      ourbiz/s/ourbiz/images/horSeparator.png
  22. BIN
      ourbiz/s/ourbiz/images/logoBackground.png
  23. BIN
      ourbiz/s/ourbiz/images/postPic1.jpg
  24. BIN
      ourbiz/s/ourbiz/images/postPic2.jpg
  25. BIN
      ourbiz/s/ourbiz/images/postPic3.jpg
  26. BIN
      ourbiz/s/ourbiz/images/siteBackground.jpg
  27. BIN
      ourbiz/s/ourbiz/images/small-arrow.png
  28. 249 0
      ourbiz/s/ourbiz/index.html
  29. 345 0
      ourbiz/s/ourbiz/jaml.js
  30. 121 0
      ourbiz/s/ourbiz/length-encoded.js
  31. 164 0
      ourbiz/s/ourbiz/listsearch.js
  32. 129 0
      ourbiz/s/ourbiz/main-menu.js
  33. 103 0
      ourbiz/s/ourbiz/measure-units.js
  34. 1 0
      ourbiz/s/ourbiz/mk-it.bat
  35. 117 0
      ourbiz/s/ourbiz/mobile.css
  36. 100 0
      ourbiz/s/ourbiz/mobile.html
  37. 9 0
      ourbiz/s/ourbiz/neat.css
  38. 165 0
      ourbiz/s/ourbiz/order-types.js
  39. 578 0
      ourbiz/s/ourbiz/orders.js
  40. 186 0
      ourbiz/s/ourbiz/otnetstrings.js
  41. 111 0
      ourbiz/s/ourbiz/payment-types.js
  42. 262 0
      ourbiz/s/ourbiz/payments.js
  43. 363 0
      ourbiz/s/ourbiz/products.js
  44. 100 0
      ourbiz/s/ourbiz/sales-tax-rates.js
  45. 75 0
      ourbiz/s/ourbiz/scroll.js
  46. 223 0
      ourbiz/s/ourbiz/shortcut.js
  47. 52 0
      ourbiz/s/ourbiz/style.css
  48. 96 0
      ourbiz/s/ourbiz/tap.js
  49. 1 0
      ourbiz/s/ourbiz/touch-all.bat
  50. 131 0
      ourbiz/s/ourbiz/touch.js
  51. 103 0
      ourbiz/s/ourbiz/warranty-types.js

Plik diff jest za duży
+ 0 - 0
ourbiz/s/codemirror-compressed.js


+ 174 - 0
ourbiz/s/codemirror.css

@@ -0,0 +1,174 @@
+.CodeMirror {
+  line-height: 1em;
+  font-family: monospace;
+
+  /* Necessary so the scrollbar can be absolutely positioned within the wrapper on Lion. */
+  position: relative;
+  /* This prevents unwanted scrollbars from showing up on the body and wrapper in IE. */
+  overflow: hidden;
+}
+
+.CodeMirror-scroll {
+  overflow: auto;
+  height: 30em;
+  /* This is needed to prevent an IE[67] bug where the scrolled content
+     is visible outside of the scrolling box. */
+  position: relative;
+  outline: none;
+}
+
+/* Vertical scrollbar */
+.CodeMirror-scrollbar {
+  position: absolute;
+  right: 0; top: 0;
+  overflow-x: hidden;
+  overflow-y: scroll;
+  z-index: 5;
+}
+.CodeMirror-scrollbar-inner {
+  /* This needs to have a nonzero width in order for the scrollbar to appear
+     in Firefox and IE9. */
+  width: 1px;
+}
+.CodeMirror-scrollbar.cm-sb-overlap {
+  /* Ensure that the scrollbar appears in Lion, and that it overlaps the content
+     rather than sitting to the right of it. */
+  position: absolute;
+  z-index: 1;
+  float: none;
+  right: 0;
+  min-width: 12px;
+}
+.CodeMirror-scrollbar.cm-sb-nonoverlap {
+  min-width: 12px;
+}
+.CodeMirror-scrollbar.cm-sb-ie7 {
+  min-width: 18px;
+}
+
+.CodeMirror-gutter {
+  position: absolute; left: 0; top: 0;
+  z-index: 10;
+  background-color: #f7f7f7;
+  border-right: 1px solid #eee;
+  min-width: 2em;
+  height: 100%;
+}
+.CodeMirror-gutter-text {
+  color: #aaa;
+  text-align: right;
+  padding: .4em .2em .4em .4em;
+  white-space: pre !important;
+  cursor: default;
+}
+.CodeMirror-lines {
+  padding: .4em;
+  white-space: pre;
+  cursor: text;
+}
+
+.CodeMirror pre {
+  -moz-border-radius: 0;
+  -webkit-border-radius: 0;
+  -o-border-radius: 0;
+  border-radius: 0;
+  border-width: 0; margin: 0; padding: 0; background: transparent;
+  font-family: inherit;
+  font-size: inherit;
+  padding: 0; margin: 0;
+  white-space: pre;
+  word-wrap: normal;
+  line-height: inherit;
+  color: inherit;
+  overflow: visible;
+}
+
+.CodeMirror-wrap pre {
+  word-wrap: break-word;
+  white-space: pre-wrap;
+  word-break: normal;
+}
+.CodeMirror-wrap .CodeMirror-scroll {
+  overflow-x: hidden;
+}
+
+.CodeMirror textarea {
+  outline: none !important;
+}
+
+.CodeMirror pre.CodeMirror-cursor {
+  z-index: 10;
+  position: absolute;
+  visibility: hidden;
+  border-left: 1px solid black;
+  border-right: none;
+  width: 0;
+}
+.cm-keymap-fat-cursor pre.CodeMirror-cursor {
+  width: auto;
+  border: 0;
+  background: transparent;
+  background: rgba(0, 200, 0, .4);
+  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr=#6600c800, endColorstr=#4c00c800);
+}
+/* Kludge to turn off filter in ie9+, which also accepts rgba */
+.cm-keymap-fat-cursor pre.CodeMirror-cursor:not(#nonsense_id) {
+  filter: progid:DXImageTransform.Microsoft.gradient(enabled=false);
+}
+.CodeMirror pre.CodeMirror-cursor.CodeMirror-overwrite {}
+.CodeMirror-focused pre.CodeMirror-cursor {
+  visibility: visible;
+}
+
+div.CodeMirror-selected { background: #d9d9d9; }
+.CodeMirror-focused div.CodeMirror-selected { background: #d7d4f0; }
+
+.CodeMirror-searching {
+  background: #ffa;
+  background: rgba(255, 255, 0, .4);
+}
+
+/* Default theme */
+
+.cm-s-default span.cm-keyword {color: #708;}
+.cm-s-default span.cm-atom {color: #219;}
+.cm-s-default span.cm-number {color: #164;}
+.cm-s-default span.cm-def {color: #00f;}
+.cm-s-default span.cm-variable {color: black;}
+.cm-s-default span.cm-variable-2 {color: #05a;}
+.cm-s-default span.cm-variable-3 {color: #085;}
+.cm-s-default span.cm-property {color: black;}
+.cm-s-default span.cm-operator {color: black;}
+.cm-s-default span.cm-comment {color: #a50;}
+.cm-s-default span.cm-string {color: #a11;}
+.cm-s-default span.cm-string-2 {color: #f50;}
+.cm-s-default span.cm-meta {color: #555;}
+.cm-s-default span.cm-error {color: #f00;}
+.cm-s-default span.cm-qualifier {color: #555;}
+.cm-s-default span.cm-builtin {color: #30a;}
+.cm-s-default span.cm-bracket {color: #997;}
+.cm-s-default span.cm-tag {color: #170;}
+.cm-s-default span.cm-attribute {color: #00c;}
+.cm-s-default span.cm-header {color: blue;}
+.cm-s-default span.cm-quote {color: #090;}
+.cm-s-default span.cm-hr {color: #999;}
+.cm-s-default span.cm-link {color: #00c;}
+
+span.cm-header, span.cm-strong {font-weight: bold;}
+span.cm-em {font-style: italic;}
+span.cm-emstrong {font-style: italic; font-weight: bold;}
+span.cm-link {text-decoration: underline;}
+
+span.cm-invalidchar {color: #f00;}
+
+div.CodeMirror span.CodeMirror-matchingbracket {color: #0f0;}
+div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #f22;}
+
+@media print {
+
+  /* Hide the cursor when printing */
+  .CodeMirror pre.CodeMirror-cursor {
+    visibility: hidden;
+  }
+
+}

+ 27 - 0
ourbiz/s/dialogs.css

@@ -0,0 +1,27 @@
+.CodeMirror-dialog {
+  position: relative;
+}
+
+.CodeMirror-dialog > div {
+  position: absolute;
+  top: 0; left: 0; right: 0;
+  background: white;
+  border-bottom: 1px solid #eee;
+  z-index: 15;
+  padding: .1em .8em;
+  overflow: hidden;
+  color: #333;
+}
+
+.CodeMirror-dialog input {
+  border: none;
+  outline: none;
+  background: transparent;
+  width: 20em;
+  color: inherit;
+  font-family: monospace;
+}
+
+.CodeMirror-dialog button {
+  font-size: 70%;
+}

+ 56 - 0
ourbiz/s/ourbiz/ajax-data-table.js

@@ -0,0 +1,56 @@
+Jaml.register('AjaxDataTable', function(args) {
+	form({id: args.form_id, style: "width:100%;height:100%;", onsubmit:"return false;"},
+		table({style: "width:100%;height:100%;"},
+			tr(
+				td({style:"height:12px; white-space:nowrap;"}, 
+					input({id: 'url_' + args.id, style: "width:90%;", value:"/DB/GetList?list=orders&search=1&sab=S"}),
+					button({id: 'btnGo' + args.id}, "Go")
+				)
+			),
+			args.data_table
+		)
+	)
+});
+
+
+function newAjaxDataTableWindow(title){
+	if(!title) title = 'Ajax Data Table';
+	var win = dad._windows[title];
+	if(!win){
+		var newId = dad.newSeqId();
+		var table_id = 'table' + newId;
+		var table_header_id = 'table_header' + newId;
+		var data = {
+			id: newId,
+			form_id: 'form_ajax' + newId,
+			'table_id': table_id,
+			'table_header_id': table_header_id
+		}
+		data.table_height = "100%";
+		data.data_table = Jaml.render('2TRDataTable', data);
+		var win = dad.newWindow(newId, 160,20, 600, 400, title, Jaml.render('AjaxDataTable', data));
+
+		var myform = $(data.form_id);
+		dad.setupEditForm(myform);
+
+		var btn = $('btnGo' + newId);
+		btn._url_input = $('url_' + newId);
+		
+		btn.ajax = dad.newAjaxDataTableAjax(win, newId);
+		btn.ajax._withHeaders = true;
+		btn.onclick = function(){
+			var go_value = btn._url_input.value;
+			var url, qs;
+			var splitPos = go_value.indexOf("?");
+			if(splitPos >= 0){
+				url = go_value.substr(0, splitPos);
+				qs = go_value.substr(splitPos+1);
+			} else {
+				url = go_value;
+				qs = '';
+			}
+			this.ajax.post(url,  qs, 'GET');
+		};
+	}
+	dad.bringToFront(win)
+}

+ 1739 - 0
ourbiz/s/ourbiz/app-base.js

@@ -0,0 +1,1739 @@
+dad = {}
+
+function $(id){return document.getElementById(id);}
+
+dad.detectEnvironment = function () {
+  var n = navigator;
+  var ua = n.userAgent;
+  var av = n.appVersion;
+  dad.isOpera = (ua.indexOf("Opera") > -1);
+  dad.isKhtml = (av.indexOf("Konqueror") > -1) ||
+    (av.indexOf("Safari") > -1);
+  dad.isSafari = (av.indexOf("Safari") > -1);
+  dad.isMoz = ((ua.indexOf('Gecko') > -1) && (!dad.isKhtml));
+  dad.isFF = false;
+  dad.isIE = false;
+  try {
+    if (dad.isMoz) {
+      dad.isFF = (ua.indexOf('Firefox') > -1);
+    }
+    if ((document.all) && (!dad.isOpera)) {
+      dad.isIE = (ua.indexOf('MSIE ') > -1);
+    }
+		if(dad.isIE){
+			dad.isIE = (function(){
+				var undef, v = 3, div = document.createElement('div'),
+					all = div.getElementsByTagName('i');
+				while (
+						div.innerHTML = '<!--[if gt IE ' + (++v) + ']><i></i><![endif]-->',
+						all[0]
+				){};
+				return v > 4 ? v : undef;
+			}());
+		}
+  }
+  // Squelch
+  catch(e) {}
+  dad.isMac = (ua.indexOf('Mac') > -1);
+  dad.isUnix = (ua.indexOf('Linux') > -1) ||
+    (ua.indexOf('BSD') > -1) || (ua.indexOf('SunOS') > -1);
+  dad.isLinux = (ua.indexOf('Linux') > -1);
+  dad.isWindows = (ua.indexOf('Windows') > -1);
+};
+
+dad.detectEnvironment();
+
+dad._seqID_ = 0;
+dad.newSeqId = function(){return this._seqID_++;}
+dad._renewLastSeqId = true;
+dad._lastSeqId = false;
+dad.newIdBy2calls = function(){
+	if(dad._renewLastSeqId)	dad._lastSeqId = 'rb' + dad.newSeqId();
+	dad._renewLastSeqId = !dad._renewLastSeqId;
+	return dad._lastSeqId;
+}
+
+dad.isArray = function(obj) { return Object.prototype.toString.call( obj ) === '[object Array]';}
+
+dad.number_format = function(num, decp){
+	if(decp == null) decp = 2;
+	var a = new Number(num);
+	var b = a.toFixed(decp); //get 12345678.90
+	a = parseInt(a); // get 12345678
+	b = decp ? (b-a).toPrecision(decp) : 0; //get 0.90
+	b = parseFloat(b).toFixed(decp); //in case we get 0.0, we pad it out to 0.00
+	a = a.toLocaleString();//put in commas - IE also puts in .00, so we'll get 12,345,678.00
+	//if IE (our number ends in .00)
+	if(a < 1 && a.lastIndexOf('.00') == (a.length - 3))
+	{
+			a=a.substr(0, a.length-3); //delete the .00
+	}
+	return a+b.substr(1);//remove the 0 from b, then return a + b = 12,345,678.90
+}
+
+dad.dumpObj = function(obj){
+	var result = '';
+	for(var key in obj){
+		result += key + '\n';
+	}
+	return result;
+}
+
+dad._scriptsIncluded = {}
+dad.include = function(jsFile){
+	if (dad._scriptsIncluded[jsFile] != null) return;
+	var scriptElt = document.createElement('script');
+	scriptElt.type = 'text/javascript';
+	scriptElt.src = jsFile;
+	document.getElementsByTagName('head')[0].appendChild(scriptElt);
+	dad._scriptsIncluded[jsFile] = true; // or whatever value your prefer
+}
+
+dad.getAsPixels = function(x){ return x + "px";}
+dad.getEventSource = function(evt) {
+	var target = evt.target ? evt.target : evt.srcElement;
+	return (target.nodeType == 3) ? target.parentNode : target;
+}
+dad.getOffsetX = function(evt) {return evt.changedTouches ? evt.changedTouches[0].offsetX : evt.offsetX || evt.layerX;}
+dad.getOffsetY = function(evt) {return evt.changedTouches ? evt.changedTouches[0].offsetY : evt.offsetY || evt.layerY;}
+dad.getClientX = function(evt) {return evt.changedTouches ? evt.changedTouches[0].pageX : evt.clientX;}
+dad.getClientY = function(evt) {return evt.changedTouches ? evt.changedTouches[0].pageY : evt.clientY;}
+
+dad.getMousePos = function (evt){
+	if (evt.targetTouches && evt.targetTouches.length){
+		var t = evt.targetTouches[0];
+		 return { x: t.pageX, y: t.pageY };
+	} else if (evt.pageX || evt.pageY)
+		 return { x: evt.pageX, y: evt.pageY };
+	else {
+		var delm = document.documentElement;
+		var bdy = document.body;
+		return { x: evt.clientX + delm.scrollLeft - bdy.clientLeft,
+							y: evt.clientY + delm.scrollTop  - bdy.clientTop };
+	}
+}
+
+if( document.documentElement && document.documentElement.scrollTop ){
+	dad.getScrolledX = function() {return document.documentElement.scrollLeft;}
+	dad.getScrolledY = function() {return document.documentElement.scrollTop;}
+} else {
+	dad.getScrolledX = function() {return document.body.scrollLeft;}
+	dad.getScrolledY = function() {return document.body.scrollTop;}
+}
+if( document.documentElement && document.documentElement.clientHeight ){
+	dad.getClientWidth = function() {return document.documentElement.clientWidth;}
+	dad.getClientHeight = function() {return document.documentElement.clientHeight;}
+} else {
+	dad.getClientWidth = function() {return document.body.clientWidth;}
+	dad.getClientHeight = function() {return document.body.clientHeight;}
+}
+dad.checkEvent = function(evt) {return evt || window.event;}
+dad.getEventKey = function(evt){
+	var key = (evt.charCode) ? evt.charCode:
+		((evt.keyCode) ? evt.keyCode: ((evt.which) ? evt.which : 0));
+	return key;
+}
+dad.trim = function (st) {return st.replace(/^\s+|\s+$/g, '');}
+dad.inArray = function (v, a){
+for (var i = 0, numA = a.length; i < numA; i++)
+	if ((v != null && a[i].constructor == Array && 
+			v.constructor == Array && a[i].toString() == v.toString()) || 
+			(a[i] == v)) return true;
+}
+
+dad.parseJSON = window.JSON ? window.JSON.parse : function(str) {return eval('(' + str + ')')}
+
+dad.arrayApply = function (ary, func) {
+	var isFunc = (typeof p == 'function');
+	for (var i = 0, numObjs = ary.length; i < numObjs; i++) 
+		isFunc ? func(ary[i]) : eval('ary[i].' + func);
+};
+
+dad.getHash = function ( url ) {return url.substring( url.lastIndexOf ( '#' ) + 1 );}
+
+//check if the first node is an element node
+dad.getFirstChild = function(n){
+	x=n.firstChild;
+	while (x.nodeType!=1) x=x.nextSibling;
+	return x;
+}
+
+dad.getFirstChildWithTagName = function( element, tagName ) {
+	var cn = element.childNodes;
+	for ( var i = 0, cnl = cn.length; i < cnl; i++ ) {
+		var elm = cn[i];
+		if ( elm.nodeName == tagName ) return elm;
+		var found = dad.getFirstChildWithTagName( elm, tagName );
+		if( found ) return found;
+	}
+}
+
+dad.getFirstChildWithClassName = function( element, className ) {
+	if(element.childNodes){
+		var cn = element.childNodes;
+		for ( var i = 0, cnl = cn.length; i < cnl; i++ ) {
+			var elm = cn[i];
+			if ( elm.className == className ) return elm;
+			var found = dad.getFirstChildWithClassName( elm, className );
+			if( found ) return found;
+		}
+	}
+}
+
+dad.getFirstChildWithAttribute = function( element, attrName, attrValue ) {
+	var cn = element.childNodes;
+	for ( var i = 0, cnl = cn.length; i < cnl; i++ ) {
+		var elm = cn[i];
+		if ( elm[attrName] && ((attrValue == null) || (elm[attrName] == attrValue))) {
+			return elm;
+		}
+		var found = dad.getFirstChildWithAttribute( elm, attrName, attrValue );
+		if( found ) return found;
+	}
+}
+
+dad.getFirstParentWithClassName = function( element, className ) {
+	var pn = element;
+	while(pn = pn.parentNode){
+		if ( pn.className == className ) return pn;
+	}
+}
+
+dad.getFirstParentWithTagName = function( element, tagName ) {
+	var pn = element;
+	while(pn = pn.parentNode){
+		if ( pn.tagName == tagName ) return pn;
+	}
+}
+
+dad.getFirstParentWithWithAttribute = function( element, attrName ) {
+	var pn = element;
+	while(pn = pn.parentNode){
+		if ( pn[attrName] ) return pn;
+	}
+}
+
+dad.getChildById = function( element, id , recurse) {
+	var cn = element.childNodes;
+	for ( var i = 0, cnl = cn.length; i < cnl; i++ ) {
+		if ( cn[i].id == id ) return cn[i];
+	}
+}
+
+dad.resizeImg = function (img, maxWidth){
+	maxWidth = maxWidth || 400;
+	if (img.width > maxWidth){
+		if (img.style.msInterpolationMode) img.style.msInterpolationMode = 'bicubic';
+		img.width = maxWidth;
+	}
+}
+
+dad.initTab = function(tabContainer) {
+  var buttons = new Array();
+  var table_rows = new Array();
+  var tabObj = {
+	'buttons': buttons,
+	'table_rows': table_rows
+  }
+  var cn = tabContainer.cells[0].childNodes;
+  for ( var i = 0, j = 0, tl = cn.length; i < tl; i++ ) {
+		var item = cn[i];
+		if ( item.nodeName == "BUTTON" ) {
+			var id = item.name;
+			buttons[id] = item;
+			item.tabObj = tabObj;
+		// Assign onclick events to the tab links, and
+			item.onclick = dad.showTab;
+		// highlight the first tab
+			if ( j == 0 ) item.className = 'selected';
+			var tabContent = $(id);
+			table_rows[id] = tabContent;
+			// Hide all content divs except the first
+			if ( j > 0 ) tabContent.className = 'tabContent hide';
+			j++;
+		}
+  }
+}
+
+dad.showTab = function() {
+  var selectedId = this.name;
+  // Highlight the selected tab, and dim all others.
+  // Also show the selected content div, and hide all others.
+  var table_rows = this.tabObj.table_rows;
+  var buttons = this.tabObj.buttons;
+  for ( var id in table_rows ) {
+		if ( id == selectedId ) {
+			buttons[id].className = 'selected';
+			table_rows[id].className = 'tabContent';
+		} else {
+			buttons[id].className = '';
+			table_rows[id].className = 'tabContent hide';
+		}
+  }
+  // Stop the browser following the link
+  return false;
+}
+
+dad.addEvent = window.addEventListener ? 
+	function(obj,evt,fn) {obj.addEventListener(evt,fn,false);} :
+	function(obj,evt,fn) {obj.attachEvent('on'+evt,fn)};
+
+dad.removeEvent = window.removeEventListener ?
+	function(obj,evt,fn) {obj.removeEventListener(evt,fn,false);} :
+	function(obj,evt,fn) {obj.detachEvent('on'+evt,fn)};
+	
+dad.cancelEvent = window.addEventListener ? 
+	function (e, c) {e.preventDefault(); if (c) e.stopPropagation();}:
+	function (e, c) {e.preventDefault ? e.preventDefault() : e.returnValue = false; if (c) e.cancelBubble = true;};
+
+dad.addEventMulti = function(obj, evts, fn){
+	var ary = evts.split(' ');
+	for(var i in ary) dad.addEvent(obj, ary[i], fn);
+}
+
+dad.removeEventMulti = function(obj, evts, fn){
+	var ary = evts.split(' ');
+	for(var i in ary) dad.removeEvent(obj, ary[i], fn);
+}
+
+dad.dragDrop = {
+	keySpeed: 10, // pixels per keypress event
+	initialMouseX: undefined,
+	initialMouseY: undefined,
+	startX: undefined,
+	startY: undefined,
+	dXKeys: undefined,
+	dYKeys: undefined,
+	startTime: undefined,
+	draggedObject: undefined,
+	initElement: function (element, dragThisObj, keyboardLink) {
+		var dd = dad.dragDrop;
+		if (typeof element == 'string') element = $(element);
+		element.onmousedown = dd.startDragMouse;
+		element.ontouchstart = dd.startDragMouse;
+		element._dragThisObj = dragThisObj;
+		if(keyboardLink) {
+			if (typeof keyboardLink == 'string')
+				keyboardLink = $(keyboardLink);
+			keyboardLink.relatedElement = element;
+			keyboardLink.onclick = dd.startDragKeys;
+		}
+	},
+	startDragMouse: function (e) {
+		var dd = dad.dragDrop;
+		dd.startDrag(this);
+		var evt = dad.checkEvent(e);
+		var pos = dad.getMousePos(evt);
+		dd.initialMouseX = pos.x; //dad.getClientX(evt);
+		dd.initialMouseY = pos.y; //dad.getClientY(evt);
+		dad.addEventMulti(document,'mousemove touchmove',dd.dragMouse);
+		dad.addEventMulti(document,'mouseup touchend',dd.releaseElement);
+		return false;
+	},
+	startDragKeys: function () {
+		var dd = dad.dragDrop;
+		dd.startDrag(this.relatedElement);
+		dd.dXKeys = dd.dYKeys = 0;
+		dad.addEvent(document,'keydown',dd.dragKeys);
+		dad.addEvent(document,'keypress',dd.switchKeyEvents);
+		this.blur();
+		return false;
+	},
+	startDrag: function (obj) {
+		var dd = dad.dragDrop;
+		if (dd.draggedObject) dd.releaseElement();
+		var dragThisObj = obj._dragThisObj ? obj._dragThisObj : obj;
+		dad.bringToFront(dragThisObj);
+		dd.startTime = new Date().getTime();
+		dd.startX = dragThisObj.offsetLeft;
+		dd.startY = dragThisObj.offsetTop;
+		dd.draggedObject = dragThisObj;
+		obj.className += ' dragged';
+		if(dragThisObj.onStartDragging)  dragThisObj.onStartDragging();
+	},
+	dragMouse: function (e) {
+		var dd = dad.dragDrop;
+		var evt = dad.checkEvent(e);
+		var pos = dad.getMousePos(evt);
+		var dX = pos.x - dd.initialMouseX; //dad.getClientX(evt) - dd.initialMouseX;
+		var dY = pos.y - dd.initialMouseY; //dad.getClientY(evt) - dd.initialMouseY;
+		dd.setPosition(dX,dY);
+		return false;
+	},
+	dragKeys: function(e) {
+		var dd = dad.dragDrop;
+		var evt = dad.checkEvent(e);
+		var key = evt.keyCode;
+		switch (key) {
+			case 37:	// left
+			case 63234:
+				dd.dXKeys -= dd.keySpeed;
+				break;
+			case 38:	// up
+			case 63232:
+				dd.dYKeys -= dd.keySpeed;
+				break;
+			case 39:	// right
+			case 63235:
+				dd.dXKeys += dd.keySpeed;
+				break;
+			case 40:	// down
+			case 63233:
+				dd.dYKeys += dd.keySpeed;
+				break;
+			case 13: 	// enter
+			case 27: 	// escape
+				dd.releaseElement();
+				return false;
+			default:
+				return true;
+		}
+		dd.setPosition(dd.dXKeys,dd.dYKeys);
+		if (evt.preventDefault)
+			evt.preventDefault();
+		return false;
+	},
+	setPosition: function (dx,dy) {
+		var dd = dad.dragDrop;
+		var style = dd.draggedObject.style;
+		var xpos = dd.startX + dx;
+		if(xpos < 0) xpos = 0;
+		var ypos = dd.startY + dy;
+		if(ypos < 0) ypos = 0;
+		style.left = dad.getAsPixels(xpos);
+		style.top = dad.getAsPixels(ypos);
+		dd.updatePending = false;
+	},
+	switchKeyEvents: function () {
+		// for Opera and Safari 1.3
+		var dd = dad.dragDrop;
+		dad.removeEventMulti(document,'keydown keypress',dd.dragKeys);
+		dad.removeEvent(document,'keypress',dd.switchKeyEvents);
+	},
+	releaseElement: function() {
+		var dd = dad.dragDrop;
+		var removeEvent = dad.removeEvent;
+		var removeEventMulti = dad.removeEventMulti;
+		removeEventMulti(document,'mousemove touchmove',dd.dragMouse);
+		removeEventMulti(document,'mouseup touchend',dd.releaseElement);
+		removeEventMulti(document,'keypress keydown',dd.dragKeys);
+		removeEvent(document,'keypress',dd.switchKeyEvents);
+		var dobj = dd.draggedObject;
+		dobj.className = dobj.className.replace(/dragged/,'');
+		if(dobj.onStopDragging)  dobj.onStopDragging();
+		dd.draggedObject = null;
+	}
+}
+
+dad.newAjaxRequest = function(){
+ var activexmodes=["Msxml2.XMLHTTP", "Microsoft.XMLHTTP"] //activeX versions to check for in IE
+ if (window.ActiveXObject){ //Test for support for ActiveXObject in IE first (as XMLHttpRequest in IE7 is broken)
+  for (var i=0; i<activexmodes.length; i++){
+   try{
+    return new ActiveXObject(activexmodes[i])
+   }
+   catch(e){
+    //suppress error
+   }
+  }
+ }
+ else if (window.XMLHttpRequest) // if Mozilla, Safari etc
+  return new XMLHttpRequest()
+ else
+  return false
+}
+
+dad.Ajax = function(callback, params, cache)
+{
+   var thisObj   = this;
+   this.cache    = {};
+   this.callback = callback;
+   this.request = dad.newAjaxRequest();
+
+   this.runCallback = function (event, cached)
+   {
+      if (!cached)
+         {
+            if (thisObj.request.readyState != 4)
+               return;
+            thisObj.responseText            = thisObj.request.responseText;
+            thisObj.responseXML             = thisObj.request.responseXML;
+            thisObj.status                  = thisObj.request.status;
+            thisObj.cache[thisObj.cacheKey] = thisObj.responseText;
+         }
+
+      if(thisObj.callback) thisObj.callback(params);
+   }
+
+
+   this.post = function (where, what, verb, headers)
+   {
+      var cachedValue;
+      this.cacheKey = where + '?' + what;
+      if (cache && ((cachedValue = this.cache[this.cacheKey]) != null))
+         {
+            this.responseText = cachedValue;
+            this.runCallback('', true);
+            return;
+         }
+
+	  /*IE needs a fresh new ajax obj each time*/
+	  if(dad.isIE) this.request = dad.newAjaxRequest(); 
+      this.request.onreadystatechange = this.runCallback;
+
+      verb = verb ? dad.trim(((verb == true) ? 'GET' : verb).toUpperCase()) : 'POST';
+      this.request.open(verb, dad.inArray(verb, ['POST', 'PUT']) ? where : where + (what ? '?' + what : ''), true);
+
+      if (dad.inArray(verb, ['POST', 'PUT']))
+         {
+            this.request.setRequestHeader('Content-Type',   'application/x-www-form-urlencoded; charset=utf-8');
+            this.request.setRequestHeader('Content-length', what.length);
+            this.request.setRequestHeader('Connection',     'close');
+         }
+      if (headers)
+         for (var i = 0, len = headers.length; i < len; i++)
+            this.request.setRequestHeader(headers[i][0], headers[i][1]);
+
+      this.request.send(dad.inArray(verb, ['POST', 'PUT']) ? what : null);
+   }
+   return this;
+}
+
+dad._topmost_zindex = false;
+
+dad.find_topmost_zindex = function() {
+  var current_top = 0;
+  var page_elements = null;
+  
+  if(document.getElementsByTagName) {
+    page_elements = document.body.getElementsByTagName('div');
+  } else if(document.all) {
+    page_elements = document.all;
+  } else { return false; }
+ 
+  for(var i=0;i<page_elements.length;i++) {
+	var elm = page_elements[i];
+    if(elm.style.zIndex){
+	  var zIndex = parseInt(elm.style.zIndex);
+      if(zIndex>current_top) {
+		current_top = zIndex;
+	  }
+	}
+  }
+  return current_top;
+} 
+
+dad.bringToFront = function(el){
+	if (typeof el == 'string')
+			el = $(el);
+	if(el != dad._topmost_zindex){
+		el.style.zIndex = dad.find_topmost_zindex()+1;
+		dad._topmost_zindex = el;
+	}
+	if(el.style.display == 'none') el.style.display = "block";
+}
+
+dad.bringToFrontParent = function(event){
+	var evt = dad.checkEvent(event);
+	var el = dad.getEventSource(evt);
+	dad.bringToFront(el.parentNode);
+}
+
+dad.getStyle = function(el,styleProp){
+	if (el.currentStyle)
+		var y = el.currentStyle[styleProp];
+	else if (window.getComputedStyle)
+		var y = document.defaultView.getComputedStyle(el,null).getPropertyValue(styleProp);
+	return y;
+}
+
+dad._winOnAfterResize = function(){
+	var child = this.firstChild;
+	if(child){
+		var style = this.style;
+		var border = 2; //parseInt(style.borderWidth);
+		var newLeft = parseInt(style.left)+border;
+		var newTop = parseInt(style.top)+border;
+		var newWidth = parseInt(style.width)-border;
+		var newHeight = parseInt(style.height)-border;
+		style = child.style;
+		var AsPixels = dad.getAsPixels;
+		style.left = AsPixels(newLeft);
+		style.top = AsPixels(newTop);
+		style.width = AsPixels(newWidth);
+		style.height = AsPixels(newHeight);
+	}
+}
+
+dad._windows = {}
+
+dad.closeTopParent = function (child){
+	var topParent = dad.getWindowForChild(child);
+	if(topParent) {
+		for(win in dad._windows){
+			if(topParent == dad._windows[win]) {
+				if(topParent.className.indexOf("mainWindow") == -1){
+					dad._windows[win] = null;
+					document.body.removeChild(topParent);
+				}
+				break;
+			}
+		}
+	}
+	return false;
+}
+
+dad.hideWindow = function (win){
+	if(win && (win.className.indexOf("mainWindow") == -1)){
+		win.style.display="none";
+	}
+	return false;
+}
+
+dad.hideTopParent = function (child){
+	var topParent = dad.getWindowForChild(child);
+	dad.hideWindow(topParent);
+	return false;
+}
+
+dad.centerOnScreen = function(win){
+	// Xwidth is the width of the div, Yheight is the height of the
+	// div passed as arguments to the function:
+	var leftOffset = dad.getScrolledX() + (dad.getClientWidth() - win.offsetWidth) / 2;
+	var topOffset = dad.getScrolledY() + (dad.getClientHeight() - win.offsetHeight) / 2;
+	// The initial width and height of the div can be set in the
+	// style sheet with display:none; divid is passed as an argument to // the function
+	var style = win.style;
+	if(topOffset < 0) topOffset = 0;
+	if(leftOffset < 0) leftOffset = 0;
+	style.top = topOffset + 'px';
+	style.left = leftOffset + 'px';
+}
+
+Jaml.register('Window', function(args) {
+		var AsPixels = dad.getAsPixels;
+		var swidth = "";
+		if(args.x > 0) swidth += "left:" + AsPixels(args.x) + ";";
+		if(args.y > 0) swidth += "top:" + AsPixels(args.y) + ";";
+		if(args.w > 0) swidth += "width:" + AsPixels(args.w) + ";";
+		if(args.h > 0) swidth += "height:" + AsPixels(args.h) + ";";
+		
+		var winOptClass = args.noWinOpt ? "noWinOpt" : "winOpt";
+		
+		div({
+				style: swidth,
+				"class":"resizeable",
+				onAfterResize: "dad._winOnAfterResize"
+			},
+			table({
+					style:"width:100%;height:100%;cursor:default;",
+					"class": "window"
+				},
+				tr({"class":"winTitle"},
+					td({"class": "winHeader"}, args.title),
+					td({cls: winOptClass}, a({href:"#",  onclick: "return dad.hideTopParent(this)"}, "_")),
+					td({cls: winOptClass}, a({href:"#"}, "^")),
+					td({cls: winOptClass}, a({href:"#",  onclick: "return dad.closeTopParent(this)"}, "X"))
+				),
+				tr({"class":"winContent"},
+					td({colspan:4},
+						div({id:"divContent" + args.id, style:"width:100%;height:100%;"},
+							args.content
+						)
+					)
+				)
+			)
+		)
+	});
+	
+dad.setOpacity = function setOpacity(obj, value) {
+	obj.style.opacity = value/10;
+	obj.style.filter = 'alpha(opacity=' + value*10 + ')';
+}
+
+dad.newWindow = function(id,x,y,w,h,title, content, noWinOpt, noCenter){
+	var args = {id:id, x: x, y: y, w: w, h: h, title: title, content: content, noWinOpt: noWinOpt};
+	var swin = Jaml.render("Window", args);
+	var elm = document.createElement('div');
+	elm.innerHTML = swin;
+	document.body.appendChild(elm);
+	var win = elm.firstChild;
+	elm.parentNode.replaceChild(win, elm);
+	win = document.body.lastChild;
+	win.style.position = "absolute";
+
+	win.ud = {};
+	win.ud.content = dad.getFirstChildWithClassName(win, "winContent");
+	win.ud.header = dad.getFirstChildWithClassName(win, "winHeader");
+	//set draggable
+	dad.dragDrop.initElement(win.ud.header, win);
+	win.onStartDragging = function(){
+		dad.setOpacity(win, 7);
+		win.ud.content.style.visibility="hidden"
+	}
+	win.onStopDragging = function(){
+		dad.setOpacity(win, 10);
+		win.ud.content.style.visibility="visible"
+	}
+	dad._windows[title] = win;
+	if(!noCenter) dad.centerOnScreen(win);
+	return win;
+}
+
+dad.setContentOverflow = function(id, value){
+	var divContent = $("divContent" + id);
+	divContent.style.overflow = value || "auto";
+}
+
+dad.isFocusableTag = function(tag, extra_tags){
+	var focusabeTags = ['INPUT', 'SELECT', "BUTTON", "SELECT"];
+	for(var i in focusabeTags){
+		if(tag == focusabeTags[i]) return true;
+	}
+	if(extra_tags){
+		for(var i in extra_tags){
+			if(tag == extra_tags[i]) return true;
+		}
+	}
+	return false;
+}
+
+dad.formGetNextFormFocusableElement = function(elm, backward){
+	var result = null;
+	var startChecking = false;
+	var form = elm.form;
+	if(backward){
+		for(var x=form.length-1; x >= 0; x--){
+			var curr_elm = form[x];
+			if(startChecking){
+				if(dad.isFocusableTag(curr_elm.tagName)){
+					result = curr_elm;
+					break;
+				}
+			} else if(curr_elm == elm) startChecking = true;
+		}
+	} else {
+		for(var x=0, len=form.length; x < len; x++){
+			var curr_elm = form[x];
+			if(startChecking){
+				if(dad.isFocusableTag(curr_elm.tagName)){
+					result = curr_elm;
+					break;
+				}
+			} else if(curr_elm == elm) startChecking = true;
+		}
+	}
+	return result;
+}
+
+dad.formFocusNext = function(elm, backward){
+	var nextElm = dad.formGetNextFormFocusableElement(elm, backward);
+	if(nextElm) nextElm.focus();
+	return nextElm;
+}
+
+dad.formFocusNextFromEvent = function(evt, backward){
+	var nextElm = dad.formGetNextFormFocusableElement(dad.getEventSource(evt), backward);
+	if(nextElm) nextElm.focus();
+	return nextElm;
+}
+
+dad.formInputTextOnKeydown = function(event){
+	var evt = dad.checkEvent(event);
+	//alert(dad.getEventSource(evt).name);
+	if (evt.altKey || evt.ctrlKey || evt.shiftKey) return true;
+	switch(dad.getEventKey(evt)){
+		case 40: //arrow down
+			//if(!o.editable || (o.editable && !ed.activeCellEditor && !ed.activeRow)) navigate('down');
+			dad.formFocusNextFromEvent(evt);
+			return false;
+		break;
+		case 38: //arrow up
+			//if(!o.editable || (o.editable && !ed.activeCellEditor && !ed.activeRow)) navigate('up');
+			dad.formFocusNextFromEvent(evt, true);
+			return false;
+		break;
+		case 37: //arrow left
+			//if(!o.editable || (o.editable && !ed.activeCellEditor && !ed.activeRow)) navigate('left');
+		break;
+		case 39: //arrow right
+			//if(!o.editable || (o.editable && !ed.activeCellEditor) && !ed.activeRow) navigate('right');
+		break;
+		case 34: //pagedown
+			//navigate('pgdown');
+		break;
+		case 33: //pageup
+			//navigate('pgup');
+		break;
+		case 36: //home
+			//navigate('home');
+		break;
+		case 35: //end
+			//navigate('end');
+		break;
+		case 9: //tab
+			//if(e.shiftKey) navigate('left');
+			//else navigate('right');
+		break;
+		case 13: //enter
+			//if(!o.onValidateRow && !o.onValidateCell) navigate('down');
+			if(dad.formFocusNextFromEvent(evt)) dad.cancelEvent(evt, true);
+		break;
+		case 113: //F2
+		case 32: //space bar
+			//if(o.editable && (!ed.activeCellEditor)){ ed.Edit(e); o.Event.Cancel(e); }
+		break;
+		case 27: //escape
+		break;
+	}
+}	
+
+dad.getTableForTableChild = function(child){
+	return dad.getFirstParentWithTagName(child, 'TABLE');
+}
+
+dad.createTable = function(header){
+	var table = document.createElement('table');
+	var th = table.createTHead();
+	var tr = th.insertRow(-1);
+	tr.className = "theader";
+	var len = header.length;
+	for(var i=0; i < len; i++){
+		tr.insertCell(-1).innerHTML = header[i];
+	}
+	return table;
+}
+
+dad.tableAddRow = function(table, row){
+	var tr = table.insertRow(-1);
+	var len = row.length;
+	for(var i=0; i < len; i++){
+		tr.insertCell(-1).innerHTML = row[i];
+	}
+}
+
+dad.tableAddRows = function(table, rows, cellClass){
+	var rlen = rows.length;
+	for(var x=0; x < rlen; x++){
+		dad.tableAddRow(table, rows[x]);
+	}
+	if(rows.length > 1) {
+		for(var i=rows.length-1; i > 0; i--){
+			//table.deleteRow(i);
+			rows[i].display = 'none';
+		}
+	}
+}
+
+dad.onTableClick = function(table){
+	alert(table.rowIndex);
+}
+
+dad.onTableRowClick = function(){
+	alert(this.rowIndex);
+	return false;
+}
+
+dad.appLogShow = false;
+
+dad.showDebug = function(str){ if(this.appLogShow) this.appLogShow.innerHTML = str; }
+
+dad.RESIZE_DIR = {
+	north: 0x01,
+	south: 0x02,
+	east: 0x04,
+	west: 0x08
+}
+var rd = dad.RESIZE_DIR;
+dad.CursorResizeDirection = new Array(rd.west+1);
+var crd = dad.CursorResizeDirection;
+crd[rd.north] = "n-resize";
+crd[rd.south] = "s-resize";
+crd[rd.east] = "e-resize";
+crd[rd.west] = "w-resize";
+crd[rd.north | rd.east] = "ne-resize";
+crd[rd.south | rd.east] = "se-resize";
+crd[rd.north | rd.west] = "nw-resize";
+crd[rd.south | rd.west] = "sw-resize";
+
+//Find out what kind of resize! Return a string inlcluding the directions
+dad.getResizeDirection = function(el, evt) {
+	var xPos, yPos, offset, dir;
+	dir = 0;
+
+	xPos = dad.getOffsetX(evt);
+	yPos = dad.getOffsetY(evt);
+
+	offset = 8; //The distance from the edge in pixels
+
+	if (yPos<offset) dir |= dad.RESIZE_DIR.north;
+	else if (yPos > el.offsetHeight-offset) dir |= dad.RESIZE_DIR.south;
+	if (xPos<offset) dir |= dad.RESIZE_DIR.west;
+	else if (xPos > el.offsetWidth-offset) dir |= dad.RESIZE_DIR.east;
+
+	return dir;
+}
+
+dad._resizingObject = null;
+dad.getIsCalssResizeable = function(el){
+	return el.className.indexOf("resizeable") != -1;
+}
+
+dad.getWindowForChild = function(child){
+	return topParent = dad.getFirstParentWithClassName(child, "resizeable");
+}
+
+dad.checkIsTop = function(el){
+	var topParent = dad.getWindowForChild(el);
+	var result = topParent == dad._topmost_zindex;
+	if(topParent) dad.bringToFront(topParent);
+	return result;
+}
+
+dad._nonChar = false;
+dad.handleNonChar = function(vchar){}
+dad.handleChar = function(vchar){}
+	 
+dad.handleKeyboard = function(e) {
+    var vchar;
+    var evt = (e) ? e : window.event;       //IE reports window.event not arg
+    if (evt.type == "keydown") {
+        vchar = evt.keycode;
+        if (vchar < 16 ||                    // non printables
+            (vchar > 16 && vchar < 32) ||     // avoid shift
+            (vchar > 32 && vchar < 41) ||     // navigation keys
+            vchar == 46) {                   // Delete Key (Add to these if you need)
+            dad.handleNonChar(vchar);            // function to handle non Characters
+            dad.nonChar = true;
+        } else
+            dad.nonChar = false;
+    } else {                                // This is keypress
+        if (dad.nonChar) return;                // Already Handled on keydown
+        vchar = (evt.charCode) ?
+                   evt.charCode : evt.keyCode;
+        if (vchar > 31 && vchar < 256)        // safari and opera
+            dad.handleChar(vchar);               //
+    }
+    if (e)                                  // Non IE
+        Event.stop(evt);                    // Using prototype
+    else if (evt.keyCode == 8)              // Catch IE backspace
+        evt.returnValue = false;            // and stop it!
+}
+
+dad.appOnKeyDown = function(event) {
+	if(event.keyCode==27) {
+		//ESC key hide windows
+		if(dad._topmost_zindex) {
+			var win = dad._topmost_zindex;
+			dad.hideWindow(win);
+			if(win.ud.caller) {
+				dad._topmost_zindex = win.ud.caller;
+				win.ud.caller = null;
+			}
+		}
+		return false;
+	}
+}
+
+dad.appOnMouseDown = function(event) {
+	var evt = dad.checkEvent(event);
+	var el = dad.getEventSource(evt);
+	
+	if (el == null) {
+		dad._resizingObject = null;
+		return;
+	}		
+	if(dad.getIsCalssResizeable(el)){
+		var dir = dad.getResizeDirection(el, evt);
+		if (dir == "") return;
+		dad._resizingObject = {};
+		var _resizingObject = dad._resizingObject;
+		
+		_resizingObject.el = el;
+		_resizingObject.dir = dir;
+
+		_resizingObject.grabx = dad.getClientX(evt);
+		_resizingObject.graby = dad.getClientY(evt);
+		_resizingObject.width = el.offsetWidth;
+		_resizingObject.height = el.offsetHeight;
+		_resizingObject.left = el.offsetLeft;
+		_resizingObject.top = el.offsetTop;
+
+		dad.cancelEvent(evt, true);
+	} else 	{
+		if(!dad.checkIsTop(el)) dad.cancelEvent(evt, true);
+	}
+}
+
+dad.appOnMouseUp = function() {
+	if (dad._resizingObject != null) {
+		var el = dad._resizingObject.el;
+		if(el.onAfterResize) el.onAfterResize();
+		dad._resizingObject = null;
+	}
+}
+
+dad.appOnMouseMove = function(event){
+	var evt = dad.checkEvent(event);
+	var el = dad.getEventSource(evt);
+	//Dragging starts here
+
+	if(dad._resizingObject != null) {
+		var xMin = 8; //The smallest width possible
+		var yMin = 8; //             height
+		var obj = dad._resizingObject;
+		el = obj.el;
+		var dir = obj.dir;
+		var rd = dad.RESIZE_DIR;
+		var mousePos = dad.getMousePos(evt);
+
+		if (dir & rd.east)
+			el.style.width = Math.max(xMin, obj.width + mousePos.x - obj.grabx) + "px";
+	
+		if (dir & rd.south)
+			el.style.height = Math.max(yMin, obj.height + mousePos.y - obj.graby) + "px";
+
+		if (dir & rd.west) {
+			var leftPos = Math.min(obj.left + mousePos.x - obj.grabx, obj.left + obj.width - xMin);
+			if(leftPos < 0) leftPos = 0;
+			el.style.left = leftPos + "px";
+			el.style.width = Math.max(xMin, obj.width - mousePos.x + obj.grabx) + "px";
+		}
+		if (dir & rd.north) {
+			var topPos = Math.min(obj.top + mousePos.y - obj.graby, obj.top + obj.height - yMin);
+			if(topPos < 0) topPos = 0;
+			el.style.top = topPos + "px";
+			el.style.height = Math.max(yMin, obj.height - mousePos.y + obj.graby) + "px";
+		}
+		dad.cancelEvent(evt, true);
+	} else {
+		if(el && dad.getIsCalssResizeable(el)){
+			var dir = dad.CursorResizeDirection[dad.getResizeDirection(el, evt)];
+			if(dir) el.style.cursor = dir;
+		}
+	}
+}
+
+var _transalations_ = {}
+
+function _tr(str){
+	var val = _transalations_[str];
+	return val ? val : str;
+}
+
+Jaml.register('ActionSelect', function(actionOnChange) {
+	select({name: "formAction", onchange: "dad.actionSelectOnActionChange(this)"},
+		option({value: "insert"}, _tr("Insert")),
+		option({value: "update"}, _tr("Update")),
+		option({value: "refresh"}, _tr("Refresh")),
+		option({value: "delete"}, _tr("Delete"))
+	);
+});
+
+dad.actionSelectOnActionChange = function (select) {
+	var fields = select.form.elements;
+	fields.btnAction.value = select.options[select.selectedIndex].text;
+}
+
+dad.fillFormField = function(fld, fld_value){
+		if(fld.type){
+			if(fld.type == 'checkbox')
+				fld.checked = fld_value == 1;
+			else if(fld.type == 'text')
+				fld.value = fld_value || '';
+			else if(fld.type == 'textarea')
+				fld.innerHTML = fld_value || '';
+			else if(fld.type == 'select-one'){
+				for(var i=0; i < fld.options.length; ++i){
+					var opt = fld.options[i];
+					opt.selected = opt.value == fld_value;
+				}
+			}
+		}
+}
+
+dad.fillFormWithExistingFields = function(form, record){
+	var prefix = form.my_field_prefix;
+	for(var name in record){
+		var fld = form[prefix + name];
+		if(fld) dad.fillFormField(fld, record[name]);
+	}
+}
+
+dad.getImageForImg = function(img, img_id, thumbnail){
+	if(img_id && img_id !== ""){
+		img.src="/DB/GetBin?image=" + img_id;
+		if(thumbnail) img.src += "&thumbnail=1";
+		img.style.visibility="visible";
+	} else img.style.visibility="hidden";
+}
+
+dad.formFillByRecord = function(form, record, prefix){
+	var prefix_len = prefix ? prefix.length : 0;
+	var fields = form.elements;
+	for (i=0; i < fields.length; i++){
+		var fld = fields[i];
+		if(!fld.name) continue;
+		if(prefix_len && fld.name.indexOf(prefix) != 0) continue;
+		var fld_name = prefix_len ? fld.name.substring(prefix_len) : fld.name;
+		var fld_value = record[fld_name];
+		if(form.onFillForm && form.onFillForm(fld, fld_value)) continue;
+		dad.fillFormField(fld, fld_value);
+	}
+}
+
+dad.formAjaxLoadResponse = function(id){
+	if(this.status == 200){
+		var form = $('form' + id);
+		var result_array;
+		if(form.processResponse){
+			result_array = form.processResponse(this.responseText);
+		}
+		else  result_array = dad.parseSLEData(this.responseText, true);
+		
+		var record = {};
+		if(result_array.length > 1){
+			var names = result_array[0];
+			var values = result_array[1];
+			for(var i in names){
+				record[names[i]] = values[i]; 
+			}
+		}
+		form._dbrecord = record;
+		var fields = form.elements;
+		dad.formFillByRecord(form, record, form.my_field_prefix);
+		if(form.afterFill) form.afterFill();
+		var formAction = fields.formAction;
+		if(formAction && (formAction.value != 'update')){
+			formAction.value = 'update';
+			formAction.onchange();
+		}
+	} else {
+		alert("An error has occured making the request");
+	}
+}
+
+dad.stringBytesLength = function (str) {
+  str = str.toString();
+	var i = str.length, len = 0, ch;
+	while (i--) {
+			ch = str.charCodeAt(i);
+			if (ch <= 0x007F) len += 1;
+			else if (ch <= 0x07FF) len += 2;
+			else if (ch <= 0xFFFF) len += 3;
+			else if (ch <= 0x10FFFF) len += 4;
+			else throw new Error("Bad Charcode: " + ch);
+	}
+	return len;
+}
+
+dad.encodeSizeString = function(str){
+	return dad.stringBytesLength(str) + ':' + str;
+}
+
+dad.getFormDataWithPrefix = function(form, prefix) {
+	var prefix_len = prefix ? prefix.length : 0;
+	var fields = form.elements;
+	var values = [];
+	var original = form._dbrecord;
+	for(var i=0; i < form.length; i++){
+		var fld = fields[i];
+		if(!fld.name) continue;
+		var fld_value;
+		if(fld.type == "text") {
+			fld_value = fld.value;
+		}
+		else if(fld.type == "checkbox") {
+			if(fld.checked) fld_value = 1;
+			else fld_value = 0;
+		}
+		else if(fld.type == "radio"){
+			if(!fld.checked) continue;
+		}
+		else if(fld.options && (fld.selectedIndex >= 0)) {
+			fld_value = fld.options[fld.selectedIndex].value;
+		}
+		else fld_value = fld.value;
+		if(prefix_len && fld.name.indexOf(prefix) != 0) continue;
+		var fld_name = prefix_len ? fld.name.substring(prefix_len) : fld.name;
+		if(original){
+			if(original[fld_name] == fld_value) continue;
+			if(fld_value == "" && original[fld_name] == null) continue;
+		}
+		values.push(encodeURIComponent(fld_name) + '=' + encodeURIComponent(fld_value));
+	}
+	return values;
+}
+
+dad.getFormData = function(form) {
+	return dad.getFormDataWithPrefix(form, form.my_field_prefix);
+}
+
+dad.formOnSubmit = function(EditWindowRefresh, form, table) {
+	var fields = form.elements;
+	var action = fields.formAction.value;
+	if(action == 'refresh'){
+		EditWindowRefresh(this.ajax);
+		return false;
+	}
+	var values = dad.getFormDataWithPrefix(form, form.my_field_prefix);
+	if(values.length == 0 && action != "delete") return;
+	var original = form._dbrecord;
+	values.push(encodeURIComponent("__table__") + '=' + encodeURIComponent(table));
+	if(action != "insert"){
+		values.push(encodeURIComponent("__id__") + '=' + encodeURIComponent(original["id"]));
+		values.push(encodeURIComponent("__version__") + '=' + encodeURIComponent(original["_version_"]));
+	}
+	values.push(encodeURIComponent("__action__") + '=' + encodeURIComponent(action));
+	var ajax = form.ajaxSubmit ? form.ajaxSubmit : new dad.Ajax(null, null, false);
+	ajax.post(form.action, values.join('&'), 'POST', null);
+	//form.submit();
+	return false;
+}
+
+dad.listEditWindowOnSubmitRespose = function (id) {
+	if(this.status == 200){
+		//retrieve result as an JavaScript object
+		var myform = $('form' +id);
+		var record = dad.parseSLEData2Object(this.responseText);
+		if(record.changes == 1){
+			myform._dbrecord._version_++;
+		}
+		var mywin = dad.getWindowForChild(myform);
+		if(mywin.ud.WindowRefresh)
+			mywin.ud.WindowRefresh(mywin.ud.ajaxTable);
+	} else {
+		alert("An error has occured making the request");
+	}
+}
+
+dad.setupEditForm = function(myform){
+	for(var x=0, len=myform.length; x < len; x++){
+		var elm = myform[x];
+		if(dad.isFocusableTag(elm.tagName)) elm.onkeydown = dad.formInputTextOnKeydown;
+	}
+}
+
+dad.setupKeyboardNavigation = function(node, extra_tags){
+	var cn = node.childNodes;
+	for ( var i = 0, cnl = cn.length; i < cnl; i++ ) {
+		var elm = cn[i];
+		if(dad.isFocusableTag(elm.tagName, extra_tags))
+			elm.onkeydown = dad.formInputTextOnKeydown;
+		dad.setupKeyboardNavigation( elm , extra_tags);
+	}
+}
+
+dad.onLoadInit = function(){	
+	dad.appLogShow = $("logShow");
+	dad.addEventMulti(document, 'mousedown', dad.appOnMouseDown);
+	dad.addEventMulti(document, 'mousemove', dad.appOnMouseMove);
+	dad.addEventMulti(document, 'mouseup', dad.appOnMouseUp);
+	dad.addEvent(document, "keydown", dad.appOnKeyDown);
+}
+
+dad.loadScript = function(scriptName) {
+	if(!self.myScripts) self.myScripts = [];
+	if (self.myScripts[scriptName]) { // Already exists
+		return;
+	}
+	var head = document.getElementsByTagName("head")[0];
+	script = document.createElement('script');
+	script.type = 'text/javascript';
+	script.src = scriptName;
+	head.appendChild(script);
+	self.myScripts[scriptName] = true;
+}
+
+dad._getTableAndHeaderKey = function(id){
+	var keys = {};
+	if(id.id) {
+		keys.table_key = id.table;
+		keys.table_header_key = id.table_header;
+	} else {
+		keys.table_key = 'table' + id;
+		keys.table_header_key = 'table_header' + id;
+	}
+	return keys;
+}
+
+dad.AjaxDataTableResizeHeader = function(id) {
+	var keys = dad._getTableAndHeaderKey(id);
+	var table_src = $(keys.table_key);
+	var table_dest = $(keys.table_header_key);
+	var th0 = table_dest.tHead.rows[0].cells;
+	var th1_rows = table_src.tFoot.rows[0];
+	var th1 = th1_rows.cells;
+
+	var col_count = th0.length-1;
+	for(var i=col_count; i >= 0 && (th0[i].className == "display_none"); --i, --col_count){};
+	for(var i=0; i < col_count; ++i){
+		if(th0[i].className == "display_none") continue;
+		th0[i].style.width = (th1[i].offsetWidth -3) +'px';
+	}
+}
+
+dad.tableInputOnKeydown = function(event){
+	var evt = dad.checkEvent(event);
+	if (evt.altKey || evt.ctrlKey || evt.shiftKey) return true;
+	var key = dad.getEventKey(evt);
+	switch(key){
+		case 40: //arrow down
+			dad.formFocusNextFromEvent(evt);
+			return false;
+		break;
+		case 38: //arrow up
+			dad.formFocusNextFromEvent(evt, true);
+			return false;
+		break;
+		case 37: //arrow left
+		case 39: //arrow right
+			var elm = dad.getEventSource(evt);
+			elm = dad.getFirstParentWithTagName( this, "TABLE" );
+			if(key == 37 && elm.myPrevFocus){
+				elm.myPrevFocus.focus();
+				return false;
+			}
+			if(key == 39 && elm.myNextFocus){
+				elm.myNextFocus.focus();
+				return false;
+			}
+		break;
+		case 45: //insert
+		case 46: //delete
+			var tbl = dad.getFirstParentWithTagName( this, "TABLE" );
+			if(key == 45 && tbl._onInsert_cb) tbl._onInsert_cb(this);
+			else if(key == 46 && tbl._onDelete_cb) tbl._onDelete_cb(this);
+			return false;
+		break;
+		case 32: //space bar
+			this.checked = !this.checked;
+			return false;
+		break;
+		case 13: //enter
+			var tr = dad.getFirstParentWithTagName( this, "TR" );
+			//alert(tr.cells[1].innerHTML);
+			if(tr.onclick) tr.onclick(event);
+			else if(tr.ondblclick) tr.ondblclick(event);
+			return false;
+		break;
+	}
+}
+
+dad.tableInputOnFocus = function(){
+	var tr = dad.getFirstParentWithTagName( this, "TR" );
+	this.tr_color = tr.style.backgroundColor;
+	tr.style.backgroundColor = "blue";
+}
+
+dad.tableInputOnBlur = function(){
+	var tr = dad.getFirstParentWithTagName( this, "TR" );
+	tr.style.backgroundColor = this.tr_color;
+}
+
+dad.localeDecimalSeparator = (1.1).toLocaleString().substring(1, 2);
+
+dad.formatCurrency = function(v, number_of_decimals, decimal_separator, currency_sign){
+	if(number_of_decimals == null) number_of_decimals = 2;
+	if(currency_sign == null) currency_sign = "";
+	if(decimal_separator == null) decimal_separator = dad.localeDecimalSeparator;
+
+  return (isNaN(v)? v : parseInt(v||0).toLocaleString() + 
+		(decimal_separator) + 
+		(v*1).toFixed(number_of_decimals).slice(-number_of_decimals)) + 
+		currency_sign;
+}
+
+dad.formatNumeric = function(v){
+	return isNaN(v)? v : parseFloat(v);
+}
+
+dad.formatBoolean = function(v){
+	return v == "1" ? "+" : "";
+}
+
+dad.fillTableById = function(records, id){
+	var keys = dad._getTableAndHeaderKey(id);
+	var table = $(keys.table_key);
+	var header_title_col = 1
+	var record_header = table.my_record_header;
+	if(!record_header) {
+		record_header = records[0];
+		var col = record_header[0];
+		header_title_col = (col && col.indexOf('|') > 0) ? 1 : 0;
+	}
+	var col_count = record_header.length;				
+	
+	var row_over_cb = table.row_over_cb;
+	var row_click_cb = table.row_click_cb;
+	var row_dblclick_cb = table.row_dblclick_cb;
+	var first_row_click_cb = table.first_row_click_cb;
+	var selection_click_cb = table.selection_click_cb;
+	var th_row = table.tFoot.rows[0];
+	if(!dad.isFF) th_row.style.visibility = "hidden";
+	var th_cells = th_row.cells;
+	var tBody = table.tBodies[0];
+	try { 
+		tBody.innerHTML = "";
+	} catch(e) {
+		var rows = tBody.rows;
+		for(var i=rows.length-1; i >= 0; --i){
+			table.deleteRow(i);
+		}
+	}
+	var rows = tBody.rows;
+
+	var table_header = $(keys.table_header_key);
+	var th_header_row = table_header.tHead.rows[0];
+	var th_cells_header = th_header_row.cells;
+	
+	//setting the header
+	//header, width, align, format, color, bgcolor
+	for(var i = th_cells.length-1; i > 0; --i){
+		th_row.removeChild(th_cells[i]);
+		th_header_row.removeChild(th_cells_header[i]);
+	}
+	var myColsAlign = new Array(col_count);
+	var myColsFormat = new Array(col_count);
+	for(var i=0; i<col_count; ++i){
+		var ar = record_header[i].split("|");
+		var new_th=document.createElement('TH');
+		new_th.innerHTML = ar[header_title_col] || "?";
+		var align = ar[3];
+		if(align){
+			switch(align){
+				case "C": myColsAlign[i] =  "center"; break;
+				case "R": myColsAlign[i] =  "right"; break;
+				default: myColsAlign[i] = "left"; //default align left
+			}
+		}
+		if(ar[2] && ar[2] == "0"){
+			new_th.className = "display_none";//hide the col
+		}
+		var format = ar[4];
+		if(format == "M") myColsFormat[i] = dad.formatCurrency;
+		else if(format == "N") myColsFormat[i] = dad.formatNumeric;
+		else if(format == "B") myColsFormat[i] = dad.formatBoolean;
+		else myColsFormat[i] = false;
+
+		th_row.appendChild(new_th);
+		th_header_row.appendChild(new_th.cloneNode(true));
+	}
+
+	var first_record_no = table.my_record_header ? 0 : 1;
+	if(records.length > first_record_no){
+		var rec_count = records.length;
+		var rowVisible = dad.isMOZ ? 'table-row' : 'block';
+		var alignSupported = !dad.isIE;
+		
+		for (var i = first_record_no; i < rec_count; i++) { //1 to skip header
+			var rec = records[i];
+			var tr = rows[i];
+			if(!tr){
+				tr = tBody.insertRow(-1);
+				if(i%2) tr.className = "odd";
+				if(row_over_cb) tr.onmouseover = row_over_cb;
+				if(row_click_cb) tr.onclick = row_click_cb;
+				else if(row_dblclick_cb) tr.ondblclick = row_dblclick_cb;
+			}
+			var cells = tr.cells;
+			cell = tr.insertCell(-1);
+			cell.align = "center";
+			var chk = document.createElement("INPUT");
+			chk.type = "checkbox";
+			chk.onkeydown = dad.tableInputOnKeydown;
+			chk.onfocus = dad.tableInputOnFocus;
+			chk.onblur = dad.tableInputOnBlur;
+			chk.onclick = selection_click_cb;
+			cell.appendChild(chk);
+			if(i==1) chk.focus();
+			
+			for(var j=0, k=1; j < col_count; ++j, ++k){
+				var cell = cells[k];
+				if(!cell){
+					cell = tr.insertCell(-1);
+					var cn = th_cells[k].className;
+					if(cn) cell.className = cn + '_c';
+					if(alignSupported) cell.align = myColsAlign[j];
+				}
+				if(j==0 && first_row_click_cb) cell.onclick = first_row_click_cb;
+				var value = rec[j] || '';
+				if(myColsFormat[j]) value = myColsFormat[j](value);
+				cell.innerHTML = value;
+			}
+		}
+	}
+	//setEditTable(table_id, 2);
+	setTimeout(function() {
+		dad.AjaxDataTableResizeHeader(id);
+	},100);
+}
+		
+dad.parseSLEData = function(data, withHeader){
+	var records = [];
+	sle = dad.StrLenEncoded();
+	sle.sle2vecOfvec(data, data.length, records);
+	if(records.length < 1){
+		alert("An error has occured making the request");
+	}
+	if(!withHeader) records.shift();
+	return records;
+}
+
+dad.parseSLEData2Object = function(data){
+		var result_array = dad.parseSLEData(data, true);
+		var record = {};
+		if(result_array.length > 1){
+			var names = result_array[0];
+			var values = result_array[1];
+			for(var i in names){
+				record[names[i]] = values[i]; 
+			}
+		}
+		return record;
+}
+
+dad.newAjaxDataTableAjax = function(win, newId){
+	// win.onAfterResize = function(){
+		// setTimeout(function() {
+				// dad.AjaxDataTableResizeHeader(newId);
+			// },100);
+	// }		
+	return new dad.Ajax(function(id){
+			if(this.status == 200){
+				//retrieve result as an JavaScript object
+				var records = dad.parseSLEData(this.responseText, true);
+				//remove headers
+				if(!this._withHeaders) records.shift();
+				dad.fillTableById(records, id);
+			} else {
+				alert("An error has occured making the request");
+			}
+		}, newId, false);
+}
+
+dad._getSABTitle = function(all_sales_buys, title){
+	if(all_sales_buys == "S") title += ' Sales';
+	else if(all_sales_buys == "B") title += ' Buys';
+	return title;
+}
+
+dad.fillSelectByRecords = function(select, records, addDumy, dummyValue){
+	var options = select.options;
+	if(records && records.length > 0) {
+		var opt, nrec = records.length;
+		if(addDumy){
+			opt = new Option("----", dummyValue ? dummyValue : 0);
+			if(dad.isIE) options.add(opt);
+			else options.add(opt, null);
+		}
+		for(var i=0; i < nrec; i++){
+			var rec = records[i];
+			opt = new Option(rec[1], rec[0]);
+			if(dad.isIE) options.add(opt);
+			else options.add(opt, i+1);
+		}
+	}
+}
+
+dad.StrLenEncoded = function(){
+var IBYTE1 = 255;
+var IBYTE2 = 255*255;
+var IBYTE3 = 255*255*255;
+var IBYTE4 = 255*255*255*255;
+
+var SIZE1BYTE = 250;
+var SIZE2BYTE = 251;
+var SIZE3BYTE = 252;
+var SIZE4BYTE = 253;
+
+var SLEMARK = 254;
+var SLEEND = 255;
+
+this.charCodeAt = function(str, idx){
+	return str.charCodeAt(idx) & 0xFF;
+}
+
+this.stringToBytesFaster = function ( str ) { 
+    var ch, st, re = [], j=0;
+    for (var i = 0; i < str.length; i++ ) { 
+        ch = str.charCodeAt(i);
+        if(ch < 127)
+        {
+            re[j++] = ch & 0xFF;
+        }
+        else
+        {
+            st = [];    // clear stack
+            do {
+                st.push( ch & 0xFF );  // push byte to stack
+                ch = ch >> 8;          // shift value down by 1 byte
+            }
+            while ( ch );
+            // add stack contents to result
+            // done because chars have "wrong" endianness
+            st = st.reverse();
+            for(var k=0;k<st.length; ++k)
+                re[j++] = st[k];
+        }
+    }   
+    // return an array of bytes
+    return re; 
+}
+
+this.utf8toUtf16 = function(string) {   
+      var result = '';
+      var start = 0;
+      var end = 0;
+	  var enc, c1, c2, c3;
+	  var mycharCodeAt = this.charCodeAt;
+      for (var i = 0, len = string.length; i < len; ++i) {
+        c1 = mycharCodeAt(string, i);
+        enc = null;
+    
+        if (c1 < 128) end++;
+        else if (c1 > 0x07FF) {
+			c2 = mycharCodeAt(string, ++i);
+			c3 = mycharCodeAt(string, ++i);
+			enc = String.fromCharCode(((c1 & 0x0F) << 12) | ((c2 & 0x3F) << 6) | (c3 & 0x3F));
+		}
+		else {
+			c2 = mycharCodeAt(string, ++i);
+			enc = String.fromCharCode(((c1 & 0x1F) << 6) | (c2 & 0x3F));
+		}
+    
+        if (enc !== null) {
+          if (end > start) result += string.slice(start, end);
+    
+          result += enc;
+          start = end = i + 1;
+        }
+      }
+    
+      if (end > start) result += string.slice(start, string.length);
+    
+      return result;
+}
+
+this.sle2array = function(strascii, strascii_size, p, result_array)
+{
+    if(strascii_size == 0) return 0;
+    var size = 0, data_count = 0, data_len = 0;
+	var rec = [];
+	var mycharCodeAt = this.charCodeAt;
+    while((mycharCodeAt(strascii, p) != SLEEND) || (p >= strascii_size)) //data finished now follow digest
+    {
+        size = mycharCodeAt(strascii, p++);
+        if(size >= SIZE1BYTE)
+        {
+            if(size == SIZE1BYTE)
+            {
+                //data bigger than 250 and less 500 next byte has more info
+                size += mycharCodeAt(strascii, p++);
+            }
+            else if(size == SIZE2BYTE)
+            {
+                //data bigger than 250 next two bytes has more info
+                size = mycharCodeAt(strascii, p++) * IBYTE1;
+                size += mycharCodeAt(strascii, p++);
+            }
+            else if(size == SIZE3BYTE)
+            {
+                //data bigger than 250 next three bytes has more info
+                size = mycharCodeAt(strascii, p++) * IBYTE2;
+                size += mycharCodeAt(strascii, p++) * IBYTE1;
+                size += mycharCodeAt(strascii, p++);
+            }
+            else if(size == SIZE4BYTE)
+            {
+                //data bigger than 250 next four bytes has more info
+                size = mycharCodeAt(strascii, p++) * IBYTE3;
+                size += mycharCodeAt(strascii, p++) * IBYTE2;
+                size += mycharCodeAt(strascii, p++) * IBYTE1;
+                size += mycharCodeAt(strascii, p++);
+            }
+            else if(size == SLEMARK)
+            {
+                //reserved can be used for multi part data, metadata, digest, ...
+                break;
+            }
+        }
+		if(size > 0) {
+			var segment = strascii.substr(p, size);
+			rec.push(this.utf8toUtf16(segment));
+			//try {rec.push(decodeURIComponent(escape(segment)));} catch(e) {rec.push(segment);}
+		}
+		else rec.push("");
+        p += size;		
+        data_count++;
+        data_len += size;
+        if(data_len > strascii_size)
+        {
+            //something went wrong here
+            throw "We got more data than expected !";
+            break;
+        }
+    }
+	result_array.push(rec);
+    return ++p;
+}
+
+this.sle2vec = function(strascii, strascii_size, p, result_array)
+{
+    if(strascii[p] != '[') throw "Invalid encoded vector !";
+    if(strascii[p+1] == ']') return p+2; //empty array
+    result = this.sle2array(strascii, strascii_size-1, p+1, result_array);
+    if(strascii[result] != ']') throw "Invalid end of vector !";
+    return ++result;
+}
+
+this.sle2vecOfvec = function(strascii, strascii_size, result_array, p)
+{
+	if(!p) p = 0;
+	if(strascii[p] != '[') throw "Invalid encoded vector !";
+	if(strascii[p+1] == ']') return 2; //empty array
+	p = this.sle2vec(strascii, strascii_size-1, p+1, result_array);
+	while(strascii[p] == '['){
+		p = this.sle2vec(strascii, strascii_size - (p - strascii_size), p, result_array);
+	}
+	if(strascii[p] != ']') throw "Invalid end of vector !";
+	//printf("RowCount %d\n", row_count);
+	return ++p;
+}
+	
+	return this;
+};
+
+dad.rightClickMenu = null;
+
+dad.showRightClickMenu = function(event) {
+     if(!dad.rightClickMenu) return;
+     /*  check whether the event is a right click 
+       *  because different browser (ahem IE) assign different numbers to the keys to
+       *  your mouse buttons and different values to the event, you'll have to do some evaluation
+       */
+     var rightclick; //will be set to true or false
+     var evt = dad.checkEvent(event);
+     if (evt.button) {
+          rightclick = (event.button == 2);
+     } else if (evt.which) {
+          rightclick = (event.which == 3);
+     }
+ 
+     if(rightclick) { //if the secondary mouse botton was clicked
+          var menu = document.getElementById(dad.rightClickMenu);
+          menu.style.display = "block"; //show menu
+ 
+	  var pos =  dad.getMousePos(evt);
+ 
+          //position the menu
+          menu.style.position = "fixed"; // use fixed or it will not work when the window is scrolled
+          menu.style.top = pos.y+"px";
+          menu.style.left= pos.x+"px";
+     }
+}
+ 
+dad.clearRightClickMenu = function() { //used to make the menu disappear
+     //this function should be used at the beginning of any function that is called from the menu
+     if(dad.rightClickMenu) document.getElementById(dad.rightClickMenu).style.display = "none"; //don't show menu
+}

+ 445 - 0
ourbiz/s/ourbiz/barchart.js

@@ -0,0 +1,445 @@
+dad.barChart = function()
+{
+    this.init = function(elm)
+    {
+        if(typeof elm == 'string') elm = document.getElementById(elm);
+        this.canvas = elm;
+    }
+    this.canvas = null;
+    this.getContext = function()
+    {
+        return this.canvas.getContext('2d');
+    }
+    this.label = "Bar Chart";
+    this.label_align = -1; /*-1, 0, 1*/
+    this._bars = [];
+    this._bar_depth = 8;
+    this._bar_update_count = 0;
+    this._bar_num_format_decimals = 0;
+    this._bar_color = "#6f6";
+
+    this.bar_count = function()
+    {
+        return this._bars.length;
+    }
+    this.bar_add = function(bheader, bvalue, bcolor)
+    {
+        this._bars.push([bheader, bvalue, bcolor]);
+    }
+    this.getBar = function (idx)
+    {
+        return this._bars[idx];
+    }
+
+    this.get_bar_depth = function()
+    {
+        return this._bar_depth;
+    };
+    this.set_bar_depth = function(val)
+    {
+        this._bar_depth = val;
+        this.update_bar_chart();
+    }
+
+    this.get_bar_num_format_decimals = function()
+    {
+        return this._bar_num_format_decimals;
+    };
+    this.set_bar_num_format_decimals = function(val)
+    {
+        this._bar_num_format_decimals = val;
+        this.update_bar_chart();
+    }
+
+    this.bar_begin_update = function()
+    {
+        return ++this._bar_update_count;
+    }
+    this.bar_end_update = function()
+    {
+        if(this._bar_update_count == 0) throw "Barchart begin/end update out of sync !";
+        if(--this._bar_update_count == 0) this.update_bar_chart();
+    }
+
+    this.update_bar_chart = function()
+    {
+        if(this._bar_update_count == 0) this.draw();
+    }
+
+    this.bar_clear = function()
+    {
+        this._bars.length = 0;
+        this.update_bar_chart();
+    }
+
+    this._tmpSpan = document.createElement("span");
+    this.getFontMetrics = function(text, font)
+    {
+        //var tm = this._tmpSpan
+        //if(font) tm.font = font;
+        //tm.textContent = text;
+        //return { w: tm.offsetWidth, h: tm.offsetHeight};
+        //return { w: this.getContext().measureText(text), h: 14};
+				var ctx = this.getContext();
+        var metrics = ctx.measureText(text);
+				var hmetrics = ctx.measureText("L");
+        metrics.height = hmetrics.width * 3;
+        return metrics;
+    }
+    this.normalize_scale_units = function(oldScale)
+    {
+        var result = oldScale;
+        if(result < 2) result = 2;
+        else if(result <= 5) result = 5;
+        else if(result <= 10) result = 10;
+        else
+        {
+            var str = result.toString();
+            var t = str.charAt(0) - '0';
+            do
+            {
+                result = Math.floor(result / 10);
+                t *= 10;
+            }
+            while(result >= 10);
+            return t;
+        }
+        return result;
+    }
+
+    this.draw_mypolygon = function(x1, y1, x2, y2, x3, y3, x4, y4, line_color, fill_color)
+    {
+        var ctx = this.getContext();
+        ctx.save();
+        ctx.lineWidth = 1;
+        ctx.fillStyle = fill_color;
+        ctx.beginPath();
+        ctx.moveTo(x1, y1);
+        ctx.lineTo(x2,y2);
+        ctx.lineTo(x3,y3);
+        ctx.lineTo(x4,y4);
+        ctx.fill();
+        ctx.stroke();
+        ctx.closePath();
+
+        ctx.strokeStyle = line_color;
+        ctx.moveTo(x1, y1);
+        ctx.lineTo(x2,y2);
+        ctx.lineTo(x3,y3);
+        ctx.lineTo(x4,y4);
+        ctx.stroke();
+        //fl_line_style(FL_SOLID, 1, NULL);
+        //fl_loop(x1, y1, x2, y2, x3, y3, x4, y4);
+        ctx.restore();
+    }
+
+    this.draw_mybar = function(pbx, pby, pw, ph, pdepth, line_color, fill_color)
+    {
+        var lbx2 = pbx+pw;
+        var lbx3 = lbx2+pdepth;
+        var lby2 = pby+ph;
+        var lby3 = pby-pdepth;
+        // face rect
+        this.draw_mypolygon(
+            pbx, pby,
+            lbx2, pby,
+            lbx2, lby2,
+            pbx, lby2,
+            line_color,
+            fill_color
+        );
+        // top polygon
+        this.draw_mypolygon(
+            pbx, pby,
+            lbx2, pby,
+            lbx3, lby3,
+            pbx+pdepth, lby3,
+            line_color,
+            fill_color
+        );
+        // side polygon
+        this.draw_mypolygon(
+            lbx2, pby,
+            lbx3, lby3,
+            lbx3, lby2-pdepth,
+            lbx2, lby2,
+            line_color,
+            fill_color
+        );
+    }
+
+    // Fixed: Minus xStep bug (when x2 < x, original code bugs)
+    // Fixed: Vertical line bug (when abs(x - x2) is zero, original code bugs because of NaN)
+    //var CP = window.CanvasRenderingContext2D && CanvasRenderingContext2D.prototype;
+    this.dashedLine = function(x, y, x2, y2, dashArray)
+    {
+        if(! dashArray) dashArray=[10,5];
+        var dashCount = dashArray.length;
+        var dx = (x2 - x);
+        var dy = (y2 - y);
+        var xSlope = (Math.abs(dx) > Math.abs(dy));
+        var slope = (xSlope) ? dy / dx : dx / dy;
+
+        this._canvas.moveTo(x, y);
+        var distRemaining = Math.sqrt(dx * dx + dy * dy);
+        var dashIndex = 0;
+        while(distRemaining >= 0.1)
+        {
+            var dashLength = Math.min(distRemaining, dashArray[dashIndex % dashCount]);
+            var step = Math.sqrt(dashLength * dashLength / (1 + slope * slope));
+            if(xSlope)
+            {
+                if(dx < 0) step = -step;
+                x += step
+                y += slope * step;
+            }
+            else
+            {
+                if(dy < 0) step = -step;
+                x += slope * step;
+                y += step;
+            }
+            this_canvas[(dashIndex % 2 == 0) ? 'lineTo' : 'moveTo'](x, y);
+            distRemaining -= dashLength;
+            dashIndex++;
+        }
+    }
+
+    this.draw = function()
+    {
+        //set font size, color and clear
+        //alert(this.canvas.parentNode.offsetWidth);
+        //this.canvas.width = this.canvas.parentNode.offsetWidth * 0.96;
+        //this.canvas.height = this.canvas.parentNode.offsetHeight * 0.96;
+				//alert(this.canvas.width + ':'+this.canvas.height);
+
+        var ctx = this.getContext();
+				ctx.font = '10px verdana';
+				//ctx.scale(2,2);
+        var bar_depth = this._bar_depth;
+
+        var color_white = "#ffffff";
+        var color_black = "#000000";
+        var color_dark3 = "#cccccc";
+        var color_yellow = "yellow";
+
+        ctx.fillStyle = color_white;
+        ctx.fillRect(0, 0, this.canvas.width, this.canvas.height);
+
+        var tm = this.getFontMetrics("W");
+        var char_width = tm.width;
+        var char_height = tm.height;
+        var my_width = this.canvas.width;
+        var my_height = this.canvas.height;
+
+        var inner_padding = char_height;
+        var box_x = 0;
+        var box_y = char_height;
+
+        var str;
+        var nf_buf;
+
+        var bars_box_x, bars_box_y, bars_box_width, bars_box_height;
+
+        var box_label_width = inner_padding;
+        var value_max = 0;
+
+        var my_bars = this._bars;
+
+        for(var i=0, bl = my_bars.length; i < bl; ++i)
+        {
+            var bar = my_bars[i];
+            var max_value_str_width = ctx.measureText(bar[0]);
+            if(max_value_str_width > box_label_width) box_label_width = max_value_str_width;
+            if(bar[1]  > value_max) value_max = bar[1];
+        }
+        box_label_width += inner_padding *3;
+        bars_box_x = box_x + box_label_width;
+        bars_box_y = box_y + inner_padding;
+        bars_box_height = my_height - inner_padding - 3 * char_height;
+        bars_box_width = my_width - box_label_width - 3 * bar_depth - inner_padding;
+
+        this.draw_mypolygon(
+            bars_box_x, bars_box_y+bar_depth,
+            bars_box_x, bars_box_y+bar_depth+bars_box_height,
+            bars_box_x+bar_depth, bars_box_y+bars_box_height,
+            bars_box_x+bar_depth, bars_box_y,
+            color_black,
+            color_yellow
+        );
+        this.draw_mypolygon(
+            bars_box_x, bars_box_y+bar_depth+bars_box_height,
+            bars_box_x+bars_box_width+bar_depth, bars_box_y+bar_depth+bars_box_height,
+            bars_box_x+bars_box_width+bar_depth*2, bars_box_y+bars_box_height,
+            bars_box_x+bar_depth, bars_box_y+bars_box_height,
+            color_black,
+            color_white
+        );
+
+        ctx.strokeStyle = color_black;
+        ctx.lineWidth = 1;
+        ctx.strokeRect(bars_box_x+bar_depth, bars_box_y, bars_box_width+bar_depth, bars_box_height+1);
+
+
+        ctx.lineWidth = 1;
+        ctx.moveTo(bars_box_x, bars_box_y+bar_depth);
+        ctx.lineTo(bars_box_x, bars_box_y+bar_depth+bars_box_height);
+        ctx.lineTo(bars_box_x+bars_box_width+bar_depth, bars_box_y+bar_depth+bars_box_height);
+        ctx.stroke();
+
+        var my_label = this.label;
+        ctx.lineWidth = 1;
+        ctx.fillStyle = "#0000ff"; // text color
+        if(my_label) ctx.fillText(my_label, (my_width - ctx.measureText(my_label).width)/2, box_y);
+
+        str = value_max.toString();
+        var max_value_str_width, max_value_str_height;
+        tm = this.getFontMetrics(str);
+        max_value_str_width = tm.width;
+        max_value_str_height = tm.height;
+
+        var pixelPerUnit, nScaleLines, scaleUnits, itmp;
+        if(value_max == 0)
+        {
+            pixelPerUnit = 1;
+            nScaleLines = 1;
+        }
+        else
+        {
+            itmp = bars_box_width-max_value_str_width-bar_depth;
+            pixelPerUnit = (itmp / value_max);
+            nScaleLines = Math.ceil(itmp / (2*max_value_str_width));
+        }
+
+        if(nScaleLines == 0) scaleUnits = value_max +1;
+        else scaleUnits = Math.floor(value_max / nScaleLines) +1;
+
+        scaleUnits = this.normalize_scale_units(scaleUnits);
+        if(scaleUnits == 0)	nScaleLines = 1;
+        else nScaleLines = (value_max / scaleUnits)+1;
+
+        ctx.strokeStyle = color_dark3;
+        ctx.lineWidth = 1;
+
+        var draw_scaleLine = function(dk,s)
+        {
+            var lx, ly, lx2, ly2;
+            lx = bars_box_x + dk + bar_depth;
+            ly = bars_box_y + bars_box_height;
+            lx2 = bars_box_x + dk;
+            ly2 = bars_box_y + bar_depth+bars_box_height;
+
+            ctx.moveTo(lx, bars_box_y);
+            ctx.lineTo(lx, ly);
+            ctx.lineTo(lx2, ly2);
+            ctx.stroke();
+
+            ctx.moveTo(lx2, ly2);
+            ctx.lineTo(lx2, ly2 + 2);
+            ctx.stroke();
+
+            ctx.save();
+            ctx.fillStyle = color_black;
+            ctx.fillText(s, bars_box_x + dk - half_max_value_str_width, bars_box_bottom+char_height);
+            ctx.restore();
+        }
+
+        var half_max_value_str_width = Math.floor(max_value_str_width / 2);
+        var bars_box_bottom = bars_box_y+bar_depth+bars_box_height+2;
+        var str_zero = "0";
+        if(value_max == 0)
+        {
+            var ik = Math.floor(bars_box_width / 2);
+            draw_scaleLine(ik,str_zero);
+        }
+        else
+        {
+            ctx.fillStyle = color_black;
+            ctx.fillText(str_zero, bars_box_x, bars_box_bottom+char_height);
+            ctx.strokeStyle = color_dark3;
+        }
+
+        for(var ik=0; ik < nScaleLines; ik++)
+        {
+            var xs = Math.floor(scaleUnits*pixelPerUnit*ik);
+            nf_buf = dad.number_format(ik*scaleUnits, this._bar_num_format_decimals);
+            draw_scaleLine(xs, nf_buf);
+        }
+
+        var bar_height, bar_y;
+        if(this._bars.length == 0) bar_height = 0;
+        else bar_height = ((bars_box_height- bar_depth) / ((2.0*this._bars.length+1)));
+
+        bars_box_bottom -= 2*bar_height + bar_depth;
+        var ikl = 0;
+
+        for(var i = 0, bl = my_bars.length; i < bl; ++i)
+        {
+            var bar = my_bars[i];
+            bar_y = bars_box_bottom - (2*i*bar_height) ;
+
+            var value = bar[1]; //bar value
+            var bar_width = Math.floor(value*pixelPerUnit);
+
+            this.draw_mybar(bars_box_x, bar_y, bar_width, bar_height, bar_depth, "#ccc", bar[2]);
+
+            nf_buf = dad.number_format(value, this._bar_num_format_decimals);
+            var rcenter = Math.floor(bar_y+(bar_height-bar_depth) / 2);
+
+            ctx.strokeStyle = color_dark3;
+            ctx.moveTo(bars_box_x+bar_width+bar_depth/2, rcenter);
+            ctx.lineTo(bars_box_x+bar_width+bar_depth*2, rcenter);
+            ctx.stroke();
+
+            var str_width, str_height;
+            tm = this.getFontMetrics(nf_buf);
+            str_width = tm.width;
+            str_height = tm.height;
+
+            var rc_x = bars_box_x+bar_width+bar_depth*2;
+            var rc_w = str_width+bar_depth;
+            var rc_y = rcenter - (str_height/2);
+            var rc_h = str_height * 1.1;
+
+            ctx.beginPath();
+            ctx.rect(rc_x, rc_y, rc_w, rc_h);
+            ctx.fillStyle = color_yellow;
+            ctx.fill();
+            ctx.stroke();
+
+            ctx.fillStyle = "black";
+            ctx.fillText(nf_buf, rc_x+(bar_depth/2), rcenter + (str_height/3));
+
+            str = bar[0]; //bar header
+            tm = this.getFontMetrics(str);
+            str_width = tm.width;
+            str_height = tm.height;
+
+            var str_x, str_y;
+            //ctx.ctx.strokeStyle = "#000000";
+            switch(this.label_align)
+            {
+            case 0: //FL_ALIGN_CENTER:
+            {
+                str_x = box_x+(box_label_width/2) - (str_width / 2);
+                str_y = rcenter + (str_height/3);
+            }
+            break;
+            case 1: //FL_ALIGN_RIGHT:
+            {
+                str_x = bars_box_x-str_width-inner_padding;
+                str_y = rcenter + (str_height/3);
+            }
+            break;
+            default:
+            {
+                str_x = box_x + inner_padding - 5;
+                str_y = rcenter + (str_height/3);
+            }
+            }
+
+            ctx.fillText(str, str_x, str_y);
+        }
+        //fl_line_style(0);
+    }
+};

+ 211 - 0
ourbiz/s/ourbiz/calendar-chooser.js

@@ -0,0 +1,211 @@
+Jaml.register('CalendarChooserWindow', function(args) {
+	var callOpFunc = "CalendarChooserSetDate('" + args.id + "','";
+	var callOp = function(op){return callOpFunc + op + "')";}
+	var cbtn = function() {return input({type:"button"});}
+	form({id: args.form_id, style: "width:100%;height:100%;", onsubmit:"return false;"},
+		table({style: "width:100%;", cls:"calTbl"},
+			tr(
+				td({id: "cc_header" + args.id, cls: "fw hcenter", style: "height: 10%;"}, "date")
+			),
+			tr(
+				td({cls: "fw cc_month", style: "height: 20%;"},
+					button({onclick: callOp('m1')}, "1"),
+					button({onclick: callOp('m2')}, "2"),
+					button({onclick: callOp('m3')}, "3"),
+					button({onclick: callOp('m4')}, "4"),
+					button({onclick: callOp('m5')}, "5"),
+					button({onclick: callOp('m6')}, "6"),
+					button({onclick: callOp('m7')}, "7"),
+					button({onclick: callOp('m8')}, "8"),
+					button({onclick: callOp('m9')}, "9"),
+					button({onclick: callOp('m10')}, "10"),
+					button({onclick: callOp('m11')}, "11"),
+					button({onclick: callOp('m12')}, "12")
+				)
+			),
+			tr(
+				td(
+					table({style: "width:100%;height:60%", cls: "cc_days", id: "cc_days_month" + args.id},
+						tr(
+							th(_tr("Mo")),th(_tr("Tu")),th(_tr("We")),th(_tr("Th")),th(_tr("Fr")),th(_tr("Sa")),th(_tr("Su"))
+						),
+						tr(
+							td(cbtn()),td(cbtn()),td(cbtn()),td(cbtn()),td(cbtn()),td(cbtn()),td(cbtn())
+						),
+						tr(
+							td(cbtn()),td(cbtn()),td(cbtn()),td(cbtn()),td(cbtn()),td(cbtn()),td(cbtn())
+						),
+						tr(
+							td(cbtn()),td(cbtn()),td(cbtn()),td(cbtn()),td(cbtn()),td(cbtn()),td(cbtn())
+						),
+						tr(
+							td(cbtn()),td(cbtn()),td(cbtn()),td(cbtn()),td(cbtn()),td(cbtn()),td(cbtn())
+						),
+						tr(
+							td(cbtn()),td(cbtn()),td(cbtn()),td(cbtn()),td(cbtn()),td(cbtn()),td(cbtn())
+						),
+						tr(
+							td(cbtn()),td(cbtn()),td(cbtn()),td(cbtn()),td(cbtn()),td(cbtn()),td(cbtn())
+						)
+					)
+				)
+			),
+			tr(
+				td({cls: "fw cc_nav", style: "height: 10%;"},
+					button({onclick: callOp('-y')}, "&lt;&lt;"),
+					button({onclick: callOp('-m')}, "&lt;"),
+					button({onclick: callOp('0')}, "&lt;&gt;"),
+					button({onclick: callOp('0')}, "@"),
+					button({onclick: callOp('+m')}, "&gt;"),
+					button({onclick: callOp('+y')}, "&gt;&gt;")
+				)
+			)
+		)
+	);
+});
+
+function CalendarChooserMakemonth(y,m){
+	var DAY_SECONDS = 86400;
+	var DAY_MILISECONDS = DAY_SECONDS * 1000;
+	var monthArray = [];
+	var adate = new Date();
+	adate.setDate(1);
+	adate.setMonth(m);
+	adate.setFullYear(y);
+	// get back to the nearest monday
+	adate.setTime(adate.getTime()-(DAY_MILISECONDS * (adate.getDay()-1)));
+	var day = adate.getDate();
+	if(day < 7 && day != 1){
+		//go back one more week
+		adate.setTime(adate.getTime() - (DAY_MILISECONDS * 7));
+	}
+	do{
+		var weekArray = [];
+		monthArray.push(weekArray);
+		do { // insert the week days
+			weekArray.push(adate.getDate());
+			adate.setTime(adate.getTime() + DAY_MILISECONDS);
+		} while( adate.getDay() != 1 ) // monday
+	} while( adate.getMonth() == m );
+	return monthArray;
+}
+
+function CalendarChooserSetDate(id, op){
+	//alert(table_month_id + ':' + op)
+	var table_month = document.getElementById("cc_days_month" + id);
+	var date = table_month._date ? table_month._date : 0;
+	switch(op){
+		case '-y': date.setFullYear(date.getFullYear()-1); break;
+		case '+y': date.setFullYear(date.getFullYear()+1); break;
+		case '-m': date.setMonth(date.getMonth()-1); break;
+		case '+m': date.setMonth(date.getMonth()+1); break;
+		case 'm1': date.setMonth(0); break;
+		case 'm2': date.setMonth(1); break;
+		case 'm3': date.setMonth(2); break;
+		case 'm4': date.setMonth(3); break;
+		case 'm5': date.setMonth(4); break;
+		case 'm6': date.setMonth(5); break;
+		case 'm7': date.setMonth(6); break;
+		case 'm8': date.setMonth(7); break;
+		case 'm9': date.setMonth(8); break;
+		case 'm10': date.setMonth(9); break;
+		case 'm11': date.setMonth(10); break;
+		case 'm12': date.setMonth(11); break;
+		default:
+			table_month._date = new Date();
+	}
+
+	var cc_header = document.getElementById("cc_header" + id);
+	cc_header.innerHTML = table_month._date.toLocaleString();
+	
+	var monthArray = CalendarChooserMakemonth(table_month._date.getFullYear(), table_month._date.getMonth());
+	for(var i = 0; i < monthArray.length; i++){
+		var week = monthArray[i];
+		var row = table_month.rows[i+1];
+		var cells = row.cells;
+		for(var j=0; j < week.length; j++){
+			dad.getFirstChild(cells[j]).value = week[j];
+		}
+	}
+}		
+
+function CalendarChooserWindowOnTableCellClick(){
+}
+
+function CalendarChooserFocusUpDown(elm, up){
+	var table = dad.getFirstParentWithTagName(elm, "TABLE");
+	var getFirstChild = dad.getFirstChild;
+	var rows = table.tBodies[0].rows;
+	for(var r=rows.length-1; r >= 0; --r){
+		var cells = rows[r].cells;
+		for(var c=cells.length-1; c >= 0; --c){
+			if(getFirstChild(cells[c]) == elm){
+				if(up){
+					if(r > 1){ //second row and bellow
+						getFirstChild(rows[r-1].cells[c]).focus();
+						return true;
+					}
+				} else if(r < rows.length-1) {
+					getFirstChild(rows[r+1].cells[c]).focus();
+					return true;
+				}
+			}
+		}
+	}
+	return false;
+}
+
+function CalendarChooserInputOnKeydown(event){
+	var evt = dad.checkEvent(event);
+	//alert(dad.getEventSource(evt).name);
+
+	switch(dad.getEventKey(evt)){
+		case 40: //arrow down
+			if(CalendarChooserFocusUpDown(this, false)) return false;
+		break;
+		case 38: //arrow up
+			if(CalendarChooserFocusUpDown(this, true)) return false;
+		break;
+		case 37: //arrow left
+			dad.formFocusNextFromEvent(evt, true);
+			return false;
+		break;
+		case 39: //arrow right
+			dad.formFocusNextFromEvent(evt);
+			return false;
+		break;
+		case 13: //enter
+		case 32: //space bar
+		break;
+	}
+}	
+
+function newCalendarChooserWindow(){
+	var title = "Calendar Chooser"
+	var win = dad._windows[title];
+	if(!win){
+		var newId = dad.newSeqId();
+		var Action_id = 'Action' + newId;
+		var btnAction_id = 'btnAction' + newId;
+		var table_id = 'table' + newId;
+		var form_id = 'form' + newId;
+		var data = {
+			id: newId,
+			form_id: form_id,
+			Action_id: Action_id,
+			btnAction_id: btnAction_id,
+			table_id: table_id
+		}
+		var win = dad.newWindow(newId, 220,20, 300, 0, _tr(title), Jaml.render('CalendarChooserWindow', data));
+		CalendarChooserSetDate(newId, 0);
+		
+		var myform = document.getElementById(data.form_id);
+		for ( var i = 0, cnl = myform.length; i < cnl; i++ ) {
+			var elm = myform[i];
+			if ( dad.isFocusableTag(elm.tagName) ){
+				elm.onkeydown = CalendarChooserInputOnKeydown;
+			}
+		}
+	}
+	dad.bringToFront(win)
+}

+ 258 - 0
ourbiz/s/ourbiz/css/styles.css

@@ -0,0 +1,258 @@
+/*
+Design by Free Responsive Templates
+http://www.free-responsive-templates.com
+Released for free under a Creative Commons Attribution 3.0 Unported License (CC BY 3.0)
+*/ 
+* {
+	margin:0;
+	padding:0;
+}
+body {
+	font-family: verdana, serif;
+	font-size:14px;
+	background: url(../images/siteBackground.jpg);
+	margin: 0;
+	padding: 0;
+	color: rgb(50, 60, 70);	
+}
+a img { 
+	border: none;
+}
+a:link {
+	color: #0484c0;
+	text-decoration: underline; 
+}
+a:visited {
+	color: #0484c0;
+	text-decoration: underline;
+}
+a:hover, a:active, a:focus { 
+	color: #0484c0;
+	text-decoration: none;
+}
+h1 {
+	font-size:30px;
+	color:#8dc35a;
+	font-family: verdana, sans-serif;
+	padding: 0 0 10px 0;
+}
+h2 {
+	font-size:24px;
+	color:#ffffff;
+	font-family: verdana, sans-serif;
+	padding: 0 0 10px 0;
+	text-shadow: 0px 0px, 1px 3px #b8bec0;
+}
+h3 {
+	font-size:30px;
+	color:#677a83;
+	font-family: verdana, sans-serif;
+	padding: 0 0 10px 0;
+}
+p {
+	line-height:140%;
+}
+.wrapper {
+	width:960px;
+	margin:40px auto;
+	background: #ffffff;
+	box-shadow: 0 0 10px rgba(0, 0, 0, 0.2);
+	padding-bottom:50px;
+}
+header {
+	padding:50px 50px 10px 50px;
+}
+.logo {
+	float: left;
+	background: url(../images/logoBackground.png) no-repeat;
+	width: 122px;
+	height: 123px;
+}
+.logo h1 a {
+	text-shadow: 0px 0px, 1px 2px #5b9e11;
+	font-size:60px;
+	color: #ffffff;
+	text-decoration:none;
+	padding:10px;
+	line-height:110px;
+}
+footer {
+	text-align:center;
+	padding-bottom:40px
+}
+.horSeparator {
+	background:url(../images/horSeparator.png) repeat-x;
+	height:13px;
+	margin:20px 0;
+}
+section {
+	padding:0 50px;
+}
+.post {
+	border-bottom:1px solid rgba(200, 207, 210, 1);
+	padding:50px 0;
+	margin:0 50px;
+}
+.post header {
+	float:right;
+	width:519px;
+	padding:0;
+}
+.post p {
+	float:right;
+	width:519px;
+}
+.post aside img {
+	border:1px solid #c8cfd2;
+	margin:10px 0 0 0;
+}
+.sectionFooter {
+	background: #d6d9da;
+	padding:40px 0;
+	margin:0 50px;
+	border-top:1px solid #ffffff;
+}
+.footerBox {
+	width:40%;
+	float:left;
+	padding:0 40px;
+}
+.footerBox p {
+	font-style:italic;
+	padding:0 0px 10px 0px;
+}
+.clearfloat { 
+	clear:both;
+	height:0;
+	font-size: 1px;
+	line-height: 0px;
+}
+
+  
+/**************************/
+/*********************************Begin main menu****************************************/
+/**************************/
+nav {
+	float:right;
+	padding:40px 0 0 0;
+}
+ul#navlist {
+	margin-left: 0;
+	padding-left: 0;
+	white-space: nowrap;
+}
+#navlist li {
+	display: inline;
+	list-style-type: none;
+}
+#navlist a { 
+	padding: 3px 10px; 
+	font-family: 'Lobster', sans-serif;
+	font-size: 36px;
+	color: #677a83;
+}
+#navlist a:link, #navlist a:visited {
+	color: #677a83;
+	text-decoration: none;
+}
+#navlist a:hover {
+	color: #8dc35a;
+	text-decoration: none;
+}
+#navlist #active a {
+	color: #8dc35a;
+	text-decoration: none;
+}
+/**************************/
+/*********************************End main menu****************************************/
+/**************************/
+/*********************************Begin Media Queries****************************************/
+/**************************/
+/* for 980px or less */
+@media screen and (max-width: 980px) {
+	.wrapper {
+		width: 95%;
+	}
+}
+/* for 768px or less */
+@media screen and (max-width: 768px) {
+	h1, h2, h3 {
+		font-size:24px;
+	}
+	header {
+		padding:20px 50px 0px 50px;
+	}
+	.post {
+		padding:20px 0;
+	}
+	.post header, .post p {
+		width:400px;
+	}
+	article aside {
+		width: 170px;
+	}
+	.footerBox {
+		padding:0 20px;
+	}
+	.footerBox p {
+		padding:0 0 10px 0;
+	}
+	#navlist a { 
+		padding: 3px 10px; 
+		font-size: 24px;
+	}
+}
+/* for 480px or less */
+@media screen and (max-width: 480px) {
+	.wrapper {
+		margin-top:10px;
+	}
+	header {
+		padding:10px 10px 0px 10px;
+	}
+	.logo {
+		float:none;
+		margin:0 auto;
+	}
+	nav {
+		float:none;
+		padding:5px 0 0 0;
+	}
+	#navlist a { 
+		padding: 7px 2px; 
+		font-family: 'Lobster', sans-serif;
+		font-size: 16px;
+		color: #677a83;
+	}
+	section {
+		padding:0 10px;
+	}
+	article aside {
+		display:none;
+	}
+	.post {
+		padding:10px 0;
+		margin:0 10px;
+	}
+	.post header, .post p {
+		width:auto;
+		float:none;
+	}
+	.sectionFooter {
+		padding:10px 0;
+		margin:0 10px;
+	}
+	.footerBox {
+		width:auto;
+		float:none;
+		padding:10px;
+	}
+}
+img {
+	max-width: 100%;
+	height: auto;
+	width: auto;
+}
+/**************************/
+/*********************************End Media Queries****************************************/
+/**************************/

BIN
ourbiz/s/ourbiz/dadbiz_120.png


+ 137 - 0
ourbiz/s/ourbiz/dadlib.js

@@ -0,0 +1,137 @@
+Jaml.register('2TRDataTable', function(args) {
+		tr(
+			td({colspan:3, style: "width:100%; height:10px;"}, //no height for firefox
+				div({'class': "divTable", style: "width:100%;overflow:auto;"},
+						table({id: args.table_header_id, 'class': "wrappedTable"},
+							thead( tr( 
+								th( input({type: "checkbox", onkeydown:"dad.formInputTextOnKeydown"}) )
+								) )
+						)
+				)
+			)
+		),
+		tr(
+		//(args.table_height || "100%") 65% for firefox
+			td({colspan:3, style: "width:100%;height:" + (args.table_height || "100%") + "; vertical-align:top;"},
+				div({'class': "divTable", style: "width:100%;height:100%;overflow:auto;"},
+					div({style:"height: 0px;"},
+						table({id: args.table_id, 'class': "wrappedTable"},
+							tbody(),
+							tfoot( tr( th( "&nbsp;" ) ) )
+						)
+					)
+				)
+			)
+		)
+});
+
+
+Jaml.register('HistoryTabContent', function(args) {
+	table({style: "width:100%;height:100%;"},
+		tr(
+			td({style: "width:80%;height:10px;"},
+				select({id: 'history_type_id' + args.id, style: "width:100%;"}, args.history_options)
+			),
+			td({style: "width:5%;"},input({type: "text", name: "history_query_limit", size:4, value: "50"})),
+			td({style: "width:15%;"},button(_tr("View Doc.")))
+		),
+		tr(
+			td({colspan:3, style: "width:100%;height:10px;"},
+				div({'class': "divTable", style: "width:100%;"},
+						table({id: args.table_history_header_id, 'class': "wrappedTable"},
+							thead( tr(  th( input({type: "checkbox", onkeydown:"dad.formInputTextOnKeydown"}) ) ) )
+						)
+				)
+			)
+		),
+		tr(
+			td({colspan:3, style: "width:100%;"},
+				div({'class': "divTable", style: "width:100%;height:22em;overflow:auto;"},
+					div({style:"height: 0px;"},
+						table({id: args.table_history_id, 'class': "wrappedTable"},
+							tbody(),
+							tfoot( tr( th( "&nbsp;" ) ) )
+						)
+					)
+				)
+			)
+		)
+	)
+});
+
+Jaml.register('StatisticsTabContent', function(args) {
+	var newIdBy2 = dad.newIdBy2calls;
+	table({style: "width:100%;height:100%;"},
+		tr(
+			td({style: "height:1%;"},
+				button({id: "btnShowChart" + args.id}, _tr("Show")),
+				input({type: "text", name: "statistics_periodes", size:4, value:"12"}),
+				input({type: "radio", name: "statistics_by", id: newIdBy2(), value: "years" }),
+				label({'for': newIdBy2()},  _tr("Years")),
+				input({type: "radio", name: "statistics_by", id: newIdBy2(), value: "months", checked:"1"}),
+				label({'for': newIdBy2()},  _tr("Months")),
+				input({type: "radio", name: "statistics_by", id: newIdBy2(), value: "weeks"}),
+				label({'for': newIdBy2()},  _tr("Weeks")),
+				input({type: "radio", name: "statistics_by", id: newIdBy2(), value: "days"}),
+				label({'for': newIdBy2()},  _tr("Days"))
+			)
+		),
+		tr(
+			td({style: "width:100%;height:90%;"},
+				div({'class': "divChart", style: "width:100%;height:100%"},
+					canvas({id:"canvas" + args.id, width:760, height:380},
+						"This text is displayed if your browser does not support HTML5 Canvas."
+					)
+				)
+			)
+		)
+	)
+});
+
+function BarChartFillByAjax(id){
+	if(this.status == 200){
+		var records = dad.parseSLEData(this.responseText);
+		var row_count = records.length;
+		
+		var btnShowChart = $("btnShowChart" + id);
+		var chart = btnShowChart._chart;
+
+		//chart.set_bar_num_format_decimals(0);
+		chart.bar_begin_update();
+		chart.bar_clear();
+		for(var i=1; i<row_count; i++){ //start at 1 to skip headers
+			var rec = records[i];
+			var cl = rec[2] == "S" ? "#11a" : "#1a1";
+			chart.bar_add(rec[0], parseFloat(rec[1]), cl);
+		}
+		chart.bar_end_update();
+	} else {
+		alert("An error has occured making the request");
+	}
+}
+
+dad.setupBarchart = function(bid, ajaxParamsFunc){
+	var btnShowChart = $("btnShowChart" + bid);
+	var canvasChart = $("canvas" + bid);
+	btnShowChart._chart = new dad.barChart();
+	btnShowChart._chart.init(canvasChart);
+	btnShowChart.ajaxData = new dad.Ajax(BarChartFillByAjax, bid, false);
+	btnShowChart.ajaxParamsFunc = ajaxParamsFunc;
+	btnShowChart.onclick = function(){
+		var ajax = btnShowChart.ajaxData;
+		var params = this.ajaxParamsFunc();
+		var form = this.form;
+		var statistics_by = 'months';
+		for (var i=form.statistics_by.length-1; i >= 0; --i){ 
+		  if (form.statistics_by[i].checked){
+				statistics_by = form.statistics_by[i].value;
+				break; 
+			}
+		} 
+		params += "&periode_count=" + form.statistics_periodes.value;
+		params += "&periode_type=" + statistics_by;
+		params += "&query_limit=" + form.history_query_limit.value;
+		ajax.post('/DB/GetList', params, "GET");
+		return false;
+	}
+}

+ 150 - 0
ourbiz/s/ourbiz/editor.html

@@ -0,0 +1,150 @@
+<!doctype html>
+<html>
+<head>
+<title>Rich Text Editor</title>
+<script type="text/javascript">
+var oDoc, sDefTxt;
+
+function initDoc() {
+  oDoc = document.getElementById("textBox");
+  sDefTxt = oDoc.innerHTML;
+  if (document.compForm.switchMode.checked) { setDocMode(true); }
+}
+
+function formatDoc(sCmd, sValue) {
+  if (validateMode()) { document.execCommand(sCmd, false, sValue); oDoc.focus(); }
+}
+
+function validateMode() {
+  if (!document.compForm.switchMode.checked) { return true ; }
+  alert("Uncheck \"Show HTML\".");
+  oDoc.focus();
+  return false;
+}
+
+function setDocMode(bToSource) {
+  var oContent;
+  if (bToSource) {
+    oContent = document.createTextNode(oDoc.innerHTML);
+    oDoc.innerHTML = "";
+    var oPre = document.createElement("pre");
+    oDoc.contentEditable = false;
+    oPre.id = "sourceText";
+    oPre.contentEditable = true;
+    oPre.appendChild(oContent);
+    oDoc.appendChild(oPre);
+  } else {
+    if (document.all) {
+      oDoc.innerHTML = oDoc.innerText;
+    } else {
+      oContent = document.createRange();
+      oContent.selectNodeContents(oDoc.firstChild);
+      oDoc.innerHTML = oContent.toString();
+    }
+    oDoc.contentEditable = true;
+  }
+  oDoc.focus();
+}
+
+function printDoc() {
+  if (!validateMode()) { return; }
+  var oPrntWin = window.open("","_blank","width=450,height=470,left=400,top=100,menubar=yes,toolbar=no,location=no,scrollbars=yes");
+  oPrntWin.document.open();
+  oPrntWin.document.write("<!doctype html><html><head><title>Print<\/title><\/head><body onload=\"print();\">" + oDoc.innerHTML + "<\/body><\/html>");
+  oPrntWin.document.close();
+}
+</script>
+<style type="text/css">
+.intLink { cursor: pointer; }
+img.intLink { border: 0; }
+#toolBar1 select { font-size:10px; }
+#textBox {
+  width: 540px;
+  height: 200px;
+  border: 1px #000000 solid;
+  padding: 12px;
+  overflow: scroll;
+}
+#textBox #sourceText {
+  padding: 0;
+  margin: 0;
+  min-width: 498px;
+  min-height: 200px;
+}
+#editMode label { cursor: pointer; }
+</style>
+</head>
+<body onload="initDoc();">
+<form name="compForm" method="post" action="sample.php" onsubmit="if(validateMode()){this.myDoc.value=oDoc.innerHTML;return true;}return false;">
+<input type="hidden" name="myDoc">
+<div id="toolBar1">
+<select onchange="formatDoc('formatblock',this[this.selectedIndex].value);this.selectedIndex=0;">
+<option selected>- formatting -</option>
+<option value="&lt;h1&gt;">Title 1 &lt;h1&gt;</option>
+<option value="&lt;h2&gt;">Title 2 &lt;h2&gt;</option>
+<option value="&lt;h3&gt;">Title 3 &lt;h3&gt;</option>
+<option value="&lt;h4&gt;">Title 4 &lt;h4&gt;</option>
+<option value="&lt;h5&gt;">Title 5 &lt;h5&gt;</option>
+<option value="&lt;h6&gt;">Subtitle &lt;h6&gt;</option>
+<option value="&lt;p&gt;">Paragraph &lt;p&gt;</option>
+<option value="&lt;pre&gt;">Preformatted &lt;pre&gt;</option>
+</select>
+<select onchange="formatDoc('fontname',this[this.selectedIndex].value);this.selectedIndex=0;">
+<option class="heading" selected>- font -</option>
+<option>Arial</option>
+<option>Arial Black</option>
+<option>Courier New</option>
+<option>Times New Roman</option>
+</select>
+<select onchange="formatDoc('fontsize',this[this.selectedIndex].value);this.selectedIndex=0;">
+<option class="heading" selected>- size -</option>
+<option value="1">Very small</option>
+<option value="2">A bit small</option>
+<option value="3">Normal</option>
+<option value="4">Medium-large</option>
+<option value="5">Big</option>
+<option value="6">Very big</option>
+<option value="7">Maximum</option>
+</select>
+<select onchange="formatDoc('forecolor',this[this.selectedIndex].value);this.selectedIndex=0;">
+<option class="heading" selected>- color -</option>
+<option value="red">Red</option>
+<option value="blue">Blue</option>
+<option value="green">Green</option>
+<option value="black">Black</option>
+</select>
+<select onchange="formatDoc('backcolor',this[this.selectedIndex].value);this.selectedIndex=0;">
+<option class="heading" selected>- background -</option>
+<option value="red">Red</option>
+<option value="green">Green</option>
+<option value="black">Black</option>
+</select>
+</div>
+<div id="toolBar2">
+<img class="intLink" title="Clean" onclick="if(validateMode()&&confirm('Are you sure?')){oDoc.innerHTML=sDefTxt};" src="data:image/gif;base64,R0lGODlhFgAWAIQbAD04KTRLYzFRjlldZl9vj1dusY14WYODhpWIbbSVFY6O7IOXw5qbms+wUbCztca0ccS4kdDQjdTLtMrL1O3YitHa7OPcsd/f4PfvrvDv8Pv5xv///////////////////yH5BAEKAB8ALAAAAAAWABYAAAV84CeOZGmeaKqubMteyzK547QoBcFWTm/jgsHq4rhMLoxFIehQQSAWR+Z4IAyaJ0kEgtFoLIzLwRE4oCQWrxoTOTAIhMCZ0tVgMBQKZHAYyFEWEV14eQ8IflhnEHmFDQkAiSkQCI2PDC4QBg+OAJc0ewadNCOgo6anqKkoIQA7" />
+<img class="intLink" title="Print" onclick="printDoc();" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABYAAAAWCAYAAADEtGw7AAAABGdBTUEAALGPC/xhBQAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9oEBxcZFmGboiwAAAAIdEVYdENvbW1lbnQA9syWvwAAAuFJREFUOMvtlUtsjFEUx//n3nn0YdpBh1abRpt4LFqtqkc3jRKkNEIsiIRIBBEhJJpKlIVo4m1RRMKKjQiRMJRUqUdKPT71qpIpiRKPaqdF55tv5vvusZjQTjOlseUkd3Xu/3dPzusC/22wtu2wRn+jG5So/OCDh8ycMJDflehMlkJkVK7KUYN+ufzA/RttH76zaVocDptRxzQtNi3mRWuPc+6cKtlXZ/sddP2uu9uXlmYXZ6Qm8v4Tz8lhF1H+zDQXt7S8oLMXtbF4e8QaFHjj3kbP2MzkktHpiTjp9VH6iHiA+whtAsX5brpwueMGdONdf/2A4M7ukDs1JW662+XkqTkeUoqjKtOjm2h53YFL15pSJ04Zc94wdtibr26fXlC2mzRvBccEbz2kiRFD414tKMlEZbVGT33+qCoHgha81SWYsew0r1uzfNylmtpx80pngQQ91LwVk2JGvGnfvZG6YcYRAT16GFtW5kKKfo1EQLtfh5Q2etT0BIWF+aitq4fDbk+ImYo1OxvGF03waFJQvBCkvDffRyEtxQiFFYgAZTHS0zwAGD7fG5TNnYNTp8/FzvGwJOfmgG7GOx0SAKKgQgDMgKBI0NJGMEImpGDk5+WACEwEd0ywblhGUZ4Hw5OdUekRBLT7DTgdEgxACsIznx8zpmWh7k4rkpJcuHDxCul6MDsmmBXDlWCH2+XozSgBnzsNCEE4euYV4pwCpsWYPW0UHDYBKSWu1NYjENDReqtKjwn2+zvtTc1vMSTB/mvev/WEYSlASsLimcOhOBJxw+N3aP/SjefNL5GePZmpu4kG7OPr1+tOfPyUu3BecWYKcwQcDFmwFKAUo90fhKDInBCAmvqnyMgqUEagQwCoHBDc1rjv9pIlD8IbVkz6qYViIBQGTJPx4k0XpIgEZoRN1Da0cij4VfR0ta3WvBXH/rjdCufv6R2zPgPH/e4pxSBCpeatqPrjNiso203/5s/zA171Mv8+w1LOAAAAAElFTkSuQmCC">
+<img class="intLink" title="Undo" onclick="formatDoc('undo');" src="data:image/gif;base64,R0lGODlhFgAWAOMKADljwliE33mOrpGjuYKl8aezxqPD+7/I19DV3NHa7P///////////////////////yH5BAEKAA8ALAAAAAAWABYAAARR8MlJq7046807TkaYeJJBnES4EeUJvIGapWYAC0CsocQ7SDlWJkAkCA6ToMYWIARGQF3mRQVIEjkkSVLIbSfEwhdRIH4fh/DZMICe3/C4nBQBADs=" />
+<img class="intLink" title="Redo" onclick="formatDoc('redo');" src="data:image/gif;base64,R0lGODlhFgAWAMIHAB1ChDljwl9vj1iE34Kl8aPD+7/I1////yH5BAEKAAcALAAAAAAWABYAAANKeLrc/jDKSesyphi7SiEgsVXZEATDICqBVJjpqWZt9NaEDNbQK1wCQsxlYnxMAImhyDoFAElJasRRvAZVRqqQXUy7Cgx4TC6bswkAOw==" />
+<img class="intLink" title="Remove formatting" onclick="formatDoc('removeFormat')" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABYAAAAWCAYAAADEtGw7AAAABGdBTUEAALGPC/xhBQAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlzAAAOxAAADsQBlSsOGwAAAAd0SU1FB9oECQMCKPI8CIIAAAAIdEVYdENvbW1lbnQA9syWvwAAAuhJREFUOMtjYBgFxAB501ZWBvVaL2nHnlmk6mXCJbF69zU+Hz/9fB5O1lx+bg45qhl8/fYr5it3XrP/YWTUvvvk3VeqGXz70TvbJy8+Wv39+2/Hz19/mGwjZzuTYjALuoBv9jImaXHeyD3H7kU8fPj2ICML8z92dlbtMzdeiG3fco7J08foH1kurkm3E9iw54YvKwuTuom+LPt/BgbWf3//sf37/1/c02cCG1lB8f//f95DZx74MTMzshhoSm6szrQ/a6Ir/Z2RkfEjBxuLYFpDiDi6Af///2ckaHBp7+7wmavP5n76+P2ClrLIYl8H9W36auJCbCxM4szMTJac7Kza////R3H1w2cfWAgafPbqs5g7D95++/P1B4+ECK8tAwMDw/1H7159+/7r7ZcvPz4fOHbzEwMDwx8GBgaGnNatfHZx8zqrJ+4VJBh5CQEGOySEua/v3n7hXmqI8WUGBgYGL3vVG7fuPK3i5GD9/fja7ZsMDAzMG/Ze52mZeSj4yu1XEq/ff7W5dvfVAS1lsXc4Db7z8C3r8p7Qjf///2dnZGxlqJuyr3rPqQd/Hhyu7oSpYWScylDQsd3kzvnH738wMDzj5GBN1VIWW4c3KDon7VOvm7S3paB9u5qsU5/x5KUnlY+eexQbkLNsErK61+++VnAJcfkyMTIwffj0QwZbJDKjcETs1Y8evyd48toz8y/ffzv//vPP4veffxpX77z6l5JewHPu8MqTDAwMDLzyrjb/mZm0JcT5Lj+89+Ybm6zz95oMh7s4XbygN3Sluq4Mj5K8iKMgP4f0////fv77//8nLy+7MCcXmyYDAwODS9jM9tcvPypd35pne3ljdjvj26+H2dhYpuENikgfvQeXNmSl3tqepxXsqhXPyc666s+fv1fMdKR3TK72zpix8nTc7bdfhfkEeVbC9KhbK/9iYWHiErbu6MWbY/7//8/4//9/pgOnH6jGVazvFDRtq2VgiBIZrUTIBgCk+ivHvuEKwAAAAABJRU5ErkJggg==">
+<img class="intLink" title="Bold" onclick="formatDoc('bold');" src="data:image/gif;base64,R0lGODlhFgAWAID/AMDAwAAAACH5BAEAAAAALAAAAAAWABYAQAInhI+pa+H9mJy0LhdgtrxzDG5WGFVk6aXqyk6Y9kXvKKNuLbb6zgMFADs=" />
+<img class="intLink" title="Italic" onclick="formatDoc('italic');" src="data:image/gif;base64,R0lGODlhFgAWAKEDAAAAAF9vj5WIbf///yH5BAEAAAMALAAAAAAWABYAAAIjnI+py+0Po5x0gXvruEKHrF2BB1YiCWgbMFIYpsbyTNd2UwAAOw==" />
+<img class="intLink" title="Underline" onclick="formatDoc('underline');" src="data:image/gif;base64,R0lGODlhFgAWAKECAAAAAF9vj////////yH5BAEAAAIALAAAAAAWABYAAAIrlI+py+0Po5zUgAsEzvEeL4Ea15EiJJ5PSqJmuwKBEKgxVuXWtun+DwxCCgA7" />
+<img class="intLink" title="Left align" onclick="formatDoc('justifyleft');" src="data:image/gif;base64,R0lGODlhFgAWAID/AMDAwAAAACH5BAEAAAAALAAAAAAWABYAQAIghI+py+0Po5y02ouz3jL4D4JMGELkGYxo+qzl4nKyXAAAOw==" />
+<img class="intLink" title="Center align" onclick="formatDoc('justifycenter');" src="data:image/gif;base64,R0lGODlhFgAWAID/AMDAwAAAACH5BAEAAAAALAAAAAAWABYAQAIfhI+py+0Po5y02ouz3jL4D4JOGI7kaZ5Bqn4sycVbAQA7" />
+<img class="intLink" title="Right align" onclick="formatDoc('justifyright');" src="data:image/gif;base64,R0lGODlhFgAWAID/AMDAwAAAACH5BAEAAAAALAAAAAAWABYAQAIghI+py+0Po5y02ouz3jL4D4JQGDLkGYxouqzl43JyVgAAOw==" />
+<img class="intLink" title="Numbered list" onclick="formatDoc('insertorderedlist');" src="data:image/gif;base64,R0lGODlhFgAWAMIGAAAAADljwliE35GjuaezxtHa7P///////yH5BAEAAAcALAAAAAAWABYAAAM2eLrc/jDKSespwjoRFvggCBUBoTFBeq6QIAysQnRHaEOzyaZ07Lu9lUBnC0UGQU1K52s6n5oEADs=" />
+<img class="intLink" title="Dotted list" onclick="formatDoc('insertunorderedlist');" src="data:image/gif;base64,R0lGODlhFgAWAMIGAAAAAB1ChF9vj1iE33mOrqezxv///////yH5BAEAAAcALAAAAAAWABYAAAMyeLrc/jDKSesppNhGRlBAKIZRERBbqm6YtnbfMY7lud64UwiuKnigGQliQuWOyKQykgAAOw==" />
+<img class="intLink" title="Quote" onclick="formatDoc('formatblock','&lt;blockquote&gt;');" src="data:image/gif;base64,R0lGODlhFgAWAIQXAC1NqjFRjkBgmT9nqUJnsk9xrFJ7u2R9qmKBt1iGzHmOrm6Sz4OXw3Odz4Cl2ZSnw6KxyqO306K63bG70bTB0rDI3bvI4P///////////////////////////////////yH5BAEKAB8ALAAAAAAWABYAAAVP4CeOZGmeaKqubEs2CekkErvEI1zZuOgYFlakECEZFi0GgTGKEBATFmJAVXweVOoKEQgABB9IQDCmrLpjETrQQlhHjINrTq/b7/i8fp8PAQA7" />
+<img class="intLink" title="Add indentation" onclick="formatDoc('outdent');" src="data:image/gif;base64,R0lGODlhFgAWAMIHAAAAADljwliE35GjuaezxtDV3NHa7P///yH5BAEAAAcALAAAAAAWABYAAAM2eLrc/jDKCQG9F2i7u8agQgyK1z2EIBil+TWqEMxhMczsYVJ3e4ahk+sFnAgtxSQDqWw6n5cEADs=" />
+<img class="intLink" title="Delete indentation" onclick="formatDoc('indent');" src="data:image/gif;base64,R0lGODlhFgAWAOMIAAAAADljwl9vj1iE35GjuaezxtDV3NHa7P///////////////////////////////yH5BAEAAAgALAAAAAAWABYAAAQ7EMlJq704650B/x8gemMpgugwHJNZXodKsO5oqUOgo5KhBwWESyMQsCRDHu9VOyk5TM9zSpFSr9gsJwIAOw==" />
+<img class="intLink" title="Hyperlink" onclick="var sLnk=prompt('Inserire l'URL','http://');if(sLnk&&sLnk!=''&&sLnk!='http://'){formatDoc('createlink',sLnk)}" src="data:image/gif;base64,R0lGODlhFgAWAOMKAB1ChDRLY19vj3mOrpGjuaezxrCztb/I19Ha7Pv8/f///////////////////////yH5BAEKAA8ALAAAAAAWABYAAARY8MlJq7046827/2BYIQVhHg9pEgVGIklyDEUBy/RlE4FQF4dCj2AQXAiJQDCWQCAEBwIioEMQBgSAFhDAGghGi9XgHAhMNoSZgJkJei33UESv2+/4vD4TAQA7" />
+<img class="intLink" title="Cut" onclick="formatDoc('cut');" src="data:image/gif;base64,R0lGODlhFgAWAIQSAB1ChBFNsRJTySJYwjljwkxwl19vj1dusYODhl6MnHmOrpqbmpGjuaezxrCztcDCxL/I18rL1P///////////////////////////////////////////////////////yH5BAEAAB8ALAAAAAAWABYAAAVu4CeOZGmeaKqubDs6TNnEbGNApNG0kbGMi5trwcA9GArXh+FAfBAw5UexUDAQESkRsfhJPwaH4YsEGAAJGisRGAQY7UCC9ZAXBB+74LGCRxIEHwAHdWooDgGJcwpxDisQBQRjIgkDCVlfmZqbmiEAOw==" />
+<img class="intLink" title="Copy" onclick="formatDoc('copy');" src="data:image/gif;base64,R0lGODlhFgAWAIQcAB1ChBFNsTRLYyJYwjljwl9vj1iE31iGzF6MnHWX9HOdz5GjuYCl2YKl8ZOt4qezxqK63aK/9KPD+7DI3b/I17LM/MrL1MLY9NHa7OPs++bx/Pv8/f///////////////yH5BAEAAB8ALAAAAAAWABYAAAWG4CeOZGmeaKqubOum1SQ/kPVOW749BeVSus2CgrCxHptLBbOQxCSNCCaF1GUqwQbBd0JGJAyGJJiobE+LnCaDcXAaEoxhQACgNw0FQx9kP+wmaRgYFBQNeAoGihCAJQsCkJAKOhgXEw8BLQYciooHf5o7EA+kC40qBKkAAAGrpy+wsbKzIiEAOw==" />
+<img class="intLink" title="Paste" onclick="formatDoc('paste');" src="data:image/gif;base64,R0lGODlhFgAWAIQUAD04KTRLY2tXQF9vj414WZWIbXmOrpqbmpGjudClFaezxsa0cb/I1+3YitHa7PrkIPHvbuPs+/fvrvv8/f///////////////////////////////////////////////yH5BAEAAB8ALAAAAAAWABYAAAWN4CeOZGmeaKqubGsusPvBSyFJjVDs6nJLB0khR4AkBCmfsCGBQAoCwjF5gwquVykSFbwZE+AwIBV0GhFog2EwIDchjwRiQo9E2Fx4XD5R+B0DDAEnBXBhBhN2DgwDAQFjJYVhCQYRfgoIDGiQJAWTCQMRiwwMfgicnVcAAAMOaK+bLAOrtLUyt7i5uiUhADs=" />
+</div>
+<div id="textBox" contenteditable="true"><p>Lorem ipsum</p></div>
+<p id="editMode"><input type="checkbox" name="switchMode" id="switchBox" onchange="setDocMode(this.checked);" /> <label for="switchBox">Show HTML</label></p>
+<p><input type="submit" value="Send" /></p>
+</form>
+</body>
+</html>

+ 297 - 0
ourbiz/s/ourbiz/entities.js

@@ -0,0 +1,297 @@
+Jaml.register('EntityEditWindow', function(args) {
+	form({action: "/DB/Action", method: "post", onsubmit:"return false;",
+			id: args.form_id, style: "width:100%;height:100%;"}, 
+		table({style: "width:100%;height:100%;", cls: "editForm"},
+			tr(
+				td({style: "height:12px;"},
+					table({style: "width:100%;"},
+						tr(
+							td({style: "width:1%;"},input({type: "text", name: "e_id", size: 8})),
+							td(input({type: "text", name: "e_name", style: "width:99%;"})),
+							td({style: "width:1%;"},input({type: "text", name: "e_mdate", size: 9}))
+						)
+					)
+				)
+			),
+			tr({id: args.main_tabs_id, 'class':"tabs"},
+				td(
+					button({name:"tab_main" + args.id}, _tr('Main')),
+					button({name:"tab_totals" + args.id}, _tr('Totals')),
+					button({name:"tab_statistics" + args.id}, _tr('Statistics')),
+					button({name:"tab_history" + args.id}, _tr('History')),
+					button({name:"tab_reports" + args.id}, _tr('Reports'))
+				)
+			),
+			tr({id:"tab_main" + args.id, 'class':"tabContent"},
+				td(
+					table({style: "width:100%;"},
+						tbody({cls:"firstRight"},
+							tr({cls:"fcr"},
+								td(_tr("Name")),
+								td({colspan:4},input({type: "text", name: "e_name", cls: "fw"}))
+							),
+							tr({cls:"fcr"},
+								td(_tr("Company")),
+								td({colspan:4},input({type: "text", name: "e_company", cls: "fw"}))
+							),
+							tr({cls:"fcr"},
+								td(_tr("Adderss")),
+								td({colspan:4},input({type: "text", name: "e_address", cls: "fw"}))
+							),
+							tr({cls:"fcr"},
+								td(_tr("ZIP")),
+								td(input({type: "text", name: "e_zip"})),
+								td( _tr("City")),
+								td({colspan:2},
+									input({type: "text", name: "e_city", cls:"fw"}))
+							),
+							tr({cls:"fcr"},
+								td(_tr("State")),
+								td({colspan:2}, input({type: "text", name: "e_state"})),
+								td(_tr("Country")),
+								td(input({type: "text", name: "e_country", style: "width:98%;"}))
+							),
+							tr({cls:"fcr"},
+								td(_tr("Tax Nº")),
+								td(input({type: "text", name: "e_tax_number"})),
+								td({colspan:2},
+									input({type: "checkbox", name: "e_show_on_sales"}),_tr("Sales"),
+									input({type: "checkbox", name: "e_show_on_buys"}),_tr("Buys")
+								),
+								td(input({type: "checkbox", name: "e_is_active"}),_tr("Active"))
+							),
+							tr({cls:"fcr"},
+								td(_tr("Phone")),
+								td(input({type: "text", name: "e_phone"})),
+								td(_tr("Fax")),
+								td(input({type: "text", name: "e_fax"})),
+								td({style: "white-space: nowrap;", colspan:2},
+									input({type: "checkbox", name: "e_use_sales_tax2"}),_tr("Use Sales Tax2"))
+							),
+							tr({cls:"fcr"},
+								td(_tr("Email")),
+								td({colspan:3},input({type: "text", name: "e_email", cls: "fw"})),
+								td(input({type: "checkbox", name: "e_sales_tax_exempt"}),_tr("Sales Tax Exempt"))
+							),
+							tr({cls:"fcr"},
+								td(_tr("Web")),
+								td({colspan:2},input({type: "text", name: "e_web", cls: "fw"})),
+								td({colspan:2},_tr("GPS"), input({type: "text", name: "e_gps_coordinates"}))
+							),
+							tr({cls:"fcr"},
+								td(_tr("Contact")),
+								td({colspan:4},input({type: "text", name: "e_contact", cls: "fw"}))
+							)
+						),
+						tbody(
+							tr({id:args.notes_tabs_id, 'class':"tabs"},
+								td({colspan:4},
+									button({name:"tab_notes" + args.id}, _tr('Notes')),
+									button({name:"tab_tags" + args.id}, _tr('Tags')),
+									button({name:"tab_groups" + args.id}, _tr('Groups'))
+								),
+								td(
+									Jaml.render('ActionSelect', args),
+									input({id: args.btnAction_id, type: "button", name: "btnAction", value: _tr("Action")})
+								)
+							),
+							tr({id:"tab_notes" + args.id, 'class':"tabContent"},
+								td({colspan:5},textarea({rows: 5, name: "e_notes", cls: "fw"}))
+							),
+							tr({id:"tab_tags" + args.id, 'class':"tabContent"},
+								td({colspan:5},textarea({rows: 5, name: "e_tags", cls: "fw"}))
+							),
+							tr({id:"tab_groups" + args.id, 'class':"tabContent"},
+								td({colspan:5},textarea({rows: 5, name: "e_notes", cls: "fw"}))
+							)
+						)
+					)
+				)
+			),
+			tr({id:"tab_totals" + args.id, 'class':"tabTotals"},
+				td({style:"height:100%;"},
+					table(
+						tr(
+							td(_tr("Credit")),
+							td({colspan:3}, input({type: "text", name: "e_credit_allowed", cls: "vright"}))
+						),
+						tr(
+							td(_tr("Balance")),
+							td({colspan:3}, input({type: "text", name: "e_balance", cls: "vright"}))
+						),
+						tr(
+							td(_tr("Sales Quoted")),
+							td(input({type: "text", name: "e_sales_quoted", cls: "vright"})),
+							td(_tr("Buys Quoted")),
+							td(input({type: "text", name: "e_buys_quoted", cls: "vright"}))
+						),
+						tr(
+							td(_tr("Sales Ordered")),
+							td(input({type: "text", name: "e_sales_ordered", cls: "vright"})),
+							td(_tr("Buys Ordered")),
+							td(input({type: "text", name: "e_buys_ordered", cls: "vright"}))
+						),
+						tr(
+							td(_tr("Sales Delivered")),
+							td(input({type: "text", name: "e_sales_delivered", cls: "vright"})),
+							td(_tr("Buys Delivered")),
+							td(input({type: "text", name: "e_buys_received", cls: "vright"}))
+						),
+						tr(
+							td(_tr("Sales Invoiced")),
+							td(input({type: "text", name: "e_sales_invoiced", cls: "vright"})),
+							td(_tr("Buys Invoiced")),
+							td(input({type: "text", name: "e_buys_invoiced", cls: "vright"}))
+						),
+						tr(
+							td(_tr("Sales Paid")),
+							td(input({type: "text", name: "e_sales_paid", cls: "vright"})),
+							td(_tr("Buys Paid")),
+							td(input({type: "text", name: "e_buys_paid", cls: "vright"}))
+						)
+					)
+				)
+			),
+			tr({id:"tab_statistics" + args.id, 'class':"tabContent"},
+				td({style:"height:100%;"},
+					Jaml.render('StatisticsTabContent', args)
+				)
+			),
+			tr({id:"tab_history" + args.id, 'class':"tabContent"},
+				td({style:"height:100%;"},
+					Jaml.render('HistoryTabContent', args)
+				)
+			),
+			tr({id:"tab_reports" + args.id, 'class':"tabContent"},
+				td({style:"height:100%;"},
+					button({id:"rptEntitiesList" + args.id}, _tr('Entities List'))
+				)
+			)
+		)
+	);
+});
+
+function EntityEditWindowRefresh(ajax) {
+}
+
+function showEntityEditWindow(all_sales_buys, caller, id){
+	var win = newEntityEditWindow(all_sales_buys);
+	win.ud.caller = caller;
+	win.ud.edit_id = id;
+	var ajax = win.ud.ajaxLoad;
+	if(ajax){
+		ajax.post("/DB/GetOne", "entities=" + id, 'GET', null);
+	}
+}
+
+function EntityEditWindowOnSubmit(btn) {
+	return dad.formOnSubmit(EntityEditWindowRefresh, this.form, "entities")
+}
+
+function EntityEditWindowOnFillForm(form_field, value) {
+	if(form_field.name == "entity_type"){
+		var options = form_field.options;
+		for(var i=0; i < options.length; i++){
+			if(value == options[i].value) {
+				form_field.selectedIndex = i;
+				break;
+			}
+		}
+		return true;
+	}
+	return false;
+}
+
+Jaml.register('EntitiesHistoryOptions', function(args) {
+	option({value:""}, "----");
+	option(_tr("Sales by Date"));
+	option(_tr("Sales by Amount"));
+	option(_tr("Products Bought"));
+	option(_tr("Products Bought by Value"));
+	option(_tr("Products Bought by Quantity"));
+});
+
+function newEntityEditWindow(all_sales_buys){
+	var title = dad._getSABTitle(all_sales_buys, 'Entity Edit');
+
+	var win = dad._windows[title];
+	if(!win){
+		var newId = dad.newSeqId();
+		var Action_id = 'Action' + newId;
+		var btnAction_id = 'btnAction' + newId;
+		var table_history_id = 'table_history' + newId;
+		var table_history_header_id = 'table_history_header' + newId;
+		var main_tabs_id = 'main_tabs' + newId;
+		var notes_tabs_id = 'notes_tabs' + newId;
+		var data = {
+			id: newId,
+			main_tabs_id: main_tabs_id,
+			notes_tabs_id: notes_tabs_id,
+			form_id: 'form' + newId,
+			Action_id: Action_id,
+			btnAction_id: btnAction_id,
+			table_history_id: table_history_id,
+			table_history_header_id: table_history_header_id,
+			history_options: Jaml.render('EntitiesHistoryOptions', data)
+		}
+		var win = dad.newWindow(newId,220,20, 800, 500, _tr(title), Jaml.render('EntityEditWindow', data));
+		//dad.setContentOverflow(newId);
+		dad.initTab($(main_tabs_id));
+		dad.initTab($(notes_tabs_id));
+		win.ud.ajaxLoad = new dad.Ajax(dad.formAjaxLoadResponse, newId, false);
+
+		var choiceHistory = $('history_type_id' + newId);
+		choiceHistory.ajaxLoadHistory = dad.newAjaxDataTableAjax(win, 
+				{id:newId, table:table_history_id, table_header:table_history_header_id});
+		choiceHistory.onchange = function(){
+			if(!this.selectedIndex) return;
+			this.ajaxLoadHistory._withHeaders = true;
+			this.ajaxLoadHistory.post('/DB/GetList', 'list=entities&history=' + 
+					win.ud.edit_id + '&htype=' + this.selectedIndex +
+					'&query_limit=' + this.form.history_query_limit.value, "GET");
+		}
+
+		dad.setupBarchart(newId, function(){
+			return 'list=entities&statistics=' + win.ud.edit_id + '&sab=' + win.ud.sab;
+		});
+		
+		var myform = $(data.form_id);
+		myform.my_field_prefix = "e_";
+		myform.onFillForm = EntityEditWindowOnFillForm;
+		dad.setupEditForm(myform);
+		myform.ajaxSubmit = new dad.Ajax(dad.listEditWindowOnSubmitRespose, newId, false);
+		
+		var btnRptEntitiesList = $("rptEntitiesList" + newId);
+		btnRptEntitiesList.onclick = function(){
+			var url = '/DB/GetList?list=entities&pdf=1';
+			window.open(url, "printPDF");
+		}
+		var btn = $(btnAction_id);
+		btn.onclick = EntityEditWindowOnSubmit;
+	}
+	
+	dad.bringToFront(win)
+	return win;
+}
+
+Jaml.register('EntitiesListSearchOn', function(args) {
+	input({type: "radio", name: "search_on", id: "by_name" + args.id, value: "name", checked:1 }),
+	label({'for': "by_name" + args.id},  _tr("Name")),
+	input({type: "radio", name: "search_on", id: "by_notes" + args.id, value: "notes"}),
+	label({'for': "by_notes" + args.id},  _tr("Notes")),
+	input({type: "radio", name: "search_on", id: "by_products" + args.id, value: "products"}),
+	label({'for': "by_products" + args.id},  _tr("Products")),
+	input({type: "radio", name: "search_on", id: "by_id" + args.id, value: "id"}),
+	label({'for': "by_id" + args.id},  _tr("ID"))
+});
+
+function newEntitiesListSearchWindow(all_sales_buys){
+	var colHeaders = ["id|ID|6|R",
+                "name|Name|-1",
+                "contact|Contact|12",
+                "phone|Phone|12",
+                "is_active|Active|0"];
+	var title = dad._getSABTitle(all_sales_buys, 'Entities List/Search');
+	return newListSearchWindow(all_sales_buys, title, colHeaders, showEntityEditWindow,
+		"entities", 'EntitiesListSearchOn', null, all_sales_buys);
+}

+ 114 - 0
ourbiz/s/ourbiz/etnetstrings.js

@@ -0,0 +1,114 @@
+var etnetstrings = (function () {
+
+	this.parse = function(data) {
+		return this.parsePrivate(data, false, 0, []);
+	}
+	
+    this.parsePrivate = function(data, expected, offset, outArray) {
+        var result;
+
+        var idx = -1;
+		var max_len = data.length - offset;
+		//9 is maximun integer digits allowed
+		if(max_len > 12) max_len = 12;
+		var slen = data.substring(offset, offset+max_len);
+		slen = slen.match(/^\d+/);
+		if(!slen) throw 'missing or invalid length header';
+
+        var blob_length = slen[0];
+		var type_pos = blob_length.length+offset;
+		blob_length |= 0;
+		var blob_type = data.charAt(type_pos);
+		var blob_begin = type_pos + 1;
+		var blob_end = type_pos + blob_length;
+
+		if(expected && (expected != blob_type)) 
+			throw 'type did not match expected';
+
+        if(blob_type == ':'){
+            result = data.substring(blob_begin, blob_end+1)
+        } else if(blob_type == '#'){
+			var str = data.substring(blob_begin, blob_end+1)
+            result = parseFloat(str, 10);
+        } else if(blob_type == '!'){
+            result = data.charAt(blob_begin) == '1';
+        } else if(blob_type == '~'){
+            if (blob_length != 0)
+                throw "Payload must be 0 length for null.";
+            result = null;
+        } else if(blob_type == '{'){
+			result = {};
+			if (blob_length > 0) {
+				var p = [blob_begin];
+				var key;
+				for(var i=0; i < blob_length; i++) {
+					key = this.parsePrivate(data, ':', p[0], p);
+					value = this.parsePrivate(data, false, p[0], p);
+					result[key] = value;
+				}
+				blob_end = p[0]-1;
+			}
+        } else if(blob_type == '['){
+			result = [];
+			if (blob_length > 0) {
+				var p = [blob_begin];
+				var value;
+				for(var i=0; i < blob_length; i++) {
+					value = this.parsePrivate(data, false, p[0], p);
+					result[result.length] = value;
+				}
+				blob_end = p[0]-1
+			}
+        } else {
+            throw "Invalid blob type: " + blob_type;
+        }
+		if(data.charAt(blob_end+1) != ',') throw 'invalid end mark ';
+		outArray[0] = blob_end+2;
+        return result;
+    }
+
+    this.dump = function(data) {
+        var otype = typeof data;
+        
+		if(otype == 'string'){
+            return data.length + ':' + data + ',';
+        } else if(otype == 'number'){
+            // return null for infinite numbers
+            if (!isFinite(data)) output.append('0~,');
+            var str = data.toString();
+			return str.length + '#' + str + ',';
+        } else if(otype == 'boolean'){
+            if(data) return '1!1,';
+			else return '1!0,';
+        } else if(otype == 'object'){
+            // object in js could be dict, list, null
+			var i, type, result = [], count = 0;
+			if (data === null) {
+				return '0~,';
+			}
+			else if (data.length) {
+				count = data.length;
+				tmp_output = count + '[';
+				for (i = 0; i < count; i++) {
+					tmp_output += dump(data[i]);
+				}
+				return tmp_output + ',';
+			} else {
+				count = 0;
+				tmp_output = "";
+				for (i in data) {
+					if (data[i]) {
+						tmp_output += dump(i);
+						tmp_output += dump(data[i]);
+						count++;
+					}
+				}
+				return count + '{' + tmp_output + ',';
+			}
+        } else {
+            throw "Invalid blob type: " + otype;
+        }
+    }
+	
+    return this;
+})();

+ 1416 - 0
ourbiz/s/ourbiz/excanvas.js

@@ -0,0 +1,1416 @@
+// Copyright 2006 Google Inc.
+//
+// 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.
+
+
+// Known Issues:
+//
+// * Patterns only support repeat.
+// * Radial gradient are not implemented. The VML version of these look very
+//   different from the canvas one.
+// * Clipping paths are not implemented.
+// * Coordsize. The width and height attribute have higher priority than the
+//   width and height style values which isn't correct.
+// * Painting mode isn't implemented.
+// * Canvas width/height should is using content-box by default. IE in
+//   Quirks mode will draw the canvas using border-box. Either change your
+//   doctype to HTML5
+//   (http://www.whatwg.org/specs/web-apps/current-work/#the-doctype)
+//   or use Box Sizing Behavior from WebFX
+//   (http://webfx.eae.net/dhtml/boxsizing/boxsizing.html)
+// * Non uniform scaling does not correctly scale strokes.
+// * Optimize. There is always room for speed improvements.
+
+// Only add this code if we do not already have a canvas implementation
+if (!document.createElement('canvas').getContext) {
+
+(function() {
+
+  // alias some functions to make (compiled) code shorter
+  var m = Math;
+  var mr = m.round;
+  var ms = m.sin;
+  var mc = m.cos;
+  var abs = m.abs;
+  var sqrt = m.sqrt;
+
+  // this is used for sub pixel precision
+  var Z = 10;
+  var Z2 = Z / 2;
+
+  var IE_VERSION = +navigator.userAgent.match(/MSIE ([\d.]+)?/)[1];
+
+  /**
+   * This funtion is assigned to the <canvas> elements as element.getContext().
+   * @this {HTMLElement}
+   * @return {CanvasRenderingContext2D_}
+   */
+  function getContext() {
+    return this.context_ ||
+        (this.context_ = new CanvasRenderingContext2D_(this));
+  }
+
+  var slice = Array.prototype.slice;
+
+  /**
+   * Binds a function to an object. The returned function will always use the
+   * passed in {@code obj} as {@code this}.
+   *
+   * Example:
+   *
+   *   g = bind(f, obj, a, b)
+   *   g(c, d) // will do f.call(obj, a, b, c, d)
+   *
+   * @param {Function} f The function to bind the object to
+   * @param {Object} obj The object that should act as this when the function
+   *     is called
+   * @param {*} var_args Rest arguments that will be used as the initial
+   *     arguments when the function is called
+   * @return {Function} A new function that has bound this
+   */
+  function bind(f, obj, var_args) {
+    var a = slice.call(arguments, 2);
+    return function() {
+      return f.apply(obj, a.concat(slice.call(arguments)));
+    };
+  }
+
+  function encodeHtmlAttribute(s) {
+    return String(s).replace(/&/g, '&amp;').replace(/"/g, '&quot;');
+  }
+
+  function addNamespace(doc, prefix, urn) {
+    if (!doc.namespaces[prefix]) {
+      doc.namespaces.add(prefix, urn, '#default#VML');
+    }
+  }
+
+  function addNamespacesAndStylesheet(doc) {
+    addNamespace(doc, 'g_vml_', 'urn:schemas-microsoft-com:vml');
+    addNamespace(doc, 'g_o_', 'urn:schemas-microsoft-com:office:office');
+
+    // Setup default CSS.  Only add one style sheet per document
+    if (!doc.styleSheets['ex_canvas_']) {
+      var ss = doc.createStyleSheet();
+      ss.owningElement.id = 'ex_canvas_';
+      ss.cssText = 'canvas{display:inline-block;overflow:hidden;' +
+          // default size is 300x150 in Gecko and Opera
+          'text-align:left;width:300px;height:150px}';
+    }
+  }
+
+  // Add namespaces and stylesheet at startup.
+  addNamespacesAndStylesheet(document);
+
+  var G_vmlCanvasManager_ = {
+    init: function(opt_doc) {
+      var doc = opt_doc || document;
+      // Create a dummy element so that IE will allow canvas elements to be
+      // recognized.
+      doc.createElement('canvas');
+      doc.attachEvent('onreadystatechange', bind(this.init_, this, doc));
+    },
+
+    init_: function(doc) {
+      // find all canvas elements
+      var els = doc.getElementsByTagName('canvas');
+      for (var i = 0; i < els.length; i++) {
+        this.initElement(els[i]);
+      }
+    },
+
+    /**
+     * Public initializes a canvas element so that it can be used as canvas
+     * element from now on. This is called automatically before the page is
+     * loaded but if you are creating elements using createElement you need to
+     * make sure this is called on the element.
+     * @param {HTMLElement} el The canvas element to initialize.
+     * @return {HTMLElement} the element that was created.
+     */
+    initElement: function(el) {
+      if (!el.getContext) {
+        el.getContext = getContext;
+
+        // Add namespaces and stylesheet to document of the element.
+        addNamespacesAndStylesheet(el.ownerDocument);
+
+        // Remove fallback content. There is no way to hide text nodes so we
+        // just remove all childNodes. We could hide all elements and remove
+        // text nodes but who really cares about the fallback content.
+        el.innerHTML = '';
+
+        // do not use inline function because that will leak memory
+        el.attachEvent('onpropertychange', onPropertyChange);
+        el.attachEvent('onresize', onResize);
+
+        var attrs = el.attributes;
+        if (attrs.width && attrs.width.specified) {
+          // TODO: use runtimeStyle and coordsize
+          // el.getContext().setWidth_(attrs.width.nodeValue);
+          el.style.width = attrs.width.nodeValue + 'px';
+        } else {
+          el.width = el.clientWidth;
+        }
+        if (attrs.height && attrs.height.specified) {
+          // TODO: use runtimeStyle and coordsize
+          // el.getContext().setHeight_(attrs.height.nodeValue);
+          el.style.height = attrs.height.nodeValue + 'px';
+        } else {
+          el.height = el.clientHeight;
+        }
+        //el.getContext().setCoordsize_()
+      }
+      return el;
+    }
+  };
+
+  function onPropertyChange(e) {
+    var el = e.srcElement;
+
+    switch (e.propertyName) {
+      case 'width':
+        el.getContext().clearRect();
+        el.style.width = el.attributes.width.nodeValue + 'px';
+        // In IE8 this does not trigger onresize.
+        el.firstChild.style.width =  el.clientWidth + 'px';
+        break;
+      case 'height':
+        el.getContext().clearRect();
+        el.style.height = el.attributes.height.nodeValue + 'px';
+        el.firstChild.style.height = el.clientHeight + 'px';
+        break;
+    }
+  }
+
+  function onResize(e) {
+    var el = e.srcElement;
+    if (el.firstChild) {
+      el.firstChild.style.width =  el.clientWidth + 'px';
+      el.firstChild.style.height = el.clientHeight + 'px';
+    }
+  }
+
+  G_vmlCanvasManager_.init();
+
+  // precompute "00" to "FF"
+  var decToHex = [];
+  for (var i = 0; i < 16; i++) {
+    for (var j = 0; j < 16; j++) {
+      decToHex[i * 16 + j] = i.toString(16) + j.toString(16);
+    }
+  }
+
+  function createMatrixIdentity() {
+    return [
+      [1, 0, 0],
+      [0, 1, 0],
+      [0, 0, 1]
+    ];
+  }
+
+  function matrixMultiply(m1, m2) {
+    var result = createMatrixIdentity();
+
+    for (var x = 0; x < 3; x++) {
+      for (var y = 0; y < 3; y++) {
+        var sum = 0;
+
+        for (var z = 0; z < 3; z++) {
+          sum += m1[x][z] * m2[z][y];
+        }
+
+        result[x][y] = sum;
+      }
+    }
+    return result;
+  }
+
+  function copyState(o1, o2) {
+    o2.fillStyle     = o1.fillStyle;
+    o2.lineCap       = o1.lineCap;
+    o2.lineJoin      = o1.lineJoin;
+    o2.lineWidth     = o1.lineWidth;
+    o2.miterLimit    = o1.miterLimit;
+    o2.shadowBlur    = o1.shadowBlur;
+    o2.shadowColor   = o1.shadowColor;
+    o2.shadowOffsetX = o1.shadowOffsetX;
+    o2.shadowOffsetY = o1.shadowOffsetY;
+    o2.strokeStyle   = o1.strokeStyle;
+    o2.globalAlpha   = o1.globalAlpha;
+    o2.font          = o1.font;
+    o2.textAlign     = o1.textAlign;
+    o2.textBaseline  = o1.textBaseline;
+    o2.arcScaleX_    = o1.arcScaleX_;
+    o2.arcScaleY_    = o1.arcScaleY_;
+    o2.lineScale_    = o1.lineScale_;
+  }
+
+  var colorData = {
+    aliceblue: '#F0F8FF',
+    antiquewhite: '#FAEBD7',
+    aquamarine: '#7FFFD4',
+    azure: '#F0FFFF',
+    beige: '#F5F5DC',
+    bisque: '#FFE4C4',
+    black: '#000000',
+    blanchedalmond: '#FFEBCD',
+    blueviolet: '#8A2BE2',
+    brown: '#A52A2A',
+    burlywood: '#DEB887',
+    cadetblue: '#5F9EA0',
+    chartreuse: '#7FFF00',
+    chocolate: '#D2691E',
+    coral: '#FF7F50',
+    cornflowerblue: '#6495ED',
+    cornsilk: '#FFF8DC',
+    crimson: '#DC143C',
+    cyan: '#00FFFF',
+    darkblue: '#00008B',
+    darkcyan: '#008B8B',
+    darkgoldenrod: '#B8860B',
+    darkgray: '#A9A9A9',
+    darkgreen: '#006400',
+    darkgrey: '#A9A9A9',
+    darkkhaki: '#BDB76B',
+    darkmagenta: '#8B008B',
+    darkolivegreen: '#556B2F',
+    darkorange: '#FF8C00',
+    darkorchid: '#9932CC',
+    darkred: '#8B0000',
+    darksalmon: '#E9967A',
+    darkseagreen: '#8FBC8F',
+    darkslateblue: '#483D8B',
+    darkslategray: '#2F4F4F',
+    darkslategrey: '#2F4F4F',
+    darkturquoise: '#00CED1',
+    darkviolet: '#9400D3',
+    deeppink: '#FF1493',
+    deepskyblue: '#00BFFF',
+    dimgray: '#696969',
+    dimgrey: '#696969',
+    dodgerblue: '#1E90FF',
+    firebrick: '#B22222',
+    floralwhite: '#FFFAF0',
+    forestgreen: '#228B22',
+    gainsboro: '#DCDCDC',
+    ghostwhite: '#F8F8FF',
+    gold: '#FFD700',
+    goldenrod: '#DAA520',
+    grey: '#808080',
+    greenyellow: '#ADFF2F',
+    honeydew: '#F0FFF0',
+    hotpink: '#FF69B4',
+    indianred: '#CD5C5C',
+    indigo: '#4B0082',
+    ivory: '#FFFFF0',
+    khaki: '#F0E68C',
+    lavender: '#E6E6FA',
+    lavenderblush: '#FFF0F5',
+    lawngreen: '#7CFC00',
+    lemonchiffon: '#FFFACD',
+    lightblue: '#ADD8E6',
+    lightcoral: '#F08080',
+    lightcyan: '#E0FFFF',
+    lightgoldenrodyellow: '#FAFAD2',
+    lightgreen: '#90EE90',
+    lightgrey: '#D3D3D3',
+    lightpink: '#FFB6C1',
+    lightsalmon: '#FFA07A',
+    lightseagreen: '#20B2AA',
+    lightskyblue: '#87CEFA',
+    lightslategray: '#778899',
+    lightslategrey: '#778899',
+    lightsteelblue: '#B0C4DE',
+    lightyellow: '#FFFFE0',
+    limegreen: '#32CD32',
+    linen: '#FAF0E6',
+    magenta: '#FF00FF',
+    mediumaquamarine: '#66CDAA',
+    mediumblue: '#0000CD',
+    mediumorchid: '#BA55D3',
+    mediumpurple: '#9370DB',
+    mediumseagreen: '#3CB371',
+    mediumslateblue: '#7B68EE',
+    mediumspringgreen: '#00FA9A',
+    mediumturquoise: '#48D1CC',
+    mediumvioletred: '#C71585',
+    midnightblue: '#191970',
+    mintcream: '#F5FFFA',
+    mistyrose: '#FFE4E1',
+    moccasin: '#FFE4B5',
+    navajowhite: '#FFDEAD',
+    oldlace: '#FDF5E6',
+    olivedrab: '#6B8E23',
+    orange: '#FFA500',
+    orangered: '#FF4500',
+    orchid: '#DA70D6',
+    palegoldenrod: '#EEE8AA',
+    palegreen: '#98FB98',
+    paleturquoise: '#AFEEEE',
+    palevioletred: '#DB7093',
+    papayawhip: '#FFEFD5',
+    peachpuff: '#FFDAB9',
+    peru: '#CD853F',
+    pink: '#FFC0CB',
+    plum: '#DDA0DD',
+    powderblue: '#B0E0E6',
+    rosybrown: '#BC8F8F',
+    royalblue: '#4169E1',
+    saddlebrown: '#8B4513',
+    salmon: '#FA8072',
+    sandybrown: '#F4A460',
+    seagreen: '#2E8B57',
+    seashell: '#FFF5EE',
+    sienna: '#A0522D',
+    skyblue: '#87CEEB',
+    slateblue: '#6A5ACD',
+    slategray: '#708090',
+    slategrey: '#708090',
+    snow: '#FFFAFA',
+    springgreen: '#00FF7F',
+    steelblue: '#4682B4',
+    tan: '#D2B48C',
+    thistle: '#D8BFD8',
+    tomato: '#FF6347',
+    turquoise: '#40E0D0',
+    violet: '#EE82EE',
+    wheat: '#F5DEB3',
+    whitesmoke: '#F5F5F5',
+    yellowgreen: '#9ACD32'
+  };
+
+
+  function getRgbHslContent(styleString) {
+    var start = styleString.indexOf('(', 3);
+    var end = styleString.indexOf(')', start + 1);
+    var parts = styleString.substring(start + 1, end).split(',');
+    // add alpha if needed
+    if (parts.length != 4 || styleString.charAt(3) != 'a') {
+      parts[3] = 1;
+    }
+    return parts;
+  }
+
+  function percent(s) {
+    return parseFloat(s) / 100;
+  }
+
+  function clamp(v, min, max) {
+    return Math.min(max, Math.max(min, v));
+  }
+
+  function hslToRgb(parts){
+    var r, g, b, h, s, l;
+    h = parseFloat(parts[0]) / 360 % 360;
+    if (h < 0)
+      h++;
+    s = clamp(percent(parts[1]), 0, 1);
+    l = clamp(percent(parts[2]), 0, 1);
+    if (s == 0) {
+      r = g = b = l; // achromatic
+    } else {
+      var q = l < 0.5 ? l * (1 + s) : l + s - l * s;
+      var p = 2 * l - q;
+      r = hueToRgb(p, q, h + 1 / 3);
+      g = hueToRgb(p, q, h);
+      b = hueToRgb(p, q, h - 1 / 3);
+    }
+
+    return '#' + decToHex[Math.floor(r * 255)] +
+        decToHex[Math.floor(g * 255)] +
+        decToHex[Math.floor(b * 255)];
+  }
+
+  function hueToRgb(m1, m2, h) {
+    if (h < 0)
+      h++;
+    if (h > 1)
+      h--;
+
+    if (6 * h < 1)
+      return m1 + (m2 - m1) * 6 * h;
+    else if (2 * h < 1)
+      return m2;
+    else if (3 * h < 2)
+      return m1 + (m2 - m1) * (2 / 3 - h) * 6;
+    else
+      return m1;
+  }
+
+  var processStyleCache = {};
+
+  function processStyle(styleString) {
+    if (styleString in processStyleCache) {
+      return processStyleCache[styleString];
+    }
+
+    var str, alpha = 1;
+
+    styleString = String(styleString);
+    if (styleString.charAt(0) == '#') {
+      str = styleString;
+    } else if (/^rgb/.test(styleString)) {
+      var parts = getRgbHslContent(styleString);
+      var str = '#', n;
+      for (var i = 0; i < 3; i++) {
+        if (parts[i].indexOf('%') != -1) {
+          n = Math.floor(percent(parts[i]) * 255);
+        } else {
+          n = +parts[i];
+        }
+        str += decToHex[clamp(n, 0, 255)];
+      }
+      alpha = +parts[3];
+    } else if (/^hsl/.test(styleString)) {
+      var parts = getRgbHslContent(styleString);
+      str = hslToRgb(parts);
+      alpha = parts[3];
+    } else {
+      str = colorData[styleString] || styleString;
+    }
+    return processStyleCache[styleString] = {color: str, alpha: alpha};
+  }
+
+  var DEFAULT_STYLE = {
+    style: 'normal',
+    variant: 'normal',
+    weight: 'normal',
+    size: 10,
+    family: 'sans-serif'
+  };
+
+  // Internal text style cache
+  var fontStyleCache = {};
+
+  function processFontStyle(styleString) {
+    if (fontStyleCache[styleString]) {
+      return fontStyleCache[styleString];
+    }
+
+    var el = document.createElement('div');
+    var style = el.style;
+    try {
+      style.font = styleString;
+    } catch (ex) {
+      // Ignore failures to set to invalid font.
+    }
+
+    return fontStyleCache[styleString] = {
+      style: style.fontStyle || DEFAULT_STYLE.style,
+      variant: style.fontVariant || DEFAULT_STYLE.variant,
+      weight: style.fontWeight || DEFAULT_STYLE.weight,
+      size: style.fontSize || DEFAULT_STYLE.size,
+      family: style.fontFamily || DEFAULT_STYLE.family
+    };
+  }
+
+  function getComputedStyle(style, element) {
+    var computedStyle = {};
+
+    for (var p in style) {
+      computedStyle[p] = style[p];
+    }
+
+    // Compute the size
+    var canvasFontSize = parseFloat(element.currentStyle.fontSize),
+        fontSize = parseFloat(style.size);
+
+    if (typeof style.size == 'number') {
+      computedStyle.size = style.size;
+    } else if (style.size.indexOf('px') != -1) {
+      computedStyle.size = fontSize;
+    } else if (style.size.indexOf('em') != -1) {
+      computedStyle.size = canvasFontSize * fontSize;
+    } else if(style.size.indexOf('%') != -1) {
+      computedStyle.size = (canvasFontSize / 100) * fontSize;
+    } else if (style.size.indexOf('pt') != -1) {
+      computedStyle.size = fontSize / .75;
+    } else {
+      computedStyle.size = canvasFontSize;
+    }
+
+    // Different scaling between normal text and VML text. This was found using
+    // trial and error to get the same size as non VML text.
+    computedStyle.size *= 0.981;
+
+    return computedStyle;
+  }
+
+  function buildStyle(style) {
+    return style.style + ' ' + style.variant + ' ' + style.weight + ' ' +
+        style.size + 'px ' + style.family;
+  }
+
+  var lineCapMap = {
+    'butt': 'flat',
+    'round': 'round'
+  };
+
+  function processLineCap(lineCap) {
+    return lineCapMap[lineCap] || 'square';
+  }
+
+  /**
+   * This class implements CanvasRenderingContext2D interface as described by
+   * the WHATWG.
+   * @param {HTMLElement} canvasElement The element that the 2D context should
+   * be associated with
+   */
+  function CanvasRenderingContext2D_(canvasElement) {
+    this.m_ = createMatrixIdentity();
+
+    this.mStack_ = [];
+    this.aStack_ = [];
+    this.currentPath_ = [];
+
+    // Canvas context properties
+    this.strokeStyle = '#000';
+    this.fillStyle = '#000';
+
+    this.lineWidth = 1;
+    this.lineJoin = 'miter';
+    this.lineCap = 'butt';
+    this.miterLimit = Z * 1;
+    this.globalAlpha = 1;
+    this.font = '10px sans-serif';
+    this.textAlign = 'left';
+    this.textBaseline = 'alphabetic';
+    this.canvas = canvasElement;
+
+    var cssText = 'width:' + canvasElement.clientWidth + 'px;height:' +
+        canvasElement.clientHeight + 'px;overflow:hidden;position:absolute';
+    var el = canvasElement.ownerDocument.createElement('div');
+    el.style.cssText = cssText;
+    canvasElement.appendChild(el);
+
+    var overlayEl = el.cloneNode(false);
+    // Use a non transparent background.
+    overlayEl.style.backgroundColor = 'red';
+    overlayEl.style.filter = 'alpha(opacity=0)';
+    canvasElement.appendChild(overlayEl);
+
+    this.element_ = el;
+    this.arcScaleX_ = 1;
+    this.arcScaleY_ = 1;
+    this.lineScale_ = 1;
+  }
+
+  var contextPrototype = CanvasRenderingContext2D_.prototype;
+  contextPrototype.clearRect = function() {
+    if (this.textMeasureEl_) {
+      this.textMeasureEl_.removeNode(true);
+      this.textMeasureEl_ = null;
+    }
+    this.element_.innerHTML = '';
+  };
+
+  contextPrototype.beginPath = function() {
+    // TODO: Branch current matrix so that save/restore has no effect
+    //       as per safari docs.
+    this.currentPath_ = [];
+  };
+
+  contextPrototype.moveTo = function(aX, aY) {
+    var p = getCoords(this, aX, aY);
+    this.currentPath_.push({type: 'moveTo', x: p.x, y: p.y});
+    this.currentX_ = p.x;
+    this.currentY_ = p.y;
+  };
+
+  contextPrototype.lineTo = function(aX, aY) {
+    var p = getCoords(this, aX, aY);
+    this.currentPath_.push({type: 'lineTo', x: p.x, y: p.y});
+
+    this.currentX_ = p.x;
+    this.currentY_ = p.y;
+  };
+
+  contextPrototype.bezierCurveTo = function(aCP1x, aCP1y,
+                                            aCP2x, aCP2y,
+                                            aX, aY) {
+    var p = getCoords(this, aX, aY);
+    var cp1 = getCoords(this, aCP1x, aCP1y);
+    var cp2 = getCoords(this, aCP2x, aCP2y);
+    bezierCurveTo(this, cp1, cp2, p);
+  };
+
+  // Helper function that takes the already fixed cordinates.
+  function bezierCurveTo(self, cp1, cp2, p) {
+    self.currentPath_.push({
+      type: 'bezierCurveTo',
+      cp1x: cp1.x,
+      cp1y: cp1.y,
+      cp2x: cp2.x,
+      cp2y: cp2.y,
+      x: p.x,
+      y: p.y
+    });
+    self.currentX_ = p.x;
+    self.currentY_ = p.y;
+  }
+
+  contextPrototype.quadraticCurveTo = function(aCPx, aCPy, aX, aY) {
+    // the following is lifted almost directly from
+    // http://developer.mozilla.org/en/docs/Canvas_tutorial:Drawing_shapes
+
+    var cp = getCoords(this, aCPx, aCPy);
+    var p = getCoords(this, aX, aY);
+
+    var cp1 = {
+      x: this.currentX_ + 2.0 / 3.0 * (cp.x - this.currentX_),
+      y: this.currentY_ + 2.0 / 3.0 * (cp.y - this.currentY_)
+    };
+    var cp2 = {
+      x: cp1.x + (p.x - this.currentX_) / 3.0,
+      y: cp1.y + (p.y - this.currentY_) / 3.0
+    };
+
+    bezierCurveTo(this, cp1, cp2, p);
+  };
+
+  contextPrototype.arc = function(aX, aY, aRadius,
+                                  aStartAngle, aEndAngle, aClockwise) {
+    aRadius *= Z;
+    var arcType = aClockwise ? 'at' : 'wa';
+
+    var xStart = aX + mc(aStartAngle) * aRadius - Z2;
+    var yStart = aY + ms(aStartAngle) * aRadius - Z2;
+
+    var xEnd = aX + mc(aEndAngle) * aRadius - Z2;
+    var yEnd = aY + ms(aEndAngle) * aRadius - Z2;
+
+    // IE won't render arches drawn counter clockwise if xStart == xEnd.
+    if (xStart == xEnd && !aClockwise) {
+      xStart += 0.125; // Offset xStart by 1/80 of a pixel. Use something
+                       // that can be represented in binary
+    }
+
+    var p = getCoords(this, aX, aY);
+    var pStart = getCoords(this, xStart, yStart);
+    var pEnd = getCoords(this, xEnd, yEnd);
+
+    this.currentPath_.push({type: arcType,
+                           x: p.x,
+                           y: p.y,
+                           radius: aRadius,
+                           xStart: pStart.x,
+                           yStart: pStart.y,
+                           xEnd: pEnd.x,
+                           yEnd: pEnd.y});
+
+  };
+
+  contextPrototype.rect = function(aX, aY, aWidth, aHeight) {
+    this.moveTo(aX, aY);
+    this.lineTo(aX + aWidth, aY);
+    this.lineTo(aX + aWidth, aY + aHeight);
+    this.lineTo(aX, aY + aHeight);
+    this.closePath();
+  };
+
+  contextPrototype.strokeRect = function(aX, aY, aWidth, aHeight) {
+    var oldPath = this.currentPath_;
+    this.beginPath();
+
+    this.moveTo(aX, aY);
+    this.lineTo(aX + aWidth, aY);
+    this.lineTo(aX + aWidth, aY + aHeight);
+    this.lineTo(aX, aY + aHeight);
+    this.closePath();
+    this.stroke();
+
+    this.currentPath_ = oldPath;
+  };
+
+  contextPrototype.fillRect = function(aX, aY, aWidth, aHeight) {
+    var oldPath = this.currentPath_;
+    this.beginPath();
+
+    this.moveTo(aX, aY);
+    this.lineTo(aX + aWidth, aY);
+    this.lineTo(aX + aWidth, aY + aHeight);
+    this.lineTo(aX, aY + aHeight);
+    this.closePath();
+    this.fill();
+
+    this.currentPath_ = oldPath;
+  };
+
+  contextPrototype.createLinearGradient = function(aX0, aY0, aX1, aY1) {
+    var gradient = new CanvasGradient_('gradient');
+    gradient.x0_ = aX0;
+    gradient.y0_ = aY0;
+    gradient.x1_ = aX1;
+    gradient.y1_ = aY1;
+    return gradient;
+  };
+
+  contextPrototype.createRadialGradient = function(aX0, aY0, aR0,
+                                                   aX1, aY1, aR1) {
+    var gradient = new CanvasGradient_('gradientradial');
+    gradient.x0_ = aX0;
+    gradient.y0_ = aY0;
+    gradient.r0_ = aR0;
+    gradient.x1_ = aX1;
+    gradient.y1_ = aY1;
+    gradient.r1_ = aR1;
+    return gradient;
+  };
+
+  contextPrototype.drawImage = function(image, var_args) {
+    var dx, dy, dw, dh, sx, sy, sw, sh;
+
+    // to find the original width we overide the width and height
+    var oldRuntimeWidth = image.runtimeStyle.width;
+    var oldRuntimeHeight = image.runtimeStyle.height;
+    image.runtimeStyle.width = 'auto';
+    image.runtimeStyle.height = 'auto';
+
+    // get the original size
+    var w = image.width;
+    var h = image.height;
+
+    // and remove overides
+    image.runtimeStyle.width = oldRuntimeWidth;
+    image.runtimeStyle.height = oldRuntimeHeight;
+
+    if (arguments.length == 3) {
+      dx = arguments[1];
+      dy = arguments[2];
+      sx = sy = 0;
+      sw = dw = w;
+      sh = dh = h;
+    } else if (arguments.length == 5) {
+      dx = arguments[1];
+      dy = arguments[2];
+      dw = arguments[3];
+      dh = arguments[4];
+      sx = sy = 0;
+      sw = w;
+      sh = h;
+    } else if (arguments.length == 9) {
+      sx = arguments[1];
+      sy = arguments[2];
+      sw = arguments[3];
+      sh = arguments[4];
+      dx = arguments[5];
+      dy = arguments[6];
+      dw = arguments[7];
+      dh = arguments[8];
+    } else {
+      throw Error('Invalid number of arguments');
+    }
+
+    var d = getCoords(this, dx, dy);
+
+    var w2 = sw / 2;
+    var h2 = sh / 2;
+
+    var vmlStr = [];
+
+    var W = 10;
+    var H = 10;
+
+    // For some reason that I've now forgotten, using divs didn't work
+    vmlStr.push(' <g_vml_:group',
+                ' coordsize="', Z * W, ',', Z * H, '"',
+                ' coordorigin="0,0"' ,
+                ' style="width:', W, 'px;height:', H, 'px;position:absolute;');
+
+    // If filters are necessary (rotation exists), create them
+    // filters are bog-slow, so only create them if abbsolutely necessary
+    // The following check doesn't account for skews (which don't exist
+    // in the canvas spec (yet) anyway.
+
+    if (this.m_[0][0] != 1 || this.m_[0][1] ||
+        this.m_[1][1] != 1 || this.m_[1][0]) {
+      var filter = [];
+
+      // Note the 12/21 reversal
+      filter.push('M11=', this.m_[0][0], ',',
+                  'M12=', this.m_[1][0], ',',
+                  'M21=', this.m_[0][1], ',',
+                  'M22=', this.m_[1][1], ',',
+                  'Dx=', mr(d.x / Z), ',',
+                  'Dy=', mr(d.y / Z), '');
+
+      // Bounding box calculation (need to minimize displayed area so that
+      // filters don't waste time on unused pixels.
+      var max = d;
+      var c2 = getCoords(this, dx + dw, dy);
+      var c3 = getCoords(this, dx, dy + dh);
+      var c4 = getCoords(this, dx + dw, dy + dh);
+
+      max.x = m.max(max.x, c2.x, c3.x, c4.x);
+      max.y = m.max(max.y, c2.y, c3.y, c4.y);
+
+      vmlStr.push('padding:0 ', mr(max.x / Z), 'px ', mr(max.y / Z),
+                  'px 0;filter:progid:DXImageTransform.Microsoft.Matrix(',
+                  filter.join(''), ", sizingmethod='clip');");
+
+    } else {
+      vmlStr.push('top:', mr(d.y / Z), 'px;left:', mr(d.x / Z), 'px;');
+    }
+
+    vmlStr.push(' ">' ,
+                '<g_vml_:image src="', image.src, '"',
+                ' style="width:', Z * dw, 'px;',
+                ' height:', Z * dh, 'px"',
+                ' cropleft="', sx / w, '"',
+                ' croptop="', sy / h, '"',
+                ' cropright="', (w - sx - sw) / w, '"',
+                ' cropbottom="', (h - sy - sh) / h, '"',
+                ' />',
+                '</g_vml_:group>');
+
+    this.element_.insertAdjacentHTML('BeforeEnd', vmlStr.join(''));
+  };
+
+  contextPrototype.stroke = function(aFill) {
+    var lineStr = [];
+    var lineOpen = false;
+
+    var W = 10;
+    var H = 10;
+
+    lineStr.push('<g_vml_:shape',
+                 ' filled="', !!aFill, '"',
+                 ' style="position:absolute;width:', W, 'px;height:', H, 'px;"',
+                 ' coordorigin="0,0"',
+                 ' coordsize="', Z * W, ',', Z * H, '"',
+                 ' stroked="', !aFill, '"',
+                 ' path="');
+
+    var newSeq = false;
+    var min = {x: null, y: null};
+    var max = {x: null, y: null};
+
+    for (var i = 0; i < this.currentPath_.length; i++) {
+      var p = this.currentPath_[i];
+      var c;
+
+      switch (p.type) {
+        case 'moveTo':
+          c = p;
+          lineStr.push(' m ', mr(p.x), ',', mr(p.y));
+          break;
+        case 'lineTo':
+          lineStr.push(' l ', mr(p.x), ',', mr(p.y));
+          break;
+        case 'close':
+          lineStr.push(' x ');
+          p = null;
+          break;
+        case 'bezierCurveTo':
+          lineStr.push(' c ',
+                       mr(p.cp1x), ',', mr(p.cp1y), ',',
+                       mr(p.cp2x), ',', mr(p.cp2y), ',',
+                       mr(p.x), ',', mr(p.y));
+          break;
+        case 'at':
+        case 'wa':
+          lineStr.push(' ', p.type, ' ',
+                       mr(p.x - this.arcScaleX_ * p.radius), ',',
+                       mr(p.y - this.arcScaleY_ * p.radius), ' ',
+                       mr(p.x + this.arcScaleX_ * p.radius), ',',
+                       mr(p.y + this.arcScaleY_ * p.radius), ' ',
+                       mr(p.xStart), ',', mr(p.yStart), ' ',
+                       mr(p.xEnd), ',', mr(p.yEnd));
+          break;
+      }
+
+
+      // TODO: Following is broken for curves due to
+      //       move to proper paths.
+
+      // Figure out dimensions so we can do gradient fills
+      // properly
+      if (p) {
+        if (min.x == null || p.x < min.x) {
+          min.x = p.x;
+        }
+        if (max.x == null || p.x > max.x) {
+          max.x = p.x;
+        }
+        if (min.y == null || p.y < min.y) {
+          min.y = p.y;
+        }
+        if (max.y == null || p.y > max.y) {
+          max.y = p.y;
+        }
+      }
+    }
+    lineStr.push(' ">');
+
+    if (!aFill) {
+      appendStroke(this, lineStr);
+    } else {
+      appendFill(this, lineStr, min, max);
+    }
+
+    lineStr.push('</g_vml_:shape>');
+
+    this.element_.insertAdjacentHTML('beforeEnd', lineStr.join(''));
+  };
+
+  function appendStroke(ctx, lineStr) {
+    var a = processStyle(ctx.strokeStyle);
+    var color = a.color;
+    var opacity = a.alpha * ctx.globalAlpha;
+    var lineWidth = ctx.lineScale_ * ctx.lineWidth;
+
+    // VML cannot correctly render a line if the width is less than 1px.
+    // In that case, we dilute the color to make the line look thinner.
+    if (lineWidth < 1) {
+      opacity *= lineWidth;
+    }
+
+    lineStr.push(
+      '<g_vml_:stroke',
+      ' opacity="', opacity, '"',
+      ' joinstyle="', ctx.lineJoin, '"',
+      ' miterlimit="', ctx.miterLimit, '"',
+      ' endcap="', processLineCap(ctx.lineCap), '"',
+      ' weight="', lineWidth, 'px"',
+      ' color="', color, '" />'
+    );
+  }
+
+  function appendFill(ctx, lineStr, min, max) {
+    var fillStyle = ctx.fillStyle;
+    var arcScaleX = ctx.arcScaleX_;
+    var arcScaleY = ctx.arcScaleY_;
+    var width = max.x - min.x;
+    var height = max.y - min.y;
+    if (fillStyle instanceof CanvasGradient_) {
+      // TODO: Gradients transformed with the transformation matrix.
+      var angle = 0;
+      var focus = {x: 0, y: 0};
+
+      // additional offset
+      var shift = 0;
+      // scale factor for offset
+      var expansion = 1;
+
+      if (fillStyle.type_ == 'gradient') {
+        var x0 = fillStyle.x0_ / arcScaleX;
+        var y0 = fillStyle.y0_ / arcScaleY;
+        var x1 = fillStyle.x1_ / arcScaleX;
+        var y1 = fillStyle.y1_ / arcScaleY;
+        var p0 = getCoords(ctx, x0, y0);
+        var p1 = getCoords(ctx, x1, y1);
+        var dx = p1.x - p0.x;
+        var dy = p1.y - p0.y;
+        angle = Math.atan2(dx, dy) * 180 / Math.PI;
+
+        // The angle should be a non-negative number.
+        if (angle < 0) {
+          angle += 360;
+        }
+
+        // Very small angles produce an unexpected result because they are
+        // converted to a scientific notation string.
+        if (angle < 1e-6) {
+          angle = 0;
+        }
+      } else {
+        var p0 = getCoords(ctx, fillStyle.x0_, fillStyle.y0_);
+        focus = {
+          x: (p0.x - min.x) / width,
+          y: (p0.y - min.y) / height
+        };
+
+        width  /= arcScaleX * Z;
+        height /= arcScaleY * Z;
+        var dimension = m.max(width, height);
+        shift = 2 * fillStyle.r0_ / dimension;
+        expansion = 2 * fillStyle.r1_ / dimension - shift;
+      }
+
+      // We need to sort the color stops in ascending order by offset,
+      // otherwise IE won't interpret it correctly.
+      var stops = fillStyle.colors_;
+      stops.sort(function(cs1, cs2) {
+        return cs1.offset - cs2.offset;
+      });
+
+      var length = stops.length;
+      var color1 = stops[0].color;
+      var color2 = stops[length - 1].color;
+      var opacity1 = stops[0].alpha * ctx.globalAlpha;
+      var opacity2 = stops[length - 1].alpha * ctx.globalAlpha;
+
+      var colors = [];
+      for (var i = 0; i < length; i++) {
+        var stop = stops[i];
+        colors.push(stop.offset * expansion + shift + ' ' + stop.color);
+      }
+
+      // When colors attribute is used, the meanings of opacity and o:opacity2
+      // are reversed.
+      lineStr.push('<g_vml_:fill type="', fillStyle.type_, '"',
+                   ' method="none" focus="100%"',
+                   ' color="', color1, '"',
+                   ' color2="', color2, '"',
+                   ' colors="', colors.join(','), '"',
+                   ' opacity="', opacity2, '"',
+                   ' g_o_:opacity2="', opacity1, '"',
+                   ' angle="', angle, '"',
+                   ' focusposition="', focus.x, ',', focus.y, '" />');
+    } else if (fillStyle instanceof CanvasPattern_) {
+      if (width && height) {
+        var deltaLeft = -min.x;
+        var deltaTop = -min.y;
+        lineStr.push('<g_vml_:fill',
+                     ' position="',
+                     deltaLeft / width * arcScaleX * arcScaleX, ',',
+                     deltaTop / height * arcScaleY * arcScaleY, '"',
+                     ' type="tile"',
+                     // TODO: Figure out the correct size to fit the scale.
+                     //' size="', w, 'px ', h, 'px"',
+                     ' src="', fillStyle.src_, '" />');
+       }
+    } else {
+      var a = processStyle(ctx.fillStyle);
+      var color = a.color;
+      var opacity = a.alpha * ctx.globalAlpha;
+      lineStr.push('<g_vml_:fill color="', color, '" opacity="', opacity,
+                   '" />');
+    }
+  }
+
+  contextPrototype.fill = function() {
+    this.stroke(true);
+  };
+
+  contextPrototype.closePath = function() {
+    this.currentPath_.push({type: 'close'});
+  };
+
+  function getCoords(ctx, aX, aY) {
+    var m = ctx.m_;
+    return {
+      x: Z * (aX * m[0][0] + aY * m[1][0] + m[2][0]) - Z2,
+      y: Z * (aX * m[0][1] + aY * m[1][1] + m[2][1]) - Z2
+    };
+  };
+
+  contextPrototype.save = function() {
+    var o = {};
+    copyState(this, o);
+    this.aStack_.push(o);
+    this.mStack_.push(this.m_);
+    this.m_ = matrixMultiply(createMatrixIdentity(), this.m_);
+  };
+
+  contextPrototype.restore = function() {
+    if (this.aStack_.length) {
+      copyState(this.aStack_.pop(), this);
+      this.m_ = this.mStack_.pop();
+    }
+  };
+
+  function matrixIsFinite(m) {
+    return isFinite(m[0][0]) && isFinite(m[0][1]) &&
+        isFinite(m[1][0]) && isFinite(m[1][1]) &&
+        isFinite(m[2][0]) && isFinite(m[2][1]);
+  }
+
+  function setM(ctx, m, updateLineScale) {
+    if (!matrixIsFinite(m)) {
+      return;
+    }
+    ctx.m_ = m;
+
+    if (updateLineScale) {
+      // Get the line scale.
+      // Determinant of this.m_ means how much the area is enlarged by the
+      // transformation. So its square root can be used as a scale factor
+      // for width.
+      var det = m[0][0] * m[1][1] - m[0][1] * m[1][0];
+      ctx.lineScale_ = sqrt(abs(det));
+    }
+  }
+
+  contextPrototype.translate = function(aX, aY) {
+    var m1 = [
+      [1,  0,  0],
+      [0,  1,  0],
+      [aX, aY, 1]
+    ];
+
+    setM(this, matrixMultiply(m1, this.m_), false);
+  };
+
+  contextPrototype.rotate = function(aRot) {
+    var c = mc(aRot);
+    var s = ms(aRot);
+
+    var m1 = [
+      [c,  s, 0],
+      [-s, c, 0],
+      [0,  0, 1]
+    ];
+
+    setM(this, matrixMultiply(m1, this.m_), false);
+  };
+
+  contextPrototype.scale = function(aX, aY) {
+    this.arcScaleX_ *= aX;
+    this.arcScaleY_ *= aY;
+    var m1 = [
+      [aX, 0,  0],
+      [0,  aY, 0],
+      [0,  0,  1]
+    ];
+
+    setM(this, matrixMultiply(m1, this.m_), true);
+  };
+
+  contextPrototype.transform = function(m11, m12, m21, m22, dx, dy) {
+    var m1 = [
+      [m11, m12, 0],
+      [m21, m22, 0],
+      [dx,  dy,  1]
+    ];
+
+    setM(this, matrixMultiply(m1, this.m_), true);
+  };
+
+  contextPrototype.setTransform = function(m11, m12, m21, m22, dx, dy) {
+    var m = [
+      [m11, m12, 0],
+      [m21, m22, 0],
+      [dx,  dy,  1]
+    ];
+
+    setM(this, m, true);
+  };
+
+  /**
+   * The text drawing function.
+   * The maxWidth argument isn't taken in account, since no browser supports
+   * it yet.
+   */
+  contextPrototype.drawText_ = function(text, x, y, maxWidth, stroke) {
+    var m = this.m_,
+        delta = 1000,
+        left = 0,
+        right = delta,
+        offset = {x: 0, y: 0},
+        lineStr = [];
+
+    var fontStyle = getComputedStyle(processFontStyle(this.font),
+                                     this.element_);
+
+    var fontStyleString = buildStyle(fontStyle);
+
+    var elementStyle = this.element_.currentStyle;
+    var textAlign = this.textAlign.toLowerCase();
+    switch (textAlign) {
+      case 'left':
+      case 'center':
+      case 'right':
+        break;
+      case 'end':
+        textAlign = elementStyle.direction == 'ltr' ? 'right' : 'left';
+        break;
+      case 'start':
+        textAlign = elementStyle.direction == 'rtl' ? 'right' : 'left';
+        break;
+      default:
+        textAlign = 'left';
+    }
+
+    // 1.75 is an arbitrary number, as there is no info about the text baseline
+    switch (this.textBaseline) {
+      case 'hanging':
+      case 'top':
+        offset.y = fontStyle.size / 1.75;
+        break;
+      case 'middle':
+        break;
+      default:
+      case null:
+      case 'alphabetic':
+      case 'ideographic':
+      case 'bottom':
+        offset.y = -fontStyle.size / 2.25;
+        break;
+    }
+
+    switch(textAlign) {
+      case 'right':
+        left = delta;
+        right = 0.05;
+        break;
+      case 'center':
+        left = right = delta / 2;
+        break;
+    }
+
+    var d = getCoords(this, x + offset.x, y + offset.y);
+
+    lineStr.push('<g_vml_:line from="', -left ,' 0" to="', right ,' 0.05" ',
+                 ' coordsize="100 100" coordorigin="0 0"',
+                 ' filled="', !stroke, '" stroked="', !!stroke,
+                 '" style="position:absolute;width:1px;height:1px;">');
+
+    if (stroke) {
+      appendStroke(this, lineStr);
+    } else {
+      // TODO: Fix the min and max params.
+      appendFill(this, lineStr, {x: -left, y: 0},
+                 {x: right, y: fontStyle.size});
+    }
+
+    var skewM = m[0][0].toFixed(3) + ',' + m[1][0].toFixed(3) + ',' +
+                m[0][1].toFixed(3) + ',' + m[1][1].toFixed(3) + ',0,0';
+
+    var skewOffset = mr(d.x / Z) + ',' + mr(d.y / Z);
+
+    lineStr.push('<g_vml_:skew on="t" matrix="', skewM ,'" ',
+                 ' offset="', skewOffset, '" origin="', left ,' 0" />',
+                 '<g_vml_:path textpathok="true" />',
+                 '<g_vml_:textpath on="true" string="',
+                 encodeHtmlAttribute(text),
+                 '" style="v-text-align:', textAlign,
+                 ';font:', encodeHtmlAttribute(fontStyleString),
+                 '" /></g_vml_:line>');
+
+    this.element_.insertAdjacentHTML('beforeEnd', lineStr.join(''));
+  };
+
+  contextPrototype.fillText = function(text, x, y, maxWidth) {
+    this.drawText_(text, x, y, maxWidth, false);
+  };
+
+  contextPrototype.strokeText = function(text, x, y, maxWidth) {
+    this.drawText_(text, x, y, maxWidth, true);
+  };
+
+  contextPrototype.measureText = function(text) {
+    if (!this.textMeasureEl_) {
+      var s = '<span style="position:absolute;' +
+          'top:-20000px;left:0;padding:0;margin:0;border:none;' +
+          'white-space:pre;"></span>';
+      this.element_.insertAdjacentHTML('beforeEnd', s);
+      this.textMeasureEl_ = this.element_.lastChild;
+    }
+    var doc = this.element_.ownerDocument;
+    this.textMeasureEl_.innerHTML = '';
+    this.textMeasureEl_.style.font = this.font;
+    // Don't use innerHTML or innerText because they allow markup/whitespace.
+    this.textMeasureEl_.appendChild(doc.createTextNode(text));
+    return {width: this.textMeasureEl_.offsetWidth};
+  };
+
+  /******** STUBS ********/
+  contextPrototype.clip = function() {
+    // TODO: Implement
+  };
+
+  contextPrototype.arcTo = function() {
+    // TODO: Implement
+  };
+
+  contextPrototype.createPattern = function(image, repetition) {
+    return new CanvasPattern_(image, repetition);
+  };
+
+  // Gradient / Pattern Stubs
+  function CanvasGradient_(aType) {
+    this.type_ = aType;
+    this.x0_ = 0;
+    this.y0_ = 0;
+    this.r0_ = 0;
+    this.x1_ = 0;
+    this.y1_ = 0;
+    this.r1_ = 0;
+    this.colors_ = [];
+  }
+
+  CanvasGradient_.prototype.addColorStop = function(aOffset, aColor) {
+    aColor = processStyle(aColor);
+    this.colors_.push({offset: aOffset,
+                       color: aColor.color,
+                       alpha: aColor.alpha});
+  };
+
+  function CanvasPattern_(image, repetition) {
+    assertImageIsValid(image);
+    switch (repetition) {
+      case 'repeat':
+      case null:
+      case '':
+        this.repetition_ = 'repeat';
+        break
+      case 'repeat-x':
+      case 'repeat-y':
+      case 'no-repeat':
+        this.repetition_ = repetition;
+        break;
+      default:
+        throwException('SYNTAX_ERR');
+    }
+
+    this.src_ = image.src;
+    this.width_ = image.width;
+    this.height_ = image.height;
+  }
+
+  function throwException(s) {
+    throw new DOMException_(s);
+  }
+
+  function assertImageIsValid(img) {
+    if (!img || img.nodeType != 1 || img.tagName != 'IMG') {
+      throwException('TYPE_MISMATCH_ERR');
+    }
+    if (img.readyState != 'complete') {
+      throwException('INVALID_STATE_ERR');
+    }
+  }
+
+  function DOMException_(s) {
+    this.code = this[s];
+    this.message = s +': DOM Exception ' + this.code;
+  }
+  var p = DOMException_.prototype = new Error;
+  p.INDEX_SIZE_ERR = 1;
+  p.DOMSTRING_SIZE_ERR = 2;
+  p.HIERARCHY_REQUEST_ERR = 3;
+  p.WRONG_DOCUMENT_ERR = 4;
+  p.INVALID_CHARACTER_ERR = 5;
+  p.NO_DATA_ALLOWED_ERR = 6;
+  p.NO_MODIFICATION_ALLOWED_ERR = 7;
+  p.NOT_FOUND_ERR = 8;
+  p.NOT_SUPPORTED_ERR = 9;
+  p.INUSE_ATTRIBUTE_ERR = 10;
+  p.INVALID_STATE_ERR = 11;
+  p.SYNTAX_ERR = 12;
+  p.INVALID_MODIFICATION_ERR = 13;
+  p.NAMESPACE_ERR = 14;
+  p.INVALID_ACCESS_ERR = 15;
+  p.VALIDATION_ERR = 16;
+  p.TYPE_MISMATCH_ERR = 17;
+
+  // set up externs
+  G_vmlCanvasManager = G_vmlCanvasManager_;
+  CanvasRenderingContext2D = CanvasRenderingContext2D_;
+  CanvasGradient = CanvasGradient_;
+  CanvasPattern = CanvasPattern_;
+  DOMException = DOMException_;
+})();
+
+} // if

BIN
ourbiz/s/ourbiz/favicon.ico


+ 151 - 0
ourbiz/s/ourbiz/gl-chart.js

@@ -0,0 +1,151 @@
+Jaml.register('GLChartEditWindow', function(args) {
+	form({action: "/DB/Action", method: "post", onsubmit:"return false;",
+			id: args.form_id, style: "width:100%;height:100%;"}, 
+		table({style: "width:100%;height:100%;", cls: "editForm"},
+			tr(
+				td(
+					table(
+						tr(
+							td(_tr("ID")),td(_tr("Budget")),td(_tr("Balance"))
+						),
+						tr(
+							td(input({type: "text", name: "glc_id", readonly:"1"})),
+							td(input({type: "text", name: "glc_budget"})),
+							td(input({type: "text", name: "glc_balance"}))
+						),
+						tr(
+							td(_tr("Code")),td({colspan:2},_tr("Group"))
+						),
+						tr(
+							td(input({type: "text", name: "glc_group_code"})),
+							td({colspan:2},select({name: "glc_gl_group_id", cls:"fw"}))
+						),
+						tr(
+							td({colspan:3},_tr("Description"))
+						),
+						tr(
+							td({colspan:3}, input({type: "text", name: "glc_description", cls:"fw"}))
+						)
+					)
+				),
+				td(
+					br(),
+					input({type: "checkbox", name: "glc_is_active"}),_tr("Active"),
+					br(),
+					input({type: "checkbox", name: "glc_is_header"}),_tr("Header"),
+					br(),
+					Jaml.render('ActionSelect', args),
+					br(),
+					input({id: args.btnAction_id, type: "button", name: "btnAction", value: _tr("Action")})
+				)
+			),
+			tr(
+				td({colspan:2},_tr("Notes"))
+			),
+			tr(
+				td({colspan:2},textarea({rows: 5, name: "glc_notes", cls: "fw"}))
+			)
+		)
+	);
+});
+
+function GLChartEditWindowRefresh(ajax) {
+}
+
+function showGLChartEditWindow(all_sales_buys, caller, id){
+	var win = newGLChartEditWindow(all_sales_buys);
+	win.ud.caller = caller;
+	win.ud.edit_id = id;
+	var ajax = win.ud.ajaxLoad;
+	if(ajax){
+		ajax.post("/DB/GetOne", "gl_chart=" + id, 'GET', null);
+	}
+}
+
+function GLChartEditWindowOnSubmit(btn) {
+	return dad.formOnSubmit(GLChartEditWindowRefresh, this.form, "gl_chart")
+}
+
+function GLChartEditWindowOnFillForm(form_field, value) {
+	if(form_field.name == "gl_group_id"){
+		var options = form_field.options;
+		for(var i=0; i < options.length; i++){
+			if(value == options[i].value) {
+				form_field.selectedIndex = i;
+				break;
+			}
+		}
+		return true;
+	}
+	return false;
+}
+
+function newGLChartEditWindow(all_sales_buys){
+	var title = dad._getSABTitle(all_sales_buys, 'GL Chart Edit');
+
+	var win = dad._windows[title];
+	if(!win){
+		var newId = dad.newSeqId();
+		var Action_id = 'Action' + newId;
+		var btnAction_id = 'btnAction' + newId;
+		var data = {
+			id: newId,
+			form_id: 'form' + newId,
+			Action_id: Action_id,
+			btnAction_id: btnAction_id
+		}
+		var win = dad.newWindow(newId,220,20, 670, 315, _tr(title), Jaml.render('GLChartEditWindow', data));
+		//dad.setContentOverflow(newId);
+		win.ud.ajaxLoad = new dad.Ajax(dad.formAjaxLoadResponse, newId, false);
+		
+		var myform = $(data.form_id);
+		myform.my_field_prefix = "glc_";
+		myform.onFillForm = GLChartEditWindowOnFillForm;
+		dad.setupEditForm(myform);
+		myform.ajaxSubmit = new dad.Ajax(dad.listGLChartWindowOnSubmitRespose, newId, false);
+		
+		var btn = $(btnAction_id);
+		btn.onclick = GLChartEditWindowOnSubmit;
+		
+		var ajaxGlGroups = new dad.Ajax(function(select){
+			if(this.status == 200){
+				//retrieve result as an JavaScript object
+				var records = dad.parseSLEData(this.responseText); 
+				dad.fillSelectByRecords(select, records, true);
+			}
+		}, myform.glc_gl_group_id);
+		if(ajaxGlGroups) ajaxGlGroups.post('/DB/GetList', 'list=gl_groups&short_list=1', "GET");		
+	}
+	
+	dad.bringToFront(win)
+	return win;
+}
+
+Jaml.register('GLChartListSearchOn', function(args) {
+	input({type: "radio", name: "search_on", id: "by_description" + args.id, value: "description", checked:1 }),
+	label({'for': "by_description" + args.id},  _tr("Description")),
+	input({type: "radio", name: "search_on", id: "by_notes" + args.id, value: "notes"}),
+	label({'for': "by_notes" + args.id},  _tr("Notes")),
+	input({type: "radio", name: "search_on", id: "by_code" + args.id, value: "code"}),
+	label({'for': "by_code" + args.id},  _tr("Code"))
+});
+
+Jaml.register('GLChartListSearchOn2', function(args) {
+	input({type: "checkbox", id: "by_active" + args.id, value: "by_active"}),
+	label({'for': "by_active" + args.id},  _tr("Active")),
+	input({type: "checkbox", id: "by_headers" + args.id, value: "headers"}),
+	label({'for': "by_headers" + args.id},  _tr("Headers")),
+	input({type: "checkbox", id: "by_accounts" + args.id, value: "accounts"}),
+	label({'for': "by_accounts" + args.id},  _tr("Accounts"))
+});
+
+function newGLChartListSearchWindow(all_sales_buys){
+	var colHeaders = ["id|ID|0|R",
+                "group_code|Grp.|3|C",
+                "code|Code|8",
+                "description|Description|-1",
+                "is_header|Hdr.|3|C|B"];
+	var title = dad._getSABTitle(all_sales_buys, 'GL Chart List/Search');
+	return newListSearchWindow(all_sales_buys, title, colHeaders, showGLChartEditWindow,
+		"gl_chart", 'GLChartListSearchOn', 'GLChartListSearchOn2', all_sales_buys);
+}

+ 93 - 0
ourbiz/s/ourbiz/gl-groups.js

@@ -0,0 +1,93 @@
+Jaml.register('GLGroupsListEdit', function(args) {
+	form({action: "/DB/Action", method: "post", id: args.form_id, style: "width:100%;height:100%;"},
+		table({style: "width:100%;height:100%;"},
+			args.data_table,
+			tr(
+				td({'class': "editBox", style: "width:100%;"},
+					fieldset(legend(_tr("Edit Form")),
+						table(
+							tr(
+								td(_tr("ID")), td(_tr("Code")), td(_tr("Op. Debit(+/-)")), td(_tr("Op. Credit(+/-)"))
+							),
+							tr(
+								td(input({type: "input", name: "glg_id", size: 12, readonly:"1"})), 
+								td(input({type: "input", name: "glg_code", size: 12})), 
+								td(input({type: "input", name: "glg_debit_op", size: 2})),
+								td(input({type: "input", name: "glg_credit_op", size: 2}))
+							),
+							tr(
+								td({colspan:3}, _tr("Description")), 
+								td(Jaml.render('ActionSelect', args))
+							),
+							tr(
+								td({colspan:3},input({type: "input", style: "width:98%;", name: "glg_description"})), 
+								td(input({id: args.btnAction_id, type: "button", name: "btnAction", value: _tr("Action")}))
+							)
+						)
+					)
+				)
+			)
+		)
+	);
+});
+
+function GLGroupsListEditWindowOnTableRowClick(){
+	var win = dad.getWindowForChild(this);
+	if(win && win.ud.ajaxLoad){
+			win.ud.ajaxLoad.post('/DB/GetOne', 'gl_groups=' + this.cells[1].innerHTML , "GET");
+			var form = dad.getFirstParentWithTagName(this, "FORM");
+			if(form) form.st_rate1.focus();
+	}
+}
+
+function GLGroupsListEditWindowRefresh(ajax) {
+	ajax.post('/DB/GetList', 'list=gl_groups', "GET");
+}
+
+function GLGroupsListEditWindowOnSubmit(btn) {
+	return dad.formOnSubmit(GLGroupsListEditWindowRefresh, this.form, "gl_groups")
+}
+
+function newGLGroupsListEditWindow(){
+	var title = "GL Groups List Edit"
+	var win = dad._windows[title];
+	if(!win){
+		var newId = dad.newSeqId();
+		var Action_id = 'Action' + newId;
+		var btnAction_id = 'btnAction' + newId;
+		var table_id = 'table' + newId;
+		var table_header_id = 'table_header' + newId;
+		var form_id = 'form' + newId;
+		var data = {
+			id: newId,
+			form_id: form_id,
+			Action_id: Action_id,
+			btnAction_id: btnAction_id,
+			table_id: table_id,
+			table_header_id: table_header_id
+		}
+		data.table_height = "50%";
+		data.data_table = Jaml.render('2TRDataTable', data);
+
+		var win = dad.newWindow(newId,220,20, 460, 420, _tr(title), Jaml.render('GLGroupsListEdit', data));
+		var myform = $(data.form_id);
+		win.ud.form = myform;
+		win.ud.WindowRefresh = GLGroupsListEditWindowRefresh;
+		myform.my_field_prefix = "glg_";
+		dad.setupEditForm(myform);
+		myform.ajaxSubmit = new dad.Ajax(dad.listEditWindowOnSubmitRespose, newId, false);
+		win.ud.ajaxLoad = new dad.Ajax(dad.formAjaxLoadResponse, newId, false);
+
+		var mytable = $(table_id);
+		mytable.my_record_header = ["id|ID|0", "code|Code|8",
+                "description|Description|-1", "debit_op|Dbt|8|C", "credit_op|Cdt|8|C"];
+		mytable.row_click_cb = GLGroupsListEditWindowOnTableRowClick;
+		win.ud.ajaxTable = new dad.newAjaxDataTableAjax(win, newId);
+
+		var btn = $(btnAction_id);
+		btn.onclick = GLGroupsListEditWindowOnSubmit;
+
+		GLGroupsListEditWindowRefresh(win.ud.ajaxTable);
+	}
+	dad.bringToFront(win)
+}

+ 248 - 0
ourbiz/s/ourbiz/gl-transactions.js

@@ -0,0 +1,248 @@
+Jaml.register('GLTransationsEditWindow', function(args) {
+	form({id: args.form_id, style: "width:100%;height:100%;", onsubmit:"return false;"}, 
+		table({style: "width:100%;height:100%", cls: "editForm"},
+			tr({style:"height:2%;"},
+				td(_tr("Description")),
+				td({colspan:2},_tr("Date"))
+			),
+			tr({style:"height:2%;"},
+				td({style:"width:98%;"}, input({type: "text", name: "glt_description", style:"width:100%;"})),
+				td(input({type: "text", name: "glt_transaction_date", size: 10})),
+				td(input({type: "button", name: "select_transaction_date", value: "&lt;&gt;", 
+						onclick:"newCalendarChooserWindow()"}))
+			),
+			tr(
+				td({colspan:3, style: "width:100%;height:100%;"},
+					table({style: "width:100%;height:100%;"},
+						args.data_table,
+						tr(
+							td(
+								table(
+									tr(
+										td(_tr("Code")), td(_tr("Grp.")), td({colspan:2},_tr("Account"))
+									),
+									tr(
+										td(_tr("Code")), td(_tr("Grp.")), td({colspan:2},_tr("Account"))
+									)
+								)
+							)
+						),
+						tr(
+							td(
+								table(
+									tr(
+										td(_tr("Document")), td(_tr("Debit")), td(_tr("Credit"))
+									),
+									tr(
+										td(_tr("Document")), td(_tr("Debit")), td(_tr("Credit"))
+									)
+								)
+							)
+						),
+						tr(
+							td(
+								table(
+									tr(
+										td({colspan:2},_tr("Due Date")), td({colspan:3},_tr("Checked Date"))
+									),
+									tr(
+										td({colspan:2},_tr("Due Date")), td({colspan:3},_tr("Checked Date"))
+									)
+								)
+							)
+						)
+					)
+				)
+			),
+			tr(
+				td({colspan:2},
+					Jaml.render('ActionSelect', args),
+					input({id: args.btnAction_id, type: "button", name: "btnAction", value: _tr("Action")})
+				),
+				td({style:"text-align:right;"},
+					_tr("Transaction #"), input({type: "input", name: "glt_id", size: 12, readonly:"1"})
+				)
+			)
+		)
+	);
+});
+
+function showGLTransationsEditWindow(all_sales_buys, caller, id){
+	var win = newGLTransationsEditWindow(all_sales_buys);
+	win.ud.caller = caller;
+	win.ud.sab = all_sales_buys;
+	var ajax = win.ud.ajaxLoad;
+	if(ajax){
+		ajax.post("/DB/GetOne", "gl_transactions=" + id + "&with_lines=1", 'GET', null);
+	}
+/*	
+	var ajaxLines = win.ud.ajaxLines;
+	if(ajaxLines){
+		ajaxLines.post('/DB/GetList', 'list=orders&lines=' + id, "GET");
+	}
+*/	
+}
+
+function FillTransactionLineEdit(form, row){
+	form.product_id.value = row[1].innerHTML;
+	form.description.value = row[2].innerHTML;
+	form.quantity.value = row[3].innerHTML;
+	form.price.value = row[4].innerHTML;
+}
+
+function TransactionLinesOnTableRowDoubleClick(ev){
+	var table = dad.getTableForTableChild(this);
+	if(table){
+		var win = dad.getWindowForChild(table);
+		if(win && win.ud.form) 		FillTransactionLineEdit(win.ud.form, this.cells);
+	}
+	dad.cancelEvent(dad.checkEvent(ev));
+	//return true;
+}
+
+function TransactionLinesOnTableRowClick(ev){
+	var win = dad.getWindowForChild(this);
+	if(win && win.ud.ajaxLoadLine) {
+		var row = this.cells;
+		win.ud.ajaxLoadLine.post('/DB/GetOne', 'gl_transactions=' + row[1].innerHTML + '&line_calculated=1', "GET");
+	}
+	dad.cancelEvent(dad.checkEvent(ev));
+	//return true;
+}
+
+function onGLTransationsEditValidateEntity(win, id, selection){
+	win.ud.ajaxLoadEntity.post('/DB/GetOne', 'entities=' + id + '&for_order=1', "GET");
+}
+
+function onGLTransationsEditSearchEntity(sender){
+	var form = sender.form;
+	var search_str = form.o_entity_name.value;
+	var win = dad.getWindowForChild(sender);
+	var entity_list_search = win.ud.entity_list_search;
+	if(!entity_list_search || !entity_list_search.ud.sab){
+		win.ud.entity_list_search = entity_list_search = newEntitiesListSearchWindow(win.ud.sab);
+	}
+	entity_list_search.searchForMe(search_str, win, onGLTransationsEditValidateEntity);
+	return false;
+}
+
+function newGLTransationsEditWindow(all_sales_buys){
+	var title = dad._getSABTitle(all_sales_buys, 'GL Transaction Edit');
+	var win = dad._windows[title];
+	if(!win){
+		var newId = dad.newSeqId();
+		var Action_id = 'Action' + newId;
+		var btnAction_id = 'btnAction' + newId;
+		var table_id = 'table' + newId;
+		var table_header_id = 'table_header' + newId;
+		var data = {
+			id: newId,
+			form_id: 'form' + newId,
+			Action_id: Action_id,
+			btnAction_id: btnAction_id,
+			table_id: table_id,
+			table_header_id: table_header_id
+		}
+		data.table_height = (dad.isOpera || dad.isIE) ? "8em" : "100%";
+		data.data_table = Jaml.render('2TRDataTable', data);
+
+		var win = dad.newWindow(newId,220,20, 800, 500, _tr(title), Jaml.render('GLTransationsEditWindow', data));
+		//dad.setContentOverflow(newId);
+
+		var data_table = $(table_id);
+		data_table.className = data_table.className + " gl_transactions_lines";
+		var myform = $(data.form_id);
+		
+		win.ud.form = myform;
+		myform.my_field_prefix = "glt_";
+		dad.setupEditForm(myform);
+		
+		
+		myform.processResponse = function(data){
+			var result_array = [];
+			sle = dad.StrLenEncoded();
+			var processed = sle.sle2vecOfvec(data, data.length, result_array);
+			var lines = [];
+			sle.sle2vecOfvec(data, data.length, lines, processed);
+			if(lines.length > 0) lines.shift();
+			dad.fillTableById(lines, newId);
+			return result_array;
+		}
+
+		var mytable = $(table_id);
+		mytable.my_record_header = ["id|ID|0",
+                "code|Code|8",
+                "description|Account|-1",
+                "account_op|Op.|5",
+                "debit|Debit|9|R|ZM",
+                "credit|Credit|9|R|ZM"];
+		mytable.row_click_cb = TransactionLinesOnTableRowClick;
+		mytable._onDelete_cb = function(sender){
+			var tr = dad.getFirstParentWithTagName( sender, "TR" );
+			dad.formFocusNext(sender);
+			tr.parentNode.removeChild(tr);
+		}
+		
+		win.ud.ajaxLoad = new dad.Ajax(dad.formAjaxLoadResponse, newId, false);
+		win.ud.ajaxLines = dad.newAjaxDataTableAjax(win, newId);
+		win.ud.ajaxLoadLine = new dad.Ajax(function(){
+			if(this.status == 200){
+				//retrieve result as an JavaScript object
+				var record = dad.parseSLEData2Object(this.responseText); 
+				var form = $(data.form_id);
+				dad.formFillByRecord(form, record, "tl_");
+				//if(!record.__table__) form.ol_quantity.focus();
+			} else {
+				alert("An error has occured making the request");
+			}
+		}, null, false);
+		
+		win.ud.ajaxLoadEntity = new dad.Ajax(function(id){
+			if(this.status == 200){
+				//retrieve result as an JavaScript object
+				var record = dad.parseSLEData2Object(this.responseText);
+				var form = $(data.form_id);
+				dad.fillFormWithExistingFields(form, record);
+				form.ol_description.focus();
+			} else {
+				alert("An error has occured making the request");
+			}
+		}, null, false);		
+	}
+	dad.bringToFront(win);
+	return win;
+}
+
+Jaml.register('GLTransationsListSearchOn', function(args) {
+	input({type: "radio", name: "search_on", id: "by_description" + args.id, value: "description"}),
+	label({'for': "by_notes" + args.id},  _tr("Notes")),
+	input({type: "radio", name: "search_on", id: "by_date" + args.id, value: "date"}),
+	label({'for': "by_date" + args.id},  _tr("Date"))
+});
+
+function newGLTransationsListSearchWindow(all_sales_buys){
+	var colHeaders = ["id|ID|6",
+                "transaction_date|Date|9",
+                "descriptio|Description|-1",
+                "amount|Amount|12"];
+	var title = dad._getSABTitle(all_sales_buys, 'GL Transactions List/Search');
+	var win = newListSearchWindow(all_sales_buys, title, colHeaders, showGLTransationsEditWindow,
+		"gl_transactions", 'GLTransationsListSearchOn', null, all_sales_buys);
+	var data_table = $("table" + win.ud.win_id);
+	data_table.className = data_table.className + " gl_transactions_list";
+
+	var ajaxOrderType = new dad.Ajax(function(id){
+		if(this.status == 200){
+			//retrieve result as an JavaScript object
+			var records = dad.parseSLEData(this.responseText); 
+			var select = $('group_filter' + id);
+			dad.fillSelectByRecords(select, records, true);
+		}
+	}, win.ud.win_id, false);
+	if(ajaxOrderType){
+		ajaxOrderType.post('/DB/GetList', 'list=order_types&short_list=1&group_order=' + 
+			all_sales_buys, "GET");
+	}
+		
+	return win;
+}

+ 191 - 0
ourbiz/s/ourbiz/groups.js

@@ -0,0 +1,191 @@
+Jaml.register('GroupsListEdit', function(args) {
+	var newIdBy2 = dad.newIdBy2calls;
+	form({action: "/DB/Action", method: "post", id: args.form_id, style: "width:100%;height:100%;"},
+		table({style: "width:100%;height:100%;"},
+			tr(td(div({id:args.div_tree_id, 'class': "divTree", style: "width:99%;overflow:auto;height:18em;"}))),
+			tr(
+				td({'class': "editBox", style: "width:100%;"},
+					fieldset(legend(_tr("Edit Form")),
+						table(
+							tr(
+								td(_tr("ID")), td(_tr("Code")), td(_tr("Print desc.")),
+								td(_tr("Series")), td(_tr("Number")), td(_tr("Grp. 1")),
+								td(_tr("Grp. 2"))
+							),
+							tr(
+								td(input({type: "input", name: "ot_id", size: 6, readonly:"readonly"})), 
+								td(input({type: "input", name: "ot_code", size: 5})), 
+								td(input({type: "input", name: "ot_description_to_print", size: 20})),
+								td(input({type: "input", name: "ot_series", size: 5})),
+								td(input({type: "input", name: "ot_numbering", size: 12})),
+								td(input({type: "input", name: "ot_group_order", size: 6})),
+								td(input({type: "input", name: "ot_subgroup_order", size: 6}))
+							)
+						),
+						table({style: "width:100%;"},
+							tr(
+								td({colspan: 3},
+									input({type: "checkbox", name: "ot_is_active", id: newIdBy2()}),
+									label({'for': newIdBy2()},  _tr("Active")),
+									input({type: "checkbox", name: "ot_with_sales_tax1", id: newIdBy2()}),
+									label({'for': newIdBy2()},  _tr("Sales Tax")),
+									input({type: "checkbox", name: "ot_with_sales_tax_included", id: newIdBy2()}),
+									label({'for': newIdBy2()},  _tr("Sales Tax Included")),
+									input({type: "checkbox", name: "ot_show_sales_tax", id: newIdBy2()}),
+									label({'for': newIdBy2()},  _tr("Show Sales Tax")),
+									input({type: "checkbox", name: "ot_show_prices", id: newIdBy2()}),
+									label({'for': newIdBy2()},  _tr("Show Prices"))
+								)
+							),
+							tr(
+								td(_tr("Description")), 
+								td(
+									input({type: "input", name: "ot_with_payment", size: 1, cls:"bold"}),
+									_tr("With Payment")
+								), 
+								td(
+									input({type: "checkbox", name: "ot_is_expense", id: newIdBy2()}),
+									label({'for': newIdBy2()},  _tr("Is Expense"))
+								)
+							),
+							tr(
+								td(input({type: "input", style: "width:98%;", name: "ot_description"})), 
+								td(
+									input({type: "input", name: "ot_with_inventory", size: 1, cls:"bold"}),
+									_tr("With Inventory")
+								), 
+								td(
+									input({type: "checkbox", name: "ot_is_income", id: newIdBy2()}),
+									label({'for': newIdBy2()},  _tr("Is Income"))
+								)
+							),
+							tr(
+								td(_tr("Notes")), 
+								td(
+									input({type: "input", name: "ot_with_reserve", size: 1, cls:"bold"}),
+									_tr("With Reserve")
+								), 
+								td(Jaml.render('ActionSelect', args))
+							),
+							tr(
+								td({style: "width:60%;"}, input({type: "input", style: "width:98%;", name: "ot_notes"})), 
+								td(
+									input({type: "input", name: "ot_with_credit", size: 1, cls:"bold"}),
+									_tr("With Credit")
+								), 
+								td(input({id: args.btnAction_id, type: "button", name: "btnAction", value: _tr("Action")}))
+							)
+						)
+					)
+				)
+			)
+		)
+	);
+});
+
+function GroupsListEditWindowOnTableRowClick(){
+	var win = dad.getWindowForChild(this);
+	if(win && win.ud.ajaxLoad){
+			win.ud.ajaxLoad.post('/DB/GetOne', 'product_groups=' + this.cells[1].innerHTML , "GET");
+			var form = dad.getFirstParentWithTagName(this, "FORM");
+			if(form) form.ot_code.focus();
+	}
+}
+
+function GroupsListEditWindowRefresh(ajax) {
+	ajax.post('/DB/GetList', 'list=product_groups', "GET");
+}
+
+function GroupsListEditWindowOnSubmit(btn) {
+	return dad.formOnSubmit(GroupsListEditWindowRefresh, this.form, "product_groups")
+}
+
+function doEditGroupID(id){
+	alert(id);
+}
+
+function fillGroupsTree(ctx){
+	var html = [];
+	html.push("<ul>");
+	var len = ctx.records.length;
+	var start_idx = ctx.idx;
+	var curr_parent = ctx.parent;
+	while(ctx.idx<len){
+		var rec = ctx.records[ctx.idx];
+		var myparent = rec[1];
+        if(myparent != curr_parent) break;
+		html.push("<li onclick='doEditGroupID(" + rec[0] + ")'>");
+		html.push(rec[2]);
+		html.push("</li>");
+		++ctx.idx;
+		ctx.parent = rec[0];
+		var result = fillGroupsTree(ctx);
+		if(result) html.push(result);
+	}
+	html.push("</ul>");
+	if(start_idx == ctx.idx) return false;
+	return html.join('');
+}
+
+function fillGroupsTreeById(records, id){
+	var div_tree = $('div_tree' +id);
+	var tree_ctx = {records:records, parent:0, idx:0, div_tree:div_tree};
+	var result = fillGroupsTree(tree_ctx);
+	if(result) div_tree.innerHTML = result;
+}
+	
+function newGroupsListEditWindow(){
+	var title = "Groups List Edit"
+	var win = dad._windows[title];
+	if(!win){
+		var newId = dad.newSeqId();
+		var Action_id = 'Action' + newId;
+		var btnAction_id = 'btnAction' + newId;
+		var div_tree_id = 'div_tree' + newId;
+		var form_id = 'form' + newId;
+		var data = {
+			id: newId,
+			form_id: form_id,
+			Action_id: Action_id,
+			btnAction_id: btnAction_id,
+			div_tree_id: div_tree_id
+		}
+
+		var win = dad.newWindow(newId,220,20, 800, 560, _tr(title), Jaml.render('GroupsListEdit', data));
+		var myform = $(data.form_id);
+		win.ud.form = myform;
+		win.ud.WindowRefresh = GroupsListEditWindowRefresh;
+		myform.my_field_prefix = "ot_";
+		dad.setupEditForm(myform);
+		myform.ajaxSubmit = new dad.Ajax(dad.listEditWindowOnSubmitRespose, newId, false);
+		win.ud.ajaxLoad = new dad.Ajax(dad.formAjaxLoadResponse, newId, false);
+
+		win.ud.ajaxTable = new dad.Ajax(function(id){
+			if(this.status == 200){
+				//retrieve result as an JavaScript object
+				var records = dad.parseJSON(this.responseText);
+				if(!records || !dad.isArray(records) || records.length < 1){
+					alert("An error has occured making the request");
+					return;
+				}
+				fillGroupsTreeById(records, id);
+			} else {
+				alert("An error has occured making the request");
+			}
+		}, newId, false);
+
+		var btn = $(btnAction_id);
+		btn.onclick = GroupsListEditWindowOnSubmit;
+		
+		GroupsListEditWindowRefresh(win.ud.ajaxTable);
+	}
+	dad.bringToFront(win)
+}
+
+function newProductGroupsListEditWindow(){
+	newGroupsListEditWindow();
+}
+
+function newEntityGroupsListEditWindow(){
+	newGroupsListEditWindow();
+}

BIN
ourbiz/s/ourbiz/images/bar.png


BIN
ourbiz/s/ourbiz/images/horSeparator.png


BIN
ourbiz/s/ourbiz/images/logoBackground.png


BIN
ourbiz/s/ourbiz/images/postPic1.jpg


BIN
ourbiz/s/ourbiz/images/postPic2.jpg


BIN
ourbiz/s/ourbiz/images/postPic3.jpg


BIN
ourbiz/s/ourbiz/images/siteBackground.jpg


BIN
ourbiz/s/ourbiz/images/small-arrow.png


+ 249 - 0
ourbiz/s/ourbiz/index.html

@@ -0,0 +1,249 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head>
+<title>OURBIZ</title>
+<meta http-equiv="X-UA-Compatible" content="IE=9" >
+<meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
+<!--<link href="style.css" rel="stylesheet" type="text/css" />-->
+<!--<script type="text/javascript" src="midori.js"></script>-->
+
+<style type="text/css">
+body, html {
+	height: 100%;
+	margin: 0;
+	padding: 0;
+}
+body, input, textarea, select, button {
+font-family: "Helvetica Neue", arial, sans-serif;
+font-size: 100%;
+/*font: 100% verdana, arial, sans-serif;*/
+}
+
+body {
+background-color: #fff;
+margin: 50px;
+background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAYAAAAGBAMAAAAS4vJ7AAAAG1BMVEXS4erj7PHf6O3g6O729vby8vLx8fHh6u%2Fz8%2FOBUUhCAAAAIElEQVQIHWNgFFJkMAlJYShzaWMQS3Nh0EhzY1BxSQMAM84Ew1msm%2BsAAAAASUVORK5CYII%3D");
+}
+
+.box  {
+  background-color: #ffff00;
+  border: 1px solid #000000;
+  color: #000000;
+  padding: 0px;
+  position: absolute;
+}
+
+.bar {
+  background-color: #008080;
+  color: #ffffff;
+  cursor: move;
+  /*font-weight: bold;*/
+  padding: 3px .5em 3px .5em;
+}
+
+.content {
+  padding: 0.5em;
+}
+
+.bold {font-weight:bold;}
+
+.keyLink {
+	position: absolute;
+	top: 1px;
+	right: 2px;
+	width: 20px;
+	height: 20px;
+	border: 1px solid #000000;
+	background-image: none;
+	font-size: 120%;
+	text-align: center;
+	padding: 0;
+	background-color: #ffffff;
+	opacity: .5;
+}
+
+.kl1 {right: +74px;}
+.kl2 {right: +50px;}
+.kl3 {right: +26px;}
+
+.resizeable {
+	border: 2px solid #888; 
+	padding: 2px;
+	background-color: #fff;
+}
+.winDiv {cursor: auto; overflow:auto;}
+.noWinOpt {display:none;}
+.winOpt {width:.3em;}
+.winOpt a {
+	color:#fff; border: 2px solid #aaa; width:.3em; 
+	font-weight:bold; text-decoration: none; 
+	font-size: 80%;
+	padding: 0 .5em 0 .5em;
+}
+.divTable {border: 1px solid #888; background: #FFFFFF;}
+.winContent {padding: 5px; width:98%;height:98%;}
+.winContent td {vertical-align:top;}
+.trvam td {vertical-align:middle;}
+.minw td {width:10px;}
+.draggable, .winheader { cursor: move; }
+.winTitle {
+    color: #eee; background: #696f77; text-shadow: 1px 1px 1px rgba(0,0,0,0.5);
+    background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#696f77), color-stop(100%,#28343b));
+    background: -webkit-linear-gradient(top, #696f77 0%,#28343b 100%); background: -ms-linear-gradient(top, #696f77 0%,#28343b 100%); 
+}
+
+.winHeader {
+	border: 0px solid #ddf; 
+	text-indent:10px; 
+	padding-top:2px;
+	cursor:move;
+}
+
+/*
+fieldset {padding:10px 30px;margin:0;border:1px solid #ccc;-moz-border-radius:1em;-webkit-border-radius:1em;border-radius:1em;border-bottom-width:10px;}
+legend {color:#333;padding:0 10px;margin:0;font-size:1.5em;font-weight:400;}
+*/
+
+.searchBox, .editBox {background-color: #aaf; padding: 2px; margin: 2px;}
+
+/*table*/
+table {border-collapse:collapse;}
+
+.wrappedTable {width:100%;}
+.wrappedTable th {
+  color: #eee; background: #4e8c0b; text-shadow: 1px 1px 1px rgba(0,0,0,0.5);
+	border: 1px solid #fff;
+}
+.wrappedTable tr td {border: 1px solid #ccc; padding-left: 5px; padding-right:5px;}
+.wrappedTable tr:hover td { background: #CAEFFD; color: #0768B3; cursor: pointer; }
+.orders_list tr:nth-child(3) {white-space:nowrap;}
+.orders_lines tfoot tr:nth-last-child(1) {white-space:nowrap;}
+tr.odd {background-color: #cfc;}
+.cell_id, .cell_pct, .cell_money {text-align:right; padding-right:5px;}
+.cell_text {padding-left:5px;}
+.cell_bool {text-align:center;}
+
+.display_none, .display_none_c {display:none;}
+
+
+.searchBox, .editBox {
+	padding: 0;
+	background: #6fb2e5;
+	white-space:nowrap;
+	box-shadow: 0 1px 5px #0061aa, inset 0 10px 20px #b6f9ff;
+	-o-box-shadow: 0 1px 5px #0061aa, inset 0 10px 20px #b6f9ff;
+	-webkit-box-shadow: 0 1px 5px #0061aa, inset 0 10px 20px #b6f9ff;
+	-moz-box-shadow: 0 1px 5px #0061aa, inset 0 10px 20px #b6f9ff;
+}
+
+/*tabs*/
+.editForm {background-color: #ffe0a7;}
+tr.tabContent { 
+	border: 1px solid #c9c3ba; 
+	padding: 0.2em; 
+	background-color: #ffc660; /*#f1f0ee; */
+	height:90%;
+}
+tr.tabContent.hide { display: none; }
+tr.tabs { margin: 0.5em 0 0 0; padding: 0 0 0.3em 0; }
+tr.tabs button { 
+	display: inline;
+	color: #42454a; background-color: #dedbde; 
+	border: 1px solid #c9c3ba; border-bottom: none; 
+	padding: 0.3em; text-decoration: none; 
+}
+tr.tabs button:hover { background-color: #f1f0ee; }
+tr.tabs button.selected { color: #000; background-color: #f1f0ee; 
+	font-weight: bold; padding: 0.3em 0.3em 0.38em 0.3em; 
+}
+.mainmenu tr.tabContent button {width:100%; display:block;padding: 0.5em;}
+.mainmenu tr.tabContent button.cfg {padding: 0.2em;}
+
+/*tbody.firstRight tr > td:first-child {text-align:right;padding-right:5px;}*/
+tr.fcr  td:first-child {text-align:right;padding-right:5px;}
+.tal {text-align:left;}
+/*
+tbody.firstRight tr > td:nth-child(2) input {width:7em;}
+tbody.firstRight tr > td:nth-child(4) input {width:7em;}
+*/
+.size9 {width:7em;}
+.fw {width:99%;}
+
+.hcenter {text-align:center;}
+.vright {text-align:right;}
+.tcvright_c {text-align:right;}
+.cc_days th {
+	background-color:green;
+	color:white;
+	border: 1px solid #fff;
+}
+.cc_days tr td {border: 1px solid green;}
+.cc_month button {font-size: 80%;}
+.cc_month button, .cc_nav button {width: 15%; font-weight: bold;}
+.cc_days td {text-align:center; width:14%;}
+.cc_days input {width:2em;text-align:right;border:0px;background-color:inherit;}
+.cc_days td:hover {background-color:yellow;}
+
+input:focus, textarea:focus, select:focus {background-color: yellow;} 
+input[type=checkbox]:focus + label, input[type=radio]:focus + label {
+	background-color: yellow;
+}
+
+.context-menu {
+	visibility:hidden; /* No, you cannot use display:none; */
+	position:absolute;
+	border:1px solid #666;
+	margin:0;
+	padding:3px;
+	list-style:none;
+	width:100px;
+	background-color:#eee;
+} 
+.context-menu li:hover, .context-menu .context-menu-item-active {
+	background-color:#ccc;
+}
+.disabled {
+	color:#999;
+	background-color:#eee !important;
+}
+
+.divTree li:hover {background-color:#ccc;}
+
+</style>
+
+<!--[if gt IE 5]>
+<!--[if lt IE 9]>
+<style type="text/css" media="screen">
+.winOpt {width:2%;}
+</style>
+<script type="text/javascript" src="excanvas.js"></script>
+<![endif]-->
+<![endif]-->
+
+<script type="text/javascript" src="jaml.js"></script>
+<script type="text/javascript" src="app-base.js"></script>
+<script type="text/javascript" src="dadlib.js"></script>
+<script type="text/javascript" src="ajax-data-table.js"></script>
+<script type="text/javascript" src="barchart.js"></script>
+<script type="text/javascript" src="calendar-chooser.js"></script>
+<script type="text/javascript" src="listsearch.js"></script>
+<script type="text/javascript" src="sales-tax-rates.js"></script>
+<script type="text/javascript" src="groups.js"></script>
+<script type="text/javascript" src="order-types.js"></script>
+<script type="text/javascript" src="payment-types.js"></script>
+<script type="text/javascript" src="measure-units.js"></script>
+<script type="text/javascript" src="warranty-types.js"></script>
+<script type="text/javascript" src="entities.js"></script>
+<script type="text/javascript" src="products.js"></script>
+<script type="text/javascript" src="payments.js"></script>
+<script type="text/javascript" src="orders.js"></script>
+<script type="text/javascript" src="gl-groups.js"></script>
+<script type="text/javascript" src="gl-chart.js"></script>
+<script type="text/javascript" src="gl-transactions.js"></script>
+<script type="text/javascript" src="main-menu.js"></script>
+
+</head>
+<body>
+<div id="logShow"></div>
+</body>
+</html>

+ 345 - 0
ourbiz/s/ourbiz/jaml.js

@@ -0,0 +1,345 @@
+/**
+ * @class Jaml
+ * @author Ed Spencer (http://edspencer.net)
+ * Jaml is a simple JavaScript library which makes HTML generation easy and pleasurable.
+ * Examples: http://edspencer.github.com/jaml
+ * Introduction: http://edspencer.net/2009/11/jaml-beautiful-html-generation-for-javascript.html
+ */
+Jaml = function() {
+  return {
+    templates: {},
+        
+    /**
+     * Registers a template by name
+     * @param {String} name The name of the template
+     * @param {Function} template The template function
+     */
+    register: function(name, template) {
+      this.templates[name] = template;
+    },
+    
+    /**
+     * Renders the given template name with an optional data object
+     * @param {String} name The name of the template to render
+     * @param {Object} thisObj Optional data object
+     * @param {Object} data Optional data object
+     */
+    render: function(name, thisObj, data) {
+      var template = this.templates[name],
+          renderer = new Jaml.Template(template);
+      return renderer.render.apply(renderer, Array.prototype.slice.call(arguments, 1));
+    }
+  };
+}();
+
+/**
+ * @constructor
+ * @param {String} tagName The tag name this node represents (e.g. 'p', 'div', etc)
+ */
+Jaml.Node = function(tagName) {
+  /**
+   * @property tagName
+   * @type String
+   * This node's current tag
+   */
+  this.tagName = tagName;
+  
+  /**
+   * @property attributes
+   * @type Object
+   * Sets of attributes on this node (e.g. 'cls', 'id', etc)
+   */
+  this.attributes = {};
+  
+  /**
+   * @property children
+   * @type Array
+   * Array of rendered child nodes that will be included as this node's innerHTML
+   */
+  this.children = [];
+};
+
+Jaml.Node.prototype = {
+  /**
+   * Adds attributes to this node
+   * @param {Object} attrs Object containing key: value pairs of node attributes
+   */
+  setAttributes: function(attrs) {
+    for (var key in attrs) {
+      //convert cls to class
+      var mappedKey = key == 'cls' ? 'class' : key;
+	  var mappedValue = attrs[key];
+	  if(typeof mappedValue == 'object'){
+		var ary = [];
+		for(var okey in mappedValue){
+			ary.push(okey);
+			ary.push(':');
+			ary.push(mappedValue[okey])
+			ary.push(';');
+		}
+		mappedValue = ary.join('');
+	  }
+      
+      this.attributes[mappedKey] = mappedValue;
+    }
+    return this;
+  },
+  
+  /**
+   * Adds a child string to this node. This can be called as often as needed to add children to a node
+   * @param {String} childText The text of the child node
+   */
+  addChild: function(childText) {
+    this.children.push(childText);
+    return this;
+  },
+  
+  /**
+   * Renders this node with its attributes and children
+   * @param {Number} lpad Amount of whitespace to add to the left of the string (defaults to 0)
+   * @return {String} The rendered node
+   */
+  render: function(lpad) {
+    lpad = lpad || 0;
+    
+    var node      = [],
+        attrs     = [],
+        textnode  = (this instanceof Jaml.TextNode),
+        multiline = this.multiLineTag();
+    
+    
+    //add any left padding
+    if (!textnode) node.push(this.getPadding(lpad));
+    
+    //open the tag
+    node.push("<" + this.tagName);
+
+    for (var key in this.attributes) {
+      attrs.push(key + "=\"" + this.attributes[key] + "\"");
+    }    
+    attrs.sort()
+    //add any tag attributes
+    for (var i=0; i<attrs.length; i++) {
+      node.push(" " + attrs[i]);
+    }
+    
+    if (this.isSelfClosing() && this.children.length==0) {
+      node.push("/>\n");
+    } else {
+      node.push(">");
+      
+      if (multiline) node.push("\n");
+      
+      this.renderChildren(node, this.children, lpad);
+            
+      if (multiline) node.push(this.getPadding(lpad));
+      node.push("</", this.tagName, ">\n");
+    }
+    
+    return node.join("");
+  },
+
+  /**
+   * Renders an array of children
+   * @node {Array} the current array of rendered lines
+   * @children {Array} the child nodes to be rendered
+   * @param {Number} lpad Amount of whitespace to add to the left of the string
+   */
+  renderChildren: function(node, children, lpad) {
+    var childLpad = lpad + 2;
+    
+    for (var i=0; i < children.length; i++) {
+      var child = children[i];
+      if (child instanceof Array) {
+        var nestedChildren = child;
+        this.renderChildren(node, nestedChildren, lpad)
+      } else {
+        node.push(child.render(childLpad));
+      }
+    }    
+  },
+  
+  /**
+   * Returns true if this tag should be rendered with multiple newlines (e.g. if it contains child nodes)
+   * @return {Boolean} True to render this tag as multi-line
+   */
+  multiLineTag: function() {
+    var childLength = this.children.length,
+        multiLine   = childLength > 0;
+    
+    if (childLength == 1 && this.children[0] instanceof Jaml.TextNode) multiLine = false;
+    
+    return multiLine;
+  },
+  
+  /**
+   * Returns a string with the given number of whitespace characters, suitable for padding
+   * @param {Number} amount The number of whitespace characters to add
+   * @return {String} A padding string
+   */
+  getPadding: function(amount) {
+    return new Array(amount + 1).join(" ");
+  },
+  
+  /**
+   * Returns true if this tag should close itself (e.g. no </tag> element)
+   * @return {Boolean} True if this tag should close itself
+   */
+  isSelfClosing: function() {
+    for (var i = this.notSelfClosingTags.length - 1; i >= 0; i--) {
+      if (this.tagName == this.notSelfClosingTags[i]) return false;
+    }
+
+    return true;
+  },
+  
+  /**
+   * @property selfClosingTags
+   * @type Array
+   * An array of all tags that should be self closing
+   */
+  notSelfClosingTags: ['textarea', 'script', 'em', 'strong', 'option', 'select']
+};
+
+Jaml.TextNode = function(text) {
+  this.text = text;
+};
+
+Jaml.TextNode.prototype = {
+  render: function() {
+    return this.text;
+  }
+};
+
+/**
+ * Represents a single registered template. Templates consist of an arbitrary number
+ * of trees (e.g. there may be more than a single root node), and are not compiled.
+ * When a template is rendered its node structure is computed with any provided template
+ * data, culminating in one or more root nodes.  The root node(s) are then joined together
+ * and returned as a single output string.
+ * 
+ * The render process uses two dirty but necessary hacks.  First, the template function is
+ * decompiled into a string (but is not modified), so that it can be eval'ed within the scope
+ * of Jaml.Template.prototype. This allows the second hack, which is the use of the 'with' keyword.
+ * This allows us to keep the pretty DSL-like syntax, though is not as efficient as it could be.
+ */
+Jaml.Template = function(tpl) {
+  /**
+   * @property tpl
+   * @type Function
+   * The function this template was created from
+   */
+  this.tpl = tpl;
+  
+  this.nodes = [];
+};
+
+Jaml.Template.prototype = {
+  /**
+   * Renders this template given the supplied data
+   * @param {Object} thisObj Optional data object
+   * @param {Object} data Optional data object
+   * @return {String} The rendered HTML string
+   */
+  render: function(thisObj, data) {
+    data = data || (thisObj = thisObj || {});
+    
+    //the 'data' argument can come in two flavours - array or non-array. Normalise it
+    //here so that it always looks like an array.
+    if (data.constructor.toString().indexOf("Array") == -1) {
+      data = [data];
+    }
+    
+    with(this) {
+      for (var i=0; i < data.length; i++) {
+        eval("(" + this.tpl.toString() + ").call(thisObj, data[i], i)");
+      };
+    }
+    
+    var roots  = this.getRoots(),
+        output = "";
+    
+    for (var i=0; i < roots.length; i++) {
+      output += roots[i].render();
+    };
+    
+    return output;
+  },
+  
+  /**
+   * Returns all top-level (root) nodes in this template tree.
+   * Templates are tree structures, but there is no guarantee that there is a
+   * single root node (e.g. a single DOM element that all other elements nest within)
+   * @return {Array} The array of root nodes
+   */
+  getRoots: function() {
+    var roots = [];
+    
+    for (var i=0; i < this.nodes.length; i++) {
+      var node = this.nodes[i];
+      
+      if (node.parent == undefined) roots.push(node);
+    };
+    
+    return roots;
+  },
+  
+  tags: [
+		"html", "head", "body", "script", "meta", "title", "link",
+		"div", "p", "span", "a", "img", "br", "hr", "em", "strong",
+		"table", "tr", "th", "td", "thead", "tbody", "tfoot", "colgroup", "col",
+		"ul", "ol", "li", 
+		"dl", "dt", "dd",
+		"button", "canvas",
+		"h1", "h2", "h3", "h4", "h5", "h6", "h7",
+		"form", "fieldset", "legend", "input", "textarea", "label", "select", "option"
+  ]
+};
+
+/**
+ * Adds a function for each tag onto Template's prototype
+ */
+(function() {
+  var tags = Jaml.Template.prototype.tags;
+
+  /**
+   * This function is created for each tag name and assigned to Template's
+   * prototype below
+   */
+  var makeTagHelper = function(tagName) {
+    return function(attrs) {
+      var node = new Jaml.Node(tagName);
+
+      var firstArgIsAttributes =  (typeof attrs == 'object')
+                               && !(attrs instanceof Jaml.Node)
+                               && !(attrs instanceof Jaml.TextNode);
+
+      if (firstArgIsAttributes) node.setAttributes(attrs);
+
+      var startIndex = firstArgIsAttributes ? 1 : 0;
+
+      for (var i=startIndex; i < arguments.length; i++) {
+        var arg = arguments[i];
+
+        if (typeof arg == "string" || arg == undefined) {
+          arg = new Jaml.TextNode(arg || "");
+        }
+
+        if (arg instanceof Jaml.Node || arg instanceof Jaml.TextNode) {
+          arg.parent = node;
+        }
+
+        node.addChild(arg);
+      };
+
+      this.nodes.push(node);
+
+      return node;
+    };
+  };
+
+  for (var i = 0, tag; tag = tags[i]; i++) {
+    Jaml.Template.prototype[tag] = makeTagHelper(tag);
+  };
+})();
+

+ 121 - 0
ourbiz/s/ourbiz/length-encoded.js

@@ -0,0 +1,121 @@
+var LengthEncodeData = (function(){
+	var IBYTE1 = 255;
+	var IBYTE2 = (255*255);
+	var IBYTE3 = (255*255*255);
+	var IBYTE4 = (255*255*255*255);
+
+	var SIZE1BYTE = 250;
+	var SIZE2BYTE = 251;
+	var SIZE3BYTE = 252;
+	var SIZE4BYTE = 253;
+
+	var SLSMARK = 254;
+	var SLSEND = 255;
+
+	this.sls2callable = function(sls, sls_size, use_str){
+		if(sls_size == 0) return 0;
+		var p = 0;
+		var size;
+		var data_count = 0, data_len = 0;
+		while(p != SLSEND) //data finished now follow digest
+		{
+			size = sls.charAt(p++);
+			if(size > 249)
+			{
+				if(size == SIZE1BYTE)
+				{
+					//data bigger than 250 and less 500 next byte has more info
+					size += sls.charAt(p++);
+				}
+				else if(size == SIZE2BYTE)
+				{
+					//data bigger than 250 next two bytes has more info
+					size = sls.charAt(p++) * IBYTE1;
+					size += sls.charAt(p++);
+				}
+				else if(size == SIZE3BYTE)
+				{
+					//data bigger than 250 next three bytes has more info
+					size = sls.charAt(p++) * IBYTE2;
+					size += sls.charAt(p++) * IBYTE1;
+					size += sls.charAt(p++);
+				}
+				else if(size == SIZE4BYTE)
+				{
+					//data bigger than 250 next four bytes has more info
+					size = sls.charAt(p++) * IBYTE3;
+					size += sls.charAt(p++) * IBYTE2;
+					size += sls.charAt(p++) * IBYTE1;
+					size += sls.charAt(p++);
+				}
+				else if(size == SLSMARK)
+				{
+					//reserved can be used for multi part data, metadata, digest, ...
+					break;
+				}
+			}
+			use_str(p, size);
+			p += size;
+			data_count++;
+			data_len += size;
+			if(data_len > sls_size)
+			{
+				//something went wrong here
+				throw "We got more data than expected !";
+				break;
+			}
+		}
+		return ++p;
+	}
+
+	this.add2sls = function(sls, str, size){
+		var next_size, tmp_size;
+		if(size < 250)
+		{
+			sls.append(size);
+		}
+		else if(size < 500)
+		{
+			sls.append(SIZE1BYTE);
+			next_size = size - 250;
+			sls.append(next_size);
+		}
+		else if(size < IBYTE2)
+		{
+			sls.append(SIZE2BYTE);
+			next_size = size/IBYTE1;
+			sls.append(next_size);
+			next_size = size%IBYTE1;
+			sls.append(next_size);
+		}
+		else if(size < IBYTE3)
+		{
+			sls.append(SIZE3BYTE);
+			next_size = size/IBYTE2;
+			sls.append(next_size);
+			tmp_size = size%IBYTE2;
+			next_size = tmp_size/IBYTE1;
+			sls.append(next_size);
+			next_size = tmp_size%IBYTE1;
+			sls.append(next_size);
+		}
+		else if(size < IBYTE4)
+		{
+			sls.append(SIZE4BYTE);
+			next_size = size/IBYTE3;
+			sls.append(next_size);
+			tmp_size = size%IBYTE3;
+			next_size = tmp_size/IBYTE2;
+			sls.append(next_size);
+			tmp_size = tmp_size%IBYTE2;
+			next_size = tmp_size/IBYTE1;
+			sls.append(next_size);
+			next_size = tmp_size%IBYTE1;
+			sls.append(next_size);
+		}
+		sls.append(str, size);
+		return size;
+	}
+	
+	return this;
+})();

+ 164 - 0
ourbiz/s/ourbiz/listsearch.js

@@ -0,0 +1,164 @@
+Jaml.register('ListSearch', function(args) {
+	form({id: args.form_id, style: "width:100%;height:100%;", onsubmit:"return false;"},
+		table({style: "width:100%;height:100%;"},
+			tr(
+				td({style:"height:12px; white-space:nowrap;"}, 
+					select({id: 'group_filter' + args.id, name:"group_id", style: "width:100%;"})
+				)
+			),
+			args.data_table,
+			tr(
+				td({'class': "editBox", style: "width:100%;height:50px; white-space:nowrap;"},
+					fieldset(legend(_tr("Search")),
+						table(
+							tr( td({'class': "radioBox", colspan:2}, args.search_on ) ),
+							tr(
+								td({colspan:2},
+									input({type: "text", name: "search_str"}),
+									input({id: args.btnSearch_id, type: "button", name: "btnSearch", value: _tr("Search")}),
+									input({type: "text", name: "query_limit", size: 4, value: "50"})
+								),
+								td({rowspan:3}, img({id: 'ls_img_' +args.id}))
+							),
+							tr(
+								td(
+									input({type: "button", name: "btnSelect", value: _tr("Select")}),
+									input({type: "button", value: _tr("Update"), onclick: "newCalendarChooserWindow()"}),
+									input({type: "button", value: _tr("Insert")})
+								),
+								td(args.search_on2)
+							)
+						)
+					)
+				)
+			)
+		)
+	)
+});
+
+function ListSearchWindowOnTableRowClick(ev){
+	var table = dad.getTableForTableChild(this);
+	if(table){
+		var win = dad.getWindowForChild(table);
+		if(win && win.ud.editWindow) win.ud.editWindow(win.ud.all_sales_buys, win, this.cells[1].innerHTML);
+	}
+	dad.cancelEvent(dad.checkEvent(ev));
+	//return true;
+}
+
+function ListSearchWindowOnTableFirstColClick(ev){
+	var win = dad.getWindowForChild(this);
+	var id = this.innerHTML;
+	if(win && win.ud.editWindow) {
+		if(win.ud.callerFuncCB){
+			var selection = [];
+			var clickedSelection = win.ud.mySelection;
+			for(var elm in clickedSelection){
+				if(clickedSelection[elm]){
+					selection.push(elm);
+				}
+				win.ud.mySelection = {};
+			}
+			dad.closeTopParent(this);
+			win.ud.callerFuncCB(win.ud.caller, id, selection);
+			win.ud.callerFuncCB = null;
+		} else {
+			win.ud.editWindow(win.ud.all_sales_buys, win, id);
+		}
+		dad.cancelEvent(dad.checkEvent(ev));
+	}
+	//return true;
+}
+
+Jaml.register('ListSearchOn2', function(args) {
+	input({type: "checkbox", id: "by_sales" + args.id, value: "by_sales"}),
+	label({'for': "by_sales" + args.id},  _tr("Sales")),
+	input({type: "checkbox", id: "by_buys" + args.id, value: "by_buys"}),
+	label({'for': "by_buys" + args.id},  _tr("Buys"))
+});
+
+function newListSearchWindow(all_sales_buys, title, colHeaders, editWindow, dbTable, search_on, search_on2, db_extra_type){
+	var win = dad._windows[title];
+	if(!win){
+		var newId = dad.newSeqId();
+		var btnSearch_id = 'btnSearch' + newId;
+		var table_id = 'table' + newId;
+		var table_header_id = 'table_header' + newId;
+		var obj_id = {id:newId};
+		if(!search_on2) search_on2 = 'ListSearchOn2';
+		var data = {
+			id: newId,
+			form_id: 'form_list_search' + newId,
+			'btnSearch_id': btnSearch_id,
+			'table_id': table_id,
+			'table_header_id': table_header_id,
+			search_on: Jaml.render(search_on, obj_id),
+			search_on2: Jaml.render(search_on2, obj_id)
+		}
+		data.table_height = (dad.isIE && (dad.isIE == 9)) ? "20em" : "19em";
+		data.data_table = Jaml.render('2TRDataTable', data);
+
+		var win = dad.newWindow(newId,220,20, 800, 500, title, Jaml.render('ListSearch', data));
+		win.ud.editWindow = editWindow;
+		win.ud.all_sales_buys = all_sales_buys;
+		win.ud.win_id = newId;
+
+		var myform = $(data.form_id);
+		win.ud.form = myform;
+		dad.setupEditForm(myform);
+
+		myform.search_str.onkeydown = function(evt){
+			var evt = dad.checkEvent(evt);
+			if (evt.altKey || evt.ctrlKey || evt.shiftKey) return true;
+			if(dad.getEventKey(evt) == 13){
+				this.form.btnSearch.onclick();
+				return false;
+			}
+			return dad.formInputTextOnKeydown(evt);
+		}
+		
+		win.searchForMe = function(search_str, call_win, cbFunc){
+			win.ud.caller = call_win;
+			myform.search_str.value = search_str;
+			win.ud.callerFuncCB = cbFunc;
+			myform.btnSearch.onclick();
+		}
+		
+		var group_filter = $('group_filter' + newId);
+		group_filter.onchange=function(evt){
+			var btn = $(btnSearch_id);
+			btn.onclick();
+		}
+
+		var btn = $(btnSearch_id);
+		btn.dbTable = dbTable;
+		btn.dbExtraType = db_extra_type;
+		var mytable = $(table_id);
+		mytable.my_record_header = colHeaders;
+		win.ud.mySelection = {};
+		mytable.row_dblclick_cb = ListSearchWindowOnTableRowClick;
+		mytable.first_row_click_cb = ListSearchWindowOnTableFirstColClick;
+		mytable.myPrevFocus = myform['group_filter'+newId];
+		mytable.myNextFocus = myform.search_str;
+		mytable.row_over_cb =  function(evt){};
+			
+		mytable.selection_click_cb = function(evt){
+			dad.checkEvent(evt);
+			var sender = dad.getEventSource(evt);
+			var tr = dad.getFirstParentWithTagName(sender, "TR");
+			var id = tr.cells[1].innerHTML;
+			win.ud.mySelection[id] = sender.checked;
+		}
+		btn.ajax = dad.newAjaxDataTableAjax(win, newId);
+		btn.onclick = function(){
+			this.form._dbrecord = {};
+			var values = dad.getFormData(this.form, this.dbTable);
+			//ajax.post(form.action, values.join('&'), 'POST', null);
+			this.ajax.post('/DB/GetList?list=' + this.dbTable + '&search=1&sab=' + this.dbExtraType,  values.join('&'), 'POST');
+		};
+		btn.onclick();
+	}
+	dad.bringToFront(win)
+	win.ud.form.search_str.focus();
+	return win;
+}

+ 129 - 0
ourbiz/s/ourbiz/main-menu.js

@@ -0,0 +1,129 @@
+function newMainOrdersListSearchWindow(otype){
+	//dad.loadScript('orders.js');
+	if(window.newOrdersListSearchWindow) newOrdersListSearchWindow(otype);
+}
+
+function newMainPaymentsListSearchWindow(otype){
+	//dad.loadScript('products.js');
+	if(window.newPaymentsListSearchWindow) newPaymentsListSearchWindow(otype);
+}
+
+function newMainProductsListSearchWindow(otype){
+	//dad.loadScript('products.js');
+	if(window.newProductsListSearchWindow) newProductsListSearchWindow(otype);
+}
+
+function newMainEntitiesListSearchWindow(otype){
+	//dad.loadScript('entities.js');
+	if(window.newEntitiesListSearchWindow) newEntitiesListSearchWindow(otype);
+}
+
+Jaml.register('MainMenu', function(args) {
+	form({id: args.form_id, onsubmit:"return false;"},
+		table({'class':"content mainmenu"},
+			tr({id: args.tabs_id, "class": "tabs"},
+				td(
+					button({name:"sales" + args.id}, _tr('Sales')),
+					button({name:"buys" + args.id}, _tr('Buys')),
+					button({name:"all" + args.id}, _tr('All')),
+					button({name:"gl" + args.id}, _tr('GL')),
+					button({name:"config" + args.id}, _tr('Config'))
+				)
+			),
+			tr({id:"sales" + args.id, 'class':"tabContent"},
+				td(
+					button({onclick:"newMainOrdersListSearchWindow('S')"}, _tr('Sales')),
+					button({onclick:"newMainPaymentsListSearchWindow('S')"}, _tr('Payments')),
+					button({onclick:"newMainProductsListSearchWindow('S')"}, _tr('Products')),
+					button({onclick:"newMainEntitiesListSearchWindow('S')"}, _tr('Entities'))
+				)
+			),
+			tr({id:"buys" + args.id, 'class':"tabContent"},
+				td(
+					button({onclick:"newMainOrdersListSearchWindow('B')"}, _tr('Buys')),
+					button({onclick:"newMainPaymentsListSearchWindow('B')"}, _tr('Payments')),
+					button({onclick:"newMainProductsListSearchWindow('B')"}, _tr('Products')),
+					button({onclick:"newMainEntitiesListSearchWindow('B')"}, _tr('Entities'))
+				)
+			),
+			tr({id:"all" + args.id, 'class':"tabContent"},
+				td(
+					button({onclick:"newMainOrdersListSearchWindow()"}, _tr('Orders')),
+					button({onclick:"newMainPaymentsListSearchWindow()"}, _tr('Payments')),
+					button({onclick:"newMainProductsListSearchWindow()"}, _tr('Products')),
+					button({onclick:"newMainEntitiesListSearchWindow()"}, _tr('Entities'))
+				)
+			),
+			tr({id:"gl" + args.id, 'class':"tabContent"},
+				td(
+					button({onclick:"newGLGroupsListEditWindow()"}, _tr('Groups')),
+					button({onclick:"newGLChartListSearchWindow()"}, _tr('Accounts')),
+					button({onclick:"newGLTransationsListSearchWindow()"}, _tr('Transactions'))
+				)
+			),
+			tr({id:"config" + args.id, 'class':"tabContent"},
+				td(
+					button({onclick:"newAjaxDataTableWindow()", cls:"cfg"}, _tr('Ajax Data Table')),
+					button({onclick:"newSalesTaxListEditWindow()", cls:"cfg"}, _tr('Sales taxes')),
+					button({onclick:"newOrderTypesListEditWindow()", cls:"cfg"}, _tr('Order Types')),
+					button({onclick:"newPaymentTypesListEditWindow()", cls:"cfg"}, _tr('Payment Types')),
+					button({onclick:"newMeasureUnitsListEditWindow()", cls:"cfg"}, _tr('Measure Units')),
+					button({onclick:"newWarrantyTypesListEditWindow()", cls:"cfg"}, _tr('Warranty Types')),
+					button({onclick:"newSalesTaxListEditWindow()", cls:"cfg"}, _tr('Images')),
+					button({onclick:"newProductGroupsListEditWindow()", cls:"cfg"}, _tr('Product Groups')),
+					button({onclick:"newEntityGroupsListEditWindow()", cls:"cfg"}, _tr('Entity Groups')),
+					button({onclick:"newSalesTaxListEditWindow()", cls:"cfg"}, _tr('App Config')),
+					button({onclick:"newSalesTaxListEditWindow()", cls:"cfg"}, _tr('Open Database'))
+				)
+			)
+		)
+	)
+});
+
+function newMainMenuWindow(){
+	var title = _tr("Main Menu");
+	var win = dad._windows[title];
+	if(!win){
+		var newId = dad.newSeqId();
+		var tabs_id = 'tabs' + newId;
+		var data = {
+			id: newId,
+			form_id: 'form' + newId,
+			tabs_id: tabs_id
+		}
+		win = dad.newWindow(newId,10,10, 0, 0, title, Jaml.render('MainMenu', data), true, true);
+		win.className = win.className + ' mainWindow';
+		if(dad.isIE && (dad.isIE < 9)) win.firstChild.style.width = '';
+		var tabsObj = $(tabs_id);
+		dad.initTab(tabsObj)
+		//dad.setupKeyboardNavigation(tabsObj, ["A", "LI"]);
+		var myform = $(data.form_id);
+		dad.setupEditForm(myform);
+	}
+	dad.bringToFront(win);
+
+	dad.addEvent(document,'contextmenu',function(e){
+		var evt = dad.checkEvent(event);
+		if(evt.srcElement == document){ //only with keyboard menu key
+			//We don't want the browsers Context menu appearing - so disable it.
+			dad.cancelEvent(evt, true);
+			dad.bringToFront(win);
+		}
+	});	
+}
+
+var _transalations_ = {
+	'Sales' : 'Ventas',
+	'Buys' : 'Compras',
+	'Payments' : 'Pagos',
+	'Products' : 'Productos',
+	'Entity' : 'Entidad',
+	'Entities' : 'Entidades',
+	'List Search' : 'Listado búsqueda',
+	'Main Menu' : 'Menu Principal'
+}
+
+window.onload = function(){
+	dad.onLoadInit();
+	newMainMenuWindow();
+}

+ 103 - 0
ourbiz/s/ourbiz/measure-units.js

@@ -0,0 +1,103 @@
+Jaml.register('MeasureUnitsListEdit', function(args) {
+	form({action: "/DB/Action", method: "post", id: args.form_id, style: "width:100%;height:100%;"},
+		table({style: "width:100%;height:100%;"},
+			args.data_table,
+			tr(
+				td({'class': "editBox", style: "width:100%;"},
+					fieldset(legend(_tr("Edit Form")),
+						table(
+							tr(
+								td(_tr("ID")), td(_tr("CDate")), td(_tr("MDate")), td("&nbsp;")
+							),
+							tr(
+								td(input({type: "input", name: "mu_id", size: 12, readonly:"1"})), 
+								td(input({type: "input", name: "mu_cdate", size: 12, readonly:"1"})), 
+								td(input({type: "input", name: "mu_mdate", size: 12, readonly:"1"})),
+								td(input({type: "checkbox", name: "mu_is_active"}, _tr("Active")))
+							),
+							tr(
+								td(_tr("Code")), 
+								td({colspan:3}, _tr("Description"))
+							),
+							tr(
+								td(input({type: "input", name: "mu_code", size: 12})), 
+								td({colspan:3},input({type: "input", name: "mu_description", style: "width:98%;"})) 
+							),
+							tr(
+								td({colspan:3}, "&nbsp"), 
+								td({style: "width:5%;padding-left:1em;"},
+									Jaml.render('ActionSelect', args),
+									br(),
+									input({id: args.btnAction_id, type: "button", name: "btnAction", value: _tr("Action")})
+									)
+							)
+						)
+					)
+				)
+			)
+		)
+	);
+});
+
+function MeasureUnitsListEditWindowOnTableRowClick(){
+	var win = dad.getWindowForChild(this);
+	if(win && win.ud.ajaxLoad){
+			win.ud.ajaxLoad.post('/DB/GetOne', 'measure_units=' + this.cells[1].innerHTML , "GET");
+			var form = dad.getFirstParentWithTagName(this, "FORM");
+			if(form) form.mu_code.focus();
+	}
+}
+
+function MeasureUnitsListEditWindowRefresh(ajax) {
+	ajax.post('/DB/GetList', 'list=measure_units', "GET");
+}
+
+function MeasureUnitsListEditWindowOnSubmit(btn) {
+	return dad.formOnSubmit(MeasureUnitsListEditWindowRefresh, this.form, "measure_units")
+}
+	
+function newMeasureUnitsListEditWindow(){
+	var title = "Measure Units List Edit"
+	var win = dad._windows[title];
+	if(!win){
+		var newId = dad.newSeqId();
+		var Action_id = 'Action' + newId;
+		var btnAction_id = 'btnAction' + newId;
+		var table_id = 'table' + newId;
+		var table_header_id = 'table_header' + newId;
+		var form_id = 'form' + newId;
+		var data = {
+			id: newId,
+			form_id: form_id,
+			Action_id: Action_id,
+			btnAction_id: btnAction_id,
+			table_id: table_id,
+			table_header_id: table_header_id
+		}
+		data.table_height = "50%";
+		data.data_table = Jaml.render('2TRDataTable', data);
+
+		var win = dad.newWindow(newId,220,20, 550, 450, _tr(title), Jaml.render('MeasureUnitsListEdit', data));
+		var myform = $(data.form_id);
+		win.ud.form = myform;
+		win.ud.WindowRefresh = MeasureUnitsListEditWindowRefresh;
+		myform.my_field_prefix = "mu_";
+		dad.setupEditForm(myform);
+		myform.ajaxSubmit = new dad.Ajax(dad.listEditWindowOnSubmitRespose, newId, false);
+		win.ud.ajaxLoad = new dad.Ajax(dad.formAjaxLoadResponse, newId, false);
+
+		var mytable = $(table_id);
+		mytable.my_record_header = ["id|ID|0",
+                "code|Code|8",
+                "description|Description|-1",
+                "is_active|Active|5|C|B"];
+		mytable.row_click_cb = MeasureUnitsListEditWindowOnTableRowClick;
+		win.ud.ajaxTable = new dad.newAjaxDataTableAjax(win, newId);
+
+		var btn = $(btnAction_id);
+		btn.onclick = MeasureUnitsListEditWindowOnSubmit;
+		
+		MeasureUnitsListEditWindowRefresh(win.ud.ajaxTable);
+	}
+	dad.bringToFront(win)
+}

+ 1 - 0
ourbiz/s/ourbiz/mk-it.bat

@@ -0,0 +1 @@
+copy jaml.js+app-base.js+dadlib.js+ajax-data-table.js+barchart.js+calendar-chooser.js+listsearch.js+sales-tax-rates.js+order-types.js+payment-types.js+measure-units.js+entities.js+products.js+orders.js+main-menu.js ourbiz.js

+ 117 - 0
ourbiz/s/ourbiz/mobile.css

@@ -0,0 +1,117 @@
+html, body, div, span, applet, object, iframe, h1, h2, h3, h4, h5, h6, p, blockquote, pre, a, abbr, acronym, address, big, cite, code, del, dfn, em, img, ins, kbd, q, s, samp, small, strike, strong, sub, sup, tt, var, b, u, i, center, dl, dt, dd, ol, ul, li, fieldset, form, label, legend, table, caption, tbody, tfoot, thead, tr, th, td, article, aside, canvas, details, embed, figure, figcaption, footer, header, hgroup, menu, nav, output, ruby, section, summary, time, mark, audio, video {
+  margin: 0;
+  padding: 0;
+  border: 0;
+  font-size: 100%;
+  font: inherit;
+  vertical-align: baseline;
+  outline: none;
+}
+html { height: 101%; }
+body { font-size: 62.5%; line-height: 1; font-family: Verdana, Arial, Tahoma, sans-serif; }
+
+article, aside, details, figcaption, figure, footer, header, hgroup, menu, nav, section { display: block; }
+ol, ul { list-style: none; }
+
+blockquote, q { quotes: none; }
+blockquote:before, blockquote:after, q:before, q:after { content: ''; content: none; }
+
+table { border-collapse: collapse; border-spacing: 0; }
+img { border: 0; max-width: 100%; }
+
+a { text-decoration: none; }
+
+/** content display **/
+#view { display: block; max-width: 800px; padding: 0; margin: 0; }
+
+#container { display: block; margin-top: 55px; }
+#container ul { }
+#container ul a li { 
+	display: block;
+	width: 100%;
+	height: 90px;
+	border-bottom: 1px solid #b9b9b9;
+	border-top: 1px solid #f7f7f7;
+	background: #ebebeb;
+  background-image: -webkit-gradient(linear, 0% 0%, 0% 100%, from(#ffffff) to(#ebebeb));
+  background-image: -webkit-linear-gradient(top, #ffffff, #ebebeb);
+  background-image:    -moz-linear-gradient(top, #ffffff, #ebebeb);
+  background-image:      -o-linear-gradient(top, #ffffff, #ebebeb);
+  background-image:         linear-gradient(top, #ffffff, #ebebeb); 
+}
+
+#container ul a { display: block; position: relative; width: 100%; }
+#container ul li h2 { font-size: 2.1em; line-height: 1.3em; font-weight: normal; letter-spacing: -0.03em; padding-top: 4px; color: #55678d; }
+#container ul li p.desc { color: #555; font-family: Arial, sans-serif; font-size: 1.3em; line-height: 1.3em; white-space: nowrap; overflow: hidden; }
+
+#container ul li .price { position: absolute; bottom: 10px; left: 90px; font-size: 1.2em; font-weight: bold; color: #6ea247; }
+
+#container ul li img.thumbnail { 
+	background: #fff;
+	display: inline-block;
+	float: left;
+	padding: 2px;
+	margin-top: 6px;
+	margin-left: 5px;
+	margin-right: 8px;
+  -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.25);
+  -moz-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.25);
+  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.25);
+}
+
+#container ul a:hover li h2 { color: #7287b1; }
+#container ul a:hover li p.desc { color: #757575; }
+
+#container ul a:hover li {
+background: #efefef;
+background-image: -webkit-gradient(linear, 0% 0%, 0% 100%, from(#ffffff) to(#efefef));
+background-image: -webkit-linear-gradient(top, #ffffff, #efefef);
+background-image:    -moz-linear-gradient(top, #ffffff, #efefef);
+background-image:      -o-linear-gradient(top, #ffffff, #efefef);
+background-image:         linear-gradient(top, #ffffff, #efefef);
+}
+
+/** top header bar **/
+header { 
+display: block;
+position: fixed; 
+top: 0;
+z-index: 9999;
+height: 55px;
+width: 100%;
+max-width: 800px;
+border-bottom: 1px solid #262422;
+-webkit-box-shadow: 0 2px 2px rgba(0, 0, 0, 0.4); 
+-moz-box-shadow: 0 2px 2px rgba(0, 0, 0, 0.4); 
+box-shadow: 0 2px 2px rgba(0, 0, 0, 0.4);
+background: #5a5955;
+background: -moz-linear-gradient(top,  #5a5955 0%, #51504c 50%, #494744 51%, #3f3d3a 100%);
+background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#5a5955), color-stop(50%,#51504c), color-stop(51%,#494744), color-stop(100%,#3f3d3a));
+background: -webkit-linear-gradient(top,  #5a5955 0%,#51504c 50%,#494744 51%,#3f3d3a 100%);
+background: -o-linear-gradient(top,  #5a5955 0%,#51504c 50%,#494744 51%,#3f3d3a 100%);
+background: -ms-linear-gradient(top,  #5a5955 0%,#51504c 50%,#494744 51%,#3f3d3a 100%);
+background: linear-gradient(to bottom,  #5a5955 0%,#51504c 50%,#494744 51%,#3f3d3a 100%);
+filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#5a5955', endColorstr='#3f3d3a',GradientType=0 );
+}
+
+header h1 { font-size: 2.4em; font-family: Tahoma, Arial, sans-serif; font-weight: bold; line-height: 55px; text-align: center; color: #efefef; text-shadow: 1px 1px 0px #000; }
+
+
+/** basic media queries **/
+@media only screen and (max-width: 480px) {
+	#container ul li h2 { font-size: 1.75em; }
+	
+	#container ul li img.thumbnail { margin-top: 2px; }
+}
+
+@media only screen and (max-width: 320px) {
+	#container ul li p.desc { display: none; }
+}
+
+
+/** clearfix **/
+.clearfix:after { content: "."; display: block; clear: both; visibility: hidden; line-height: 0; height: 0; }
+.clearfix { display: inline-block; }
+ 
+html[xmlns] .clearfix { display: block; }
+* html .clearfix { height: 1%; }

+ 100 - 0
ourbiz/s/ourbiz/mobile.html

@@ -0,0 +1,100 @@
+<!doctype html>
+<html lang="en">
+<head>
+  <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+  <title>Simple Mobile Listview</title>
+  <meta name="author" content="Jake Rocheleau">
+	<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
+	<meta name="HandheldFriendly" content="true">
+	<meta name="viewport" content="width=device-width, initial-scale=1,maximum-scale=1,user-scalable=no">
+  <link rel="stylesheet" type="text/css" href="mobile.css">
+<!--[if lt IE 9]>
+  <script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
+  <script src="http://css3-mediaqueries-js.googlecode.com/svn/trunk/css3-mediaqueries.js"></script>
+<![endif]-->
+</head>
+
+<body>
+	<div id="view">
+		<header>
+			<h1>Products</h1>
+		</header>
+	
+		<div id="container">
+			<ul>
+				<!-- row 01 -->
+				<a href="#"><li class="clearfix">
+						<img src="images/modern-castle-kitchen.png" alt="thumb" class="thumbnail">
+						<h2>Full-Room Mansion with Open Kitchen</h2>
+						<p class="desc">Rental located in Pheonix, AZ. 2 bedrooms 1.5 baths. </p>
+						
+						<span class="price">$2,650/month</span>
+				</li></a>
+				
+				<!-- row 02 -->
+				<a href="#"><li class="clearfix">
+					<img src="images/penthouse-with-bar.png" alt="Modern penthouse bar" class="thumbnail">
+					<h2>Modern Penthouse Highrise with Bar</h2>
+					<p class="desc">Rental located in New York City, NY. 1 bedroom 1 bath.</p>
+					
+					<span class="price">$1,800/month</span>
+				</li></a>
+				
+				<!-- row 03 -->
+				<a href="#"><li class="clearfix">
+					<img src="images/single-room-loft.png" alt="An adventure room with sofa" class="thumbnail">
+					<h2>Single-Room 3rd Floor Rental</h2>
+					<p class="desc">Rental located in New York City, NY. 1 bedroom 2 baths.</p>
+					
+					<span class="price">$1,350/month</span>
+				</li></a>
+				
+				<!-- row 04 -->
+				<a href="#"><li class="clearfix">
+					<img src="images/dining-room-duplex.png" alt="2nd story duplex apartment" class="thumbnail">
+					<h2>2nd Floor Duplex Apartment with Balcony</h2>
+					<p class="desc">Rental located in Madison, WI. 2 bedrooms 1 bath.</p>
+					
+					<span class="price">$1,650/month</span>
+				</li></a>
+				
+				<!-- row 05 -->
+				<a href="#"><li class="clearfix">
+					<img src="images/yacht-style-bedroom.png" alt="unique yacht-style bedroom set" class="thumbnail">
+					<h2>Open Apartment with Yacht-Style Interior</h2>
+					<p class="desc">Rental located in Los Angeles, CA. 2 bedrooms 1 bath.</p>
+					
+					<span class="price">$2,100/month</span>
+				</li></a>
+				
+				<!-- row 06 -->
+				<a href="#"><li class="clearfix">
+					<img src="images/kids-room-apartment.png" alt="big apartment with a kids room" class="thumbnail">
+					<h2>Large Apartment Space with Children's Bedroom</h2>
+					<p class="desc">Rental located in New Haven, CT. 3 bedrooms 1 bath.</p>
+					
+					<span class="price">$2,850/month</span>
+				</li></a>
+				
+				<!-- row 07 -->
+				<a href="#"><li class="clearfix">
+					<img src="images/circular-apartment.png" alt="Open circular apartment complex" class="thumbnail">
+					<h2>Circular Living Room Space 1st Floor</h2>
+					<p class="desc">Rental located in Greensboro, NC. 2 bedrooms 1 bath.</p>
+					
+					<span class="price">$1,890/month</span>
+				</li></a>
+				
+				<!-- row 08 -->
+				<a href="#"><li class="clearfix">
+					<img src="images/beautiful-villa-ocean.png" alt="beautiful villa rental overlooking the ocean" class="thumbnail">
+					<h2>Beachfront Ocean Villa Rental</h2>
+					<p class="desc">Rental located in Naxos, Greece. 2 bedrooms 2 bath.</p>
+					
+					<span class="price">$2,200/month</span>
+				</li></a>
+			</ul>
+		</div>
+	</div>
+</body>
+</html>

+ 9 - 0
ourbiz/s/ourbiz/neat.css

@@ -0,0 +1,9 @@
+.cm-s-neat span.cm-comment { color: #a86; }
+.cm-s-neat span.cm-keyword { line-height: 1em; font-weight: bold; color: blue; }
+.cm-s-neat span.cm-string { color: #a22; }
+.cm-s-neat span.cm-builtin { line-height: 1em; font-weight: bold; color: #077; }
+.cm-s-neat span.cm-special { line-height: 1em; font-weight: bold; color: #0aa; }
+.cm-s-neat span.cm-variable { color: black; }
+.cm-s-neat span.cm-number, .cm-s-neat span.cm-atom { color: #3a3; }
+.cm-s-neat span.cm-meta {color: #555;}
+.cm-s-neat span.cm-link { color: #3a3; }

+ 165 - 0
ourbiz/s/ourbiz/order-types.js

@@ -0,0 +1,165 @@
+Jaml.register('OrderTypesListEdit', function(args) {
+	var newIdBy2 = dad.newIdBy2calls;
+	form({action: "/DB/Action", method: "post", id: args.form_id, style: "width:100%;height:100%;"},
+		table({style: "width:100%;height:100%;"},
+			args.data_table,
+			tr(
+				td({'class': "editBox", style: "width:100%;"},
+					fieldset(legend(_tr("Edit Form")),
+						table(
+							tr(
+								td(_tr("ID")), td(_tr("Code")), td(_tr("Print desc.")),
+								td(_tr("Series")), td(_tr("Number")), td(_tr("Grp. 1")),
+								td(_tr("Grp. 2"))
+							),
+							tr(
+								td(input({type: "input", name: "ot_id", size: 6, readonly:"readonly"})), 
+								td(input({type: "input", name: "ot_code", size: 5})), 
+								td(input({type: "input", name: "ot_description_to_print", size: 20})),
+								td(input({type: "input", name: "ot_series", size: 5})),
+								td(input({type: "input", name: "ot_numbering", size: 12})),
+								td(input({type: "input", name: "ot_group_order", size: 6})),
+								td(input({type: "input", name: "ot_subgroup_order", size: 6}))
+							)
+						),
+						table({style: "width:100%;"},
+							tr(
+								td({colspan: 3},
+									input({type: "checkbox", name: "ot_is_active", id: newIdBy2()}),
+									label({'for': newIdBy2()},  _tr("Active")),
+									input({type: "checkbox", name: "ot_with_sales_tax1", id: newIdBy2()}),
+									label({'for': newIdBy2()},  _tr("Sales Tax")),
+									input({type: "checkbox", name: "ot_with_sales_tax_included", id: newIdBy2()}),
+									label({'for': newIdBy2()},  _tr("Sales Tax Included")),
+									input({type: "checkbox", name: "ot_show_sales_tax", id: newIdBy2()}),
+									label({'for': newIdBy2()},  _tr("Show Sales Tax")),
+									input({type: "checkbox", name: "ot_show_prices", id: newIdBy2()}),
+									label({'for': newIdBy2()},  _tr("Show Prices"))
+								)
+							),
+							tr(
+								td(_tr("Description")), 
+								td(
+									input({type: "input", name: "ot_with_quote", size: 1, cls:"bold"}),
+									_tr("With Quote")
+								), 
+								td(
+									input({type: "checkbox", name: "ot_is_expense", id: newIdBy2()}),
+									label({'for': newIdBy2()},  _tr("Is Expense"))
+								)
+							),
+							tr(
+								td(input({type: "input", style: "width:98%;", name: "ot_description"})), 
+								td(
+									input({type: "input", name: "ot_with_order", size: 1, cls:"bold"}),
+									_tr("With Order")
+								), 
+								td(
+									input({type: "checkbox", name: "ot_is_income", id: newIdBy2()}),
+									label({'for': newIdBy2()},  _tr("Is Income"))
+								)
+							),
+							tr(
+								td(_tr("Notes")), 
+								td(
+									input({type: "input", name: "ot_with_inventory", size: 1, cls:"bold"}),
+									_tr("With Inventory")
+								), 
+								td(Jaml.render('ActionSelect', args))
+							),
+							tr(
+								td({rowspan:3, style: "width:60%;"},textarea({rows: 5, name: "ott_notes", cls: "fw"})),
+								td(
+									input({type: "input", name: "ot_with_payment", size: 1, cls:"bold"}),
+									_tr("With Payment")
+								), 
+								td(input({id: args.btnAction_id, type: "button", name: "btnAction", value: _tr("Action")}))
+							),
+							tr(
+								td(
+									input({type: "input", name: "ot_with_credit", size: 1, cls:"bold"}),
+									_tr("With Credit")
+								), 
+								td("&nbsp;")
+							),
+							tr(
+								td(
+									input({type: "input", name: "ot_with_lost", size: 1, cls:"bold"}),
+									_tr("With Lost")
+								), 
+								td("&nbsp;")
+							)
+						)
+					)
+				)
+			)
+		)
+	);
+});
+
+function OrderTypesListEditWindowOnTableRowClick(){
+	var win = dad.getWindowForChild(this);
+	if(win && win.ud.ajaxLoad){
+			win.ud.ajaxLoad.post('/DB/GetOne', 'order_types=' + this.cells[1].innerHTML , "GET");
+			var form = dad.getFirstParentWithTagName(this, "FORM");
+			if(form) form.ot_code.focus();
+	}
+}
+
+function OrderTypesListEditWindowRefresh(ajax) {
+	ajax.post('/DB/GetList', 'list=order_types', "GET");
+}
+
+function OrderTypesListEditWindowOnSubmit(btn) {
+	return dad.formOnSubmit(OrderTypesListEditWindowRefresh, this.form, "order_types")
+}
+	
+function newOrderTypesListEditWindow(){
+	var title = "Order Types List Edit"
+	var win = dad._windows[title];
+	if(!win){
+		var newId = dad.newSeqId();
+		var Action_id = 'Action' + newId;
+		var btnAction_id = 'btnAction' + newId;
+		var table_id = 'table' + newId;
+		var table_header_id = 'table_header' + newId;
+		var form_id = 'form' + newId;
+		var data = {
+			id: newId,
+			form_id: form_id,
+			Action_id: Action_id,
+			btnAction_id: btnAction_id,
+			table_id: table_id,
+			table_header_id: table_header_id
+		}
+		data.table_height = "50%";
+		data.data_table = Jaml.render('2TRDataTable', data);
+
+		var win = dad.newWindow(newId,220,20, 800, 560, _tr(title), Jaml.render('OrderTypesListEdit', data));
+		var myform = $(data.form_id);
+		win.ud.form = myform;
+		win.ud.WindowRefresh = OrderTypesListEditWindowRefresh;
+		myform.my_field_prefix = "ot_";
+		dad.setupEditForm(myform);
+		myform.ajaxSubmit = new dad.Ajax(dad.listEditWindowOnSubmitRespose, newId, false);
+		win.ud.ajaxLoad = new dad.Ajax(dad.formAjaxLoadResponse, newId, false);
+
+		var mytable = $(table_id);
+		mytable.my_record_header = ["id|ID|0|R",
+                "code|Code|6|R",
+                "description|Description|-1",
+                "with_payment|Pay|6|C",
+                "with_inventory|Inv.|6|C",
+                "group_order|Grp. 1|6|C",
+                "subgroup_order|Grp. 2|6|C",
+                "is_active|Active|6|C|B"];
+		mytable.row_click_cb = OrderTypesListEditWindowOnTableRowClick;
+		win.ud.ajaxTable = new dad.newAjaxDataTableAjax(win, newId);
+
+		var btn = $(btnAction_id);
+		btn.onclick = OrderTypesListEditWindowOnSubmit;
+		
+		OrderTypesListEditWindowRefresh(win.ud.ajaxTable);
+	}
+	dad.bringToFront(win)
+}

+ 578 - 0
ourbiz/s/ourbiz/orders.js

@@ -0,0 +1,578 @@
+Jaml.register('OrderEditWindow', function(args) {
+	dad.rightClickMenu = "rightClickMenu" + args.newId;
+	div({id: dad.rightClickMenu, style:"display:none"},
+		table(
+			tr(th("Menu")),
+			tr(td("Copy")),
+			tr(td("Paste"))
+		)
+	),
+	form({id: args.form_id, style: "width:100%;height:100%;", onsubmit:"return false;"}, 
+		table({style: "width:100%;height:100%", cls: "editForm"},
+			tr({cls:"trvam"},
+				td({colspan:8},
+					select({name: 'o_order_type_id', style: "width:100%;", id: args.select_ot_id})
+				),
+				td({colspan:2, width:"2%"}, input({type: "text", name: "o_mdate"}))
+			),
+			tr({cls:"trvam minw"},
+				td(_tr("Series")),
+				td( input({type: "text", name: "o_series", size: 3})),
+				td(_tr("Number")),
+				td(input({type: "text", name: "o_order_number", size: 9})),
+				td(_tr("Entity")),
+				td(input({type: "text", name: "o_entity_id", size: 6})),
+				td({colspan:3, style:"width:90%;"},
+					input({type: "text", name: "o_entity_name", style:"width:100%;"})),
+				td(input({type: "button", name: "btnSearchEntity", value: "&lt;&gt;", 
+						onclick:"onOrderEditSearchEntity(this)"}))
+			),
+			tr({id: args.tabs_id, "class": "tabs"},
+				td({colspan:10},
+					button({name:"tab_main" + args.id}, _tr('Main')),
+					button({name:"tab_delivery" + args.id}, _tr('Delivery')),
+					button({name:"tab_statistics" + args.id}, _tr('Statistics')),
+					button({name:"tab_history" + args.id}, _tr('History')),
+					button({name:"tab_preview" + args.id}, _tr('Preview')),
+					button({name:"tab_totals" + args.id}, _tr('Totals'))
+				)
+			),
+			tr({id:"tab_main" + args.id, 'class':"tabContent"},
+				td({colspan:10, style:"height:100%;"},
+					table({style: "width:100%;height:100%;"},
+						tr({cls:"trvam"},
+							td({colspan:3, style: "width:100%;height:12px;"},
+								_tr("Lines"), input({type: "text", name: "o_lines_count", size: 4}),
+								_tr("Weight"), input({type: "text", name: "o_weight_total", size: 9}),
+								_tr("Payment Type"), select({name: "o_payment_type_id"}),
+								_tr("Date"), input({type: "text", name: "o_order_date", size: 10}),
+								input({type: "button", name: "select_order_date", value: "&lt;&gt;", 
+									onclick: "newCalendarChooserWindow()"})
+							)
+						),
+						args.data_table,
+						tr(
+							td({colspan:2,'class': "editBox", style: "width:100%;height:50px;vertical-align:top;"},
+								fieldset({'class': "editBox"},
+									table({cls: "fw"},
+										tr(
+											td({cls: "fw"},
+												table({cls: "fw"},
+													tr(
+														td(_tr("ID")),
+														td(_tr("Description")),
+														td("&nbsp;")
+													),
+													tr(
+														td({style: "width: 5%;"}, input({type: "text", name: "ol_product_id", size: 6, onfocus:"this.select()"})),
+														td(input({type: "text", name: "ol_description", cls: "fw", onfocus:"this.select()"})),
+														td({style: "width: 5%;"},input({type: "button", name: "btnSearchProduct", 
+															value: "&lt;&gt;", onclick:"onOrderEditSearchProduct(this)"}))
+													)
+												)
+											)
+										),
+										tr(
+											td({cls: "fw"},
+												table({cls: "fw"},
+													tr(
+														td(_tr("Qty.")),
+														td(_tr("Weight")),
+														td(_tr("Price")),
+														td(_tr("1º Total")),
+														td(_tr("Disc. %")),
+														td(_tr("Disc. $"))
+													),
+													tr(
+														td(input({type: "text", name: "ol_quantity", size: 6, onfocus:"this.select()"})),
+														td(input({type: "text", name: "ol_weight", size: 6, onfocus:"this.select()"})),
+														td(input({type: "text", name: "ol_price", size: 6, onfocus:"this.select()"})),
+														td(input({type: "text", name: "ol_first_total", size: 6})),
+														td(input({type: "text", name: "ol_discount_pct", size: 6, onfocus:"this.select()"})),
+														td(input({type: "text", name: "ol_discount_amt", size: 6}))
+													)
+												)
+											)
+										),
+										tr(
+											td({cls: "fw"},
+												table({cls: "fw"},
+													tr(
+														td(_tr("Subtotal")),
+														td(_tr("Tax II %")),
+														td(_tr("Tax I %")),
+														td(_tr("Tax I $")),
+														td("&nbsp;"),
+														td(_tr("Total $"))
+													),
+													tr(
+														td(input({type: "text", name: "ol_line_subtotal", size: 6})),
+														td(input({type: "text", name: "ol_sales_tax2_pct", size: 6})),
+														td(input({type: "text", name: "ol_sales_tax1_pct", size: 6})),
+														td(input({type: "text", name: "ol_sales_tax1_amt", size: 6})),
+														td(input({type: "button", name: "btnSaveLine", value: _tr("Save")})),
+														td(input({type: "text", name: "ol_line_total", size: 6}))
+													)
+												)
+											)
+										)
+									)
+								),
+								Jaml.render('ActionSelect', args), 
+								input({id: args.btnAction_id, type: "button", name: "btnAction", value:_tr("Action")}),
+								input({type: "button", value:_tr("Numbering")})
+							),
+							td({'class': "editBox", style: "width:50px;height:1%;vertical-align:top;"},
+								fieldset({'class': "editBox"},
+									table(
+										tr(td(_tr("Subtotal")), td(input({type: "text", name: "o_subtotal_amt", size: 9, 'class': "vright"}))),
+										tr(td(_tr("Sales Tax I")), td(input({type: "text", name: "o_sales_tax1_amt", size: 9, 'class': "vright"}))),
+										tr(td(_tr("Sales Tax II")), td(input({type: "text", name: "o_sales_tax2_amt", size: 9, 'class': "vright"}))),
+										tr(td(_tr("Total")), td(input({type: "text", name: "o_total_amt", size: 9, 'class': "vright"}))),
+										tr(td(_tr("Cash")), td("&nbsp;")),
+										tr(td(_tr("Return")), td("&nbsp;")),
+										tr(
+											td("&nbsp;"), 
+											td(input({type: "button", id: "btnPrint" + args.id, value:_tr("Print")}))
+										)
+									)
+								)
+							)
+						)
+					)
+				)
+			),
+			tr({id:"tab_delivery" + args.id, 'class':"tabContent"},
+				td({colspan:10, style:"height:100%;"},
+					table({style: "width:100%;"},
+						tr(
+							td(_tr("Adderss")),
+							td(input({type: "text", name: "o_entity_address", cls: "fw"}))
+						),
+						tr(
+							td(_tr("ZIP")),
+							td(
+								input({type: "text", name: "o_entity_zip_code"}),
+								_tr("City"), input({type: "text", name: "o_entity_city"})
+							)
+						),
+						tr(
+							td(_tr("State")),
+							td(
+								input({type: "text", name: "o_state"}),
+								_tr("Country"), input({type: "text", name: "o_country"})
+							)
+						),
+						tr(
+							td(_tr("Phone")),
+							td(
+								input({type: "text", name: "o_phone"}),
+								_tr("Tax Number"), input({type: "text", name: "o_tax_number"})
+							)
+						),
+						tr(
+							td(_tr("Valid till")),
+							td(
+								input({type: "text", name: "o_order_valid_till_date"}),
+								_tr("Their Number"), input({type: "text", name: "o_entity_order_number"})
+							)
+						),
+						tr(
+							td(
+								input({type: "checkbox", name: "o_entity_tax_exempt"}), _tr("Tax exempt")
+							),
+							td(
+								input({type: "checkbox", name: "o_entity_use_sales_tax2"}), _tr("Use sales tax2")
+							)
+						),
+						tr(
+							td({colspan:2}, 
+								_tr("Notes"),
+								textarea({rows: 5, name: "o_order_notes", cls: "fw"})
+							)
+						)
+					)
+				)
+			),
+			tr({id:"tab_statistics" + args.id, 'class':"tabContent"},
+				td({colspan:10, style:"height:100%;"},
+					Jaml.render('StatisticsTabContent', args)
+				)
+			),
+			tr({id:"tab_history" + args.id, 'class':"tabContent"},
+				td({colspan:10, style:"height:100%;"},
+					Jaml.render('HistoryTabContent', args)
+				)
+			),
+			tr({id:"tab_preview" + args.id, 'class':"tabContent"},
+				td({colspan:10, style:"height:100%;"}
+					//_tr("Empty")
+				)
+			),
+			tr({id:"tab_totals" + args.id, 'class':"tabTotals"},
+				td({colspan:10, style:"height:100%;"},
+					table(
+						tr(
+							td(_tr("Balance")),
+							td(input({type: "text", name: "e_balance", cls: "vright"})),
+							td("&nbsp;"),
+							td(input({type: "button", name: "btnTotalsOverviewRefresh", value: "Refresh"}))
+						),
+						tr(
+							td(_tr("Sales Quoted")),
+							td(input({type: "text", name: "t_sales_quoted", cls: "vright"})),
+							td(_tr("Buys Quoted")),
+							td(input({type: "text", name: "t_buys_quoted", cls: "vright"}))
+						),
+						tr(
+							td(_tr("Sales Ordered")),
+							td(input({type: "text", name: "t_sales_ordered", cls: "vright"})),
+							td(_tr("Buys Ordered")),
+							td(input({type: "text", name: "t_buys_ordered", cls: "vright"}))
+						),
+						tr(
+							td(_tr("Sales Delivered")),
+							td(input({type: "text", name: "t_sales_delivered", cls: "vright"})),
+							td(_tr("Buys Delivered")),
+							td(input({type: "text", name: "t_buys_received", cls: "vright"}))
+						),
+						tr(
+							td(_tr("Sales Invoiced")),
+							td(input({type: "text", name: "t_sales_invoiced", cls: "vright"})),
+							td(_tr("Buys Invoiced")),
+							td(input({type: "text", name: "t_buys_invoiced", cls: "vright"}))
+						),
+						tr(
+							td(_tr("Sales Paid")),
+							td(input({type: "text", name: "t_sales_paid", cls: "vright"})),
+							td(_tr("Buys Paid")),
+							td(input({type: "text", name: "t_buys_paid", cls: "vright"}))
+						)
+					)					
+				)
+			)
+		)
+	);
+});
+
+function showOrderEditWindow(all_sales_buys, caller, id){
+	var win = newOrderEditWindow(all_sales_buys);
+	win.ud.caller = caller;
+	win.ud.sab = all_sales_buys;
+	var ajax = win.ud.ajaxLoad;
+	if(ajax){
+		ajax.post("/DB/GetOne", "orders=" + id + "&with_lines=1", 'GET', null);
+	}
+/*	
+	var ajaxLines = win.ud.ajaxLines;
+	if(ajaxLines){
+		ajaxLines.post('/DB/GetList', 'list=orders&lines=' + id, "GET");
+	}
+*/	
+}
+
+function FillOrderLineEdit(form, row){
+	form.product_id.value = row[1].innerHTML;
+	form.description.value = row[2].innerHTML;
+	form.quantity.value = row[3].innerHTML;
+	form.price.value = row[4].innerHTML;
+}
+
+function EntityEditWindowOnFillForm(form_field, value) {
+	switch(form_field.name){
+		case "o_order_type_id":{
+			var options = form_field.options;
+			for(var i=0; i < options.length; i++){
+				if(value == options[i].value) {
+					form_field.selectedIndex = i;
+					break;
+				}
+			}
+			return true;
+		}
+		break;
+		case "o_weight_total":
+			form_field.value = dad.formatNumeric(value);
+		break;
+		case "o_subtotal_amt":
+		case "o_sales_tax1_amt":
+		case "o_sales_tax2_amt":
+		case "o_total_amt":
+		{
+			form_field.value = dad.formatCurrency(value);
+			return true;
+		}
+		break;
+	}
+	return false;
+}
+
+function OrderLinesOnTableRowDoubleClick(ev){
+	var table = dad.getTableForTableChild(this);
+	if(table){
+		var win = dad.getWindowForChild(table);
+		if(win && win.ud.form) 		FillOrderLineEdit(win.ud.form, this.cells);
+	}
+	dad.cancelEvent(dad.checkEvent(ev));
+	//return true;
+}
+
+function OrderLinesOnTableRowClick(ev){
+	var win = dad.getWindowForChild(this);
+	if(win && win.ud.ajaxLoadLine) {
+		var row = this.cells;
+		win.ud.ajaxLoadLine.post('/DB/GetOne', 'orders=' + row[1].innerHTML + '&line_calculated=1', "GET");
+	}
+	dad.cancelEvent(dad.checkEvent(ev));
+	//return true;
+}
+
+function onOrderEditValidateEntity(win, id, selection){
+	win.ud.ajaxLoadEntity.post('/DB/GetOne', 'entities=' + id + '&for_order=1', "GET");
+}
+
+function onOrderEditSearchEntity(sender){
+	var form = sender.form;
+	var search_str = form.o_entity_name.value;
+	var win = dad.getWindowForChild(sender);
+	var entity_list_search = win.ud.entity_list_search;
+	if(!entity_list_search || !entity_list_search.ud.sab){
+		win.ud.entity_list_search = entity_list_search = newEntitiesListSearchWindow(win.ud.sab);
+	}
+	entity_list_search.searchForMe(search_str, win, onOrderEditValidateEntity);
+	return false;
+}
+
+function onOrderEditValidateProduct(win, id, selection){
+	win.ud.ajaxLoadLine.post('/DB/GetOne', 'products=' + id + '&for_order=1', "GET");
+	if(selection){
+		for(var i in selection){
+			alert(selection[i])
+		}
+	}
+}
+
+function onOrderEditSearchProduct(sender){
+	var form = sender.form;
+	var search_str = form.ol_description.value;
+	var win = dad.getWindowForChild(sender);
+	var product_list_search = win.ud.product_list_search;
+	if(!product_list_search || !product_list_search.ud.sab){
+		win.ud.product_list_search = product_list_search = newProductsListSearchWindow(win.ud.sab);
+	}
+	product_list_search.searchForMe(search_str, win, onOrderEditValidateProduct);
+	return false;
+}
+
+function onOrderEditCalcLine(){
+	//alert(this.value)
+	var win = dad.getWindowForChild(this);
+	if(win && win.ud.ajaxLoadLine) {
+		var form_prefix = "ol_";
+		var values = dad.getFormDataWithPrefix(this.form, form_prefix);
+		values.push("__table__=orders");
+		values.push("__id__=" + win.ud.form._dbrecord.id);
+		values.push("__action__=calc_order_line");
+		values.push("trigger=" + this.name.substring(form_prefix.length));
+		win.ud.ajaxLoadLine.post('/DB/Action', values.join('&'), "POST");
+	}	
+}
+
+function onOrderLineProductChange(){
+	var win = dad.getWindowForChild(this);
+	if(win && win.ud.ajaxLoadLine) {
+		win.ud.ajaxLoadLine.post('/DB/GetOne?products=' + 
+			win.ud.form.ol_product_id.value + "&for_order=1", "GET");
+	}		
+}
+
+function newOrderEditWindow(all_sales_buys){
+	var title = dad._getSABTitle(all_sales_buys, 'Order Edit');
+	var win = dad._windows[title];
+	if(!win){
+		var newId = dad.newSeqId();
+		var Action_id = 'Action' + newId;
+		var btnAction_id = 'btnAction' + newId;
+		var table_id = 'table' + newId;
+		var table_header_id = 'table_header' + newId;
+		var select_ot_id = 'select' + newId;
+		var tabs_id = 'tabs' + newId;
+		var data = {
+			id: newId,
+			tabs_id: tabs_id,
+			form_id: 'form' + newId,
+			select_ot_id: select_ot_id,
+			Action_id: Action_id,
+			btnAction_id: btnAction_id,
+			table_id: table_id,
+			table_header_id: table_header_id
+		}
+		data.table_height = (dad.isOpera || dad.isIE) ? "8em" : "100%";
+		data.data_table = Jaml.render('2TRDataTable', data);
+
+		var win = dad.newWindow(newId,220,20, 800, 500, _tr(title), Jaml.render('OrderEditWindow', data));
+		//dad.setContentOverflow(newId);
+		dad.initTab($(tabs_id));
+
+		var data_table = $(table_id);
+		data_table.className = data_table.className + " orders_lines";
+		var myform = $(data.form_id);
+		
+		win.ud.form = myform;
+		myform.my_field_prefix = "o_";
+		myform.onFillForm = EntityEditWindowOnFillForm;
+		dad.setupEditForm(myform);
+		
+		myform.ol_product_id.onchange = onOrderLineProductChange;
+		myform.ol_description.onchange = onOrderLineProductChange;
+
+		var calc_fields_list = ["ol_quantity","ol_price", "ol_discount_pct"];
+		for(var i in calc_fields_list){
+			myform[calc_fields_list[i]].onchange = onOrderEditCalcLine;
+		}
+		
+		myform.processResponse = function(data){
+			var result_array = [];
+			sle = dad.StrLenEncoded();
+			var processed = sle.sle2vecOfvec(data, data.length, result_array);
+			var lines = [];
+			sle.sle2vecOfvec(data, data.length, lines, processed);
+			if(lines.length > 0) lines.shift();
+			dad.fillTableById(lines, newId);
+			return result_array;
+		}
+
+		dad.setupBarchart(newId, function(){
+			return 'list=orders&statistics=1&sab=' + win.ud.sab;
+		});
+
+		var mytable = $(table_id);
+		mytable.my_record_header = ['id|ID|0', 'product_id|Code|6|R',
+			'description|Description|-1', 'quantity|Quantity|8|R|N',
+			'price|Price|8|R|M', 'first_total|1st Total|8|R|M'];
+		mytable.row_click_cb = OrderLinesOnTableRowClick;
+		mytable._onDelete_cb = function(sender){
+			var tr = dad.getFirstParentWithTagName( sender, "TR" );
+			dad.formFocusNext(sender);
+			tr.parentNode.removeChild(tr);
+		}
+		
+		var btnPrint = $("btnPrint" + newId);
+		btnPrint.onclick = function(){
+			var url = '/DB/GetOne?orders=' + this.form._dbrecord.id + '&pdf=1';
+			window.open(url, "printPDF");
+		}
+
+		var ajaxOrderType = new dad.Ajax(function(){
+			if(this.status == 200){
+				//retrieve result as an JavaScript object
+				var records = dad.parseSLEData(this.responseText); 
+				var select = $(select_ot_id);
+				dad.fillSelectByRecords(select, records, false);
+			}
+		});
+		if(ajaxOrderType){
+			ajaxOrderType.post('/DB/GetList', 'list=order_types&short_list=1&group_order=' + 
+				all_sales_buys, "GET");
+		}
+
+		win.ud.ajaxLoad = new dad.Ajax(dad.formAjaxLoadResponse, newId, false);
+		win.ud.ajaxLines = dad.newAjaxDataTableAjax(win, newId);
+		win.ud.ajaxLoadLine = new dad.Ajax(function(){
+			if(this.status == 200){
+				//retrieve result as an JavaScript object
+				var record = dad.parseSLEData2Object(this.responseText); 
+				var form = $(data.form_id);
+				dad.formFillByRecord(form, record, "ol_");
+				if(!record.__table__) form.ol_quantity.focus();
+			} else {
+				alert("An error has occured making the request");
+			}
+		}, null, false);
+		
+		win.ud.ajaxLoadEntity = new dad.Ajax(function(id){
+			if(this.status == 200){
+				//retrieve result as an JavaScript object
+				var record = dad.parseSLEData2Object(this.responseText);
+				var form = $(data.form_id);
+				dad.fillFormWithExistingFields(form, record);
+				form.ol_description.focus();
+			} else {
+				alert("An error has occured making the request");
+			}
+		}, null, false);
+
+		var ajaxAuxTables = new dad.Ajax(function(select){
+			if(this.status == 200){
+				//retrieve result as an JavaScript object
+				var records = dad.parseSLEData(this.responseText); 
+				dad.fillSelectByRecords(select, records, true);
+			}
+		}, myform.o_payment_type_id);
+		if(ajaxAuxTables) ajaxAuxTables.post('/DB/GetList', 'list=payment_types&short_list=1', "GET");
+
+		var btn = myform.btnTotalsOverviewRefresh;
+		btn.ajaxLoadTotals = new dad.Ajax(function(){
+			if(this.status == 200){
+				//retrieve result as an JavaScript object
+				var record = dad.parseSLEData2Object(this.responseText); 
+				var form = $(data.form_id);
+				dad.formFillByRecord(form, record, "t_");
+			} else {
+				alert("An error has occured making the totals request");
+			}
+		}, null, false);
+		btn.onclick = function(){
+			if(this.ajaxLoadTotals) 
+				this.ajaxLoadTotals.post('/DB/GetOne?orders=1&totals_overview=1', "GET");
+		}		
+	}
+	dad.bringToFront(win);
+	return win;
+}
+
+Jaml.register('OrdersListSearchOn', function(args) {
+	input({type: "radio", name: "search_on", id: "by_entity" + args.id, value: "entity", checked:1 }),
+	label({'for': "by_entity" + args.id},  _tr("Entity")),
+	input({type: "radio", name: "search_on", id: "by_notes" + args.id, value: "notes"}),
+	label({'for': "by_notes" + args.id},  _tr("Notes")),
+	input({type: "radio", name: "search_on", id: "by_products" + args.id, value: "products"}),
+	label({'for': "by_products" + args.id},  _tr("Products")),
+	input({type: "radio", name: "search_on", id: "by_date" + args.id, value: "date"}),
+	label({'for': "by_date" + args.id},  _tr("Date")),
+	input({type: "radio", name: "search_on", id: "by_total" + args.id, value: "total"}),
+	label({'for': "by_total" + args.id},  _tr("Total"))
+});
+
+function newOrdersListSearchWindow(all_sales_buys){
+	var colHeaders = ["id|ID|6|R",
+                "order_date|Date|8",
+                "order_type_code|Type|4",
+                "series|Series|5",
+                "order_number|Number|7",
+                "entity_name|Entity|-1",
+                "total_amt|Total|8|R|M",
+                "payment_type_code|P.T.|4|C"];
+	var title = dad._getSABTitle(all_sales_buys, 'Orders List/Search');
+	var win = newListSearchWindow(all_sales_buys, title, colHeaders, showOrderEditWindow,
+		"orders", 'OrdersListSearchOn', null, all_sales_buys);
+	var data_table = $("table" + win.ud.win_id);
+	data_table.className = data_table.className + " orders_list";
+	
+	var group_filter = $('group_filter' + win.ud.win_id);
+	if(group_filter.options.length == 0){
+		var ajaxOrderType = new dad.Ajax(function(id){
+			if(this.status == 200){
+				//retrieve result as an JavaScript object
+				var records = dad.parseSLEData(this.responseText); 
+				dad.fillSelectByRecords(group_filter, records, true);
+			}
+		}, win.ud.win_id, false);
+		if(ajaxOrderType){
+			ajaxOrderType.post('/DB/GetList', 'list=order_types&short_list=1&group_order=' + 
+				all_sales_buys, "GET");
+		}
+	}
+		
+	return win;
+}

+ 186 - 0
ourbiz/s/ourbiz/otnetstrings.js

@@ -0,0 +1,186 @@
+/* Tagged netstrings implementation
+   tnetstrings.org
+
+   (c) 2011 Alexander Solovyov under terms of MIT License
+ */
+
+var otnetstrings = {
+    parsePayload: function(data) {
+        if (!data) {
+            throw "Invalid data to parse, it's empty.";
+        }
+        var idx = data.indexOf(":");
+        if (idx === -1) {
+            throw "Missing netstring delimiter";
+        }
+
+        var length = parseInt(data.substr(0, idx), 10);
+        var payload = data.substr(idx + 1, length);
+        if (payload.length !== length) {
+            throw "Data is wrong length: " + length + " vs " + payload.length;
+        }
+
+        var type = data.substr(idx + length + 1, 1);
+        var extra = data.substr(idx + length + 2);
+        if (!type) {
+            throw "No payload type: " + extra;
+        }
+        return {payload: payload, type: type, extra: extra};
+    },
+
+
+    parseList: function(data) {
+        if (!data) {
+            return [];
+        }
+        var result = [];
+        var p = this.parse(data);
+        result[result.length] = p.value;
+        while(p.extra) {
+            p = this.parse(p.extra);
+            result[result.length] = p.value;
+        }
+        return result;
+    },
+
+    parsePair: function(data) {
+        var pk = this.parse(data);
+        if (!pk.extra) {
+            throw "Unbalanced dictionary store.";
+        }
+        var pv = this.parse(pk.extra);
+        if (!pk.value) {
+            throw "Got an invalid value, null not allowed.";
+        }
+        return {key: pk.value, value: pv.value, extra: pv.extra};
+    },
+
+    parseDict: function(data) {
+        if (!data) {
+            return {};
+        }
+        var kv = this.parsePair(data);
+        var result = {};
+        result[kv.key] = kv.value;
+        while (kv.extra) {
+            kv = this.parsePair(kv.extra);
+            result[kv.key] = kv.value;
+        }
+        return result;
+    },
+
+    dumpObject: function(data) {
+        var i, type, result = [];
+
+        if (data === null) {
+            return '0~';
+        } else if (Object.prototype.toString.apply(data) === '[object Array]') {
+            type = ']';
+            for (i = 0; i < data.length; i++) {
+                result.push(this.dump(data[i]));
+            }
+        } else {
+            type = '}';
+            for (i in data) {
+                if (data.hasOwnProperty(i)) {
+                    result.push(this.dump(i), this.dump(data[i]));
+                }
+            }
+        }
+
+        var payload = result.join('');
+        return payload.length + type + payload;
+    },
+
+    parse: function(data) {
+        var value;
+        var p = this.parsePayload(data);
+        switch (p.type) {
+        case '#':
+            value = parseInt(p.payload, 10);
+            break;
+        case '^':
+            value = parseFloat(p.payload);
+            break;
+        case '!':
+            value = p.payload === 'true';
+            break;
+        case '~':
+            if (p.payload.length !== 0)
+                throw "Payload must be 0 length for null.";
+            value = null;
+            break;
+        case ',':
+            value = p.payload;
+            break;
+        case '}':
+            value = this.parseDict(p.payload);
+            break;
+        case ']':
+            value = this.parseList(p.payload);
+            break;
+        default:
+            throw "Invalid payload type: " + p.type;
+        }
+        return {value: value, extra: p.extra};
+    },
+
+    dump: function(data) {
+        switch (typeof data) {
+        case 'number':
+            // return null for infinite numbers
+            if (!isFinite(data))
+                return this.dump(null);
+            var out = data.toString();
+            return out.length + (~~data === data ? '#' : '^') + out;
+        case 'boolean':
+            if(data) return '1!1';
+            else return '1!0';
+        case 'string':
+            return this.stringLength(data) + ',' + data;
+        case 'object':
+            // object in js could be dict, list, null
+            return this.dumpObject(data);
+        }
+    },
+
+    // returns the length (in bytes) of a js
+    // string when  encoded as utf-8
+    stringLength: function (str) {
+        var i = str.length,
+            len = 0,
+            ch;
+
+        while (i--) {
+            ch = str.charCodeAt(i);
+
+            if (ch <= 0x007F) {
+                len += 1;
+            }
+
+            else if (ch <= 0x07FF) {
+                len += 2;
+            }
+
+            else if (ch <= 0xFFFF) {
+                len += 3;
+            }
+
+            else if (ch <= 0x10FFFF) {
+                len += 4;
+            }
+
+            else {
+                // Realistically this should never happen
+                throw new Error("Bad Charcode: " + ch);
+            }
+        }
+
+        return len;
+    }
+};
+
+
+if (typeof module !== 'undefined' && module.exports) {
+    module.exports = otnetstrings;
+}

+ 111 - 0
ourbiz/s/ourbiz/payment-types.js

@@ -0,0 +1,111 @@
+Jaml.register('PaymentTypesListEdit', function(args) {
+	form({action: "/DB/Action", method: "post", id: args.form_id, style: "width:100%;height:100%;"},
+		table({style: "width:100%;height:100%;"},
+			args.data_table,
+			tr(
+				td({'class': "editBox", style: "width:100%;"},
+					fieldset(legend(_tr("Edit Form")),
+						table(
+							tr(
+								td(_tr("ID")), td(_tr("CDate")), td(_tr("MDate")), td("&nbsp;")
+							),
+							tr(
+								td(input({type: "input", name: "pt_id", size: 12, readonly:"1"})), 
+								td(input({type: "input", name: "pt_cdate", size: 12, readonly:"1"})), 
+								td(input({type: "input", name: "pt_mdate", size: 12, readonly:"1"})),
+								td(input({type: "checkbox", name: "pt_is_active"}, _tr("Active")))
+							),
+							tr(
+								td(_tr("Code")), 
+								td({colspan:3}, _tr("Description"))
+							),
+							tr(
+								td(input({type: "input", name: "pt_code", size: 12})), 
+								td({colspan:3},input({type: "input", name: "pt_description", style: "width:98%;"})) 
+							),
+							tr(
+								td({colspan:2}, input({type: "input", name: "pt_payment_terms", style: "width:98%;"})), 
+								td({colspan:2}, _tr("Payment Terms"))
+							),
+							tr(
+								td(_tr("Notes")), 
+								td({colspan:3}, "&nbsp;")
+							),
+							tr(
+								td({colspan:3},textarea({rows: 5, name: "pt_notes", cls: "fw"})), 
+								td({style: "width:5%;padding-left:1em;"},
+									Jaml.render('ActionSelect', args),
+									br(),
+									input({id: args.btnAction_id, type: "button", name: "btnAction", value: _tr("Action")})
+									)
+							)
+						)
+					)
+				)
+			)
+		)
+	);
+});
+
+function PaymentTypesListEditWindowOnTableRowClick(){
+	var win = dad.getWindowForChild(this);
+	if(win && win.ud.ajaxLoad){
+			win.ud.ajaxLoad.post('/DB/GetOne', 'payment_types=' + this.cells[1].innerHTML , "GET");
+			var form = dad.getFirstParentWithTagName(this, "FORM");
+			if(form) form.pt_code.focus();
+	}
+}
+
+function PaymentTypesListEditWindowRefresh(ajax) {
+	ajax.post('/DB/GetList', 'list=payment_types', "GET");
+}
+
+function PaymentTypesListEditWindowOnSubmit(btn) {
+	return dad.formOnSubmit(PaymentTypesListEditWindowRefresh, this.form, "payment_types")
+}
+	
+function newPaymentTypesListEditWindow(){
+	var title = "Payment Types List Edit"
+	var win = dad._windows[title];
+	if(!win){
+		var newId = dad.newSeqId();
+		var Action_id = 'Action' + newId;
+		var btnAction_id = 'btnAction' + newId;
+		var table_id = 'table' + newId;
+		var table_header_id = 'table_header' + newId;
+		var form_id = 'form' + newId;
+		var data = {
+			id: newId,
+			form_id: form_id,
+			Action_id: Action_id,
+			btnAction_id: btnAction_id,
+			table_id: table_id,
+			table_header_id: table_header_id
+		}
+		data.table_height = "50%";
+		data.data_table = Jaml.render('2TRDataTable', data);
+		
+		var win = dad.newWindow(newId,220,20, 550, 450, _tr(title), Jaml.render('PaymentTypesListEdit', data));
+		var myform = $(data.form_id);
+		win.ud.form = myform;
+		win.ud.WindowRefresh = PaymentTypesListEditWindowRefresh;
+		myform.my_field_prefix = "pt_";
+		dad.setupEditForm(myform);
+		myform.ajaxSubmit = new dad.Ajax(dad.listEditWindowOnSubmitRespose, newId, false);
+		win.ud.ajaxLoad = new dad.Ajax(dad.formAjaxLoadResponse, newId, false);
+		
+		var mytable = $(table_id);
+		mytable.my_record_header = ["id|ID|0",
+                "code|Code|8|C",
+                "description|Description|-1",
+                "is_active|Active|5|C|B"];
+		mytable.row_click_cb = PaymentTypesListEditWindowOnTableRowClick;
+		win.ud.ajaxTable = new dad.newAjaxDataTableAjax(win, newId);
+
+		var btn = $(btnAction_id);
+		btn.onclick = PaymentTypesListEditWindowOnSubmit;
+		
+		PaymentTypesListEditWindowRefresh(win.ud.ajaxTable);
+	}
+	dad.bringToFront(win)
+}

+ 262 - 0
ourbiz/s/ourbiz/payments.js

@@ -0,0 +1,262 @@
+Jaml.register('PaymentsEditWindow', function(args) {
+	form({id: args.form_id, style: "width:100%;height:100%;", onsubmit:"return false;"}, 
+		table({style: "width:100%;height:100%", cls: "editForm"},
+			tr({style:"height:2%;"},
+				td(_tr("Payment #")),
+				td(input({type: "text", name: "pmt_id", size: 10})),
+				td(_tr("Amount")),
+				td(input({type: "text", name: "pmt_amount", size: 10})),
+				td(_tr("Due Date")),
+				td(input({type: "text", name: "pmt_due_date", size: 10})),
+				td("&nbsp;")
+			),
+			tr({style:"height:2%;"},
+				td({colspan:5},_tr("Entity")),
+				td(_tr("Created")),
+				td("&nbsp;")
+			),
+			tr({style:"height:2%;"},
+				td({colspan:5}, input({type: "text", name: "pmt_entity_name", style:"width:98%;"})),
+				td(input({type: "text", name: "pmt_cdate", size: 10})),
+				td("&nbsp;")
+			),
+			tr({style:"height:2%;"},
+				td({colspan:5},_tr("Description")),
+				td(_tr("Cleared")),
+				td("&nbsp;")
+			),
+			tr({style:"height:2%;"},
+				td({colspan:5}, 
+					input({type: "text", name: "pmt_description", style:"width:98%;"})
+				),
+				td({style:"width:2%;"},
+					input({type: "text", name: "pmt_cleared_date", size: 10})
+				),
+				td({style:"width:2%;"},
+					input({type: "button", name: "select_due_date", value: "&lt;&gt;", 
+						onclick:"newCalendarChooserWindow()"})
+				)
+			),
+			tr(
+				td({colspan:7, style: "width:100%;height:100%;"},
+					table({style: "width:100%;height:100%;"},
+						args.data_table,
+						tr(
+							td(_tr("Description"))
+						),
+						tr(
+							td(input({type: "text", name: "pl_description", style:"width:98%;"}))
+						),
+						tr(
+							td(
+								table(
+									tr(
+										td(_tr("Amount")), td(_tr("Date")), td("&nbsp;"), td("&nbsp;")
+									),
+									tr(
+										td(input({type: "text", name: "pl_amount", size: 10})), 
+										td(input({type: "text", name: "pl_payment_date", size: 10})), 
+										td(input({type: "button", name: "select_payment_date", value: "&lt;&gt;", 
+												onclick:"newCalendarChooserWindow()"})
+										), 
+										td(
+											input({id: args.btnSaveLine_id, type: "button", name: "btnSaveLine", value: _tr("Save Line")})
+										)
+									)
+								)
+							)
+						)
+					)
+				)
+			),
+			tr(
+				td({style:"text-align:right;", colspan:7},
+					input({id: args.btnAction_id, type: "button", name: "btnSave", value: _tr("Save")}),
+					input({id: args.btnAction_id, type: "button", name: "btnPrint", value: _tr("Print")})
+				)
+			)
+		)
+	);
+});
+
+function showPaymentsEditWindow(all_sales_buys, caller, id){
+	var win = newPaymentsEditWindow(all_sales_buys);
+	win.ud.caller = caller;
+	win.ud.sab = all_sales_buys;
+	var ajax = win.ud.ajaxLoad;
+	if(ajax){
+		ajax.post("/DB/GetOne", "payments=" + id + "&with_lines=1", 'GET', null);
+	}
+/*	
+	var ajaxLines = win.ud.ajaxLines;
+	if(ajaxLines){
+		ajaxLines.post('/DB/GetList', 'list=orders&lines=' + id, "GET");
+	}
+*/	
+}
+
+function FillPaymentLineEdit(form, row){
+	form.product_id.value = row[1].innerHTML;
+	form.description.value = row[2].innerHTML;
+	form.quantity.value = row[3].innerHTML;
+	form.price.value = row[4].innerHTML;
+}
+
+function PaymentLinesOnTableRowDoubleClick(ev){
+	var table = dad.getTableForTableChild(this);
+	if(table){
+		var win = dad.getWindowForChild(table);
+		if(win && win.ud.form) 		FillTransactionLineEdit(win.ud.form, this.cells);
+	}
+	dad.cancelEvent(dad.checkEvent(ev));
+	//return true;
+}
+
+function PaymentLinesOnTableRowClick(ev){
+	var win = dad.getWindowForChild(this);
+	if(win && win.ud.ajaxLoadLine) {
+		var row = this.cells;
+		win.ud.ajaxLoadLine.post('/DB/GetOne', 'payments=' + row[1].innerHTML + '&line_calculated=1', "GET");
+	}
+	dad.cancelEvent(dad.checkEvent(ev));
+	//return true;
+}
+
+function onPaymentsEditValidateEntity(win, id, selection){
+	win.ud.ajaxLoadEntity.post('/DB/GetOne', 'entities=' + id + '&for_order=1', "GET");
+}
+
+function onPaymentsEditSearchEntity(sender){
+	var form = sender.form;
+	var search_str = form.o_entity_name.value;
+	var win = dad.getWindowForChild(sender);
+	var entity_list_search = win.ud.entity_list_search;
+	if(!entity_list_search || !entity_list_search.ud.sab){
+		win.ud.entity_list_search = entity_list_search = newEntitiesListSearchWindow(win.ud.sab);
+	}
+	entity_list_search.searchForMe(search_str, win, onGLTransationsEditValidateEntity);
+	return false;
+}
+
+function newPaymentsEditWindow(all_sales_buys){
+	var title = dad._getSABTitle(all_sales_buys, 'Payment Edit');
+	var win = dad._windows[title];
+	if(!win){
+		var newId = dad.newSeqId();
+		var Action_id = 'Action' + newId;
+		var btnAction_id = 'btnAction' + newId;
+		var table_id = 'table' + newId;
+		var table_header_id = 'table_header' + newId;
+		var data = {
+			id: newId,
+			form_id: 'form' + newId,
+			Action_id: Action_id,
+			btnAction_id: btnAction_id,
+			table_id: table_id,
+			table_header_id: table_header_id
+		}
+		data.table_height = (dad.isOpera || dad.isIE) ? "8em" : "100%";
+		data.data_table = Jaml.render('2TRDataTable', data);
+
+		var win = dad.newWindow(newId,220,20, 800, 500, _tr(title), Jaml.render('PaymentsEditWindow', data));
+		//dad.setContentOverflow(newId);
+
+		var data_table = $(table_id);
+		data_table.className = data_table.className + " payments_lines";
+		var myform = $(data.form_id);
+		
+		win.ud.form = myform;
+		myform.my_field_prefix = "pmt_";
+		dad.setupEditForm(myform);
+		
+		
+		myform.processResponse = function(data){
+			var result_array = [];
+			sle = dad.StrLenEncoded();
+			var processed = sle.sle2vecOfvec(data, data.length, result_array);
+			var lines = [];
+			sle.sle2vecOfvec(data, data.length, lines, processed);
+			if(lines.length > 0) lines.shift();
+			dad.fillTableById(lines, newId);
+			return result_array;
+		}
+
+		var mytable = $(table_id);
+		mytable.my_record_header = [
+                "id|ID|0",
+                "notes|Description|-1",
+                "payment_date|Date|9",
+                "amount|Amount|9|R"
+			];
+		mytable.row_click_cb = PaymentLinesOnTableRowClick;
+		mytable._onDelete_cb = function(sender){
+			var tr = dad.getFirstParentWithTagName( sender, "TR" );
+			dad.formFocusNext(sender);
+			tr.parentNode.removeChild(tr);
+		}
+		
+		win.ud.ajaxLoad = new dad.Ajax(dad.formAjaxLoadResponse, newId, false);
+		win.ud.ajaxLines = dad.newAjaxDataTableAjax(win, newId);
+		win.ud.ajaxLoadLine = new dad.Ajax(function(){
+			if(this.status == 200){
+				//retrieve result as an JavaScript object
+				var record = dad.parseSLEData2Object(this.responseText); 
+				var form = $(data.form_id);
+				dad.formFillByRecord(form, record, "pl_");
+				//if(!record.__table__) form.ol_quantity.focus();
+			} else {
+				alert("An error has occured making the request");
+			}
+		}, null, false);
+		
+		win.ud.ajaxLoadEntity = new dad.Ajax(function(id){
+			if(this.status == 200){
+				//retrieve result as an JavaScript object
+				var record = dad.parseSLEData2Object(this.responseText);
+				var form = $(data.form_id);
+				dad.fillFormWithExistingFields(form, record);
+				form.ol_description.focus();
+			} else {
+				alert("An error has occured making the request");
+			}
+		}, null, false);		
+	}
+	dad.bringToFront(win);
+	return win;
+}
+
+Jaml.register('PaymentsListSearchOn', function(args) {
+	input({type: "radio", name: "search_on", id: "by_entities" + args.id, value: "entities", checked:1}),
+	label({'for': "by_entities" + args.id},  _tr("Entities")),
+	input({type: "radio", name: "search_on", id: "by_notes" + args.id, value: "notes"}),
+	label({'for': "by_notes" + args.id},  _tr("Notes")),
+	input({type: "radio", name: "search_on", id: "by_date" + args.id, value: "date"}),
+	label({'for': "by_date" + args.id},  _tr("Date"))
+});
+
+function newPaymentsListSearchWindow(all_sales_buys){
+	var colHeaders = ["id|ID|6",
+                "entity_name|Entity|-1",
+				"amount|Amount|12|R",
+                "due_date|Date|9"];
+	var title = dad._getSABTitle(all_sales_buys, 'Payments List/Search');
+	var win = newListSearchWindow(all_sales_buys, title, colHeaders, showPaymentsEditWindow,
+		"payments", 'PaymentsListSearchOn', null, all_sales_buys);
+	var data_table = $("table" + win.ud.win_id);
+	data_table.className = data_table.className + " payments_list";
+
+	var ajaxOrderType = new dad.Ajax(function(id){
+		if(this.status == 200){
+			//retrieve result as an JavaScript object
+			var records = dad.parseSLEData(this.responseText); 
+			var select = $('group_filter' + id);
+			dad.fillSelectByRecords(select, records, true);
+		}
+	}, win.ud.win_id, false);
+	if(ajaxOrderType){
+		ajaxOrderType.post('/DB/GetList', 'list=order_types&short_list=1&group_order=' + 
+			all_sales_buys, "GET");
+	}
+		
+	return win;
+}

+ 363 - 0
ourbiz/s/ourbiz/products.js

@@ -0,0 +1,363 @@
+Jaml.register('ProductEditWindow', function(args) {
+	form({action: "/DB/Action", method: "post", onsubmit:"return false;",
+			id: args.form_id, style: "width:100%;height:100%;"}, 
+		table({style: "width:100%;height:100%;", cls: "editForm"},
+			tr(
+				td({style: "width:12px;"},
+					table({style: "width:100%;"},
+						tr(
+							td({style: "width:1%;"},input({type: "text", name: "p_id", size: 8})),
+							td(input({type: "text", name: "p_sell_description", style: "width:99%;"})),
+							td({style: "width:1%;"},input({type: "text", name: "p_mdate", size: 9}))
+						)
+					)
+				)
+			),
+			tr({id: args.main_tabs_id, "class": "tabs"},
+				td(
+					button({name:"tab_main" + args.id}, _tr('Main')),
+					button({name:"tab_prices" + args.id}, _tr('Prices')),
+					button({name:"tab_kit" + args.id}, _tr('Kit')),
+					button({name:"tab_statistics" + args.id}, _tr('Statistics')),
+					button({name:"tab_history" + args.id}, _tr('History')),
+					button({name:"tab_reports" + args.id}, _tr('Reports')),
+					button({name:"tab_totals" + args.id}, _tr('Totals'))
+				)
+			),
+			tr({id:"tab_main" + args.id, 'class':"tabContent"},
+				td(
+					table({style: "width:100%;"},
+						tbody({cls:"firstRight"},
+							tr({cls:"fcr"},
+								td(_tr("Reference")),
+								td(input({type: "text", name: "p_reference_code", cls:"size9"})),
+								td(_tr("Ref. Supp.")),
+								td(input({type: "text", name: "p_supplier_code", cls:"size9"})),
+								td(_tr("Barcode")),
+								td(input({type: "text", name: "p_bar_code", cls:"size9"}))
+							),
+							tr({cls:"fcr"},
+								td(_tr("Description")),
+								td({colspan:5}, input({type: "text", name: "p_sell_description", cls: "fw"}))
+							),
+							tr({cls:"fcr"},
+								td(_tr("Des. Supp.")),
+								td({colspan:5}, input({type: "text", name: "p_buy_description", cls: "fw"}))
+							),
+							tr({cls:"fcr"},
+								td(_tr("Sales Price")),
+								td(input({type: "text", name: "p_sell_price", cls:"size9"})),
+								td(_tr("Measure Unit")),
+								td(select({type: "text", name: "p_measure_unit_id", cls:"size9"})),
+								td({colspan:2, rowspan:6}, img({id: 'prod_img_' +args.id}))
+							),
+							tr({cls:"fcr"},
+								td(_tr("Sales Tax")),
+								td(select({type: "text", name: "p_sales_tax_id", cls:"size9"})),
+								td(_tr("Warranty")),
+								td(select({type: "text", name: "p_warranty_id", cls:"size9"}))
+							),
+							tr({cls:"fcr"},
+								td(_tr("Onhand")),
+								td(input({type: "text", name: "p_quantity_onhand", cls:"size9"})),
+								td(_tr("Weight")),
+								td(input({type: "text", name: "p_weight", cls:"size9"}))
+							),
+							tr({cls:"fcr"},
+								td(_tr("Reserved")),
+								td(input({type: "text", name: "p_quantity_reserved", cls:"size9"})),
+								td(_tr("Sell Min. Qty.")),
+								td(input({type: "text", name: "p_sell_quantity_min", cls:"size9"}))
+							),
+							tr(
+								td({colspan:2}, input({type: "checkbox", name: "p_show_on_sales"}),_tr("Show on Sales")),
+								td( input({type: "checkbox", name: "p_show_on_web"}),_tr("WEB"))
+							),
+							tr(
+								td({colspan:2}, input({type: "checkbox", name: "p_show_on_buys"}),_tr("Show on Buys")),
+								td(input({type: "checkbox", name: "p_show_price_on_web"}),_tr("WEB Price"))
+							)
+						),
+						tbody(
+							tr({id:args.notes_tabs_id, 'class':"tabs"},
+								td({colspan:4},
+									button({name:"tab_notes" + args.id}, _tr('Sales Notes')),
+									button({name:"tab_notes_supplier" + args.id}, _tr('Buy Notes')),
+									button({name:"tab_tags" + args.id}, _tr('Tags')),
+									button({name:"tab_groups" + args.id}, _tr('Groups'))
+								),
+								td({colspan:2},
+									Jaml.render('ActionSelect', args),
+									input({id: args.btnAction_id, type: "button", name: "btnAction", value: _tr("Action")})
+								)
+							),
+							tr({id:"tab_notes" + args.id, 'class':"tabContent"},
+								td({colspan:6},textarea({rows: 7, name: "p_sell_notes", cls: "fw"}))
+							),
+							tr({id:"tab_notes_supplier" + args.id, 'class':"tabContent"},
+								td({colspan:6},textarea({rows: 7, name: "p_buy_notes", cls: "fw"}))
+							),
+							tr({id:"tab_tags" + args.id, 'class':"tabContent"},
+								td({colspan:6},textarea({rows: 7, name: "p_tags", cls: "fw"}))
+							),
+							tr({id:"tab_groups" + args.id, 'class':"tabContent"},
+								td({colspan:6},textarea({rows: 7, name: "p_notes", cls: "fw"}))
+							)
+						)
+					)
+				)
+			),
+			tr({id:"tab_prices" + args.id, 'class':"tabContent"},
+				td({align:"center"},
+					table(
+						tr(
+							td(_tr("Buy $")),
+							td(_tr("Buy Disc. %")),
+							td(_tr("Other Costs $")),
+							td(_tr("Markup %")),
+							td(_tr("Margin %")),
+							td(_tr("Sales $"))
+						),
+						tr(
+							td(input({type: "text", name: "p_buy_price", cls:"size9"})),
+							td(input({type: "text", name: "p_buy_discount", cls:"size9"})),
+							td(input({type: "text", name: "p_buy_other_costs", cls:"size9"})),
+							td(input({type: "text", name: "p_sell_markup", cls:"size9"})),
+							td(input({type: "text", name: "p_sell_margin", cls:"size9"})),
+							td(input({type: "text", name: "p_sell_price", cls:"size9"}))
+						),
+						tr(
+							td({rowspan:3, colspan:4},
+								_tr("Price Formula"),
+								br(),
+								textarea({rows: 3, name: "p_price_formula", cls: "fw"})
+							),
+							td(_tr("Stock Min.")),
+							td(input({type: "text", name: "p_stock_min", cls:"size9"}))
+						),
+						tr(
+							td(_tr("Stock Max.")),
+							td(input({type: "text", name: "p_stock_max", cls:"size9"}))
+						),
+						tr(
+							td(_tr("Buy Min. Qty")),
+							td(input({type: "text", name: "p_buy_quantity_min", cls:"size9"}))
+						)
+					)
+				)
+			),
+			tr({id:"tab_kit" + args.id, 'class':"tabContent"},
+				td(
+					_tr("Empty")
+				)
+			),
+			tr({id:"tab_statistics" + args.id, 'class':"tabContent"},
+				td(
+					Jaml.render('StatisticsTabContent', args)
+				)
+			),
+			tr({id:"tab_history" + args.id, 'class':"tabContent"},
+				td(
+					Jaml.render('HistoryTabContent', args)
+				)
+			),
+			tr({id:"tab_reports" + args.id, 'class':"tabContent"},
+				td(
+					button({id:"rptProductsList" + args.id}, _tr('Products List'))
+				)
+			),
+			tr({id:"tab_totals" + args.id, 'class':"tabTotals"},
+				td({style:"height:100%;"},
+					table(
+						tr(
+							td(_tr("Quantity quoted sales")),
+							td(input({type: "text", name: "p_quantity_quoted_sales", cls: "vright"})),
+							td(_tr("Quantity quoted buys")),
+							td(input({type: "text", name: "p_quantity_quoted_buys", cls: "vright"}))
+						),
+						tr(
+							td(_tr("Quantity ordered sales")),
+							td(input({type: "text", name: "p_quantity_ordered_sales", cls: "vright"})),
+							td(_tr("Quantity ordered buys")),
+							td(input({type: "text", name: "p_quantity_ordered_buys", cls: "vright"}))
+						),
+						tr(
+							td(_tr("Quantity delivered sales")),
+							td(input({type: "text", name: "p_quantity_delivered", cls: "vright"})),
+							td(_tr("Quantity received buys")),
+							td(input({type: "text", name: "p_quantity_received", cls: "vright"}))
+						),
+						tr(
+							td(_tr("Quantity invoiced sales")),
+							td(input({type: "text", name: "p_quantity_invoiced_sales", cls: "vright"})),
+							td(_tr("Quantity invoiced buys")),
+							td(input({type: "text", name: "p_quantity_invoiced_buys", cls: "vright"}))
+						),
+						tr(
+							td(_tr("Quantity lost")),
+							td({colspan:3}, input({type: "text", name: "p_quantity_lost", cls: "vright"}))
+						)
+					)
+				)
+			)
+		)
+	);
+});
+
+function ProductEditWindowRefresh(ajax) {
+}
+
+function showProductEditWindow(all_sales_buys, caller, id){
+	var win = newProductEditWindow(all_sales_buys);
+	win.ud.caller = caller;
+	win.ud.edit_id = id;
+	var ajax = win.ud.ajaxLoad;
+	if(ajax){
+		ajax.post("/DB/GetOne", "products=" + id, 'GET', null);
+	}
+}	
+
+function ProductEditWindowOnSubmit(btn) {
+	return dad.formOnSubmit(ProductEditWindowRefresh, this.form, "products")
+}
+
+Jaml.register('ProductsHistoryOptions', function(args) {
+	option({value:""}, "----");
+	option(_tr("Sales by Date"));
+	option(_tr("Sales by Amount"));
+	option(_tr("Entities that Bought"));
+	option(_tr("Entities that Bought by Value"));
+	option(_tr("Entities that Bought by Quantity"));
+	option(_tr("Price History"));
+	option(_tr("Price History All"));
+});
+
+function newProductEditWindow(all_sales_buys){
+	var title = dad._getSABTitle(all_sales_buys, 'Product Edit');
+	var win = dad._windows[title];
+	if(!win){
+		var newId = dad.newSeqId();
+		var Action_id = 'Action' + newId;
+		var btnAction_id = 'btnAction' + newId;
+		var table_history_id = 'table_history' + newId;
+		var table_history_header_id = 'table_history_header' + newId;
+		var main_tabs_id = 'main_tabs' + newId;
+		var notes_tabs_id = 'notes_tabs' + newId;
+		var data = {
+			id: newId,
+			main_tabs_id: main_tabs_id,
+			notes_tabs_id: notes_tabs_id,
+			form_id: 'form' + newId,
+			Action_id: Action_id,
+			btnAction_id: btnAction_id,
+			table_history_id: table_history_id,
+			table_history_header_id: table_history_header_id,
+			history_options: Jaml.render('ProductsHistoryOptions', data)
+		}
+		var win = dad.newWindow(newId,220,20, 800, 500, _tr(title), Jaml.render('ProductEditWindow', data));
+		//dad.setContentOverflow(newId);
+		dad.initTab($(main_tabs_id));
+		dad.initTab($(notes_tabs_id));
+		win.ud.ajaxLoad = new dad.Ajax(dad.formAjaxLoadResponse, newId, false);
+
+		var choiceHistory = $('history_type_id' + newId);
+		choiceHistory.ajaxLoadHistory = dad.newAjaxDataTableAjax(win, 
+				{id:newId, table:table_history_id, table_header:table_history_header_id});
+		choiceHistory.onchange = function(){
+			if(!this.selectedIndex) return;
+			this.ajaxLoadHistory._withHeaders = true;
+			this.ajaxLoadHistory.post('/DB/GetList', 'list=products&history=' + 
+					win.ud.edit_id + '&htype=' + this.selectedIndex +
+					'&query_limit=' + this.form.history_query_limit.value, "GET");
+		}
+
+		dad.setupBarchart(newId, function(){
+			return 'list=products&statistics=' + win.ud.edit_id + '&sab=' + win.ud.sab;;
+		});
+
+		var myform = $(data.form_id);
+		myform.my_field_prefix = "p_";
+		dad.setupEditForm(myform);
+		myform.ajaxSubmit = new dad.Ajax(dad.listEditWindowOnSubmitRespose, newId, false);
+		myform.afterFill = function(){
+			var img_id = this._dbrecord.image_id;
+			var img = $('prod_img_' + newId);
+			dad.getImageForImg(img, img_id);
+		}
+
+		var btnRptProductsList = $("rptProductsList" + newId);
+		btnRptProductsList.onclick = function(){
+			var url = '/DB/GetList?list=products&pdf=1';
+			window.open(url, "printPDF");
+		}
+
+		var ajaxAuxTables = new dad.Ajax(function(select){
+			if(this.status == 200){
+				//retrieve result as an JavaScript object
+				var records = dad.parseSLEData(this.responseText);
+				dad.fillSelectByRecords(select, records, true, "");
+			}
+		}, myform.p_measure_unit_id);
+		if(ajaxAuxTables) ajaxAuxTables.post('/DB/GetList', 'list=measure_units&short_list=1', "GET");
+
+		ajaxAuxTables = new dad.Ajax(function(select){
+			if(this.status == 200){
+				//retrieve result as an JavaScript object
+				var records = dad.parseSLEData(this.responseText);
+				dad.fillSelectByRecords(select, records, true);
+			}
+		}, myform.p_sales_tax_id);
+		if(ajaxAuxTables) ajaxAuxTables.post('/DB/GetList', 'list=sales_tax_rates&short_list=1', "GET");
+
+		ajaxAuxTables = new dad.Ajax(function(select){
+			if(this.status == 200){
+				//retrieve result as an JavaScript object
+				var records = dad.parseSLEData(this.responseText); 
+				dad.fillSelectByRecords(select, records, true, "");
+			}
+		}, myform.p_warranty_id);
+		if(ajaxAuxTables) ajaxAuxTables.post('/DB/GetList', 'list=warranty_types&short_list=1', "GET");
+		
+		var btn = $(btnAction_id);
+		btn.onclick = ProductEditWindowOnSubmit;
+	}
+	dad.bringToFront(win);
+	return win;
+}
+
+Jaml.register('ProductsListSearchOn', function(args) {
+	input({type: "radio", name: "search_on", id: "by_description" + args.id, value: "description", checked:1 }),
+	label({'for': "by_description" + args.id},  _tr("Description")),
+	input({type: "radio", name: "search_on", id: "by_notes" + args.id, value: "notes"}),
+	label({'for': "by_notes" + args.id},  _tr("Notes")),
+	input({type: "radio", name: "search_on", id: "by_reference" + args.id, value: "reference"}),
+	label({'for': "by_reference" + args.id},  _tr("Reference")),
+	input({type: "radio", name: "search_on", id: "by_entity" + args.id, value: "entity"}),
+	label({'for': "by_entity" + args.id},  _tr("Entity")),
+	input({type: "radio", name: "search_on", id: "by_id" + args.id, value: "id"}),
+	label({'for': "by_id" + args.id},  _tr("ID"))
+});
+
+function newProductsListSearchWindow(all_sales_buys){
+	var colHeaders = ["id|ID|6|R",
+                "reference_code|Reference|9",
+                "sell_description|Description|-1",
+                "kit|Kit|3|C",
+                "price_taxed|Price+V.A.T.|9|R|M",
+                "price|Price|0|R|M",
+                "quantity_onhand|Onhand|6|R|N",
+                "is_active|Active|4|C|B",
+                "price_date|Price Date|0",
+                "image_id|image_id|0"];
+	var title = dad._getSABTitle(all_sales_buys, 'Products List/Search');
+	var win = newListSearchWindow(all_sales_buys, title, colHeaders, showProductEditWindow,
+		"products", 'ProductsListSearchOn', null, all_sales_buys);
+	var myId = win.ud.win_id;
+	var ltbl =  $('table' +myId);
+	ltbl.row_over_cb =  function(evt){
+		var img_id = this.cells[10].innerHTML;
+		var img = $('ls_img_' + myId);
+		dad.getImageForImg(img, img_id, true);
+	};
+	return win;
+}

+ 100 - 0
ourbiz/s/ourbiz/sales-tax-rates.js

@@ -0,0 +1,100 @@
+Jaml.register('SalesTaxListEdit', function(args) {
+	form({action: "/DB/Action", method: "post", id: args.form_id, style: "width:100%;height:100%;"},
+		table({style: "width:100%;height:100%;"},
+			args.data_table,
+			tr(
+				td({'class': "editBox", style: "width:100%;"},
+					fieldset(legend(_tr("Edit Form")),
+						table(
+							tr(
+								td(_tr("ID")), td(_tr("CDate")), td(_tr("MDate"))
+							),
+							tr(
+								td(input({type: "input", name: "st_id", size: 12, readonly:"1"})), 
+								td(input({type: "input", name: "st_cdate", size: 12, readonly:"1"})), 
+								td(input({type: "input", name: "st_mdate", size: 12, readonly:"1"}))
+							),
+							tr(
+								td(_tr("Tax I %")), td(_tr("Tax II %")), td("&nbsp;")
+							),
+							tr(
+								td(input({type: "input", name: "st_rate1", size: 12})), 
+								td(input({type: "input", name: "st_rate2", size: 12})), 
+								td(input({type: "checkbox", name: "st_is_active"}, _tr("Active")))
+							),
+							tr(
+								td({colspan:2}, _tr("Description")), 
+								td(Jaml.render('ActionSelect', args))
+							),
+							tr(
+								td({colspan:2},input({type: "input", style: "width:98%;", name: "st_description"})), 
+								td(input({id: args.btnAction_id, type: "button", name: "btnAction", value: _tr("Action")}))
+							)
+						)
+					)
+				)
+			)
+		)
+	);
+});
+
+function SalesTaxListEditWindowOnTableRowClick(){
+	var win = dad.getWindowForChild(this);
+	if(win && win.ud.ajaxLoad){
+			win.ud.ajaxLoad.post('/DB/GetOne', 'sales_tax_rates=' + this.cells[1].innerHTML , "GET");
+			var form = dad.getFirstParentWithTagName(this, "FORM");
+			if(form) form.st_rate1.focus();
+	}
+}
+
+function SalesTaxListEditWindowRefresh(ajax) {
+	ajax.post('/DB/GetList', 'list=sales_tax_rates', "GET");
+}
+
+function SalesTaxListEditWindowOnSubmit(btn) {
+	return dad.formOnSubmit(SalesTaxListEditWindowRefresh, this.form, "sales_tax_rates")
+}
+
+function newSalesTaxListEditWindow(){
+	var title = "Sales Tax List Edit"
+	var win = dad._windows[title];
+	if(!win){
+		var newId = dad.newSeqId();
+		var Action_id = 'Action' + newId;
+		var btnAction_id = 'btnAction' + newId;
+		var table_id = 'table' + newId;
+		var table_header_id = 'table_header' + newId;
+		var form_id = 'form' + newId;
+		var data = {
+			id: newId,
+			form_id: form_id,
+			Action_id: Action_id,
+			btnAction_id: btnAction_id,
+			table_id: table_id,
+			table_header_id: table_header_id
+		}
+		data.table_height = "50%";
+		data.data_table = Jaml.render('2TRDataTable', data);
+
+		var win = dad.newWindow(newId,220,20, 460, 420, _tr(title), Jaml.render('SalesTaxListEdit', data));
+		var myform = $(data.form_id);
+		win.ud.form = myform;
+		win.ud.WindowRefresh = SalesTaxListEditWindowRefresh;
+		myform.my_field_prefix = "st_";
+		dad.setupEditForm(myform);
+		myform.ajaxSubmit = new dad.Ajax(dad.listEditWindowOnSubmitRespose, newId, false);
+		win.ud.ajaxLoad = new dad.Ajax(dad.formAjaxLoadResponse, newId, false);
+
+		var mytable = $(table_id);
+		mytable.my_record_header = ["id|ID|0", "rate1|V.A.T. %|8|R", "rate2|R.E. %|8|R",
+			"description|Description|-1", "is_active|Active|5|C|B"];
+		mytable.row_click_cb = SalesTaxListEditWindowOnTableRowClick;
+		win.ud.ajaxTable = new dad.newAjaxDataTableAjax(win, newId);
+
+		var btn = $(btnAction_id);
+		btn.onclick = SalesTaxListEditWindowOnSubmit;
+
+		SalesTaxListEditWindowRefresh(win.ud.ajaxTable);
+	}
+	dad.bringToFront(win)
+}

+ 75 - 0
ourbiz/s/ourbiz/scroll.js

@@ -0,0 +1,75 @@
+var testEl,position=0;
+window.onload = function () {
+	testEl = $('testElement');
+	testEl.onmousedown = testEl.ontouchstart = startDrag;
+	var divs = testEl.getElementsByTagName('div');
+	for (var i=0;i<divs.length;i+=1) {
+			divs[i].style.left = position + 'px';
+			position += divs[i].offsetWidth + 10;
+	}
+}
+
+var scroll;
+function startDrag(e) {
+	var pos = [testEl.offsetLeft,testEl.offsetTop];
+	var origin = getCoors(e);
+	var originTime = new Date().getTime();
+	var step = 50,	// in milliseconds
+		startPos,speed,
+		distance = 0,
+		min = -position + $('wrapper').offsetWidth/2,
+		max = $('wrapper').offsetWidth/2;
+	clearInterval(scroll);
+
+	testEl.ontouchmove = testEl.onmousemove = moveDrag;
+	testEl.ontouchend = document.onmouseup = function (e) {
+		var end  = getCoors(e);
+		startPos = testEl.offsetLeft;
+		var endTime = new Date().getTime();
+		var dist = end - origin;
+		var time = endTime - originTime;
+		speed = dist/(time/1000); // pixels per second
+		$('log').innerHTML = 'Speed is ' + Math.abs(Math.round(speed)) + ' pixels per second!';
+		scroll = setInterval(extraScroll,step);
+		testEl.ontouchmove = testEl.ontouchend = testEl.onmousemove = document.onmouseup = null;
+	}
+
+	return false; // cancels scrolling
+
+	function extraScroll() {
+		distance += Math.round(speed*(step/1000))
+		var newPos = startPos + distance;
+		if (newPos > max || newPos < min) {
+			clearInterval(scroll);
+			return;
+		}
+		testEl.style.left = newPos + 'px';
+		speed *= .85;
+		if (Math.abs(speed) < 10) {
+			speed = 0;
+			clearInterval(scroll);
+		}
+	}
+
+	function moveDrag (e) {
+		var currentPos = getCoors(e);
+		var newPos = (currentPos - origin) + pos[0];
+		if (newPos <= max && newPos >= min) {
+			testEl.style.left = newPos + 'px';
+		}
+	}
+
+	function getCoors(e) {
+		var coors;
+		if (e.changedTouches) { 	// iPhone
+			coors = e.changedTouches[0].clientX;
+		} else { 								// all others
+			coors = e.clientX;
+		}
+		return coors;
+	}
+}
+
+function $(id) {
+	return document.getElementById(id);
+}

+ 223 - 0
ourbiz/s/ourbiz/shortcut.js

@@ -0,0 +1,223 @@
+/**
+ * http://www.openjs.com/scripts/events/keyboard_shortcuts/
+ * Version : 2.01.B
+ * By Binny V A
+ * License : BSD
+ */
+dad.shortcut = {
+	'all_shortcuts':{},//All the shortcuts are stored in this array
+	'add': function(shortcut_combination,callback,opt) {
+		//Provide a set of default options
+		var default_options = {
+			'type':'keydown',
+			'propagate':false,
+			'disable_in_input':false,
+			'target':document,
+			'keycode':false
+		}
+		if(!opt) opt = default_options;
+		else {
+			for(var dfo in default_options) {
+				if(typeof opt[dfo] == 'undefined') opt[dfo] = default_options[dfo];
+			}
+		}
+
+		var ele = opt.target;
+		if(typeof opt.target == 'string') ele = document.getElementById(opt.target);
+		var ths = this;
+		shortcut_combination = shortcut_combination.toLowerCase();
+
+		//The function to be called at keypress
+		var func = function(e) {
+			e = e || window.event;
+			
+			if(opt['disable_in_input']) { //Don't enable shortcut keys in Input, Textarea fields
+				var element;
+				if(e.target) element=e.target;
+				else if(e.srcElement) element=e.srcElement;
+				if(element.nodeType==3) element=element.parentNode;
+
+				if(element.tagName == 'INPUT' || element.tagName == 'TEXTAREA') return;
+			}
+	
+			//Find Which key is pressed
+			if (e.keyCode) code = e.keyCode;
+			else if (e.which) code = e.which;
+			var character = String.fromCharCode(code).toLowerCase();
+			
+			if(code == 188) character=","; //If the user presses , when the type is onkeydown
+			if(code == 190) character="."; //If the user presses , when the type is onkeydown
+
+			var keys = shortcut_combination.split("+");
+			//Key Pressed - counts the number of valid keypresses - if it is same as the number of keys, the shortcut function is invoked
+			var kp = 0;
+			
+			//Work around for stupid Shift key bug created by using lowercase - as a result the shift+num combination was broken
+			var shift_nums = {
+				"`":"~",
+				"1":"!",
+				"2":"@",
+				"3":"#",
+				"4":"$",
+				"5":"%",
+				"6":"^",
+				"7":"&",
+				"8":"*",
+				"9":"(",
+				"0":")",
+				"-":"_",
+				"=":"+",
+				";":":",
+				"'":"\"",
+				",":"<",
+				".":">",
+				"/":"?",
+				"\\":"|"
+			}
+			//Special Keys - and their codes
+			var special_keys = {
+				'esc':27,
+				'escape':27,
+				'tab':9,
+				'space':32,
+				'return':13,
+				'enter':13,
+				'backspace':8,
+	
+				'scrolllock':145,
+				'scroll_lock':145,
+				'scroll':145,
+				'capslock':20,
+				'caps_lock':20,
+				'caps':20,
+				'numlock':144,
+				'num_lock':144,
+				'num':144,
+				
+				'pause':19,
+				'break':19,
+				
+				'insert':45,
+				'home':36,
+				'delete':46,
+				'end':35,
+				
+				'pageup':33,
+				'page_up':33,
+				'pu':33,
+	
+				'pagedown':34,
+				'page_down':34,
+				'pd':34,
+	
+				'left':37,
+				'up':38,
+				'right':39,
+				'down':40,
+	
+				'f1':112,
+				'f2':113,
+				'f3':114,
+				'f4':115,
+				'f5':116,
+				'f6':117,
+				'f7':118,
+				'f8':119,
+				'f9':120,
+				'f10':121,
+				'f11':122,
+				'f12':123
+			}
+	
+			var modifiers = { 
+				shift: { wanted:false, pressed:false},
+				ctrl : { wanted:false, pressed:false},
+				alt  : { wanted:false, pressed:false},
+				meta : { wanted:false, pressed:false}	//Meta is Mac specific
+			};
+                        
+			if(e.ctrlKey)	modifiers.ctrl.pressed = true;
+			if(e.shiftKey)	modifiers.shift.pressed = true;
+			if(e.altKey)	modifiers.alt.pressed = true;
+			if(e.metaKey)   modifiers.meta.pressed = true;
+                        
+			for(var i=0; k=keys[i],i<keys.length; i++) {
+				//Modifiers
+				if(k == 'ctrl' || k == 'control') {
+					kp++;
+					modifiers.ctrl.wanted = true;
+
+				} else if(k == 'shift') {
+					kp++;
+					modifiers.shift.wanted = true;
+
+				} else if(k == 'alt') {
+					kp++;
+					modifiers.alt.wanted = true;
+				} else if(k == 'meta') {
+					kp++;
+					modifiers.meta.wanted = true;
+				} else if(k.length > 1) { //If it is a special key
+					if(special_keys[k] == code) kp++;
+					
+				} else if(opt['keycode']) {
+					if(opt['keycode'] == code) kp++;
+
+				} else { //The special keys did not match
+					if(character == k) kp++;
+					else {
+						if(shift_nums[character] && e.shiftKey) { //Stupid Shift key bug created by using lowercase
+							character = shift_nums[character]; 
+							if(character == k) kp++;
+						}
+					}
+				}
+			}
+			
+			if(kp == keys.length && 
+						modifiers.ctrl.pressed == modifiers.ctrl.wanted &&
+						modifiers.shift.pressed == modifiers.shift.wanted &&
+						modifiers.alt.pressed == modifiers.alt.wanted &&
+						modifiers.meta.pressed == modifiers.meta.wanted) {
+				callback(e);
+	
+				if(!opt['propagate']) { //Stop the event
+					//e.cancelBubble is supported by IE - this will kill the bubbling process.
+					e.cancelBubble = true;
+					e.returnValue = false;
+	
+					//e.stopPropagation works in Firefox.
+					if (e.stopPropagation) {
+						e.stopPropagation();
+						e.preventDefault();
+					}
+					return false;
+				}
+			}
+		}
+		this.all_shortcuts[shortcut_combination] = {
+			'callback':func, 
+			'target':ele, 
+			'event': opt['type']
+		};
+		//Attach the function with the event
+		if(ele.addEventListener) ele.addEventListener(opt['type'], func, false);
+		else if(ele.attachEvent) ele.attachEvent('on'+opt['type'], func);
+		else ele['on'+opt['type']] = func;
+	},
+
+	//Remove the shortcut - just specify the shortcut and I will remove the binding
+	'remove':function(shortcut_combination) {
+		shortcut_combination = shortcut_combination.toLowerCase();
+		var binding = this.all_shortcuts[shortcut_combination];
+		delete(this.all_shortcuts[shortcut_combination])
+		if(!binding) return;
+		var type = binding['event'];
+		var ele = binding['target'];
+		var callback = binding['callback'];
+
+		if(ele.detachEvent) ele.detachEvent('on'+type, callback);
+		else if(ele.removeEventListener) ele.removeEventListener(type, callback, false);
+		else ele['on'+type] = false;
+	}
+}

+ 52 - 0
ourbiz/s/ourbiz/style.css

@@ -0,0 +1,52 @@
+body {
+font: 100% verdana, arial, sans-serif;
+background-color: #fff;
+margin: 50px;
+}
+
+.box  {
+  background-color: #ffff00;
+  border: 1px solid #000000;
+  color: #000000;
+  padding: 0px;
+  position: absolute;
+}
+
+.bar {
+  background-color: #008080;
+  color: #ffffff;
+  cursor: move;
+  font-weight: bold;
+  padding: 3px 1em 3px 1em;
+}
+
+.content {
+  padding: 1em;
+}
+
+.keyLink {
+	position: absolute;
+	top: 1px;
+	right: 2px;
+	width: 20px;
+	height: 20px;
+	border: 1px solid #000000;
+	background-image: none;
+	font-size: 120%;
+	text-align: center;
+	padding: 0;
+	background-color: #ffffff;
+	opacity: .5;
+}
+
+.kl1 {right: +74px;}
+.kl2 {right: +50px;}
+.kl3 {right: +26px;}
+
+.fw {
+	width:100%;
+}
+
+}
+
+/* end css tabs */

+ 96 - 0
ourbiz/s/ourbiz/tap.js

@@ -0,0 +1,96 @@
+/*
+ *
+ * Find more about this plugin by visiting
+ * http://miniapps.co.uk/
+ *
+ * Copyright (c) 2012 Alex Gibson, http://miniapps.co.uk/
+ * Released under MIT license
+ * http://miniapps.co.uk/license/
+ *
+ */
+
+(function (window, document) {
+
+	function Tap(el) {
+		this.element = typeof el === 'object' ? el : document.getElementById(el);
+		this.eventStart = this.hasTouch ? 'touchstart' : 'mousedown';
+		this.eventMove = this.hasTouch ? 'touchmove' : 'mousemove';
+		this.eventEnd = this.hasTouch ? 'touchend' : 'mouseup';
+		this.moved = false; //flags if the finger has moved
+		this.startX = 0; //starting x coordinate
+		this.startY = 0; //starting y coordinate
+		this.element.addEventListener(this.eventStart, this, false);
+	}
+	
+	Tap.prototype.hasTouch = 'ontouchstart' in window || 'createTouch' in document;
+
+	//start			
+	Tap.prototype.start = function (e) {
+		this.moved = false;
+		this.startX = this.hasTouch ? e.touches[0].clientX : e.clientX;
+		this.startY = this.hasTouch ? e.touches[0].clientY : e.clientY;
+		this.element.addEventListener(this.eventMove, this, false);
+		this.element.addEventListener(this.eventEnd, this, false);
+		if (this.hasTouch) {
+			this.element.addEventListener('touchcancel', this, false);
+		}
+	};
+
+	//move	
+	Tap.prototype.move = function (e) {
+		var x = this.hasTouch ? e.touches[0].clientX : e.clientX,
+			y = this.hasTouch ? e.touches[0].clientY : e.clientY;
+		//if finger moves more than 10px flag to cancel
+		if (Math.abs(x - this.startX) > 10 || Math.abs(y - this.startY) > 10) {
+			this.moved = true;
+		}
+	};
+
+	//end
+	Tap.prototype.end = function (e) {
+		var event;
+		//only preventDefault on elements that are not form inputs
+		if (e.target.tagName !== 'SELECT' && e.target.tagName !== 'INPUT' && e.target.tagName !== 'TEXTAREA') {
+			e.preventDefault();
+		}
+		if (!this.moved) {
+			event = document.createEvent('Event');
+			event.initEvent('tap', true, true);
+			e.target.dispatchEvent(event);
+		}
+		this.element.removeEventListener(this.eventMove, this, false);
+		this.element.removeEventListener(this.eventEnd, this, false);
+		if (this.hasTouch) {
+			this.element.removeEventListener('touchcancel', this, false);
+		}
+	};
+
+	//touchcancel
+	Tap.prototype.cancel = function (e) {
+		//reset state
+		this.moved = false;
+		this.startX = 0;
+		this.startY = 0;
+		this.element.removeEventListener(this.eventMove, this, false);
+		this.element.removeEventListener(this.eventEnd, this, false);
+		if (this.hasTouch) {
+			this.element.removeEventListener('touchcancel', this, false);
+		}
+	};
+
+	Tap.prototype.handleEvent = function (e) {
+		switch (e.type) {
+		case 'touchstart': this.start(e); break;
+		case 'touchmove': this.move(e); break;
+		case 'touchend': this.end(e); break;
+		case 'touchcancel': this.cancel(e); break;
+		case 'mousedown': this.start(e); break;
+		case 'mousemove': this.move(e); break;
+		case 'mouseup': this.end(e); break;
+		}
+	};
+
+	//public function
+	window.Tap = Tap;
+
+}(window, document));

+ 1 - 0
ourbiz/s/ourbiz/touch-all.bat

@@ -0,0 +1 @@
+for %%f in (*) do COPY /B %%f +,,

+ 131 - 0
ourbiz/s/ourbiz/touch.js

@@ -0,0 +1,131 @@
+var input = {
+	right:false,
+	up:false,
+	left:false,
+	down:false,
+	quit:false,
+	info:false,
+	play:false,
+	jump:false
+}; //edit what ever you want with this
+
+var triggerElementID = null;
+var fingerCount = 0;
+var startX = 0;
+var startY = 0;
+var curX = 0;
+var curY = 0;
+var deltaX = 0; //have not found a use for delta but I'm sure you will
+var deltaY = 0;//have not found a use for delta but I'm sure you will
+var horzDiff = 0;
+var vertDiff = 0;
+var minLength = 50;
+var swipeLength = 0;
+var swipeAngle = null;
+var swipeDirection = null;
+
+function touchStart(event,passedName)
+{
+    event.preventDefault();
+    fingerCount = event.touches.length;
+    if ( fingerCount == 1 ){
+       startX = event.touches[0].pageX;
+       startY = event.touches[0].pageY;
+        triggerElementID = passedName;
+    }else{
+       touchCancel(event);
+    }
+}
+
+function touchMove(event)
+{
+    event.preventDefault();
+    if ( event.touches.length == 1 ){
+        curX = event.touches[0].pageX;
+        curY = event.touches[0].pageY;
+    }else{
+        touchCancel(event);
+    }
+}
+
+function touchEnd(event)
+{
+    event.preventDefault();
+    if ( fingerCount == 1 && curX != 0 ){
+        swipeLength = Math.round(Math.sqrt(Math.pow(curX - startX,2) + Math.pow(curY - startY,2)));
+        if ( swipeLength >= minLength ){
+            caluculateAngle();
+            determineSwipeDirection();
+            processingRoutine();
+            //touchCancel(event);
+        }else{
+            touchCancel(event);
+        }
+    }else{
+        touchCancel(event);
+    }
+}
+
+function getSpeed(){
+    return swipeLength/10;
+}
+
+function touchCancel(event){
+    fingerCount = 0;
+    startX = 0;
+    startY = 0;
+    curX = 0;
+    curY = 0;
+    deltaX = 0;
+    deltaY = 0;
+    horzDiff = 0;
+    vertDiff = 0;
+    swipeLength = 0;
+    swipeAngle = null;
+    swipeDirection = null;
+    triggerElementID = null;
+    input.left = false;
+    input.right = false;
+    input.up = false;
+    input.down = false;
+}
+
+function caluculateAngle(){
+    var X = startX-curX;
+    var Y = curY-startY;
+    var Z = Math.round(Math.sqrt(Math.pow(X,2)+Math.pow(Y,2)));
+    var r = Math.atan2(Y,X);
+    swipeAngle = Math.round(r*180/Math.PI);
+    if ( swipeAngle < 0 ){
+        swipeAngle =  360 - Math.abs(swipeAngle);
+    }
+}
+
+
+function determineSwipeDirection(){
+    if ( (swipeAngle <= 45) && (swipeAngle >= 0) ){
+        swipeDirection = 'left';
+    }else if ( (swipeAngle <= 360) && (swipeAngle >= 315) ){
+        swipeDirection = 'left';
+    }else if ( (swipeAngle >= 135) && (swipeAngle <= 225) ){
+        swipeDirection = 'right';
+    }else if ( (swipeAngle > 45) && (swipeAngle < 135) ){
+        swipeDirection = 'down';
+    }else{
+        swipeDirection = 'up';
+    }
+}
+
+function processingRoutine(){
+   var swipedElement = document.getElementById("canvas");
+
+    if ( swipeDirection == 'left' ){
+        //execute left arrow action
+    }else if ( swipeDirection == 'right' ){
+        //execute right arrow action
+    }else if ( swipeDirection == 'up' ){
+        //execute up arrow action
+    }else if ( swipeDirection == 'down' ){
+        //execute downward arrow action
+    }
+}

+ 103 - 0
ourbiz/s/ourbiz/warranty-types.js

@@ -0,0 +1,103 @@
+Jaml.register('WarrantyTypesListEdit', function(args) {
+	form({action: "/DB/Action", method: "post", id: args.form_id, style: "width:100%;height:100%;"},
+		table({style: "width:100%;height:100%;"},
+			args.data_table,
+			tr(
+				td({'class': "editBox", style: "width:100%;"},
+					fieldset(legend(_tr("Edit Form")),
+						table(
+							tr(
+								td(_tr("ID")), td(_tr("CDate")), td(_tr("MDate")), td("&nbsp;")
+							),
+							tr(
+								td(input({type: "input", name: "wt_id", size: 12, readonly:"1"})), 
+								td(input({type: "input", name: "wt_cdate", size: 12, readonly:"1"})), 
+								td(input({type: "input", name: "wt_mdate", size: 12, readonly:"1"})),
+								td(input({type: "checkbox", name: "wt_is_active"}, _tr("Active")))
+							),
+							tr(
+								td(_tr("Code")), 
+								td({colspan:3}, _tr("Description"))
+							),
+							tr(
+								td(input({type: "input", name: "wt_code", size: 12})), 
+								td({colspan:3},input({type: "input", name: "wt_description", style: "width:98%;"})) 
+							),
+							tr(
+								td({colspan:3}, "&nbsp"), 
+								td({style: "width:5%;padding-left:1em;"},
+									Jaml.render('ActionSelect', args),
+									br(),
+									input({id: args.btnAction_id, type: "button", name: "btnAction", value: _tr("Action")})
+									)
+							)
+						)
+					)
+				)
+			)
+		)
+	);
+});
+
+function WarrantyTypesListEditWindowOnTableRowClick(){
+	var win = dad.getWindowForChild(this);
+	if(win && win.ud.ajaxLoad){
+			win.ud.ajaxLoad.post('/DB/GetOne', 'warranty_types=' + this.cells[1].innerHTML , "GET");
+			var form = dad.getFirstParentWithTagName(this, "FORM");
+			if(form) form.wt_code.focus();
+	}
+}
+
+function WarrantyTypesListEditWindowRefresh(ajax) {
+	ajax.post('/DB/GetList', 'list=warranty_types', "GET");
+}
+
+function WarrantyTypesListEditWindowOnSubmit(btn) {
+	return dad.formOnSubmit(MeasureUnitsListEditWindowRefresh, this.form, "warranty_types")
+}
+	
+function newWarrantyTypesListEditWindow(){
+	var title = "Warranty Types List Edit"
+	var win = dad._windows[title];
+	if(!win){
+		var newId = dad.newSeqId();
+		var Action_id = 'Action' + newId;
+		var btnAction_id = 'btnAction' + newId;
+		var table_id = 'table' + newId;
+		var table_header_id = 'table_header' + newId;
+		var form_id = 'form' + newId;
+		var data = {
+			id: newId,
+			form_id: form_id,
+			Action_id: Action_id,
+			btnAction_id: btnAction_id,
+			table_id: table_id,
+			table_header_id: table_header_id
+		}
+		data.table_height = "50%";
+		data.data_table = Jaml.render('2TRDataTable', data);
+
+		var win = dad.newWindow(newId,220,20, 550, 450, _tr(title), Jaml.render('WarrantyTypesListEdit', data));
+		var myform = $(data.form_id);
+		win.ud.form = myform;
+		win.ud.WindowRefresh = WarrantyTypesListEditWindowRefresh;
+		myform.my_field_prefix = "wt_";
+		dad.setupEditForm(myform);
+		myform.ajaxSubmit = new dad.Ajax(dad.listEditWindowOnSubmitRespose, newId, false);
+		win.ud.ajaxLoad = new dad.Ajax(dad.formAjaxLoadResponse, newId, false);
+
+		var mytable = $(table_id);
+		mytable.my_record_header = ["id|ID|0",
+                "code|Code|8",
+                "description|Description|-1",
+                "is_active|Active|5|C|B"];
+		mytable.row_click_cb = WarrantyTypesListEditWindowOnTableRowClick;
+		win.ud.ajaxTable = new dad.newAjaxDataTableAjax(win, newId);
+
+		var btn = $(btnAction_id);
+		btn.onclick = WarrantyTypesListEditWindowOnSubmit;
+		
+		WarrantyTypesListEditWindowRefresh(win.ud.ajaxTable);
+	}
+	dad.bringToFront(win)
+}

Niektóre pliki nie zostały wyświetlone z powodu dużej ilości zmienionych plików