Buffalo 学习笔记- buffalo.js 源代码注释(三)

//定义返回信息处理对象
Buffalo.Reply = Class.create();
Buffalo.Reply.prototype = {
   // 初始化 Buffalo.Reply调用的方法,已经很多次用到这个方法了,初始化方法的参数就是服务短的返回信息
   //xhr :包含返回信息的 XmlHttp 对象
 initialize: function(xhr) {  
  this._isFault = false;
  this._type = "null";
  this._objects = [];
  this._objectNodes = [];
    this._source = xhr.responseText;
   //返回的XML字符串是否DOM化了
    var root = xhr.responseXML ? xhr.responseXML.documentElement :
    this.constructNodeFromXmlStringInIEOrFF(this._source);
  this.dataNode = root.firstChild;
  //获取节点的类型 在后台已经设置好了
  this._type = this._getType(this.dataNode);
  
 },
 //将xml字符串的转化为dom层次结构对象
 constructNodeFromXmlStringInIEOrFF: function(xmlString) {
  var xmldoc = XmlDocument.create();
  xmldoc.async=false;
  xmldoc.loadXML(xmlString);
  return xmldoc.documentElement;
 },

 getType: function() { return this._type; },
 //获取结果的服务器的返回结果
 getResult : function() { return this.deserialize(this.dataNode); },
   
 isFault : function() { return (this._type == "fault"); },
 
 isNull: function() { return (this._type == "null"); },
 //获取 服务器放回的 responseText 信息
 getSource : function() { return this._source; },
 
 //根据根节点 反序列化 相关操作
 deserialize: function(dataNode) {
  var ret;
  //获取节点数据的类型 然后根据不同的类型 初始化相关的数据
  var type = this._getType(dataNode);
  switch (type) {
   case "boolean": ret = this.doBoolean(dataNode); break;
   case "date": ret = this.doDate(dataNode); break;
   case "double": ret = this.doDouble(dataNode); break;
   case "int":
   case "long":
    ret = this.doInt(dataNode);
    break;
   case "list": ret = this.doList(dataNode); break;
   case "map": ret = this.doMap(dataNode); break;
   case "null": ret = this.doNull(dataNode); break;
   case "ref": ret = this.doRef(dataNode); break;
   case "string": ret = this.doString(dataNode);break;
   case "xml": ret = this.doXML(dataNode); break;
   case "fault": ret = this.doFault(dataNode); break;
   default: ;
  }

  return ret;
 },
 //获取节点的数据类型
 _getType : function(dataNode) {
  return dataNode.tagName.toLowerCase();
 },
 
 //获取节点的文本值 
 getNodeText :function(dataNode) {
  if (dataNode && dataNode.hasChildNodes()) {
   var s = "";
   for (var i = 0; i < dataNode.childNodes.length; i++)
   {
    s += new String(dataNode.childNodes.item(i).nodeValue);
   }
    //alert("tagName = " + dataNode.tagName+"nodeValue :"+ s);
   return s;
  } else {
   return null;
  }
 },
    //获取布尔值 true 或 false
 doBoolean : function (dataNode) {
  var value = this.getNodeText(dataNode);
  return (value == "1");
 },
 
 doDate : function (dataNode) {

  var dateStr = this.getNodeText(dataNode);
  var year = parseInt(dateStr.substring(0,4),"10");
  var month = parseInt(dateStr.substring(4,6),"10") - 1;
  var day = parseInt(dateStr.substring(6,8),"10");
  var hour = parseInt(dateStr.substring(9,11),"10");
  var minute = parseInt(dateStr.substring(11,13),"10");
  var second = parseInt(dateStr.substring(13,15),"10");
  
  var d = new Date(year, month, day, hour, minute, second);
  return d;
 },
 
 doDouble : function (dataNode) {
  var value = this.getNodeText(dataNode);
  return parseFloat(value);
 },
 
 doInt: function (dataNode) {
  var value = this.getNodeText(dataNode);
  return parseInt(value);
 },
 //处理数组的时候 我认为应该考虑内存的释放,如果数据量比较大(30W个元素),同一个浏览器没执行改函数一次 内存占有率都会涨40MB左右
 doList: function (dataNode) {
  var arr = new Array();
  this._objects[this._objects.length] = arr;
   
    var children = dataNode.childNodes;
    arr[Buffalo.BOCLASS] = this.getNodeText(children[0]);
  for (var i=2; i < children.length; i++) {
   arr[arr.length] = this.deserialize(children[i]);
  }

  return arr;
 },

 doMap: function (dataNode) {
 
  var obj = new Object();
  this._objects[this._objects.length] = obj;

  var attrs = dataNode.childNodes;
  obj[Buffalo.BOCLASS] = this.getNodeText(attrs[0]);
  for (var i = 1; i < attrs.length; i+=2) {
   obj[this.getNodeText(attrs[i])] = this.deserialize(attrs[i+1]);
  }
  
  return obj;
 },
 
 doNull: function (dataNode) { return null; },
 
 doRef: function (dataNode) {
  var value = this.getNodeText(dataNode);
  var idx = parseInt(value);
  
  return this._objects[idx];
 },
 
 doString: function (dataNode) {
  var value = this.getNodeText(dataNode);
  if (value == null) {
   return "";
  }
  return (value);
 },
 //如果返回的是XML形式的字符串 需要使用unescape()方法解码用 escape 方法进行了编码的 String 对象
 doXML : function (dataNode) {
  var value = this.getNodeText(dataNode);
  return unescape(value);
 },
 
 doFault : function (dataNode) {
  var code = this.getNodeText(dataNode.childNodes[1]);
  var msg = this.getNodeText(dataNode.childNodes[3]);
  var detail = this.deserialize(dataNode.childNodes[5]);
  return new Buffalo.Fault(code, msg, detail);
 }
 ,
 clearResponse:function(){
     this._objects = null ;
 }
}

// 显示 后台返回的 错误信息 对于调式比较有用
Buffalo.Fault = Class.create();

Buffalo.Fault.prototype = {
 initialize: function(code, message, detail) {
  this.code = code;
  this.message = message;
  this.detail = detail;
 },
 toString: function() {
  return "Buffalo.Fault:[code=" + this.code + ", message=" + this.message + ", detail=" + this.detail+"]";
 }
}

// 为 Buffalo类添加一个绑定的方法,如果需要绑定页面的元素可以使用该方法调用 后台的服务
Object.extend(Buffalo.prototype, {
 bindReply : function(service, params, bindElemId, options) {
  this.remoteCall(service, params, function(reply) {
   Buffalo.Bind.bind(bindElemId, reply.getResult(), options);
  })
 }
});

//将调用的服务的返回值 与 页面的表单元素进行绑定
//设置的表单类型可以是text hidden password checkbox radio TEXTAREA TABLE SELECT DIV SPAN FORM中的任何一种。
Buffalo.Bind = {
 bind : function(elementId, bindValue, options) {
  var elem = $(elementId);
  switch(elem.tagName) {
   case "INPUT":
    switch (elem.type.toLowerCase()) {
     case "text": ;
     case "hidden": ;
     case "password": Buffalo.BindFactory.bindText(elem, bindValue); break;

     case "checkbox": ;
     case "radio": Buffalo.BindFactory.bindRadioOrCheckbox(elem, bindValue); break;
    }
    break;
   case "TEXTAREA":
    Buffalo.BindFactory.bindText(elem, bindValue);
    break;
   case "TABLE":
    Buffalo.BindFactory.bindTable(elem, bindValue);
    break;
   case "SELECT":
    Buffalo.BindFactory.bindSelect(elem, bindValue, options);
    break;
   case "DIV":
   case "SPAN":
    elem.innerHTML = bindValue;
    break;
   case "FORM":
    Buffalo.Form.bindForm(elem, bindValue);
  }
 }
}

Buffalo.BindFactory = {
 reportError: function(elem, value, msg) {
  throw "Data bind failed: "+msg;
 },
 
 bindText: function(elem, value) {
  elem.value = value;
 },
 
 bindRadioOrCheckbox: function(elem, value) {
  elem.checked = Buffalo.BindFactory.checkTrue(value);
 },

 bindSelect : function(elem, value, options) {
  //TODO: Check the data type
  if (typeof(value) != "object" || value.constructor != Array) {
   this.reportError(elem,value,"Array Type Needed for binding select!");
  }
  // 初始化select标签前 先清除其原来的所有标签
  while (elem.childNodes.length > 0) {
   elem.removeChild(elem.childNodes[0]);
  }
  // bind data
  for (var i = 0; i < value.length; i++) {
   var option = document.createElement("OPTION");
            if (options && options.binder) {
                options.binder(value, option, i);
            } else {
                var data = value[i];
       if (typeof(data) != 'object') {
        option.value = data;
        option.text = data;
       } else {
        option.value = data[elem.getAttribute("jvalue")];
        option.text = data[elem.getAttribute("jtext")];
        if (Buffalo.BindFactory.checkTrue(data.selected)) {
         option.selected = true; 
        }
       }
            }
    
   elem.options.add(option);
  }
 },

 bindTable: function(elem, value) {
  var jHeight = parseInt(elem.getAttribute("jheight"));
  var dataHeader = [];
  var tBody = elem.getElementsByTagName("TBODY")[0];
  
  // clear the generated rows
  if (elem.getElementsByTagName("TBODY").length > 0) {
   while (tBody.rows.length > jHeight) {
     tBody.deleteRow(jHeight);
   }
  }

  if (jHeight == 0) { // if table is null, push the data to the tables.

   for (var x in value[0] ) {
    dataHeader[dataHeader.length] = x;
   }

   var hTr = elem.insertRow(elem.rows.length);
   for (var i = 0; i < dataHeader.length; i++) {
    var td = hTr.insertCell(hTr.cells.length);
    td.innerHTML = dataHeader[i];
   }
   
   for (var i = 0; i < value.length; i++) {
    var tr = elem.insertRow(elem.rows.length);
    var data = value[i];
    for (x in data ) {
     var td = tr.insertCell(tr.cells.length);
     td.innerHTML = data[x];
    }
   } 
  }
  
  if (jHeight == 1) { // if there is only one line, first line is header(every td indicate by a jtext property)
   var headerTR = tBody.rows[0];

   for (var i = 0; i < headerTR.cells.length ; i++ ) {
    dataHeader[dataHeader.length] = headerTR.cells[i].getAttribute("jtext");
   }
   
   for (var i = 0; i < value.length; i++) {
    var tr = tBody.insertRow(tBody.rows.length);
    var data = value[i];
    for (var j = 0; j < dataHeader.length; j++ ) {
     var td = tr.insertCell(tr.cells.length);
     td.innerHTML = data[dataHeader[j]];
    }
   } 
  }

  if (jHeight == 2) { // two lines, first line is header, the second is style

   var headerTR = tBody.rows[0];

   for (var i = 0; i < headerTR.cells.length ; i++ ) {
    dataHeader[dataHeader.length] = headerTR.cells[i].getAttribute("jtext");
   }

   for (var i = 0; i < value.length; i++) {
    
    var tr;
    
    if (i == 0) { // if the first row
     tr = elem.rows[1];
    } else { // else copy the first row
     tr = elem.rows[1].cloneNode(true);
    }

    if (i > 0)  {
     tBody.appendChild(tr);
    }

    var data = value[i];
    for (var j = 0; j < tr.cells.length; j++ ) {
     var td = tr.cells[j];
     
     td.innerHTML = data[dataHeader[j]];
    }
    
   } 
  }

  if (jHeight >= 3) { // more than 3 rows, first header, second and third is odd/even style, other lines ommited.
   var headerTR = tBody.rows[0];
   for (var i = 0; i < headerTR.cells.length ; i++ ) {
    dataHeader[dataHeader.length] = headerTR.cells[i].getAttribute("jtext");
   }
   for (var i = 0; i < value.length; i++) {
    var tr;
    
    if (i == 0) { // 1st row
     tr = tBody.rows[1];
    } else if (i == 1)  { // 2nd row
     tr = tBody.rows[2];
    } else if ( i % 2 == 0) { // get the 1st row
     tr = tBody.rows[1].cloneNode(true);
    } else if (i % 2 == 1) { // the 2nd row
     tr = tBody.rows[2].cloneNode(true);
    }

    
    if (i > 1)  {
     tBody.appendChild(tr);
    }

    var data = value[i];
    
    for (var j = 0; j < tr.cells.length; j++ ) {
     var td = tr.cells[j]; 
     td.innerHTML = data[dataHeader[j]];
    }
   } 
  }
  
 },
 
 checkTrue: function(value) {
  var ret = false;
  switch (typeof(value)) {
   case 'boolean': ret = value; break;
   case 'string': ret = (value == true || value == "1" || value == "true" || value == "yes"); break;
   case 'number': ret = (parseInt(value) == 1); break;
   default: ret = false;
  }
  return ret;
 }
}

Buffalo.bind = Buffalo.Bind.bind; /*capable with the old version, deprecated*/


Buffalo.View = Class.create();

Buffalo.View.LAST_VIEWNAME = null;
Buffalo.View.CURRENT_VIEW = null;
Buffalo.View.HOME_VIEW = null;
Buffalo.View.HISTORY_IFRAME_ID = "buffalo-view-history-iframe";

Buffalo.View.iframeLoaded = function(loc) {
 var url = loc.href;
 
 var idx = url.indexOf("?");
 var viewName = "";
 if (idx > -1) {
  viewName = url.substring(idx+1);
 }
 
 if (viewName == "") {
  viewName = Buffalo.View.HOME_VIEW;
 }

 if (Buffalo.View.CURRENT_VIEW != null) {
  Buffalo.View.CURRENT_VIEW.doSwitchPart(viewName);
 }
}

Buffalo.View.prototype = {
 initialize:function(buffaloObj) {
  this.buffalo = buffaloObj;
 },
 switchPart: function(partId, viewName, addToHistory) {
  this.partId = partId;
  this.viewName = viewName;
  if (typeof(addToHistory) == "undefined" || addToHistory == true) {
   this.addToHistory = true;
  } else {
   this.addToHistory = false;
  }
  if (Buffalo.View.LAST_VIEWNAME == null) {
   /* the first visit view is home view */
   Buffalo.View.HOME_VIEW = viewName;
   /* The first view, don't add to history */
   this.doSwitchPart(viewName);
   Buffalo.View.LAST_VIEWNAME = viewName;
   return;
  }

  Buffalo.View.CURRENT_VIEW = this;

  if (this.addToHistory) {
   if ($(Buffalo.View.HISTORY_IFRAME_ID)) {
    var iframesrc=$(Buffalo.View.HISTORY_IFRAME_ID).src;
    var newUrl = iframesrc;
    var idx = iframesrc.indexOf("?");
    if (idx > -1) {
     newUrl = iframesrc.substr(0,idx);
    }
    newUrl += "?" + viewName;
    $(Buffalo.View.HISTORY_IFRAME_ID).src = newUrl;
   } else {
    var msg = "It seems that you havent add the buffalo-blank.html as an Iframe for browser history.";
    msg += "/nSo this view cannot add to browser history.";
    msg += "/n/nTo prevent this dialog, use buffalo.switchPart(partId, viewName, false) or ";
    msg += "add the buffalo-blank.html to your main page with id 'buffalo-view-history-iframe'.";

    alert(msg);
   }
  }
  this.doSwitchPart(viewName);
  Buffalo.View.LAST_VIEWNAME = viewName;
  
 },
 
 doSwitchPart: function(viewName) {
  if (Buffalo.View.LAST_VIEWNAME == viewName) {
   return ;
  }

  this.transport = XmlHttp.create();
  var nonCachedViewName = viewName;
  try {
   /*Fix for the IE cache*/
   if (/MSIE/.test(navigator.userAgent)) {
    var bfViewHackKey = "_bfviewhackkey_=" + (new Date()).getTime();
    if (viewName.indexOf('?') > -1) {
     nonCachedViewName += "&" + bfViewHackKey;
    } else {
     nonCachedViewName += "?" + bfViewHackKey;
    }
   }
   this.transport.open("GET", nonCachedViewName, this.buffalo.async);/*use get for static page*/
  } catch (e) {
   var msg = "Buffalo View Error: /n/n Cannot find view with name: " + "[" + viewName + "]";
   alert(msg); 
  }
  
  this.transport.send(null);
  if (this.buffalo.async) {
   this.transport.onreadystatechange = this._viewHandle.bind(this);
   this.buffalo.events["onLoading"](true);
  } else {
   this._processView();
  }

  Buffalo.View.LAST_VIEWNAME = viewName;

 },

 _viewHandle : function(){
  this._processView();
 },

 _processView : function() {
  this.buffalo.events["onLoading"](false);
  if (this.transport.readyState == 4) {
   if (this.transport.status == '200') {
    var data = this.transport.responseText;
    this._showView(this.partId, this.viewName, data);
   } else {
    this.buffalo.events["onError"](this.transport);
   }
  }
 },

 _showView: function(partId, viewPath, viewData) {
  
  var regexp1 = /(.|/n|/r/n)*?/ig;
  var regexp2 = /((.|/n|/r/n)*)?/im;
  
  /* draw the html first */
  $(partId).innerHTML = viewData.replace(regexp1, "");
  
  var result = viewData.match(regexp1);
  if (result) {
   for (var i = 0; i < result.length; i++) {
    var realScript = result[i].match(regexp2);
    this._executeScript(realScript[2], partId);
    /* Note: do not try to write more than one

你可能感兴趣的:(Buffalo 学习笔记- buffalo.js 源代码注释(三))