.net server control is almost feature complete and functional. All .net examples...
[infodrom/rico3] / ricoClient / js / rico.js
index 96c21c5..cb46cba 100644 (file)
@@ -1,6 +1,6 @@
 /*
- *  (c) 2005-2009 Richard Cowin (http://openrico.org)
- *  (c) 2005-2009 Matt Brown (http://dowdybrown.com)
+ *  (c) 2005-2011 Richard Cowin (http://openrico.org)
+ *  (c) 2005-2011 Matt Brown (http://dowdybrown.com)
  *
  *  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
  * @namespace Main Rico object
  */
 var Rico = {
-  Version: '3.0b1',
-  loadRequested: 1,
-  loadComplete: 2,
+  Version: '3.0b2',
   theme: {},
+  onLoadCallbacks: [],
+  windowIsLoaded: false,
+  preloadMsgs: '',
+  inputtypes: {search: 0, number: 0, range: 0, color: 0, tel: 0, url: 0, email: 0, date: 0, month: 0, week: 0, time: 0, datetime: 0, 'datetime-local': 0},
 
   init : function() {
     try {  // fix IE background image flicker (credit: www.mister-pixel.com)
       document.execCommand("BackgroundImageCache", false, true);
     } catch(err) {}
-    if (typeof Rico_CONFIG == 'object') {
-      this.setPaths(Rico_CONFIG.jsDir,Rico_CONFIG.cssDir,Rico_CONFIG.imgDir);
-      if (Rico_CONFIG.enableLogging) this.enableLogging();
-    }
-    this.preloadMsgs='';
-    this.baseHref= location.protocol + "//" + location.host;
-    this.loadedFiles={};
-    this.windowIsLoaded=false;
-    this.onLoadCallbacks=[];
-    var onloadAction=Rico.bind(this,'windowLoaded');
-    if (window.addEventListener)
-      window.addEventListener('load', onloadAction, false);
-    else if (window.attachEvent)
-      window.attachEvent('onload', onloadAction);
+    if (typeof Rico_CONFIG == 'object') this.setConfig(Rico_CONFIG);
     this.onLoad(function() { Rico.log('Pre-load messages:\n'+Rico.preloadMsgs); });
   },
 
-  setPaths : function(jsDir,cssDir,imgDir,htmDir) {
-    this.jsDir = jsDir;
-    this.cssDir = cssDir;
-    this.imgDir = imgDir;
-    this.htmDir = htmDir || jsDir;
-  },
-
-  // Array entries can reference a javascript file or css stylesheet
-  // A dependency on another module can be indicated with a plus-sign prefix: '+DependsOnModule'
-  moduleDependencies : {
-    DragAndDrop: ['ricoDragDrop.js'],
-    Calendar   : ['ricoCalendar.js'],
-    SearchBox  : ['ricoSearch.js'],
-    Tree       : ['ricoTree.js'],
-    ColorPicker: ['ricoColorPicker.js'],
-    SimpleGrid : ['ricoGridCommon.js', 'ricoSimpleGrid.js'],
-    LiveGridBasic : ['ricoGridCommon.js', 'ricoLiveGrid.js'],
-    LiveGrid      : ['+LiveGridBasic', 'ricoLiveGridControls.js'],
-    LiveGridMenu  : ['ricoLiveGridMenu.js'],
-    LiveGridAjax  : ['+LiveGrid', 'ricoLiveGridAjax.js'],
-    LiveGridJSON  : ['+LiveGridAjax', 'ricoLiveGridJSON.js'],
-    LiveGridForms : ['+LiveGridAjax', '+LiveGridMenu', 'ricoLiveGridForms.js']
-  },
-
-  languages : {
-    de: "translations/ricoLocale_de.js",
-    en: "translations/ricoLocale_en.js",
-    es: "translations/ricoLocale_es.js",
-    fr: "translations/ricoLocale_fr.js",
-    it: "translations/ricoLocale_it.js",
-    ja: "translations/ricoLocale_ja.js",
-    ko: "translations/ricoLocale_ko.js",
-    pt: "translations/ricoLocale_pt.js",
-    zh: "translations/ricoLocale_zh.js"
-  },
-
-  languageInclude : function(lang2) {
-    var filename=this.languages[lang2];
-    if (filename) this.include(filename);
-    return !!filename;\r
+  // called by rico2xxx.js
+  _bindLoadEvent : function() {
+    Rico.eventBind(window,"load", Rico.eventHandle(Rico,'windowLoaded'));
   },
 
-  acceptLanguage : function(acceptLang) {
-    var arLang=acceptLang.toLowerCase().split(',');\r
-    for (var i=0; i<arLang.length; i++) {\r
-      var lang2=arLang[i].match(/\w\w/);
-      if (!lang2) continue;\r
-      if (this.languageInclude(lang2)) return true;\r
+  setConfig : function(ConfigObj) {
+    var el = document.createElement('style');
+    document.getElementsByTagName('head')[0].appendChild(el);
+    if (!window.createPopup) { /* For Safari */
+      el.appendChild(document.createTextNode(''));
     }
-    return false;\r
-  },
-
-  /**
-   *  Expects one or more module or file names and loads
-   *  the appropriate files.
-   *  MUST call Rico.setPaths() before calling this method
-   */
-  loadModule : function() {
-    for (var a=0, length=arguments.length; a<length; a++) {
-      var name=arguments[a];
-      var dep=this.moduleDependencies[name];
-      if (dep) {
-        for (var i=0; i<dep.length; i++) {
-          if (dep[i].substring(0,1)=='+') {
-            this.loadModule(dep[i].slice(1));
-          } else {
-            this.include(dep[i]);
-          }
-        }
-      } else {
-        this.include(name);
-      }
+    var s = document.styleSheets[document.styleSheets.length - 1];
+    this.addCssBackgroundRule(s,'.rico-icon',ConfigObj.imgIcons,'no-repeat');
+    this.addCssBackgroundRule(s,'.ricoLG_Resize',ConfigObj.imgResize,'repeat');
+    if (ConfigObj.imgHeading) {
+      var repeat='repeat-x';
+      var pos='left center';
+      this.addCssBackgroundRule(s,'tr.ricoLG_hdg th',ConfigObj.imgHeading,repeat,pos);
+      this.addCssBackgroundRule(s,'tr.ricoLG_hdg td',ConfigObj.imgHeading,repeat,pos);
+      this.addCssBackgroundRule(s,'table.ricoLiveGrid thead td',ConfigObj.imgHeading,repeat,pos);
+      this.addCssBackgroundRule(s,'table.ricoLiveGrid thead th',ConfigObj.imgHeading,repeat,pos);
+      this.addCssBackgroundRule(s,'.ricoTitle',ConfigObj.imgHeading,repeat,pos);
+      this.addCssBackgroundRule(s,'.Rico_accTitle',ConfigObj.imgHeading,repeat,pos);
     }
+
+    if (ConfigObj.enableLogging) this.enableLogging();
+    if (ConfigObj.enableHTML5) this._CheckInputTypes();
   },
 
-  include : function(filename) {
-    if (this.loadedFiles[filename]) return;
-    this.addPreloadMsg('include: '+filename);
-    var ext = filename.substr(filename.lastIndexOf('.')+1);
-    switch (ext.toLowerCase()) {
-      case 'js':
-        this.loadedFiles[filename]=filename.substring(0,4)=='rico' ? this.loadRequested : this.loadComplete;
-        var el = document.createElement('script');
-        el.type = 'text/javascript';
-        el.src = this.jsDir+filename;
-        document.getElementsByTagName('head')[0].appendChild(el);
-        break;
-      case 'css':
-        var el = document.createElement('link');
-        el.type = 'text/css';
-        el.rel = 'stylesheet';
-        el.href = this.cssDir+filename;
-        this.loadedFiles[filename]=this.loadComplete;
-        document.getElementsByTagName('head')[0].appendChild(el);
-        break;
-    }
+  addCssBackgroundRule: function(sheet,selector,imageUrl,repeat,position) {
+    if (!imageUrl) return;
+    this.addCssRule(sheet,selector,"background-image:url('"+imageUrl+"')");
+    this.addCssRule(sheet,selector,"background-repeat:"+repeat);
+    if (position) this.addCssRule(sheet,selector,"background-position:"+position);
   },
 
-  // called after a script file has finished loading
-  includeLoaded: function(filename) {
-    this.loadedFiles[filename]=this.loadComplete;
-    this.checkIfComplete();
+  addCssRule: function(sheet,selector,rule) {
+    if (sheet.addRule) {
+      sheet.addRule(selector, rule);
+    } else if (sheet.insertRule) {
+      sheet.insertRule (selector+" { "+rule+" }", 0);
+    } else {
+      alert('unable to add rule: '+rule);
+    }
   },
 
   // called by the document onload event
   windowLoaded: function() {
     this.windowIsLoaded=true;
-    this.checkIfComplete();
-  },
-
-  checkIfComplete: function() {
-    var waitingFor=this.windowIsLoaded ? '' : 'window';
-    for(var filename in  this.loadedFiles) {
-      if (this.loadedFiles[filename]==this.loadRequested)
-        waitingFor+=' '+filename;
+    this.addPreloadMsg('Processing callbacks');
+    while (this.onLoadCallbacks.length > 0) {
+      var callback=this.onLoadCallbacks.shift();
+      if (callback) callback();
     }
-    //window.status='waitingFor: '+waitingFor;
-    this.addPreloadMsg('waitingFor: '+waitingFor);
-    if (waitingFor.length==0) {
-      this.addPreloadMsg('Processing callbacks');
-      while (this.onLoadCallbacks.length > 0) {
-        var callback=this.onLoadCallbacks.shift();
-        if (callback) callback();
-      }
+  },
+  
+  // check for availability of HTML5 input types
+  _CheckInputTypes: function() {
+    var i = document.createElement("input");
+    for (var itype in this.inputtypes) {
+      i.setAttribute("type", "text");
+      i.setAttribute("type", itype);
+      this.inputtypes[itype]=(i.type !== "text");
     }
   },
 
@@ -175,7 +103,7 @@ var Rico = {
       this.onLoadCallbacks.unshift(callback);
     else
       this.onLoadCallbacks.push(callback);
-    this.checkIfComplete();
+    if (this.windowIsLoaded) this.windowLoaded();
   },
 
   isKonqueror : navigator.userAgent.toLowerCase().indexOf("konqueror") > -1,
@@ -229,16 +157,6 @@ $: function(e) {
   return typeof e == 'string' ? document.getElementById(e) : e;
 },
 
-bind: function() {
-  var binderArgs = Array.prototype.slice.call(arguments);
-  var object = binderArgs.shift();
-  var method = binderArgs.shift();
-  return function() {
-    var callerArgs = Array.prototype.slice.call(arguments);
-    return object[method].apply(object,binderArgs.concat(callerArgs));
-  };
-},
-
 runLater: function() {
   var args = Array.prototype.slice.call(arguments);
   var msec = args.shift();
@@ -492,7 +410,7 @@ positionCtlOverIcon: function(ctl,icon) {
 createFormField: function(parent,elemTag,elemType,id,name) {
   var field;
   if (typeof name!='string') name=id;
-  if (this.isIE) {
+  if (this.isIE && this.ieVersion < 8) {
     // IE cannot set NAME attribute on dynamically created elements
     var s=elemTag+' id="'+id+'"';
     if (elemType) {
@@ -638,19 +556,18 @@ getPhraseById: function(phraseId) {
  * Format a positive number (integer or float)
  * @param posnum number to format
  * @param decPlaces the number of digits to display after the decimal point
- * @param thouSep the character to use as the thousands separator
- * @param decPoint the character to use as the decimal point
+ * @param thouSep boolean indicating whether to insert thousands separator
  * @returns formatted string
  */
-formatPosNumber: function(posnum,decPlaces,thouSep,decPoint) {
+formatPosNumber: function(posnum,decPlaces,thouSep) {
   var a=posnum.toFixed(decPlaces).split(/\./);
   if (thouSep) {
     var rgx = /(\d+)(\d{3})/;
     while (rgx.test(a[0])) {
-      a[0]=a[0].replace(rgx, '$1'+thouSep+'$2');
+      a[0]=a[0].replace(rgx, '$1'+Rico.thouSep+'$2');
     }
   }
-  return a.join(decPoint);
+  return a.join(Rico.decPoint);
 },
 
 /**
@@ -662,8 +579,7 @@ formatPosNumber: function(posnum,decPlaces,thouSep,decPoint) {
  * @param fmt may contain any of the following:<dl>
  *   <dt>multiplier </dt><dd> the original number is multiplied by this amount before formatting</dd>
  *   <dt>decPlaces  </dt><dd> number of digits to the right of the decimal point</dd>
- *   <dt>decPoint   </dt><dd> character to be used as the decimal point</dd>
- *   <dt>thouSep    </dt><dd> character to use as the thousands separator</dd>
+ *   <dt>thouSep    </dt><dd> boolean indicating whether to insert thousands separator</dd>
  *   <dt>prefix     </dt><dd> string added to the beginning of the result (e.g. a currency symbol)</dd>
  *   <dt>suffix     </dt><dd> string added to the end of the result (e.g. % symbol)</dd>
  *   <dt>negSign    </dt><dd> specifies format for negative numbers: L=leading minus, T=trailing minus, P=parens</dd>
@@ -674,15 +590,14 @@ formatNumber : function(n,fmt) {
   if (isNaN(n)) return 'NaN';
   if (typeof fmt.multiplier=='number') n*=fmt.multiplier;
   var decPlaces=typeof fmt.decPlaces=='number' ? fmt.decPlaces : 0;
-  var thouSep=typeof fmt.thouSep=='string' ? fmt.thouSep : this.thouSep;
-  var decPoint=typeof fmt.decPoint=='string' ? fmt.decPoint : this.decPoint;
+  var thouSep=typeof fmt.thouSep=='undefined' ? true : this.thouSep;
   var prefix=fmt.prefix || "";
   var suffix=fmt.suffix || "";
   var negSign=typeof fmt.negSign=='string' ? fmt.negSign : "L";
   negSign=negSign.toUpperCase();
   var s,cls;
   if (n<0.0) {
-    s=this.formatPosNumber(-n,decPlaces,thouSep,decPoint);
+    s=this.formatPosNumber(-n,decPlaces,thouSep);
     if (negSign=="P") s="("+s+")";
     s=prefix+s;
     if (negSign=="L") s="-"+s;
@@ -690,7 +605,7 @@ formatNumber : function(n,fmt) {
     cls='negNumber';
   } else {
     cls=n==0.0 ? 'zeroNumber' : 'posNumber';
-    s=prefix+this.formatPosNumber(n,decPlaces,thouSep,decPoint);
+    s=prefix+this.formatPosNumber(n,decPlaces,thouSep);
   }
   return "<span class='"+cls+"'>"+s+suffix+"</span>";
 },
@@ -728,7 +643,7 @@ formatDate : function(d,fmt) {
       datefmt=this.dateFmt;
       break;
   }
-  return datefmt.replace(/(yyyy|yy|mmmm|mmm|mm|dddd|ddd|dd|hh|nn|ss|a\/p)/gi,
+  return datefmt.replace(/(yyyy|yy|mmmm|mmm|mm|dddd|ddd|dd|d|hh|nn|ss|a\/p)/gi,
     function($1) {
       var h;
       switch ($1) {
@@ -846,7 +761,7 @@ createXmlDocument : function() {
   if (document.implementation && document.implementation.createDocument) {
     var doc = document.implementation.createDocument("", "", null);
     // some older versions of Moz did not support the readyState property
-    // and the onreadystate event so we patch it! 
+    // and the onreadystate event so we patch it!
     if (doc.readyState == null) {
       doc.readyState = 1;
       doc.addEventListener("load", function () {
@@ -882,7 +797,7 @@ Rico.ajaxUpdater.prototype = {
   updateSend : function(elem,url,options) {
     this.element=elem;
     this.onComplete=options.onComplete;
-    options.onComplete=Rico.bind(this,'updateComplete');
+    options.onComplete=function(xhr) { self.updateComplete(xhr); };
     new Rico.ajaxRequest(url,options);
   },
 
@@ -893,5 +808,4 @@ Rico.ajaxUpdater.prototype = {
 };
 
 Rico.writeDebugMsg=Rico.log;  // for backwards compatibility
-
 Rico.init();