1 /*global Ext document */
  2 /*  
  3   * Author: Sierk Hoeksma. WebBlocks.eu
  4   * Copyright 2007-2008, WebBlocks.  All rights reserved.
  5   *
  6   * This extension enables a panel to be directly created from Gui Designer Json
  7   * Dependend JavaScripts are loaded using ScriptLoader function
  8   ************************************************************************************
  9   *   This file is distributed on an AS IS BASIS WITHOUT ANY WARRANTY;
 10   *   without even the implied warranty of MERCHANTABILITY or
 11   *   FITNESS FOR A PARTICULAR PURPOSE.
 12   ************************************************************************************
 13 
 14   License: This source is licensed under the terms of the Open Source LGPL 3.0 license.
 15   Commercial use is permitted to the extent that the code/component(s) do NOT become
 16   part of another Open Source or Commercially licensed development library or toolkit
 17   without explicit permission.Full text: http://www.opensource.org/licenses/lgpl-3.0.html
 18 
 19   * Donations are welcomed: http://donate.webblocks.eu
 20   */
 21 
 22 /**
 23  * Override Ext.Panel so that scope of keymap is always set to object when not set, 
 24  * instead of window 
 25  */
 26 Ext.override(Ext.Panel,{
 27    // private
 28     getKeyMap : function(){
 29       if(!this.keyMap){
 30         if(Ext.isArray(this.keys)){          
 31           for(var i = 0, len = this.keys.length; i < len; i++){
 32             this.keys[i].scope = this.keys[i].scope || this;
 33           }
 34         } else if (this.keys && !this.keys.scope) this.keys.scope = this;
 35         this.keyMap = new Ext.KeyMap(this.el, this.keys);
 36       }
 37       return this.keyMap;
 38     }
 39 });
 40 
 41 
 42 /**
 43  * Override Ext.FormPanel so that in case whe create a form without items from a json
 44  * it still has a item list.
 45  */
 46 Ext.override(Ext.FormPanel, {
 47     // private
 48     initFields : function(){
 49         //BEGIN FIX It can happend that there is a form created without items (json)
 50         this.initItems(); 
 51         //END FIX
 52         var f = this.form;
 53         var formPanel = this;
 54         var fn = function(c){
 55             if(c.doLayout && c != formPanel){
 56                 Ext.applyIf(c, {
 57                     labelAlign: c.ownerCt.labelAlign,
 58                     labelWidth: c.ownerCt.labelWidth,
 59                     itemCls: c.ownerCt.itemCls
 60                 });
 61                 if(c.items){
 62                     c.items.each(fn);
 63                 }
 64             }else if(c.isFormField){
 65                 f.add(c);
 66             }
 67         }
 68         this.items.each(fn);
 69     }
 70 });
 71 
 72 /**
 73  * A Synchronized Content loader for data from url
 74  * @param {String} url The url to load synchronized
 75  * @param {Boolean} cachingOff Should caching of file be disabled
 76  * @param {Boolean} responseXML Should responseXML be returned instead of responseText
 77  * @return {Boolean/String/XMLObject} When there was a error False otherwise response base on responseXML flag
 78  */
 79 Ext.ux.SyncLoader = function(url,cachingOff,responseXML) {
 80  var activeX = Ext.lib.Ajax.activeX;
 81  var isLocal = (document.location.protocol == 'file:');
 82  var conn;
 83  
 84  try { 
 85   if(Ext.isIE7 && isLocal){throw("IE7forceActiveX");}
 86   conn = new XMLHttpRequest();
 87  } catch(e)  {
 88    for (var i = 0; i < activeX.length; ++i) {
 89      try {conn = new ActiveXObject(activeX[i]); break;} catch(e) {}
 90    }
 91  }
 92  //Should we disable caching
 93  if (!cachingOff)
 94     url += (url.indexOf('?') != -1 ? '&' : '?') + '_dc=' + (new Date().getTime());
 95  try {
 96   conn.open('GET', url , false);
 97   conn.send(null);
 98   if ((isLocal && conn.responseText.length!=0) || (conn.status !== undefined && conn.status>=200 && conn.status< 300)) {
 99     return responseXML ? conn.responseXML : conn.responseText;
100   }
101  } catch (e) {}
102  return false;
103 } 
104 
105 /**
106  * Function used to load a JavaScript into a document.head element
107  * the id of the script item is the name of the file.
108  * @param {String} url The url to load javascript from
109  * @param {Boolean} cachingOff Should caching of javascript files be disabled
110  * @return {Boolean} Indicator if load went corretly true/false
111  */
112 Ext.ux.ScriptLoader = function(url,cachingOff) {
113  if(url && !document.getElementById(url)) {
114    var content = Ext.ux.SyncLoader(url,cachingOff);
115    if (content===false) return false;
116    var head = document.getElementsByTagName("head")[0];
117    var script = document.createElement("script");
118    try {
119      script.text = content;
120    } catch (e) {
121      script.appendChild(content);
122    }
123    script.setAttribute("type", "text/javascript");
124    script.setAttribute("id", url);
125    head.appendChild(script);
126  }
127  return true;
128 } 
129 
130 
131 /**
132  * A class used by JsonPanel and JsonWindow to load a jsonFile
133  */
134 Ext.ux.Json = Ext.extend(Ext.util.Observable,{
135     /**
136      * Boolean indicator when true loadMsg will be shown
137      @cfg */
138     loadMask: true,
139     /**
140      * The loading message
141      @cfg */
142     loadMsg: 'Loading...',
143     /**
144      * Mask used for loading message
145      @cfg */
146     msgCls : 'x-mask-loading',
147    
148     /** 
149      * The string used to indent   
150      * @type {String} 
151      @cfg */
152     indentString : '  ',
153 
154     /**
155      * Array with items which should be blocked during init
156      * @type {Array}
157      @cfg */
158     blockedJsonInit : ['items'],
159 
160     /** 
161     * Should caching be disabled when JSON are loaded (defaults false).   
162     * @type {Boolean} 
163     @cfg */
164     disableCaching:false, 
165 
166     /**
167     * @private Tag added to json code so whe can see begining of code  
168     */
169     scriptStart  : '/*BEGIN*/',
170 
171     /**
172     * @private Tag added to json code so whe can see ending of code
173     */
174     scriptEnd    : '/*END*/',
175     
176     /**
177      * The lisenceText that should be added to each JSON File Created
178      * @type {String}
179      @cfg */
180     licenseText  : '',
181     
182     /**
183      * @private Indicator if object hasOwnProperty
184      */
185     useHasOwn : ({}.hasOwnProperty ? true : false),
186     
187     //@private The internal tag used to create unique, when null no id is generated
188     jsonId : null, 
189     //@private Last id used to create json
190     lastJsonId : 0,
191 
192     
193     //@private The maximum number of json histories to keep
194     jsonHistoryMax : 0,
195     //@private The history for json
196     jsonHistory : [],
197     
198     /**
199      * Add a json to the json history
200      * @param {String} json the json to add
201      */
202     addJsonHistory : function(json) {
203       if (json) {
204         this.jsonHistory.push(json);
205         while (this.jsonHistory.length > this.jsonHistoryMax)
206           this.jsonHistory.remove(this.jsonHistory[0]);
207       }
208     },
209     
210     /**
211      * Get the last item from the json history
212      * @param {Boolean} keep Should history be untouched
213      * @return {String} The json
214      */
215     getJsonHistory : function(keep) {
216       if (this.jsonHistory.length > 0) {
217         if (keep) return this.jsonHistory[this.jsonHistory.length-1];
218         return this.jsonHistory.pop();
219       }
220       return null;
221     },
222 
223     /**
224      * Load one or more javascripts. Is trigger by root element window.required_js in json file. 
225      * The javascripts are synchonrized load before the JSON is evaluated. Base on the config item
226      * disableCaching (defaults true) the url of the javascript to load is made unique with parameter _dc.
227      * @param {String} list A comma seperated list of javascripts to load
228      */
229     setRequired_js : function(list) {   
230      if (!list) return;
231      var files = list.split(',');
232      for (var f=0;f<files.length;f++) {
233        if (!Ext.ux.ScriptLoader(files[f],this.disableCaching)) {
234           Ext.Msg.alert('Failure','Failed to load javascript '+ files[f]);
235        }
236      }
237     },
238 
239     /**
240      * Load one or more stylesheets. Is triggered by root element window.required_css in json file
241      * @param {String} list A comma seperated list of stylesheets to load
242      */
243     setRequired_css : function(list) {
244       if (!list) return;
245       var files = list.split(',');
246       for (var f=0;f<files.length;f++) {    
247         if(document.getElementById(files[f])) {continue;}
248         Ext.util.CSS.swapStyleSheet(files[f], files[f]);
249      }
250     },
251 
252     /**
253     * Added items to blockedJsonInit during jsonInit
254     * @param {Object} args A object indexed by xtype containing array of blocked keys
255     */
256     setBlockedJsonInit : function(args){
257       if (this.getXType && args) {
258         var val = args[this.getXType()];
259         if (typeof val == 'object') {
260           for (var i=0;i<val.length;i++) this.blockedJsonInit.push(val[i]);
261         } else this.blockedJsonInit.push(val);
262       }
263     },
264 
265     /**
266     * Function called with config object of json file
267     * @param {Object} config The config object that can be applied
268     * @return {Boolean} indicator if all changes where set
269     */
270     jsonInit : function (config,element,all,scopeOnly) {
271      var allSet = true, el = element || this;
272      if (config) {
273       for (var i in config) {       
274         var j = i;
275         if (all || this.blockedJsonInit.indexOf(i) == -1) {
276           if (i=='required_js') { 
277             this.setRequired_js(config[i]);
278           } else if (i=='required_css') {
279              this.setRequired_css(config[i]);
280           } else {
281             var applyTo = el;
282             //When scope of var set if
283             if (i.indexOf('scope.')==0) {
284                j = i.substring(6);
285                applyTo = this.getJsonScope();
286             } else if (scopeOnly) continue;
287             var k = 'set' + j.substring(0,1).toUpperCase() + j.substring(1);
288             try {
289               if (applyTo[k] && typeof applyTo[k] == 'function') {
290                 applyTo[k].call(el,config[i]);
291               } else if (applyTo[j] && typeof applyTo[j] == 'function') {
292                 applyTo[j].call(el,config[i]);
293               } else {
294                 applyTo[j] = config[i];
295               }
296             } catch (e) {
297               allSet = false;
298             }
299           }
300         }
301       }
302      }
303      return allSet;
304     },
305     
306     /**
307      * Check if a object is empty
308      */
309     isEmptyObject : function(obj) {
310      for (var i in obj) {if (i!=this.jsonId)  return false;}
311      return true;
312     },
313     
314    /**
315     * Apply the Json to given element
316     * @param {Object/String} json The json to apply
317     * @param {Element} element The element to apply the json to
318     * @return {Object} The elements applied
319     */
320     applyJson : function (json,element) {
321      var el = element || this;
322      try {
323        if (this.loadMask && el.ownerCt) el.ownerCt.el.mask(this.loadMsg, this.msgCls);
324        var items = this.jsonId ? this.editableJson(json) : json || {};
325        if (typeof(items) !== 'object') items = this.decode(json);
326        if (items) {
327          //Apply global json vars to element
328          if (el instanceof Ext.Container) {
329            //Clear out orignal content of container
330            while (el.items && el.items.first()) {el.remove(el.items.first(), true);}
331            if (items instanceof Array) {
332              el.add.apply(el,items);
333            } else if (!this.isEmptyObject(items)) { 
334              el.add(items);
335            }
336          } else {
337            this.jsonInit(items,el);
338          }
339        }
340       if (el.rendered && el.layout && el.layout.layout) el.doLayout();     
341      } catch (e) {   
342       throw e;
343      } finally {
344       if (this.loadMask && el.ownerCt) el.ownerCt.el.unmask();
345      }
346       return items;
347     },
348     
349    /**
350     * Convert a Json to a editableJson by adding an edtiableId when set
351     * @param {Object/String} json The json to add an id to
352     * @param {Object} id The id object used to give id
353     * @return {Object} The decoded object with id
354     */
355     editableJson : function(json) {
356      var items = json || {};
357      if (typeof(items) !== 'object') items = this.decode(json);
358      if (items instanceof Array) {
359        for (var i=0;i<items.length;i++) {
360         items[i]=this.editableJson(items[i]);
361        }
362        return items;
363      }
364      if (this.jsonId) {
365        if (!items[this.jsonId]) {
366          items[this.jsonId]=Ext.id();
367        }
368        for (var k in items) {      
369          if (k.indexOf(this.jsonId)==0 && k!=this.jsonId) {
370            var orgK = k.substring(this.jsonId.length);
371            if (orgK && typeof(items[orgK])=='undefined') items[orgK]=null; //Code is there but not key, create it
372          } else if (!items[this.jsonId + k ]) {
373            if (typeof(items[k]) == 'function') {
374              items[this.jsonId + k]=String(items[k]);
375            } else if (typeof(items[k]) == 'object' && k!='items') {
376             items[this.jsonId + k] = Ext.ux.JSON.encode(items[k]);
377            } 
378          } 
379        }
380        if (items.items) items.items=this.editableJson(items.items);
381      }
382      return items;
383     },
384 
385     /**
386      * @private Encode a string to Json
387      * @param {String} s The string to encode
388      * @return {String} A string containing the encode string 
389      */
390     encodeString : function(s){
391        var m = {"\b": '\\b',"\t": '\\t',"\n": '\\n',"\f": '\\f',"\r": '\\r','"' : '\\"',"\\": '\\\\'};
392        if (/["\\\x00-\x1f]/.test(s)) { //"
393            return '"'  + s.replace(/([\x00-\x1f\\"])/g, function(a, b) { //"
394                var c = m[b];
395                if(c){ return c; }
396                c = b.charCodeAt();
397                return "\\u00" +
398                    Math.floor(c / 16).toString(16) +
399                    (c % 16).toString(16);
400            })  + '"';
401        }
402        return '"' + s + '"';
403      },
404 
405      /**
406       * @private Create a indent so code is readable
407       * @param {Int} n The indent length
408       * @return {String} A string containing n spaces
409       */
410      indentStr : function(n) {
411        var str = "", i = 0;
412        while (i<n) {
413          str += this.indentString;
414          i++;
415        }
416        return str;
417      },  
418 
419      /**
420       * @private Encode an Array to Json
421       * @param {Array} o The array to encode
422       * @param {Int} indent The indent to uses (defaults 0)
423       * @param {Boolean} notags Should code be wrapped between scriptStart and scriptEnd
424       * @return {String} The array encode as string
425       */
426      encodeArray  : function(o,indent,keepJsonId){
427        indent = indent || 0;
428        var a = ["["], b, i, l = o.length, v;
429        for (var i = 0; i < l; i += 1) {
430          v = o[i];
431          switch (typeof v) {
432            case "undefined":
433            case "unknown":
434                break;
435            default:
436                if (b) a.push(',');
437                a.push(v === null ? "null" : this.encode(v, indent + 1,keepJsonId));
438                b = true;
439          }
440        }
441        a.push("]");
442        return a.join("");
443      },
444 
445      /** 
446       * @private Encode a date to json 
447       * @param {Date} o The date object to encode
448       * @return {String} The data encode as string
449       */
450      encodeDate : function(o){
451        var pad = function(n) { return n < 10 ? "0" + n : n; };
452        return '"' + o.getFullYear() + "-" +
453                pad(o.getMonth() + 1) + "-" +
454                pad(o.getDate()) + "T" +
455                pad(o.getHours()) + ":" +
456                pad(o.getMinutes()) + ":" +
457                pad(o.getSeconds()) + '"';
458      },
459 
460      /** 
461       * Customer encode decode and recode, enabling reading and writing of JSON files with javascript code
462       * @param {Object} o The object to encode
463       * @param {Int} indent The indent to uses (defaults 0)
464       * @return {String} The object encode as string
465       */  
466     encode : function(o,indent,keepJsonId,noLicense){       
467        indent = indent || 0;
468        if(typeof o == "undefined" || o === null){
469            return "null";
470        }else if(o instanceof Array){
471            return this.encodeArray(o, indent,keepJsonId);
472        }else if(o instanceof Date){
473            return this.encodeDate(o);
474        }else if(typeof o == "number"){
475            return isFinite(o) ? String(o) : "null";
476        }else if(typeof o == "string" && !isNaN(o) && o!='' ){
477            return o; 
478        } else if(typeof o == "string" && ['true','false'].indexOf(o)!=-1){
479           return o;
480        } else if(typeof o == "boolean") {
481            return String(o);
482        } else if(typeof o == "string"){
483            return this.encodeString(o);
484        }else {
485         if (o.constructor) {
486           var c = ""+o.constructor;
487           c=c.substring(c.indexOf('function ')+9);
488           c=c.substring(0,c.indexOf('(')).replace(' '); 
489           if (!c) {
490            b = ""+o.constructor;
491            var b=b.substring(0,b.indexOf('.superclass'));
492            for (var i=b.length-1;i>0;i--) {
493              if ([';',' ','\n','\t'].indexOf(b.substring(i,i+1))!=-1) {
494                c=b.substring(i+1);
495                i=-1;
496              }
497            }
498            if (c && o.initialConfig) {
499              return this.indentStr(indent) + this.scriptStart 
500                + 'new '+ c + '(' +
501                 this.encode(o.initialConfig,indent+1,keepJsonId)
502                + ') ' + this.scriptEnd;
503            }
504           } 
505           if (['Array','Object','Date'].indexOf(c)== -1) { 
506             return 'null /* Class ' + c + ' has no initialConfig */';
507           }
508          }
509          var a = [], b, i, v;
510          //Check if whe should create a license text
511          if (indent==0 && !noLicense) {
512           if (this.licenseText) a.push(this.licenseText + "\n");
513          }
514          a.push("{\n");
515          for (var i in o) {
516            v = o[i];   
517            //Check if key (i) is an internal jsonId and original is empty then use this
518            if (i.indexOf(this.jsonId)==0 && (!keepJsonId || i!=this.jsonId)) {
519              var orgK = i.substring(this.jsonId.length);
520              if (orgK && typeof(o[orgK])=='undefined' && v) {
521                 if(b) a.push(',\n'); 
522                 a.push(this.indentStr(indent), orgK, " : ", this.scriptStart,v,this.scriptEnd);
523                 b = true;
524              }
525              continue; //internal id skip it during encode
526            }
527            //Create code for item
528            if(!this.useHasOwn || o.hasOwnProperty(i)) {
529              if (this.jsonId && o[this.jsonId + i]) {
530                  if(b) a.push(',\n'); 
531                  a.push(this.indentStr(indent), i, " : ", this.scriptStart,o[this.jsonId + i],this.scriptEnd);
532                  b = true;
533              } else {               
534                switch (typeof v) {
535                  case "undefined":
536                  case "unknown":               
537                      break;            
538                  case "function":
539                    if(b) a.push(',\n'); 
540                    a.push(this.indentStr(indent), i, " : ", this.scriptStart,""+v,this.scriptEnd);
541                    b = true;
542                    break;
543                  case "object" :
544                  case "string" :
545                     if (!v) break; //Skip empty string and objects else default
546                  default:
547                      if(b) a.push(',\n');
548                      a.push(this.indentStr(indent), i, " : ",
549                            v === null ? "null" : this.encode(v,indent + 1,keepJsonId));
550                      b = true;
551                }
552              }
553            }
554          }
555          a.push("\n" + this.indentStr(indent-1) + "}");
556          return a.join("");
557        }
558      },
559 
560      /**
561       * Decode json evaluating Json tag (required_js,required_css) returning all elements as string
562       * @param {String} value The string to decode
563       * @return {Object} The decoded object with string only
564       */     
565      decodeAsString : function(json) {
566        if (!json) return;
567        /* Encode all functions between begin and end as string enabling load of packages */
568        var value = json
569        var v = '', s = value.indexOf(this.scriptStart);
570        var jsonStr;
571        while (s!=-1) {
572          jsonStr = '';
573          e = value.indexOf(this.scriptEnd,s);
574          v += value.substring(0,s);
575          if (this.jsonId) {
576            var i = v.lastIndexOf(':')-1;
577            while (i>0 && [" ","\t","\n","\r"].indexOf(v.substring(i,i+1))>=0) {i--;}
578            var w = '';
579            while (i>0 && [" ","\t","\n","\r","{","["].indexOf(v.substring(i,i+1))==-1) {
580               w = v.substring(i,i+1) + w;
581               i--;
582            }
583            jsonStr += ',' + this.jsonId + w + ' : ' + this.encodeString(value.substring(s+this.scriptStart.length,e));
584         }            
585          v += this.encodeString(value.substring(s+this.scriptStart.length,e)) + jsonStr;               
586          value = value.substring(e+this.scriptEnd.length);
587          s=value.indexOf(this.scriptStart);
588        }
589        v += value;   
590        var scope = this.getJsonScope(); 
591        var items = eval("(" + v + ")");
592        if(items && items.json) { 
593           items.json = eval("(" + items.json + ")");
594           this.jsonInit(items.json,null,null,true);
595        }
596        
597        //When jsonId is set convert changed fields to jsonId+key=StringValue
598        return items;
599      },
600      
601      /**
602       * Function returning the scope to beused for the json
603       * @return {Object} 
604       */
605      getJsonScope : function(){
606        return  this.jsonScope || this.scope || this;  
607      },
608      
609      /**
610       * Clean null elements from json object
611       */
612      deleteJsonNull : function(json) {
613        return json;
614        var c=0;      
615        for (var k in json) {
616          if(!this.useHasOwn || json.hasOwnProperty(k)) {
617            if (k=='items') {
618              if (json[k] instanceof Array) {
619               var n =[];
620               for (var i=0,a=json[k];i<a.length;i++) {
621                 var o = this.deleteJsonNull(a[i]);
622                 if (o!=null) n.push(o); 
623               }
624               json[k] = (n.length>0) ? n : null; //Was null but form crashed on it
625              } else json[k]=this.deleteJsonNull(json[k]);
626            }
627            if (json[k]===null) {
628              delete json[k];
629            } else {
630              c++;
631            }
632          }
633        }
634        return c ? json : null;
635      },
636      
637      /**
638       * Decode json evaluating Json tag (required_js,required_css) 
639       * @param {String} value The string to decode
640       * @return {Object} The decoded object
641       */
642      decode : function(json) {
643        var applyJsonId=function(o,j) {
644          if (!this.jsonId) return o;
645          for (var i in o) {
646            if(!this.useHasOwn || o.hasOwnProperty(i)) {
647             if (i=='items') {
648               for (var k=0,len=o.items.length;k<len;k++){
649                  o.items[k] = applyJsonId(o.items[k],j.items[k]);
650               }
651             }
652             else if (j[this.jsonId+i]) {
653              o[this.jsonId+i] = j[this.jsonId+i];
654             }
655           }
656          }
657          return o;
658        }.createDelegate(this);
659        this.addJsonHistory(json);
660        var items = this.decodeAsString(json);
661        //Now we can do decode by using eval setting scope
662        var scope = this.getJsonScope();
663        items = applyJsonId(eval("(" + json + ")"),items); 
664        if(items) this.jsonInit(items.json); 
665        return items;
666      },
667 
668     /**
669      * Function used to clone a object
670      * @param {Object} o the object to be cloned
671      * @return {Object} The cloned object
672      */
673     clone : function(o) {
674       return this.decode(this.encode(o));
675     }
676 });
677 
678 /**
679  * Create global object 
680  */
681 Ext.ux.JSON = new Ext.ux.Json();
682 
683 /**
684  * Component extending a panel giving it the capability to read or create a JSON file.
685  * When using Json file created with designer this JsonPanel will also evaluate the special items 
686  * under Json root called <b>winbow</b>. The JsonPanel currently evaluates two special window items 
687  * called <i>required_js,required_css</i> that enable loading of javascripts and stylesheets directly from the json.
688  *
689  *<p>Example how to create a Json from a external file filling the browser:</p>
690  * <pre><code>new Ext.Viewport({
691      items : new Ext.ux.JsonPanel({autoLoad:'json/designer.json'}),
692      layout: 'fit'
693    }).show();</code></pre>
694  *<p>Example how to (re)load a JsonPanel that is allready loaded:</p>
695  * <pre><code>this.load({url:'new url'});</code></pre>   
696  * <p><b>IMPORTANT:</b>When you want use the JsonPanel to load a Json file in a local browser make sure that you include a
697  * local xhr package like <a href="http://extjs.com/forum/showthread.php?t=10672">localXHR</a> or any other
698  * to fix the problem of ExtJs not supporting Ajax from local file system</p>
699  * @type component
700  */
701 Ext.ux.JsonPanel = Ext.extend(Ext.Panel,Ext.applyIf({
702  
703  //@private Layout is by default fit
704  layout: 'fit',
705  
706  //@private Border is by default false
707  border: false,
708  
709  //@private Whe only read a JSON file once
710  single:true,  //only needed once
711 
712   /**
713    * Array with items which should be blocked during init
714    * @type {Array}
715    @cfg */
716   blockedJsonInit : ['alignTo','anchorTo','items'],
717     
718  
719  /**
720   * @private Init the JSON Panel making sure caching is set depending on disableCaching 
721   */
722  initComponent : function(){
723    if (this.autoLoad) {
724      if (typeof this.autoLoad !== 'object')  this.autoLoad = {url: this.autoLoad};
725      if (typeof this.autoLoad['nocache'] == 'undefined') this.autoLoad['nocache'] = this.disableCaching;
726    }                
727    Ext.ux.JsonPanel.superclass.initComponent.call(this);
728    
729    this.addEvents({
730      /**
731       * Fires after the jsonfile is retrived from server but before it's loaded in panel
732       * @event beforejsonload
733       * @param {Object} response The response object returned
734       * @param {Exception} e The exception when avialable
735       */
736     'beforejsonload' : true,
737      /**
738       * Fires after panel the panel is loaded with new content
739       * @event afterjsonload
740       */
741     'afterjsonload'  : true,
742      /**
743       * Fires when loading of jsonfile fails
744       * @event afterjsonload
745       */
746     'failedjsonload' : false
747    });
748  },
749 
750 
751  /**
752   * @private We override the render function of the panel, so that the updater.renderer is changed to accept JSON
753   * @param {Component} ct The component to render
754   * @param {Object} position A object containing the position of the component
755   */
756  onRender : function(ct, position){
757   Ext.ux.JsonPanel.superclass.onRender.call(this, ct, position);
758   var um = this.getUpdater();
759   um.showLoadIndicator = false; //disable it.
760   um.on('failure',function(el, response){
761     this.ownerCt.el.unmask();
762     this.fireEvent('failedjsonload',response)
763   }.createDelegate(this));
764   um.on('beforeupdate',function(el, url, params) {
765    if (this.loadMask && this.ownerCt)
766      this.ownerCt.el.mask(this.loadMsg, this.msgCls);
767   }.createDelegate(this));
768  
769   um.setRenderer({render:
770        function(el, response, updater, callback){
771      //add item configs to the panel layout
772         //Load the code to check if we should javascripts
773         this.fireEvent('beforejsonload', response);
774         try { 
775           this.applyJson(response.responseText);           
776           this.fireEvent('afterjsonload');
777           this.ownerCt.el.unmask();
778 
779           if(callback) {callback();}
780         } catch (e) {
781           this.ownerCt.el.unmask();
782           if (!this.fireEvent('afterjsonload',response,e))
783              Ext.Msg.alert('Failure','Failed to decode load Json:' + e)
784         }
785       }.createDelegate(this)
786     });  
787   }
788 
789 },Ext.ux.JSON));
790 //Register the panel
791 Ext.reg('jsonpanel', Ext.ux.JsonPanel);
792 
793 
794 /* FOR NOW WE COPY CODE TO ALSO HAVE A WINDOW, WE NEED TO FIND A SOLUTION */
795 Ext.ux.JsonWindow = Ext.extend(Ext.Window,Ext.applyIf({
796 
797  //@private Window is hidden by moving X out of screen
798  x     : -1000,
799  //@private Window is hidden by moving Y out of screen
800  y     : -1000,
801  
802  //@private Layout is by default fit
803  layout: 'fit',
804  
805  //@private Border is by default false
806  border: false,
807  
808  //@private Whe only read a JSON file once
809  single:true,  //only needed once
810  
811  /**
812   * @private Init the JSON Panel making sure caching is set depending on disableCaching 
813   */
814  initComponent : function(){
815    if (this.autoLoad) {
816      if (typeof this.autoLoad !== 'object')  this.autoLoad = {url: this.autoLoad};
817      if (typeof this.autoLoad['nocache'] == 'undefined') this.autoLoad['nocache'] = this.disableCaching;
818    }                
819    Ext.ux.JsonWindow.superclass.initComponent.call(this);
820    
821    this.addEvents({
822      /**
823       * Fires after the jsonfile is retrived from server but before it's loaded in panel
824       * @event beforejsonload
825       * @param {Object} response The response object returned
826       * @param {Exception} e The exception when avialable
827       */
828     'beforejsonload' : true,
829      /**
830       * Fires after panel the panel is loaded with new content
831       * @event afterjsonload
832       */
833     'afterjsonload'  : true,
834      /**
835       * Fires when loading of jsonfile fails
836       * @event afterjsonload
837       */
838     'failedjsonload' : false
839    });
840  },
841  
842  setX : function(x) {
843    this.setPosition(x,this.y);
844  },
845  
846  setY : function(y) {
847     this.setPosition(this.x,y);
848  },
849  
850  setAlignTo : function(arg) {
851    this.alignTo(arg[0],arg[1],arg[2]);
852  },
853  
854  setAnchorTo : function(ar) {
855    this.anchorTo(arg[0],arg[1],arg[2],arg[3]);
856  },
857  
858   
859  /**
860   * @private We override the render function of the panel, so that the updater.renderer is changed to accept JSON
861   * @param {Component} ct The component to render
862   * @param {Object} position A object containing the position of the component
863   */
864  onRender : function(ct, position){
865   Ext.ux.JsonWindow.superclass.onRender.call(this, ct, position);
866   var um = this.getUpdater();
867   um.showLoadIndicator = false; //disable it.
868   um.on('failure',function(el, response){
869       this.ownerCt.el.unmask();
870       this.fireEvent('failedjsonload',response)
871     }.createDelegate(this));
872     um.on('beforeupdate',function(el, url, params) {
873      if (this.loadMask && this.ownerCt)
874        this.ownerCt.el.mask(this.loadMsg, this.msgCls);
875   }.createDelegate(this));
876   
877   um.setRenderer({render:
878        function(el, response, updater, callback){
879      //add item configs to the panel layout
880         //Load the code to check if we should javascripts
881         this.fireEvent('beforejsonload', response);
882         try { 
883           this.applyJson(response.responseText); 
884           this.fireEvent('afterjsonload');
885           if(callback) {callback();}
886         } catch (e) {
887           if (!this.fireEvent('afterjsonload',response,e))
888              Ext.Msg.alert('Failure','Failed to decode load Json:' + e)
889         }
890       }.createDelegate(this)
891     });  
892   }
893 
894 },Ext.ux.JSON));
895 
896 //Register the window
897 Ext.reg('jsonwindow